From 3f125e26b3bccc7c4fb8af49f6ad00d2e70972d8 Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Fri, 19 Apr 2024 22:52:02 -0400 Subject: [PATCH 01/19] UI progress --- .../modding/game/file/kaitai/ResMonster.java | 2 +- .../excite/modding/concurrent/Batch.java | 143 ++++++ .../modding/concurrent/BatchContainer.java | 13 + .../modding/concurrent/BatchListener.java | 5 + .../modding/concurrent/BatchRunner.java | 100 ++++ .../modding/concurrent/BatchWorker.java | 22 + .../excite/modding/concurrent/Batcher.java | 22 + .../excite/modding/concurrent/Shutdown.java | 3 + .../modding/concurrent/package-info.java | 1 + .../modding/quicklz/DecodingException.java | 15 + .../excite/modding/quicklz/QuickLZ.java | 20 + .../excite/modding/quicklz/QuicklzDumper.java | 15 +- .../modding/ui/BatchOperationComponent.java | 43 ++ .../modding/ui/BatchedImageComponent.java | 73 +++ .../modding/ui/BatchedImageListener.java | 7 + .../excite/modding/ui/FixedCellGrid.java | 106 +++++ .../excite/modding/ui/FixedCellSizeGrid.java | 101 ++++ .../excite/modding/ui/ImageComponent.java | 33 ++ .../modding/ui/JTextAreaOutputStream.java | 30 ++ .../modding/ui/NonWrappedJEditorPane.java | 17 + .../modding/ui/StripedImageGenerator.java | 57 +++ .../excite/modding/ui/Window.java | 438 ++++++++++++++++++ .../excite/modding/ui/package-info.java | 1 + .../excite/modding/unarchiver/Archive.java | 25 +- .../modding/unarchiver/ArchivedFile.java | 76 ++- .../excite/modding/unarchiver/Unarchiver.java | 3 +- .../excite/modding/{ => util}/FileUtils.java | 6 +- .../modding/util/SplitOutputStream.java | 73 +++ .../excite/modding/util/package-info.java | 1 + src/main/resources/kaitai/monster_res.ksy | 2 +- 30 files changed, 1422 insertions(+), 31 deletions(-) create mode 100644 src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchListener.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchWorker.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/concurrent/Batcher.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/concurrent/Shutdown.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/concurrent/package-info.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/quicklz/DecodingException.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/ui/BatchOperationComponent.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageListener.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/ui/FixedCellGrid.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/ui/FixedCellSizeGrid.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/ui/ImageComponent.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/ui/JTextAreaOutputStream.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/ui/NonWrappedJEditorPane.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/ui/StripedImageGenerator.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/ui/Window.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/ui/package-info.java rename src/main/java/com/gamebuster19901/excite/modding/{ => util}/FileUtils.java (95%) create mode 100644 src/main/java/com/gamebuster19901/excite/modding/util/SplitOutputStream.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/util/package-info.java diff --git a/build/generated/kaitai/com/gamebuster19901/excite/modding/game/file/kaitai/ResMonster.java b/build/generated/kaitai/com/gamebuster19901/excite/modding/game/file/kaitai/ResMonster.java index 9aac540..32a7636 100644 --- a/build/generated/kaitai/com/gamebuster19901/excite/modding/game/file/kaitai/ResMonster.java +++ b/build/generated/kaitai/com/gamebuster19901/excite/modding/game/file/kaitai/ResMonster.java @@ -155,7 +155,7 @@ public Data(KaitaiStream _io, ResMonster _parent, ResMonster _root) { _read(); } private void _read() { - if (_root().header().compressed() == 128) { + if ( ((_root().header().compressed() == 128) || (_root().header().compressed() == 1152)) ) { this.compressedData = new QuicklzRcmp(this._io); } if (_root().header().compressed() == 0) { diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java new file mode 100644 index 0000000..51f57b9 --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java @@ -0,0 +1,143 @@ +package com.gamebuster19901.excite.modding.concurrent; + +import java.lang.ref.SoftReference; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.concurrent.Callable; +import static java.lang.Thread.State; + +public class Batch implements Batcher { + + private final Set runnables = new HashSet<>(); + private final LinkedHashSet listeners = new LinkedHashSet<>(); + private volatile boolean accepting = true; + + + public void addRunnable(Callable runnable) { + if(accepting) { + BatchedCallable b = new BatchedCallable(runnable); + runnables.add(new BatchedCallable(runnable)); + updateListeners(); + } + else { + notAccepting(); + } + } + + public void addRunnable(Runnable runnable) { + if(accepting) { + BatchedCallable b = new BatchedCallable(runnable); + runnables.add(new BatchedCallable(runnable)); + updateListeners(); + } + else { + notAccepting(); + } + } + + public void addListener(BatchListener listener) { + if(accepting) { + if(!listeners.add(listener)) { + System.out.println("Warning: duplicate batch listener ignored."); + } + } + else { + notAccepting(); + } + } + + @Override + public Collection getRunnables() { + return Set.copyOf(runnables); + } + + @Override + public Collection getListeners() { + return (Collection) listeners.clone(); + } + + public void shutdownNow() throws InterruptedException { + accepting = false; + Shutdown shutdown = new Shutdown(); + for(BatchedCallable r : runnables) { + if(r.getState() == State.NEW) { + r.shutdown(shutdown); + } + } + System.err.println(runnables.size()); + } + + public void updateListeners() { + for(BatchListener listener : listeners) { + listener.update(); + } + } + + private void notAccepting() { + throw new IllegalStateException("Batch is not accepting new tasks or listeners."); + } + + public class BatchedCallable implements Callable { + + private final Callable child; + private volatile SoftReference threadRef; + protected volatile Throwable thrown; + protected volatile boolean finished = false; + + public BatchedCallable(Runnable r) { + this(() -> { + r.run(); + return null; + }); + } + + public BatchedCallable(Callable c) { + this.child = c; + updateListeners(); + } + + @Override + public Void call() { + Thread thread; + try { + thread = Thread.currentThread(); + threadRef = new SoftReference<>(thread); + updateListeners(); + child.call(); + } + catch(Throwable t) { + this.thrown = t; + } + finally { + finished = true; + updateListeners(); + } + return null; + } + + public State getState() { + if(finished) { //the thread is no longer working on this runnable + return State.TERMINATED; + } + if(threadRef == null) { + return State.NEW; + } + Thread thread = threadRef.get(); + if(thread == null) { + return State.TERMINATED; //thread has been garbage collected, so it has been terminated. + } + return thread.getState(); + } + + public Throwable getThrown() { + return thrown; + } + + protected void shutdown(Shutdown shutdown) { + finished = true; + thrown = shutdown; + } + } + } diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java new file mode 100644 index 0000000..3a2ab37 --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java @@ -0,0 +1,13 @@ +package com.gamebuster19901.excite.modding.concurrent; + +import java.util.Collection; + +import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; + +public interface BatchContainer { + + public Collection getRunnables(); + + public Collection getListeners(); + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchListener.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchListener.java new file mode 100644 index 0000000..20df878 --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchListener.java @@ -0,0 +1,5 @@ +package com.gamebuster19901.excite.modding.concurrent; + +public interface BatchListener { + public void update(); +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java new file mode 100644 index 0000000..3d224df --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java @@ -0,0 +1,100 @@ +package com.gamebuster19901.excite.modding.concurrent; + +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; + +public class BatchRunner implements BatchWorker { + + private final ExecutorService executor; + private final LinkedHashSet batches = new LinkedHashSet(); + private volatile boolean started = false; + + public BatchRunner() { + this(Runtime.getRuntime().availableProcessors()); + } + + public BatchRunner(int threads) throws IllegalArgumentException { + this(Executors.newFixedThreadPool(threads)); + } + + public BatchRunner(ExecutorService executor) { + this.executor = executor; + } + + @Override + public void addBatch(Batcher batcher) { + synchronized(executor) { + if(executor.isShutdown()) { + throw new IllegalStateException("Cannot add more batches after the batch runner has shut down!"); + } + synchronized(batches) { + batches.add(batcher); + } + } + } + + @Override + public void startBatch() throws InterruptedException { + synchronized(executor) { + if(executor.isShutdown()) { + throw new IllegalStateException("BatchRunner has already been started!"); + } + synchronized(batches) { + started = true; + executor.invokeAll(getRunnables()); + } + } + } + + @Override + public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { + return executor.awaitTermination(timeout, unit); + } + + @Override + public void shutdownNow() throws InterruptedException { + executor.shutdownNow(); // Force shutdown of any remaining tasks + try { + executor.awaitTermination(5, TimeUnit.SECONDS); + } + finally { + for(Batcher batch : batches) { + batch.shutdownNow(); + } + } + } + + @Override + public Collection getRunnables() { + synchronized(batches) { + LinkedHashSet ret = new LinkedHashSet<>(); + for(Batcher batch : batches) { + ret.addAll(batch.getRunnables()); + } + return ret; + } + } + + @Override + public Collection getListeners() { + synchronized(batches) { + LinkedHashSet ret = new LinkedHashSet<>(); + for(Batcher batch : batches) { + ret.addAll(batch.getListeners()); + } + return ret; + } + } + + public int getCompleted() { + int ret = 0; + Collection callables = getRunnables(); + for(BatchedCallable callable : callables) {ret++;} + return ret; + } + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchWorker.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchWorker.java new file mode 100644 index 0000000..cbffafa --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchWorker.java @@ -0,0 +1,22 @@ +package com.gamebuster19901.excite.modding.concurrent; + +import java.util.Collection; +import java.util.concurrent.TimeUnit; + +import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; + +public interface BatchWorker extends BatchContainer { + + public abstract void addBatch(Batcher batcher); + + public abstract void startBatch() throws InterruptedException; + + public abstract boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException; + + public void shutdownNow() throws InterruptedException; + + public Collection getRunnables(); + + public Collection getListeners(); + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batcher.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batcher.java new file mode 100644 index 0000000..aaef965 --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batcher.java @@ -0,0 +1,22 @@ +package com.gamebuster19901.excite.modding.concurrent; + +import java.util.Collection; +import java.util.concurrent.Callable; + +import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; + +public interface Batcher extends BatchContainer { + + public abstract void addRunnable(Callable runnable); + + public abstract void addRunnable(Runnable runnable); + + public abstract void addListener(BatchListener listener); + + public void shutdownNow() throws InterruptedException; + + public Collection getRunnables(); + + public Collection getListeners(); + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Shutdown.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Shutdown.java new file mode 100644 index 0000000..def151d --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Shutdown.java @@ -0,0 +1,3 @@ +package com.gamebuster19901.excite.modding.concurrent; + +class Shutdown extends Throwable {Shutdown(){}} \ No newline at end of file diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/package-info.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/package-info.java new file mode 100644 index 0000000..4d7194f --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/package-info.java @@ -0,0 +1 @@ +package com.gamebuster19901.excite.modding.concurrent; \ No newline at end of file diff --git a/src/main/java/com/gamebuster19901/excite/modding/quicklz/DecodingException.java b/src/main/java/com/gamebuster19901/excite/modding/quicklz/DecodingException.java new file mode 100644 index 0000000..fdcbee5 --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/quicklz/DecodingException.java @@ -0,0 +1,15 @@ +package com.gamebuster19901.excite.modding.quicklz; + +import java.io.IOException; + +public class DecodingException extends IOException { + + public DecodingException(int exitCode) { + super("QuickLZ process failed with exit code (" + exitCode + "): " + QuickLZ.ExitCode.get(exitCode)); + } + + public DecodingException(Throwable cause) { + super(cause); + } + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/quicklz/QuickLZ.java b/src/main/java/com/gamebuster19901/excite/modding/quicklz/QuickLZ.java index 0a1ea82..eb79f0f 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/quicklz/QuickLZ.java +++ b/src/main/java/com/gamebuster19901/excite/modding/quicklz/QuickLZ.java @@ -19,6 +19,26 @@ public static enum Mode { decompress } + public static enum ExitCode { + SUCCESS, + HELP_SUCCESS, + UNKNOWN_MODE, + MISSING_MODE_ARG, + MISSING_SOURCE_ARG, + MISSING_DEST_ARG, + TOO_MANY_ARGS, + SOURCE_ERR, + DEST_ERR, + UNKNOWN; + + public static ExitCode get(int i) { + if(i < values().length && i >= 0) { + return values()[i]; + } + return UNKNOWN; + } + } + private static final QuickLZImpl impl = QuickLZImpl.get(); public static void compress(Path file, Path dest) { diff --git a/src/main/java/com/gamebuster19901/excite/modding/quicklz/QuicklzDumper.java b/src/main/java/com/gamebuster19901/excite/modding/quicklz/QuicklzDumper.java index eef767c..28adfab 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/quicklz/QuicklzDumper.java +++ b/src/main/java/com/gamebuster19901/excite/modding/quicklz/QuicklzDumper.java @@ -5,9 +5,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; -import java.util.concurrent.TimeUnit; -import com.gamebuster19901.excite.modding.FileUtils; +import com.gamebuster19901.excite.modding.quicklz.QuickLZ.ExitCode; +import com.gamebuster19901.excite.modding.util.FileUtils; public class QuicklzDumper { @@ -28,12 +28,17 @@ public byte[] decode(byte[] _raw_data) { try { Files.write(input, _raw_data, StandardOpenOption.CREATE); Process process = QuickLZ.decompress(input, output); - process.waitFor(5000, TimeUnit.SECONDS); + int exitCode = process.waitFor(); + if(exitCode != ExitCode.SUCCESS.ordinal()) { + throw new DecodingException(exitCode); + } return Files.readAllBytes(output); } catch(IOException | InterruptedException e) { - throw new IOError(e); + IOError err = new IOError(e); + err.printStackTrace(); + throw err; } } - + } diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchOperationComponent.java b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchOperationComponent.java new file mode 100644 index 0000000..4d2d545 --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchOperationComponent.java @@ -0,0 +1,43 @@ +package com.gamebuster19901.excite.modding.ui; + +import javax.swing.JPanel; + +import com.gamebuster19901.excite.modding.concurrent.BatchContainer; + +import java.awt.BorderLayout; +import javax.swing.JLabel; +import javax.swing.SwingConstants; + +public class BatchOperationComponent extends JPanel { + + private BatchedImageComponent batch; + private String name; + private JLabel fileName; + + public BatchOperationComponent(BatchContainer batch, String name) { + this(new BatchedImageComponent(batch), name); + } + + /** + @wbp.parser.constructor + **/ + public BatchOperationComponent(BatchedImageComponent batch, String name) { + this.batch = batch; + setLayout(new BorderLayout(0, 0)); + + add(batch, BorderLayout.CENTER); + + fileName = new JLabel(name); + fileName.setHorizontalAlignment(SwingConstants.CENTER); + add(fileName, BorderLayout.SOUTH); + this.setName(name); + } + + @Override + public void setName(String name) { + super.setName(name); + this.setToolTipText(name); + this.fileName.setText(name); + } + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java new file mode 100644 index 0000000..19f783b --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java @@ -0,0 +1,73 @@ +package com.gamebuster19901.excite.modding.ui; + +import java.awt.Color; +import java.awt.Image; +import java.util.Collection; +import java.util.LinkedHashMap; +import com.gamebuster19901.excite.modding.concurrent.BatchListener; +import com.gamebuster19901.excite.modding.concurrent.Batch; +import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; +import com.gamebuster19901.excite.modding.concurrent.BatchContainer; + +public class BatchedImageComponent extends ImageComponent implements BatchContainer { + + private final BatchContainer batch; + + public BatchedImageComponent() { + this(new Batch()); + } + + public BatchedImageComponent(BatchContainer batch) { + this.batch = batch; + } + + @Override + public Image getImage() { + int _new = 0; + int working = 0; + int success = 0; + int failure = 0; + int other = 0; + + for (BatchedCallable runnable : getRunnables()) { + switch (runnable.getState()) { + case NEW: + _new++; + continue; + case RUNNABLE: + working++; + continue; + case TERMINATED: + if(runnable.getThrown() == null) { + success++; + continue; + } + failure++; + continue; + default: + other++; + } + } + + LinkedHashMap colors = new LinkedHashMap<>(); + colors.put(Color.GREEN, success); + colors.put(Color.RED, failure); + colors.put(Color.WHITE, working); + colors.put(Color.ORANGE, other); + colors.put(Color.GRAY, _new); + + return StripedImageGenerator.generateImage(getWidth(), getHeight(), (LinkedHashMap) colors); + } + + + @Override + public Collection getRunnables() { + return batch.getRunnables(); + } + + @Override + public Collection getListeners() { + return batch.getListeners(); + } + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageListener.java b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageListener.java new file mode 100644 index 0000000..53d399d --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageListener.java @@ -0,0 +1,7 @@ +package com.gamebuster19901.excite.modding.ui; + +public interface BatchedImageListener { + + public void onBatchedImageUpdate(); + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/FixedCellGrid.java b/src/main/java/com/gamebuster19901/excite/modding/ui/FixedCellGrid.java new file mode 100644 index 0000000..74e9480 --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/FixedCellGrid.java @@ -0,0 +1,106 @@ +package com.gamebuster19901.excite.modding.ui; + +import java.awt.Component; +import java.util.NavigableSet; +import java.util.TreeMap; + +import javax.swing.JComponent; +import java.awt.*; + +public abstract class FixedCellGrid extends JComponent { + + protected final int padding; + protected final TreeMap components = new TreeMap<>(); + protected final NavigableSet navigator = components.navigableKeySet(); + + public FixedCellGrid(int padding) { + this.padding = padding; + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + + components.forEach((index, component) -> { + component.setBounds(calculateCellX(index), calculateCellY(index), getCellWidth(), getCellHeight()); + //System.out.println("Rendering component " + index + " at " + component.getX() + ", " + component.getY()); + }); + + } + + @Override + public void setPreferredSize(Dimension dimension) { + super.setPreferredSize(dimension); + } + + @Override + public void setBounds(int x, int y, int width, int height) { + super.setBounds(x, y, width, height); + this.setPreferredSize(new Dimension(width - x, height - y)); + } + + protected abstract void onGridUpdate(); + + protected abstract int calculateCellX(int index); + + protected abstract int getCellWidth(); + + protected abstract int calculateCellY(int index); + + protected abstract int getCellHeight(); + + public final Component getComponent(Integer index) { + return components.get(index); + } + + public final Component putComponent(Integer index, Component component) { + super.add(component); + System.out.println("Adding component " + component + " at index " + index); + return components.put(index, component); + } + + public final int getLowestFreeCell() { + Integer prevIndex = 0; + Integer index = -1; + while(index != null) { + index = navigator.higher(index); + if(index == null) { + return components.size(); + } + if(index - prevIndex > 1) { //we've found a gap in the defined cells + return prevIndex + 1; + } + prevIndex = index; + } + + return components.size(); + } + + public final Component getFirstComponent() { + return components.firstEntry().getValue(); + } + + public final Component getLastComponent() { + return components.lastEntry().getValue(); + } + + public final TreeMap getComponentMap() { + return components; + } + + @Override + @Deprecated + public Component add(Component component) { + //super.add(component); + System.out.println("Adding component at index " + getLowestFreeCell()); + putComponent(getLowestFreeCell(), component); + return component; + } + + @Override + @Deprecated + public void add(Component component, Object constraints) { + add(component); // Ignore constraints, components are positioned based on the cell location and size + } + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/FixedCellSizeGrid.java b/src/main/java/com/gamebuster19901/excite/modding/ui/FixedCellSizeGrid.java new file mode 100644 index 0000000..1c35c5a --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/FixedCellSizeGrid.java @@ -0,0 +1,101 @@ +package com.gamebuster19901.excite.modding.ui; +import java.awt.*; + +public class FixedCellSizeGrid extends FixedCellGrid { + + private int cellWidth; + private int cellHeight; + private int scroll; + + public FixedCellSizeGrid(Dimension gridDimension, Dimension cellDimension) { + this(gridDimension, cellDimension, 0); + } + + public FixedCellSizeGrid(Dimension gridDimension, Dimension cellDimension, int padding) { + super(padding); + this.cellWidth = cellDimension.width; + this.cellHeight = cellDimension.height; + this.setPreferredSize(gridDimension); + try { + calculateCellX(1); + } + catch(ArithmeticException e) { + throw new IllegalArgumentException("Grid size is too small, it cannot hold any cells!", e); + } + } + + @Override + public void setPreferredSize(Dimension dimension) { + super.setPreferredSize(dimension); + onGridUpdate(); + } + + @Override + protected void onGridUpdate() { + components.forEach((index, component) -> { + component.setBounds(calculateCellX(index), calculateCellY(index), getCellWidth(), getCellHeight()); + }); + System.out.println(this.getPreferredSize()); + System.out.println(cellWidth); + invalidate(); + } + + protected void setCellSize(Dimension dimension) { + this.cellWidth = dimension.width; + this.cellHeight = dimension.height; + onGridUpdate(); + } + + @Override + protected int getCellWidth() { + return cellWidth; + } + + @Override + protected int getCellHeight() { + return cellHeight; + } + + @Override + protected int calculateCellX(int index) { + return ((((index % (this.getPreferredSize().width / (cellWidth + padding))) * (cellWidth + padding))) + (padding / 2)); + } + + private int calculateCellYRaw(int index) { + int rowIndex = index / (this.getPreferredSize().width / (cellWidth + padding)); + return (rowIndex * (cellHeight + padding)) / (cellHeight + padding); + } + + private int getVisibleRows() { + return this.getPreferredSize().height / (cellHeight + padding); + } + + private int getMaxScroll() { + return Math.max(0, calculateCellYRaw(components.size()) - getVisibleRows()); + } + + protected int calculateCellY(int index) { + int rowIndex = index / (this.getPreferredSize().width / (cellWidth + padding)); + return (rowIndex * (cellHeight + padding)) - (scroll * (cellHeight + padding)); + } + + public int getScroll() { + return scroll; + } + + public void scroll(int offset) { + int newScroll = scroll + offset; + System.out.println("Max scroll: " + getMaxScroll()); + if(newScroll < 0) { + scroll = 0; + } + else if(newScroll > getMaxScroll()) { + scroll = getMaxScroll(); + } + else { + scroll = newScroll; + } + onGridUpdate(); + } + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/ImageComponent.java b/src/main/java/com/gamebuster19901/excite/modding/ui/ImageComponent.java new file mode 100644 index 0000000..2c79444 --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/ImageComponent.java @@ -0,0 +1,33 @@ +package com.gamebuster19901.excite.modding.ui; + +import java.awt.Graphics; +import java.awt.Image; + +import javax.swing.JComponent; + +public class ImageComponent extends JComponent { + + Image image = null; + + public ImageComponent() { + this(null); + } + + public ImageComponent(Image image) { + this.image = image; + } + + public Image getImage() { + return image; + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + Image image = getImage(); + if(image != null) { + g.drawImage(image, 0, 0, this); + } + } + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/JTextAreaOutputStream.java b/src/main/java/com/gamebuster19901/excite/modding/ui/JTextAreaOutputStream.java new file mode 100644 index 0000000..838e05b --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/JTextAreaOutputStream.java @@ -0,0 +1,30 @@ +package com.gamebuster19901.excite.modding.ui; + +import java.io.IOException; +import java.io.OutputStream; + +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; + +public class JTextAreaOutputStream extends OutputStream { + + private final JTextArea dest; + + public JTextAreaOutputStream(JTextArea dest) { + this.dest = dest; + } + + @Override + public void write(int b) throws IOException { + write(new byte[]{(byte)b}, 0, 1); + } + + @Override + public void write(byte[] buf, int off, int len) throws IOException { + String text = new String(buf, off, len); + SwingUtilities.invokeLater(() -> { + dest.append(text); + }); + } + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/NonWrappedJEditorPane.java b/src/main/java/com/gamebuster19901/excite/modding/ui/NonWrappedJEditorPane.java new file mode 100644 index 0000000..9d3b71c --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/NonWrappedJEditorPane.java @@ -0,0 +1,17 @@ +package com.gamebuster19901.excite.modding.ui; + +import java.awt.Component; +import javax.swing.JEditorPane; +import javax.swing.plaf.ComponentUI; + +public class NonWrappedJEditorPane extends JEditorPane { + + @Override + public boolean getScrollableTracksViewportWidth() { + Component parent = getParent(); + ComponentUI ui = getUI(); + + return true; + } + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/StripedImageGenerator.java b/src/main/java/com/gamebuster19901/excite/modding/ui/StripedImageGenerator.java new file mode 100644 index 0000000..95f9465 --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/StripedImageGenerator.java @@ -0,0 +1,57 @@ +package com.gamebuster19901.excite.modding.ui; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.util.LinkedHashMap; +import java.util.Map; + +public class StripedImageGenerator { + + public static BufferedImage generateImage(int width, int height, LinkedHashMap colorWeights) { + // Check for valid input + if (width <= 0 || height <= 0 || colorWeights == null || colorWeights.isEmpty()) { + throw new IllegalArgumentException("Invalid input parameters"); + } + + int totalWeight = 0; + for (int weight : colorWeights.values()) { + if (weight < 0) { + throw new IllegalArgumentException("Color weights must be 0 or a positive integer"); + } + totalWeight += weight; + } + + if (totalWeight == 0) { + totalWeight = height; + colorWeights = new LinkedHashMap(); + colorWeights.put(Color.GRAY, totalWeight); + } + double scaleFactor = (double) height / totalWeight; + + LinkedHashMap colorHeights = new LinkedHashMap<>(); + for (Map.Entry entry : colorWeights.reversed().entrySet()) { + Color color = entry.getKey(); + int weight = entry.getValue(); + int rowHeight = (int) Math.ceil(weight * scaleFactor); + colorHeights.put(color, rowHeight); + } + + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + + Graphics2D graphics = image.createGraphics(); + + int currentY = 0; + for (Map.Entry entry : colorHeights.entrySet()) { + Color color = entry.getKey(); + int rowHeight = entry.getValue(); + graphics.setColor(color); + graphics.fillRect(0, currentY, width, rowHeight); + currentY += rowHeight; + } + + graphics.dispose(); + + return image; + } +} \ No newline at end of file diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java new file mode 100644 index 0000000..9d34ba5 --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java @@ -0,0 +1,438 @@ +package com.gamebuster19901.excite.modding.ui; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Insets; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.io.PrintStream; + +import javax.swing.JFrame; +import com.gamebuster19901.excite.modding.concurrent.BatchListener; +import com.gamebuster19901.excite.modding.concurrent.BatchRunner; +import com.gamebuster19901.excite.modding.util.SplitOutputStream; +import com.gamebuster19901.excite.modding.concurrent.Batch; + +import javax.swing.JTextField; +import javax.swing.UIManager; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JSeparator; +import javax.swing.JTabbedPane; +import javax.swing.JTextArea; +import javax.swing.JSlider; +import javax.swing.JProgressBar; +import javax.swing.SwingConstants; +import javax.swing.JScrollPane; +import javax.swing.ScrollPaneConstants; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import javax.swing.JList; +import javax.swing.BoxLayout; +import com.jgoodies.forms.layout.FormLayout; +import com.jgoodies.forms.layout.ColumnSpec; +import com.jgoodies.forms.layout.RowSpec; +import java.awt.GridLayout; +import javax.swing.GroupLayout; +import javax.swing.GroupLayout.Alignment; +import java.awt.GridBagLayout; +import java.awt.GridBagConstraints; +import java.awt.FlowLayout; +import javax.swing.JTable; + +public class Window implements BatchListener, MouseWheelListener { + + static { + UIManager.getDefaults().put("TabbedPane.contentBorderInsets", new Insets(0,0,0,0)); + } + + private JFrame frame; + private JTextField textField; + private JTextField textField_1; + private JSlider threadSlider; + private JLabel lblThreads; + private static Window window; + private final JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP); + private final JProgressBar progressBar = new JProgressBar(); + private JTable table; + + /** + * Launch the application. + * @throws InterruptedException + */ + public static void main(String[] args) throws InterruptedException { + + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + Window window = new Window(); + Window.window = window; + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + /** + * Create the application. + * @throws InterruptedException + */ + public Window() throws InterruptedException { + initialize(); + update(); + } + + /** + * Initialize the contents of the frame. + * @throws InterruptedException + */ + private void initialize() throws InterruptedException { + frame = new JFrame(); + frame.setTitle("ExciteModder"); + frame.setBounds(100, 100, 1000, 680); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.getContentPane().setLayout(null); + //frame.setResizable(false); + frame.setVisible(true); + + JLabel lblUnmoddedDirectory = new JLabel("Source Directory:"); + lblUnmoddedDirectory.setToolTipText("The directory of the unmodified, original ripped files."); + lblUnmoddedDirectory.setBounds(12, 12, 165, 15); + frame.getContentPane().add(lblUnmoddedDirectory); + + JLabel lblModdedDirectory = new JLabel("Destination Directory:"); + lblModdedDirectory.setToolTipText("Where ExciteModder will copy modified game files to."); + lblModdedDirectory.setBounds(12, 39, 165, 15); + frame.getContentPane().add(lblModdedDirectory); + + textField = new JTextField(); + textField.setBounds(171, 37, 578, 19); + frame.getContentPane().add(textField); + textField.setColumns(10); + + textField_1 = new JTextField(); + textField_1.setColumns(10); + textField_1.setBounds(171, 10, 578, 19); + frame.getContentPane().add(textField_1); + + JButton btnChangeSource = new JButton("Change"); + btnChangeSource.setToolTipText("Change where ExciteModder will copy the game files from"); + btnChangeSource.setBounds(761, 9, 117, 19); + frame.getContentPane().add(btnChangeSource); + + JButton btnChangeDest = new JButton("Change"); + btnChangeDest.setToolTipText("Change where ExciteModder will copy the game files to"); + btnChangeDest.setBounds(761, 36, 117, 19); + frame.getContentPane().add(btnChangeDest); + tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); + + tabbedPane.setBounds(0, 129, 1000, 511); + frame.getContentPane().add(tabbedPane); + + + + + FixedCellGrid gridPanel = new FixedCellSizeGrid(new Dimension(385, 385), new Dimension(100, 100), 0); + + gridPanel.setVisible(true); + gridPanel.components.remove(-1); + + JTextArea textArea = new JTextArea(); + textArea.setBorder(BorderFactory.createLoweredBevelBorder()); + textArea.setOpaque(true); + JTextAreaOutputStream textPaneOutputStream = new JTextAreaOutputStream(textArea); + System.setOut(new PrintStream(SplitOutputStream.splitSysOut(textPaneOutputStream))); + System.setErr(new PrintStream(SplitOutputStream.splitErrOut(textPaneOutputStream))); + + JScrollPane scrollPane = new JScrollPane(textArea); + scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); + tabbedPane.addTab("Console Output", null, scrollPane, null); + tabbedPane.addTab("Status", null, gridPanel, null); + + JPanel panel = new JPanel(); + tabbedPane.addTab("Progress", null, panel, null); + panel.setLayout(new BorderLayout(0, 0)); + + //gridPanel.setPreferredSize(new Dimension(814, 406)); + + BatchRunner batchRunner = new BatchRunner(); + for(int i = 0; i < 10; i++) { + Batch b = new Batch(); + batchRunner.addBatch(b); + BatchOperationComponent c = new BatchOperationComponent(b, "File " + i); + gridPanel.putComponent(i, c); + if(i == 5) { + c.setName("A very long file name"); + } + tabbedPane.addTab(c.getName(), null); + } + + JPanel panel_1 = new JPanel(); + panel.add(panel_1, BorderLayout.CENTER); + GridBagLayout gbl_panel_1 = new GridBagLayout(); + gbl_panel_1.columnWidths = new int[]{0, 0, 70, 90, 0}; + gbl_panel_1.rowHeights = new int[]{0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + gbl_panel_1.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + gbl_panel_1.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + panel_1.setLayout(gbl_panel_1); + + JLabel lblCopyOperation = new JLabel("Copy Operation"); + GridBagConstraints gbc_lblCopyOperation = new GridBagConstraints(); + gbc_lblCopyOperation.gridwidth = 4; + gbc_lblCopyOperation.insets = new Insets(0, 0, 5, 5); + gbc_lblCopyOperation.gridx = 0; + gbc_lblCopyOperation.gridy = 0; + panel_1.add(lblCopyOperation, gbc_lblCopyOperation); + BatchOperationComponent allBatches = new BatchOperationComponent(batchRunner, " All Batches "); + GridBagConstraints gbc_allBatches = new GridBagConstraints(); + gbc_allBatches.fill = GridBagConstraints.VERTICAL; + gbc_allBatches.gridheight = 9; + gbc_allBatches.insets = new Insets(0, 0, 5, 5); + gbc_allBatches.gridx = 0; + gbc_allBatches.gridy = 1; + panel_1.add(allBatches, gbc_allBatches); + + JSeparator separator_1 = new JSeparator(); + GridBagConstraints gbc_separator_1 = new GridBagConstraints(); + gbc_separator_1.fill = GridBagConstraints.BOTH; + gbc_separator_1.gridheight = 10; + gbc_separator_1.insets = new Insets(0, 0, 5, 5); + gbc_separator_1.gridx = 1; + gbc_separator_1.gridy = 0; + panel_1.add(separator_1, gbc_separator_1); + + JLabel lblTotalArchives = new JLabel("Total Archives:"); + lblTotalArchives.setHorizontalAlignment(SwingConstants.CENTER); + GridBagConstraints gbc_lblTotalArchives = new GridBagConstraints(); + gbc_lblTotalArchives.insets = new Insets(0, 0, 5, 5); + gbc_lblTotalArchives.anchor = GridBagConstraints.NORTHEAST; + gbc_lblTotalArchives.gridx = 2; + gbc_lblTotalArchives.gridy = 1; + panel_1.add(lblTotalArchives, gbc_lblTotalArchives); + + JLabel lblTotalArchivesCount = new JLabel("0"); + GridBagConstraints gbc_lblTotalArchivesCount = new GridBagConstraints(); + gbc_lblTotalArchivesCount.anchor = GridBagConstraints.WEST; + gbc_lblTotalArchivesCount.insets = new Insets(0, 0, 5, 0); + gbc_lblTotalArchivesCount.gridx = 3; + gbc_lblTotalArchivesCount.gridy = 1; + panel_1.add(lblTotalArchivesCount, gbc_lblTotalArchivesCount); + + JLabel lblTotalResources = new JLabel("Total Resources:"); + lblTotalResources.setHorizontalAlignment(SwingConstants.RIGHT); + GridBagConstraints gbc_lblTotalResources = new GridBagConstraints(); + gbc_lblTotalResources.anchor = GridBagConstraints.EAST; + gbc_lblTotalResources.insets = new Insets(0, 0, 5, 5); + gbc_lblTotalResources.gridx = 2; + gbc_lblTotalResources.gridy = 2; + panel_1.add(lblTotalResources, gbc_lblTotalResources); + + JLabel lblTotalResourcesCount = new JLabel("0"); + GridBagConstraints gbc_lblTotalResourcesCount = new GridBagConstraints(); + gbc_lblTotalResourcesCount.anchor = GridBagConstraints.WEST; + gbc_lblTotalResourcesCount.insets = new Insets(0, 0, 5, 0); + gbc_lblTotalResourcesCount.gridx = 3; + gbc_lblTotalResourcesCount.gridy = 2; + panel_1.add(lblTotalResourcesCount, gbc_lblTotalResourcesCount); + + JLabel lblArchivesCopied = new JLabel("Archives Copied:"); + GridBagConstraints gbc_lblArchivesCopied = new GridBagConstraints(); + gbc_lblArchivesCopied.anchor = GridBagConstraints.EAST; + gbc_lblArchivesCopied.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesCopied.gridx = 2; + gbc_lblArchivesCopied.gridy = 4; + panel_1.add(lblArchivesCopied, gbc_lblArchivesCopied); + + JLabel label_1 = new JLabel("0 (0%)"); + GridBagConstraints gbc_label_1 = new GridBagConstraints(); + gbc_label_1.anchor = GridBagConstraints.WEST; + gbc_label_1.insets = new Insets(0, 0, 5, 0); + gbc_label_1.gridx = 3; + gbc_label_1.gridy = 4; + panel_1.add(label_1, gbc_label_1); + + JLabel lblResourcesCopied = new JLabel("Resources Copied:"); + GridBagConstraints gbc_lblResourcesCopied = new GridBagConstraints(); + gbc_lblResourcesCopied.anchor = GridBagConstraints.EAST; + gbc_lblResourcesCopied.insets = new Insets(0, 0, 5, 5); + gbc_lblResourcesCopied.gridx = 2; + gbc_lblResourcesCopied.gridy = 5; + panel_1.add(lblResourcesCopied, gbc_lblResourcesCopied); + + JLabel label_2 = new JLabel("0 (0%)"); + GridBagConstraints gbc_label_2 = new GridBagConstraints(); + gbc_label_2.anchor = GridBagConstraints.WEST; + gbc_label_2.insets = new Insets(0, 0, 5, 0); + gbc_label_2.gridx = 3; + gbc_label_2.gridy = 5; + panel_1.add(label_2, gbc_label_2); + + JLabel lblArchivesProcessed = new JLabel("Archives Processed:"); + lblArchivesProcessed.setHorizontalAlignment(SwingConstants.RIGHT); + GridBagConstraints gbc_lblArchivesProcessed = new GridBagConstraints(); + gbc_lblArchivesProcessed.anchor = GridBagConstraints.EAST; + gbc_lblArchivesProcessed.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesProcessed.gridx = 2; + gbc_lblArchivesProcessed.gridy = 7; + panel_1.add(lblArchivesProcessed, gbc_lblArchivesProcessed); + + JLabel lblArchivesprocessed = new JLabel("0 (0%)"); + GridBagConstraints gbc_lblArchivesprocessed = new GridBagConstraints(); + gbc_lblArchivesprocessed.insets = new Insets(0, 0, 5, 0); + gbc_lblArchivesprocessed.anchor = GridBagConstraints.WEST; + gbc_lblArchivesprocessed.gridx = 3; + gbc_lblArchivesprocessed.gridy = 7; + panel_1.add(lblArchivesprocessed, gbc_lblArchivesprocessed); + + JLabel lblArchivesProcessed_1 = new JLabel("Archives Skipped:"); + lblArchivesProcessed_1.setHorizontalAlignment(SwingConstants.RIGHT); + GridBagConstraints gbc_lblArchivesProcessed_1 = new GridBagConstraints(); + gbc_lblArchivesProcessed_1.anchor = GridBagConstraints.EAST; + gbc_lblArchivesProcessed_1.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesProcessed_1.gridx = 2; + gbc_lblArchivesProcessed_1.gridy = 8; + panel_1.add(lblArchivesProcessed_1, gbc_lblArchivesProcessed_1); + + JLabel label_3 = new JLabel("0 (0%)"); + GridBagConstraints gbc_label_3 = new GridBagConstraints(); + gbc_label_3.anchor = GridBagConstraints.WEST; + gbc_label_3.insets = new Insets(0, 0, 5, 0); + gbc_label_3.gridx = 3; + gbc_label_3.gridy = 8; + panel_1.add(label_3, gbc_label_3); + + JLabel lblResourcesProcessed = new JLabel("Resources Processed:"); + GridBagConstraints gbc_lblResourcesProcessed = new GridBagConstraints(); + gbc_lblResourcesProcessed.anchor = GridBagConstraints.EAST; + gbc_lblResourcesProcessed.insets = new Insets(0, 0, 5, 5); + gbc_lblResourcesProcessed.gridx = 2; + gbc_lblResourcesProcessed.gridy = 9; + panel_1.add(lblResourcesProcessed, gbc_lblResourcesProcessed); + + JLabel label = new JLabel("100 (100%)"); + GridBagConstraints gbc_label = new GridBagConstraints(); + gbc_label.insets = new Insets(0, 0, 5, 0); + gbc_label.anchor = GridBagConstraints.WEST; + gbc_label.gridx = 3; + gbc_label.gridy = 9; + panel_1.add(label, gbc_label); + + JLabel lblResourcesSkipped = new JLabel("Resources Skipped"); + GridBagConstraints gbc_lblResourcesSkipped = new GridBagConstraints(); + gbc_lblResourcesSkipped.anchor = GridBagConstraints.EAST; + gbc_lblResourcesSkipped.insets = new Insets(0, 0, 0, 5); + gbc_lblResourcesSkipped.gridx = 2; + gbc_lblResourcesSkipped.gridy = 10; + panel_1.add(lblResourcesSkipped, gbc_lblResourcesSkipped); + + JLabel label_4 = new JLabel("0 (0%)"); + GridBagConstraints gbc_label_4 = new GridBagConstraints(); + gbc_label_4.anchor = GridBagConstraints.WEST; + gbc_label_4.gridx = 3; + gbc_label_4.gridy = 10; + panel_1.add(label_4, gbc_label_4); + + JPanel panel_2 = new JPanel(); + panel.add(panel_2, BorderLayout.EAST); + GridBagLayout gbl_panel_2 = new GridBagLayout(); + gbl_panel_2.columnWidths = new int[]{0, 0}; + gbl_panel_2.rowHeights = new int[]{0, 0}; + gbl_panel_2.columnWeights = new double[]{0.0, Double.MIN_VALUE}; + gbl_panel_2.rowWeights = new double[]{0.0, Double.MIN_VALUE}; + panel_2.setLayout(gbl_panel_2); + + JLabel lblNewLabel = new JLabel("New label"); + GridBagConstraints gbc_lblNewLabel = new GridBagConstraints(); + gbc_lblNewLabel.gridx = 0; + gbc_lblNewLabel.gridy = 0; + panel_2.add(lblNewLabel, gbc_lblNewLabel); + + threadSlider = new JSlider(); + threadSlider.getSnapToTicks(); + threadSlider.setMinimum(1); + threadSlider.setMaximum(Runtime.getRuntime().availableProcessors()); + threadSlider.setValue(Math.max(1, Runtime.getRuntime().availableProcessors() / 2)); + threadSlider.setBounds(5, 90, 92, 16); + threadSlider.addChangeListener((s) -> { + if(lblThreads != null) { + lblThreads.setText("Threads: " + threadSlider.getValue()); + } + }); + frame.getContentPane().add(threadSlider); + + lblThreads = new JLabel("Threads: " + threadSlider.getValue()); + lblThreads.setBounds(12, 74, 132, 15); + frame.getContentPane().add(lblThreads); + + JSeparator separator = new JSeparator(); + separator.setBounds(12, 64, 971, 2); + frame.getContentPane().add(separator); + + progressBar.setVisible(false); + + JLabel lblStatus = new JLabel("Progress: 0%"); + lblStatus.setHorizontalAlignment(SwingConstants.CENTER); + lblStatus.setBounds(440, 110, 120, 15); + lblStatus.setVisible(false); + + frame.getContentPane().add(lblStatus); + progressBar.setBounds(12, 110, 971, 15); + frame.getContentPane().add(progressBar); + + JButton btnExtract = new JButton("Extract!"); + btnExtract.setBounds(890, 9, 93, 45); + btnExtract.setEnabled(false); + + frame.getContentPane().add(btnExtract); + frame.validate(); + frame.repaint(); + tabbedPane.addMouseWheelListener(this); + + } + + @Override + public void update() { + frame.repaint(); + } + + @Override + public void mouseWheelMoved(MouseWheelEvent e) { + if(e.getSource() instanceof JTabbedPane) { + JTabbedPane pane = (JTabbedPane) e.getSource(); + Component scrolledComponent = pane.getComponentAt(e.getPoint()); + if(!(scrolledComponent instanceof FixedCellSizeGrid) && scrolledComponent.getParent() instanceof JTabbedPane) { + int units = e.getWheelRotation(); + System.out.println(units); + int oldIndex = pane.getSelectedIndex(); + int newIndex = oldIndex + units; + if(newIndex < 0) { + pane.setSelectedIndex(0); + } + else if (newIndex >= pane.getTabCount()) { + pane.setSelectedIndex(pane.getTabCount() - 1); + } + else { + pane.setSelectedIndex(newIndex); + } + } + else if(scrolledComponent instanceof FixedCellSizeGrid) { + FixedCellSizeGrid grid = (FixedCellSizeGrid) scrolledComponent; + grid.scroll(e.getWheelRotation()); + } + } + else { + //System.out.println(e.getSource()); + } + } + + private int getWantedThreads() { + int ret = threadSlider.getValue(); + if(ret < 1) { + return 1; + } + return ret; + } +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/package-info.java b/src/main/java/com/gamebuster19901/excite/modding/ui/package-info.java new file mode 100644 index 0000000..b7d428a --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/package-info.java @@ -0,0 +1 @@ +package com.gamebuster19901.excite.modding.ui; \ No newline at end of file diff --git a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Archive.java b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Archive.java index 4af6f2e..0260593 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Archive.java +++ b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Archive.java @@ -18,7 +18,7 @@ public class Archive { private final Path archiveFile; private final ResMonster archive; private final Toc toc; - private byte[] bytes; + private final byte[] bytes; private final LinkedHashMap files = new LinkedHashMap<>(); public Archive(Path archivePath, Path tocPath) throws IOException { @@ -29,6 +29,18 @@ public Archive(Path archivePath, Toc toc) throws IOException { this.archiveFile = archivePath; this.archive = ResMonster.fromFile(archivePath.toAbsolutePath().toString()); this.toc = toc; + if(isCompressed()) { + bytes = archive.data().compressedData().bytes(); + } + else { + bytes = archive.data().uncompressedData(); + } + if(bytes == null) { + throw new AssertionError(); + } + if(bytes.length == 0) { + throw new AssertionError(); + } for(TocMonster.Details fileDetails : getFileDetails()) { try { files.put(fileDetails.name(), new ArchivedFile(fileDetails, this)); @@ -37,6 +49,7 @@ public Archive(Path archivePath, Toc toc) throws IOException { //swallo } } + } public Toc getToc() { @@ -80,7 +93,7 @@ public long getHash() { } public boolean isCompressed() { - if (archive.header().compressed() == 128) { + if (((archive.header().compressed() >>> 7) & 1) != 0) { return true; } else if (archive.header().compressed() == 0) { @@ -92,14 +105,6 @@ else if (archive.header().compressed() == 0) { } public byte[] getBytes() { - if(bytes == null) { - if(isCompressed()) { - bytes = archive.data().compressedData().bytes(); - } - else { - bytes = archive.data().uncompressedData(); - } - } return Arrays.copyOf(bytes, bytes.length); } diff --git a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/ArchivedFile.java b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/ArchivedFile.java index b956de5..aa0d6eb 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/ArchivedFile.java +++ b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/ArchivedFile.java @@ -4,7 +4,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; -import java.util.Arrays; import com.gamebuster19901.excite.modding.game.file.kaitai.TocMonster; @@ -18,22 +17,17 @@ public ArchivedFile(TocMonster.Details fileDetails, Archive archive) { try { this.fileDetails = fileDetails; this.archive = archive; + System.out.println("Archive size: " + archive.getUncompressedSize()); System.out.println("File offset: " + fileDetails.fileOffset()); System.out.println("File size: " + fileDetails.fileSize()); System.out.println("File end: " + ((int)fileDetails.fileOffset() + (int)fileDetails.fileSize())); - System.out.println("Thread: " + Thread.currentThread().getName()); - System.out.println(archive.getBytes().length); - this.bytes = Arrays.copyOfRange(archive.getBytes(), (int)fileDetails.fileOffset(), (int)(fileDetails.fileOffset() + (int)fileDetails.fileSize())); + byte[] bytes = archive.getBytes(); + System.out.println("Array size: " + bytes.length); + this.bytes = copyOfRange(archive.getBytes(), (int)fileDetails.fileOffset(), (int)(fileDetails.fileOffset() + (int)fileDetails.fileSize())); } catch(Throwable t) { System.err.println("Could not extract resource " + getName() + " from " + archive.getArchiveFile().getFileName()); - java.util.Collection a1 = java.lang.Thread.getAllStackTraces().values(); - for (java.lang.StackTraceElement[] a2 : a1){ - System.out.println("========== "); - for (java.lang.StackTraceElement a3 : a2){ - System.out.println(a3.toString()); - } - } + t.printStackTrace(); throw t; } } @@ -54,4 +48,64 @@ public void writeTo(Path directory) throws IOException { Files.write(f, getBytes(), StandardOpenOption.CREATE); } + /** + * Copies the specified range of the specified array into a new array. + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). + * Values from subsequent elements in the original array are placed into + * subsequent elements in the copy. The final index of the range + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code (byte)0} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. + * + * @param original the array from which a range is to be copied + * @param from the initial index of the range to be copied, inclusive + * @param to the final index of the range to be copied, exclusive. + * (This index may lie outside the array.) + * @return a new array containing the specified range from the original array, + * truncated or padded with zeros to obtain the required length + * @throws ArrayIndexOutOfBoundsException if {@code from < 0} + * or {@code from > original.length} + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null + * @since 1.6 + */ + public static byte[] copyOfRange(byte[] original, int from, int to) { + // Tickle the JIT to fold special cases optimally + if (from != 0 || to != original.length) + return copyOfRangeByte(original, from, to); + else // from == 0 && to == original.length + return original.clone(); + } + + private static byte[] copyOfRangeByte(byte[] original, int from, int to) { + checkLength(from, to); + int newLength = to - from; + int calcedLength = original.length - from; + System.out.println("Original Length: " + original.length); + System.out.println("From: " + from); + System.out.println("To: " + to); + byte[] copy = new byte[newLength]; + try { + System.arraycopy(original, from, copy, 0, + Math.min(original.length - from, newLength)); + } + catch(ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + System.arraycopy(original, from, copy, 0, + Math.min(original.length - from, newLength)); + } + return copy; + } + + private static void checkLength(int from, int to) { + if (to < from) { + throw new IllegalArgumentException(from + " > " + to); + } + } + } diff --git a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java index 88d5ad7..c4db3ac 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java +++ b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java @@ -15,6 +15,7 @@ public class Unarchiver { private static final Path runDir = Path.of(".").resolve("run"); + private static final Path ripDir = runDir.resolve("rip"); public LinkedHashSet tocs = new LinkedHashSet<>(); public LinkedHashSet archives = new LinkedHashSet<>(); @@ -49,7 +50,7 @@ public void unarchive(Path tocFile) throws IOException { throw new FileNotFoundException("Resource file for toc " + tocFile); } - archive.writeTo(runDir); + archive.writeTo(ripDir); } @SuppressWarnings("resource") diff --git a/src/main/java/com/gamebuster19901/excite/modding/FileUtils.java b/src/main/java/com/gamebuster19901/excite/modding/util/FileUtils.java similarity index 95% rename from src/main/java/com/gamebuster19901/excite/modding/FileUtils.java rename to src/main/java/com/gamebuster19901/excite/modding/util/FileUtils.java index 2b20c6b..3923d4f 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/FileUtils.java +++ b/src/main/java/com/gamebuster19901/excite/modding/util/FileUtils.java @@ -1,4 +1,4 @@ -package com.gamebuster19901.excite.modding; +package com.gamebuster19901.excite.modding.util; import java.io.File; import java.io.IOError; @@ -65,7 +65,9 @@ public static String readNullTerminatedString(ByteBuffer buffer, Charset charset } public static Path createTempFile() throws IOException { - return Files.createTempFile(TEMP, null, null); + Path f = Files.createTempFile(TEMP, null, null); + System.out.println("Created temporary file " + f); + return f; } public static Path createTempFile(String name) throws IOException { diff --git a/src/main/java/com/gamebuster19901/excite/modding/util/SplitOutputStream.java b/src/main/java/com/gamebuster19901/excite/modding/util/SplitOutputStream.java new file mode 100644 index 0000000..97b322c --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/util/SplitOutputStream.java @@ -0,0 +1,73 @@ +package com.gamebuster19901.excite.modding.util; + +import java.io.IOException; +import java.io.OutputStream; + +public class SplitOutputStream extends OutputStream { + + private OutputStream[] outputs; + + public SplitOutputStream(OutputStream... consumers) { + this.outputs = consumers; + } + + public static SplitOutputStream splitSysOut(OutputStream... consumers) { + OutputStream original = System.out; + OutputStream[] outputs = new OutputStream[consumers.length + 1]; + outputs[0] = original; + + for(int i = 0; i < consumers.length; i++) { + outputs[i + 1] = consumers[i]; + } + + return new SplitOutputStream(outputs); + } + + public static SplitOutputStream splitErrOut(OutputStream... consumers) { + OutputStream original = System.err; + OutputStream[] outputs = new OutputStream[consumers.length + 1]; + outputs[0] = original; + + for(int i = 0; i < consumers.length; i++) { + outputs[i + 1] = consumers[i]; + } + + return new SplitOutputStream(outputs); + } + + @Override + public void write(int b) throws IOException { + for(OutputStream o : outputs) { + o.write(b); + } + } + + @Override + public void write(byte[] b) throws IOException { + for(OutputStream o : outputs) { + o.write(b); + } + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + for(OutputStream o : outputs) { + o.write(b, off, len); + } + } + + @Override + public void flush() throws IOException{ + for(OutputStream o : outputs) { + o.flush(); + } + } + + @Override + public void close() throws IOException { + for(OutputStream o : outputs) { + o.close(); + } + } + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/util/package-info.java b/src/main/java/com/gamebuster19901/excite/modding/util/package-info.java new file mode 100644 index 0000000..908c39e --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/util/package-info.java @@ -0,0 +1 @@ +package com.gamebuster19901.excite.modding.util; \ No newline at end of file diff --git a/src/main/resources/kaitai/monster_res.ksy b/src/main/resources/kaitai/monster_res.ksy index d92ce62..b7b5813 100644 --- a/src/main/resources/kaitai/monster_res.ksy +++ b/src/main/resources/kaitai/monster_res.ksy @@ -59,7 +59,7 @@ types: seq: - id: compressed_data type: quicklz_rcmp - if: _root.header.compressed == 128 + if: _root.header.compressed == 128 or _root.header.compressed == 1152 - id: uncompressed_data size-eos: true if: _root.header.compressed == 0 From a7e886b84a0f0487e595ca946e1c0b687195bb13 Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Fri, 19 Apr 2024 22:53:53 -0400 Subject: [PATCH 02/19] rm debug code --- .../modding/unarchiver/ArchivedFile.java | 63 +------------------ 1 file changed, 2 insertions(+), 61 deletions(-) diff --git a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/ArchivedFile.java b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/ArchivedFile.java index aa0d6eb..aaa5f5a 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/ArchivedFile.java +++ b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/ArchivedFile.java @@ -4,6 +4,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; +import java.util.Arrays; import com.gamebuster19901.excite.modding.game.file.kaitai.TocMonster; @@ -23,7 +24,7 @@ public ArchivedFile(TocMonster.Details fileDetails, Archive archive) { System.out.println("File end: " + ((int)fileDetails.fileOffset() + (int)fileDetails.fileSize())); byte[] bytes = archive.getBytes(); System.out.println("Array size: " + bytes.length); - this.bytes = copyOfRange(archive.getBytes(), (int)fileDetails.fileOffset(), (int)(fileDetails.fileOffset() + (int)fileDetails.fileSize())); + this.bytes = Arrays.copyOfRange(archive.getBytes(), (int)fileDetails.fileOffset(), (int)(fileDetails.fileOffset() + (int)fileDetails.fileSize())); } catch(Throwable t) { System.err.println("Could not extract resource " + getName() + " from " + archive.getArchiveFile().getFileName()); @@ -48,64 +49,4 @@ public void writeTo(Path directory) throws IOException { Files.write(f, getBytes(), StandardOpenOption.CREATE); } - /** - * Copies the specified range of the specified array into a new array. - * The initial index of the range ({@code from}) must lie between zero - * and {@code original.length}, inclusive. The value at - * {@code original[from]} is placed into the initial element of the copy - * (unless {@code from == original.length} or {@code from == to}). - * Values from subsequent elements in the original array are placed into - * subsequent elements in the copy. The final index of the range - * ({@code to}), which must be greater than or equal to {@code from}, - * may be greater than {@code original.length}, in which case - * {@code (byte)0} is placed in all elements of the copy whose index is - * greater than or equal to {@code original.length - from}. The length - * of the returned array will be {@code to - from}. - * - * @param original the array from which a range is to be copied - * @param from the initial index of the range to be copied, inclusive - * @param to the final index of the range to be copied, exclusive. - * (This index may lie outside the array.) - * @return a new array containing the specified range from the original array, - * truncated or padded with zeros to obtain the required length - * @throws ArrayIndexOutOfBoundsException if {@code from < 0} - * or {@code from > original.length} - * @throws IllegalArgumentException if {@code from > to} - * @throws NullPointerException if {@code original} is null - * @since 1.6 - */ - public static byte[] copyOfRange(byte[] original, int from, int to) { - // Tickle the JIT to fold special cases optimally - if (from != 0 || to != original.length) - return copyOfRangeByte(original, from, to); - else // from == 0 && to == original.length - return original.clone(); - } - - private static byte[] copyOfRangeByte(byte[] original, int from, int to) { - checkLength(from, to); - int newLength = to - from; - int calcedLength = original.length - from; - System.out.println("Original Length: " + original.length); - System.out.println("From: " + from); - System.out.println("To: " + to); - byte[] copy = new byte[newLength]; - try { - System.arraycopy(original, from, copy, 0, - Math.min(original.length - from, newLength)); - } - catch(ArrayIndexOutOfBoundsException e) { - e.printStackTrace(); - System.arraycopy(original, from, copy, 0, - Math.min(original.length - from, newLength)); - } - return copy; - } - - private static void checkLength(int from, int to) { - if (to < from) { - throw new IllegalArgumentException(from + " > " + to); - } - } - } From 929a55fb568f80b21a761311495cfeb83f3e89d8 Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Fri, 19 Apr 2024 22:54:31 -0400 Subject: [PATCH 03/19] more ui progress --- .../excite/modding/ui/Window.java | 169 +++++++++++------- 1 file changed, 104 insertions(+), 65 deletions(-) diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java index 9d34ba5..53510f1 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java @@ -28,18 +28,9 @@ import javax.swing.JScrollPane; import javax.swing.ScrollPaneConstants; import javax.swing.JPanel; -import java.awt.BorderLayout; -import javax.swing.JList; -import javax.swing.BoxLayout; -import com.jgoodies.forms.layout.FormLayout; -import com.jgoodies.forms.layout.ColumnSpec; -import com.jgoodies.forms.layout.RowSpec; import java.awt.GridLayout; -import javax.swing.GroupLayout; -import javax.swing.GroupLayout.Alignment; import java.awt.GridBagLayout; import java.awt.GridBagConstraints; -import java.awt.FlowLayout; import javax.swing.JTable; public class Window implements BatchListener, MouseWheelListener { @@ -154,7 +145,6 @@ private void initialize() throws InterruptedException { JPanel panel = new JPanel(); tabbedPane.addTab("Progress", null, panel, null); - panel.setLayout(new BorderLayout(0, 0)); //gridPanel.setPreferredSize(new Dimension(814, 406)); @@ -169,28 +159,30 @@ private void initialize() throws InterruptedException { } tabbedPane.addTab(c.getName(), null); } + panel.setLayout(new GridLayout(0, 2, 0, 0)); JPanel panel_1 = new JPanel(); - panel.add(panel_1, BorderLayout.CENTER); + panel.add(panel_1); GridBagLayout gbl_panel_1 = new GridBagLayout(); - gbl_panel_1.columnWidths = new int[]{0, 0, 70, 90, 0}; + gbl_panel_1.columnWidths = new int[]{100, 0, 70, 90, 0, 0}; gbl_panel_1.rowHeights = new int[]{0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - gbl_panel_1.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + gbl_panel_1.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; gbl_panel_1.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; panel_1.setLayout(gbl_panel_1); JLabel lblCopyOperation = new JLabel("Copy Operation"); GridBagConstraints gbc_lblCopyOperation = new GridBagConstraints(); - gbc_lblCopyOperation.gridwidth = 4; - gbc_lblCopyOperation.insets = new Insets(0, 0, 5, 5); + gbc_lblCopyOperation.gridwidth = 5; + gbc_lblCopyOperation.insets = new Insets(0, 0, 5, 0); gbc_lblCopyOperation.gridx = 0; gbc_lblCopyOperation.gridy = 0; panel_1.add(lblCopyOperation, gbc_lblCopyOperation); - BatchOperationComponent allBatches = new BatchOperationComponent(batchRunner, " All Batches "); + BatchOperationComponent allBatches = new BatchOperationComponent(batchRunner, "All Batches"); + allBatches.setToolTipText("All Batches"); GridBagConstraints gbc_allBatches = new GridBagConstraints(); - gbc_allBatches.fill = GridBagConstraints.VERTICAL; - gbc_allBatches.gridheight = 9; - gbc_allBatches.insets = new Insets(0, 0, 5, 5); + gbc_allBatches.fill = GridBagConstraints.BOTH; + gbc_allBatches.gridheight = 10; + gbc_allBatches.insets = new Insets(0, 0, 0, 5); gbc_allBatches.gridx = 0; gbc_allBatches.gridy = 1; panel_1.add(allBatches, gbc_allBatches); @@ -216,11 +208,18 @@ private void initialize() throws InterruptedException { JLabel lblTotalArchivesCount = new JLabel("0"); GridBagConstraints gbc_lblTotalArchivesCount = new GridBagConstraints(); gbc_lblTotalArchivesCount.anchor = GridBagConstraints.WEST; - gbc_lblTotalArchivesCount.insets = new Insets(0, 0, 5, 0); + gbc_lblTotalArchivesCount.insets = new Insets(0, 0, 5, 5); gbc_lblTotalArchivesCount.gridx = 3; gbc_lblTotalArchivesCount.gridy = 1; panel_1.add(lblTotalArchivesCount, gbc_lblTotalArchivesCount); + JLabel label_5 = new JLabel("100%"); + GridBagConstraints gbc_label_5 = new GridBagConstraints(); + gbc_label_5.insets = new Insets(0, 0, 5, 0); + gbc_label_5.gridx = 4; + gbc_label_5.gridy = 1; + panel_1.add(label_5, gbc_label_5); + JLabel lblTotalResources = new JLabel("Total Resources:"); lblTotalResources.setHorizontalAlignment(SwingConstants.RIGHT); GridBagConstraints gbc_lblTotalResources = new GridBagConstraints(); @@ -233,11 +232,18 @@ private void initialize() throws InterruptedException { JLabel lblTotalResourcesCount = new JLabel("0"); GridBagConstraints gbc_lblTotalResourcesCount = new GridBagConstraints(); gbc_lblTotalResourcesCount.anchor = GridBagConstraints.WEST; - gbc_lblTotalResourcesCount.insets = new Insets(0, 0, 5, 0); + gbc_lblTotalResourcesCount.insets = new Insets(0, 0, 5, 5); gbc_lblTotalResourcesCount.gridx = 3; gbc_lblTotalResourcesCount.gridy = 2; panel_1.add(lblTotalResourcesCount, gbc_lblTotalResourcesCount); + JLabel label_6 = new JLabel("100%"); + GridBagConstraints gbc_label_6 = new GridBagConstraints(); + gbc_label_6.insets = new Insets(0, 0, 5, 0); + gbc_label_6.gridx = 4; + gbc_label_6.gridy = 2; + panel_1.add(label_6, gbc_label_6); + JLabel lblArchivesCopied = new JLabel("Archives Copied:"); GridBagConstraints gbc_lblArchivesCopied = new GridBagConstraints(); gbc_lblArchivesCopied.anchor = GridBagConstraints.EAST; @@ -246,14 +252,21 @@ private void initialize() throws InterruptedException { gbc_lblArchivesCopied.gridy = 4; panel_1.add(lblArchivesCopied, gbc_lblArchivesCopied); - JLabel label_1 = new JLabel("0 (0%)"); + JLabel label_1 = new JLabel("99"); GridBagConstraints gbc_label_1 = new GridBagConstraints(); gbc_label_1.anchor = GridBagConstraints.WEST; - gbc_label_1.insets = new Insets(0, 0, 5, 0); + gbc_label_1.insets = new Insets(0, 0, 5, 5); gbc_label_1.gridx = 3; gbc_label_1.gridy = 4; panel_1.add(label_1, gbc_label_1); + JLabel label_7 = new JLabel("0%"); + GridBagConstraints gbc_label_7 = new GridBagConstraints(); + gbc_label_7.insets = new Insets(0, 0, 5, 0); + gbc_label_7.gridx = 4; + gbc_label_7.gridy = 4; + panel_1.add(label_7, gbc_label_7); + JLabel lblResourcesCopied = new JLabel("Resources Copied:"); GridBagConstraints gbc_lblResourcesCopied = new GridBagConstraints(); gbc_lblResourcesCopied.anchor = GridBagConstraints.EAST; @@ -262,30 +275,20 @@ private void initialize() throws InterruptedException { gbc_lblResourcesCopied.gridy = 5; panel_1.add(lblResourcesCopied, gbc_lblResourcesCopied); - JLabel label_2 = new JLabel("0 (0%)"); + JLabel label_2 = new JLabel("0"); GridBagConstraints gbc_label_2 = new GridBagConstraints(); gbc_label_2.anchor = GridBagConstraints.WEST; - gbc_label_2.insets = new Insets(0, 0, 5, 0); + gbc_label_2.insets = new Insets(0, 0, 5, 5); gbc_label_2.gridx = 3; gbc_label_2.gridy = 5; panel_1.add(label_2, gbc_label_2); - JLabel lblArchivesProcessed = new JLabel("Archives Processed:"); - lblArchivesProcessed.setHorizontalAlignment(SwingConstants.RIGHT); - GridBagConstraints gbc_lblArchivesProcessed = new GridBagConstraints(); - gbc_lblArchivesProcessed.anchor = GridBagConstraints.EAST; - gbc_lblArchivesProcessed.insets = new Insets(0, 0, 5, 5); - gbc_lblArchivesProcessed.gridx = 2; - gbc_lblArchivesProcessed.gridy = 7; - panel_1.add(lblArchivesProcessed, gbc_lblArchivesProcessed); - - JLabel lblArchivesprocessed = new JLabel("0 (0%)"); - GridBagConstraints gbc_lblArchivesprocessed = new GridBagConstraints(); - gbc_lblArchivesprocessed.insets = new Insets(0, 0, 5, 0); - gbc_lblArchivesprocessed.anchor = GridBagConstraints.WEST; - gbc_lblArchivesprocessed.gridx = 3; - gbc_lblArchivesprocessed.gridy = 7; - panel_1.add(lblArchivesprocessed, gbc_lblArchivesprocessed); + JLabel label_8 = new JLabel("0%"); + GridBagConstraints gbc_label_8 = new GridBagConstraints(); + gbc_label_8.insets = new Insets(0, 0, 5, 0); + gbc_label_8.gridx = 4; + gbc_label_8.gridy = 5; + panel_1.add(label_8, gbc_label_8); JLabel lblArchivesProcessed_1 = new JLabel("Archives Skipped:"); lblArchivesProcessed_1.setHorizontalAlignment(SwingConstants.RIGHT); @@ -296,29 +299,20 @@ private void initialize() throws InterruptedException { gbc_lblArchivesProcessed_1.gridy = 8; panel_1.add(lblArchivesProcessed_1, gbc_lblArchivesProcessed_1); - JLabel label_3 = new JLabel("0 (0%)"); + JLabel label_3 = new JLabel("0"); GridBagConstraints gbc_label_3 = new GridBagConstraints(); gbc_label_3.anchor = GridBagConstraints.WEST; - gbc_label_3.insets = new Insets(0, 0, 5, 0); + gbc_label_3.insets = new Insets(0, 0, 5, 5); gbc_label_3.gridx = 3; gbc_label_3.gridy = 8; panel_1.add(label_3, gbc_label_3); - JLabel lblResourcesProcessed = new JLabel("Resources Processed:"); - GridBagConstraints gbc_lblResourcesProcessed = new GridBagConstraints(); - gbc_lblResourcesProcessed.anchor = GridBagConstraints.EAST; - gbc_lblResourcesProcessed.insets = new Insets(0, 0, 5, 5); - gbc_lblResourcesProcessed.gridx = 2; - gbc_lblResourcesProcessed.gridy = 9; - panel_1.add(lblResourcesProcessed, gbc_lblResourcesProcessed); - - JLabel label = new JLabel("100 (100%)"); - GridBagConstraints gbc_label = new GridBagConstraints(); - gbc_label.insets = new Insets(0, 0, 5, 0); - gbc_label.anchor = GridBagConstraints.WEST; - gbc_label.gridx = 3; - gbc_label.gridy = 9; - panel_1.add(label, gbc_label); + JLabel label_10 = new JLabel("0%"); + GridBagConstraints gbc_label_10 = new GridBagConstraints(); + gbc_label_10.insets = new Insets(0, 0, 5, 0); + gbc_label_10.gridx = 4; + gbc_label_10.gridy = 8; + panel_1.add(label_10, gbc_label_10); JLabel lblResourcesSkipped = new JLabel("Resources Skipped"); GridBagConstraints gbc_lblResourcesSkipped = new GridBagConstraints(); @@ -328,28 +322,73 @@ private void initialize() throws InterruptedException { gbc_lblResourcesSkipped.gridy = 10; panel_1.add(lblResourcesSkipped, gbc_lblResourcesSkipped); - JLabel label_4 = new JLabel("0 (0%)"); + JLabel label_4 = new JLabel("0"); GridBagConstraints gbc_label_4 = new GridBagConstraints(); + gbc_label_4.insets = new Insets(0, 0, 0, 5); gbc_label_4.anchor = GridBagConstraints.WEST; gbc_label_4.gridx = 3; gbc_label_4.gridy = 10; panel_1.add(label_4, gbc_label_4); JPanel panel_2 = new JPanel(); - panel.add(panel_2, BorderLayout.EAST); + panel.add(panel_2); GridBagLayout gbl_panel_2 = new GridBagLayout(); - gbl_panel_2.columnWidths = new int[]{0, 0}; - gbl_panel_2.rowHeights = new int[]{0, 0}; - gbl_panel_2.columnWeights = new double[]{0.0, Double.MIN_VALUE}; - gbl_panel_2.rowWeights = new double[]{0.0, Double.MIN_VALUE}; + gbl_panel_2.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0}; + gbl_panel_2.rowHeights = new int[]{0, 0, 0, 0, 0, 0}; + gbl_panel_2.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + gbl_panel_2.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; panel_2.setLayout(gbl_panel_2); - JLabel lblNewLabel = new JLabel("New label"); + JLabel lblNewLabel = new JLabel("Process Operation"); GridBagConstraints gbc_lblNewLabel = new GridBagConstraints(); + gbc_lblNewLabel.insets = new Insets(0, 0, 5, 5); gbc_lblNewLabel.gridx = 0; gbc_lblNewLabel.gridy = 0; panel_2.add(lblNewLabel, gbc_lblNewLabel); + JLabel lblArchivesProcessed = new JLabel("Archives Processed:"); + GridBagConstraints gbc_lblArchivesProcessed = new GridBagConstraints(); + gbc_lblArchivesProcessed.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesProcessed.gridx = 1; + gbc_lblArchivesProcessed.gridy = 3; + panel_2.add(lblArchivesProcessed, gbc_lblArchivesProcessed); + lblArchivesProcessed.setHorizontalAlignment(SwingConstants.RIGHT); + + JLabel lblArchivesprocessed = new JLabel("0"); + GridBagConstraints gbc_lblArchivesprocessed = new GridBagConstraints(); + gbc_lblArchivesprocessed.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesprocessed.gridx = 2; + gbc_lblArchivesprocessed.gridy = 3; + panel_2.add(lblArchivesprocessed, gbc_lblArchivesprocessed); + + JLabel label_9 = new JLabel("0%"); + GridBagConstraints gbc_label_9 = new GridBagConstraints(); + gbc_label_9.insets = new Insets(0, 0, 5, 5); + gbc_label_9.gridx = 3; + gbc_label_9.gridy = 3; + panel_2.add(label_9, gbc_label_9); + + JLabel lblResourcesProcessed = new JLabel("Resources Processed:"); + GridBagConstraints gbc_lblResourcesProcessed = new GridBagConstraints(); + gbc_lblResourcesProcessed.insets = new Insets(0, 0, 0, 5); + gbc_lblResourcesProcessed.gridx = 1; + gbc_lblResourcesProcessed.gridy = 4; + panel_2.add(lblResourcesProcessed, gbc_lblResourcesProcessed); + + JLabel label = new JLabel("100"); + GridBagConstraints gbc_label = new GridBagConstraints(); + gbc_label.insets = new Insets(0, 0, 0, 5); + gbc_label.gridx = 2; + gbc_label.gridy = 4; + panel_2.add(label, gbc_label); + + JLabel label_11 = new JLabel("0%"); + GridBagConstraints gbc_label_11 = new GridBagConstraints(); + gbc_label_11.insets = new Insets(0, 0, 0, 5); + gbc_label_11.gridx = 3; + gbc_label_11.gridy = 4; + panel_2.add(label_11, gbc_label_11); + threadSlider = new JSlider(); threadSlider.getSnapToTicks(); threadSlider.setMinimum(1); From 88a65387c05837ecc72ef7ef212550b5060b8704 Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Sun, 21 Apr 2024 20:01:05 -0400 Subject: [PATCH 04/19] Organize the window initialization code --- .../excite/modding/concurrent/Batch.java | 12 + .../modding/concurrent/BatchContainer.java | 2 + .../modding/concurrent/BatchRunner.java | 21 +- .../modding/ui/BatchOperationComponent.java | 27 +- .../modding/ui/BatchedImageComponent.java | 6 +- .../excite/modding/ui/FixedCellGrid.java | 44 +++- .../excite/modding/ui/ImageComponent.java | 7 +- .../excite/modding/ui/Window.java | 238 +++++++++++------- 8 files changed, 247 insertions(+), 110 deletions(-) diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java index 51f57b9..4da026d 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java @@ -10,11 +10,21 @@ public class Batch implements Batcher { + private final String name; private final Set runnables = new HashSet<>(); private final LinkedHashSet listeners = new LinkedHashSet<>(); private volatile boolean accepting = true; + public Batch(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + @Override public void addRunnable(Callable runnable) { if(accepting) { BatchedCallable b = new BatchedCallable(runnable); @@ -26,6 +36,7 @@ public void addRunnable(Callable runnable) { } } + @Override public void addRunnable(Runnable runnable) { if(accepting) { BatchedCallable b = new BatchedCallable(runnable); @@ -37,6 +48,7 @@ public void addRunnable(Runnable runnable) { } } + @Override public void addListener(BatchListener listener) { if(accepting) { if(!listeners.add(listener)) { diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java index 3a2ab37..c2332dd 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java @@ -5,6 +5,8 @@ import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; public interface BatchContainer { + + public abstract String getName(); public Collection getRunnables(); diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java index 3d224df..a369f27 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java @@ -9,21 +9,28 @@ public class BatchRunner implements BatchWorker { + private final String name; private final ExecutorService executor; private final LinkedHashSet batches = new LinkedHashSet(); private volatile boolean started = false; - public BatchRunner() { - this(Runtime.getRuntime().availableProcessors()); + public BatchRunner(String name) { + this(name, Runtime.getRuntime().availableProcessors()); } - public BatchRunner(int threads) throws IllegalArgumentException { - this(Executors.newFixedThreadPool(threads)); + public BatchRunner(String name, int threads) throws IllegalArgumentException { + this(name, Executors.newFixedThreadPool(threads)); } - public BatchRunner(ExecutorService executor) { + public BatchRunner(String name, ExecutorService executor) { + this.name = name; this.executor = executor; } + + @Override + public String getName() { + return name; + } @Override public void addBatch(Batcher batcher) { @@ -89,6 +96,10 @@ public Collection getListeners() { return ret; } } + + public Collection getBatches() { + return (Collection) batches.clone(); + } public int getCompleted() { int ret = 0; diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchOperationComponent.java b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchOperationComponent.java index 4d2d545..94c7be9 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchOperationComponent.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchOperationComponent.java @@ -2,31 +2,36 @@ import javax.swing.JPanel; +import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; import com.gamebuster19901.excite.modding.concurrent.BatchContainer; - +import com.gamebuster19901.excite.modding.concurrent.BatchListener; import java.awt.BorderLayout; +import java.util.Collection; + import javax.swing.JLabel; import javax.swing.SwingConstants; -public class BatchOperationComponent extends JPanel { +public class BatchOperationComponent extends JPanel implements BatchContainer { private BatchedImageComponent batch; - private String name; private JLabel fileName; - public BatchOperationComponent(BatchContainer batch, String name) { - this(new BatchedImageComponent(batch), name); + public BatchOperationComponent(BatchContainer batch) { + this(new BatchedImageComponent(batch)); + setName(batch.getName()); } /** @wbp.parser.constructor **/ - public BatchOperationComponent(BatchedImageComponent batch, String name) { + public BatchOperationComponent(BatchedImageComponent batch) { this.batch = batch; setLayout(new BorderLayout(0, 0)); add(batch, BorderLayout.CENTER); + String name = batch.getName(); + fileName = new JLabel(name); fileName.setHorizontalAlignment(SwingConstants.CENTER); add(fileName, BorderLayout.SOUTH); @@ -39,5 +44,15 @@ public void setName(String name) { this.setToolTipText(name); this.fileName.setText(name); } + + @Override + public Collection getRunnables() { + return batch.getRunnables(); + } + + @Override + public Collection getListeners() { + return batch.getListeners(); + } } diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java index 19f783b..6f834e6 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java @@ -5,7 +5,6 @@ import java.util.Collection; import java.util.LinkedHashMap; import com.gamebuster19901.excite.modding.concurrent.BatchListener; -import com.gamebuster19901.excite.modding.concurrent.Batch; import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; import com.gamebuster19901.excite.modding.concurrent.BatchContainer; @@ -13,11 +12,8 @@ public class BatchedImageComponent extends ImageComponent implements BatchContai private final BatchContainer batch; - public BatchedImageComponent() { - this(new Batch()); - } - public BatchedImageComponent(BatchContainer batch) { + super(batch.getName()); this.batch = batch; } diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/FixedCellGrid.java b/src/main/java/com/gamebuster19901/excite/modding/ui/FixedCellGrid.java index 74e9480..27c6fc7 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/FixedCellGrid.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/FixedCellGrid.java @@ -1,6 +1,8 @@ package com.gamebuster19901.excite.modding.ui; import java.awt.Component; +import java.util.Iterator; +import java.util.Map.Entry; import java.util.NavigableSet; import java.util.TreeMap; @@ -23,7 +25,6 @@ protected void paintComponent(Graphics g) { components.forEach((index, component) -> { component.setBounds(calculateCellX(index), calculateCellY(index), getCellWidth(), getCellHeight()); - //System.out.println("Rendering component " + index + " at " + component.getX() + ", " + component.getY()); }); } @@ -59,6 +60,20 @@ public final Component putComponent(Integer index, Component component) { return components.put(index, component); } + public final void removeComponent(Integer index) { + Component toRemove = getComponent(index); + if(toRemove != null) { + components.remove(index); //we want to remove from the grid directly since it will be much faster than the overridden FixedCellGrid.remove() + super.remove(toRemove); //Then use super to remove the component reference from swing + } + } + + @Override + public void removeAll() { + components.clear(); + super.removeAll(); + } + public final int getLowestFreeCell() { Integer prevIndex = 0; Integer index = -1; @@ -96,6 +111,33 @@ public Component add(Component component) { putComponent(getLowestFreeCell(), component); return component; } + + @Override + @Deprecated + public Component add(Component component, int index) { + putComponent(index, component); + return component; + } + + @Override + @Deprecated + public void remove(Component component) { + Iterator> set = components.entrySet().iterator(); + while(set.hasNext()) { + Entry e = set.next(); + if(e.getValue() == component) { + set.remove(); + break; + } + } + super.remove(component); + } + + @Override + @Deprecated + public void remove(int index) { + removeComponent(index); + } @Override @Deprecated diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/ImageComponent.java b/src/main/java/com/gamebuster19901/excite/modding/ui/ImageComponent.java index 2c79444..fe910d0 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/ImageComponent.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/ImageComponent.java @@ -9,11 +9,12 @@ public class ImageComponent extends JComponent { Image image = null; - public ImageComponent() { - this(null); + public ImageComponent(String name) { + this(name, null); } - public ImageComponent(Image image) { + public ImageComponent(String name, Image image) { + this.setName(name); this.image = image; } diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java index 53510f1..06cc76c 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java @@ -7,31 +7,36 @@ import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.io.PrintStream; +import java.util.Collection; +import java.util.Iterator; import javax.swing.JFrame; import com.gamebuster19901.excite.modding.concurrent.BatchListener; import com.gamebuster19901.excite.modding.concurrent.BatchRunner; +import com.gamebuster19901.excite.modding.concurrent.Batcher; import com.gamebuster19901.excite.modding.util.SplitOutputStream; import com.gamebuster19901.excite.modding.concurrent.Batch; +import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; +import com.gamebuster19901.excite.modding.concurrent.BatchContainer; import javax.swing.JTextField; +import javax.swing.ScrollPaneConstants; import javax.swing.UIManager; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JSeparator; import javax.swing.JTabbedPane; -import javax.swing.JTextArea; import javax.swing.JSlider; import javax.swing.JProgressBar; -import javax.swing.SwingConstants; import javax.swing.JScrollPane; -import javax.swing.ScrollPaneConstants; +import javax.swing.SwingConstants; import javax.swing.JPanel; import java.awt.GridLayout; import java.awt.GridBagLayout; import java.awt.GridBagConstraints; import javax.swing.JTable; +import javax.swing.JTextArea; public class Window implements BatchListener, MouseWheelListener { @@ -45,9 +50,13 @@ public class Window implements BatchListener, MouseWheelListener { private JSlider threadSlider; private JLabel lblThreads; private static Window window; - private final JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP); private final JProgressBar progressBar = new JProgressBar(); + private final JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP); + private final FixedCellGrid gridPanel = genGridPanel(); private JTable table; + + private BatchRunner copyOperations; + private BatchRunner processOperations; /** * Launch the application. @@ -81,6 +90,14 @@ public Window() throws InterruptedException { * @throws InterruptedException */ private void initialize() throws InterruptedException { + + copyOperations = genCopyBatches(); + + setupFrame(); + setupTabbedPane(); + } + + private void setupFrame() { frame = new JFrame(); frame.setTitle("ExciteModder"); frame.setBounds(100, 100, 1000, 680); @@ -118,19 +135,68 @@ private void initialize() throws InterruptedException { btnChangeDest.setToolTipText("Change where ExciteModder will copy the game files to"); btnChangeDest.setBounds(761, 36, 117, 19); frame.getContentPane().add(btnChangeDest); + + threadSlider = new JSlider(); + threadSlider.getSnapToTicks(); + threadSlider.setMinimum(1); + threadSlider.setMaximum(Runtime.getRuntime().availableProcessors()); + threadSlider.setValue(Math.max(1, Runtime.getRuntime().availableProcessors() / 2)); + threadSlider.setBounds(5, 90, 92, 16); + threadSlider.addChangeListener((s) -> { + if(lblThreads != null) { + lblThreads.setText("Threads: " + threadSlider.getValue()); + } + }); + frame.getContentPane().add(threadSlider); + + lblThreads = new JLabel("Threads: " + threadSlider.getValue()); + lblThreads.setBounds(12, 74, 132, 15); + frame.getContentPane().add(lblThreads); + + JSeparator separator = new JSeparator(); + separator.setBounds(12, 64, 971, 2); + frame.getContentPane().add(separator); + + progressBar.setVisible(false); + + JLabel lblStatus = new JLabel("Progress: 0%"); + lblStatus.setHorizontalAlignment(SwingConstants.CENTER); + lblStatus.setBounds(440, 110, 120, 15); + lblStatus.setVisible(false); + + frame.getContentPane().add(lblStatus); + progressBar.setBounds(12, 110, 971, 15); + frame.getContentPane().add(progressBar); + + JButton btnExtract = new JButton("Extract!"); + btnExtract.setBounds(890, 9, 93, 45); + btnExtract.setEnabled(false); + + frame.getContentPane().add(btnExtract); + frame.validate(); + frame.repaint(); + tabbedPane.addMouseWheelListener(this); + } + + private void setupTabbedPane() { tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); tabbedPane.setBounds(0, 129, 1000, 511); frame.getContentPane().add(tabbedPane); - - + setupConsoleOutputTab(); + setupStatusTab(); + setupProgressTab(); - FixedCellGrid gridPanel = new FixedCellSizeGrid(new Dimension(385, 385), new Dimension(100, 100), 0); - - gridPanel.setVisible(true); - gridPanel.components.remove(-1); + for(Batcher b : copyOperations.getBatches()) { + tabbedPane.addTab(b.getName(), null); + } + } + + private void setupConsoleOutputTab() { + JPanel consolePanel = new JPanel(); + consolePanel.setLayout(new GridLayout(0, 2, 0, 0)); JTextArea textArea = new JTextArea(); textArea.setBorder(BorderFactory.createLoweredBevelBorder()); textArea.setOpaque(true); @@ -141,51 +207,55 @@ private void initialize() throws InterruptedException { JScrollPane scrollPane = new JScrollPane(textArea); scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); tabbedPane.addTab("Console Output", null, scrollPane, null); + } + + public void setupStatusTab() { tabbedPane.addTab("Status", null, gridPanel, null); - - JPanel panel = new JPanel(); - tabbedPane.addTab("Progress", null, panel, null); - - //gridPanel.setPreferredSize(new Dimension(814, 406)); - - BatchRunner batchRunner = new BatchRunner(); - for(int i = 0; i < 10; i++) { - Batch b = new Batch(); - batchRunner.addBatch(b); - BatchOperationComponent c = new BatchOperationComponent(b, "File " + i); - gridPanel.putComponent(i, c); - if(i == 5) { - c.setName("A very long file name"); - } - tabbedPane.addTab(c.getName(), null); + Iterator batches = copyOperations.getBatches().iterator(); + int i = 0; + while(batches.hasNext()) { + gridPanel.putComponent(i, new BatchOperationComponent(batches.next())); + i++; } - panel.setLayout(new GridLayout(0, 2, 0, 0)); + } + + public void setupProgressTab() { + JPanel progressPanel = new JPanel(); + tabbedPane.addTab("Progress", null, progressPanel, null); + + progressPanel.setLayout(new GridLayout(0, 2, 0, 0)); + setupLeftProgressPane(progressPanel); + setupRightProgressPane(progressPanel); + + } + + private void setupLeftProgressPane(JPanel progressPanel) { JPanel panel_1 = new JPanel(); - panel.add(panel_1); + progressPanel.add(panel_1); GridBagLayout gbl_panel_1 = new GridBagLayout(); - gbl_panel_1.columnWidths = new int[]{100, 0, 70, 90, 0, 0}; - gbl_panel_1.rowHeights = new int[]{0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + gbl_panel_1.columnWidths = new int[] {100, 0, 70, 90, 0, 0, 0}; + gbl_panel_1.rowHeights = new int[] {0, 15, 0, 30, 0, 0, 30, 30, 0, 0, 30, 0}; gbl_panel_1.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; gbl_panel_1.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; panel_1.setLayout(gbl_panel_1); JLabel lblCopyOperation = new JLabel("Copy Operation"); GridBagConstraints gbc_lblCopyOperation = new GridBagConstraints(); - gbc_lblCopyOperation.gridwidth = 5; + gbc_lblCopyOperation.gridwidth = 6; gbc_lblCopyOperation.insets = new Insets(0, 0, 5, 0); gbc_lblCopyOperation.gridx = 0; gbc_lblCopyOperation.gridy = 0; panel_1.add(lblCopyOperation, gbc_lblCopyOperation); - BatchOperationComponent allBatches = new BatchOperationComponent(batchRunner, "All Batches"); - allBatches.setToolTipText("All Batches"); + BatchOperationComponent allBatchesCopy = new BatchOperationComponent(copyOperations); + allBatchesCopy.setToolTipText("All Batches"); GridBagConstraints gbc_allBatches = new GridBagConstraints(); gbc_allBatches.fill = GridBagConstraints.BOTH; - gbc_allBatches.gridheight = 10; + gbc_allBatches.gridheight = 9; gbc_allBatches.insets = new Insets(0, 0, 0, 5); gbc_allBatches.gridx = 0; gbc_allBatches.gridy = 1; - panel_1.add(allBatches, gbc_allBatches); + panel_1.add(allBatchesCopy, gbc_allBatches); JSeparator separator_1 = new JSeparator(); GridBagConstraints gbc_separator_1 = new GridBagConstraints(); @@ -314,33 +384,36 @@ private void initialize() throws InterruptedException { gbc_label_10.gridy = 8; panel_1.add(label_10, gbc_label_10); - JLabel lblResourcesSkipped = new JLabel("Resources Skipped"); + JLabel lblResourcesSkipped = new JLabel("Resources Skipped:"); GridBagConstraints gbc_lblResourcesSkipped = new GridBagConstraints(); gbc_lblResourcesSkipped.anchor = GridBagConstraints.EAST; - gbc_lblResourcesSkipped.insets = new Insets(0, 0, 0, 5); + gbc_lblResourcesSkipped.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesSkipped.gridx = 2; - gbc_lblResourcesSkipped.gridy = 10; + gbc_lblResourcesSkipped.gridy = 9; panel_1.add(lblResourcesSkipped, gbc_lblResourcesSkipped); JLabel label_4 = new JLabel("0"); GridBagConstraints gbc_label_4 = new GridBagConstraints(); - gbc_label_4.insets = new Insets(0, 0, 0, 5); + gbc_label_4.insets = new Insets(0, 0, 5, 5); gbc_label_4.anchor = GridBagConstraints.WEST; gbc_label_4.gridx = 3; - gbc_label_4.gridy = 10; + gbc_label_4.gridy = 9; panel_1.add(label_4, gbc_label_4); - + } + + private void setupRightProgressPane(JPanel progressPanel) { JPanel panel_2 = new JPanel(); - panel.add(panel_2); + progressPanel.add(panel_2); GridBagLayout gbl_panel_2 = new GridBagLayout(); - gbl_panel_2.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0}; - gbl_panel_2.rowHeights = new int[]{0, 0, 0, 0, 0, 0}; + gbl_panel_2.columnWidths = new int[] {30, 0, 0, 0, 30, 30, 0, 0}; + gbl_panel_2.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0}; gbl_panel_2.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; - gbl_panel_2.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + gbl_panel_2.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; panel_2.setLayout(gbl_panel_2); JLabel lblNewLabel = new JLabel("Process Operation"); GridBagConstraints gbc_lblNewLabel = new GridBagConstraints(); + gbc_lblNewLabel.gridwidth = 7; gbc_lblNewLabel.insets = new Insets(0, 0, 5, 5); gbc_lblNewLabel.gridx = 0; gbc_lblNewLabel.gridy = 0; @@ -370,66 +443,44 @@ private void initialize() throws InterruptedException { JLabel lblResourcesProcessed = new JLabel("Resources Processed:"); GridBagConstraints gbc_lblResourcesProcessed = new GridBagConstraints(); - gbc_lblResourcesProcessed.insets = new Insets(0, 0, 0, 5); + gbc_lblResourcesProcessed.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesProcessed.gridx = 1; gbc_lblResourcesProcessed.gridy = 4; panel_2.add(lblResourcesProcessed, gbc_lblResourcesProcessed); JLabel label = new JLabel("100"); GridBagConstraints gbc_label = new GridBagConstraints(); - gbc_label.insets = new Insets(0, 0, 0, 5); + gbc_label.insets = new Insets(0, 0, 5, 5); gbc_label.gridx = 2; gbc_label.gridy = 4; panel_2.add(label, gbc_label); JLabel label_11 = new JLabel("0%"); GridBagConstraints gbc_label_11 = new GridBagConstraints(); - gbc_label_11.insets = new Insets(0, 0, 0, 5); + gbc_label_11.insets = new Insets(0, 0, 5, 5); gbc_label_11.gridx = 3; gbc_label_11.gridy = 4; panel_2.add(label_11, gbc_label_11); - - threadSlider = new JSlider(); - threadSlider.getSnapToTicks(); - threadSlider.setMinimum(1); - threadSlider.setMaximum(Runtime.getRuntime().availableProcessors()); - threadSlider.setValue(Math.max(1, Runtime.getRuntime().availableProcessors() / 2)); - threadSlider.setBounds(5, 90, 92, 16); - threadSlider.addChangeListener((s) -> { - if(lblThreads != null) { - lblThreads.setText("Threads: " + threadSlider.getValue()); - } - }); - frame.getContentPane().add(threadSlider); - - lblThreads = new JLabel("Threads: " + threadSlider.getValue()); - lblThreads.setBounds(12, 74, 132, 15); - frame.getContentPane().add(lblThreads); - - JSeparator separator = new JSeparator(); - separator.setBounds(12, 64, 971, 2); - frame.getContentPane().add(separator); - - progressBar.setVisible(false); - - JLabel lblStatus = new JLabel("Progress: 0%"); - lblStatus.setHorizontalAlignment(SwingConstants.CENTER); - lblStatus.setBounds(440, 110, 120, 15); - lblStatus.setVisible(false); - - frame.getContentPane().add(lblStatus); - progressBar.setBounds(12, 110, 971, 15); - frame.getContentPane().add(progressBar); - - JButton btnExtract = new JButton("Extract!"); - btnExtract.setBounds(890, 9, 93, 45); - btnExtract.setEnabled(false); - - frame.getContentPane().add(btnExtract); - frame.validate(); - frame.repaint(); - tabbedPane.addMouseWheelListener(this); - + } + + private BatchRunner genCopyBatches() { + BatchRunner batchRunner = new BatchRunner("Copy Operations"); + for(int i = 0; i < 10; i++) { + Batch b = new Batch("File " + i); + batchRunner.addBatch(b); + } + return batchRunner; + } + + private void setGridBatches(BatchContainer batch, FixedCellGrid grid) { + Collection batches = batch.getRunnables(); + for(int i = 0; i < batches.size(); i++) { + tabbedPane.addTab("File " + i, new BatchOperationComponent(batch)); + } + } + + private BatchRunner getProcessBatches() { + throw new UnsupportedOperationException("Not yet implemented"); } @Override @@ -467,6 +518,13 @@ else if(scrolledComponent instanceof FixedCellSizeGrid) { } } + private FixedCellGrid genGridPanel() { + FixedCellGrid gridPanel = new FixedCellSizeGrid(new Dimension(385, 385), new Dimension(100, 100), 0); + gridPanel.setVisible(true); + + return gridPanel; + } + private int getWantedThreads() { int ret = threadSlider.getValue(); if(ret < 1) { From 5dbad9d2b094081ef03860f025ca430a78be2404 Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Sun, 21 Apr 2024 20:30:07 -0400 Subject: [PATCH 05/19] More organization and renaming varialbes --- .../excite/modding/ui/Window.java | 404 +++++++++++++----- 1 file changed, 286 insertions(+), 118 deletions(-) diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java index 06cc76c..72c18ce 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java @@ -235,15 +235,15 @@ private void setupLeftProgressPane(JPanel progressPanel) { progressPanel.add(panel_1); GridBagLayout gbl_panel_1 = new GridBagLayout(); gbl_panel_1.columnWidths = new int[] {100, 0, 70, 90, 0, 0, 0}; - gbl_panel_1.rowHeights = new int[] {0, 15, 0, 30, 0, 0, 30, 30, 0, 0, 30, 0}; + gbl_panel_1.rowHeights = new int[] {0, 15, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0}; gbl_panel_1.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; - gbl_panel_1.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + gbl_panel_1.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; panel_1.setLayout(gbl_panel_1); JLabel lblCopyOperation = new JLabel("Copy Operation"); GridBagConstraints gbc_lblCopyOperation = new GridBagConstraints(); gbc_lblCopyOperation.gridwidth = 6; - gbc_lblCopyOperation.insets = new Insets(0, 0, 5, 0); + gbc_lblCopyOperation.insets = new Insets(0, 0, 5, 5); gbc_lblCopyOperation.gridx = 0; gbc_lblCopyOperation.gridy = 0; panel_1.add(lblCopyOperation, gbc_lblCopyOperation); @@ -251,8 +251,8 @@ private void setupLeftProgressPane(JPanel progressPanel) { allBatchesCopy.setToolTipText("All Batches"); GridBagConstraints gbc_allBatches = new GridBagConstraints(); gbc_allBatches.fill = GridBagConstraints.BOTH; - gbc_allBatches.gridheight = 9; - gbc_allBatches.insets = new Insets(0, 0, 0, 5); + gbc_allBatches.gridheight = 11; + gbc_allBatches.insets = new Insets(0, 0, 0, 0); gbc_allBatches.gridx = 0; gbc_allBatches.gridy = 1; panel_1.add(allBatchesCopy, gbc_allBatches); @@ -283,21 +283,14 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblTotalArchivesCount.gridy = 1; panel_1.add(lblTotalArchivesCount, gbc_lblTotalArchivesCount); - JLabel label_5 = new JLabel("100%"); - GridBagConstraints gbc_label_5 = new GridBagConstraints(); - gbc_label_5.insets = new Insets(0, 0, 5, 0); - gbc_label_5.gridx = 4; - gbc_label_5.gridy = 1; - panel_1.add(label_5, gbc_label_5); - - JLabel lblTotalResources = new JLabel("Total Resources:"); - lblTotalResources.setHorizontalAlignment(SwingConstants.RIGHT); - GridBagConstraints gbc_lblTotalResources = new GridBagConstraints(); - gbc_lblTotalResources.anchor = GridBagConstraints.EAST; - gbc_lblTotalResources.insets = new Insets(0, 0, 5, 5); - gbc_lblTotalResources.gridx = 2; - gbc_lblTotalResources.gridy = 2; - panel_1.add(lblTotalResources, gbc_lblTotalResources); + JLabel lblFoundResources = new JLabel("Total Resources:"); + lblFoundResources.setHorizontalAlignment(SwingConstants.RIGHT); + GridBagConstraints gbc_lblFoundResources = new GridBagConstraints(); + gbc_lblFoundResources.anchor = GridBagConstraints.EAST; + gbc_lblFoundResources.insets = new Insets(0, 0, 5, 5); + gbc_lblFoundResources.gridx = 2; + gbc_lblFoundResources.gridy = 2; + panel_1.add(lblFoundResources, gbc_lblFoundResources); JLabel lblTotalResourcesCount = new JLabel("0"); GridBagConstraints gbc_lblTotalResourcesCount = new GridBagConstraints(); @@ -307,13 +300,6 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblTotalResourcesCount.gridy = 2; panel_1.add(lblTotalResourcesCount, gbc_lblTotalResourcesCount); - JLabel label_6 = new JLabel("100%"); - GridBagConstraints gbc_label_6 = new GridBagConstraints(); - gbc_label_6.insets = new Insets(0, 0, 5, 0); - gbc_label_6.gridx = 4; - gbc_label_6.gridy = 2; - panel_1.add(label_6, gbc_label_6); - JLabel lblArchivesCopied = new JLabel("Archives Copied:"); GridBagConstraints gbc_lblArchivesCopied = new GridBagConstraints(); gbc_lblArchivesCopied.anchor = GridBagConstraints.EAST; @@ -322,20 +308,20 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblArchivesCopied.gridy = 4; panel_1.add(lblArchivesCopied, gbc_lblArchivesCopied); - JLabel label_1 = new JLabel("99"); - GridBagConstraints gbc_label_1 = new GridBagConstraints(); - gbc_label_1.anchor = GridBagConstraints.WEST; - gbc_label_1.insets = new Insets(0, 0, 5, 5); - gbc_label_1.gridx = 3; - gbc_label_1.gridy = 4; - panel_1.add(label_1, gbc_label_1); - - JLabel label_7 = new JLabel("0%"); - GridBagConstraints gbc_label_7 = new GridBagConstraints(); - gbc_label_7.insets = new Insets(0, 0, 5, 0); - gbc_label_7.gridx = 4; - gbc_label_7.gridy = 4; - panel_1.add(label_7, gbc_label_7); + JLabel lblArchivesCopiedCount = new JLabel("0"); + GridBagConstraints gbc_lblArchivesCopiedCount = new GridBagConstraints(); + gbc_lblArchivesCopiedCount.anchor = GridBagConstraints.WEST; + gbc_lblArchivesCopiedCount.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesCopiedCount.gridx = 3; + gbc_lblArchivesCopiedCount.gridy = 4; + panel_1.add(lblArchivesCopiedCount, gbc_lblArchivesCopiedCount); + + JLabel lblArchivesCopiedPercent = new JLabel("0%"); + GridBagConstraints gbc_lblArchivesCopiedPercent = new GridBagConstraints(); + gbc_lblArchivesCopiedPercent.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesCopiedPercent.gridx = 4; + gbc_lblArchivesCopiedPercent.gridy = 4; + panel_1.add(lblArchivesCopiedPercent, gbc_lblArchivesCopiedPercent); JLabel lblResourcesCopied = new JLabel("Resources Copied:"); GridBagConstraints gbc_lblResourcesCopied = new GridBagConstraints(); @@ -345,70 +331,124 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblResourcesCopied.gridy = 5; panel_1.add(lblResourcesCopied, gbc_lblResourcesCopied); - JLabel label_2 = new JLabel("0"); - GridBagConstraints gbc_label_2 = new GridBagConstraints(); - gbc_label_2.anchor = GridBagConstraints.WEST; - gbc_label_2.insets = new Insets(0, 0, 5, 5); - gbc_label_2.gridx = 3; - gbc_label_2.gridy = 5; - panel_1.add(label_2, gbc_label_2); - - JLabel label_8 = new JLabel("0%"); - GridBagConstraints gbc_label_8 = new GridBagConstraints(); - gbc_label_8.insets = new Insets(0, 0, 5, 0); - gbc_label_8.gridx = 4; - gbc_label_8.gridy = 5; - panel_1.add(label_8, gbc_label_8); - - JLabel lblArchivesProcessed_1 = new JLabel("Archives Skipped:"); - lblArchivesProcessed_1.setHorizontalAlignment(SwingConstants.RIGHT); - GridBagConstraints gbc_lblArchivesProcessed_1 = new GridBagConstraints(); - gbc_lblArchivesProcessed_1.anchor = GridBagConstraints.EAST; - gbc_lblArchivesProcessed_1.insets = new Insets(0, 0, 5, 5); - gbc_lblArchivesProcessed_1.gridx = 2; - gbc_lblArchivesProcessed_1.gridy = 8; - panel_1.add(lblArchivesProcessed_1, gbc_lblArchivesProcessed_1); - - JLabel label_3 = new JLabel("0"); - GridBagConstraints gbc_label_3 = new GridBagConstraints(); - gbc_label_3.anchor = GridBagConstraints.WEST; - gbc_label_3.insets = new Insets(0, 0, 5, 5); - gbc_label_3.gridx = 3; - gbc_label_3.gridy = 8; - panel_1.add(label_3, gbc_label_3); - - JLabel label_10 = new JLabel("0%"); - GridBagConstraints gbc_label_10 = new GridBagConstraints(); - gbc_label_10.insets = new Insets(0, 0, 5, 0); - gbc_label_10.gridx = 4; - gbc_label_10.gridy = 8; - panel_1.add(label_10, gbc_label_10); + JLabel lblResourcesCopiedCount = new JLabel("0"); + GridBagConstraints gbc_lblResourcesCopiedCount = new GridBagConstraints(); + gbc_lblResourcesCopiedCount.anchor = GridBagConstraints.WEST; + gbc_lblResourcesCopiedCount.insets = new Insets(0, 0, 5, 5); + gbc_lblResourcesCopiedCount.gridx = 3; + gbc_lblResourcesCopiedCount.gridy = 5; + panel_1.add(lblResourcesCopiedCount, gbc_lblResourcesCopiedCount); + + JLabel lblResourcesCopiedPercent = new JLabel("0%"); + GridBagConstraints gbc_lblResourcesCopiedPercent = new GridBagConstraints(); + gbc_lblResourcesCopiedPercent.insets = new Insets(0, 0, 5, 5); + gbc_lblResourcesCopiedPercent.gridx = 4; + gbc_lblResourcesCopiedPercent.gridy = 5; + panel_1.add(lblResourcesCopiedPercent, gbc_lblResourcesCopiedPercent); + + JLabel lblArchivesSkipped = new JLabel("Archives Skipped:"); + lblArchivesSkipped.setHorizontalAlignment(SwingConstants.RIGHT); + GridBagConstraints gbc_lblArchivesSkipped = new GridBagConstraints(); + gbc_lblArchivesSkipped.anchor = GridBagConstraints.EAST; + gbc_lblArchivesSkipped.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesSkipped.gridx = 2; + gbc_lblArchivesSkipped.gridy = 7; + panel_1.add(lblArchivesSkipped, gbc_lblArchivesSkipped); + + JLabel lblArchivesSkippedCount = new JLabel("0"); + GridBagConstraints gbc_lblArchivesSkippedCount = new GridBagConstraints(); + gbc_lblArchivesSkippedCount.anchor = GridBagConstraints.WEST; + gbc_lblArchivesSkippedCount.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesSkippedCount.gridx = 3; + gbc_lblArchivesSkippedCount.gridy = 7; + panel_1.add(lblArchivesSkippedCount, gbc_lblArchivesSkippedCount); + + JLabel lblArchivesSkippedPercent = new JLabel("0%"); + GridBagConstraints gbc_lblArchivesSkippedPercent = new GridBagConstraints(); + gbc_lblArchivesSkippedPercent.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesSkippedPercent.gridx = 4; + gbc_lblArchivesSkippedPercent.gridy = 7; + panel_1.add(lblArchivesSkippedPercent, gbc_lblArchivesSkippedPercent); JLabel lblResourcesSkipped = new JLabel("Resources Skipped:"); GridBagConstraints gbc_lblResourcesSkipped = new GridBagConstraints(); gbc_lblResourcesSkipped.anchor = GridBagConstraints.EAST; gbc_lblResourcesSkipped.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesSkipped.gridx = 2; - gbc_lblResourcesSkipped.gridy = 9; + gbc_lblResourcesSkipped.gridy = 8; panel_1.add(lblResourcesSkipped, gbc_lblResourcesSkipped); - JLabel label_4 = new JLabel("0"); - GridBagConstraints gbc_label_4 = new GridBagConstraints(); - gbc_label_4.insets = new Insets(0, 0, 5, 5); - gbc_label_4.anchor = GridBagConstraints.WEST; - gbc_label_4.gridx = 3; - gbc_label_4.gridy = 9; - panel_1.add(label_4, gbc_label_4); + JLabel lblResourcesSkippedCount = new JLabel("0"); + GridBagConstraints gbc_lblResourcesSkippedCount = new GridBagConstraints(); + gbc_lblResourcesSkippedCount.insets = new Insets(0, 0, 5, 5); + gbc_lblResourcesSkippedCount.anchor = GridBagConstraints.WEST; + gbc_lblResourcesSkippedCount.gridx = 3; + gbc_lblResourcesSkippedCount.gridy = 8; + panel_1.add(lblResourcesSkippedCount, gbc_lblResourcesSkippedCount); + + JLabel labelResourcesSkippedPercent = new JLabel("0%"); + GridBagConstraints gbc_labelResourcesSkippedPercent = new GridBagConstraints(); + gbc_labelResourcesSkippedPercent.insets = new Insets(0, 0, 5, 5); + gbc_labelResourcesSkippedPercent.gridx = 4; + gbc_labelResourcesSkippedPercent.gridy = 8; + panel_1.add(labelResourcesSkippedPercent, gbc_labelResourcesSkippedPercent); + + JLabel lblArchivesFailed = new JLabel("Archives Failed:"); + lblArchivesFailed.setHorizontalAlignment(SwingConstants.RIGHT); + GridBagConstraints gbc_lblArchivesFailed = new GridBagConstraints(); + gbc_lblArchivesFailed.anchor = GridBagConstraints.EAST; + gbc_lblArchivesFailed.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesFailed.gridx = 2; + gbc_lblArchivesFailed.gridy = 10; + panel_1.add(lblArchivesFailed, gbc_lblArchivesFailed); + + JLabel lblArchivesFailedCount = new JLabel("0"); + GridBagConstraints gbc_lblArchivesFailedCount = new GridBagConstraints(); + gbc_lblArchivesFailedCount.anchor = GridBagConstraints.WEST; + gbc_lblArchivesFailedCount.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesFailedCount.gridx = 3; + gbc_lblArchivesFailedCount.gridy = 10; + panel_1.add(lblArchivesFailedCount, gbc_lblArchivesFailedCount); + + JLabel lblArchivesFailedPercent = new JLabel("0%"); + GridBagConstraints gbc_lblArchivesFailedPercent = new GridBagConstraints(); + gbc_lblArchivesFailedPercent.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesFailedPercent.gridx = 4; + gbc_lblArchivesFailedPercent.gridy = 10; + panel_1.add(lblArchivesFailedPercent, gbc_lblArchivesFailedPercent); + + JLabel lblResourcesFailed = new JLabel("Resources Failed:"); + GridBagConstraints gbc_lblResourcesFailed = new GridBagConstraints(); + gbc_lblResourcesFailed.anchor = GridBagConstraints.EAST; + gbc_lblResourcesFailed.insets = new Insets(0, 0, 0, 5); + gbc_lblResourcesFailed.gridx = 2; + gbc_lblResourcesFailed.gridy = 11; + panel_1.add(lblResourcesFailed, gbc_lblResourcesFailed); + + JLabel lblResourcesFailedCount = new JLabel("0"); + GridBagConstraints gbc_lblResourcesFailedCount = new GridBagConstraints(); + gbc_lblResourcesFailedCount.anchor = GridBagConstraints.WEST; + gbc_lblResourcesFailedCount.insets = new Insets(0, 0, 0, 5); + gbc_lblResourcesFailedCount.gridx = 3; + gbc_lblResourcesFailedCount.gridy = 11; + panel_1.add(lblResourcesFailedCount, gbc_lblResourcesFailedCount); + + JLabel lblResourcesFailedPercent = new JLabel("0%"); + GridBagConstraints gbc_lblResourcesFailedPercent = new GridBagConstraints(); + gbc_lblResourcesFailedPercent.insets = new Insets(0, 0, 0, 5); + gbc_lblResourcesFailedPercent.gridx = 4; + gbc_lblResourcesFailedPercent.gridy = 11; + panel_1.add(lblResourcesFailedPercent, gbc_lblResourcesFailedPercent); } private void setupRightProgressPane(JPanel progressPanel) { JPanel panel_2 = new JPanel(); progressPanel.add(panel_2); GridBagLayout gbl_panel_2 = new GridBagLayout(); - gbl_panel_2.columnWidths = new int[] {30, 0, 0, 0, 30, 30, 0, 0}; - gbl_panel_2.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0}; + gbl_panel_2.columnWidths = new int[] {30, 0, 90, 0, 30, 30, 0, 0}; + gbl_panel_2.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; gbl_panel_2.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; - gbl_panel_2.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + gbl_panel_2.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; panel_2.setLayout(gbl_panel_2); JLabel lblNewLabel = new JLabel("Process Operation"); @@ -419,48 +459,176 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblNewLabel.gridy = 0; panel_2.add(lblNewLabel, gbc_lblNewLabel); + JLabel lblTotalArchives = new JLabel("Total Archives:"); + GridBagConstraints gbc_lblTotalArchives = new GridBagConstraints(); + gbc_lblTotalArchives.anchor = GridBagConstraints.EAST; + gbc_lblTotalArchives.insets = new Insets(0, 0, 5, 5); + gbc_lblTotalArchives.gridx = 1; + gbc_lblTotalArchives.gridy = 1; + panel_2.add(lblTotalArchives, gbc_lblTotalArchives); + + JLabel lblTotalArchvesCount = new JLabel("0"); + GridBagConstraints gbc_lblTotalArchvesCount = new GridBagConstraints(); + gbc_lblTotalArchvesCount.anchor = GridBagConstraints.WEST; + gbc_lblTotalArchvesCount.insets = new Insets(0, 0, 5, 5); + gbc_lblTotalArchvesCount.gridx = 2; + gbc_lblTotalArchvesCount.gridy = 1; + panel_2.add(lblTotalArchvesCount, gbc_lblTotalArchvesCount); + + JLabel lblTotalResources = new JLabel("Total Resources:"); + GridBagConstraints gbc_lblTotalResources = new GridBagConstraints(); + gbc_lblTotalResources.anchor = GridBagConstraints.EAST; + gbc_lblTotalResources.insets = new Insets(0, 0, 5, 5); + gbc_lblTotalResources.gridx = 1; + gbc_lblTotalResources.gridy = 2; + panel_2.add(lblTotalResources, gbc_lblTotalResources); + + JLabel lblTotalResourcesCount = new JLabel("0"); + GridBagConstraints gbc_lblTotalResourcesCount = new GridBagConstraints(); + gbc_lblTotalResourcesCount.anchor = GridBagConstraints.WEST; + gbc_lblTotalResourcesCount.insets = new Insets(0, 0, 5, 5); + gbc_lblTotalResourcesCount.gridx = 2; + gbc_lblTotalResourcesCount.gridy = 2; + panel_2.add(lblTotalResourcesCount, gbc_lblTotalResourcesCount); + JLabel lblArchivesProcessed = new JLabel("Archives Processed:"); GridBagConstraints gbc_lblArchivesProcessed = new GridBagConstraints(); + gbc_lblArchivesProcessed.anchor = GridBagConstraints.EAST; gbc_lblArchivesProcessed.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesProcessed.gridx = 1; - gbc_lblArchivesProcessed.gridy = 3; + gbc_lblArchivesProcessed.gridy = 4; panel_2.add(lblArchivesProcessed, gbc_lblArchivesProcessed); lblArchivesProcessed.setHorizontalAlignment(SwingConstants.RIGHT); - JLabel lblArchivesprocessed = new JLabel("0"); - GridBagConstraints gbc_lblArchivesprocessed = new GridBagConstraints(); - gbc_lblArchivesprocessed.insets = new Insets(0, 0, 5, 5); - gbc_lblArchivesprocessed.gridx = 2; - gbc_lblArchivesprocessed.gridy = 3; - panel_2.add(lblArchivesprocessed, gbc_lblArchivesprocessed); - - JLabel label_9 = new JLabel("0%"); - GridBagConstraints gbc_label_9 = new GridBagConstraints(); - gbc_label_9.insets = new Insets(0, 0, 5, 5); - gbc_label_9.gridx = 3; - gbc_label_9.gridy = 3; - panel_2.add(label_9, gbc_label_9); + JLabel lblArchivesProcessedCount = new JLabel("0"); + GridBagConstraints gbc_lblArchivesProcessedCount = new GridBagConstraints(); + gbc_lblArchivesProcessedCount.anchor = GridBagConstraints.WEST; + gbc_lblArchivesProcessedCount.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesProcessedCount.gridx = 2; + gbc_lblArchivesProcessedCount.gridy = 4; + panel_2.add(lblArchivesProcessedCount, gbc_lblArchivesProcessedCount); + + JLabel lblArchivesProcessedPercent = new JLabel("0%"); + GridBagConstraints gbc_lblArchivesProcessedPercent = new GridBagConstraints(); + gbc_lblArchivesProcessedPercent.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesProcessedPercent.gridx = 3; + gbc_lblArchivesProcessedPercent.gridy = 4; + panel_2.add(lblArchivesProcessedPercent, gbc_lblArchivesProcessedPercent); JLabel lblResourcesProcessed = new JLabel("Resources Processed:"); GridBagConstraints gbc_lblResourcesProcessed = new GridBagConstraints(); + gbc_lblResourcesProcessed.anchor = GridBagConstraints.EAST; gbc_lblResourcesProcessed.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesProcessed.gridx = 1; - gbc_lblResourcesProcessed.gridy = 4; + gbc_lblResourcesProcessed.gridy = 5; panel_2.add(lblResourcesProcessed, gbc_lblResourcesProcessed); - JLabel label = new JLabel("100"); - GridBagConstraints gbc_label = new GridBagConstraints(); - gbc_label.insets = new Insets(0, 0, 5, 5); - gbc_label.gridx = 2; - gbc_label.gridy = 4; - panel_2.add(label, gbc_label); - - JLabel label_11 = new JLabel("0%"); - GridBagConstraints gbc_label_11 = new GridBagConstraints(); - gbc_label_11.insets = new Insets(0, 0, 5, 5); - gbc_label_11.gridx = 3; - gbc_label_11.gridy = 4; - panel_2.add(label_11, gbc_label_11); + JLabel lblResourcesProcessedCount = new JLabel("0"); + GridBagConstraints gbc_lblResourcesProcessedCount = new GridBagConstraints(); + gbc_lblResourcesProcessedCount.anchor = GridBagConstraints.WEST; + gbc_lblResourcesProcessedCount.insets = new Insets(0, 0, 5, 5); + gbc_lblResourcesProcessedCount.gridx = 2; + gbc_lblResourcesProcessedCount.gridy = 5; + panel_2.add(lblResourcesProcessedCount, gbc_lblResourcesProcessedCount); + + JLabel lblResourcesProcessedPercent = new JLabel("0%"); + GridBagConstraints gbc_lblResourcesProcessedPercent = new GridBagConstraints(); + gbc_lblResourcesProcessedPercent.insets = new Insets(0, 0, 5, 5); + gbc_lblResourcesProcessedPercent.gridx = 3; + gbc_lblResourcesProcessedPercent.gridy = 5; + panel_2.add(lblResourcesProcessedPercent, gbc_lblResourcesProcessedPercent); + + JLabel lblArchivesSkipped = new JLabel("Archives Skipped:"); + GridBagConstraints gbc_lblArchivesSkipped = new GridBagConstraints(); + gbc_lblArchivesSkipped.anchor = GridBagConstraints.EAST; + gbc_lblArchivesSkipped.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesSkipped.gridx = 1; + gbc_lblArchivesSkipped.gridy = 7; + panel_2.add(lblArchivesSkipped, gbc_lblArchivesSkipped); + + JLabel lblArchivesSkippedCount = new JLabel("0"); + GridBagConstraints gbc_lblArchivesSkippedCount = new GridBagConstraints(); + gbc_lblArchivesSkippedCount.anchor = GridBagConstraints.WEST; + gbc_lblArchivesSkippedCount.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesSkippedCount.gridx = 2; + gbc_lblArchivesSkippedCount.gridy = 7; + panel_2.add(lblArchivesSkippedCount, gbc_lblArchivesSkippedCount); + + JLabel lblArchivesSkippedPercent = new JLabel("0%"); + GridBagConstraints gbc_lblArchivesSkippedPercent = new GridBagConstraints(); + gbc_lblArchivesSkippedPercent.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesSkippedPercent.gridx = 3; + gbc_lblArchivesSkippedPercent.gridy = 7; + panel_2.add(lblArchivesSkippedPercent, gbc_lblArchivesSkippedPercent); + + JLabel lblResourcesSkipped = new JLabel("Resources Skipped:"); + GridBagConstraints gbc_lblResourcesSkipped = new GridBagConstraints(); + gbc_lblResourcesSkipped.anchor = GridBagConstraints.EAST; + gbc_lblResourcesSkipped.insets = new Insets(0, 0, 5, 5); + gbc_lblResourcesSkipped.gridx = 1; + gbc_lblResourcesSkipped.gridy = 8; + panel_2.add(lblResourcesSkipped, gbc_lblResourcesSkipped); + + JLabel lblResourcesSkippedCount = new JLabel("0"); + GridBagConstraints gbc_lblResourcesSkippedCount = new GridBagConstraints(); + gbc_lblResourcesSkippedCount.anchor = GridBagConstraints.WEST; + gbc_lblResourcesSkippedCount.insets = new Insets(0, 0, 5, 5); + gbc_lblResourcesSkippedCount.gridx = 2; + gbc_lblResourcesSkippedCount.gridy = 8; + panel_2.add(lblResourcesSkippedCount, gbc_lblResourcesSkippedCount); + + JLabel lblResourcesSkippedPercent = new JLabel("0%"); + GridBagConstraints gbc_lblResourcesSkippedPercent = new GridBagConstraints(); + gbc_lblResourcesSkippedPercent.insets = new Insets(0, 0, 5, 5); + gbc_lblResourcesSkippedPercent.gridx = 3; + gbc_lblResourcesSkippedPercent.gridy = 8; + panel_2.add(lblResourcesSkippedPercent, gbc_lblResourcesSkippedPercent); + + JLabel lblArchivesFailed = new JLabel("Archives Failed:"); + GridBagConstraints gbc_lblArchivesFailed = new GridBagConstraints(); + gbc_lblArchivesFailed.anchor = GridBagConstraints.EAST; + gbc_lblArchivesFailed.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesFailed.gridx = 1; + gbc_lblArchivesFailed.gridy = 10; + panel_2.add(lblArchivesFailed, gbc_lblArchivesFailed); + + JLabel lblArchivesFailedCount = new JLabel("0"); + GridBagConstraints gbc_lblArchivesFailedCount = new GridBagConstraints(); + gbc_lblArchivesFailedCount.anchor = GridBagConstraints.WEST; + gbc_lblArchivesFailedCount.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesFailedCount.gridx = 2; + gbc_lblArchivesFailedCount.gridy = 10; + panel_2.add(lblArchivesFailedCount, gbc_lblArchivesFailedCount); + + JLabel lblArchivesFailedPercent = new JLabel("0%"); + GridBagConstraints gbc_lblArchivesFailedPercent = new GridBagConstraints(); + gbc_lblArchivesFailedPercent.insets = new Insets(0, 0, 5, 5); + gbc_lblArchivesFailedPercent.gridx = 3; + gbc_lblArchivesFailedPercent.gridy = 10; + panel_2.add(lblArchivesFailedPercent, gbc_lblArchivesFailedPercent); + + JLabel lblResourcesFailed = new JLabel("Resources Failed:"); + GridBagConstraints gbc_lblResourcesFailed = new GridBagConstraints(); + gbc_lblResourcesFailed.anchor = GridBagConstraints.EAST; + gbc_lblResourcesFailed.insets = new Insets(0, 0, 0, 5); + gbc_lblResourcesFailed.gridx = 1; + gbc_lblResourcesFailed.gridy = 11; + panel_2.add(lblResourcesFailed, gbc_lblResourcesFailed); + + JLabel lblResourcesFailedCount = new JLabel("0"); + GridBagConstraints gbc_lblResourcesFailedCount = new GridBagConstraints(); + gbc_lblResourcesFailedCount.anchor = GridBagConstraints.WEST; + gbc_lblResourcesFailedCount.insets = new Insets(0, 0, 0, 5); + gbc_lblResourcesFailedCount.gridx = 2; + gbc_lblResourcesFailedCount.gridy = 11; + panel_2.add(lblResourcesFailedCount, gbc_lblResourcesFailedCount); + + JLabel lblResourcesFailedPercent = new JLabel("0%"); + GridBagConstraints gbc_lblResourcesFailedPercent = new GridBagConstraints(); + gbc_lblResourcesFailedPercent.insets = new Insets(0, 0, 0, 5); + gbc_lblResourcesFailedPercent.gridx = 3; + gbc_lblResourcesFailedPercent.gridy = 11; + panel_2.add(lblResourcesFailedPercent, gbc_lblResourcesFailedPercent); } private BatchRunner genCopyBatches() { From 2aaad7b60284211b0cdc94a30066756f28a19ea7 Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Tue, 23 Apr 2024 20:56:04 -0400 Subject: [PATCH 06/19] More progress --- .../excite/modding/concurrent/Batch.java | 12 +- .../modding/concurrent/BatchContainer.java | 6 +- .../modding/concurrent/BatchListener.java | 1 + .../modding/concurrent/BatchRunner.java | 39 ++- .../modding/concurrent/BatchWorker.java | 10 +- .../excite/modding/concurrent/Batcher.java | 8 +- .../modding/ui/NonWrappedJEditorPane.java | 17 -- .../excite/modding/ui/Window.java | 257 +++++++++++------- 8 files changed, 203 insertions(+), 147 deletions(-) delete mode 100644 src/main/java/com/gamebuster19901/excite/modding/ui/NonWrappedJEditorPane.java diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java index 4da026d..75d71b0 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java @@ -8,7 +8,7 @@ import java.util.concurrent.Callable; import static java.lang.Thread.State; -public class Batch implements Batcher { +public class Batch implements Batcher { private final String name; private final Set runnables = new HashSet<>(); @@ -25,7 +25,7 @@ public String getName() { } @Override - public void addRunnable(Callable runnable) { + public void addRunnable(Callable runnable) { if(accepting) { BatchedCallable b = new BatchedCallable(runnable); runnables.add(new BatchedCallable(runnable)); @@ -91,9 +91,9 @@ private void notAccepting() { throw new IllegalStateException("Batch is not accepting new tasks or listeners."); } - public class BatchedCallable implements Callable { + public class BatchedCallable implements Callable { - private final Callable child; + private final Callable child; private volatile SoftReference threadRef; protected volatile Throwable thrown; protected volatile boolean finished = false; @@ -105,13 +105,13 @@ public BatchedCallable(Runnable r) { }); } - public BatchedCallable(Callable c) { + public BatchedCallable(Callable c) { this.child = c; updateListeners(); } @Override - public Void call() { + public T call() { Thread thread; try { thread = Thread.currentThread(); diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java index c2332dd..51a6a10 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java @@ -2,13 +2,11 @@ import java.util.Collection; -import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; - -public interface BatchContainer { +public interface BatchContainer { public abstract String getName(); - public Collection getRunnables(); + public Collection.BatchedCallable> getRunnables(); public Collection getListeners(); diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchListener.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchListener.java index 20df878..ba66094 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchListener.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchListener.java @@ -1,5 +1,6 @@ package com.gamebuster19901.excite.modding.concurrent; +@FunctionalInterface public interface BatchListener { public void update(); } diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java index a369f27..811a05c 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java @@ -5,14 +5,14 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; -public class BatchRunner implements BatchWorker { +public class BatchRunner implements BatchWorker { private final String name; private final ExecutorService executor; - private final LinkedHashSet batches = new LinkedHashSet(); + private final LinkedHashSet> batches = new LinkedHashSet>(); private volatile boolean started = false; + private volatile boolean listenerAdded = false; public BatchRunner(String name) { this(name, Runtime.getRuntime().availableProcessors()); @@ -33,8 +33,11 @@ public String getName() { } @Override - public void addBatch(Batcher batcher) { + public void addBatch(Batcher batcher) { synchronized(executor) { + if(listenerAdded) { + throw new IllegalStateException("Cannot add a batch after a BatchListener has been added! Add all batches before adding listeners!"); + } if(executor.isShutdown()) { throw new IllegalStateException("Cannot add more batches after the batch runner has shut down!"); } @@ -69,17 +72,17 @@ public void shutdownNow() throws InterruptedException { executor.awaitTermination(5, TimeUnit.SECONDS); } finally { - for(Batcher batch : batches) { + for(Batcher batch : batches) { batch.shutdownNow(); } } } @Override - public Collection getRunnables() { + public Collection.BatchedCallable> getRunnables() { synchronized(batches) { - LinkedHashSet ret = new LinkedHashSet<>(); - for(Batcher batch : batches) { + LinkedHashSet.BatchedCallable> ret = new LinkedHashSet<>(); + for(Batcher batch : batches) { ret.addAll(batch.getRunnables()); } return ret; @@ -90,21 +93,31 @@ public Collection getRunnables() { public Collection getListeners() { synchronized(batches) { LinkedHashSet ret = new LinkedHashSet<>(); - for(Batcher batch : batches) { + for(Batcher batch : batches) { ret.addAll(batch.getListeners()); } return ret; } } - public Collection getBatches() { - return (Collection) batches.clone(); + @Override + public void addBatchListener(BatchListener listener) { + if(!listenerAdded) { + listenerAdded = true; + } + for(Batcher batch : batches) { + batch.addListener(listener); + } + } + + public Collection> getBatches() { + return (Collection>) batches.clone(); } public int getCompleted() { int ret = 0; - Collection callables = getRunnables(); - for(BatchedCallable callable : callables) {ret++;} + Collection.BatchedCallable> callables = getRunnables(); + for(Batch.BatchedCallable callable : callables) {ret++;} return ret; } diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchWorker.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchWorker.java index cbffafa..aace9af 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchWorker.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchWorker.java @@ -3,11 +3,9 @@ import java.util.Collection; import java.util.concurrent.TimeUnit; -import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; - -public interface BatchWorker extends BatchContainer { +public interface BatchWorker extends BatchContainer { - public abstract void addBatch(Batcher batcher); + public abstract void addBatch(Batcher batcher); public abstract void startBatch() throws InterruptedException; @@ -15,8 +13,10 @@ public interface BatchWorker extends BatchContainer { public void shutdownNow() throws InterruptedException; - public Collection getRunnables(); + public Collection.BatchedCallable> getRunnables(); public Collection getListeners(); + public void addBatchListener(BatchListener listener); + } diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batcher.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batcher.java index aaef965..0a3e795 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batcher.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batcher.java @@ -3,11 +3,9 @@ import java.util.Collection; import java.util.concurrent.Callable; -import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; - -public interface Batcher extends BatchContainer { +public interface Batcher extends BatchContainer { - public abstract void addRunnable(Callable runnable); + public abstract void addRunnable(Callable runnable); public abstract void addRunnable(Runnable runnable); @@ -15,7 +13,7 @@ public interface Batcher extends BatchContainer { public void shutdownNow() throws InterruptedException; - public Collection getRunnables(); + public Collection.BatchedCallable> getRunnables(); public Collection getListeners(); diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/NonWrappedJEditorPane.java b/src/main/java/com/gamebuster19901/excite/modding/ui/NonWrappedJEditorPane.java deleted file mode 100644 index 9d3b71c..0000000 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/NonWrappedJEditorPane.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.gamebuster19901.excite.modding.ui; - -import java.awt.Component; -import javax.swing.JEditorPane; -import javax.swing.plaf.ComponentUI; - -public class NonWrappedJEditorPane extends JEditorPane { - - @Override - public boolean getScrollableTracksViewportWidth() { - Component parent = getParent(); - ComponentUI ui = getUI(); - - return true; - } - -} diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java index 72c18ce..4deaa9c 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java @@ -6,7 +6,13 @@ import java.awt.Insets; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; +import java.io.File; import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Collection; import java.util.Iterator; @@ -24,6 +30,7 @@ import javax.swing.UIManager; import javax.swing.BorderFactory; import javax.swing.JButton; +import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JSeparator; import javax.swing.JTabbedPane; @@ -31,6 +38,7 @@ import javax.swing.JProgressBar; import javax.swing.JScrollPane; import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; import javax.swing.JPanel; import java.awt.GridLayout; import java.awt.GridBagLayout; @@ -45,8 +53,8 @@ public class Window implements BatchListener, MouseWheelListener { } private JFrame frame; - private JTextField textField; - private JTextField textField_1; + private JTextField textFieldDestDir; + private JTextField textFieldSourceDir; private JSlider threadSlider; private JLabel lblThreads; private static Window window; @@ -55,12 +63,12 @@ public class Window implements BatchListener, MouseWheelListener { private final FixedCellGrid gridPanel = genGridPanel(); private JTable table; - private BatchRunner copyOperations; + private BatchRunner copyOperations; private BatchRunner processOperations; + /** - * Launch the application. - * @throws InterruptedException + * @wbp.parser.entryPoint */ public static void main(String[] args) throws InterruptedException { @@ -86,24 +94,21 @@ public Window() throws InterruptedException { } /** - * Initialize the contents of the frame. - * @throws InterruptedException + * @wbp.parser.entryPoint */ private void initialize() throws InterruptedException { - copyOperations = genCopyBatches(); - + copyOperations = genCopyBatches(null); setupFrame(); - setupTabbedPane(); } private void setupFrame() { - frame = new JFrame(); + frame = new JFrame(); // @wbp.parser.preferredRoot frame.setTitle("ExciteModder"); frame.setBounds(100, 100, 1000, 680); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().setLayout(null); - //frame.setResizable(false); + frame.setResizable(false); frame.setVisible(true); JLabel lblUnmoddedDirectory = new JLabel("Source Directory:"); @@ -116,19 +121,40 @@ private void setupFrame() { lblModdedDirectory.setBounds(12, 39, 165, 15); frame.getContentPane().add(lblModdedDirectory); - textField = new JTextField(); - textField.setBounds(171, 37, 578, 19); - frame.getContentPane().add(textField); - textField.setColumns(10); + textFieldSourceDir = new JTextField(); + textFieldSourceDir.setColumns(10); + textFieldSourceDir.setBounds(171, 10, 578, 19); + frame.getContentPane().add(textFieldSourceDir); - textField_1 = new JTextField(); - textField_1.setColumns(10); - textField_1.setBounds(171, 10, 578, 19); - frame.getContentPane().add(textField_1); + textFieldDestDir = new JTextField(); + textFieldDestDir.setBounds(171, 37, 578, 19); + frame.getContentPane().add(textFieldDestDir); + textFieldDestDir.setColumns(10); JButton btnChangeSource = new JButton("Change"); btnChangeSource.setToolTipText("Change where ExciteModder will copy the game files from"); btnChangeSource.setBounds(761, 9, 117, 19); + btnChangeSource.addActionListener((e) -> { + File f; + Path path = Path.of(textFieldSourceDir.getText().trim()).toAbsolutePath(); + if(Files.exists(path)) { + f = path.toAbsolutePath().toFile(); + } + else { + f = null; + } + + JFileChooser chooser = new JFileChooser(f); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + int status = chooser.showOpenDialog(frame); + if(status == JFileChooser.APPROVE_OPTION) { + try { + selectSourceDirectory(chooser.getSelectedFile()); + } catch (InvocationTargetException | InterruptedException e1) { + e1.printStackTrace(); + } + } + }); frame.getContentPane().add(btnChangeSource); JButton btnChangeDest = new JButton("Change"); @@ -175,23 +201,40 @@ private void setupFrame() { frame.getContentPane().add(btnExtract); frame.validate(); frame.repaint(); - tabbedPane.addMouseWheelListener(this); + //tabbedPane = setupTabbedPane(true); + //frame.add(setupTabbedPane(true)); //this line is necessary here so that the wbp parser can see that the tabbed pane is a subcomponent of the frame. It doesn't seem to recognize it as being so if it isn't manually added here, even though it's added in setupTabbedPane } - private void setupTabbedPane() { - tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); + private void selectSourceDirectory(File selectedDir) throws InvocationTargetException, InterruptedException { + if(selectedDir != null) { + textFieldSourceDir.setText(selectedDir.getAbsolutePath()); + } + else { + textFieldSourceDir.setText(""); + } - tabbedPane.setBounds(0, 129, 1000, 511); - frame.getContentPane().add(tabbedPane); + copyOperations.shutdownNow(); + copyOperations = genCopyBatches(selectedDir); + setupTabbedPane(false); + update(); + } + + private void setupTabbedPane(boolean initialSetup) { + tabbedPane.removeAll(); + if(initialSetup) { + tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); + tabbedPane.setBounds(0, 129, 1000, 511); + frame.getContentPane().add(tabbedPane); + } setupConsoleOutputTab(); setupStatusTab(); setupProgressTab(); - for(Batcher b : copyOperations.getBatches()) { + for(Batcher b : copyOperations.getBatches()) { tabbedPane.addTab(b.getName(), null); } - + return; } private void setupConsoleOutputTab() { @@ -204,14 +247,22 @@ private void setupConsoleOutputTab() { System.setOut(new PrintStream(SplitOutputStream.splitSysOut(textPaneOutputStream))); System.setErr(new PrintStream(SplitOutputStream.splitErrOut(textPaneOutputStream))); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + new Throwable().printStackTrace(pw); + textArea.setText(sw.toString()); + JScrollPane scrollPane = new JScrollPane(textArea); scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); - tabbedPane.addTab("Console Output", null, scrollPane, null); + tabbedPane.addTab("Console OutputT", null, scrollPane, null); + + + } public void setupStatusTab() { tabbedPane.addTab("Status", null, gridPanel, null); - Iterator batches = copyOperations.getBatches().iterator(); + Iterator> batches = copyOperations.getBatches().iterator(); int i = 0; while(batches.hasNext()) { gridPanel.putComponent(i, new BatchOperationComponent(batches.next())); @@ -231,14 +282,14 @@ public void setupProgressTab() { } private void setupLeftProgressPane(JPanel progressPanel) { - JPanel panel_1 = new JPanel(); - progressPanel.add(panel_1); - GridBagLayout gbl_panel_1 = new GridBagLayout(); - gbl_panel_1.columnWidths = new int[] {100, 0, 70, 90, 0, 0, 0}; - gbl_panel_1.rowHeights = new int[] {0, 15, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0}; - gbl_panel_1.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; - gbl_panel_1.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; - panel_1.setLayout(gbl_panel_1); + JPanel leftPanel = new JPanel(); + progressPanel.add(leftPanel); + GridBagLayout gbl_leftPanel = new GridBagLayout(); + gbl_leftPanel.columnWidths = new int[] {100, 0, 70, 90, 0, 0, 0}; + gbl_leftPanel.rowHeights = new int[] {0, 15, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0}; + gbl_leftPanel.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + gbl_leftPanel.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + leftPanel.setLayout(gbl_leftPanel); JLabel lblCopyOperation = new JLabel("Copy Operation"); GridBagConstraints gbc_lblCopyOperation = new GridBagConstraints(); @@ -246,7 +297,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblCopyOperation.insets = new Insets(0, 0, 5, 5); gbc_lblCopyOperation.gridx = 0; gbc_lblCopyOperation.gridy = 0; - panel_1.add(lblCopyOperation, gbc_lblCopyOperation); + leftPanel.add(lblCopyOperation, gbc_lblCopyOperation); BatchOperationComponent allBatchesCopy = new BatchOperationComponent(copyOperations); allBatchesCopy.setToolTipText("All Batches"); GridBagConstraints gbc_allBatches = new GridBagConstraints(); @@ -255,7 +306,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_allBatches.insets = new Insets(0, 0, 0, 0); gbc_allBatches.gridx = 0; gbc_allBatches.gridy = 1; - panel_1.add(allBatchesCopy, gbc_allBatches); + leftPanel.add(allBatchesCopy, gbc_allBatches); JSeparator separator_1 = new JSeparator(); GridBagConstraints gbc_separator_1 = new GridBagConstraints(); @@ -264,7 +315,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_separator_1.insets = new Insets(0, 0, 5, 5); gbc_separator_1.gridx = 1; gbc_separator_1.gridy = 0; - panel_1.add(separator_1, gbc_separator_1); + leftPanel.add(separator_1, gbc_separator_1); JLabel lblTotalArchives = new JLabel("Total Archives:"); lblTotalArchives.setHorizontalAlignment(SwingConstants.CENTER); @@ -273,7 +324,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblTotalArchives.anchor = GridBagConstraints.NORTHEAST; gbc_lblTotalArchives.gridx = 2; gbc_lblTotalArchives.gridy = 1; - panel_1.add(lblTotalArchives, gbc_lblTotalArchives); + leftPanel.add(lblTotalArchives, gbc_lblTotalArchives); JLabel lblTotalArchivesCount = new JLabel("0"); GridBagConstraints gbc_lblTotalArchivesCount = new GridBagConstraints(); @@ -281,7 +332,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblTotalArchivesCount.insets = new Insets(0, 0, 5, 5); gbc_lblTotalArchivesCount.gridx = 3; gbc_lblTotalArchivesCount.gridy = 1; - panel_1.add(lblTotalArchivesCount, gbc_lblTotalArchivesCount); + leftPanel.add(lblTotalArchivesCount, gbc_lblTotalArchivesCount); JLabel lblFoundResources = new JLabel("Total Resources:"); lblFoundResources.setHorizontalAlignment(SwingConstants.RIGHT); @@ -290,7 +341,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblFoundResources.insets = new Insets(0, 0, 5, 5); gbc_lblFoundResources.gridx = 2; gbc_lblFoundResources.gridy = 2; - panel_1.add(lblFoundResources, gbc_lblFoundResources); + leftPanel.add(lblFoundResources, gbc_lblFoundResources); JLabel lblTotalResourcesCount = new JLabel("0"); GridBagConstraints gbc_lblTotalResourcesCount = new GridBagConstraints(); @@ -298,7 +349,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblTotalResourcesCount.insets = new Insets(0, 0, 5, 5); gbc_lblTotalResourcesCount.gridx = 3; gbc_lblTotalResourcesCount.gridy = 2; - panel_1.add(lblTotalResourcesCount, gbc_lblTotalResourcesCount); + leftPanel.add(lblTotalResourcesCount, gbc_lblTotalResourcesCount); JLabel lblArchivesCopied = new JLabel("Archives Copied:"); GridBagConstraints gbc_lblArchivesCopied = new GridBagConstraints(); @@ -306,7 +357,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblArchivesCopied.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesCopied.gridx = 2; gbc_lblArchivesCopied.gridy = 4; - panel_1.add(lblArchivesCopied, gbc_lblArchivesCopied); + leftPanel.add(lblArchivesCopied, gbc_lblArchivesCopied); JLabel lblArchivesCopiedCount = new JLabel("0"); GridBagConstraints gbc_lblArchivesCopiedCount = new GridBagConstraints(); @@ -314,14 +365,14 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblArchivesCopiedCount.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesCopiedCount.gridx = 3; gbc_lblArchivesCopiedCount.gridy = 4; - panel_1.add(lblArchivesCopiedCount, gbc_lblArchivesCopiedCount); + leftPanel.add(lblArchivesCopiedCount, gbc_lblArchivesCopiedCount); JLabel lblArchivesCopiedPercent = new JLabel("0%"); GridBagConstraints gbc_lblArchivesCopiedPercent = new GridBagConstraints(); gbc_lblArchivesCopiedPercent.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesCopiedPercent.gridx = 4; gbc_lblArchivesCopiedPercent.gridy = 4; - panel_1.add(lblArchivesCopiedPercent, gbc_lblArchivesCopiedPercent); + leftPanel.add(lblArchivesCopiedPercent, gbc_lblArchivesCopiedPercent); JLabel lblResourcesCopied = new JLabel("Resources Copied:"); GridBagConstraints gbc_lblResourcesCopied = new GridBagConstraints(); @@ -329,7 +380,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblResourcesCopied.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesCopied.gridx = 2; gbc_lblResourcesCopied.gridy = 5; - panel_1.add(lblResourcesCopied, gbc_lblResourcesCopied); + leftPanel.add(lblResourcesCopied, gbc_lblResourcesCopied); JLabel lblResourcesCopiedCount = new JLabel("0"); GridBagConstraints gbc_lblResourcesCopiedCount = new GridBagConstraints(); @@ -337,14 +388,14 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblResourcesCopiedCount.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesCopiedCount.gridx = 3; gbc_lblResourcesCopiedCount.gridy = 5; - panel_1.add(lblResourcesCopiedCount, gbc_lblResourcesCopiedCount); + leftPanel.add(lblResourcesCopiedCount, gbc_lblResourcesCopiedCount); JLabel lblResourcesCopiedPercent = new JLabel("0%"); GridBagConstraints gbc_lblResourcesCopiedPercent = new GridBagConstraints(); gbc_lblResourcesCopiedPercent.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesCopiedPercent.gridx = 4; gbc_lblResourcesCopiedPercent.gridy = 5; - panel_1.add(lblResourcesCopiedPercent, gbc_lblResourcesCopiedPercent); + leftPanel.add(lblResourcesCopiedPercent, gbc_lblResourcesCopiedPercent); JLabel lblArchivesSkipped = new JLabel("Archives Skipped:"); lblArchivesSkipped.setHorizontalAlignment(SwingConstants.RIGHT); @@ -353,7 +404,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblArchivesSkipped.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesSkipped.gridx = 2; gbc_lblArchivesSkipped.gridy = 7; - panel_1.add(lblArchivesSkipped, gbc_lblArchivesSkipped); + leftPanel.add(lblArchivesSkipped, gbc_lblArchivesSkipped); JLabel lblArchivesSkippedCount = new JLabel("0"); GridBagConstraints gbc_lblArchivesSkippedCount = new GridBagConstraints(); @@ -361,14 +412,14 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblArchivesSkippedCount.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesSkippedCount.gridx = 3; gbc_lblArchivesSkippedCount.gridy = 7; - panel_1.add(lblArchivesSkippedCount, gbc_lblArchivesSkippedCount); + leftPanel.add(lblArchivesSkippedCount, gbc_lblArchivesSkippedCount); JLabel lblArchivesSkippedPercent = new JLabel("0%"); GridBagConstraints gbc_lblArchivesSkippedPercent = new GridBagConstraints(); gbc_lblArchivesSkippedPercent.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesSkippedPercent.gridx = 4; gbc_lblArchivesSkippedPercent.gridy = 7; - panel_1.add(lblArchivesSkippedPercent, gbc_lblArchivesSkippedPercent); + leftPanel.add(lblArchivesSkippedPercent, gbc_lblArchivesSkippedPercent); JLabel lblResourcesSkipped = new JLabel("Resources Skipped:"); GridBagConstraints gbc_lblResourcesSkipped = new GridBagConstraints(); @@ -376,7 +427,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblResourcesSkipped.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesSkipped.gridx = 2; gbc_lblResourcesSkipped.gridy = 8; - panel_1.add(lblResourcesSkipped, gbc_lblResourcesSkipped); + leftPanel.add(lblResourcesSkipped, gbc_lblResourcesSkipped); JLabel lblResourcesSkippedCount = new JLabel("0"); GridBagConstraints gbc_lblResourcesSkippedCount = new GridBagConstraints(); @@ -384,14 +435,14 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblResourcesSkippedCount.anchor = GridBagConstraints.WEST; gbc_lblResourcesSkippedCount.gridx = 3; gbc_lblResourcesSkippedCount.gridy = 8; - panel_1.add(lblResourcesSkippedCount, gbc_lblResourcesSkippedCount); + leftPanel.add(lblResourcesSkippedCount, gbc_lblResourcesSkippedCount); JLabel labelResourcesSkippedPercent = new JLabel("0%"); GridBagConstraints gbc_labelResourcesSkippedPercent = new GridBagConstraints(); gbc_labelResourcesSkippedPercent.insets = new Insets(0, 0, 5, 5); gbc_labelResourcesSkippedPercent.gridx = 4; gbc_labelResourcesSkippedPercent.gridy = 8; - panel_1.add(labelResourcesSkippedPercent, gbc_labelResourcesSkippedPercent); + leftPanel.add(labelResourcesSkippedPercent, gbc_labelResourcesSkippedPercent); JLabel lblArchivesFailed = new JLabel("Archives Failed:"); lblArchivesFailed.setHorizontalAlignment(SwingConstants.RIGHT); @@ -400,7 +451,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblArchivesFailed.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesFailed.gridx = 2; gbc_lblArchivesFailed.gridy = 10; - panel_1.add(lblArchivesFailed, gbc_lblArchivesFailed); + leftPanel.add(lblArchivesFailed, gbc_lblArchivesFailed); JLabel lblArchivesFailedCount = new JLabel("0"); GridBagConstraints gbc_lblArchivesFailedCount = new GridBagConstraints(); @@ -408,14 +459,14 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblArchivesFailedCount.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesFailedCount.gridx = 3; gbc_lblArchivesFailedCount.gridy = 10; - panel_1.add(lblArchivesFailedCount, gbc_lblArchivesFailedCount); + leftPanel.add(lblArchivesFailedCount, gbc_lblArchivesFailedCount); JLabel lblArchivesFailedPercent = new JLabel("0%"); GridBagConstraints gbc_lblArchivesFailedPercent = new GridBagConstraints(); gbc_lblArchivesFailedPercent.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesFailedPercent.gridx = 4; gbc_lblArchivesFailedPercent.gridy = 10; - panel_1.add(lblArchivesFailedPercent, gbc_lblArchivesFailedPercent); + leftPanel.add(lblArchivesFailedPercent, gbc_lblArchivesFailedPercent); JLabel lblResourcesFailed = new JLabel("Resources Failed:"); GridBagConstraints gbc_lblResourcesFailed = new GridBagConstraints(); @@ -423,7 +474,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblResourcesFailed.insets = new Insets(0, 0, 0, 5); gbc_lblResourcesFailed.gridx = 2; gbc_lblResourcesFailed.gridy = 11; - panel_1.add(lblResourcesFailed, gbc_lblResourcesFailed); + leftPanel.add(lblResourcesFailed, gbc_lblResourcesFailed); JLabel lblResourcesFailedCount = new JLabel("0"); GridBagConstraints gbc_lblResourcesFailedCount = new GridBagConstraints(); @@ -431,25 +482,33 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblResourcesFailedCount.insets = new Insets(0, 0, 0, 5); gbc_lblResourcesFailedCount.gridx = 3; gbc_lblResourcesFailedCount.gridy = 11; - panel_1.add(lblResourcesFailedCount, gbc_lblResourcesFailedCount); + leftPanel.add(lblResourcesFailedCount, gbc_lblResourcesFailedCount); JLabel lblResourcesFailedPercent = new JLabel("0%"); GridBagConstraints gbc_lblResourcesFailedPercent = new GridBagConstraints(); gbc_lblResourcesFailedPercent.insets = new Insets(0, 0, 0, 5); gbc_lblResourcesFailedPercent.gridx = 4; gbc_lblResourcesFailedPercent.gridy = 11; - panel_1.add(lblResourcesFailedPercent, gbc_lblResourcesFailedPercent); + leftPanel.add(lblResourcesFailedPercent, gbc_lblResourcesFailedPercent); + + copyOperations.addBatchListener(() -> { + SwingUtilities.invokeLater(() -> { + + //Set all of the label text + + }); + }); } private void setupRightProgressPane(JPanel progressPanel) { - JPanel panel_2 = new JPanel(); - progressPanel.add(panel_2); - GridBagLayout gbl_panel_2 = new GridBagLayout(); - gbl_panel_2.columnWidths = new int[] {30, 0, 90, 0, 30, 30, 0, 0}; - gbl_panel_2.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - gbl_panel_2.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; - gbl_panel_2.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; - panel_2.setLayout(gbl_panel_2); + JPanel rightPanel = new JPanel(); + progressPanel.add(rightPanel); + GridBagLayout gbl_rightPanel = new GridBagLayout(); + gbl_rightPanel.columnWidths = new int[] {30, 0, 90, 0, 30, 30, 0, 0}; + gbl_rightPanel.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + gbl_rightPanel.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + gbl_rightPanel.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + rightPanel.setLayout(gbl_rightPanel); JLabel lblNewLabel = new JLabel("Process Operation"); GridBagConstraints gbc_lblNewLabel = new GridBagConstraints(); @@ -457,7 +516,7 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblNewLabel.insets = new Insets(0, 0, 5, 5); gbc_lblNewLabel.gridx = 0; gbc_lblNewLabel.gridy = 0; - panel_2.add(lblNewLabel, gbc_lblNewLabel); + rightPanel.add(lblNewLabel, gbc_lblNewLabel); JLabel lblTotalArchives = new JLabel("Total Archives:"); GridBagConstraints gbc_lblTotalArchives = new GridBagConstraints(); @@ -465,7 +524,7 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblTotalArchives.insets = new Insets(0, 0, 5, 5); gbc_lblTotalArchives.gridx = 1; gbc_lblTotalArchives.gridy = 1; - panel_2.add(lblTotalArchives, gbc_lblTotalArchives); + rightPanel.add(lblTotalArchives, gbc_lblTotalArchives); JLabel lblTotalArchvesCount = new JLabel("0"); GridBagConstraints gbc_lblTotalArchvesCount = new GridBagConstraints(); @@ -473,7 +532,7 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblTotalArchvesCount.insets = new Insets(0, 0, 5, 5); gbc_lblTotalArchvesCount.gridx = 2; gbc_lblTotalArchvesCount.gridy = 1; - panel_2.add(lblTotalArchvesCount, gbc_lblTotalArchvesCount); + rightPanel.add(lblTotalArchvesCount, gbc_lblTotalArchvesCount); JLabel lblTotalResources = new JLabel("Total Resources:"); GridBagConstraints gbc_lblTotalResources = new GridBagConstraints(); @@ -481,7 +540,7 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblTotalResources.insets = new Insets(0, 0, 5, 5); gbc_lblTotalResources.gridx = 1; gbc_lblTotalResources.gridy = 2; - panel_2.add(lblTotalResources, gbc_lblTotalResources); + rightPanel.add(lblTotalResources, gbc_lblTotalResources); JLabel lblTotalResourcesCount = new JLabel("0"); GridBagConstraints gbc_lblTotalResourcesCount = new GridBagConstraints(); @@ -489,7 +548,7 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblTotalResourcesCount.insets = new Insets(0, 0, 5, 5); gbc_lblTotalResourcesCount.gridx = 2; gbc_lblTotalResourcesCount.gridy = 2; - panel_2.add(lblTotalResourcesCount, gbc_lblTotalResourcesCount); + rightPanel.add(lblTotalResourcesCount, gbc_lblTotalResourcesCount); JLabel lblArchivesProcessed = new JLabel("Archives Processed:"); GridBagConstraints gbc_lblArchivesProcessed = new GridBagConstraints(); @@ -497,7 +556,7 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblArchivesProcessed.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesProcessed.gridx = 1; gbc_lblArchivesProcessed.gridy = 4; - panel_2.add(lblArchivesProcessed, gbc_lblArchivesProcessed); + rightPanel.add(lblArchivesProcessed, gbc_lblArchivesProcessed); lblArchivesProcessed.setHorizontalAlignment(SwingConstants.RIGHT); JLabel lblArchivesProcessedCount = new JLabel("0"); @@ -506,14 +565,14 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblArchivesProcessedCount.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesProcessedCount.gridx = 2; gbc_lblArchivesProcessedCount.gridy = 4; - panel_2.add(lblArchivesProcessedCount, gbc_lblArchivesProcessedCount); + rightPanel.add(lblArchivesProcessedCount, gbc_lblArchivesProcessedCount); JLabel lblArchivesProcessedPercent = new JLabel("0%"); GridBagConstraints gbc_lblArchivesProcessedPercent = new GridBagConstraints(); gbc_lblArchivesProcessedPercent.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesProcessedPercent.gridx = 3; gbc_lblArchivesProcessedPercent.gridy = 4; - panel_2.add(lblArchivesProcessedPercent, gbc_lblArchivesProcessedPercent); + rightPanel.add(lblArchivesProcessedPercent, gbc_lblArchivesProcessedPercent); JLabel lblResourcesProcessed = new JLabel("Resources Processed:"); GridBagConstraints gbc_lblResourcesProcessed = new GridBagConstraints(); @@ -521,7 +580,7 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblResourcesProcessed.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesProcessed.gridx = 1; gbc_lblResourcesProcessed.gridy = 5; - panel_2.add(lblResourcesProcessed, gbc_lblResourcesProcessed); + rightPanel.add(lblResourcesProcessed, gbc_lblResourcesProcessed); JLabel lblResourcesProcessedCount = new JLabel("0"); GridBagConstraints gbc_lblResourcesProcessedCount = new GridBagConstraints(); @@ -529,14 +588,14 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblResourcesProcessedCount.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesProcessedCount.gridx = 2; gbc_lblResourcesProcessedCount.gridy = 5; - panel_2.add(lblResourcesProcessedCount, gbc_lblResourcesProcessedCount); + rightPanel.add(lblResourcesProcessedCount, gbc_lblResourcesProcessedCount); JLabel lblResourcesProcessedPercent = new JLabel("0%"); GridBagConstraints gbc_lblResourcesProcessedPercent = new GridBagConstraints(); gbc_lblResourcesProcessedPercent.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesProcessedPercent.gridx = 3; gbc_lblResourcesProcessedPercent.gridy = 5; - panel_2.add(lblResourcesProcessedPercent, gbc_lblResourcesProcessedPercent); + rightPanel.add(lblResourcesProcessedPercent, gbc_lblResourcesProcessedPercent); JLabel lblArchivesSkipped = new JLabel("Archives Skipped:"); GridBagConstraints gbc_lblArchivesSkipped = new GridBagConstraints(); @@ -544,7 +603,7 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblArchivesSkipped.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesSkipped.gridx = 1; gbc_lblArchivesSkipped.gridy = 7; - panel_2.add(lblArchivesSkipped, gbc_lblArchivesSkipped); + rightPanel.add(lblArchivesSkipped, gbc_lblArchivesSkipped); JLabel lblArchivesSkippedCount = new JLabel("0"); GridBagConstraints gbc_lblArchivesSkippedCount = new GridBagConstraints(); @@ -552,14 +611,14 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblArchivesSkippedCount.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesSkippedCount.gridx = 2; gbc_lblArchivesSkippedCount.gridy = 7; - panel_2.add(lblArchivesSkippedCount, gbc_lblArchivesSkippedCount); + rightPanel.add(lblArchivesSkippedCount, gbc_lblArchivesSkippedCount); JLabel lblArchivesSkippedPercent = new JLabel("0%"); GridBagConstraints gbc_lblArchivesSkippedPercent = new GridBagConstraints(); gbc_lblArchivesSkippedPercent.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesSkippedPercent.gridx = 3; gbc_lblArchivesSkippedPercent.gridy = 7; - panel_2.add(lblArchivesSkippedPercent, gbc_lblArchivesSkippedPercent); + rightPanel.add(lblArchivesSkippedPercent, gbc_lblArchivesSkippedPercent); JLabel lblResourcesSkipped = new JLabel("Resources Skipped:"); GridBagConstraints gbc_lblResourcesSkipped = new GridBagConstraints(); @@ -567,7 +626,7 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblResourcesSkipped.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesSkipped.gridx = 1; gbc_lblResourcesSkipped.gridy = 8; - panel_2.add(lblResourcesSkipped, gbc_lblResourcesSkipped); + rightPanel.add(lblResourcesSkipped, gbc_lblResourcesSkipped); JLabel lblResourcesSkippedCount = new JLabel("0"); GridBagConstraints gbc_lblResourcesSkippedCount = new GridBagConstraints(); @@ -575,14 +634,14 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblResourcesSkippedCount.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesSkippedCount.gridx = 2; gbc_lblResourcesSkippedCount.gridy = 8; - panel_2.add(lblResourcesSkippedCount, gbc_lblResourcesSkippedCount); + rightPanel.add(lblResourcesSkippedCount, gbc_lblResourcesSkippedCount); JLabel lblResourcesSkippedPercent = new JLabel("0%"); GridBagConstraints gbc_lblResourcesSkippedPercent = new GridBagConstraints(); gbc_lblResourcesSkippedPercent.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesSkippedPercent.gridx = 3; gbc_lblResourcesSkippedPercent.gridy = 8; - panel_2.add(lblResourcesSkippedPercent, gbc_lblResourcesSkippedPercent); + rightPanel.add(lblResourcesSkippedPercent, gbc_lblResourcesSkippedPercent); JLabel lblArchivesFailed = new JLabel("Archives Failed:"); GridBagConstraints gbc_lblArchivesFailed = new GridBagConstraints(); @@ -590,7 +649,7 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblArchivesFailed.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesFailed.gridx = 1; gbc_lblArchivesFailed.gridy = 10; - panel_2.add(lblArchivesFailed, gbc_lblArchivesFailed); + rightPanel.add(lblArchivesFailed, gbc_lblArchivesFailed); JLabel lblArchivesFailedCount = new JLabel("0"); GridBagConstraints gbc_lblArchivesFailedCount = new GridBagConstraints(); @@ -598,14 +657,14 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblArchivesFailedCount.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesFailedCount.gridx = 2; gbc_lblArchivesFailedCount.gridy = 10; - panel_2.add(lblArchivesFailedCount, gbc_lblArchivesFailedCount); + rightPanel.add(lblArchivesFailedCount, gbc_lblArchivesFailedCount); JLabel lblArchivesFailedPercent = new JLabel("0%"); GridBagConstraints gbc_lblArchivesFailedPercent = new GridBagConstraints(); gbc_lblArchivesFailedPercent.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesFailedPercent.gridx = 3; gbc_lblArchivesFailedPercent.gridy = 10; - panel_2.add(lblArchivesFailedPercent, gbc_lblArchivesFailedPercent); + rightPanel.add(lblArchivesFailedPercent, gbc_lblArchivesFailedPercent); JLabel lblResourcesFailed = new JLabel("Resources Failed:"); GridBagConstraints gbc_lblResourcesFailed = new GridBagConstraints(); @@ -613,7 +672,7 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblResourcesFailed.insets = new Insets(0, 0, 0, 5); gbc_lblResourcesFailed.gridx = 1; gbc_lblResourcesFailed.gridy = 11; - panel_2.add(lblResourcesFailed, gbc_lblResourcesFailed); + rightPanel.add(lblResourcesFailed, gbc_lblResourcesFailed); JLabel lblResourcesFailedCount = new JLabel("0"); GridBagConstraints gbc_lblResourcesFailedCount = new GridBagConstraints(); @@ -621,21 +680,23 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblResourcesFailedCount.insets = new Insets(0, 0, 0, 5); gbc_lblResourcesFailedCount.gridx = 2; gbc_lblResourcesFailedCount.gridy = 11; - panel_2.add(lblResourcesFailedCount, gbc_lblResourcesFailedCount); + rightPanel.add(lblResourcesFailedCount, gbc_lblResourcesFailedCount); JLabel lblResourcesFailedPercent = new JLabel("0%"); GridBagConstraints gbc_lblResourcesFailedPercent = new GridBagConstraints(); gbc_lblResourcesFailedPercent.insets = new Insets(0, 0, 0, 5); gbc_lblResourcesFailedPercent.gridx = 3; gbc_lblResourcesFailedPercent.gridy = 11; - panel_2.add(lblResourcesFailedPercent, gbc_lblResourcesFailedPercent); + rightPanel.add(lblResourcesFailedPercent, gbc_lblResourcesFailedPercent); } - private BatchRunner genCopyBatches() { + private BatchRunner genCopyBatches(File dir) { BatchRunner batchRunner = new BatchRunner("Copy Operations"); - for(int i = 0; i < 10; i++) { - Batch b = new Batch("File " + i); - batchRunner.addBatch(b); + if(dir != null) { + for(File f : dir.listFiles()) { + Batch b = new Batch(f.getName()); + batchRunner.addBatch(b); + } } return batchRunner; } @@ -658,6 +719,8 @@ public void update() { @Override public void mouseWheelMoved(MouseWheelEvent e) { + System.out.println("Scrolled: " + e.getComponent()); + System.out.println("Child: " + e.getComponent().getComponentAt(e.getPoint())); if(e.getSource() instanceof JTabbedPane) { JTabbedPane pane = (JTabbedPane) e.getSource(); Component scrolledComponent = pane.getComponentAt(e.getPoint()); From a3e96a4aa09e594c89afda37600158fa1590fc0e Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Sun, 5 May 2024 21:22:40 -0400 Subject: [PATCH 07/19] More progress --- .gitignore | 2 +- .../excite/modding/concurrent/Batch.java | 113 ++- .../modding/concurrent/BatchContainer.java | 4 +- .../modding/concurrent/BatchRunner.java | 14 +- .../modding/concurrent/BatchWorker.java | 4 +- .../excite/modding/concurrent/Batcher.java | 29 +- .../excite/modding/ui/CustomProgressBar.java | 18 + .../excite/modding/ui/EJTabbedPane.java | 167 ++++ .../excite/modding/ui/FixedCellGrid.java | 148 ---- .../excite/modding/ui/FixedCellSizeGrid.java | 101 --- .../excite/modding/ui/Window.java | 741 +++++++++--------- .../excite/modding/ui/WrapLayout.java | 192 +++++ .../unarchiver/QuickAccessArchive.java | 37 + .../excite/modding/unarchiver/Unarchiver.java | 110 ++- .../excite/modding/util/FileUtils.java | 43 + 15 files changed, 1043 insertions(+), 680 deletions(-) create mode 100644 src/main/java/com/gamebuster19901/excite/modding/ui/CustomProgressBar.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/ui/EJTabbedPane.java delete mode 100644 src/main/java/com/gamebuster19901/excite/modding/ui/FixedCellGrid.java delete mode 100644 src/main/java/com/gamebuster19901/excite/modding/ui/FixedCellSizeGrid.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/ui/WrapLayout.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/unarchiver/QuickAccessArchive.java diff --git a/.gitignore b/.gitignore index f7fcb5a..af9628a 100644 --- a/.gitignore +++ b/.gitignore @@ -24,7 +24,7 @@ build/tmp hs_err_pid*.log #Run -/run +/run* /backups # output diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java index 75d71b0..29f8eb8 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java @@ -11,7 +11,7 @@ public class Batch implements Batcher { private final String name; - private final Set runnables = new HashSet<>(); + private final Set> runnables = new HashSet<>(); private final LinkedHashSet listeners = new LinkedHashSet<>(); private volatile boolean accepting = true; @@ -27,8 +27,8 @@ public String getName() { @Override public void addRunnable(Callable runnable) { if(accepting) { - BatchedCallable b = new BatchedCallable(runnable); - runnables.add(new BatchedCallable(runnable)); + BatchedCallable b = new BatchedCallable<>(this, runnable); + runnables.add(new BatchedCallable<>(this, runnable)); updateListeners(); } else { @@ -39,8 +39,8 @@ public void addRunnable(Callable runnable) { @Override public void addRunnable(Runnable runnable) { if(accepting) { - BatchedCallable b = new BatchedCallable(runnable); - runnables.add(new BatchedCallable(runnable)); + BatchedCallable b = new BatchedCallable<>(this, runnable); + runnables.add(new BatchedCallable<>(this, runnable)); updateListeners(); } else { @@ -61,11 +61,12 @@ public void addListener(BatchListener listener) { } @Override - public Collection getRunnables() { + public Collection> getRunnables() { return Set.copyOf(runnables); } - + @Override + @SuppressWarnings("unchecked") public Collection getListeners() { return (Collection) listeners.clone(); } @@ -73,7 +74,7 @@ public Collection getListeners() { public void shutdownNow() throws InterruptedException { accepting = false; Shutdown shutdown = new Shutdown(); - for(BatchedCallable r : runnables) { + for(BatchedCallable r : runnables) { if(r.getState() == State.NEW) { r.shutdown(shutdown); } @@ -91,44 +92,98 @@ private void notAccepting() { throw new IllegalStateException("Batch is not accepting new tasks or listeners."); } - public class BatchedCallable implements Callable { + /** + * A wrapper class for a {@link Callable} object that participates in a batch execution managed by a {@link Batcher}. + * + * This class allows for the creation of callables that can be tracked and managed by a batching system. It provides methods + * to get the execution state, retrieve the result after completion, and handle exceptions. + * + * @param the type of the result produced by the wrapped {@link Callable} + */ + public static class BatchedCallable implements Callable { + private final Batcher batch; private final Callable child; private volatile SoftReference threadRef; protected volatile Throwable thrown; protected volatile boolean finished = false; + protected volatile T result; + - public BatchedCallable(Runnable r) { - this(() -> { + /** + * Creates a new BatchedCallable instance for a provided {@link Runnable} object. + *

+ * This convenience constructor takes a Runnable and converts it to a Callable that simply calls the {@link Runnable#run} method + * and returns null. It then delegates to the main constructor with the converted callable. + * + * @param batch the {@link Batcher} instance managing this callable + * @param r the {@link Runnable} object to be wrapped + */ + public BatchedCallable(Batcher batch, Runnable r) { + this(batch, () -> { r.run(); return null; }); } - public BatchedCallable(Callable c) { + /** + * Creates a new BatchedCallable instance for the provided {@link Callable} object. + *

+ * This constructor wraps a given Callable and associates it with the specified Batcher. The Batcher is + * notified of updates to the state of this callable. + * + * @param batch the {@link Batcher} instance managing this callable + * @param c the {@link Callable} object to be wrapped + */ + public BatchedCallable(Batcher batch, Callable c) { + this.batch = batch; this.child = c; - updateListeners(); + batch.updateListeners(); } + /** + * Implements the `call` method of the {@link Callable} interface. + *

+ * This method executes the wrapped `Callable` object and stores the result. It also updates the state of this object + * and notifies the associated Batcher before and after execution. If any exceptions occur during execution, they are + * stored but not re-thrown by this method. The caller of this method is responsible for handling any exceptions. + * + * @return the result of the wrapped callable's execution (which may be null), or null if an exception occurred + */ @Override public T call() { Thread thread; try { thread = Thread.currentThread(); threadRef = new SoftReference<>(thread); - updateListeners(); - child.call(); + batch.updateListeners(); + result = child.call(); + return result; } catch(Throwable t) { this.thrown = t; } finally { finished = true; - updateListeners(); + batch.updateListeners(); } return null; } + /** + * Gets the current execution state of the wrapped callable. + * + * This method examines the internal state and thread reference to determine the current execution state. It can return one of the following states: + * + *

    + *
  • NEW: The callable has not yet been submitted for execution. + *
  • TERMINATED: The callable has finished execution, either successfully or with an exception. + *
  • The actual state of the thread running the callable (e.g., `RUNNING`, `WAITING`): + *

    If a thread is currently executing the callable, this state reflects the thread's lifecycle. + *

+ * + * @return the current state of the callable execution, as described above + */ public State getState() { if(finished) { //the thread is no longer working on this runnable return State.TERMINATED; @@ -143,10 +198,36 @@ public State getState() { return thread.getState(); } + /** + * Retrieves the result of the computation after the {@link #call} method has finished executing. + * + * @throws IllegalStateException if the {@link #call} method has not yet finished executing. + * @return the result of the computation (which may be null), or {@code null} if the computation threw an exception. + */ + public T getResult() { + if(!finished) { + throw new IllegalStateException("Cannot obtain the result before it is calculated!"); + } + return result; + } + + /** + * Gets the exception thrown by the wrapped callable, if any. + *

+ * This method returns the exception that was thrown during the execution of the wrapped callable, or null if no exception + * occurred. + * + * @return the exception thrown by the wrapped callable, or null if no exception occurred + */ public Throwable getThrown() { return thrown; } + /** + * Sets the state of this callable to a proper shutdown state + * + * @param shutdown a dummy exception representing that this thread has failed to complete due to being shutdown. + */ protected void shutdown(Shutdown shutdown) { finished = true; thrown = shutdown; diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java index 51a6a10..59e2785 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java @@ -2,11 +2,13 @@ import java.util.Collection; +import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; + public interface BatchContainer { public abstract String getName(); - public Collection.BatchedCallable> getRunnables(); + public Collection> getRunnables(); public Collection getListeners(); diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java index 811a05c..ed0e104 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java @@ -6,6 +6,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; + public class BatchRunner implements BatchWorker { private final String name; @@ -55,7 +57,9 @@ public void startBatch() throws InterruptedException { } synchronized(batches) { started = true; - executor.invokeAll(getRunnables()); + for(Batcher batch : batches) { + executor.invokeAll(batch.getRunnables()); + } } } } @@ -79,9 +83,9 @@ public void shutdownNow() throws InterruptedException { } @Override - public Collection.BatchedCallable> getRunnables() { + public Collection> getRunnables() { synchronized(batches) { - LinkedHashSet.BatchedCallable> ret = new LinkedHashSet<>(); + LinkedHashSet> ret = new LinkedHashSet<>(); for(Batcher batch : batches) { ret.addAll(batch.getRunnables()); } @@ -116,8 +120,8 @@ public Collection> getBatches() { public int getCompleted() { int ret = 0; - Collection.BatchedCallable> callables = getRunnables(); - for(Batch.BatchedCallable callable : callables) {ret++;} + Collection> callables = getRunnables(); + for(BatchedCallable callable : callables) {ret++;} return ret; } diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchWorker.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchWorker.java index aace9af..713b370 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchWorker.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchWorker.java @@ -3,6 +3,8 @@ import java.util.Collection; import java.util.concurrent.TimeUnit; +import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; + public interface BatchWorker extends BatchContainer { public abstract void addBatch(Batcher batcher); @@ -13,7 +15,7 @@ public interface BatchWorker extends BatchContainer { public void shutdownNow() throws InterruptedException; - public Collection.BatchedCallable> getRunnables(); + public Collection> getRunnables(); public Collection getListeners(); diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batcher.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batcher.java index 0a3e795..bd2cb19 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batcher.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batcher.java @@ -3,18 +3,45 @@ import java.util.Collection; import java.util.concurrent.Callable; +import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; + public interface Batcher extends BatchContainer { public abstract void addRunnable(Callable runnable); public abstract void addRunnable(Runnable runnable); + @SuppressWarnings({ "rawtypes", "unchecked" }) + public default void addRunnables(Collection runnables) { + if(runnables.size() > 0) { + Object o = runnables.iterator().next(); + if(o instanceof Callable) { + runnables.forEach((r) -> { + addRunnable((Callable)r); + }); + } + else if (o instanceof Runnable) { + runnables.forEach((r) -> { + addRunnable((Runnable)r); + }); + } + else { + throw new IllegalArgumentException(o.getClass().toString()); + } + } + else { + return; + } + } + public abstract void addListener(BatchListener listener); public void shutdownNow() throws InterruptedException; - public Collection.BatchedCallable> getRunnables(); + public Collection> getRunnables(); public Collection getListeners(); + public void updateListeners(); + } diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/CustomProgressBar.java b/src/main/java/com/gamebuster19901/excite/modding/ui/CustomProgressBar.java new file mode 100644 index 0000000..8f77905 --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/CustomProgressBar.java @@ -0,0 +1,18 @@ +package com.gamebuster19901.excite.modding.ui; + +import javax.swing.JProgressBar; + +public class CustomProgressBar extends JProgressBar { + + @Override + public String getString() { + if(this.getPercentComplete() <= 0d) { + return "Not Started"; + } + if(this.getPercentComplete() < 1d) { + return "Progress: " + ((int)(this.getPercentComplete() * 100)) + "%"; + } + return "Complete"; + } + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/EJTabbedPane.java b/src/main/java/com/gamebuster19901/excite/modding/ui/EJTabbedPane.java new file mode 100644 index 0000000..b3a76e0 --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/EJTabbedPane.java @@ -0,0 +1,167 @@ +package com.gamebuster19901.excite.modding.ui; + +import java.awt.Component; + +import javax.swing.Icon; +import javax.swing.JTabbedPane; + +/** + * A custom tabbed pane component that extends {@link javax.swing.JTabbedPane} and provides additional functionalities for managing tabs. + * + * This class offers a convenience layer on top of the standard `JTabbedPane` by: + * * Encapsulating tab information within a {@link Tab} record. + * * Providing methods for adding and retrieving tabs using `Tab` objects. + * * Propagating `IndexOutOfBoundsException` for methods that interact with tabs to ensure consistent error handling. + * + * @see javax.swing.JTabbedPane + * @see Tab + */ +public class EJTabbedPane extends JTabbedPane { + + /** + * Constructs a new EJTabbedPane with the default tab placement (TOP). + */ + public EJTabbedPane() { + super(); + } + + /** + * Constructs a new EJTabbedPane with the specified tab placement. + * + * @param tabPlacement The placement of the tabs. This can be one of the following values from {@link javax.swing.JTabbedPane}: + * * {@link JTabbedPane#TOP} + * * {@link JTabbedPane#BOTTOM} + * * {@link JTabbedPane#LEFT} + * * {@link JTabbedPane#RIGHT} + * @throws IllegalArgumentException if the tabPlacement is not a valid value. + */ + public EJTabbedPane(int tabPlacement) throws IllegalArgumentException { + super(tabPlacement); + } + + /** + * Constructs a new EJTabbedPane with the specified tab placement and layout policy. + * + * @param tabPlacement The placement of the tabs. Refer to {@link #EJTabbedPane(int)} for valid values. + * @param tabLayoutPolicy The layout policy for the tabs. This can be one of the following values from {@link javax.swing.JTabbedPane}: + * * {@link JTabbedPane#WRAP_TAB_LAYOUT} + * * {@link JTabbedPane#SCROLL_TAB_LAYOUT} + * @throws IllegalArgumentException if the tabPlacement or tabLayoutPolicy is not a valid value. + */ + public EJTabbedPane(int tabPlacement, int tabLayoutPolicy) throws IllegalArgumentException { + super(tabPlacement, tabLayoutPolicy); + } + + /** + * Adds a new tab to the EJTabbedPane. + * + * This method extracts the title and component from the provided {@link Tab} object and calls the underlying `JTabbedPane` method to add the tab. + * + * @param tab The tab object containing the information for the new tab. + * @return The same `tab` object that was provided as input. + */ + public Tab addTab(Tab tab) { + this.addTab(tab.title, tab.icon, tab.component, tab.tip); + return tab; + } + + /** + * Inserts a new tab at the specified index within the EJTabbedPane. + * + * This method uses the information from the provided {@link Tab} object (title, icon, component, tooltip) to call the underlying `JTabbedPane` method for insertion. + * + * @param tab The tab object containing the information for the new tab. + * @param index The index at which to insert the tab. + * @return The same `tab` object that was provided as input. + * @throws IndexOutOfBoundsException if the index is invalid. + */ + public Tab putTab(Tab tab, int index) throws IndexOutOfBoundsException { + this.insertTab(tab.title, tab.icon, tab.component, tab.tip, index); + return tab; + } + + /** + * Retrieves a {@link Tab} object from the EJTabbedPane by its title. + * + * This method first finds the index of the tab with the matching title and then calls the `getTab(int index)` method. + * + * @param title The title of the tab to retrieve. + * @return A `Tab` object representing the tab with the specified title, or null if the tab is not found. + */ + public Tab getTab(String title) throws IndexOutOfBoundsException { + int index = this.indexOfTab(title); + return getTab(index); + } + + /** + * Retrieves a {@link Tab} object from the EJTabbedPane by its index. + * + * This method extracts the title, icon, component, and tooltip from the underlying `JTabbedPane` at the specified index and creates a new `Tab` object with this information. + * + * @param index The index of the tab to retrieve. + * @return A `Tab` object representing the tab at the specified index, or null if the index is invalid. + * @throws IndexOutOfBoundsException if the index is invalid. + */ + public Tab getTab(int index) throws IndexOutOfBoundsException { + if(index < 0 || index > this.getComponentCount()) { + return null; + } + String title = this.getTitleAt(index); + Icon icon = this.getIconAt(index); + Component component = this.getComponentAt(index); + String tip = this.getToolTipTextAt(index); + return new Tab(title, icon, component, tip); + } + + public Tab getSelectedTab() { + return getTab(getSelectedIndex()); + } + + public int getIndex(Tab tab) { + if(tab.title != null) { + return this.indexOfTab(tab.title); + } + if(tab.icon != null) { + return this.indexOfTab(tab.icon); + } + throw new IllegalArgumentException("Tab has null title and null icon, cannot obtain index"); + } + + public void setSelectedTab(Tab tab) { + this.setSelectedIndex(getIndex(tab)); + this.invalidate(); + } + + @Override + protected void fireStateChanged() { + super.fireStateChanged(); + } + + /** + * A record that encapsulates information about a single tab. + */ + public static final record Tab(String title, Icon icon, Component component, String tip) { + + /** + * Constructs a new Tab object with the specified title and component. + * + * @param title The title of the tab. + * @param component The component to be displayed in the tab. + */ + public Tab(String title, Component component) { + this(title, null, component, null); + } + + /** + * Constructs a new Tab object with the specified title, icon, and component. + * + * @param title The title of the tab. + * @param icon The icon to be displayed on the tab. + * @param component The component to be displayed in the tab. + */ + public Tab(String title, Icon icon, Component component) { + this(title, icon, component, null); + } + } +} + diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/FixedCellGrid.java b/src/main/java/com/gamebuster19901/excite/modding/ui/FixedCellGrid.java deleted file mode 100644 index 27c6fc7..0000000 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/FixedCellGrid.java +++ /dev/null @@ -1,148 +0,0 @@ -package com.gamebuster19901.excite.modding.ui; - -import java.awt.Component; -import java.util.Iterator; -import java.util.Map.Entry; -import java.util.NavigableSet; -import java.util.TreeMap; - -import javax.swing.JComponent; -import java.awt.*; - -public abstract class FixedCellGrid extends JComponent { - - protected final int padding; - protected final TreeMap components = new TreeMap<>(); - protected final NavigableSet navigator = components.navigableKeySet(); - - public FixedCellGrid(int padding) { - this.padding = padding; - } - - @Override - protected void paintComponent(Graphics g) { - super.paintComponent(g); - - components.forEach((index, component) -> { - component.setBounds(calculateCellX(index), calculateCellY(index), getCellWidth(), getCellHeight()); - }); - - } - - @Override - public void setPreferredSize(Dimension dimension) { - super.setPreferredSize(dimension); - } - - @Override - public void setBounds(int x, int y, int width, int height) { - super.setBounds(x, y, width, height); - this.setPreferredSize(new Dimension(width - x, height - y)); - } - - protected abstract void onGridUpdate(); - - protected abstract int calculateCellX(int index); - - protected abstract int getCellWidth(); - - protected abstract int calculateCellY(int index); - - protected abstract int getCellHeight(); - - public final Component getComponent(Integer index) { - return components.get(index); - } - - public final Component putComponent(Integer index, Component component) { - super.add(component); - System.out.println("Adding component " + component + " at index " + index); - return components.put(index, component); - } - - public final void removeComponent(Integer index) { - Component toRemove = getComponent(index); - if(toRemove != null) { - components.remove(index); //we want to remove from the grid directly since it will be much faster than the overridden FixedCellGrid.remove() - super.remove(toRemove); //Then use super to remove the component reference from swing - } - } - - @Override - public void removeAll() { - components.clear(); - super.removeAll(); - } - - public final int getLowestFreeCell() { - Integer prevIndex = 0; - Integer index = -1; - while(index != null) { - index = navigator.higher(index); - if(index == null) { - return components.size(); - } - if(index - prevIndex > 1) { //we've found a gap in the defined cells - return prevIndex + 1; - } - prevIndex = index; - } - - return components.size(); - } - - public final Component getFirstComponent() { - return components.firstEntry().getValue(); - } - - public final Component getLastComponent() { - return components.lastEntry().getValue(); - } - - public final TreeMap getComponentMap() { - return components; - } - - @Override - @Deprecated - public Component add(Component component) { - //super.add(component); - System.out.println("Adding component at index " + getLowestFreeCell()); - putComponent(getLowestFreeCell(), component); - return component; - } - - @Override - @Deprecated - public Component add(Component component, int index) { - putComponent(index, component); - return component; - } - - @Override - @Deprecated - public void remove(Component component) { - Iterator> set = components.entrySet().iterator(); - while(set.hasNext()) { - Entry e = set.next(); - if(e.getValue() == component) { - set.remove(); - break; - } - } - super.remove(component); - } - - @Override - @Deprecated - public void remove(int index) { - removeComponent(index); - } - - @Override - @Deprecated - public void add(Component component, Object constraints) { - add(component); // Ignore constraints, components are positioned based on the cell location and size - } - -} diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/FixedCellSizeGrid.java b/src/main/java/com/gamebuster19901/excite/modding/ui/FixedCellSizeGrid.java deleted file mode 100644 index 1c35c5a..0000000 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/FixedCellSizeGrid.java +++ /dev/null @@ -1,101 +0,0 @@ -package com.gamebuster19901.excite.modding.ui; -import java.awt.*; - -public class FixedCellSizeGrid extends FixedCellGrid { - - private int cellWidth; - private int cellHeight; - private int scroll; - - public FixedCellSizeGrid(Dimension gridDimension, Dimension cellDimension) { - this(gridDimension, cellDimension, 0); - } - - public FixedCellSizeGrid(Dimension gridDimension, Dimension cellDimension, int padding) { - super(padding); - this.cellWidth = cellDimension.width; - this.cellHeight = cellDimension.height; - this.setPreferredSize(gridDimension); - try { - calculateCellX(1); - } - catch(ArithmeticException e) { - throw new IllegalArgumentException("Grid size is too small, it cannot hold any cells!", e); - } - } - - @Override - public void setPreferredSize(Dimension dimension) { - super.setPreferredSize(dimension); - onGridUpdate(); - } - - @Override - protected void onGridUpdate() { - components.forEach((index, component) -> { - component.setBounds(calculateCellX(index), calculateCellY(index), getCellWidth(), getCellHeight()); - }); - System.out.println(this.getPreferredSize()); - System.out.println(cellWidth); - invalidate(); - } - - protected void setCellSize(Dimension dimension) { - this.cellWidth = dimension.width; - this.cellHeight = dimension.height; - onGridUpdate(); - } - - @Override - protected int getCellWidth() { - return cellWidth; - } - - @Override - protected int getCellHeight() { - return cellHeight; - } - - @Override - protected int calculateCellX(int index) { - return ((((index % (this.getPreferredSize().width / (cellWidth + padding))) * (cellWidth + padding))) + (padding / 2)); - } - - private int calculateCellYRaw(int index) { - int rowIndex = index / (this.getPreferredSize().width / (cellWidth + padding)); - return (rowIndex * (cellHeight + padding)) / (cellHeight + padding); - } - - private int getVisibleRows() { - return this.getPreferredSize().height / (cellHeight + padding); - } - - private int getMaxScroll() { - return Math.max(0, calculateCellYRaw(components.size()) - getVisibleRows()); - } - - protected int calculateCellY(int index) { - int rowIndex = index / (this.getPreferredSize().width / (cellWidth + padding)); - return (rowIndex * (cellHeight + padding)) - (scroll * (cellHeight + padding)); - } - - public int getScroll() { - return scroll; - } - - public void scroll(int offset) { - int newScroll = scroll + offset; - System.out.println("Max scroll: " + getMaxScroll()); - if(newScroll < 0) { - scroll = 0; - } - else if(newScroll > getMaxScroll()) { - scroll = getMaxScroll(); - } - else { - scroll = newScroll; - } - onGridUpdate(); - } - -} diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java index 4deaa9c..17d6b78 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java @@ -1,82 +1,78 @@ package com.gamebuster19901.excite.modding.ui; -import java.awt.Component; import java.awt.Dimension; import java.awt.EventQueue; + +import javax.swing.JFrame; + +import java.awt.GridBagLayout; +import java.awt.GridLayout; + +import javax.swing.JLabel; +import javax.swing.JOptionPane; + +import java.awt.GridBagConstraints; import java.awt.Insets; -import java.awt.event.MouseWheelEvent; -import java.awt.event.MouseWheelListener; import java.io.File; +import java.io.FileNotFoundException; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; -import java.lang.reflect.InvocationTargetException; import java.nio.file.Files; +import java.nio.file.NotDirectoryException; import java.nio.file.Path; -import java.util.Collection; import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.concurrent.Callable; -import javax.swing.JFrame; +import javax.swing.JTextField; +import javax.swing.ScrollPaneConstants; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; + +import com.gamebuster19901.excite.modding.concurrent.Batch; import com.gamebuster19901.excite.modding.concurrent.BatchListener; import com.gamebuster19901.excite.modding.concurrent.BatchRunner; import com.gamebuster19901.excite.modding.concurrent.Batcher; +import com.gamebuster19901.excite.modding.ui.EJTabbedPane.Tab; +import com.gamebuster19901.excite.modding.unarchiver.Unarchiver; +import com.gamebuster19901.excite.modding.util.FileUtils; import com.gamebuster19901.excite.modding.util.SplitOutputStream; -import com.gamebuster19901.excite.modding.concurrent.Batch; -import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; -import com.gamebuster19901.excite.modding.concurrent.BatchContainer; -import javax.swing.JTextField; -import javax.swing.ScrollPaneConstants; -import javax.swing.UIManager; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JFileChooser; -import javax.swing.JLabel; import javax.swing.JSeparator; -import javax.swing.JTabbedPane; import javax.swing.JSlider; import javax.swing.JProgressBar; import javax.swing.JScrollPane; -import javax.swing.SwingConstants; -import javax.swing.SwingUtilities; import javax.swing.JPanel; -import java.awt.GridLayout; -import java.awt.GridBagLayout; -import java.awt.GridBagConstraints; -import javax.swing.JTable; +import javax.swing.JTabbedPane; import javax.swing.JTextArea; -public class Window implements BatchListener, MouseWheelListener { - - static { - UIManager.getDefaults().put("TabbedPane.contentBorderInsets", new Insets(0,0,0,0)); - } +public class Window implements BatchListener { + private static final String CONSOLE = "Console Output"; + private static final String STATUS = "Status"; + private static final String PROGRESS = "Progress"; + private JFrame frame; - private JTextField textFieldDestDir; - private JTextField textFieldSourceDir; - private JSlider threadSlider; - private JLabel lblThreads; - private static Window window; - private final JProgressBar progressBar = new JProgressBar(); - private final JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP); - private final FixedCellGrid gridPanel = genGridPanel(); - private JTable table; + private JTextField textFieldSource; + private JTextField textFieldDest; - private BatchRunner copyOperations; - private BatchRunner processOperations; - + private BatchRunner> copyOperations; + private BatchRunner processOperations; /** - * @wbp.parser.entryPoint + * Launch the application. */ - public static void main(String[] args) throws InterruptedException { - + public static void main(String[] args) { + Window window; EventQueue.invokeLater(new Runnable() { public void run() { try { Window window = new Window(); - Window.window = window; + window.frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } @@ -86,57 +82,142 @@ public void run() { /** * Create the application. - * @throws InterruptedException */ - public Window() throws InterruptedException { + public Window() { initialize(); - update(); } /** - * @wbp.parser.entryPoint + * Initialize the contents of the frame. */ - private void initialize() throws InterruptedException { + private void initialize() { + copyOperations = genCopyBatches(null, null); + processOperations = genProcessBatches(null); - copyOperations = genCopyBatches(null); - setupFrame(); - } - - private void setupFrame() { - frame = new JFrame(); // @wbp.parser.preferredRoot - frame.setTitle("ExciteModder"); + frame = new JFrame(); frame.setBounds(100, 100, 1000, 680); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - frame.getContentPane().setLayout(null); - frame.setResizable(false); - frame.setVisible(true); - - JLabel lblUnmoddedDirectory = new JLabel("Source Directory:"); - lblUnmoddedDirectory.setToolTipText("The directory of the unmodified, original ripped files."); - lblUnmoddedDirectory.setBounds(12, 12, 165, 15); - frame.getContentPane().add(lblUnmoddedDirectory); - - JLabel lblModdedDirectory = new JLabel("Destination Directory:"); - lblModdedDirectory.setToolTipText("Where ExciteModder will copy modified game files to."); - lblModdedDirectory.setBounds(12, 39, 165, 15); - frame.getContentPane().add(lblModdedDirectory); - - textFieldSourceDir = new JTextField(); - textFieldSourceDir.setColumns(10); - textFieldSourceDir.setBounds(171, 10, 578, 19); - frame.getContentPane().add(textFieldSourceDir); - - textFieldDestDir = new JTextField(); - textFieldDestDir.setBounds(171, 37, 578, 19); - frame.getContentPane().add(textFieldDestDir); - textFieldDestDir.setColumns(10); + GridBagLayout gridBagLayout = new GridBagLayout(); + gridBagLayout.columnWidths = new int[]{5, 0, 0, 0, 0, 0, 5, 0}; + gridBagLayout.rowHeights = new int[]{5, 0, 0, 5, 0, 0, 16, 0, 0}; + gridBagLayout.columnWeights = new double[]{0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + gridBagLayout.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, Double.MIN_VALUE}; + frame.getContentPane().setLayout(gridBagLayout); + + JLabel lblSourceDirectory = new JLabel("Source Directory"); + GridBagConstraints gbc_lblSourceDirectory = new GridBagConstraints(); + gbc_lblSourceDirectory.gridwidth = 2; + gbc_lblSourceDirectory.fill = GridBagConstraints.VERTICAL; + gbc_lblSourceDirectory.anchor = GridBagConstraints.EAST; + gbc_lblSourceDirectory.insets = new Insets(0, 0, 5, 5); + gbc_lblSourceDirectory.gridx = 1; + gbc_lblSourceDirectory.gridy = 1; + frame.getContentPane().add(lblSourceDirectory, gbc_lblSourceDirectory); + + textFieldSource = new JTextField(); + GridBagConstraints gbc_textFieldSource = new GridBagConstraints(); + gbc_textFieldSource.insets = new Insets(0, 0, 5, 5); + gbc_textFieldSource.fill = GridBagConstraints.BOTH; + gbc_textFieldSource.gridx = 3; + gbc_textFieldSource.gridy = 1; + frame.getContentPane().add(textFieldSource, gbc_textFieldSource); + textFieldSource.setColumns(10); JButton btnChangeSource = new JButton("Change"); - btnChangeSource.setToolTipText("Change where ExciteModder will copy the game files from"); - btnChangeSource.setBounds(761, 9, 117, 19); + GridBagConstraints gbc_btnChangeSource = new GridBagConstraints(); + gbc_btnChangeSource.fill = GridBagConstraints.VERTICAL; + gbc_btnChangeSource.insets = new Insets(0, 0, 5, 5); + gbc_btnChangeSource.gridx = 4; + gbc_btnChangeSource.gridy = 1; + frame.getContentPane().add(btnChangeSource, gbc_btnChangeSource); + + JButton btnExtract = new JButton("Extract!"); + GridBagConstraints gbc_btnExtract = new GridBagConstraints(); + gbc_btnExtract.insets = new Insets(0, 0, 5, 5); + gbc_btnExtract.fill = GridBagConstraints.VERTICAL; + gbc_btnExtract.gridheight = 2; + gbc_btnExtract.gridx = 5; + gbc_btnExtract.gridy = 1; + frame.getContentPane().add(btnExtract, gbc_btnExtract); + + JLabel lblDestinationDirectory = new JLabel("Destination Directory"); + GridBagConstraints gbc_lblDestinationDirectory = new GridBagConstraints(); + gbc_lblDestinationDirectory.gridwidth = 2; + gbc_lblDestinationDirectory.insets = new Insets(0, 0, 5, 5); + gbc_lblDestinationDirectory.anchor = GridBagConstraints.EAST; + gbc_lblDestinationDirectory.gridx = 1; + gbc_lblDestinationDirectory.gridy = 2; + frame.getContentPane().add(lblDestinationDirectory, gbc_lblDestinationDirectory); + + textFieldDest = new JTextField(); + GridBagConstraints gbc_textFieldDest = new GridBagConstraints(); + gbc_textFieldDest.insets = new Insets(0, 0, 5, 5); + gbc_textFieldDest.fill = GridBagConstraints.BOTH; + gbc_textFieldDest.gridx = 3; + gbc_textFieldDest.gridy = 2; + frame.getContentPane().add(textFieldDest, gbc_textFieldDest); + textFieldDest.setColumns(10); + + JButton btnChangeDest = new JButton("Change"); + GridBagConstraints gbc_btnChangeDest = new GridBagConstraints(); + gbc_btnChangeDest.insets = new Insets(0, 0, 5, 5); + gbc_btnChangeDest.gridx = 4; + gbc_btnChangeDest.gridy = 2; + frame.getContentPane().add(btnChangeDest, gbc_btnChangeDest); + + JSeparator separator = new JSeparator(); + separator.setPreferredSize(new Dimension(1,1)); + GridBagConstraints gbc_separator = new GridBagConstraints(); + gbc_separator.anchor = GridBagConstraints.SOUTH; + gbc_separator.fill = GridBagConstraints.HORIZONTAL; + gbc_separator.gridwidth = 5; + gbc_separator.insets = new Insets(0, 0, 5, 5); + gbc_separator.gridx = 1; + gbc_separator.gridy = 3; + frame.getContentPane().add(separator, gbc_separator); + + JLabel lblThreads = new JLabel("Threads: "); + GridBagConstraints gbc_lblThreads = new GridBagConstraints(); + gbc_lblThreads.anchor = GridBagConstraints.WEST; + gbc_lblThreads.insets = new Insets(0, 0, 5, 5); + gbc_lblThreads.gridx = 1; + gbc_lblThreads.gridy = 4; + frame.getContentPane().add(lblThreads, gbc_lblThreads); + + JSlider slider = new JSlider(); + slider.setSnapToTicks(true); + slider.setPreferredSize(new Dimension(77, 16)); + slider.setBorder(null); + GridBagConstraints gbc_slider = new GridBagConstraints(); + gbc_slider.fill = GridBagConstraints.HORIZONTAL; + gbc_slider.insets = new Insets(0, 0, 5, 5); + gbc_slider.gridx = 1; + gbc_slider.gridy = 5; + frame.getContentPane().add(slider, gbc_slider); + + JProgressBar progressBar = new CustomProgressBar(); + progressBar.setStringPainted(true); + GridBagConstraints gbc_progressBar = new GridBagConstraints(); + gbc_progressBar.fill = GridBagConstraints.HORIZONTAL; + gbc_progressBar.gridwidth = 5; + gbc_progressBar.insets = new Insets(0, 0, 5, 5); + gbc_progressBar.gridx = 1; + gbc_progressBar.gridy = 6; + frame.getContentPane().add(progressBar, gbc_progressBar); + + EJTabbedPane tabbedPane = new EJTabbedPane(JTabbedPane.TOP); + setupTabbedPane(tabbedPane); + GridBagConstraints gbc_tabbedPane = new GridBagConstraints(); + gbc_tabbedPane.gridwidth = 5; + gbc_tabbedPane.insets = new Insets(0, 0, 0, 5); + gbc_tabbedPane.fill = GridBagConstraints.BOTH; + gbc_tabbedPane.gridx = 1; + gbc_tabbedPane.gridy = 7; + frame.getContentPane().add(tabbedPane, gbc_tabbedPane); + btnChangeSource.addActionListener((e) -> { File f; - Path path = Path.of(textFieldSourceDir.getText().trim()).toAbsolutePath(); + Path path = Path.of(textFieldSource.getText().trim()).toAbsolutePath(); if(Files.exists(path)) { f = path.toAbsolutePath().toFile(); } @@ -149,95 +230,107 @@ private void setupFrame() { int status = chooser.showOpenDialog(frame); if(status == JFileChooser.APPROVE_OPTION) { try { - selectSourceDirectory(chooser.getSelectedFile()); - } catch (InvocationTargetException | InterruptedException e1) { + selectDirectories(tabbedPane, chooser.getSelectedFile(), new File(textFieldDest.getText())); + } catch (InterruptedException e1) { e1.printStackTrace(); } } }); - frame.getContentPane().add(btnChangeSource); - JButton btnChangeDest = new JButton("Change"); - btnChangeDest.setToolTipText("Change where ExciteModder will copy the game files to"); - btnChangeDest.setBounds(761, 36, 117, 19); - frame.getContentPane().add(btnChangeDest); - - threadSlider = new JSlider(); - threadSlider.getSnapToTicks(); - threadSlider.setMinimum(1); - threadSlider.setMaximum(Runtime.getRuntime().availableProcessors()); - threadSlider.setValue(Math.max(1, Runtime.getRuntime().availableProcessors() / 2)); - threadSlider.setBounds(5, 90, 92, 16); - threadSlider.addChangeListener((s) -> { - if(lblThreads != null) { - lblThreads.setText("Threads: " + threadSlider.getValue()); + btnChangeDest.addActionListener((e) -> { + File f; + Path path = Path.of(textFieldDest.getText().trim()).toAbsolutePath(); + if(Files.exists(path)) { + f = path.toAbsolutePath().toFile(); + } + else { + f = null; + } + + JFileChooser chooser = new JFileChooser(f); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + int status = chooser.showOpenDialog(frame); + if(status == JFileChooser.APPROVE_OPTION) { + try { + selectDirectories(tabbedPane, new File(textFieldSource.getText()), chooser.getSelectedFile()); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } } }); - frame.getContentPane().add(threadSlider); - - lblThreads = new JLabel("Threads: " + threadSlider.getValue()); - lblThreads.setBounds(12, 74, 132, 15); - frame.getContentPane().add(lblThreads); - - JSeparator separator = new JSeparator(); - separator.setBounds(12, 64, 971, 2); - frame.getContentPane().add(separator); - - progressBar.setVisible(false); - JLabel lblStatus = new JLabel("Progress: 0%"); - lblStatus.setHorizontalAlignment(SwingConstants.CENTER); - lblStatus.setBounds(440, 110, 120, 15); - lblStatus.setVisible(false); - - frame.getContentPane().add(lblStatus); - progressBar.setBounds(12, 110, 971, 15); - frame.getContentPane().add(progressBar); - - JButton btnExtract = new JButton("Extract!"); - btnExtract.setBounds(890, 9, 93, 45); - btnExtract.setEnabled(false); - - frame.getContentPane().add(btnExtract); - frame.validate(); - frame.repaint(); - //tabbedPane = setupTabbedPane(true); - //frame.add(setupTabbedPane(true)); //this line is necessary here so that the wbp parser can see that the tabbed pane is a subcomponent of the frame. It doesn't seem to recognize it as being so if it isn't manually added here, even though it's added in setupTabbedPane + btnExtract.addActionListener((e) -> { + try { + File folder = new File(textFieldDest.getText()); + if(folder.exists()) { + LinkedHashSet paths = FileUtils.getFilesRecursively(folder.toPath()); + if(!folder.isDirectory()) { + throw new NotDirectoryException(folder.getAbsolutePath().toString()); + } + if(paths.size() != 0) { + int result = JOptionPane.showOptionDialog(frame, "Are you sure? You will overwrite " + paths.size() + " files.", "Overwrite?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, null, null); + if(result != 0) { + return; + } + } + } + + + + } + catch(Throwable t) { + throw new RuntimeException(t); + } + }); } - private void selectSourceDirectory(File selectedDir) throws InvocationTargetException, InterruptedException { - if(selectedDir != null) { - textFieldSourceDir.setText(selectedDir.getAbsolutePath()); + private void selectDirectories(EJTabbedPane pane, File sourceDir, File destDir) throws InterruptedException { + Tab tab = pane.getSelectedTab(); + if(sourceDir != null && !sourceDir.getPath().isBlank()) { + textFieldSource.setText(sourceDir.getAbsolutePath()); + } + else { + textFieldSource.setText(""); + } + if(destDir != null && !destDir.getPath().isBlank()) { + textFieldDest.setText(destDir.getAbsolutePath()); } else { - textFieldSourceDir.setText(""); + textFieldDest.setText(""); } copyOperations.shutdownNow(); - copyOperations = genCopyBatches(selectedDir); - setupTabbedPane(false); + copyOperations = genCopyBatches(sourceDir, destDir); + setupTabbedPane(pane); + pane.setSelectedTab(tab); + System.out.println("Set tab!"); update(); } - - private void setupTabbedPane(boolean initialSetup) { - tabbedPane.removeAll(); - if(initialSetup) { - tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); - tabbedPane.setBounds(0, 129, 1000, 511); - frame.getContentPane().add(tabbedPane); - } + + public EJTabbedPane setupTabbedPane(EJTabbedPane tabbedPane) { + Tab consoleTab = setupConsoleOutputTab(tabbedPane); + Tab statusTab = setupStatusTab(tabbedPane); + Tab progressTab = setupProgressTab(tabbedPane); - setupConsoleOutputTab(); - setupStatusTab(); - setupProgressTab(); + tabbedPane.removeAll(); + tabbedPane.setTabLayoutPolicy(EJTabbedPane.SCROLL_TAB_LAYOUT); + tabbedPane.addTab(consoleTab); + tabbedPane.addTab(statusTab); + tabbedPane.addTab(progressTab); - for(Batcher b : copyOperations.getBatches()) { - tabbedPane.addTab(b.getName(), null); + for(Batcher> b : copyOperations.getBatches()) { + tabbedPane.addTab(b.getName(), new JPanel()); } - return; + + return tabbedPane; } - private void setupConsoleOutputTab() { + private Tab setupConsoleOutputTab(EJTabbedPane tabbedPane) { + Tab consoleTab = tabbedPane.getTab(CONSOLE); + if(consoleTab != null) { + return consoleTab; + } + JPanel consolePanel = new JPanel(); consolePanel.setLayout(new GridLayout(0, 2, 0, 0)); JTextArea textArea = new JTextArea(); @@ -252,61 +345,93 @@ private void setupConsoleOutputTab() { new Throwable().printStackTrace(pw); textArea.setText(sw.toString()); - JScrollPane scrollPane = new JScrollPane(textArea); - scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); - tabbedPane.addTab("Console OutputT", null, scrollPane, null); - - - + JScrollPane scrollPaneConsole = new JScrollPane(textArea); + scrollPaneConsole.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); + Tab tab = new Tab(CONSOLE, null, scrollPaneConsole, null); + tabbedPane.addTab(tab.title(), tab.icon(), tab.component(), tab.tip()); //need to add this separately so the window builder can see it + return tab; } - public void setupStatusTab() { - tabbedPane.addTab("Status", null, gridPanel, null); - Iterator> batches = copyOperations.getBatches().iterator(); + private Tab setupStatusTab(EJTabbedPane tabbedPane) { + Tab statusTab = tabbedPane.getTab(STATUS); + + if(statusTab != null) { + //remove all + } + + JPanel statusGrid = new JPanel(new WrapLayout()); + JScrollPane statusGridScroller = new JScrollPane(statusGrid); + + Iterator>> batches = copyOperations.getBatches().iterator(); int i = 0; while(batches.hasNext()) { - gridPanel.putComponent(i, new BatchOperationComponent(batches.next())); + BatchOperationComponent b = new BatchOperationComponent(batches.next()); + b.setPreferredSize(new Dimension(150, 175)); + statusGrid.add(b); i++; } + + Tab tab = new Tab(STATUS, null, statusGridScroller, null); + tabbedPane.addTab(tab.title(), tab.icon(), tab.component(), tab.tip()); //need to add this separately so the window builder can see it + + + return tab; } - public void setupProgressTab() { + public Tab setupProgressTab(EJTabbedPane tabbedPane) { + Tab progressTab = tabbedPane.getTab(PROGRESS); + if(progressTab != null) { + return progressTab; + } + JPanel progressPanel = new JPanel(); - tabbedPane.addTab("Progress", null, progressPanel, null); + Tab tab = new Tab(PROGRESS, null, progressPanel, null); + tabbedPane.addTab(tab.title(), tab.icon(), tab.component(), tab.tip()); //need to add this separately so the window builder can see it progressPanel.setLayout(new GridLayout(0, 2, 0, 0)); setupLeftProgressPane(progressPanel); setupRightProgressPane(progressPanel); - + return tab; } private void setupLeftProgressPane(JPanel progressPanel) { JPanel leftPanel = new JPanel(); progressPanel.add(leftPanel); GridBagLayout gbl_leftPanel = new GridBagLayout(); - gbl_leftPanel.columnWidths = new int[] {100, 0, 70, 90, 0, 0, 0}; - gbl_leftPanel.rowHeights = new int[] {0, 15, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0}; + gbl_leftPanel.columnWidths = new int[] {100, 0, 70, 90, 0, 0, 11}; + gbl_leftPanel.rowHeights = new int[] {0, 15, 0, 0, 30, 0, 0, 30, 0, 0, 30, 0, 0, 29, 0}; gbl_leftPanel.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; - gbl_leftPanel.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + gbl_leftPanel.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, Double.MIN_VALUE}; leftPanel.setLayout(gbl_leftPanel); - JLabel lblCopyOperation = new JLabel("Copy Operation"); + JLabel lblCopyOperation = new JLabel("Unarchive Operation"); GridBagConstraints gbc_lblCopyOperation = new GridBagConstraints(); gbc_lblCopyOperation.gridwidth = 6; gbc_lblCopyOperation.insets = new Insets(0, 0, 5, 5); gbc_lblCopyOperation.gridx = 0; gbc_lblCopyOperation.gridy = 0; leftPanel.add(lblCopyOperation, gbc_lblCopyOperation); - BatchOperationComponent allBatchesCopy = new BatchOperationComponent(copyOperations); - allBatchesCopy.setToolTipText("All Batches"); - GridBagConstraints gbc_allBatches = new GridBagConstraints(); - gbc_allBatches.fill = GridBagConstraints.BOTH; - gbc_allBatches.gridheight = 11; - gbc_allBatches.insets = new Insets(0, 0, 0, 0); - gbc_allBatches.gridx = 0; - gbc_allBatches.gridy = 1; - leftPanel.add(allBatchesCopy, gbc_allBatches); + + JSeparator separator = new JSeparator(); + separator.setOrientation(SwingConstants.VERTICAL); + separator.setPreferredSize(new Dimension(1, 1)); + GridBagConstraints gbc_separator = new GridBagConstraints(); + gbc_separator.gridheight = 14; + gbc_separator.fill = GridBagConstraints.VERTICAL; + gbc_separator.gridx = 6; + gbc_separator.gridy = 0; + leftPanel.add(separator, gbc_separator); + BatchOperationComponent copyBatchComponent = new BatchOperationComponent(copyOperations); + copyBatchComponent.setToolTipText("All Batches"); + + GridBagConstraints gbc_copyBatchComponent = new GridBagConstraints(); + gbc_copyBatchComponent.fill = GridBagConstraints.BOTH; + gbc_copyBatchComponent.gridheight = 13; + gbc_copyBatchComponent.insets = new Insets(0, 0, 0, 5); + gbc_copyBatchComponent.gridx = 0; + gbc_copyBatchComponent.gridy = 1; + leftPanel.add(copyBatchComponent, gbc_copyBatchComponent); JSeparator separator_1 = new JSeparator(); GridBagConstraints gbc_separator_1 = new GridBagConstraints(); @@ -323,7 +448,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblTotalArchives.insets = new Insets(0, 0, 5, 5); gbc_lblTotalArchives.anchor = GridBagConstraints.NORTHEAST; gbc_lblTotalArchives.gridx = 2; - gbc_lblTotalArchives.gridy = 1; + gbc_lblTotalArchives.gridy = 2; leftPanel.add(lblTotalArchives, gbc_lblTotalArchives); JLabel lblTotalArchivesCount = new JLabel("0"); @@ -331,7 +456,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblTotalArchivesCount.anchor = GridBagConstraints.WEST; gbc_lblTotalArchivesCount.insets = new Insets(0, 0, 5, 5); gbc_lblTotalArchivesCount.gridx = 3; - gbc_lblTotalArchivesCount.gridy = 1; + gbc_lblTotalArchivesCount.gridy = 2; leftPanel.add(lblTotalArchivesCount, gbc_lblTotalArchivesCount); JLabel lblFoundResources = new JLabel("Total Resources:"); @@ -340,7 +465,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblFoundResources.anchor = GridBagConstraints.EAST; gbc_lblFoundResources.insets = new Insets(0, 0, 5, 5); gbc_lblFoundResources.gridx = 2; - gbc_lblFoundResources.gridy = 2; + gbc_lblFoundResources.gridy = 3; leftPanel.add(lblFoundResources, gbc_lblFoundResources); JLabel lblTotalResourcesCount = new JLabel("0"); @@ -348,7 +473,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblTotalResourcesCount.anchor = GridBagConstraints.WEST; gbc_lblTotalResourcesCount.insets = new Insets(0, 0, 5, 5); gbc_lblTotalResourcesCount.gridx = 3; - gbc_lblTotalResourcesCount.gridy = 2; + gbc_lblTotalResourcesCount.gridy = 3; leftPanel.add(lblTotalResourcesCount, gbc_lblTotalResourcesCount); JLabel lblArchivesCopied = new JLabel("Archives Copied:"); @@ -356,7 +481,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblArchivesCopied.anchor = GridBagConstraints.EAST; gbc_lblArchivesCopied.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesCopied.gridx = 2; - gbc_lblArchivesCopied.gridy = 4; + gbc_lblArchivesCopied.gridy = 5; leftPanel.add(lblArchivesCopied, gbc_lblArchivesCopied); JLabel lblArchivesCopiedCount = new JLabel("0"); @@ -364,22 +489,15 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblArchivesCopiedCount.anchor = GridBagConstraints.WEST; gbc_lblArchivesCopiedCount.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesCopiedCount.gridx = 3; - gbc_lblArchivesCopiedCount.gridy = 4; + gbc_lblArchivesCopiedCount.gridy = 5; leftPanel.add(lblArchivesCopiedCount, gbc_lblArchivesCopiedCount); - JLabel lblArchivesCopiedPercent = new JLabel("0%"); - GridBagConstraints gbc_lblArchivesCopiedPercent = new GridBagConstraints(); - gbc_lblArchivesCopiedPercent.insets = new Insets(0, 0, 5, 5); - gbc_lblArchivesCopiedPercent.gridx = 4; - gbc_lblArchivesCopiedPercent.gridy = 4; - leftPanel.add(lblArchivesCopiedPercent, gbc_lblArchivesCopiedPercent); - JLabel lblResourcesCopied = new JLabel("Resources Copied:"); GridBagConstraints gbc_lblResourcesCopied = new GridBagConstraints(); gbc_lblResourcesCopied.anchor = GridBagConstraints.EAST; gbc_lblResourcesCopied.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesCopied.gridx = 2; - gbc_lblResourcesCopied.gridy = 5; + gbc_lblResourcesCopied.gridy = 6; leftPanel.add(lblResourcesCopied, gbc_lblResourcesCopied); JLabel lblResourcesCopiedCount = new JLabel("0"); @@ -387,14 +505,14 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblResourcesCopiedCount.anchor = GridBagConstraints.WEST; gbc_lblResourcesCopiedCount.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesCopiedCount.gridx = 3; - gbc_lblResourcesCopiedCount.gridy = 5; + gbc_lblResourcesCopiedCount.gridy = 6; leftPanel.add(lblResourcesCopiedCount, gbc_lblResourcesCopiedCount); JLabel lblResourcesCopiedPercent = new JLabel("0%"); GridBagConstraints gbc_lblResourcesCopiedPercent = new GridBagConstraints(); gbc_lblResourcesCopiedPercent.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesCopiedPercent.gridx = 4; - gbc_lblResourcesCopiedPercent.gridy = 5; + gbc_lblResourcesCopiedPercent.gridy = 6; leftPanel.add(lblResourcesCopiedPercent, gbc_lblResourcesCopiedPercent); JLabel lblArchivesSkipped = new JLabel("Archives Skipped:"); @@ -403,7 +521,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblArchivesSkipped.anchor = GridBagConstraints.EAST; gbc_lblArchivesSkipped.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesSkipped.gridx = 2; - gbc_lblArchivesSkipped.gridy = 7; + gbc_lblArchivesSkipped.gridy = 8; leftPanel.add(lblArchivesSkipped, gbc_lblArchivesSkipped); JLabel lblArchivesSkippedCount = new JLabel("0"); @@ -411,14 +529,14 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblArchivesSkippedCount.anchor = GridBagConstraints.WEST; gbc_lblArchivesSkippedCount.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesSkippedCount.gridx = 3; - gbc_lblArchivesSkippedCount.gridy = 7; + gbc_lblArchivesSkippedCount.gridy = 8; leftPanel.add(lblArchivesSkippedCount, gbc_lblArchivesSkippedCount); JLabel lblArchivesSkippedPercent = new JLabel("0%"); GridBagConstraints gbc_lblArchivesSkippedPercent = new GridBagConstraints(); gbc_lblArchivesSkippedPercent.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesSkippedPercent.gridx = 4; - gbc_lblArchivesSkippedPercent.gridy = 7; + gbc_lblArchivesSkippedPercent.gridy = 8; leftPanel.add(lblArchivesSkippedPercent, gbc_lblArchivesSkippedPercent); JLabel lblResourcesSkipped = new JLabel("Resources Skipped:"); @@ -426,7 +544,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblResourcesSkipped.anchor = GridBagConstraints.EAST; gbc_lblResourcesSkipped.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesSkipped.gridx = 2; - gbc_lblResourcesSkipped.gridy = 8; + gbc_lblResourcesSkipped.gridy = 9; leftPanel.add(lblResourcesSkipped, gbc_lblResourcesSkipped); JLabel lblResourcesSkippedCount = new JLabel("0"); @@ -434,14 +552,14 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblResourcesSkippedCount.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesSkippedCount.anchor = GridBagConstraints.WEST; gbc_lblResourcesSkippedCount.gridx = 3; - gbc_lblResourcesSkippedCount.gridy = 8; + gbc_lblResourcesSkippedCount.gridy = 9; leftPanel.add(lblResourcesSkippedCount, gbc_lblResourcesSkippedCount); JLabel labelResourcesSkippedPercent = new JLabel("0%"); GridBagConstraints gbc_labelResourcesSkippedPercent = new GridBagConstraints(); gbc_labelResourcesSkippedPercent.insets = new Insets(0, 0, 5, 5); gbc_labelResourcesSkippedPercent.gridx = 4; - gbc_labelResourcesSkippedPercent.gridy = 8; + gbc_labelResourcesSkippedPercent.gridy = 9; leftPanel.add(labelResourcesSkippedPercent, gbc_labelResourcesSkippedPercent); JLabel lblArchivesFailed = new JLabel("Archives Failed:"); @@ -450,7 +568,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblArchivesFailed.anchor = GridBagConstraints.EAST; gbc_lblArchivesFailed.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesFailed.gridx = 2; - gbc_lblArchivesFailed.gridy = 10; + gbc_lblArchivesFailed.gridy = 11; leftPanel.add(lblArchivesFailed, gbc_lblArchivesFailed); JLabel lblArchivesFailedCount = new JLabel("0"); @@ -458,44 +576,42 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_lblArchivesFailedCount.anchor = GridBagConstraints.WEST; gbc_lblArchivesFailedCount.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesFailedCount.gridx = 3; - gbc_lblArchivesFailedCount.gridy = 10; + gbc_lblArchivesFailedCount.gridy = 11; leftPanel.add(lblArchivesFailedCount, gbc_lblArchivesFailedCount); JLabel lblArchivesFailedPercent = new JLabel("0%"); GridBagConstraints gbc_lblArchivesFailedPercent = new GridBagConstraints(); gbc_lblArchivesFailedPercent.insets = new Insets(0, 0, 5, 5); gbc_lblArchivesFailedPercent.gridx = 4; - gbc_lblArchivesFailedPercent.gridy = 10; + gbc_lblArchivesFailedPercent.gridy = 11; leftPanel.add(lblArchivesFailedPercent, gbc_lblArchivesFailedPercent); JLabel lblResourcesFailed = new JLabel("Resources Failed:"); GridBagConstraints gbc_lblResourcesFailed = new GridBagConstraints(); gbc_lblResourcesFailed.anchor = GridBagConstraints.EAST; - gbc_lblResourcesFailed.insets = new Insets(0, 0, 0, 5); + gbc_lblResourcesFailed.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesFailed.gridx = 2; - gbc_lblResourcesFailed.gridy = 11; + gbc_lblResourcesFailed.gridy = 12; leftPanel.add(lblResourcesFailed, gbc_lblResourcesFailed); JLabel lblResourcesFailedCount = new JLabel("0"); GridBagConstraints gbc_lblResourcesFailedCount = new GridBagConstraints(); gbc_lblResourcesFailedCount.anchor = GridBagConstraints.WEST; - gbc_lblResourcesFailedCount.insets = new Insets(0, 0, 0, 5); + gbc_lblResourcesFailedCount.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesFailedCount.gridx = 3; - gbc_lblResourcesFailedCount.gridy = 11; + gbc_lblResourcesFailedCount.gridy = 12; leftPanel.add(lblResourcesFailedCount, gbc_lblResourcesFailedCount); JLabel lblResourcesFailedPercent = new JLabel("0%"); GridBagConstraints gbc_lblResourcesFailedPercent = new GridBagConstraints(); - gbc_lblResourcesFailedPercent.insets = new Insets(0, 0, 0, 5); + gbc_lblResourcesFailedPercent.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesFailedPercent.gridx = 4; - gbc_lblResourcesFailedPercent.gridy = 11; + gbc_lblResourcesFailedPercent.gridy = 12; leftPanel.add(lblResourcesFailedPercent, gbc_lblResourcesFailedPercent); copyOperations.addBatchListener(() -> { SwingUtilities.invokeLater(() -> { - - //Set all of the label text - + update(); }); }); } @@ -504,12 +620,23 @@ private void setupRightProgressPane(JPanel progressPanel) { JPanel rightPanel = new JPanel(); progressPanel.add(rightPanel); GridBagLayout gbl_rightPanel = new GridBagLayout(); - gbl_rightPanel.columnWidths = new int[] {30, 0, 90, 0, 30, 30, 0, 0}; - gbl_rightPanel.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + gbl_rightPanel.columnWidths = new int[] {0, 0, 90, 0, 30, 30, 0, 0}; + gbl_rightPanel.rowHeights = new int[]{0, 30, 0, 30, 0, 0, 0, 30, 30, 30, 30, 0, 0, 0, 0}; gbl_rightPanel.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; - gbl_rightPanel.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + gbl_rightPanel.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, Double.MIN_VALUE}; rightPanel.setLayout(gbl_rightPanel); + BatchOperationComponent copyBatchComponent = new BatchOperationComponent(processOperations); + copyBatchComponent.setToolTipText("All Batches"); + + GridBagConstraints gbc_copyBatchComponent = new GridBagConstraints(); + gbc_copyBatchComponent.fill = GridBagConstraints.BOTH; + gbc_copyBatchComponent.gridheight = 13; + gbc_copyBatchComponent.insets = new Insets(0, 0, 5, 5); + gbc_copyBatchComponent.gridx = 0; + gbc_copyBatchComponent.gridy = 1; + rightPanel.add(copyBatchComponent, gbc_copyBatchComponent); + JLabel lblNewLabel = new JLabel("Process Operation"); GridBagConstraints gbc_lblNewLabel = new GridBagConstraints(); gbc_lblNewLabel.gridwidth = 7; @@ -518,22 +645,6 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblNewLabel.gridy = 0; rightPanel.add(lblNewLabel, gbc_lblNewLabel); - JLabel lblTotalArchives = new JLabel("Total Archives:"); - GridBagConstraints gbc_lblTotalArchives = new GridBagConstraints(); - gbc_lblTotalArchives.anchor = GridBagConstraints.EAST; - gbc_lblTotalArchives.insets = new Insets(0, 0, 5, 5); - gbc_lblTotalArchives.gridx = 1; - gbc_lblTotalArchives.gridy = 1; - rightPanel.add(lblTotalArchives, gbc_lblTotalArchives); - - JLabel lblTotalArchvesCount = new JLabel("0"); - GridBagConstraints gbc_lblTotalArchvesCount = new GridBagConstraints(); - gbc_lblTotalArchvesCount.anchor = GridBagConstraints.WEST; - gbc_lblTotalArchvesCount.insets = new Insets(0, 0, 5, 5); - gbc_lblTotalArchvesCount.gridx = 2; - gbc_lblTotalArchvesCount.gridy = 1; - rightPanel.add(lblTotalArchvesCount, gbc_lblTotalArchvesCount); - JLabel lblTotalResources = new JLabel("Total Resources:"); GridBagConstraints gbc_lblTotalResources = new GridBagConstraints(); gbc_lblTotalResources.anchor = GridBagConstraints.EAST; @@ -550,36 +661,12 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblTotalResourcesCount.gridy = 2; rightPanel.add(lblTotalResourcesCount, gbc_lblTotalResourcesCount); - JLabel lblArchivesProcessed = new JLabel("Archives Processed:"); - GridBagConstraints gbc_lblArchivesProcessed = new GridBagConstraints(); - gbc_lblArchivesProcessed.anchor = GridBagConstraints.EAST; - gbc_lblArchivesProcessed.insets = new Insets(0, 0, 5, 5); - gbc_lblArchivesProcessed.gridx = 1; - gbc_lblArchivesProcessed.gridy = 4; - rightPanel.add(lblArchivesProcessed, gbc_lblArchivesProcessed); - lblArchivesProcessed.setHorizontalAlignment(SwingConstants.RIGHT); - - JLabel lblArchivesProcessedCount = new JLabel("0"); - GridBagConstraints gbc_lblArchivesProcessedCount = new GridBagConstraints(); - gbc_lblArchivesProcessedCount.anchor = GridBagConstraints.WEST; - gbc_lblArchivesProcessedCount.insets = new Insets(0, 0, 5, 5); - gbc_lblArchivesProcessedCount.gridx = 2; - gbc_lblArchivesProcessedCount.gridy = 4; - rightPanel.add(lblArchivesProcessedCount, gbc_lblArchivesProcessedCount); - - JLabel lblArchivesProcessedPercent = new JLabel("0%"); - GridBagConstraints gbc_lblArchivesProcessedPercent = new GridBagConstraints(); - gbc_lblArchivesProcessedPercent.insets = new Insets(0, 0, 5, 5); - gbc_lblArchivesProcessedPercent.gridx = 3; - gbc_lblArchivesProcessedPercent.gridy = 4; - rightPanel.add(lblArchivesProcessedPercent, gbc_lblArchivesProcessedPercent); - JLabel lblResourcesProcessed = new JLabel("Resources Processed:"); GridBagConstraints gbc_lblResourcesProcessed = new GridBagConstraints(); gbc_lblResourcesProcessed.anchor = GridBagConstraints.EAST; gbc_lblResourcesProcessed.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesProcessed.gridx = 1; - gbc_lblResourcesProcessed.gridy = 5; + gbc_lblResourcesProcessed.gridy = 4; rightPanel.add(lblResourcesProcessed, gbc_lblResourcesProcessed); JLabel lblResourcesProcessedCount = new JLabel("0"); @@ -587,45 +674,22 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblResourcesProcessedCount.anchor = GridBagConstraints.WEST; gbc_lblResourcesProcessedCount.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesProcessedCount.gridx = 2; - gbc_lblResourcesProcessedCount.gridy = 5; + gbc_lblResourcesProcessedCount.gridy = 4; rightPanel.add(lblResourcesProcessedCount, gbc_lblResourcesProcessedCount); JLabel lblResourcesProcessedPercent = new JLabel("0%"); GridBagConstraints gbc_lblResourcesProcessedPercent = new GridBagConstraints(); gbc_lblResourcesProcessedPercent.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesProcessedPercent.gridx = 3; - gbc_lblResourcesProcessedPercent.gridy = 5; + gbc_lblResourcesProcessedPercent.gridy = 4; rightPanel.add(lblResourcesProcessedPercent, gbc_lblResourcesProcessedPercent); - JLabel lblArchivesSkipped = new JLabel("Archives Skipped:"); - GridBagConstraints gbc_lblArchivesSkipped = new GridBagConstraints(); - gbc_lblArchivesSkipped.anchor = GridBagConstraints.EAST; - gbc_lblArchivesSkipped.insets = new Insets(0, 0, 5, 5); - gbc_lblArchivesSkipped.gridx = 1; - gbc_lblArchivesSkipped.gridy = 7; - rightPanel.add(lblArchivesSkipped, gbc_lblArchivesSkipped); - - JLabel lblArchivesSkippedCount = new JLabel("0"); - GridBagConstraints gbc_lblArchivesSkippedCount = new GridBagConstraints(); - gbc_lblArchivesSkippedCount.anchor = GridBagConstraints.WEST; - gbc_lblArchivesSkippedCount.insets = new Insets(0, 0, 5, 5); - gbc_lblArchivesSkippedCount.gridx = 2; - gbc_lblArchivesSkippedCount.gridy = 7; - rightPanel.add(lblArchivesSkippedCount, gbc_lblArchivesSkippedCount); - - JLabel lblArchivesSkippedPercent = new JLabel("0%"); - GridBagConstraints gbc_lblArchivesSkippedPercent = new GridBagConstraints(); - gbc_lblArchivesSkippedPercent.insets = new Insets(0, 0, 5, 5); - gbc_lblArchivesSkippedPercent.gridx = 3; - gbc_lblArchivesSkippedPercent.gridy = 7; - rightPanel.add(lblArchivesSkippedPercent, gbc_lblArchivesSkippedPercent); - JLabel lblResourcesSkipped = new JLabel("Resources Skipped:"); GridBagConstraints gbc_lblResourcesSkipped = new GridBagConstraints(); gbc_lblResourcesSkipped.anchor = GridBagConstraints.EAST; gbc_lblResourcesSkipped.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesSkipped.gridx = 1; - gbc_lblResourcesSkipped.gridy = 8; + gbc_lblResourcesSkipped.gridy = 5; rightPanel.add(lblResourcesSkipped, gbc_lblResourcesSkipped); JLabel lblResourcesSkippedCount = new JLabel("0"); @@ -633,134 +697,79 @@ private void setupRightProgressPane(JPanel progressPanel) { gbc_lblResourcesSkippedCount.anchor = GridBagConstraints.WEST; gbc_lblResourcesSkippedCount.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesSkippedCount.gridx = 2; - gbc_lblResourcesSkippedCount.gridy = 8; + gbc_lblResourcesSkippedCount.gridy = 5; rightPanel.add(lblResourcesSkippedCount, gbc_lblResourcesSkippedCount); JLabel lblResourcesSkippedPercent = new JLabel("0%"); GridBagConstraints gbc_lblResourcesSkippedPercent = new GridBagConstraints(); gbc_lblResourcesSkippedPercent.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesSkippedPercent.gridx = 3; - gbc_lblResourcesSkippedPercent.gridy = 8; + gbc_lblResourcesSkippedPercent.gridy = 5; rightPanel.add(lblResourcesSkippedPercent, gbc_lblResourcesSkippedPercent); - JLabel lblArchivesFailed = new JLabel("Archives Failed:"); - GridBagConstraints gbc_lblArchivesFailed = new GridBagConstraints(); - gbc_lblArchivesFailed.anchor = GridBagConstraints.EAST; - gbc_lblArchivesFailed.insets = new Insets(0, 0, 5, 5); - gbc_lblArchivesFailed.gridx = 1; - gbc_lblArchivesFailed.gridy = 10; - rightPanel.add(lblArchivesFailed, gbc_lblArchivesFailed); - - JLabel lblArchivesFailedCount = new JLabel("0"); - GridBagConstraints gbc_lblArchivesFailedCount = new GridBagConstraints(); - gbc_lblArchivesFailedCount.anchor = GridBagConstraints.WEST; - gbc_lblArchivesFailedCount.insets = new Insets(0, 0, 5, 5); - gbc_lblArchivesFailedCount.gridx = 2; - gbc_lblArchivesFailedCount.gridy = 10; - rightPanel.add(lblArchivesFailedCount, gbc_lblArchivesFailedCount); - - JLabel lblArchivesFailedPercent = new JLabel("0%"); - GridBagConstraints gbc_lblArchivesFailedPercent = new GridBagConstraints(); - gbc_lblArchivesFailedPercent.insets = new Insets(0, 0, 5, 5); - gbc_lblArchivesFailedPercent.gridx = 3; - gbc_lblArchivesFailedPercent.gridy = 10; - rightPanel.add(lblArchivesFailedPercent, gbc_lblArchivesFailedPercent); - JLabel lblResourcesFailed = new JLabel("Resources Failed:"); GridBagConstraints gbc_lblResourcesFailed = new GridBagConstraints(); gbc_lblResourcesFailed.anchor = GridBagConstraints.EAST; - gbc_lblResourcesFailed.insets = new Insets(0, 0, 0, 5); + gbc_lblResourcesFailed.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesFailed.gridx = 1; - gbc_lblResourcesFailed.gridy = 11; + gbc_lblResourcesFailed.gridy = 6; rightPanel.add(lblResourcesFailed, gbc_lblResourcesFailed); JLabel lblResourcesFailedCount = new JLabel("0"); GridBagConstraints gbc_lblResourcesFailedCount = new GridBagConstraints(); gbc_lblResourcesFailedCount.anchor = GridBagConstraints.WEST; - gbc_lblResourcesFailedCount.insets = new Insets(0, 0, 0, 5); + gbc_lblResourcesFailedCount.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesFailedCount.gridx = 2; - gbc_lblResourcesFailedCount.gridy = 11; + gbc_lblResourcesFailedCount.gridy = 6; rightPanel.add(lblResourcesFailedCount, gbc_lblResourcesFailedCount); JLabel lblResourcesFailedPercent = new JLabel("0%"); GridBagConstraints gbc_lblResourcesFailedPercent = new GridBagConstraints(); - gbc_lblResourcesFailedPercent.insets = new Insets(0, 0, 0, 5); + gbc_lblResourcesFailedPercent.insets = new Insets(0, 0, 5, 5); gbc_lblResourcesFailedPercent.gridx = 3; - gbc_lblResourcesFailedPercent.gridy = 11; + gbc_lblResourcesFailedPercent.gridy = 6; rightPanel.add(lblResourcesFailedPercent, gbc_lblResourcesFailedPercent); } - private BatchRunner genCopyBatches(File dir) { - BatchRunner batchRunner = new BatchRunner("Copy Operations"); - if(dir != null) { - for(File f : dir.listFiles()) { - Batch b = new Batch(f.getName()); - batchRunner.addBatch(b); + @SuppressWarnings({ "rawtypes", "unchecked" }) + private BatchRunner> genCopyBatches(File source, File dest) { + BatchRunner> batchRunner = new BatchRunner("Unarchive"); + try { + Unarchiver unarchiver = new Unarchiver(source.toPath(), dest.toPath()); + if(FileUtils.isDirectory(source) && FileUtils.isDirectory(dest)) { + for(Batch> batch : unarchiver.getCopyBatches()) { + batchRunner.addBatch(batch); + } } } + catch(Throwable t) { + Batch> errBatch = new Batch<>("Error"); + errBatch.addRunnable(() -> { + throw t; + }); + batchRunner.addBatch(errBatch); + } return batchRunner; } - private void setGridBatches(BatchContainer batch, FixedCellGrid grid) { - Collection batches = batch.getRunnables(); - for(int i = 0; i < batches.size(); i++) { - tabbedPane.addTab("File " + i, new BatchOperationComponent(batch)); + private BatchRunner genProcessBatches(File dir) { + BatchRunner batchRunner = new BatchRunner("Process"); + if(dir != null) { + //stuff } + return batchRunner; } - private BatchRunner getProcessBatches() { - throw new UnsupportedOperationException("Not yet implemented"); + public static enum BatchResult { + SUCCESS, + FAILURE, + SKIP } - + @Override public void update() { + frame.invalidate(); frame.repaint(); } - @Override - public void mouseWheelMoved(MouseWheelEvent e) { - System.out.println("Scrolled: " + e.getComponent()); - System.out.println("Child: " + e.getComponent().getComponentAt(e.getPoint())); - if(e.getSource() instanceof JTabbedPane) { - JTabbedPane pane = (JTabbedPane) e.getSource(); - Component scrolledComponent = pane.getComponentAt(e.getPoint()); - if(!(scrolledComponent instanceof FixedCellSizeGrid) && scrolledComponent.getParent() instanceof JTabbedPane) { - int units = e.getWheelRotation(); - System.out.println(units); - int oldIndex = pane.getSelectedIndex(); - int newIndex = oldIndex + units; - if(newIndex < 0) { - pane.setSelectedIndex(0); - } - else if (newIndex >= pane.getTabCount()) { - pane.setSelectedIndex(pane.getTabCount() - 1); - } - else { - pane.setSelectedIndex(newIndex); - } - } - else if(scrolledComponent instanceof FixedCellSizeGrid) { - FixedCellSizeGrid grid = (FixedCellSizeGrid) scrolledComponent; - grid.scroll(e.getWheelRotation()); - } - } - else { - //System.out.println(e.getSource()); - } - } - - private FixedCellGrid genGridPanel() { - FixedCellGrid gridPanel = new FixedCellSizeGrid(new Dimension(385, 385), new Dimension(100, 100), 0); - gridPanel.setVisible(true); - - return gridPanel; - } - - private int getWantedThreads() { - int ret = threadSlider.getValue(); - if(ret < 1) { - return 1; - } - return ret; - } } diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/WrapLayout.java b/src/main/java/com/gamebuster19901/excite/modding/ui/WrapLayout.java new file mode 100644 index 0000000..2260ef3 --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/WrapLayout.java @@ -0,0 +1,192 @@ +package com.gamebuster19901.excite.modding.ui; + +import java.awt.*; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; + +/** + * FlowLayout subclass that fully supports wrapping of components. + */ +public class WrapLayout extends FlowLayout +{ + private Dimension preferredLayoutSize; + + /** + * Constructs a new WrapLayout with a left + * alignment and a default 5-unit horizontal and vertical gap. + */ + public WrapLayout() + { + super(); + } + + /** + * Constructs a new FlowLayout with the specified + * alignment and a default 5-unit horizontal and vertical gap. + * The value of the alignment argument must be one of + * WrapLayout, WrapLayout, + * or WrapLayout. + * @param align the alignment value + */ + public WrapLayout(int align) + { + super(align); + } + + /** + * Creates a new flow layout manager with the indicated alignment + * and the indicated horizontal and vertical gaps. + *

+ * The value of the alignment argument must be one of + * WrapLayout, WrapLayout, + * or WrapLayout. + * @param align the alignment value + * @param hgap the horizontal gap between components + * @param vgap the vertical gap between components + */ + public WrapLayout(int align, int hgap, int vgap) + { + super(align, hgap, vgap); + } + + /** + * Returns the preferred dimensions for this layout given the + * visible components in the specified target container. + * @param target the component which needs to be laid out + * @return the preferred dimensions to lay out the + * subcomponents of the specified container + */ + @Override + public Dimension preferredLayoutSize(Container target) + { + return layoutSize(target, true); + } + + /** + * Returns the minimum dimensions needed to layout the visible + * components contained in the specified target container. + * @param target the component which needs to be laid out + * @return the minimum dimensions to lay out the + * subcomponents of the specified container + */ + @Override + public Dimension minimumLayoutSize(Container target) + { + Dimension minimum = layoutSize(target, false); + minimum.width -= (getHgap() + 1); + return minimum; + } + + /** + * Returns the minimum or preferred dimension needed to layout the target + * container. + * + * @param target target to get layout size for + * @param preferred should preferred size be calculated + * @return the dimension to layout the target container + */ + private Dimension layoutSize(Container target, boolean preferred) + { + synchronized (target.getTreeLock()) + { + // Each row must fit with the width allocated to the containter. + // When the container width = 0, the preferred width of the container + // has not yet been calculated so lets ask for the maximum. + + int targetWidth = target.getSize().width; + Container container = target; + + while (container.getSize().width == 0 && container.getParent() != null) + { + container = container.getParent(); + } + + targetWidth = container.getSize().width; + + if (targetWidth == 0) + targetWidth = Integer.MAX_VALUE; + + int hgap = getHgap(); + int vgap = getVgap(); + Insets insets = target.getInsets(); + int horizontalInsetsAndGap = insets.left + insets.right + (hgap * 2); + int maxWidth = targetWidth - horizontalInsetsAndGap; + + // Fit components into the allowed width + + Dimension dim = new Dimension(0, 0); + int rowWidth = 0; + int rowHeight = 0; + + int nmembers = target.getComponentCount(); + + for (int i = 0; i < nmembers; i++) + { + Component m = target.getComponent(i); + + if (m.isVisible()) + { + Dimension d = preferred ? m.getPreferredSize() : m.getMinimumSize(); + + // Can't add the component to current row. Start a new row. + + if (rowWidth + d.width > maxWidth) + { + addRow(dim, rowWidth, rowHeight); + rowWidth = 0; + rowHeight = 0; + } + + // Add a horizontal gap for all components after the first + + if (rowWidth != 0) + { + rowWidth += hgap; + } + + rowWidth += d.width; + rowHeight = Math.max(rowHeight, d.height); + } + } + + addRow(dim, rowWidth, rowHeight); + + dim.width += horizontalInsetsAndGap; + dim.height += insets.top + insets.bottom + vgap * 2; + + // When using a scroll pane or the DecoratedLookAndFeel we need to + // make sure the preferred size is less than the size of the + // target containter so shrinking the container size works + // correctly. Removing the horizontal gap is an easy way to do this. + + Container scrollPane = SwingUtilities.getAncestorOfClass(JScrollPane.class, target); + + if (scrollPane != null && target.isValid()) + { + dim.width -= (hgap + 1); + } + + return dim; + } + } + + /* + * A new row has been completed. Use the dimensions of this row + * to update the preferred size for the container. + * + * @param dim update the width and height when appropriate + * @param rowWidth the width of the row to add + * @param rowHeight the height of the row to add + */ + private void addRow(Dimension dim, int rowWidth, int rowHeight) + { + dim.width = Math.max(dim.width, rowWidth); + + if (dim.height > 0) + { + dim.height += getVgap(); + } + + dim.height += rowHeight; + } +} \ No newline at end of file diff --git a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/QuickAccessArchive.java b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/QuickAccessArchive.java new file mode 100644 index 0000000..f2a87ec --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/QuickAccessArchive.java @@ -0,0 +1,37 @@ +package com.gamebuster19901.excite.modding.unarchiver; + +import java.io.IOException; +import java.nio.file.Path; + +public class QuickAccessArchive { + + private final Toc toc; + private final Path archivePath; + private volatile Archive archive; + private volatile boolean set; + + public QuickAccessArchive(Toc toc, Path archivePath) { + this.toc = toc; + this.archivePath = archivePath; + } + + public synchronized void setArchive() throws IOException { + if(set == false) { + try { + this.archive = new Archive(archivePath, toc); + } + catch(Throwable t) { + throw t; + } + finally { + set = true; //so we don't attempt to read the file multiple times if it fails + } + } + } + + public Archive getArchive() throws IOException { + setArchive(); + return archive; + } + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java index c4db3ac..7b7f96f 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java +++ b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java @@ -4,65 +4,80 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; +import java.util.Collection; import java.util.LinkedHashSet; -import java.util.Scanner; +import java.util.List; +import java.util.concurrent.Callable; import java.util.stream.Stream; -import com.gamebuster19901.excite.modding.game.file.kaitai.TocMonster; +import com.gamebuster19901.excite.modding.concurrent.Batch; import com.gamebuster19901.excite.modding.game.file.kaitai.TocMonster.Details; public class Unarchiver { - private static final Path runDir = Path.of(".").resolve("run"); - private static final Path ripDir = runDir.resolve("rip"); + private final Path sourceDir; + private final Path destDir; public LinkedHashSet tocs = new LinkedHashSet<>(); public LinkedHashSet archives = new LinkedHashSet<>(); - - public void unarchiveDir(Path dir) throws IOException { - try(Stream fileStream = Files.walk(dir)) { - fileStream.filter(Files::isRegularFile).forEach((f) -> { - if(f.getFileName().toString().endsWith(".toc")) { - tocs.add(f); - } - else { - archives.add(f); - } - }); - } + + public Unarchiver(Path sourceDir, Path destDir) throws IOException { + this.sourceDir = sourceDir; + this.destDir = destDir; + refresh(); } - public void unarchive(Path tocFile) throws IOException { - TocMonster toc = TocMonster.fromFile(tocFile.toAbsolutePath().toString()); - ArrayList

details = toc.details(); - for(Details fileDetails : details) { - System.out.println(tocFile.getFileName() + "/" + fileDetails.name()); + public Collection>> getCopyBatches() { + LinkedHashSet>> batches = new LinkedHashSet<>(); + for(Path toc : tocs) { + batches.add(getCopyBatch(toc)); } - Archive archive = null; - for(Path archivePath : archives) { - if(getFileName(tocFile).equals(getFileName(archivePath))) { - archive = new Archive(archivePath, tocFile); - break; + return batches; + } + + public Batch> getCopyBatch(Path tocFile) { + Batch> batch = new Batch<>(tocFile.getFileName().toString()); + try { + Toc toc = new Toc(tocFile.toAbsolutePath()); + List
details = toc.getFiles(); + + final QuickAccessArchive archive = getArchive(toc); + for(Details resource : details) { + batch.addRunnable(() -> { + try { + String resourceName = resource.name(); + System.out.println(tocFile.getFileName() + "/" + resourceName); + archive.getArchive().getFile(resourceName).writeTo(destDir.resolve(resourceName)); + if(resource.name().endsWith("tex")) { + return () -> { + System.out.println("This is an example of processing a texture!"); + return null; + }; + } + } + catch(Throwable t) { + throw t; + } + return null; + }); } + } - if(archive == null) { - throw new FileNotFoundException("Resource file for toc " + tocFile); + catch(Throwable t) { + batch.addRunnable(() -> { + throw t; //let the batchrunner know that an error occurred + }); } - - archive.writeTo(ripDir); + return batch; } - @SuppressWarnings("resource") - public static void main(String[] args) throws IOException { - Unarchiver unarchiver = new Unarchiver(); - unarchiver.unarchiveDir(Path.of("./gameData")); - - for(Path toc : unarchiver.tocs) { - System.out.println("Unarchiving " + toc); - unarchiver.unarchive(toc); + private QuickAccessArchive getArchive(Toc toc) throws IOException { + for(Path archivePath : archives) { + if(getFileName(toc.getFile()).equals(getFileName(archivePath))) { + return new QuickAccessArchive(toc, archivePath); + } } - new Scanner(System.in).nextLine(); //wait to exit + throw new FileNotFoundException("Resource file for toc " + toc.getFile().getFileName()); } private static String getFileName(Path f) { @@ -71,4 +86,19 @@ private static String getFileName(Path f) { return (i == -1) ? fileName : fileName.substring(0, i); } + private void refresh() throws IOException { + tocs.clear(); + archives.clear(); + try(Stream fileStream = Files.walk(sourceDir)) { + fileStream.filter(Files::isRegularFile).forEach((f) -> { + if(f.getFileName().toString().endsWith(".toc")) { + tocs.add(f); + } + else { + archives.add(f); + } + }); + } + } + } diff --git a/src/main/java/com/gamebuster19901/excite/modding/util/FileUtils.java b/src/main/java/com/gamebuster19901/excite/modding/util/FileUtils.java index 3923d4f..9216ad5 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/util/FileUtils.java +++ b/src/main/java/com/gamebuster19901/excite/modding/util/FileUtils.java @@ -8,11 +8,15 @@ import java.nio.ByteOrder; import java.nio.charset.Charset; import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; public class FileUtils { @@ -120,4 +124,43 @@ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOEx } } + public static LinkedHashSet getFilesRecursively(Path path) throws IOException { + LinkedHashSet paths = new LinkedHashSet<>(); + if (Files.exists(path)) { + Files.walkFileTree(path, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + paths.add(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + if (Files.isSymbolicLink(dir)) { + //skip symbolic links + return FileVisitResult.SKIP_SUBTREE; + } + return FileVisitResult.CONTINUE; + } + }); + } else { + System.out.println("The specified path does not exist: " + path); + } + return paths; + } + + public static String getFileName(Path f) { + String fileName = f.getFileName().toString(); + int i = fileName.lastIndexOf('.'); + return (i == -1) ? fileName : fileName.substring(0, i); + } + + public static boolean isDirectory(Path dir) { + return Files.isDirectory(dir) && !Files.isSymbolicLink(dir); + } + + public static boolean isDirectory(File dir) { + return isDirectory(dir.getAbsoluteFile().toPath()); + } + } From 89b0d6169850e2ff9191357e3b0cd5273b711bef Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Tue, 7 May 2024 16:32:11 -0400 Subject: [PATCH 08/19] improve concurrency --- .../excite/modding/concurrent/Batch.java | 5 + .../modding/concurrent/BatchContainer.java | 2 +- .../modding/concurrent/BatchRunner.java | 25 ++--- .../modding/ui/BatchOperationComponent.java | 11 +++ .../modding/ui/BatchedImageComponent.java | 7 ++ .../excite/modding/ui/TestWindow.java | 98 +++++++++++++++++++ .../excite/modding/ui/Window.java | 47 ++++++--- .../modding/unarchiver/ArchivedFile.java | 13 ++- .../unarchiver/QuickAccessArchive.java | 23 ++--- .../excite/modding/unarchiver/Unarchiver.java | 5 + 10 files changed, 191 insertions(+), 45 deletions(-) create mode 100644 src/main/java/com/gamebuster19901/excite/modding/ui/TestWindow.java diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java index 29f8eb8..e995735 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java @@ -233,4 +233,9 @@ protected void shutdown(Shutdown shutdown) { thrown = shutdown; } } + + @Override + public void update() { + //NO-OP + } } diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java index 59e2785..4f507ae 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java @@ -4,7 +4,7 @@ import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; -public interface BatchContainer { +public interface BatchContainer extends BatchListener { public abstract String getName(); diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java index ed0e104..4b7a264 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java @@ -84,24 +84,20 @@ public void shutdownNow() throws InterruptedException { @Override public Collection> getRunnables() { - synchronized(batches) { - LinkedHashSet> ret = new LinkedHashSet<>(); - for(Batcher batch : batches) { - ret.addAll(batch.getRunnables()); - } - return ret; + LinkedHashSet> ret = new LinkedHashSet<>(); + for(Batcher batch : batches) { + ret.addAll(batch.getRunnables()); } + return ret; } @Override public Collection getListeners() { - synchronized(batches) { - LinkedHashSet ret = new LinkedHashSet<>(); - for(Batcher batch : batches) { - ret.addAll(batch.getListeners()); - } - return ret; + LinkedHashSet ret = new LinkedHashSet<>(); + for(Batcher batch : batches) { + ret.addAll(batch.getListeners()); } + return ret; } @Override @@ -124,5 +120,10 @@ public int getCompleted() { for(BatchedCallable callable : callables) {ret++;} return ret; } + + @Override + public void update() { + //NO-OP + } } diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchOperationComponent.java b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchOperationComponent.java index 94c7be9..3c34370 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchOperationComponent.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchOperationComponent.java @@ -10,6 +10,7 @@ import javax.swing.JLabel; import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; public class BatchOperationComponent extends JPanel implements BatchContainer { @@ -54,5 +55,15 @@ public Collection getRunnables() { public Collection getListeners() { return batch.getListeners(); } + + @Override + public void update() { + SwingUtilities.invokeLater(() -> { + batch.update(); + revalidate(); + repaint(); + }); + + } } diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java index 6f834e6..31a3656 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java @@ -19,6 +19,7 @@ public BatchedImageComponent(BatchContainer batch) { @Override public Image getImage() { + System.out.println("Image"); int _new = 0; int working = 0; int success = 0; @@ -65,5 +66,11 @@ public Collection getRunnables() { public Collection getListeners() { return batch.getListeners(); } + + @Override + public void update() { + revalidate(); + repaint(); + } } diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/TestWindow.java b/src/main/java/com/gamebuster19901/excite/modding/ui/TestWindow.java new file mode 100644 index 0000000..7e5d43f --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/TestWindow.java @@ -0,0 +1,98 @@ +package com.gamebuster19901.excite.modding.ui; + +import java.awt.Dimension; +import java.awt.EventQueue; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +import com.gamebuster19901.excite.modding.concurrent.Batch; +import com.gamebuster19901.excite.modding.concurrent.BatchRunner; +import java.awt.GridBagLayout; +import java.awt.GridBagConstraints; + +public class TestWindow { + + private JFrame frame; + + /** + * Launch the application. + */ + public static void main(String[] args) { + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + TestWindow window = new TestWindow(); + window.frame.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + /** + * Create the application. + */ + public TestWindow() { + initialize(); + } + + /** + * Initialize the contents of the frame. + */ + private void initialize() { + System.out.println(Thread.currentThread()); + frame = new JFrame(); + frame.setBounds(100, 100, 450, 300); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + Batch batch = new Batch("Test"); + BatchRunner r = new BatchRunner("TestRunner"); + r.addBatch(batch); + BatchOperationComponent c = new BatchOperationComponent(r); + c.setPreferredSize(new Dimension(150, 175)); + for(int i = 0; i < 1000; i++) { + final int j = i; + batch.addRunnable(() -> { + try { + System.out.println(Thread.currentThread() + ": Ran " + j); + SwingUtilities.invokeLater(() -> { + c.update(); + System.out.println("Updated!"); + }); + + } catch (Throwable e) { + throw new RuntimeException(e); + } + }); + } + GridBagLayout gridBagLayout = new GridBagLayout(); + gridBagLayout.columnWidths = new int[]{450, 0}; + gridBagLayout.rowHeights = new int[]{263, 0}; + gridBagLayout.columnWeights = new double[]{1.0, Double.MIN_VALUE}; + gridBagLayout.rowWeights = new double[]{1.0, Double.MIN_VALUE}; + frame.getContentPane().setLayout(gridBagLayout); + JPanel panel = new JPanel(); + + + panel.add(c); + panel.setLayout(new WrapLayout()); + GridBagConstraints gbc_panel = new GridBagConstraints(); + gbc_panel.fill = GridBagConstraints.BOTH; + gbc_panel.gridx = 0; + gbc_panel.gridy = 0; + frame.getContentPane().add(panel, gbc_panel); + frame.setVisible(true); + new Thread(() -> { + try { + Thread.sleep(500); + r.startBatch(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }).start(); + } + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java index 17d6b78..601723e 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java @@ -14,7 +14,7 @@ import java.awt.GridBagConstraints; import java.awt.Insets; import java.io.File; -import java.io.FileNotFoundException; +import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; @@ -60,8 +60,9 @@ public class Window implements BatchListener { private JTextField textFieldSource; private JTextField textFieldDest; - private BatchRunner> copyOperations; - private BatchRunner processOperations; + private volatile Unarchiver unarchiver; + private volatile BatchRunner> copyOperations; + private volatile BatchRunner processOperations; /** * Launch the application. @@ -89,9 +90,11 @@ public Window() { /** * Initialize the contents of the frame. + * @throws IOException */ private void initialize() { - copyOperations = genCopyBatches(null, null); + unarchiver = genUnarchiver(null, null); + copyOperations = genCopyBatches(); processOperations = genProcessBatches(null); frame = new JFrame(); @@ -268,15 +271,23 @@ private void initialize() { throw new NotDirectoryException(folder.getAbsolutePath().toString()); } if(paths.size() != 0) { - int result = JOptionPane.showOptionDialog(frame, "Are you sure? You will overwrite " + paths.size() + " files.", "Overwrite?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, null, null); + int result = JOptionPane.showOptionDialog(frame, "Are you sure? This directory has " + paths.size() + " pre-existing files.\n\nDuplicates will be overridden", "Overwrite?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, null, null); if(result != 0) { return; } + + new Thread(() -> { + try { + copyOperations.startBatch(); + } catch (InterruptedException e1) { + throw new RuntimeException(e1); + } + }).start(); + } } - } catch(Throwable t) { throw new RuntimeException(t); @@ -300,7 +311,8 @@ private void selectDirectories(EJTabbedPane pane, File sourceDir, File destDir) } copyOperations.shutdownNow(); - copyOperations = genCopyBatches(sourceDir, destDir); + unarchiver = genUnarchiver(sourceDir, destDir); + copyOperations = genCopyBatches(); setupTabbedPane(pane); pane.setSelectedTab(tab); System.out.println("Set tab!"); @@ -731,14 +743,25 @@ private void setupRightProgressPane(JPanel progressPanel) { rightPanel.add(lblResourcesFailedPercent, gbc_lblResourcesFailedPercent); } + private Unarchiver genUnarchiver(File source, File dest) { + try { + Unarchiver unarchiver = new Unarchiver(source.toPath(), dest.toPath()); + return unarchiver; + } + catch(Throwable t) { + return null; + } + } + @SuppressWarnings({ "rawtypes", "unchecked" }) - private BatchRunner> genCopyBatches(File source, File dest) { + private BatchRunner> genCopyBatches() { BatchRunner> batchRunner = new BatchRunner("Unarchive"); try { - Unarchiver unarchiver = new Unarchiver(source.toPath(), dest.toPath()); - if(FileUtils.isDirectory(source) && FileUtils.isDirectory(dest)) { - for(Batch> batch : unarchiver.getCopyBatches()) { - batchRunner.addBatch(batch); + if(unarchiver != null) { + if(unarchiver.isValid()) { + for(Batch> batch : unarchiver.getCopyBatches()) { + batchRunner.addBatch(batch); + } } } } diff --git a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/ArchivedFile.java b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/ArchivedFile.java index aaa5f5a..f45e7d8 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/ArchivedFile.java +++ b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/ArchivedFile.java @@ -12,7 +12,6 @@ public class ArchivedFile { private final TocMonster.Details fileDetails; private final Archive archive; - private final byte[] bytes; public ArchivedFile(TocMonster.Details fileDetails, Archive archive) { try { @@ -24,10 +23,9 @@ public ArchivedFile(TocMonster.Details fileDetails, Archive archive) { System.out.println("File end: " + ((int)fileDetails.fileOffset() + (int)fileDetails.fileSize())); byte[] bytes = archive.getBytes(); System.out.println("Array size: " + bytes.length); - this.bytes = Arrays.copyOfRange(archive.getBytes(), (int)fileDetails.fileOffset(), (int)(fileDetails.fileOffset() + (int)fileDetails.fileSize())); } catch(Throwable t) { - System.err.println("Could not extract resource " + getName() + " from " + archive.getArchiveFile().getFileName()); + System.err.println("Bad resource reference: " + getName() + " from " + archive.getArchiveFile().getFileName()); t.printStackTrace(); throw t; } @@ -37,8 +35,13 @@ public String getName() { return fileDetails.name(); } - public byte[] getBytes() { - return bytes; + public byte[] getBytes() throws IOException { + try { + return Arrays.copyOfRange(archive.getBytes(), (int)fileDetails.fileOffset(), (int)(fileDetails.fileOffset() + (int)fileDetails.fileSize())); + } + catch(Throwable t) { + throw new IOException(t); + } } public void writeTo(Path directory) throws IOException { diff --git a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/QuickAccessArchive.java b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/QuickAccessArchive.java index f2a87ec..9faed06 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/QuickAccessArchive.java +++ b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/QuickAccessArchive.java @@ -3,34 +3,27 @@ import java.io.IOException; import java.nio.file.Path; +import org.apache.commons.lang3.concurrent.ConcurrentException; + public class QuickAccessArchive { private final Toc toc; private final Path archivePath; private volatile Archive archive; - private volatile boolean set; public QuickAccessArchive(Toc toc, Path archivePath) { this.toc = toc; this.archivePath = archivePath; } - public synchronized void setArchive() throws IOException { - if(set == false) { - try { - this.archive = new Archive(archivePath, toc); - } - catch(Throwable t) { - throw t; - } - finally { - set = true; //so we don't attempt to read the file multiple times if it fails + public Archive getArchive() throws IOException, ConcurrentException { + if(archive == null) { + synchronized(this) { + if(archive == null) { + archive = new Archive(archivePath, toc); + } } } - } - - public Archive getArchive() throws IOException { - setArchive(); return archive; } diff --git a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java index 7b7f96f..8a8b7fb 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java +++ b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java @@ -12,6 +12,7 @@ import com.gamebuster19901.excite.modding.concurrent.Batch; import com.gamebuster19901.excite.modding.game.file.kaitai.TocMonster.Details; +import com.gamebuster19901.excite.modding.util.FileUtils; public class Unarchiver { @@ -71,6 +72,10 @@ public Batch> getCopyBatch(Path tocFile) { return batch; } + public boolean isValid() { + return FileUtils.isDirectory(sourceDir) && FileUtils.isDirectory(destDir); + } + private QuickAccessArchive getArchive(Toc toc) throws IOException { for(Path archivePath : archives) { if(getFileName(toc.getFile()).equals(getFileName(archivePath))) { From 1f19e658fe0ad9b2db11c428ccdd6bf5e050efe6 Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Wed, 15 May 2024 03:50:17 -0400 Subject: [PATCH 09/19] More progress --- .../excite/modding/concurrent/Batch.java | 7 +-- .../modding/concurrent/BatchContainer.java | 12 +++- .../modding/concurrent/BatchRunner.java | 10 +--- .../modding/concurrent/BatchWorker.java | 11 ---- .../excite/modding/concurrent/Batcher.java | 14 +---- .../modding/concurrent/BatcherContainer.java | 11 ++++ .../modding/ui/BatchOperationComponent.java | 60 +++++++++++-------- .../modding/ui/BatchedImageComponent.java | 23 +++++-- .../excite/modding/ui/EJTabbedPane.java | 3 +- .../excite/modding/ui/TestWindow.java | 49 ++++++++++----- .../unarchiver/QuickAccessArchive.java | 2 +- 11 files changed, 115 insertions(+), 87 deletions(-) create mode 100644 src/main/java/com/gamebuster19901/excite/modding/concurrent/BatcherContainer.java diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java index e995735..4a314e1 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java @@ -6,6 +6,7 @@ import java.util.LinkedHashSet; import java.util.Set; import java.util.concurrent.Callable; + import static java.lang.Thread.State; public class Batch implements Batcher { @@ -49,7 +50,7 @@ public void addRunnable(Runnable runnable) { } @Override - public void addListener(BatchListener listener) { + public void addBatchListener(BatchListener listener) { if(accepting) { if(!listeners.add(listener)) { System.out.println("Warning: duplicate batch listener ignored."); @@ -234,8 +235,4 @@ protected void shutdown(Shutdown shutdown) { } } - @Override - public void update() { - //NO-OP - } } diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java index 4f507ae..01cc3a8 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java @@ -4,7 +4,7 @@ import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; -public interface BatchContainer extends BatchListener { +public interface BatchContainer { public abstract String getName(); @@ -12,4 +12,14 @@ public interface BatchContainer extends BatchListener { public Collection getListeners(); + public void addBatchListener(BatchListener listener); + + public default void updateListeners() { + for(BatchListener l : getListeners()) { + l.update(); + } + } + + public void shutdownNow() throws InterruptedException; + } diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java index 4b7a264..40d3274 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java @@ -8,7 +8,7 @@ import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; -public class BatchRunner implements BatchWorker { +public class BatchRunner implements BatchWorker, BatcherContainer { private final String name; private final ExecutorService executor; @@ -106,10 +106,11 @@ public void addBatchListener(BatchListener listener) { listenerAdded = true; } for(Batcher batch : batches) { - batch.addListener(listener); + batch.addBatchListener(listener); } } + @Override public Collection> getBatches() { return (Collection>) batches.clone(); } @@ -120,10 +121,5 @@ public int getCompleted() { for(BatchedCallable callable : callables) {ret++;} return ret; } - - @Override - public void update() { - //NO-OP - } } diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchWorker.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchWorker.java index 713b370..86def76 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchWorker.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchWorker.java @@ -1,13 +1,8 @@ package com.gamebuster19901.excite.modding.concurrent; -import java.util.Collection; import java.util.concurrent.TimeUnit; -import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; - public interface BatchWorker extends BatchContainer { - - public abstract void addBatch(Batcher batcher); public abstract void startBatch() throws InterruptedException; @@ -15,10 +10,4 @@ public interface BatchWorker extends BatchContainer { public void shutdownNow() throws InterruptedException; - public Collection> getRunnables(); - - public Collection getListeners(); - - public void addBatchListener(BatchListener listener); - } diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batcher.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batcher.java index bd2cb19..60debc1 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batcher.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batcher.java @@ -3,14 +3,12 @@ import java.util.Collection; import java.util.concurrent.Callable; -import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; - public interface Batcher extends BatchContainer { public abstract void addRunnable(Callable runnable); public abstract void addRunnable(Runnable runnable); - + @SuppressWarnings({ "rawtypes", "unchecked" }) public default void addRunnables(Collection runnables) { if(runnables.size() > 0) { @@ -34,14 +32,4 @@ else if (o instanceof Runnable) { } } - public abstract void addListener(BatchListener listener); - - public void shutdownNow() throws InterruptedException; - - public Collection> getRunnables(); - - public Collection getListeners(); - - public void updateListeners(); - } diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatcherContainer.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatcherContainer.java new file mode 100644 index 0000000..c744692 --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatcherContainer.java @@ -0,0 +1,11 @@ +package com.gamebuster19901.excite.modding.concurrent; + +import java.util.Collection; + +public interface BatcherContainer extends BatchContainer{ + + public abstract Collection> getBatches(); + + public abstract void addBatch(Batcher batcher); + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchOperationComponent.java b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchOperationComponent.java index 3c34370..bf20cca 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchOperationComponent.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchOperationComponent.java @@ -1,23 +1,22 @@ package com.gamebuster19901.excite.modding.ui; +import java.awt.BorderLayout; +import java.util.Collection; + +import javax.swing.JLabel; import javax.swing.JPanel; +import javax.swing.SwingConstants; import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; import com.gamebuster19901.excite.modding.concurrent.BatchContainer; import com.gamebuster19901.excite.modding.concurrent.BatchListener; -import java.awt.BorderLayout; -import java.util.Collection; -import javax.swing.JLabel; -import javax.swing.SwingConstants; -import javax.swing.SwingUtilities; +public class BatchOperationComponent extends JPanel implements BatchContainer, BatchListener { -public class BatchOperationComponent extends JPanel implements BatchContainer { - - private BatchedImageComponent batch; - private JLabel fileName; + private BatchedImageComponent image; + private JLabel nameLabel; - public BatchOperationComponent(BatchContainer batch) { + public BatchOperationComponent(BatchContainer batch) { this(new BatchedImageComponent(batch)); setName(batch.getName()); } @@ -25,17 +24,17 @@ public BatchOperationComponent(BatchContainer batch) { /** @wbp.parser.constructor **/ - public BatchOperationComponent(BatchedImageComponent batch) { - this.batch = batch; + public BatchOperationComponent(BatchedImageComponent batch) { + this.image = batch; setLayout(new BorderLayout(0, 0)); add(batch, BorderLayout.CENTER); String name = batch.getName(); - fileName = new JLabel(name); - fileName.setHorizontalAlignment(SwingConstants.CENTER); - add(fileName, BorderLayout.SOUTH); + nameLabel = new JLabel(name); + nameLabel.setHorizontalAlignment(SwingConstants.CENTER); + add(nameLabel, BorderLayout.SOUTH); this.setName(name); } @@ -43,27 +42,38 @@ public BatchOperationComponent(BatchedImageComponent batch) { public void setName(String name) { super.setName(name); this.setToolTipText(name); - this.fileName.setText(name); + this.nameLabel.setText(name); } @Override - public Collection getRunnables() { - return batch.getRunnables(); + public void addBatchListener(BatchListener listener) { + image.addBatchListener(listener); + } + + @Override + public void shutdownNow() throws InterruptedException { + image.shutdownNow(); + } + + @Override + public Collection> getRunnables() { + return image.getRunnables(); } @Override public Collection getListeners() { - return batch.getListeners(); + return image.getListeners(); } @Override - public void update() { - SwingUtilities.invokeLater(() -> { - batch.update(); - revalidate(); - repaint(); - }); + public void updateListeners() { + image.updateListeners(); + } + @Override + public void update() { + image.update(); + repaint(); } } diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java index 31a3656..affc6a6 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java @@ -4,17 +4,19 @@ import java.awt.Image; import java.util.Collection; import java.util.LinkedHashMap; + import com.gamebuster19901.excite.modding.concurrent.BatchListener; import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; import com.gamebuster19901.excite.modding.concurrent.BatchContainer; -public class BatchedImageComponent extends ImageComponent implements BatchContainer { +public class BatchedImageComponent extends ImageComponent implements BatchContainer, BatchListener { - private final BatchContainer batch; + private final BatchContainer batch; - public BatchedImageComponent(BatchContainer batch) { + public BatchedImageComponent(BatchContainer batch) { super(batch.getName()); this.batch = batch; + addBatchListener(this); } @Override @@ -56,9 +58,8 @@ public Image getImage() { return StripedImageGenerator.generateImage(getWidth(), getHeight(), (LinkedHashMap) colors); } - @Override - public Collection getRunnables() { + public Collection> getRunnables() { return batch.getRunnables(); } @@ -67,10 +68,20 @@ public Collection getListeners() { return batch.getListeners(); } + @Override + public void addBatchListener(BatchListener listener) { + batch.addBatchListener(listener); + } + @Override public void update() { - revalidate(); repaint(); + System.out.println("Updated"); + } + + @Override + public void shutdownNow() throws InterruptedException { + batch.shutdownNow(); } } diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/EJTabbedPane.java b/src/main/java/com/gamebuster19901/excite/modding/ui/EJTabbedPane.java index b3a76e0..b8317ab 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/EJTabbedPane.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/EJTabbedPane.java @@ -100,9 +100,8 @@ public Tab getTab(String title) throws IndexOutOfBoundsException { * * @param index The index of the tab to retrieve. * @return A `Tab` object representing the tab at the specified index, or null if the index is invalid. - * @throws IndexOutOfBoundsException if the index is invalid. */ - public Tab getTab(int index) throws IndexOutOfBoundsException { + public Tab getTab(int index) { if(index < 0 || index > this.getComponentCount()) { return null; } diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/TestWindow.java b/src/main/java/com/gamebuster19901/excite/modding/ui/TestWindow.java index 7e5d43f..ecb6801 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/TestWindow.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/TestWindow.java @@ -5,12 +5,14 @@ import javax.swing.JFrame; import javax.swing.JPanel; -import javax.swing.SwingUtilities; import com.gamebuster19901.excite.modding.concurrent.Batch; import com.gamebuster19901.excite.modding.concurrent.BatchRunner; import java.awt.GridBagLayout; import java.awt.GridBagConstraints; +import javax.swing.JTabbedPane; +import java.awt.Insets; +import java.util.Random; public class TestWindow { @@ -51,34 +53,49 @@ private void initialize() { Batch batch = new Batch("Test"); BatchRunner r = new BatchRunner("TestRunner"); r.addBatch(batch); + + GridBagLayout gridBagLayout = new GridBagLayout(); + gridBagLayout.columnWidths = new int[]{450, 0}; + gridBagLayout.rowHeights = new int[]{263, 0}; + gridBagLayout.columnWeights = new double[]{1.0, Double.MIN_VALUE}; + gridBagLayout.rowWeights = new double[]{1.0, Double.MIN_VALUE}; + frame.getContentPane().setLayout(gridBagLayout); + JPanel panel = new JPanel(); + GridBagLayout gbl_panel = new GridBagLayout(); + gbl_panel.columnWidths = new int[]{150, 39, 0}; + gbl_panel.rowHeights = new int[]{175, 0}; + gbl_panel.columnWeights = new double[]{0.0, 1.0, Double.MIN_VALUE}; + gbl_panel.rowWeights = new double[]{1.0, Double.MIN_VALUE}; + panel.setLayout(gbl_panel); BatchOperationComponent c = new BatchOperationComponent(r); c.setPreferredSize(new Dimension(150, 175)); - for(int i = 0; i < 1000; i++) { + for(int i = 0; i < 20; i++) { final int j = i; batch.addRunnable(() -> { try { + Thread.sleep(new Random().nextInt(0, 1000)); System.out.println(Thread.currentThread() + ": Ran " + j); - SwingUtilities.invokeLater(() -> { - c.update(); - System.out.println("Updated!"); - }); - } catch (Throwable e) { throw new RuntimeException(e); } }); } - GridBagLayout gridBagLayout = new GridBagLayout(); - gridBagLayout.columnWidths = new int[]{450, 0}; - gridBagLayout.rowHeights = new int[]{263, 0}; - gridBagLayout.columnWeights = new double[]{1.0, Double.MIN_VALUE}; - gridBagLayout.rowWeights = new double[]{1.0, Double.MIN_VALUE}; - frame.getContentPane().setLayout(gridBagLayout); - JPanel panel = new JPanel(); - panel.add(c); - panel.setLayout(new WrapLayout()); + + + JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP); + GridBagConstraints gbc_c = new GridBagConstraints(); + gbc_c.anchor = GridBagConstraints.NORTHWEST; + gbc_c.insets = new Insets(0, 0, 0, 5); + gbc_c.gridx = 0; + gbc_c.gridy = 0; + tabbedPane.add(c, gbc_c); + GridBagConstraints gbc_tabbedPane = new GridBagConstraints(); + gbc_tabbedPane.anchor = GridBagConstraints.WEST; + gbc_tabbedPane.gridx = 1; + gbc_tabbedPane.gridy = 0; + panel.add(tabbedPane, gbc_tabbedPane); GridBagConstraints gbc_panel = new GridBagConstraints(); gbc_panel.fill = GridBagConstraints.BOTH; gbc_panel.gridx = 0; diff --git a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/QuickAccessArchive.java b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/QuickAccessArchive.java index 9faed06..e845a0d 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/QuickAccessArchive.java +++ b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/QuickAccessArchive.java @@ -9,7 +9,7 @@ public class QuickAccessArchive { private final Toc toc; private final Path archivePath; - private volatile Archive archive; + private volatile Archive archive; //This MUST be volatile or double checked locking will not work! public QuickAccessArchive(Toc toc, Path archivePath) { this.toc = toc; From f6dc8c733d91b32c5f172a869fbad48e6ae4c57c Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Wed, 15 May 2024 14:22:22 -0400 Subject: [PATCH 10/19] Resources to skip are blue --- .../excite/modding/concurrent/Batch.java | 20 ++++++++-- .../modding/concurrent/BatchContainer.java | 12 ++++++ .../modding/ui/BatchedImageComponent.java | 30 +++++++++++++- .../excite/modding/ui/Window.java | 17 ++++---- .../excite/modding/unarchiver/Unarchiver.java | 22 +++++------ .../concurrent/DecidingBatchedCallable.java | 39 +++++++++++++++++++ .../unarchiver/concurrent/DecisionType.java | 9 +++++ .../unarchiver/concurrent/Skippable.java | 7 ++++ .../unarchiver/concurrent/package-info.java | 1 + 9 files changed, 134 insertions(+), 23 deletions(-) create mode 100644 src/main/java/com/gamebuster19901/excite/modding/unarchiver/concurrent/DecidingBatchedCallable.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/unarchiver/concurrent/DecisionType.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/unarchiver/concurrent/Skippable.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/unarchiver/concurrent/package-info.java diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java index 4a314e1..d456312 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java @@ -1,6 +1,6 @@ package com.gamebuster19901.excite.modding.concurrent; -import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashSet; @@ -25,6 +25,16 @@ public String getName() { return name; } + public void addRunnable(BatchedCallable batchedCallable) { + if(accepting) { + runnables.add(batchedCallable); + updateListeners(); + } + else { + notAccepting(); + } + } + @Override public void addRunnable(Callable runnable) { if(accepting) { @@ -105,8 +115,10 @@ public static class BatchedCallable implements Callable { private final Batcher batch; private final Callable child; - private volatile SoftReference threadRef; + private volatile WeakReference threadRef; protected volatile Throwable thrown; + private final Object startLock = new Object(); + private volatile Boolean started = false; protected volatile boolean finished = false; protected volatile T result; @@ -148,6 +160,8 @@ public BatchedCallable(Batcher batch, Callable c) { * This method executes the wrapped `Callable` object and stores the result. It also updates the state of this object * and notifies the associated Batcher before and after execution. If any exceptions occur during execution, they are * stored but not re-thrown by this method. The caller of this method is responsible for handling any exceptions. + * + * The behavior of this callable is undefined if call() is executed more than once. * * @return the result of the wrapped callable's execution (which may be null), or null if an exception occurred */ @@ -156,7 +170,7 @@ public T call() { Thread thread; try { thread = Thread.currentThread(); - threadRef = new SoftReference<>(thread); + threadRef = new WeakReference<>(thread); batch.updateListeners(); result = child.call(); return result; diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java index 01cc3a8..6938af8 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchContainer.java @@ -1,6 +1,7 @@ package com.gamebuster19901.excite.modding.concurrent; import java.util.Collection; +import java.util.LinkedHashSet; import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; @@ -10,6 +11,17 @@ public interface BatchContainer { public Collection> getRunnables(); + public default Collection getResults() throws IllegalStateException { + LinkedHashSet results = new LinkedHashSet<>(); + for(BatchedCallable callable : getRunnables()) { + T result = callable.getResult(); + if(result != null || (result == null && callable.getThrown() == null)) { + results.add(result); + } + } + return results; + } + public Collection getListeners(); public void addBatchListener(BatchListener listener); diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java index affc6a6..aa786e4 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java @@ -5,7 +5,10 @@ import java.util.Collection; import java.util.LinkedHashMap; +import org.apache.commons.lang3.tuple.Pair; + import com.gamebuster19901.excite.modding.concurrent.BatchListener; +import com.gamebuster19901.excite.modding.unarchiver.concurrent.DecisionType; import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; import com.gamebuster19901.excite.modding.concurrent.BatchContainer; @@ -23,6 +26,7 @@ public BatchedImageComponent(BatchContainer batch) { public Image getImage() { System.out.println("Image"); int _new = 0; + int skipped = 0; int working = 0; int success = 0; int failure = 0; @@ -37,10 +41,31 @@ public Image getImage() { working++; continue; case TERMINATED: - if(runnable.getThrown() == null) { - success++; + if(runnable.getThrown() != null) { + failure++; continue; } + Object r = runnable.getResult(); + if (r instanceof Pair) { + Object key = ((Pair) r).getKey(); + if(key instanceof DecisionType) { + DecisionType decision = (DecisionType) key; + switch(decision) { + case IGNORE: + failure++; + continue; + case PROCEED: + success++; + continue; + case SKIP: + skipped++; + continue; + default: + other++; + continue; + } + } + } failure++; continue; default: @@ -50,6 +75,7 @@ public Image getImage() { LinkedHashMap colors = new LinkedHashMap<>(); colors.put(Color.GREEN, success); + colors.put(Color.BLUE, skipped); colors.put(Color.RED, failure); colors.put(Color.WHITE, working); colors.put(Color.ORANGE, other); diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java index 601723e..3adc4b2 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java @@ -30,12 +30,15 @@ import javax.swing.SwingConstants; import javax.swing.SwingUtilities; +import org.apache.commons.lang3.tuple.Pair; + import com.gamebuster19901.excite.modding.concurrent.Batch; import com.gamebuster19901.excite.modding.concurrent.BatchListener; import com.gamebuster19901.excite.modding.concurrent.BatchRunner; import com.gamebuster19901.excite.modding.concurrent.Batcher; import com.gamebuster19901.excite.modding.ui.EJTabbedPane.Tab; import com.gamebuster19901.excite.modding.unarchiver.Unarchiver; +import com.gamebuster19901.excite.modding.unarchiver.concurrent.DecisionType; import com.gamebuster19901.excite.modding.util.FileUtils; import com.gamebuster19901.excite.modding.util.SplitOutputStream; @@ -61,7 +64,7 @@ public class Window implements BatchListener { private JTextField textFieldDest; private volatile Unarchiver unarchiver; - private volatile BatchRunner> copyOperations; + private volatile BatchRunner>> copyOperations; private volatile BatchRunner processOperations; /** @@ -330,7 +333,7 @@ public EJTabbedPane setupTabbedPane(EJTabbedPane tabbedPane) { tabbedPane.addTab(statusTab); tabbedPane.addTab(progressTab); - for(Batcher> b : copyOperations.getBatches()) { + for(Batcher>> b : copyOperations.getBatches()) { tabbedPane.addTab(b.getName(), new JPanel()); } @@ -374,7 +377,7 @@ private Tab setupStatusTab(EJTabbedPane tabbedPane) { JPanel statusGrid = new JPanel(new WrapLayout()); JScrollPane statusGridScroller = new JScrollPane(statusGrid); - Iterator>> batches = copyOperations.getBatches().iterator(); + Iterator>>> batches = copyOperations.getBatches().iterator(); int i = 0; while(batches.hasNext()) { BatchOperationComponent b = new BatchOperationComponent(batches.next()); @@ -754,19 +757,19 @@ private Unarchiver genUnarchiver(File source, File dest) { } @SuppressWarnings({ "rawtypes", "unchecked" }) - private BatchRunner> genCopyBatches() { - BatchRunner> batchRunner = new BatchRunner("Unarchive"); + private BatchRunner>> genCopyBatches() { + BatchRunner>> batchRunner = new BatchRunner("Unarchive"); try { if(unarchiver != null) { if(unarchiver.isValid()) { - for(Batch> batch : unarchiver.getCopyBatches()) { + for(Batch>> batch : unarchiver.getCopyBatches()) { batchRunner.addBatch(batch); } } } } catch(Throwable t) { - Batch> errBatch = new Batch<>("Error"); + Batch>> errBatch = new Batch<>("Error"); errBatch.addRunnable(() -> { throw t; }); diff --git a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java index 8a8b7fb..d00df4c 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java +++ b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java @@ -10,8 +10,11 @@ import java.util.concurrent.Callable; import java.util.stream.Stream; +import org.apache.commons.lang3.tuple.Pair; + import com.gamebuster19901.excite.modding.concurrent.Batch; import com.gamebuster19901.excite.modding.game.file.kaitai.TocMonster.Details; +import com.gamebuster19901.excite.modding.unarchiver.concurrent.DecisionType; import com.gamebuster19901.excite.modding.util.FileUtils; public class Unarchiver { @@ -28,16 +31,16 @@ public Unarchiver(Path sourceDir, Path destDir) throws IOException { refresh(); } - public Collection>> getCopyBatches() { - LinkedHashSet>> batches = new LinkedHashSet<>(); + public Collection>>> getCopyBatches() { + LinkedHashSet>>> batches = new LinkedHashSet<>(); for(Path toc : tocs) { batches.add(getCopyBatch(toc)); } return batches; } - public Batch> getCopyBatch(Path tocFile) { - Batch> batch = new Batch<>(tocFile.getFileName().toString()); + public Batch>> getCopyBatch(Path tocFile) { + Batch>> batch = new Batch<>(tocFile.getFileName().toString()); try { Toc toc = new Toc(tocFile.toAbsolutePath()); List
details = toc.getFiles(); @@ -50,23 +53,20 @@ public Batch> getCopyBatch(Path tocFile) { System.out.println(tocFile.getFileName() + "/" + resourceName); archive.getArchive().getFile(resourceName).writeTo(destDir.resolve(resourceName)); if(resource.name().endsWith("tex")) { - return () -> { - System.out.println("This is an example of processing a texture!"); - return null; - }; + return Pair.of(DecisionType.SKIP, () -> {return null;}); } } catch(Throwable t) { - throw t; + return Pair.of(DecisionType.IGNORE, () -> {throw t;}); } - return null; + return Pair.of(DecisionType.PROCEED, () -> {return null;}); }); } } catch(Throwable t) { batch.addRunnable(() -> { - throw t; //let the batchrunner know that an error occurred + return Pair.of(DecisionType.IGNORE, () -> {throw t;}); //let the batchrunner know that an error occurred }); } return batch; diff --git a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/concurrent/DecidingBatchedCallable.java b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/concurrent/DecidingBatchedCallable.java new file mode 100644 index 0000000..f0f4b67 --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/concurrent/DecidingBatchedCallable.java @@ -0,0 +1,39 @@ +package com.gamebuster19901.excite.modding.unarchiver.concurrent; + +import java.util.concurrent.Callable; + +import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; +import com.gamebuster19901.excite.modding.concurrent.Batcher; + +public class DecidingBatchedCallable extends BatchedCallable { + + private volatile DecisionType decision; + + public DecidingBatchedCallable(Batcher batch, Callable c) { + super(batch, c); + } + + @Override + public T call() { + T ret = super.call(); + processDecision(); + return ret; + } + + private void processDecision() { + if(this.getThrown() != null) { + decision = DecisionType.IGNORE; + } + else if(this.result.shouldSkip()) { + decision = DecisionType.SKIP; + } + else { + decision = DecisionType.PROCEED; + } + } + + public DecisionType getDecisionType() { + return decision; + } + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/concurrent/DecisionType.java b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/concurrent/DecisionType.java new file mode 100644 index 0000000..85fef16 --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/concurrent/DecisionType.java @@ -0,0 +1,9 @@ +package com.gamebuster19901.excite.modding.unarchiver.concurrent; + +public enum DecisionType { + + PROCEED, //Proceed with the process + SKIP, //Don't proceed with the process, we know we don't know how to handle it + IGNORE; //Don't proceed with the process, an unexpected exception occurred. + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/concurrent/Skippable.java b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/concurrent/Skippable.java new file mode 100644 index 0000000..b707c4f --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/concurrent/Skippable.java @@ -0,0 +1,7 @@ +package com.gamebuster19901.excite.modding.unarchiver.concurrent; + +public interface Skippable { + + public boolean shouldSkip(); + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/concurrent/package-info.java b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/concurrent/package-info.java new file mode 100644 index 0000000..1c2836b --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/concurrent/package-info.java @@ -0,0 +1 @@ +package com.gamebuster19901.excite.modding.unarchiver.concurrent; \ No newline at end of file From 958ffd6356b4d79e5a5a31fda953ed5a70d6dcab Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Wed, 15 May 2024 14:22:48 -0400 Subject: [PATCH 11/19] Add key to status tab --- .../modding/ui/BatchedImageComponent.java | 2 +- .../excite/modding/ui/ColorKeyComponent.java | 47 +++++++++++++++ .../excite/modding/ui/TestWindow.java | 57 ++++++++++++++++--- .../excite/modding/ui/Window.java | 54 +++++++++++++++++- 4 files changed, 150 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/gamebuster19901/excite/modding/ui/ColorKeyComponent.java diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java index aa786e4..78e9ad3 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageComponent.java @@ -75,7 +75,7 @@ public Image getImage() { LinkedHashMap colors = new LinkedHashMap<>(); colors.put(Color.GREEN, success); - colors.put(Color.BLUE, skipped); + colors.put(Color.CYAN.darker(), skipped); colors.put(Color.RED, failure); colors.put(Color.WHITE, working); colors.put(Color.ORANGE, other); diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/ColorKeyComponent.java b/src/main/java/com/gamebuster19901/excite/modding/ui/ColorKeyComponent.java new file mode 100644 index 0000000..6b8c326 --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/ColorKeyComponent.java @@ -0,0 +1,47 @@ +package com.gamebuster19901.excite.modding.ui; + +import java.awt.Color; + +import javax.swing.JPanel; +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import java.awt.FlowLayout; +import java.awt.GridBagLayout; +import java.awt.GridBagConstraints; +import java.awt.Insets; +import javax.swing.SwingConstants; + +public class ColorKeyComponent extends JPanel { + + private static final long serialVersionUID = 1L; + + public ColorKeyComponent(Color color, String name) { + this.setBorder(BorderFactory.createEmptyBorder()); + GridBagLayout gridBagLayout = new GridBagLayout(); + gridBagLayout.columnWidths = new int[]{0, 0}; + gridBagLayout.rowHeights = new int[]{25}; + gridBagLayout.columnWeights = new double[]{0.0, 0.0}; + gridBagLayout.rowWeights = new double[]{0.0}; + setLayout(gridBagLayout); + JLabel coloring = new JLabel("■"); + coloring.setBorder(BorderFactory.createEmptyBorder()); + coloring.setHorizontalAlignment(SwingConstants.TRAILING); + FlowLayout flowLayout = new FlowLayout(); + flowLayout.setAlignment(FlowLayout.LEFT); + coloring.setForeground(color); + GridBagConstraints gbc_coloring = new GridBagConstraints(); + gbc_coloring.anchor = GridBagConstraints.EAST; + gbc_coloring.insets = new Insets(0, 0, 2, 0); + gbc_coloring.gridx = 0; + gbc_coloring.gridy = 0; + add(coloring, gbc_coloring); + JLabel lblName = new JLabel(":" + name); + GridBagConstraints gbc_lblName = new GridBagConstraints(); + gbc_lblName.anchor = GridBagConstraints.WEST; + gbc_lblName.gridx = 1; + gbc_lblName.gridy = 0; + add(lblName, gbc_lblName); + + } + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/TestWindow.java b/src/main/java/com/gamebuster19901/excite/modding/ui/TestWindow.java index ecb6801..fc49b8a 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/TestWindow.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/TestWindow.java @@ -1,5 +1,6 @@ package com.gamebuster19901.excite.modding.ui; +import java.awt.Color; import java.awt.Dimension; import java.awt.EventQueue; @@ -13,6 +14,7 @@ import javax.swing.JTabbedPane; import java.awt.Insets; import java.util.Random; +import javax.swing.JScrollPane; public class TestWindow { @@ -67,8 +69,6 @@ private void initialize() { gbl_panel.columnWeights = new double[]{0.0, 1.0, Double.MIN_VALUE}; gbl_panel.rowWeights = new double[]{1.0, Double.MIN_VALUE}; panel.setLayout(gbl_panel); - BatchOperationComponent c = new BatchOperationComponent(r); - c.setPreferredSize(new Dimension(150, 175)); for(int i = 0; i < 20; i++) { final int j = i; batch.addRunnable(() -> { @@ -85,17 +85,58 @@ private void initialize() { JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP); - GridBagConstraints gbc_c = new GridBagConstraints(); - gbc_c.anchor = GridBagConstraints.NORTHWEST; - gbc_c.insets = new Insets(0, 0, 0, 5); - gbc_c.gridx = 0; - gbc_c.gridy = 0; - tabbedPane.add(c, gbc_c); GridBagConstraints gbc_tabbedPane = new GridBagConstraints(); gbc_tabbedPane.anchor = GridBagConstraints.WEST; gbc_tabbedPane.gridx = 1; gbc_tabbedPane.gridy = 0; panel.add(tabbedPane, gbc_tabbedPane); + + JPanel panel_1 = new JPanel(); + tabbedPane.addTab("New tab", null, panel_1, null); + GridBagLayout gbl_panel_1 = new GridBagLayout(); + gbl_panel_1.columnWidths = new int[]{0, 0, 0}; + gbl_panel_1.rowHeights = new int[]{0, 178, 0}; + gbl_panel_1.columnWeights = new double[]{0.0, 1.0, Double.MIN_VALUE}; + gbl_panel_1.rowWeights = new double[]{1.0, 0.0, Double.MIN_VALUE}; + panel_1.setLayout(gbl_panel_1); + + ColorKeyComponent lblNewLabel = new ColorKeyComponent(Color.RED, "Errorifying, really weird"); + GridBagConstraints gbc_lblNewLabel = new GridBagConstraints(); + gbc_lblNewLabel.insets = new Insets(0, 0, 5, 5); + gbc_lblNewLabel.gridx = 0; + gbc_lblNewLabel.gridy = 0; + panel_1.add(lblNewLabel, gbc_lblNewLabel); + + ColorKeyComponent lblNewLabel_1 = new ColorKeyComponent(Color.RED, "Error"); + GridBagLayout gridBagLayout_1 = (GridBagLayout) lblNewLabel_1.getLayout(); + gridBagLayout_1.rowWeights = new double[]{0.0}; + gridBagLayout_1.rowHeights = new int[]{25}; + gridBagLayout_1.columnWeights = new double[]{0.0, 1.0}; + gridBagLayout_1.columnWidths = new int[]{25, 78}; + GridBagConstraints gbc_lblNewLabel_1 = new GridBagConstraints(); + gbc_lblNewLabel_1.insets = new Insets(0, 0, 5, 0); + gbc_lblNewLabel_1.fill = GridBagConstraints.BOTH; + gbc_lblNewLabel_1.gridx = 1; + gbc_lblNewLabel_1.gridy = 0; + panel_1.add(lblNewLabel_1, gbc_lblNewLabel_1); + + + + BatchOperationComponent c = new BatchOperationComponent(r); + + JScrollPane scrollPane = new JScrollPane(c); + GridBagConstraints gbc_scrollPane = new GridBagConstraints(); + gbc_scrollPane.gridwidth = 2; + gbc_scrollPane.anchor = GridBagConstraints.NORTHWEST; + gbc_scrollPane.gridx = 0; + gbc_scrollPane.gridy = 1; + panel_1.add(scrollPane, gbc_scrollPane); + c.setPreferredSize(new Dimension(150, 175)); + GridBagConstraints gbc_c = new GridBagConstraints(); + gbc_c.anchor = GridBagConstraints.NORTHWEST; + gbc_c.insets = new Insets(0, 0, 0, 5); + gbc_c.gridx = 0; + gbc_c.gridy = 0; GridBagConstraints gbc_panel = new GridBagConstraints(); gbc_panel.fill = GridBagConstraints.BOTH; gbc_panel.gridx = 0; diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java index 3adc4b2..a45b293 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java @@ -52,6 +52,9 @@ import javax.swing.JPanel; import javax.swing.JTabbedPane; import javax.swing.JTextArea; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.FlowLayout; public class Window implements BatchListener { @@ -374,6 +377,11 @@ private Tab setupStatusTab(EJTabbedPane tabbedPane) { //remove all } + JPanel contents = setupStatusNavigationPanel(tabbedPane); + + + + Tab tab = new Tab(STATUS, null, contents, null); JPanel statusGrid = new JPanel(new WrapLayout()); JScrollPane statusGridScroller = new JScrollPane(statusGrid); @@ -386,13 +394,57 @@ private Tab setupStatusTab(EJTabbedPane tabbedPane) { i++; } - Tab tab = new Tab(STATUS, null, statusGridScroller, null); + GridBagConstraints gbc_statusGridScroller = new GridBagConstraints(); + gbc_statusGridScroller.fill = GridBagConstraints.BOTH; + gbc_statusGridScroller.gridx = 0; + gbc_statusGridScroller.gridy = 1; + contents.add(statusGridScroller, gbc_statusGridScroller); + + statusGridScroller.getVerticalScrollBar().setUnitIncrement(175 / 2); tabbedPane.addTab(tab.title(), tab.icon(), tab.component(), tab.tip()); //need to add this separately so the window builder can see it return tab; } + private JPanel setupStatusNavigationPanel(EJTabbedPane tabbedPane) { + JPanel contents = new JPanel(); + GridBagLayout gbl_contents = new GridBagLayout(); + gbl_contents.columnWidths = new int[]{22, 0}; + gbl_contents.rowHeights = new int[]{0, 13, 0}; + gbl_contents.columnWeights = new double[]{1.0, Double.MIN_VALUE}; + gbl_contents.rowWeights = new double[]{0.0, 1.0, Double.MIN_VALUE}; + contents.setLayout(gbl_contents); + + JPanel NavigationPanel = new JPanel(); + GridBagConstraints gbc_NavigationPanel = new GridBagConstraints(); + gbc_NavigationPanel.insets = new Insets(0, 0, 5, 0); + gbc_NavigationPanel.fill = GridBagConstraints.BOTH; + gbc_NavigationPanel.gridx = 0; + gbc_NavigationPanel.gridy = 0; + contents.add(NavigationPanel, gbc_NavigationPanel); + NavigationPanel.setLayout(new BorderLayout(0, 0)); + + JLabel lblKey = new JLabel("Key"); + lblKey.setHorizontalAlignment(SwingConstants.CENTER); + NavigationPanel.add(lblKey); + + JPanel keysPanel = new JPanel(); + FlowLayout flowLayout = (FlowLayout) keysPanel.getLayout(); + flowLayout.setHgap(20); + flowLayout.setVgap(0); + NavigationPanel.add(keysPanel, BorderLayout.SOUTH); + + keysPanel.add(new ColorKeyComponent(Color.GRAY, "Not Started")); + keysPanel.add(new ColorKeyComponent(Color.ORANGE, "Other")); + keysPanel.add(new ColorKeyComponent(Color.WHITE, "Working")); + keysPanel.add(new ColorKeyComponent(Color.RED, "Failure")); + keysPanel.add(new ColorKeyComponent(Color.CYAN.darker(), "Skipped")); + keysPanel.add(new ColorKeyComponent(Color.GREEN, "Success")); + + return contents; + } + public Tab setupProgressTab(EJTabbedPane tabbedPane) { Tab progressTab = tabbedPane.getTab(PROGRESS); if(progressTab != null) { From 56628d29501fea8dcd3abaeb882fa86d2a2b97d6 Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Wed, 15 May 2024 16:40:55 -0400 Subject: [PATCH 12/19] MOAR performance, Batchrunner go vroom --- .../modding/concurrent/BatchRunner.java | 15 +++---- .../modding/ui/BatchedImageListener.java | 7 ---- .../excite/modding/ui/Window.java | 31 ++++++++++----- .../concurrent/DecidingBatchedCallable.java | 39 ------------------- .../excite/modding/util/FileUtils.java | 3 -- 5 files changed, 27 insertions(+), 68 deletions(-) delete mode 100644 src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageListener.java delete mode 100644 src/main/java/com/gamebuster19901/excite/modding/unarchiver/concurrent/DecidingBatchedCallable.java diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java index 40d3274..5c26b10 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java @@ -1,6 +1,8 @@ package com.gamebuster19901.excite.modding.concurrent; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.LinkedHashSet; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -57,9 +59,9 @@ public void startBatch() throws InterruptedException { } synchronized(batches) { started = true; - for(Batcher batch : batches) { - executor.invokeAll(batch.getRunnables()); - } + ArrayList> batchers = new ArrayList<>(getRunnables()); + Collections.shuffle(batchers); //So multiple threads don't wait for a single archive to lazily load, allows multiple archives to lazily load at a time + executor.invokeAll(batchers); } } } @@ -114,12 +116,5 @@ public void addBatchListener(BatchListener listener) { public Collection> getBatches() { return (Collection>) batches.clone(); } - - public int getCompleted() { - int ret = 0; - Collection> callables = getRunnables(); - for(BatchedCallable callable : callables) {ret++;} - return ret; - } } diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageListener.java b/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageListener.java deleted file mode 100644 index 53d399d..0000000 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/BatchedImageListener.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.gamebuster19901.excite.modding.ui; - -public interface BatchedImageListener { - - public void onBatchedImageUpdate(); - -} diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java index a45b293..9fc1ba8 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java @@ -65,6 +65,7 @@ public class Window implements BatchListener { private JFrame frame; private JTextField textFieldSource; private JTextField textFieldDest; + private JSlider threadSlider; private volatile Unarchiver unarchiver; private volatile BatchRunner>> copyOperations; @@ -100,6 +101,14 @@ public Window() { */ private void initialize() { unarchiver = genUnarchiver(null, null); + + threadSlider = new JSlider(); + threadSlider.setSnapToTicks(true); + threadSlider.setMinimum(1); + threadSlider.setMaximum(Runtime.getRuntime().availableProcessors()); + threadSlider.setPreferredSize(new Dimension(77, 16)); + threadSlider.setBorder(null); + copyOperations = genCopyBatches(); processOperations = genProcessBatches(null); @@ -193,16 +202,13 @@ private void initialize() { gbc_lblThreads.gridy = 4; frame.getContentPane().add(lblThreads, gbc_lblThreads); - JSlider slider = new JSlider(); - slider.setSnapToTicks(true); - slider.setPreferredSize(new Dimension(77, 16)); - slider.setBorder(null); + GridBagConstraints gbc_slider = new GridBagConstraints(); gbc_slider.fill = GridBagConstraints.HORIZONTAL; gbc_slider.insets = new Insets(0, 0, 5, 5); gbc_slider.gridx = 1; gbc_slider.gridy = 5; - frame.getContentPane().add(slider, gbc_slider); + frame.getContentPane().add(threadSlider, gbc_slider); JProgressBar progressBar = new CustomProgressBar(); progressBar.setStringPainted(true); @@ -425,7 +431,7 @@ private JPanel setupStatusNavigationPanel(EJTabbedPane tabbedPane) { contents.add(NavigationPanel, gbc_NavigationPanel); NavigationPanel.setLayout(new BorderLayout(0, 0)); - JLabel lblKey = new JLabel("Key"); + JLabel lblKey = new JLabel("Legend"); lblKey.setHorizontalAlignment(SwingConstants.CENTER); NavigationPanel.add(lblKey); @@ -447,9 +453,9 @@ private JPanel setupStatusNavigationPanel(EJTabbedPane tabbedPane) { public Tab setupProgressTab(EJTabbedPane tabbedPane) { Tab progressTab = tabbedPane.getTab(PROGRESS); - if(progressTab != null) { + /*if(progressTab != null) { return progressTab; - } + }*/ JPanel progressPanel = new JPanel(); Tab tab = new Tab(PROGRESS, null, progressPanel, null); @@ -490,7 +496,9 @@ private void setupLeftProgressPane(JPanel progressPanel) { gbc_separator.gridy = 0; leftPanel.add(separator, gbc_separator); BatchOperationComponent copyBatchComponent = new BatchOperationComponent(copyOperations); + copyOperations.addBatchListener(copyBatchComponent); copyBatchComponent.setToolTipText("All Batches"); + System.out.println(copyOperations.getBatches().size() + " OISHDFPIOHDFIUOSPHUIFSIDOHUOFHUIOSDHIFUHOHIUO"); GridBagConstraints gbc_copyBatchComponent = new GridBagConstraints(); gbc_copyBatchComponent.fill = GridBagConstraints.BOTH; @@ -678,6 +686,7 @@ private void setupLeftProgressPane(JPanel progressPanel) { copyOperations.addBatchListener(() -> { SwingUtilities.invokeLater(() -> { + //lblResourcesCopiedCount.setText(copyBatchComponent.); update(); }); }); @@ -810,7 +819,7 @@ private Unarchiver genUnarchiver(File source, File dest) { @SuppressWarnings({ "rawtypes", "unchecked" }) private BatchRunner>> genCopyBatches() { - BatchRunner>> batchRunner = new BatchRunner("Unarchive"); + BatchRunner>> batchRunner = new BatchRunner("Unarchive", this.getUsableThreads()); try { if(unarchiver != null) { if(unarchiver.isValid()) { @@ -850,4 +859,8 @@ public void update() { frame.repaint(); } + private int getUsableThreads() { + return Math.clamp(threadSlider.getValue(), 1, Runtime.getRuntime().availableProcessors()); + } + } diff --git a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/concurrent/DecidingBatchedCallable.java b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/concurrent/DecidingBatchedCallable.java deleted file mode 100644 index f0f4b67..0000000 --- a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/concurrent/DecidingBatchedCallable.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.gamebuster19901.excite.modding.unarchiver.concurrent; - -import java.util.concurrent.Callable; - -import com.gamebuster19901.excite.modding.concurrent.Batch.BatchedCallable; -import com.gamebuster19901.excite.modding.concurrent.Batcher; - -public class DecidingBatchedCallable extends BatchedCallable { - - private volatile DecisionType decision; - - public DecidingBatchedCallable(Batcher batch, Callable c) { - super(batch, c); - } - - @Override - public T call() { - T ret = super.call(); - processDecision(); - return ret; - } - - private void processDecision() { - if(this.getThrown() != null) { - decision = DecisionType.IGNORE; - } - else if(this.result.shouldSkip()) { - decision = DecisionType.SKIP; - } - else { - decision = DecisionType.PROCEED; - } - } - - public DecisionType getDecisionType() { - return decision; - } - -} diff --git a/src/main/java/com/gamebuster19901/excite/modding/util/FileUtils.java b/src/main/java/com/gamebuster19901/excite/modding/util/FileUtils.java index 9216ad5..43b98e0 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/util/FileUtils.java +++ b/src/main/java/com/gamebuster19901/excite/modding/util/FileUtils.java @@ -8,15 +8,12 @@ import java.nio.ByteOrder; import java.nio.charset.Charset; import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; -import java.util.HashSet; import java.util.LinkedHashSet; -import java.util.List; public class FileUtils { From e06144c02f430fdcb0f8affce6c264396cbb220b Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Sat, 18 May 2024 22:09:01 -0400 Subject: [PATCH 13/19] rm unused field --- .../gamebuster19901/excite/modding/concurrent/BatchRunner.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java index 5c26b10..ae0b281 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java @@ -15,7 +15,6 @@ public class BatchRunner implements BatchWorker, BatcherContainer { private final String name; private final ExecutorService executor; private final LinkedHashSet> batches = new LinkedHashSet>(); - private volatile boolean started = false; private volatile boolean listenerAdded = false; public BatchRunner(String name) { @@ -58,7 +57,6 @@ public void startBatch() throws InterruptedException { throw new IllegalStateException("BatchRunner has already been started!"); } synchronized(batches) { - started = true; ArrayList> batchers = new ArrayList<>(getRunnables()); Collections.shuffle(batchers); //So multiple threads don't wait for a single archive to lazily load, allows multiple archives to lazily load at a time executor.invokeAll(batchers); From 21aadee837069d0d76de984deb336dbf4e8108f6 Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Sat, 18 May 2024 22:09:26 -0400 Subject: [PATCH 14/19] Fix extraction doing nothing if the destination directory contains no files --- .../gamebuster19901/excite/modding/ui/Window.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java index 9fc1ba8..2fca743 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java +++ b/src/main/java/com/gamebuster19901/excite/modding/ui/Window.java @@ -288,15 +288,14 @@ private void initialize() { return; } - new Thread(() -> { - try { - copyOperations.startBatch(); - } catch (InterruptedException e1) { - throw new RuntimeException(e1); - } - }).start(); - } + new Thread(() -> { + try { + copyOperations.startBatch(); + } catch (InterruptedException e1) { + throw new RuntimeException(e1); + } + }).start(); } From de42a0c50a49b4e6de003524f5969825f4799fae Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Sat, 18 May 2024 22:10:15 -0400 Subject: [PATCH 15/19] Extracted resources are now placed into a folder with their respective archives' names. --- .../gamebuster19901/excite/modding/unarchiver/Unarchiver.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java index d00df4c..36c1336 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java +++ b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java @@ -50,8 +50,9 @@ public Batch>> getCopyBatch(Path tocFile) { batch.addRunnable(() -> { try { String resourceName = resource.name(); + Path dest = destDir.resolve(tocFile.getFileName()).resolve(resourceName); System.out.println(tocFile.getFileName() + "/" + resourceName); - archive.getArchive().getFile(resourceName).writeTo(destDir.resolve(resourceName)); + archive.getArchive().getFile(resourceName).writeTo(dest); if(resource.name().endsWith("tex")) { return Pair.of(DecisionType.SKIP, () -> {return null;}); } From 8fcfb4332e4ae94ef402a56f0a2c53ff9936f566 Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Sat, 18 May 2024 22:46:18 -0400 Subject: [PATCH 16/19] Actually put resources in correct folder --- .../gamebuster19901/excite/modding/unarchiver/Unarchiver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java index 36c1336..3134341 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java +++ b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java @@ -50,7 +50,7 @@ public Batch>> getCopyBatch(Path tocFile) { batch.addRunnable(() -> { try { String resourceName = resource.name(); - Path dest = destDir.resolve(tocFile.getFileName()).resolve(resourceName); + Path dest = destDir.resolve(tocFile.getFileName()); System.out.println(tocFile.getFileName() + "/" + resourceName); archive.getArchive().getFile(resourceName).writeTo(dest); if(resource.name().endsWith("tex")) { From 7b9f7d712ece2c872dcd440adaf26164a24b9503 Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Tue, 21 May 2024 10:32:21 -0400 Subject: [PATCH 17/19] Fix deadlock --- .../gamebuster19901/excite/modding/concurrent/BatchRunner.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java index ae0b281..974240a 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/BatchRunner.java @@ -60,6 +60,7 @@ public void startBatch() throws InterruptedException { ArrayList> batchers = new ArrayList<>(getRunnables()); Collections.shuffle(batchers); //So multiple threads don't wait for a single archive to lazily load, allows multiple archives to lazily load at a time executor.invokeAll(batchers); + executor.close(); } } } From ba427d2ed51cbde78c89a6260e866046d8a3ad8c Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Tue, 21 May 2024 10:35:16 -0400 Subject: [PATCH 18/19] Add an AssetAnalyzer --- .../modding/debugging/AssetAnalyzer.java | 96 +++++++++++++++++++ .../modding/debugging/package-info.java | 1 + .../excite/modding/unarchiver/Unarchiver.java | 21 ++-- .../excite/modding/util/FileUtils.java | 5 + 4 files changed, 116 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/gamebuster19901/excite/modding/debugging/AssetAnalyzer.java create mode 100644 src/main/java/com/gamebuster19901/excite/modding/debugging/package-info.java diff --git a/src/main/java/com/gamebuster19901/excite/modding/debugging/AssetAnalyzer.java b/src/main/java/com/gamebuster19901/excite/modding/debugging/AssetAnalyzer.java new file mode 100644 index 0000000..ba4a730 --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/debugging/AssetAnalyzer.java @@ -0,0 +1,96 @@ +package com.gamebuster19901.excite.modding.debugging; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; + +import org.apache.commons.lang3.tuple.Pair; + +import com.gamebuster19901.excite.modding.concurrent.Batch; +import com.gamebuster19901.excite.modding.concurrent.BatchRunner; +import com.gamebuster19901.excite.modding.game.file.kaitai.TocMonster.Details; +import com.gamebuster19901.excite.modding.unarchiver.QuickAccessArchive; +import com.gamebuster19901.excite.modding.unarchiver.Toc; +import com.gamebuster19901.excite.modding.unarchiver.Unarchiver; +import com.thegamecommunity.excite.modding.game.file.AssetType; + +public class AssetAnalyzer { + + private static final Path current = Path.of("").toAbsolutePath(); + private static final Path run = current.resolve("run"); + private static final Path assets = current.resolve("gameData"); + + public static void main(String[] args) throws IOException, InterruptedException { + System.out.println(current); + System.out.println(run); + System.out.println(assets); + + Unarchiver unarchiver = new Unarchiver(assets, run); + Collection tocs = unarchiver.getTocs(); + BatchRunner>> runner = new BatchRunner<>("Analyzer"); + + for(Path tocFile : tocs) { + String tocName = tocFile.getFileName().toString(); + Batch>> batch = new Batch>>(tocName); + Toc toc = new Toc(tocFile); + List
details = toc.getFiles(); + + final QuickAccessArchive QArchive = unarchiver.getArchive(toc); + for(Details resource : details) { + String resourceName = resource.name(); + AssetType type = AssetType.getAssetType(resourceName); + if(type == AssetType.UNRECOGNIZED) { + throw new AssertionError("Unrecognized asset type: " + resourceName + " in " + tocName); + } + batch.addRunnable(() -> { + return Pair.of(type, Pair.of(resource.typeCode(), resource.typeCodeInt())); + }); + } + runner.addBatch(batch); + } + + runner.startBatch(); + Collection>> results = runner.getResults(); + HashMap> stringCodes = new HashMap>(); + HashMap> intCodes = new HashMap>(); + for(AssetType type : AssetType.values()) { + stringCodes.put(type, new HashSet<>()); + intCodes.put(type, new HashSet<>()); + } + for(Pair> pair : results) { + Pair pair2 = pair.getValue(); + stringCodes.get(pair.getKey()).add(pair2.getKey()); + intCodes.get(pair.getKey()).add(pair2.getValue()); + } + + for(AssetType assetType : AssetType.values()) { + HashSet strings = stringCodes.get(assetType); + HashSet ints = intCodes.get(assetType); + System.out.println("============" + assetType.toString().toUpperCase() + "============"); + System.out.println("Analysis of '" + assetType + "' type:"); + System.out.println("Total string typecodes: " + strings.size()); + System.out.println("Total int typecodes: " + ints.size()); + System.out.println("List of string typecodes below: \n"); + stringCodes.get(assetType).forEach((forCode) -> { + if(forCode.indexOf('\0') != -1) { + System.out.print('['); + for(char c : forCode.toCharArray()) { + System.out.print(Integer.toHexString((int)c) + " "); + } + System.out.println(']'); + } + else { + System.out.println(forCode); + } + }); + System.out.println("List of int typecodes below: \n"); + intCodes.get(assetType).forEach((forCode) -> { + System.out.println(forCode); + }); + } + } + +} diff --git a/src/main/java/com/gamebuster19901/excite/modding/debugging/package-info.java b/src/main/java/com/gamebuster19901/excite/modding/debugging/package-info.java new file mode 100644 index 0000000..0a8f913 --- /dev/null +++ b/src/main/java/com/gamebuster19901/excite/modding/debugging/package-info.java @@ -0,0 +1 @@ +package com.gamebuster19901.excite.modding.debugging; \ No newline at end of file diff --git a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java index 3134341..36565ee 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java +++ b/src/main/java/com/gamebuster19901/excite/modding/unarchiver/Unarchiver.java @@ -5,6 +5,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Collection; +import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.concurrent.Callable; @@ -31,6 +32,10 @@ public Unarchiver(Path sourceDir, Path destDir) throws IOException { refresh(); } + public Collection getTocs() { + return Collections.unmodifiableCollection(tocs); + } + public Collection>>> getCopyBatches() { LinkedHashSet>>> batches = new LinkedHashSet<>(); for(Path toc : tocs) { @@ -45,29 +50,31 @@ public Batch>> getCopyBatch(Path tocFile) { Toc toc = new Toc(tocFile.toAbsolutePath()); List
details = toc.getFiles(); - final QuickAccessArchive archive = getArchive(toc); + final QuickAccessArchive QArchive = getArchive(toc); for(Details resource : details) { batch.addRunnable(() -> { try { String resourceName = resource.name(); Path dest = destDir.resolve(tocFile.getFileName()); System.out.println(tocFile.getFileName() + "/" + resourceName); - archive.getArchive().getFile(resourceName).writeTo(dest); + Archive archive = QArchive.getArchive(); + ArchivedFile f = archive.getFile(resourceName); + f.writeTo(dest); if(resource.name().endsWith("tex")) { - return Pair.of(DecisionType.SKIP, () -> {return null;}); + return Pair.of(DecisionType.SKIP, () -> {return null;}); //the asset was successfully extracted, but we don't know how to process it } + return Pair.of(DecisionType.PROCEED, () -> {return null;}); //the asset was successfully extracted, and will be submitted to the next batchRunner to convert into a viewable format } catch(Throwable t) { - return Pair.of(DecisionType.IGNORE, () -> {throw t;}); + return Pair.of(DecisionType.IGNORE, () -> {throw t;}); //let the next batchrunner that an error ocurred, and will not be submitted to the next batchrunner. } - return Pair.of(DecisionType.PROCEED, () -> {return null;}); }); } } catch(Throwable t) { batch.addRunnable(() -> { - return Pair.of(DecisionType.IGNORE, () -> {throw t;}); //let the batchrunner know that an error occurred + return Pair.of(DecisionType.IGNORE, () -> {throw t;}); //let the next batchrunner know that an error occurred }); } return batch; @@ -77,7 +84,7 @@ public boolean isValid() { return FileUtils.isDirectory(sourceDir) && FileUtils.isDirectory(destDir); } - private QuickAccessArchive getArchive(Toc toc) throws IOException { + public QuickAccessArchive getArchive(Toc toc) throws IOException { for(Path archivePath : archives) { if(getFileName(toc.getFile()).equals(getFileName(archivePath))) { return new QuickAccessArchive(toc, archivePath); diff --git a/src/main/java/com/gamebuster19901/excite/modding/util/FileUtils.java b/src/main/java/com/gamebuster19901/excite/modding/util/FileUtils.java index 43b98e0..92154e6 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/util/FileUtils.java +++ b/src/main/java/com/gamebuster19901/excite/modding/util/FileUtils.java @@ -151,6 +151,11 @@ public static String getFileName(Path f) { int i = fileName.lastIndexOf('.'); return (i == -1) ? fileName : fileName.substring(0, i); } + + public static String getExtension(String fileName) { + int i = fileName.lastIndexOf('.'); + return i == -1 ? "" : fileName.substring(i + 1); + } public static boolean isDirectory(Path dir) { return Files.isDirectory(dir) && !Files.isSymbolicLink(dir); From a0079ad9354fb332c9819eaf2225416faa2cb1af Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Tue, 21 May 2024 13:03:10 -0400 Subject: [PATCH 19/19] spaces -> tabs --- .../excite/modding/concurrent/Batch.java | 328 +++++++++--------- 1 file changed, 164 insertions(+), 164 deletions(-) diff --git a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java index d456312..54a6f87 100644 --- a/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java +++ b/src/main/java/com/gamebuster19901/excite/modding/concurrent/Batch.java @@ -12,65 +12,65 @@ public class Batch implements Batcher { private final String name; - private final Set> runnables = new HashSet<>(); - private final LinkedHashSet listeners = new LinkedHashSet<>(); - private volatile boolean accepting = true; - - public Batch(String name) { - this.name = name; - } - - @Override - public String getName() { - return name; - } - - public void addRunnable(BatchedCallable batchedCallable) { - if(accepting) { - runnables.add(batchedCallable); - updateListeners(); - } - else { - notAccepting(); - } - } - - @Override - public void addRunnable(Callable runnable) { - if(accepting) { - BatchedCallable b = new BatchedCallable<>(this, runnable); - runnables.add(new BatchedCallable<>(this, runnable)); - updateListeners(); - } - else { - notAccepting(); - } - } + private final Set> runnables = new HashSet<>(); + private final LinkedHashSet listeners = new LinkedHashSet<>(); + private volatile boolean accepting = true; + + public Batch(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + + public void addRunnable(BatchedCallable batchedCallable) { + if(accepting) { + runnables.add(batchedCallable); + updateListeners(); + } + else { + notAccepting(); + } + } + + @Override + public void addRunnable(Callable runnable) { + if(accepting) { + BatchedCallable b = new BatchedCallable<>(this, runnable); + runnables.add(new BatchedCallable<>(this, runnable)); + updateListeners(); + } + else { + notAccepting(); + } + } - @Override - public void addRunnable(Runnable runnable) { - if(accepting) { - BatchedCallable b = new BatchedCallable<>(this, runnable); - runnables.add(new BatchedCallable<>(this, runnable)); - updateListeners(); - } - else { - notAccepting(); - } - } - - @Override - public void addBatchListener(BatchListener listener) { - if(accepting) { - if(!listeners.add(listener)) { - System.out.println("Warning: duplicate batch listener ignored."); - } - } - else { - notAccepting(); - } - } - + @Override + public void addRunnable(Runnable runnable) { + if(accepting) { + BatchedCallable b = new BatchedCallable<>(this, runnable); + runnables.add(new BatchedCallable<>(this, runnable)); + updateListeners(); + } + else { + notAccepting(); + } + } + + @Override + public void addBatchListener(BatchListener listener) { + if(accepting) { + if(!listeners.add(listener)) { + System.out.println("Warning: duplicate batch listener ignored."); + } + } + else { + notAccepting(); + } + } + @Override public Collection> getRunnables() { return Set.copyOf(runnables); @@ -82,90 +82,90 @@ public Collection getListeners() { return (Collection) listeners.clone(); } - public void shutdownNow() throws InterruptedException { - accepting = false; - Shutdown shutdown = new Shutdown(); - for(BatchedCallable r : runnables) { - if(r.getState() == State.NEW) { - r.shutdown(shutdown); - } - } - System.err.println(runnables.size()); - } - - public void updateListeners() { - for(BatchListener listener : listeners) { - listener.update(); - } - } - - private void notAccepting() { - throw new IllegalStateException("Batch is not accepting new tasks or listeners."); - } - - /** - * A wrapper class for a {@link Callable} object that participates in a batch execution managed by a {@link Batcher}. - * - * This class allows for the creation of callables that can be tracked and managed by a batching system. It provides methods - * to get the execution state, retrieve the result after completion, and handle exceptions. - * - * @param the type of the result produced by the wrapped {@link Callable} - */ - public static class BatchedCallable implements Callable { - - private final Batcher batch; - private final Callable child; - private volatile WeakReference threadRef; - protected volatile Throwable thrown; - private final Object startLock = new Object(); - private volatile Boolean started = false; - protected volatile boolean finished = false; - protected volatile T result; - - - /** - * Creates a new BatchedCallable instance for a provided {@link Runnable} object. - *

- * This convenience constructor takes a Runnable and converts it to a Callable that simply calls the {@link Runnable#run} method - * and returns null. It then delegates to the main constructor with the converted callable. - * - * @param batch the {@link Batcher} instance managing this callable - * @param r the {@link Runnable} object to be wrapped - */ - public BatchedCallable(Batcher batch, Runnable r) { - this(batch, () -> { - r.run(); - return null; - }); - } - - /** - * Creates a new BatchedCallable instance for the provided {@link Callable} object. - *

- * This constructor wraps a given Callable and associates it with the specified Batcher. The Batcher is - * notified of updates to the state of this callable. - * - * @param batch the {@link Batcher} instance managing this callable - * @param c the {@link Callable} object to be wrapped - */ - public BatchedCallable(Batcher batch, Callable c) { - this.batch = batch; - this.child = c; - batch.updateListeners(); - } - - /** - * Implements the `call` method of the {@link Callable} interface. - *

- * This method executes the wrapped `Callable` object and stores the result. It also updates the state of this object - * and notifies the associated Batcher before and after execution. If any exceptions occur during execution, they are - * stored but not re-thrown by this method. The caller of this method is responsible for handling any exceptions. - * - * The behavior of this callable is undefined if call() is executed more than once. + public void shutdownNow() throws InterruptedException { + accepting = false; + Shutdown shutdown = new Shutdown(); + for(BatchedCallable r : runnables) { + if(r.getState() == State.NEW) { + r.shutdown(shutdown); + } + } + System.err.println(runnables.size()); + } + + public void updateListeners() { + for(BatchListener listener : listeners) { + listener.update(); + } + } + + private void notAccepting() { + throw new IllegalStateException("Batch is not accepting new tasks or listeners."); + } + + /** + * A wrapper class for a {@link Callable} object that participates in a batch execution managed by a {@link Batcher}. + * + * This class allows for the creation of callables that can be tracked and managed by a batching system. It provides methods + * to get the execution state, retrieve the result after completion, and handle exceptions. + * + * @param the type of the result produced by the wrapped {@link Callable} + */ + public static class BatchedCallable implements Callable { + + private final Batcher batch; + private final Callable child; + private volatile WeakReference threadRef; + protected volatile Throwable thrown; + private final Object startLock = new Object(); + private volatile Boolean started = false; + protected volatile boolean finished = false; + protected volatile T result; + + + /** + * Creates a new BatchedCallable instance for a provided {@link Runnable} object. + *

+ * This convenience constructor takes a Runnable and converts it to a Callable that simply calls the {@link Runnable#run} method + * and returns null. It then delegates to the main constructor with the converted callable. * - * @return the result of the wrapped callable's execution (which may be null), or null if an exception occurred - */ - @Override + * @param batch the {@link Batcher} instance managing this callable + * @param r the {@link Runnable} object to be wrapped + */ + public BatchedCallable(Batcher batch, Runnable r) { + this(batch, () -> { + r.run(); + return null; + }); + } + + /** + * Creates a new BatchedCallable instance for the provided {@link Callable} object. + *

+ * This constructor wraps a given Callable and associates it with the specified Batcher. The Batcher is + * notified of updates to the state of this callable. + * + * @param batch the {@link Batcher} instance managing this callable + * @param c the {@link Callable} object to be wrapped + */ + public BatchedCallable(Batcher batch, Callable c) { + this.batch = batch; + this.child = c; + batch.updateListeners(); + } + + /** + * Implements the `call` method of the {@link Callable} interface. + *

+ * This method executes the wrapped `Callable` object and stores the result. It also updates the state of this object + * and notifies the associated Batcher before and after execution. If any exceptions occur during execution, they are + * stored but not re-thrown by this method. The caller of this method is responsible for handling any exceptions. + * + * The behavior of this callable is undefined if call() is executed more than once. + * + * @return the result of the wrapped callable's execution (which may be null), or null if an exception occurred + */ + @Override public T call() { Thread thread; try { @@ -185,20 +185,20 @@ public T call() { return null; } - /** - * Gets the current execution state of the wrapped callable. - * - * This method examines the internal state and thread reference to determine the current execution state. It can return one of the following states: - * - *

    - *
  • NEW: The callable has not yet been submitted for execution. - *
  • TERMINATED: The callable has finished execution, either successfully or with an exception. - *
  • The actual state of the thread running the callable (e.g., `RUNNING`, `WAITING`): - *

    If a thread is currently executing the callable, this state reflects the thread's lifecycle. - *

- * - * @return the current state of the callable execution, as described above - */ + /** + * Gets the current execution state of the wrapped callable. + * + * This method examines the internal state and thread reference to determine the current execution state. It can return one of the following states: + * + *
    + *
  • NEW: The callable has not yet been submitted for execution. + *
  • TERMINATED: The callable has finished execution, either successfully or with an exception. + *
  • The actual state of the thread running the callable (e.g., `RUNNING`, `WAITING`): + *

    If a thread is currently executing the callable, this state reflects the thread's lifecycle. + *

+ * + * @return the current state of the callable execution, as described above + */ public State getState() { if(finished) { //the thread is no longer working on this runnable return State.TERMINATED; @@ -226,14 +226,14 @@ public T getResult() { return result; } - /** - * Gets the exception thrown by the wrapped callable, if any. - *

- * This method returns the exception that was thrown during the execution of the wrapped callable, or null if no exception - * occurred. - * - * @return the exception thrown by the wrapped callable, or null if no exception occurred - */ + /** + * Gets the exception thrown by the wrapped callable, if any. + *

+ * This method returns the exception that was thrown during the execution of the wrapped callable, or null if no exception + * occurred. + * + * @return the exception thrown by the wrapped callable, or null if no exception occurred + */ public Throwable getThrown() { return thrown; } @@ -247,6 +247,6 @@ protected void shutdown(Shutdown shutdown) { finished = true; thrown = shutdown; } - } + } }