Cleaned up temporary classes during work.

This commit is contained in:
Andrew Lalis 2023-07-09 20:30:25 -04:00
parent 2a9edf125e
commit 9ae48ec944
7 changed files with 116 additions and 263 deletions

View File

@ -27,7 +27,7 @@ public class ExportBookToMinecraftAction extends AbstractAction {
if (book == null || book.getPageCount() == 0) {
JOptionPane.showMessageDialog(
this.bookPreviewPanel.getRootPane(),
"Cannot export an empty book.",
"Cannot export an empty book.\nChoose \"Compile to Source\" first, and then export.",
"Empty Book",
JOptionPane.WARNING_MESSAGE
);

View File

@ -5,7 +5,7 @@ import org.jnativehook.keyboard.NativeKeyListener;
/**
* Native key listener that's used during the export process, to detect when the
* user performs certain key actions outside of the focus of this program.
* user performs certain key actions outside the focus of this program.
*/
public class ExporterKeyListener implements NativeKeyListener {
private final BookExporter exporterRunnable;

View File

@ -3,6 +3,7 @@ package nl.andrewlalis.blockbookbinder.control.source;
import lombok.Getter;
import lombok.Setter;
import nl.andrewlalis.blockbookbinder.model.build.BookBuilder;
import nl.andrewlalis.blockbookbinder.util.ApplicationProperties;
import nl.andrewlalis.blockbookbinder.view.SourceTextPanel;
import nl.andrewlalis.blockbookbinder.view.book.BookPreviewPanel;
@ -26,7 +27,11 @@ public class CompileFromSourceAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent e) {
this.bookPreviewPanel.setBook(
new BookBuilder().build(this.sourceTextPanel.getSourceText())
new BookBuilder(
ApplicationProperties.getIntProp("book.page_max_lines"),
ApplicationProperties.getIntProp("book.page_max_chars"),
ApplicationProperties.getIntProp("book.page_max_width")
).addText(this.sourceTextPanel.getSourceText()).build()
);
}
}

View File

@ -1,37 +0,0 @@
package nl.andrewlalis.blockbookbinder.control.source;
import lombok.Getter;
import lombok.Setter;
import nl.andrewlalis.blockbookbinder.model.build.BookBuilder2;
import nl.andrewlalis.blockbookbinder.util.ApplicationProperties;
import nl.andrewlalis.blockbookbinder.view.SourceTextPanel;
import nl.andrewlalis.blockbookbinder.view.book.BookPreviewPanel;
import javax.swing.*;
import java.awt.event.ActionEvent;
public class CompileFromSourceAction2 extends AbstractAction {
@Getter
private static final CompileFromSourceAction2 instance = new CompileFromSourceAction2();
@Setter
private SourceTextPanel sourceTextPanel;
@Setter
private BookPreviewPanel bookPreviewPanel;
public CompileFromSourceAction2() {
super("Compile From Source 2");
this.putValue(SHORT_DESCRIPTION, "Compile the current source text into a book.");
}
@Override
public void actionPerformed(ActionEvent e) {
this.bookPreviewPanel.setBook(
new BookBuilder2(
ApplicationProperties.getIntProp("book.page_max_lines"),
ApplicationProperties.getIntProp("book.page_max_chars"),
ApplicationProperties.getIntProp("book.page_max_width")
).addText(this.sourceTextPanel.getSourceText()).build()
);
}
}

View File

@ -3,112 +3,123 @@ package nl.andrewlalis.blockbookbinder.model.build;
import nl.andrewlalis.blockbookbinder.model.Book;
import nl.andrewlalis.blockbookbinder.model.BookPage;
import nl.andrewlalis.blockbookbinder.model.CharWidthMapper;
import nl.andrewlalis.blockbookbinder.util.ApplicationProperties;
import java.util.ArrayList;
import java.util.List;
public class BookBuilder {
/**
* Builds a full book of pages from the given source text.
* @param source The source text to convert.
* @return A book containing the source text formatted for a minecraft book.
*/
public Book build(String source) {
final int maxLines = ApplicationProperties.getIntProp("book.page_max_lines");
List<String> lines = this.convertSourceToLines(source);
private final int MAX_LINES_PER_PAGE;
private final int MAX_CHARS_PER_PAGE;
private final int MAX_LINE_PIXEL_WIDTH;
private final List<String> lines;
private final StringBuilder lineBuilder;
private final StringBuilder wordBuilder;
public BookBuilder(int maxLinesPerPage, int maxCharsPerPage, int maxLinePixelWidth) {
this.MAX_LINES_PER_PAGE = maxLinesPerPage;
this.MAX_CHARS_PER_PAGE = maxCharsPerPage;
this.MAX_LINE_PIXEL_WIDTH = maxLinePixelWidth;
this.lines = new ArrayList<>();
this.lineBuilder = new StringBuilder(64);
this.wordBuilder = new StringBuilder(64);
}
public BookBuilder addText(String text) {
int idx = 0;
while (idx < text.length()) {
final char c = text.charAt(idx++);
if (c == '\n') {
appendLine();
} else if (c == ' ' && lineBuilder.length() == 0) {
continue; // Skip spaces at the start of lines.
} else if (Character.isWhitespace(c)) {
if (CharWidthMapper.getWidth(lineBuilder.toString() + c) > MAX_LINE_PIXEL_WIDTH) {
appendLine();
if (c != ' ') {
lineBuilder.append(c);
}
} else {
lineBuilder.append(c);
}
} else { // Read a continuous word.
String word = readWord(text, idx - 1);
idx += word.length() - 1;
if (CharWidthMapper.getWidth(lineBuilder + word) <= MAX_LINE_PIXEL_WIDTH) {
// Append the word if it'll fit completely.
lineBuilder.append(word);
} else if (CharWidthMapper.getWidth(word) <= MAX_LINE_PIXEL_WIDTH) {
// Go to the next line and put the word there, since it'll fit.
appendLine();
lineBuilder.append(word);
} else {
// The word is so large that it doesn't fit on a line on its own.
// Find the largest substring of the word that'll fit with a hyphen.
int subStringSize = word.length() - 2;
while (CharWidthMapper.getWidth(word.substring(0, subStringSize) + "-") > MAX_LINE_PIXEL_WIDTH) {
subStringSize--;
}
appendLine();
lineBuilder.append(word, 0, subStringSize).append('-');
appendLine();
lineBuilder.append(word.substring(subStringSize));
}
}
}
return this;
}
public Book build() {
Book book = new Book();
BookPage page = new BookPage();
int currentPageLineCount = 0;
int currentPageCharCount = 0;
// Flush anything remaining in lineBuilder to a final line.
if (lineBuilder.length() > 0) {
appendLine();
}
for (String line : lines) {
page.addLine(line);
currentPageLineCount++;
if (currentPageLineCount == maxLines) {
if (currentPageCharCount + line.length() > MAX_CHARS_PER_PAGE) {
book.addPage(page);
page = new BookPage();
currentPageLineCount = 0;
currentPageCharCount = 0;
}
page.addLine(line);
currentPageLineCount++;
currentPageCharCount += line.length();
if (currentPageLineCount == MAX_LINES_PER_PAGE) {
book.addPage(page);
page = new BookPage();
currentPageLineCount = 0;
currentPageCharCount = 0;
}
}
if (page.hasContent()) {
book.addPage(page);
}
return book;
}
/**
* Converts the given source string into a formatted list of lines that can
* be copied to a minecraft book.
* @param source The source string.
* @return A list of lines.
*/
private List<String> convertSourceToLines(String source) {
List<String> lines = new ArrayList<>();
final char[] sourceChars = source.toCharArray();
final int maxLinePixelWidth = ApplicationProperties.getIntProp("book.page_max_width");
int sourceIndex = 0;
StringBuilder lineBuilder = new StringBuilder(64);
int linePixelWidth = 0;
StringBuilder symbolBuilder = new StringBuilder(64);
while (sourceIndex < sourceChars.length) {
final char c = sourceChars[sourceIndex];
sourceIndex++;
symbolBuilder.setLength(0);
symbolBuilder.append(c);
int symbolWidth = CharWidthMapper.getWidth(c);
// Since there's a 1-pixel gap between characters, add it to the width if this isn't the first char.
if (lineBuilder.length() > 0) {
symbolWidth++;
}
// If we encounter a non-newline whitespace at the beginning of the line, skip it.
if (c == ' ' && lineBuilder.length() == 0) {
continue;
}
// If we encounter a newline, immediately skip to a new line.
if (c == '\n') {
lines.add(lineBuilder.toString());
lineBuilder.setLength(0);
linePixelWidth = 0;
continue;
}
// If we encounter a word, keep accepting characters until we reach the end.
if (Character.isLetterOrDigit(c)) {
while (
sourceIndex < sourceChars.length
&& Character.isLetterOrDigit(sourceChars[sourceIndex])
) {
char nextChar = sourceChars[sourceIndex];
symbolBuilder.append(nextChar);
symbolWidth += 1 + CharWidthMapper.getWidth(nextChar);
sourceIndex++;
private String readWord(String text, int firstCharIdx) {
wordBuilder.setLength(0);
int idx = firstCharIdx;
while (idx < text.length()) {
char c = text.charAt(idx++);
if (!Character.isWhitespace(c)) {
wordBuilder.append(c);
} else {
break;
}
}
final String symbol = symbolBuilder.toString();
// Check if we need to go to the next line to fit the symbol.
if (linePixelWidth + symbolWidth > maxLinePixelWidth) {
lines.add(lineBuilder.toString());
lineBuilder.setLength(0);
linePixelWidth = 0;
return wordBuilder.toString();
}
// Finally, append the symbol.
lineBuilder.append(symbol);
linePixelWidth += symbolWidth;
}
// Append any remaining text.
if (lineBuilder.length() > 0) {
lines.add(lineBuilder.toString());
}
return lines;
private void appendLine() {
this.lines.add(this.lineBuilder.toString());
this.lineBuilder.setLength(0);
}
}

View File

@ -1,125 +0,0 @@
package nl.andrewlalis.blockbookbinder.model.build;
import nl.andrewlalis.blockbookbinder.model.Book;
import nl.andrewlalis.blockbookbinder.model.BookPage;
import nl.andrewlalis.blockbookbinder.model.CharWidthMapper;
import java.util.ArrayList;
import java.util.List;
public class BookBuilder2 {
private final int MAX_LINES_PER_PAGE;
private final int MAX_CHARS_PER_PAGE;
private final int MAX_LINE_PIXEL_WIDTH;
private final List<String> lines;
private final StringBuilder lineBuilder;
private final StringBuilder wordBuilder;
public BookBuilder2(int maxLinesPerPage, int maxCharsPerPage, int maxLinePixelWidth) {
this.MAX_LINES_PER_PAGE = maxLinesPerPage;
this.MAX_CHARS_PER_PAGE = maxCharsPerPage;
this.MAX_LINE_PIXEL_WIDTH = maxLinePixelWidth;
this.lines = new ArrayList<>();
this.lineBuilder = new StringBuilder(64);
this.wordBuilder = new StringBuilder(64);
}
public BookBuilder2 addText(String text) {
int idx = 0;
while (idx < text.length()) {
final char c = text.charAt(idx++);
if (c == '\n') {
appendLine();
} else if (c == ' ' && lineBuilder.length() == 0) {
continue; // Skip spaces at the start of lines.
} else if (Character.isWhitespace(c)) {
if (CharWidthMapper.getWidth(lineBuilder.toString() + c) > MAX_LINE_PIXEL_WIDTH) {
appendLine();
if (c != ' ') {
lineBuilder.append(c);
}
} else {
lineBuilder.append(c);
}
} else { // Read a continuous word.
String word = readWord(text, idx - 1);
idx += word.length() - 1;
if (CharWidthMapper.getWidth(lineBuilder + word) <= MAX_LINE_PIXEL_WIDTH) {
// Append the word if it'll fit completely.
lineBuilder.append(word);
} else if (CharWidthMapper.getWidth(word) <= MAX_LINE_PIXEL_WIDTH) {
// Go to the next line and put the word there, since it'll fit.
appendLine();
lineBuilder.append(word);
} else {
// The word is so large that it doesn't fit on a line on its own.
// Find the largest substring of the word that'll fit with a hyphen.
int subStringSize = word.length() - 2;
while (CharWidthMapper.getWidth(word.substring(0, subStringSize) + "-") > MAX_LINE_PIXEL_WIDTH) {
subStringSize--;
}
appendLine();
lineBuilder.append(word, 0, subStringSize).append('-');
appendLine();
lineBuilder.append(word.substring(subStringSize));
}
}
}
return this;
}
public Book build() {
Book book = new Book();
BookPage page = new BookPage();
int currentPageLineCount = 0;
int currentPageCharCount = 0;
// Flush anything remaining in lineBuilder to a final line.
if (lineBuilder.length() > 0) {
appendLine();
}
for (String line : lines) {
if (currentPageCharCount + line.length() > MAX_CHARS_PER_PAGE) {
book.addPage(page);
page = new BookPage();
currentPageLineCount = 0;
currentPageCharCount = 0;
}
page.addLine(line);
currentPageLineCount++;
currentPageCharCount += line.length();
if (currentPageLineCount == MAX_LINES_PER_PAGE) {
book.addPage(page);
page = new BookPage();
currentPageLineCount = 0;
currentPageCharCount = 0;
}
}
if (page.hasContent()) {
book.addPage(page);
}
return book;
}
private String readWord(String text, int firstCharIdx) {
wordBuilder.setLength(0);
int idx = firstCharIdx;
while (idx < text.length()) {
char c = text.charAt(idx++);
if (!Character.isWhitespace(c)) {
wordBuilder.append(c);
} else {
break;
}
}
return wordBuilder.toString();
}
private void appendLine() {
this.lines.add(this.lineBuilder.toString());
this.lineBuilder.setLength(0);
}
}

View File

@ -4,7 +4,6 @@ import nl.andrewlalis.blockbookbinder.BlockBookBinder;
import nl.andrewlalis.blockbookbinder.control.export.ExportBookToMinecraftAction;
import nl.andrewlalis.blockbookbinder.control.source.CleanSourceAction;
import nl.andrewlalis.blockbookbinder.control.source.CompileFromSourceAction;
import nl.andrewlalis.blockbookbinder.control.source.CompileFromSourceAction2;
import nl.andrewlalis.blockbookbinder.control.source.ImportSourceAction;
import nl.andrewlalis.blockbookbinder.util.ApplicationProperties;
import nl.andrewlalis.blockbookbinder.view.about.AboutDialog;
@ -45,13 +44,13 @@ public class MainFrame extends JFrame {
BookPreviewPanel bookPreviewPanel = new BookPreviewPanel();
doublePanel.add(bookPreviewPanel);
CompileFromSourceAction.getInstance().setBookPreviewPanel(bookPreviewPanel);
CompileFromSourceAction2.getInstance().setBookPreviewPanel(bookPreviewPanel);
CompileFromSourceAction.getInstance().setBookPreviewPanel(bookPreviewPanel);
ExportBookToMinecraftAction.getInstance().setBookPreviewPanel(bookPreviewPanel);
SourceTextPanel sourceTextPanel = new SourceTextPanel();
doublePanel.add(sourceTextPanel);
CompileFromSourceAction.getInstance().setSourceTextPanel(sourceTextPanel);
CompileFromSourceAction2.getInstance().setSourceTextPanel(sourceTextPanel);
CompileFromSourceAction.getInstance().setSourceTextPanel(sourceTextPanel);
CleanSourceAction.getInstance().setSourceTextPanel(sourceTextPanel);
mainPanel.add(doublePanel, BorderLayout.CENTER);
@ -71,7 +70,7 @@ public class MainFrame extends JFrame {
JMenu bookMenu = new JMenu("Book");
bookMenu.add(CompileFromSourceAction.getInstance());
bookMenu.add(CompileFromSourceAction2.getInstance());
bookMenu.add(CompileFromSourceAction.getInstance());
bookMenu.add(CleanSourceAction.getInstance());
bookMenu.add(ExportBookToMinecraftAction.getInstance());
menuBar.add(bookMenu);