Upgrade version, add improved export flow.
This commit is contained in:
parent
e5e3c08c6e
commit
e2ebb3085f
2
pom.xml
2
pom.xml
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
<groupId>nl.andrewlalis</groupId>
|
<groupId>nl.andrewlalis</groupId>
|
||||||
<artifactId>BlockBookBinder</artifactId>
|
<artifactId>BlockBookBinder</artifactId>
|
||||||
<version>0.0.2</version>
|
<version>1.0.0</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>12</maven.compiler.source>
|
<maven.compiler.source>12</maven.compiler.source>
|
||||||
|
|
|
@ -2,6 +2,7 @@ package nl.andrewlalis.blockbookbinder.control;
|
||||||
|
|
||||||
import nl.andrewlalis.blockbookbinder.model.Book;
|
import nl.andrewlalis.blockbookbinder.model.Book;
|
||||||
import nl.andrewlalis.blockbookbinder.view.BookPreviewPanel;
|
import nl.andrewlalis.blockbookbinder.view.BookPreviewPanel;
|
||||||
|
import nl.andrewlalis.blockbookbinder.view.export.ExportToBookDialog;
|
||||||
import org.jnativehook.GlobalScreen;
|
import org.jnativehook.GlobalScreen;
|
||||||
import org.jnativehook.NativeHookException;
|
import org.jnativehook.NativeHookException;
|
||||||
|
|
||||||
|
@ -34,7 +35,7 @@ public class BookExportActionListener implements ActionListener {
|
||||||
final Book book = this.bookPreviewPanel.getBook();
|
final Book book = this.bookPreviewPanel.getBook();
|
||||||
int choice = JOptionPane.showConfirmDialog(
|
int choice = JOptionPane.showConfirmDialog(
|
||||||
this.bookPreviewPanel.getRootPane(),
|
this.bookPreviewPanel.getRootPane(),
|
||||||
"Press CTRL+V to initialize export.",
|
"Press OK to initialize export.",
|
||||||
"Confirm Export",
|
"Confirm Export",
|
||||||
JOptionPane.OK_CANCEL_OPTION
|
JOptionPane.OK_CANCEL_OPTION
|
||||||
);
|
);
|
||||||
|
|
|
@ -8,9 +8,12 @@ import org.jnativehook.keyboard.NativeKeyEvent;
|
||||||
import org.jnativehook.keyboard.NativeKeyListener;
|
import org.jnativehook.keyboard.NativeKeyListener;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
import java.awt.datatransfer.Clipboard;
|
import java.awt.datatransfer.Clipboard;
|
||||||
import java.awt.datatransfer.StringSelection;
|
import java.awt.datatransfer.StringSelection;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener that listens for native key-presses that indicate the user has
|
* Listener that listens for native key-presses that indicate the user has
|
||||||
|
@ -22,6 +25,7 @@ public class BookPagePasteListener implements NativeKeyListener {
|
||||||
private final BookPreviewPanel bookPreviewPanel;
|
private final BookPreviewPanel bookPreviewPanel;
|
||||||
private final JButton cancelExportButton;
|
private final JButton cancelExportButton;
|
||||||
private final ActionListener cancelExportActionListener;
|
private final ActionListener cancelExportActionListener;
|
||||||
|
private Robot robot;
|
||||||
private int nextPage;
|
private int nextPage;
|
||||||
|
|
||||||
public BookPagePasteListener(Book book, Clipboard clipboard, BookPreviewPanel bookPreviewPanel, JButton cancelExportButton) {
|
public BookPagePasteListener(Book book, Clipboard clipboard, BookPreviewPanel bookPreviewPanel, JButton cancelExportButton) {
|
||||||
|
@ -32,6 +36,11 @@ public class BookPagePasteListener implements NativeKeyListener {
|
||||||
this.nextPage = 0;
|
this.nextPage = 0;
|
||||||
this.cancelExportActionListener = (e) -> this.cancelExport();
|
this.cancelExportActionListener = (e) -> this.cancelExport();
|
||||||
this.cancelExportButton.addActionListener(this.cancelExportActionListener);
|
this.cancelExportButton.addActionListener(this.cancelExportActionListener);
|
||||||
|
try {
|
||||||
|
this.robot = new Robot();
|
||||||
|
} catch (AWTException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void exportNextPage() {
|
public void exportNextPage() {
|
||||||
|
@ -68,7 +77,22 @@ public class BookPagePasteListener implements NativeKeyListener {
|
||||||
// If we've reached the end of the book, unregister this listener and remove native hooks.
|
// If we've reached the end of the book, unregister this listener and remove native hooks.
|
||||||
if (this.nextPage >= this.book.getPageCount()) {
|
if (this.nextPage >= this.book.getPageCount()) {
|
||||||
this.cancelExport();
|
this.cancelExport();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Automatically do a CTRL+V and click the mouse to go to the next page.
|
||||||
|
this.robot.keyPress(KeyEvent.VK_CONTROL);
|
||||||
|
this.robot.keyPress(KeyEvent.VK_V);
|
||||||
|
try {
|
||||||
|
Thread.sleep(50);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
this.robot.keyRelease(KeyEvent.VK_V);
|
||||||
|
this.robot.keyRelease(KeyEvent.VK_CONTROL);
|
||||||
|
|
||||||
|
this.robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK);
|
||||||
|
this.robot.mouseRelease(MouseEvent.BUTTON1_DOWN_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cancelExport() {
|
public void cancelExport() {
|
||||||
|
|
|
@ -0,0 +1,214 @@
|
||||||
|
package nl.andrewlalis.blockbookbinder.control.export;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
|
import nl.andrewlalis.blockbookbinder.model.Book;
|
||||||
|
import nl.andrewlalis.blockbookbinder.util.ApplicationProperties;
|
||||||
|
import org.jnativehook.GlobalScreen;
|
||||||
|
import org.jnativehook.NativeHookException;
|
||||||
|
|
||||||
|
import javax.sound.sampled.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.datatransfer.Clipboard;
|
||||||
|
import java.awt.datatransfer.StringSelection;
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A separate runnable process which handles exporting a book, page by page,
|
||||||
|
* into one's clipboard and pasting the pages.
|
||||||
|
*/
|
||||||
|
public class BookExporter implements Runnable {
|
||||||
|
private final static int START_DELAY = 10;
|
||||||
|
private final static int CLIPBOARD_RETRY_DELAY_MS = 100;
|
||||||
|
private final static int ROBOT_ACTION_DELAY_MS = 100;
|
||||||
|
|
||||||
|
private final Book book;
|
||||||
|
private final boolean autoPaste;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private volatile boolean running;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private volatile boolean nextPageRequested;
|
||||||
|
|
||||||
|
private final PagePasteListener pagePasteListener;
|
||||||
|
private final Clipboard clipboard;
|
||||||
|
private Robot robot;
|
||||||
|
|
||||||
|
// Some sound clips to play as user feedback.
|
||||||
|
private final Clip beepClip;
|
||||||
|
private final Clip beginningExportClip;
|
||||||
|
|
||||||
|
public BookExporter(Book book, boolean autoPaste) {
|
||||||
|
this.book = book;
|
||||||
|
this.autoPaste = autoPaste;
|
||||||
|
this.beepClip = this.loadAudioClip(ApplicationProperties.getProp("export_dialog.beep_sound"));
|
||||||
|
this.beginningExportClip = this.loadAudioClip(ApplicationProperties.getProp("export_dialog.beginning_export"));
|
||||||
|
this.clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
|
||||||
|
this.pagePasteListener = new PagePasteListener(this);
|
||||||
|
if (this.autoPaste) { // Only initialize the robot if we'll need it.
|
||||||
|
try {
|
||||||
|
this.robot = new Robot();
|
||||||
|
} catch (AWTException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
this.running = true;
|
||||||
|
this.nextPageRequested = true;
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
long lastAudioPlayedAt = 0;
|
||||||
|
long lastPageExportedAt = 0;
|
||||||
|
int nextPageToExport = 0;
|
||||||
|
while (this.running) {
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
// Check if we're still in the first few seconds of runtime.
|
||||||
|
boolean inStartPhase = (currentTime - startTime < (START_DELAY * 1000));
|
||||||
|
if (inStartPhase && currentTime - lastAudioPlayedAt > 1000) {
|
||||||
|
this.playAudioClip(this.beepClip);
|
||||||
|
lastAudioPlayedAt = currentTime;
|
||||||
|
}
|
||||||
|
// Otherwise, export one page.
|
||||||
|
if (!inStartPhase && this.nextPageRequested) {
|
||||||
|
System.out.println("Page requested: " + nextPageToExport);
|
||||||
|
this.nextPageRequested = false; // Reset the flag so that some other process has to set it before the next page is exported.
|
||||||
|
// If this is the first time we're exporting, play a sound.
|
||||||
|
if (lastPageExportedAt == 0) {
|
||||||
|
this.initNativeListener();
|
||||||
|
this.playAudioClip(this.beginningExportClip);
|
||||||
|
}
|
||||||
|
this.exportPageToClipboard(nextPageToExport);
|
||||||
|
if (this.autoPaste) {
|
||||||
|
this.pasteAndTurnPage();
|
||||||
|
}
|
||||||
|
this.playAudioClip(this.beepClip);
|
||||||
|
nextPageToExport++;
|
||||||
|
// If we've reached the end of the book, stop the exporter.
|
||||||
|
if (nextPageToExport >= this.book.getPageCount()) {
|
||||||
|
System.out.println("Export finished: " + this.book.getPageCount() + " pages exported.");
|
||||||
|
if (!this.autoPaste) {
|
||||||
|
this.stopNativeListener();
|
||||||
|
}
|
||||||
|
this.running = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Since there may be significant delay, get a fresh timestamp.
|
||||||
|
lastPageExportedAt = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the given page onto the system clipboard so either a user or this
|
||||||
|
* program can paste it into a minecraft book.
|
||||||
|
* @param page The index of the page to export.
|
||||||
|
*/
|
||||||
|
private void exportPageToClipboard(int page) {
|
||||||
|
boolean clipboardSuccess = false;
|
||||||
|
int attempts = 0;
|
||||||
|
while (!clipboardSuccess) {
|
||||||
|
try {
|
||||||
|
attempts++;
|
||||||
|
clipboard.setContents(new StringSelection(book.getPages().get(page).toString()), null);
|
||||||
|
clipboardSuccess = true;
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
System.err.println("Could not open and set contents of system clipboard.");
|
||||||
|
}
|
||||||
|
if (!clipboardSuccess) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(CLIPBOARD_RETRY_DELAY_MS);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (attempts > 10) {
|
||||||
|
throw new RuntimeException("Could not insert page into clipboard after " + attempts + " attempts.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("Exported page " + page + " to clipboard.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically pastes and turns the page of the minecraft book, so that
|
||||||
|
* the next page can be pasted in.
|
||||||
|
*/
|
||||||
|
private void pasteAndTurnPage() {
|
||||||
|
this.robot.keyPress(KeyEvent.VK_CONTROL);
|
||||||
|
this.robot.keyPress(KeyEvent.VK_V);
|
||||||
|
try {
|
||||||
|
Thread.sleep(ROBOT_ACTION_DELAY_MS);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
this.robot.keyRelease(KeyEvent.VK_V);
|
||||||
|
this.robot.keyRelease(KeyEvent.VK_CONTROL);
|
||||||
|
System.out.println("Pasted.");
|
||||||
|
this.robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK);
|
||||||
|
try {
|
||||||
|
Thread.sleep(ROBOT_ACTION_DELAY_MS);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
this.robot.mouseRelease(MouseEvent.BUTTON1_DOWN_MASK);
|
||||||
|
try { // Wait for minecraft to turn the page.
|
||||||
|
Thread.sleep(ROBOT_ACTION_DELAY_MS);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
System.out.println("Clicked mouse.");
|
||||||
|
this.nextPageRequested = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initNativeListener() {
|
||||||
|
try {
|
||||||
|
// For catching native events, set logging here.
|
||||||
|
Logger logger = Logger.getLogger(GlobalScreen.class.getPackage().getName());
|
||||||
|
logger.setLevel(Level.WARNING);
|
||||||
|
logger.setUseParentHandlers(false);
|
||||||
|
GlobalScreen.registerNativeHook();
|
||||||
|
GlobalScreen.addNativeKeyListener(this.pagePasteListener);
|
||||||
|
} catch (NativeHookException nativeHookException) {
|
||||||
|
System.err.println("Could not register native hook.");
|
||||||
|
nativeHookException.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopNativeListener() {
|
||||||
|
try {
|
||||||
|
GlobalScreen.removeNativeKeyListener(this.pagePasteListener);
|
||||||
|
GlobalScreen.unregisterNativeHook();
|
||||||
|
} catch (NativeHookException nativeHookException) {
|
||||||
|
System.err.println("Could not unregister a native hook.");
|
||||||
|
nativeHookException.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void playAudioClip(Clip clip) {
|
||||||
|
clip.setFramePosition(0);
|
||||||
|
clip.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Clip loadAudioClip(String path) {
|
||||||
|
try {
|
||||||
|
Clip clip = AudioSystem.getClip();
|
||||||
|
InputStream fileInputStream = this.getClass().getClassLoader().getResourceAsStream(path);
|
||||||
|
if (fileInputStream == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
AudioInputStream ais = AudioSystem.getAudioInputStream(fileInputStream);
|
||||||
|
clip.open(ais);
|
||||||
|
return clip;
|
||||||
|
} catch (LineUnavailableException | IOException | UnsupportedAudioFileException e) {
|
||||||
|
System.err.println("Could not load audio clip.");
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package nl.andrewlalis.blockbookbinder.control.export;
|
||||||
|
|
||||||
|
import org.jnativehook.keyboard.NativeKeyEvent;
|
||||||
|
import org.jnativehook.keyboard.NativeKeyListener;
|
||||||
|
|
||||||
|
public class PagePasteListener implements NativeKeyListener {
|
||||||
|
private BookExporter exporterRunnable;
|
||||||
|
|
||||||
|
public PagePasteListener(BookExporter exporterRunnable) {
|
||||||
|
this.exporterRunnable = exporterRunnable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nativeKeyTyped(NativeKeyEvent nativeKeyEvent) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nativeKeyPressed(NativeKeyEvent nativeKeyEvent) {
|
||||||
|
if (nativeKeyEvent.getKeyCode() == NativeKeyEvent.VC_V && (nativeKeyEvent.getModifiers() & NativeKeyEvent.CTRL_MASK) > 0) {
|
||||||
|
// Wait a little bit so that we can let the system do whatever it was planning to do with the original paste action.
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
this.exporterRunnable.setNextPageRequested(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nativeKeyReleased(NativeKeyEvent nativeKeyEvent) {}
|
||||||
|
}
|
|
@ -21,6 +21,20 @@ public class Book {
|
||||||
this.pages.add(page);
|
this.pages.add(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a book containing the pages specified by the range.
|
||||||
|
* @param firstIndex The index of the first page to include.
|
||||||
|
* @param count The number of pages to include.
|
||||||
|
* @return The book containing the range of pages.
|
||||||
|
*/
|
||||||
|
public Book getPageRange(int firstIndex, int count) {
|
||||||
|
Book book = new Book();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
book.addPage(this.pages.get(firstIndex + i));
|
||||||
|
}
|
||||||
|
return book;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder("Book of " + this.getPageCount() + " pages:\n");
|
StringBuilder sb = new StringBuilder("Book of " + this.getPageCount() + " pages:\n");
|
||||||
|
|
|
@ -2,7 +2,9 @@ package nl.andrewlalis.blockbookbinder.view;
|
||||||
|
|
||||||
import nl.andrewlalis.blockbookbinder.control.BookExportActionListener;
|
import nl.andrewlalis.blockbookbinder.control.BookExportActionListener;
|
||||||
import nl.andrewlalis.blockbookbinder.control.ImportAction;
|
import nl.andrewlalis.blockbookbinder.control.ImportAction;
|
||||||
|
import nl.andrewlalis.blockbookbinder.model.Book;
|
||||||
import nl.andrewlalis.blockbookbinder.util.ApplicationProperties;
|
import nl.andrewlalis.blockbookbinder.util.ApplicationProperties;
|
||||||
|
import nl.andrewlalis.blockbookbinder.view.export.ExportToBookDialog;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
@ -67,7 +69,15 @@ public class MainFrame extends JFrame {
|
||||||
JButton exportButton = new JButton("Export to Book");
|
JButton exportButton = new JButton("Export to Book");
|
||||||
JButton cancelExportButton = new JButton("Cancel Export");
|
JButton cancelExportButton = new JButton("Cancel Export");
|
||||||
cancelExportButton.setEnabled(false);
|
cancelExportButton.setEnabled(false);
|
||||||
exportButton.addActionListener(new BookExportActionListener(bookPreviewPanel, cancelExportButton));
|
exportButton.addActionListener(e -> {
|
||||||
|
final Book book = bookPreviewPanel.getBook();
|
||||||
|
if (book == null || book.getPageCount() == 0) {
|
||||||
|
JOptionPane.showMessageDialog(this, "Cannot export an empty book.", "Empty Book", JOptionPane.WARNING_MESSAGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ExportToBookDialog dialog = new ExportToBookDialog(this, bookPreviewPanel.getBook());
|
||||||
|
dialog.setupAndShow();
|
||||||
|
});
|
||||||
bottomPanel.add(exportButton);
|
bottomPanel.add(exportButton);
|
||||||
bottomPanel.add(cancelExportButton);
|
bottomPanel.add(cancelExportButton);
|
||||||
mainPanel.add(bottomPanel, BorderLayout.SOUTH);
|
mainPanel.add(bottomPanel, BorderLayout.SOUTH);
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package nl.andrewlalis.blockbookbinder.view.export;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A panel with some components for displaying the current status of an export
|
||||||
|
* job.
|
||||||
|
*/
|
||||||
|
public class ExportStatusPanel extends JPanel {
|
||||||
|
private JProgressBar exportProgressBar;
|
||||||
|
|
||||||
|
public ExportStatusPanel() {
|
||||||
|
this.setLayout(new BorderLayout());
|
||||||
|
|
||||||
|
this.exportProgressBar = new JProgressBar();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
package nl.andrewlalis.blockbookbinder.view.export;
|
||||||
|
|
||||||
|
import nl.andrewlalis.blockbookbinder.control.export.BookExporter;
|
||||||
|
import nl.andrewlalis.blockbookbinder.model.Book;
|
||||||
|
import nl.andrewlalis.blockbookbinder.util.ApplicationProperties;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A special dialog box that's shown during the process of exporting a book into
|
||||||
|
* minecraft.
|
||||||
|
*/
|
||||||
|
public class ExportToBookDialog extends JDialog {
|
||||||
|
private final static String SETUP_CARD = "SETUP";
|
||||||
|
private final static String STATUS_CARD = "STATUS";
|
||||||
|
|
||||||
|
private final Book book;
|
||||||
|
|
||||||
|
// Setup input fields.
|
||||||
|
private JCheckBox autoCheckbox;
|
||||||
|
private JSpinner firstPageSpinner;
|
||||||
|
private JSpinner lastPageSpinner;
|
||||||
|
|
||||||
|
private JButton startButton;
|
||||||
|
private JButton stopButton;
|
||||||
|
private JPanel centerCardPanel;
|
||||||
|
private ExportStatusPanel exportStatusPanel;
|
||||||
|
|
||||||
|
private Thread exporterThread;
|
||||||
|
private BookExporter exporterRunnable;
|
||||||
|
|
||||||
|
public ExportToBookDialog(Frame owner, Book book) {
|
||||||
|
super(owner, "Export to Book", true);
|
||||||
|
this.book = book;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setupAndShow() {
|
||||||
|
this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
||||||
|
this.setContentPane(this.buildContentPane());
|
||||||
|
this.setMinimumSize(new Dimension(
|
||||||
|
ApplicationProperties.getIntProp("export_dialog.min_width"),
|
||||||
|
ApplicationProperties.getIntProp("export_dialog.min_height")
|
||||||
|
));
|
||||||
|
this.pack();
|
||||||
|
this.setLocationRelativeTo(null);
|
||||||
|
this.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Container buildContentPane() {
|
||||||
|
JPanel mainPanel = new JPanel(new BorderLayout());
|
||||||
|
|
||||||
|
JPanel setupPanel = new JPanel();
|
||||||
|
setupPanel.setLayout(new BoxLayout(setupPanel, BoxLayout.PAGE_AXIS));
|
||||||
|
this.autoCheckbox = new JCheckBox("Auto-paste", true);
|
||||||
|
this.firstPageSpinner = new JSpinner(new SpinnerNumberModel(1, 1, this.book.getPageCount(), 1));
|
||||||
|
this.lastPageSpinner = new JSpinner(new SpinnerNumberModel(this.book.getPageCount(), 1, this.book.getPageCount(), 1));
|
||||||
|
setupPanel.add(this.autoCheckbox);
|
||||||
|
setupPanel.add(this.firstPageSpinner);
|
||||||
|
setupPanel.add(this.lastPageSpinner);
|
||||||
|
|
||||||
|
this.exportStatusPanel = new ExportStatusPanel();
|
||||||
|
|
||||||
|
this.centerCardPanel = new JPanel(new CardLayout());
|
||||||
|
centerCardPanel.add(setupPanel, SETUP_CARD);
|
||||||
|
centerCardPanel.add(this.exportStatusPanel, STATUS_CARD);
|
||||||
|
this.showCardByName(SETUP_CARD);
|
||||||
|
|
||||||
|
mainPanel.add(centerCardPanel, BorderLayout.CENTER);
|
||||||
|
|
||||||
|
JPanel controlPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
|
||||||
|
this.startButton = new JButton("Start");
|
||||||
|
this.startButton.addActionListener(e -> {
|
||||||
|
int choice = JOptionPane.showConfirmDialog(
|
||||||
|
this.rootPane,
|
||||||
|
"Exporting will begin after roughly 10 seconds.\n" +
|
||||||
|
"If you have selected \"Auto-paste\", then place\n" +
|
||||||
|
"your mouse cursor over the right arrow of the book\n" +
|
||||||
|
"so that BlockBookBinder can automatically click it.\n\n" +
|
||||||
|
"You have chosen to export pages " + this.firstPageSpinner.getValue() + " to " + this.lastPageSpinner.getValue() + ".",
|
||||||
|
"Export Start Confirmation",
|
||||||
|
JOptionPane.OK_CANCEL_OPTION,
|
||||||
|
JOptionPane.INFORMATION_MESSAGE
|
||||||
|
);
|
||||||
|
if (choice == JOptionPane.OK_OPTION) {
|
||||||
|
this.startExporter();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
controlPanel.add(this.startButton);
|
||||||
|
this.stopButton = new JButton("Stop");
|
||||||
|
this.stopButton.setVisible(false);
|
||||||
|
this.stopButton.setEnabled(false);
|
||||||
|
this.stopButton.addActionListener(e -> this.stopExporter());
|
||||||
|
controlPanel.add(this.stopButton);
|
||||||
|
mainPanel.add(controlPanel, BorderLayout.SOUTH);
|
||||||
|
|
||||||
|
return mainPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startExporter() {
|
||||||
|
final int firstPage = (int) this.firstPageSpinner.getValue();
|
||||||
|
final int lastPage = (int) this.lastPageSpinner.getValue();
|
||||||
|
final Book pagesRange = this.book.getPageRange(firstPage - 1, lastPage - firstPage + 1);
|
||||||
|
|
||||||
|
this.startButton.setEnabled(false);
|
||||||
|
this.startButton.setVisible(false);
|
||||||
|
this.stopButton.setEnabled(true);
|
||||||
|
this.stopButton.setVisible(true);
|
||||||
|
this.showCardByName(STATUS_CARD);
|
||||||
|
this.exporterRunnable = new BookExporter(pagesRange, this.autoCheckbox.isSelected());
|
||||||
|
this.exporterThread = new Thread(this.exporterRunnable);
|
||||||
|
this.exporterThread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopExporter() {
|
||||||
|
this.exporterRunnable.setRunning(false);
|
||||||
|
try {
|
||||||
|
this.exporterThread.join();
|
||||||
|
} catch (InterruptedException interruptedException) {
|
||||||
|
interruptedException.printStackTrace();
|
||||||
|
}
|
||||||
|
this.showCardByName(SETUP_CARD);
|
||||||
|
this.stopButton.setEnabled(false);
|
||||||
|
this.stopButton.setVisible(false);
|
||||||
|
this.startButton.setEnabled(true);
|
||||||
|
this.startButton.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showCardByName(String name) {
|
||||||
|
CardLayout cl = (CardLayout) this.centerCardPanel.getLayout();
|
||||||
|
cl.show(this.centerCardPanel, name);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,11 @@ frame.title=Block Book Binder
|
||||||
frame.default_width=800
|
frame.default_width=800
|
||||||
frame.default_height=600
|
frame.default_height=600
|
||||||
|
|
||||||
|
export_dialog.min_width=400
|
||||||
|
export_dialog.min_height=300
|
||||||
|
export_dialog.beep_sound=sound/andrew_beep.wav
|
||||||
|
export_dialog.beginning_export=sound/beginning_export.wav
|
||||||
|
|
||||||
# Settings for Minecraft book interaction.
|
# Settings for Minecraft book interaction.
|
||||||
book.max_pages=100
|
book.max_pages=100
|
||||||
book.page_max_lines=14
|
book.page_max_lines=14
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue