From cb4af176c13b340ca9c0e8ce496c98b6ff687b32 Mon Sep 17 00:00:00 2001 From: Paul Vorbach Date: Wed, 10 Jul 2019 13:32:52 +0200 Subject: [PATCH 1/4] Simplify project model --- .../gui/controller/TesseractController.java | 4 -- .../tesseract/gui/model/ProjectModel.java | 61 ++++++++----------- 2 files changed, 25 insertions(+), 40 deletions(-) diff --git a/gui/src/main/java/de/vorb/tesseract/gui/controller/TesseractController.java b/gui/src/main/java/de/vorb/tesseract/gui/controller/TesseractController.java index d11f7db7..8d921e5b 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/controller/TesseractController.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/controller/TesseractController.java @@ -141,13 +141,11 @@ private static void setLookAndFeel() { } } - // constants private static final String KEY_TRAINING_FILE = "training_file"; private static final String KEY_BOX_FILE = "box_file"; public static final Preprocessor DEFAULT_PREPROCESSOR = new DefaultPreprocessor(); - // components references private final TesseractFrame view; private ApplicationMode mode = ApplicationMode.NONE; @@ -169,13 +167,11 @@ private static void setLookAndFeel() { private final List tasks = new LinkedList<>(); - // models private Optional projectModel = Optional.empty(); private Optional pageThumbnail = Optional.empty(); private String lastTraineddataFile; - // preprocessing private Preprocessor defaultPreprocessor = new DefaultPreprocessor(); private final Map preprocessors = new HashMap<>(); diff --git a/gui/src/main/java/de/vorb/tesseract/gui/model/ProjectModel.java b/gui/src/main/java/de/vorb/tesseract/gui/model/ProjectModel.java index b0d6e4f8..32cdc477 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/model/ProjectModel.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/model/ProjectModel.java @@ -6,41 +6,41 @@ import java.nio.file.Path; public class ProjectModel { - public static final String PROJECT_DIR = "tesseract-project"; - public static final String THUMBNAIL_DIR = "tesseract-project/thumbs"; - public static final String PREPROCESSED_DIR = "tesseract-project/preprocessed"; - public static final String TRANSCRIPTION_DIR = "tesseract-project/transcriptions"; - public static final String OCR_DIR = "tesseract-project/ocr"; - public static final String EVALUATION_DIR = "tesseract-project/evaluation"; + + private static final String PROJECT_DIR = "tesseract-project"; + private static final String THUMBNAIL_DIR = "tesseract-project/thumbs"; + private static final String PREPROCESSED_DIR = "tesseract-project/preprocessed"; + private static final String TRANSCRIPTION_DIR = "tesseract-project/transcriptions"; + private static final String OCR_DIR = "tesseract-project/ocr"; + private static final String EVALUATION_DIR = "tesseract-project/evaluation"; private final String projectName; private final Path imageDir; - private final boolean tiffFiles; - private final boolean pngFiles; - private final boolean jpegFiles; - - private final DirectoryStream.Filter filter = entry -> { - final String e = entry.getFileName().toString(); + private final DirectoryStream.Filter filter; - if (png() && e.endsWith(".png")) { - return true; - } else if (tiff() && (e.endsWith(".tif") || e.endsWith(".tiff"))) { - return true; - } else { - return jpeg() && (e.endsWith(".jpg") || e.endsWith(".jpeg")); - } - }; + public ProjectModel(Path projectDir, boolean includeTiffFiles, boolean includePngFiles, boolean includeJpegFiles) { - public ProjectModel(Path projectDir, boolean tiffFiles, boolean pngFiles, boolean jpegFiles) { projectName = projectDir.getFileName().toString(); this.imageDir = projectDir; - this.tiffFiles = tiffFiles; - this.pngFiles = pngFiles; - this.jpegFiles = jpegFiles; + //noinspection Convert2Lambda + this.filter = new DirectoryStream.Filter() { + @Override + public boolean accept(Path entry) { + final String fileName = entry.getFileName().toString(); + + if (includePngFiles && fileName.endsWith(".png")) { + return true; + } else if (includeTiffFiles && (fileName.endsWith(".tif") || fileName.endsWith(".tiff"))) { + return true; + } else { + return includeJpegFiles && (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")); + } + } + }; } public String getProjectName() { @@ -75,19 +75,8 @@ public Path getEvaluationDir() { return imageDir.resolve(EVALUATION_DIR); } - public Iterable getImageFiles() throws IOException { + public DirectoryStream getImageFiles() throws IOException { return Files.newDirectoryStream(imageDir, filter); } - public boolean tiff() { - return tiffFiles; - } - - public boolean png() { - return pngFiles; - } - - public boolean jpeg() { - return jpegFiles; - } } From 4d762d022076eb7eab478e3fb3106f79b03b3d03 Mon Sep 17 00:00:00 2001 From: Paul Vorbach Date: Wed, 10 Jul 2019 23:45:12 +0200 Subject: [PATCH 2/4] Introduce checker framework --- gui/pom.xml | 34 +++++ .../gui/controller/TesseractController.java | 118 +++++++++--------- .../gui/controller/package-info.java | 6 - .../tesseract/gui/event/package-info.java | 8 -- .../vorb/tesseract/gui/io/BoxFileWriter.java | 37 +++--- ...BatchExportModel.java => BatchExport.java} | 4 +- .../model/{BoxFileModel.java => BoxFile.java} | 12 +- .../gui/model/FilteredTableModel.java | 2 +- .../gui/model/{ImageModel.java => Image.java} | 4 +- .../vorb/tesseract/gui/model/PageModel.java | 25 ++-- .../tesseract/gui/model/PageThumbnail.java | 63 +++++----- .../model/{ProjectModel.java => Project.java} | 12 +- .../tesseract/gui/model/package-info.java | 6 - .../de/vorb/tesseract/gui/view/BoxEditor.java | 8 +- .../gui/view/BoxFileModelComponent.java | 4 +- .../tesseract/gui/view/EvaluationPane.java | 4 +- .../gui/view/ImageModelComponent.java | 6 +- .../gui/view/PageListCellRenderer.java | 15 +-- .../gui/view/PageModelComponent.java | 4 +- .../tesseract/gui/view/PreprocessingPane.java | 8 +- .../tesseract/gui/view/RecognitionPane.java | 6 +- .../tesseract/gui/view/SymbolOverview.java | 10 +- .../gui/view/dialogs/BatchExportDialog.java | 11 +- .../gui/view/dialogs/NewProjectDialog.java | 8 +- .../tesseract/gui/view/i18n/package-info.java | 8 -- .../vorb/tesseract/gui/view/package-info.java | 4 - .../gui/view/renderer/BoxFileRenderer.java | 4 +- .../view/renderer/EvaluationPaneRenderer.java | 2 +- .../view/renderer/PageListCellRenderer.java | 17 +-- .../view/renderer/RecognitionRenderer.java | 2 +- .../tesseract/gui/work/BatchExecutor.java | 36 +++--- .../de/vorb/tesseract/gui/work/OCRTask.java | 18 ++- .../tesseract/gui/work/PageListWorker.java | 17 +-- .../gui/work/PageRecognitionProducer.java | 8 +- .../gui/work/PreprocessingWorker.java | 8 +- .../tesseract/gui/work/RecognitionWorker.java | 16 +-- .../tesseract/gui/work/RecognitionWriter.java | 2 + .../tesseract/gui/work/ThumbnailWorker.java | 16 ++- ocrevalUAtion/pom.xml | 1 - pom.xml | 57 ++++++++- tools/pom.xml | 39 ++++++ .../de/vorb/tesseract/tools/package-info.java | 7 -- .../tools/preprocessing/package-info.java | 6 - .../tools/recognition/package-info.java | 6 - .../tools/training/package-info.java | 7 -- .../de/vorb/tesseract/util/package-info.java | 7 -- .../main/java/de/vorb/util/package-info.java | 7 -- 47 files changed, 372 insertions(+), 338 deletions(-) delete mode 100644 gui/src/main/java/de/vorb/tesseract/gui/controller/package-info.java delete mode 100644 gui/src/main/java/de/vorb/tesseract/gui/event/package-info.java rename gui/src/main/java/de/vorb/tesseract/gui/model/{BatchExportModel.java => BatchExport.java} (93%) rename gui/src/main/java/de/vorb/tesseract/gui/model/{BoxFileModel.java => BoxFile.java} (78%) rename gui/src/main/java/de/vorb/tesseract/gui/model/{ImageModel.java => Image.java} (90%) rename gui/src/main/java/de/vorb/tesseract/gui/model/{ProjectModel.java => Project.java} (87%) delete mode 100644 gui/src/main/java/de/vorb/tesseract/gui/model/package-info.java delete mode 100644 gui/src/main/java/de/vorb/tesseract/gui/view/i18n/package-info.java delete mode 100644 gui/src/main/java/de/vorb/tesseract/gui/view/package-info.java delete mode 100644 tools/src/main/java/de/vorb/tesseract/tools/package-info.java delete mode 100644 tools/src/main/java/de/vorb/tesseract/tools/preprocessing/package-info.java delete mode 100644 tools/src/main/java/de/vorb/tesseract/tools/recognition/package-info.java delete mode 100644 tools/src/main/java/de/vorb/tesseract/tools/training/package-info.java delete mode 100644 tools/src/main/java/de/vorb/tesseract/util/package-info.java delete mode 100644 tools/src/main/java/de/vorb/util/package-info.java diff --git a/gui/pom.xml b/gui/pom.xml index 64fa5ab6..42474db0 100644 --- a/gui/pom.xml +++ b/gui/pom.xml @@ -31,6 +31,18 @@ imageio-tiff 3.4.1 + + org.checkerframework + checker + + + org.checkerframework + checker-qual + + + org.checkerframework + jdk8 + junit junit @@ -41,6 +53,28 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.checkerframework + checker + ${checker-framework.version} + + + + + org.checkerframework.checker.nullness.NullnessChecker + + + + -Xbootclasspath/p:${annotatedJdk} + -Awarns + + + org.codehaus.mojo exec-maven-plugin diff --git a/gui/src/main/java/de/vorb/tesseract/gui/controller/TesseractController.java b/gui/src/main/java/de/vorb/tesseract/gui/controller/TesseractController.java index 8d921e5b..6461af21 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/controller/TesseractController.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/controller/TesseractController.java @@ -4,14 +4,14 @@ import de.vorb.tesseract.gui.io.BoxFileWriter; import de.vorb.tesseract.gui.io.PlainTextWriter; import de.vorb.tesseract.gui.model.ApplicationMode; -import de.vorb.tesseract.gui.model.BatchExportModel; -import de.vorb.tesseract.gui.model.BoxFileModel; +import de.vorb.tesseract.gui.model.BatchExport; +import de.vorb.tesseract.gui.model.BoxFile; import de.vorb.tesseract.gui.model.FilteredListModel; -import de.vorb.tesseract.gui.model.ImageModel; +import de.vorb.tesseract.gui.model.Image; import de.vorb.tesseract.gui.model.PageModel; import de.vorb.tesseract.gui.model.PageThumbnail; import de.vorb.tesseract.gui.model.PreferencesUtil; -import de.vorb.tesseract.gui.model.ProjectModel; +import de.vorb.tesseract.gui.model.Project; import de.vorb.tesseract.gui.model.SymbolListModel; import de.vorb.tesseract.gui.model.SymbolOrder; import de.vorb.tesseract.gui.util.DocumentWriter; @@ -55,6 +55,7 @@ import eu.digitisation.input.Parameters; import eu.digitisation.input.WarningException; import eu.digitisation.output.Report; +import org.checkerframework.checker.nullness.qual.Nullable; import javax.imageio.ImageIO; import javax.swing.DefaultListModel; @@ -167,7 +168,8 @@ private static void setLookAndFeel() { private final List tasks = new LinkedList<>(); - private Optional projectModel = Optional.empty(); + @Nullable + private Project project = null; private Optional pageThumbnail = Optional.empty(); private String lastTraineddataFile; @@ -368,8 +370,9 @@ public PageRecognitionProducer getPageRecognitionProducer() { return pageRecognitionProducer; } - public Optional getProjectModel() { - return projectModel; + @Nullable + public Project getProject() { + return project; } public Optional getSelectedPage() { @@ -417,7 +420,7 @@ private void handleActiveComponentChange() { final Optional pm = ((PageModelComponent) activeComponent).getPageModel(); if (pm.isPresent()) { - setImageModel(Optional.of(pm.get().getImageModel())); + setImageModel(Optional.of(pm.get().getImage())); } else { setImageModel(Optional.empty()); } @@ -443,7 +446,7 @@ private void handleActiveComponentChange() { private void handleOpenProjectDirectory() { if (Desktop.isDesktopSupported()) { try { - Desktop.getDesktop().browse(projectModel.get().getProjectDir().toUri()); + Desktop.getDesktop().browse(project.getProjectDir().toUri()); } catch (IOException e) { Dialogs.showError(view, "Exception", "Project directory could not be opened."); @@ -469,21 +472,21 @@ private void handleImportTranscriptions() { new ImportTranscriptionDialog(); importDialog.setVisible(true); - if (importDialog.isApproved() && projectModel.isPresent()) { + if (importDialog.isApproved() && project != null) { final Path file = importDialog.getTranscriptionFile(); final String sep = importDialog.getPageSeparator(); try { - Files.createDirectories(projectModel.get().getTranscriptionDir()); + Files.createDirectories(project.getTranscriptionDir()); view.getProgressBar().setIndeterminate(true); try (final BufferedReader reader = Files.newBufferedReader(file, StandardCharsets.UTF_8)) { // for every file - for (final Path imgFile : projectModel.get().getImageFiles()) { + for (final Path imgFile : project.getImageFiles()) { final Path filename = FileNames.replaceExtension(imgFile, "txt").getFileName(); - final Path transcription = projectModel.get().getTranscriptionDir().resolve(filename); + final Path transcription = project.getTranscriptionDir().resolve(filename); final BufferedWriter writer = Files.newBufferedWriter(transcription, StandardCharsets.UTF_8); @@ -525,14 +528,14 @@ private void handleImportTranscriptions() { } private void handleBatchExport() { - final Optional export = BatchExportDialog.showBatchExportDialog(this); + final Optional export = BatchExportDialog.showBatchExportDialog(this); if (export.isPresent()) { - final BatchExecutor batchExec = new BatchExecutor(this, this.getProjectModel().get(), export.get()); + final BatchExecutor batchExec = new BatchExecutor(this, this.getProject(), export.get()); try { final int totalFiles = - (int) Lists.newArrayList(this.getProjectModel().get().getImageFiles()).stream().count(); + (int) Lists.newArrayList(this.getProject().getImageFiles()).stream().count(); final ProgressMonitor progressMonitor = new ProgressMonitor(view, "Processing:", "", 0, totalFiles + 1); progressMonitor.setProgress(0); @@ -555,7 +558,7 @@ private void handleCompareSymbolToPrototype() { final Optional pm = getPageModel(); if (pm.isPresent()) { - final BufferedImage pageImg = pm.get().getImageModel().getPreprocessedImage(); + final BufferedImage pageImg = pm.get().getImage().getPreprocessedImage(); final Box symbolBox = selected.getBoundingBox(); final BufferedImage symbolImg = pageImg.getSubimage( symbolBox.getX(), symbolBox.getY(), @@ -576,11 +579,11 @@ private void handleGenerateReport() { return; } - final Path sourceFile = getPageModel().get().getImageModel().getSourceFile(); + final Path sourceFile = getPageModel().get().getImage().getSourceFile(); final Path fname = FileNames.replaceExtension(sourceFile, "txt").getFileName(); final Path repName = FileNames.replaceExtension(fname, "html"); - final Path plain = projectModel.get().getOCRDir().resolve(fname); - final Path report = projectModel.get().getEvaluationDir().resolve(repName); + final Path plain = project.getOCRDir().resolve(fname); + final Path report = project.getEvaluationDir().resolve(repName); try { final Path equivalencesFile = prepareReports(); @@ -603,9 +606,9 @@ private void handleGenerateReport() { } public Path prepareReports() throws IOException { - Files.createDirectories(projectModel.get().getEvaluationDir()); + Files.createDirectories(project.getEvaluationDir()); - final Path equivalencesFile = projectModel.get().getProjectDir().resolve("character_equivalences.csv"); + final Path equivalencesFile = project.getProjectDir().resolve("character_equivalences.csv"); if (!Files.exists(equivalencesFile)) { // copy the default character equivalences to the equivalences file @@ -630,16 +633,15 @@ public Path prepareReports() throws IOException { private Optional handleTranscriptionSave() { try { - if (projectModel.isPresent() && getPageModel().isPresent()) { - Files.createDirectories( - projectModel.get().getTranscriptionDir()); + if (project != null && getPageModel().isPresent()) { + Files.createDirectories(project.getTranscriptionDir()); final Path sourceFile = - getPageModel().get().getImageModel().getSourceFile(); + getPageModel().get().getImage().getSourceFile(); final Path fileName = FileNames.replaceExtension(sourceFile, "txt").getFileName(); - final Path transcriptionFile = projectModel.get().getTranscriptionDir().resolve(fileName); + final Path transcriptionFile = project.getTranscriptionDir().resolve(fileName); try (final Writer writer = Files.newBufferedWriter(transcriptionFile, StandardCharsets.UTF_8)) { @@ -664,35 +666,34 @@ private void handleNewProject() { return; } - final Optional result = NewProjectDialog.showDialog(view); + final Optional result = NewProjectDialog.showDialog(view); if (!result.isPresent()) { return; } - setProjectModel(result); + setProject(result.get()); - projectModel = result; - final ProjectModel projectModel = result.get(); + final Project project = result.get(); final DefaultListModel pages = view.getPages().getListModel(); - final ThumbnailWorker thumbnailLoader = new ThumbnailWorker(projectModel, pages); + final ThumbnailWorker thumbnailLoader = new ThumbnailWorker(project, pages); thumbnailLoader.execute(); this.thumbnailLoader = Optional.of(thumbnailLoader); - final PageListWorker pageListLoader = new PageListWorker(projectModel, pages); + final PageListWorker pageListLoader = new PageListWorker(project, pages); pageListLoader.execute(); setApplicationMode(ApplicationMode.PROJECT); } - private void setProjectModel(Optional model) { - projectModel = model; + private void setProject(@Nullable Project project) { + this.project = project; - if (model.isPresent()) { - view.setTitle(String.format("tesseract4java - %s", model.get().getProjectName())); + if (project != null) { + view.setTitle(String.format("tesseract4java - %s", project.getName())); } else { view.setTitle("tesseract4java"); @@ -752,7 +753,7 @@ public boolean accept(File f) { PreferencesUtil.getPreferences().put(KEY_BOX_FILE, boxFile.toAbsolutePath().toString()); - setBoxFileModel(Optional.of(new BoxFileModel(boxFile, image, boxes))); + setBoxFileModel(Optional.of(new BoxFile(boxFile, image, boxes))); } catch (IOException | IndexOutOfBoundsException e) { Dialogs.showError(view, "Error", "Box file could not be opened."); } @@ -787,8 +788,7 @@ public boolean accept(File f) { private void handleSaveProject() { // TODO fix me - final JFileChooser fc = new JFileChooser( - projectModel.get().getProjectDir().toFile()); + final JFileChooser fc = new JFileChooser(project.getProjectDir().toFile()); fc.setFileFilter(new FileFilter() { @Override public String getDescription() { @@ -808,7 +808,7 @@ public boolean accept(File f) { } private void handleSaveBoxFile() { - final Optional boxFileModel = getBoxFileModel(); + final Optional boxFileModel = getBoxFileModel(); if (boxFileModel.isPresent()) { try { @@ -823,12 +823,12 @@ private void handleSaveBoxFile() { } } - private Optional getBoxFileModel() { + private Optional getBoxFileModel() { if (mode == ApplicationMode.NONE) { return Optional.empty(); } else if (mode == ApplicationMode.BOX_FILE) { // first check box editor, then symbol overview - final Optional model = view.getBoxEditor().getBoxFileModel(); + final Optional model = view.getBoxEditor().getBoxFileModel(); if (model.isPresent()) { return model; @@ -851,7 +851,7 @@ private boolean handleCloseProject() { if (really) { setPageModel(Optional.empty()); - setProjectModel(Optional.empty()); + setProject(null); setApplicationMode(ApplicationMode.NONE); } @@ -919,7 +919,7 @@ public void run() { final PreprocessingWorker pw = new PreprocessingWorker( TesseractController.this, getPreprocessor(pt.getFile()), pt.getFile(), - getProjectModel().get().getPreprocessedDir()); + getProject().getPreprocessedDir()); // save reference preprocessingWorker = Optional.of(pw); @@ -971,7 +971,7 @@ private void handleSymbolGroupSelection() { final List symbols = selectionList.getModel().getElementAt(index).getValue(); - final Optional bfm = view.getSymbolOverview().getBoxFileModel(); + final Optional bfm = view.getSymbolOverview().getBoxFileModel(); if (!bfm.isPresent()) { return; @@ -1027,7 +1027,7 @@ public void run() { for (int i = first; i <= last; i++) { final PageThumbnail pt = model.getElementAt(i); - if (pt == null || pt.getThumbnail().isPresent()) { + if (pt == null || pt.getThumbnail() != null) { continue; } @@ -1076,9 +1076,9 @@ private void handlePreprocessorPreview() { return; } - final Optional projectModel = getProjectModel(); + final Project project = getProject(); - if (!projectModel.isPresent()) { + if (project == null) { Dialogs.showWarning(view, "No project", "No project has been selected. You need to create a project first."); return; @@ -1087,13 +1087,11 @@ private void handlePreprocessorPreview() { final Preprocessor preprocessor = view.getPreprocessingPane().getPreprocessor(); - if (preprocessingWorker.isPresent()) { - preprocessingWorker.get().cancel(false); - } + preprocessingWorker.ifPresent(worker -> worker.cancel(false)); final PreprocessingWorker pw = new PreprocessingWorker(this, preprocessor, selectedPage.get(), - projectModel.get().getProjectDir()); + project.getProjectDir()); preprocessingWorker = Optional.of(pw); @@ -1238,24 +1236,24 @@ private void handleTesseractTrainer() { } public void setPageModel(Optional model) { - if (projectModel.isPresent() && model.isPresent()) { + if (project != null && model.isPresent()) { try { // plain text file name final Path filename = - FileNames.replaceExtension(model.get().getImageModel().getSourceFile().getFileName(), "txt"); + FileNames.replaceExtension(model.get().getImage().getSourceFile().getFileName(), "txt"); // create ocr directory - Files.createDirectories(projectModel.get().getOCRDir()); + Files.createDirectories(project.getOCRDir()); // write the plain text ocr file - final Path plain = projectModel.get().getOCRDir().resolve(filename); + final Path plain = project.getOCRDir().resolve(filename); final Writer writer = Files.newBufferedWriter(plain, StandardCharsets.UTF_8); new PlainTextWriter(true).write(model.get().getPage(), writer); writer.close(); // read the transcription file - final Path transcriptionFile = projectModel.get().getTranscriptionDir().resolve(filename); + final Path transcriptionFile = project.getTranscriptionDir().resolve(filename); if (Files.isRegularFile(transcriptionFile)) { final byte[] bytes = Files.readAllBytes(transcriptionFile); @@ -1281,7 +1279,7 @@ public void setPageModel(Optional model) { } } - public void setBoxFileModel(Optional model) { + public void setBoxFileModel(Optional model) { final MainComponent active = view.getActiveComponent(); if (active instanceof BoxFileModelComponent) { ((BoxFileModelComponent) active).setBoxFileModel(model); @@ -1290,7 +1288,7 @@ public void setBoxFileModel(Optional model) { } } - public void setImageModel(Optional model) { + public void setImageModel(Optional model) { view.getProgressBar().setIndeterminate(false); final MainComponent active = view.getActiveComponent(); diff --git a/gui/src/main/java/de/vorb/tesseract/gui/controller/package-info.java b/gui/src/main/java/de/vorb/tesseract/gui/controller/package-info.java deleted file mode 100644 index 69889f5a..00000000 --- a/gui/src/main/java/de/vorb/tesseract/gui/controller/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Controller classes for TesseractGUI. - * - * @author Paul Vorbach - */ -package de.vorb.tesseract.gui.controller; diff --git a/gui/src/main/java/de/vorb/tesseract/gui/event/package-info.java b/gui/src/main/java/de/vorb/tesseract/gui/event/package-info.java deleted file mode 100644 index 0969d2ac..00000000 --- a/gui/src/main/java/de/vorb/tesseract/gui/event/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @author Paul Vorbach - */ -/** - * @author Paul Vorbach - * - */ -package de.vorb.tesseract.gui.event; diff --git a/gui/src/main/java/de/vorb/tesseract/gui/io/BoxFileWriter.java b/gui/src/main/java/de/vorb/tesseract/gui/io/BoxFileWriter.java index 8a72ce0c..69477b0a 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/io/BoxFileWriter.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/io/BoxFileWriter.java @@ -1,6 +1,6 @@ package de.vorb.tesseract.gui.io; -import de.vorb.tesseract.gui.model.BoxFileModel; +import de.vorb.tesseract.gui.model.BoxFile; import de.vorb.tesseract.util.Box; import de.vorb.tesseract.util.Symbol; @@ -9,28 +9,33 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import static java.nio.file.StandardOpenOption.CREATE; +import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; +import static java.nio.file.StandardOpenOption.WRITE; + public final class BoxFileWriter { - private BoxFileWriter() {} + private BoxFileWriter() { + } - public static void writeBoxFile(BoxFileModel model) throws IOException { - final BufferedWriter boxFileWriter = Files.newBufferedWriter( - model.getFile(), StandardCharsets.UTF_8); + public static void writeBoxFile(BoxFile model) throws IOException { + try ( + final BufferedWriter boxFileWriter = Files.newBufferedWriter(model.getFilePath(), + StandardCharsets.UTF_8, CREATE, TRUNCATE_EXISTING, WRITE)) { - final int pageHeight = model.getImage().getHeight(); + final int pageHeight = model.getImage().getHeight(); - for (Symbol symbol : model.getBoxes()) { + for (Symbol symbol : model.getBoxes()) { - final Box boundingBox = symbol.getBoundingBox(); - final int x0 = boundingBox.getX(); - final int y0 = pageHeight - boundingBox.getY() - boundingBox.getHeight(); - final int x1 = x0 + boundingBox.getWidth(); - final int y1 = y0 + boundingBox.getHeight(); + final Box boundingBox = symbol.getBoundingBox(); + final int x0 = boundingBox.getX(); + final int y0 = pageHeight - boundingBox.getY() - boundingBox.getHeight(); + final int x1 = x0 + boundingBox.getWidth(); + final int y1 = y0 + boundingBox.getHeight(); - boxFileWriter.write(String.format("%s %d %d %d %d 0\n", - symbol.getText(), x0, y0, x1, y1)); + boxFileWriter.write(String.format("%s %d %d %d %d 0\n", + symbol.getText(), x0, y0, x1, y1)); + } } - - boxFileWriter.close(); } } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/model/BatchExportModel.java b/gui/src/main/java/de/vorb/tesseract/gui/model/BatchExport.java similarity index 93% rename from gui/src/main/java/de/vorb/tesseract/gui/model/BatchExportModel.java rename to gui/src/main/java/de/vorb/tesseract/gui/model/BatchExport.java index 296a607c..a0a2ca80 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/model/BatchExportModel.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/model/BatchExport.java @@ -2,7 +2,7 @@ import java.nio.file.Path; -public class BatchExportModel { +public class BatchExport { private final Path destinationDir; private final boolean exportTXT; @@ -13,7 +13,7 @@ public class BatchExportModel { private final boolean openDestination; private final int numThreads; - public BatchExportModel(Path destinationDir, boolean exportTXT, + public BatchExport(Path destinationDir, boolean exportTXT, boolean exportHTML, boolean exportXML, boolean exportImages, boolean exportReports, int numThreads, boolean openDestination) { this.destinationDir = destinationDir; diff --git a/gui/src/main/java/de/vorb/tesseract/gui/model/BoxFileModel.java b/gui/src/main/java/de/vorb/tesseract/gui/model/BoxFile.java similarity index 78% rename from gui/src/main/java/de/vorb/tesseract/gui/model/BoxFileModel.java rename to gui/src/main/java/de/vorb/tesseract/gui/model/BoxFile.java index f1379f70..6d1d87fb 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/model/BoxFileModel.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/model/BoxFile.java @@ -7,19 +7,19 @@ import java.util.Collections; import java.util.List; -public class BoxFileModel { - private final Path file; +public class BoxFile { + private final Path filePath; private final BufferedImage image; private final List boxes; - public BoxFileModel(Path file, BufferedImage image, List boxes) { - this.file = file; + public BoxFile(Path filePath, BufferedImage image, List boxes) { + this.filePath = filePath; this.image = image; this.boxes = boxes; } - public Path getFile() { - return file; + public Path getFilePath() { + return filePath; } public BufferedImage getImage() { diff --git a/gui/src/main/java/de/vorb/tesseract/gui/model/FilteredTableModel.java b/gui/src/main/java/de/vorb/tesseract/gui/model/FilteredTableModel.java index 90fbf1e0..2333e62a 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/model/FilteredTableModel.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/model/FilteredTableModel.java @@ -9,7 +9,7 @@ public abstract class FilteredTableModel extends AbstractTableModel { private final FilteredListModel source; - protected FilteredTableModel(FilteredListModel source) { + FilteredTableModel(FilteredListModel source) { this.source = source; source.addListDataListener(new ListDataListener() { diff --git a/gui/src/main/java/de/vorb/tesseract/gui/model/ImageModel.java b/gui/src/main/java/de/vorb/tesseract/gui/model/Image.java similarity index 90% rename from gui/src/main/java/de/vorb/tesseract/gui/model/ImageModel.java rename to gui/src/main/java/de/vorb/tesseract/gui/model/Image.java index 5d3cbbce..276bfa05 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/model/ImageModel.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/model/Image.java @@ -3,14 +3,14 @@ import java.awt.image.BufferedImage; import java.nio.file.Path; -public class ImageModel { +public class Image { private final Path sourceFile; private final BufferedImage sourceImage; private final Path preprocessedFile; private final BufferedImage preprocessedImage; - public ImageModel(Path sourceFile, BufferedImage sourceImage, + public Image(Path sourceFile, BufferedImage sourceImage, Path preprocessedFile, BufferedImage preprocessedImage) { this.sourceFile = sourceFile; this.sourceImage = sourceImage; diff --git a/gui/src/main/java/de/vorb/tesseract/gui/model/PageModel.java b/gui/src/main/java/de/vorb/tesseract/gui/model/PageModel.java index 80ca9037..1849a01f 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/model/PageModel.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/model/PageModel.java @@ -10,12 +10,13 @@ import java.util.LinkedList; public class PageModel { - private final ImageModel imageModel; + + private final Image image; private final Page page; private final String transcription; - public PageModel(ImageModel imageModel, Page page, String string) { - this.imageModel = imageModel; + public PageModel(Image image, Page page, String string) { + this.image = image; this.page = page; this.transcription = string; } @@ -24,8 +25,8 @@ public Page getPage() { return page; } - public ImageModel getImageModel() { - return imageModel; + public Image getImage() { + return image; } public String getTranscription() { @@ -33,16 +34,16 @@ public String getTranscription() { } public PageModel withTranscription(String transcription) { - if (transcription.equals(this.transcription)) + if (transcription.equals(this.transcription)) { return this; + } - return new PageModel(imageModel, page, transcription); + return new PageModel(image, page, transcription); } - public BoxFileModel toBoxFileModel() { - final Path boxFile = FileNames.replaceExtension( - imageModel.getPreprocessedFile(), "box"); - final BufferedImage image = imageModel.getPreprocessedImage(); + public BoxFile toBoxFileModel() { + final Path boxFile = FileNames.replaceExtension(image.getPreprocessedFile(), "box"); + final BufferedImage image = this.image.getPreprocessedImage(); final LinkedList boxes = new LinkedList<>(); final Iterator symbolIt = page.symbolIterator(); @@ -50,6 +51,6 @@ public BoxFileModel toBoxFileModel() { boxes.add(symbolIt.next()); } - return new BoxFileModel(boxFile, image, boxes); + return new BoxFile(boxFile, image, boxes); } } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/model/PageThumbnail.java b/gui/src/main/java/de/vorb/tesseract/gui/model/PageThumbnail.java index ed457822..5ef12545 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/model/PageThumbnail.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/model/PageThumbnail.java @@ -1,60 +1,61 @@ package de.vorb.tesseract.gui.model; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.awt.image.BufferedImage; import java.nio.file.Path; -import java.util.Optional; +import java.util.Objects; public class PageThumbnail { + + @NonNull private final Path file; - private Optional thumbnail; - public PageThumbnail(Path file, Optional thumbnail) { + @Nullable + private BufferedImage thumbnail; + + public PageThumbnail(@NonNull Path file, @Nullable BufferedImage thumbnail) { this.file = file; this.thumbnail = thumbnail; } + @NonNull public Path getFile() { return file; } - public Optional getThumbnail() { + @Nullable + public BufferedImage getThumbnail() { return thumbnail; } - public void setThumbnail(Optional thumbnail) { + public void setThumbnail(@Nullable BufferedImage thumbnail) { this.thumbnail = thumbnail; } @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((file == null) ? 0 : file.hashCode()); - result = prime * result - + ((thumbnail == null) ? 0 : thumbnail.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) + public boolean equals(Object o) { + if (this == o) { return true; - if (obj == null) - return false; - if (!(obj instanceof PageThumbnail)) + } + if (o == null || getClass() != o.getClass()) { return false; - PageThumbnail other = (PageThumbnail) obj; - if (file == null) { - if (other.file != null) - return false; - } else if (!file.equals(other.file)) - return false; - if (thumbnail == null) { - if (other.thumbnail != null) - return false; - } else if (!thumbnail.equals(other.thumbnail)) + } + + final PageThumbnail that = (PageThumbnail) o; + + if (!file.equals(that.file)) { return false; - return true; + } + return Objects.equals(thumbnail, that.thumbnail); + } + + @Override + public int hashCode() { + int result = file.hashCode(); + result = 31 * result + (thumbnail != null ? thumbnail.hashCode() : 0); + return result; } } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/model/ProjectModel.java b/gui/src/main/java/de/vorb/tesseract/gui/model/Project.java similarity index 87% rename from gui/src/main/java/de/vorb/tesseract/gui/model/ProjectModel.java rename to gui/src/main/java/de/vorb/tesseract/gui/model/Project.java index 32cdc477..ce70fb02 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/model/ProjectModel.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/model/Project.java @@ -5,7 +5,7 @@ import java.nio.file.Files; import java.nio.file.Path; -public class ProjectModel { +public class Project { private static final String PROJECT_DIR = "tesseract-project"; private static final String THUMBNAIL_DIR = "tesseract-project/thumbs"; @@ -14,15 +14,15 @@ public class ProjectModel { private static final String OCR_DIR = "tesseract-project/ocr"; private static final String EVALUATION_DIR = "tesseract-project/evaluation"; - private final String projectName; + private final String name; private final Path imageDir; private final DirectoryStream.Filter filter; - public ProjectModel(Path projectDir, boolean includeTiffFiles, boolean includePngFiles, boolean includeJpegFiles) { + public Project(Path projectDir, boolean includeTiffFiles, boolean includePngFiles, boolean includeJpegFiles) { - projectName = projectDir.getFileName().toString(); + name = projectDir.getFileName().toString(); this.imageDir = projectDir; @@ -43,8 +43,8 @@ public boolean accept(Path entry) { }; } - public String getProjectName() { - return projectName; + public String getName() { + return name; } public Path getImageDir() { diff --git a/gui/src/main/java/de/vorb/tesseract/gui/model/package-info.java b/gui/src/main/java/de/vorb/tesseract/gui/model/package-info.java deleted file mode 100644 index 65111624..00000000 --- a/gui/src/main/java/de/vorb/tesseract/gui/model/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Model classes. - * - * @author Paul Vorbach - */ -package de.vorb.tesseract.gui.model; diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/BoxEditor.java b/gui/src/main/java/de/vorb/tesseract/gui/view/BoxEditor.java index 0fbb340a..b86c78cf 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/BoxEditor.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/BoxEditor.java @@ -1,6 +1,6 @@ package de.vorb.tesseract.gui.view; -import de.vorb.tesseract.gui.model.BoxFileModel; +import de.vorb.tesseract.gui.model.BoxFile; import de.vorb.tesseract.gui.model.PageModel; import de.vorb.tesseract.gui.model.Scale; import de.vorb.tesseract.gui.model.SingleSelectionModel; @@ -67,7 +67,7 @@ public class BoxEditor extends JPanel implements BoxFileModelComponent { private final Scale scale; private boolean changed = false; - private Optional model = Optional.empty(); + private Optional model = Optional.empty(); private Optional pageModel = Optional.empty(); private final SingleSelectionModel selectionModel = @@ -525,7 +525,7 @@ private void clicked(MouseEvent e) { } @Override - public void setBoxFileModel(Optional model) { + public void setBoxFileModel(Optional model) { this.model = model; final SymbolTableModel tabModel = @@ -556,7 +556,7 @@ public void setPageModel(Optional model) { } @Override - public Optional getBoxFileModel() { + public Optional getBoxFileModel() { return model; } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/BoxFileModelComponent.java b/gui/src/main/java/de/vorb/tesseract/gui/view/BoxFileModelComponent.java index 8b08d69b..fb65a12d 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/BoxFileModelComponent.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/BoxFileModelComponent.java @@ -1,9 +1,9 @@ package de.vorb.tesseract.gui.view; -import de.vorb.tesseract.gui.model.BoxFileModel; +import de.vorb.tesseract.gui.model.BoxFile; import java.util.Optional; public interface BoxFileModelComponent extends PageModelComponent { - void setBoxFileModel(Optional model); + void setBoxFileModel(Optional model); } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/EvaluationPane.java b/gui/src/main/java/de/vorb/tesseract/gui/view/EvaluationPane.java index e662d406..5af7e163 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/EvaluationPane.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/EvaluationPane.java @@ -1,6 +1,6 @@ package de.vorb.tesseract.gui.view; -import de.vorb.tesseract.gui.model.BoxFileModel; +import de.vorb.tesseract.gui.model.BoxFile; import de.vorb.tesseract.gui.model.PageModel; import de.vorb.tesseract.gui.model.Scale; import de.vorb.tesseract.gui.view.renderer.EvaluationPaneRenderer; @@ -229,7 +229,7 @@ public void freeResources() { } @Override - public Optional getBoxFileModel() { + public Optional getBoxFileModel() { if (model.isPresent()) { return Optional.of(model.get().toBoxFileModel()); } else { diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/ImageModelComponent.java b/gui/src/main/java/de/vorb/tesseract/gui/view/ImageModelComponent.java index fcc9d1e4..d3e16124 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/ImageModelComponent.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/ImageModelComponent.java @@ -1,11 +1,11 @@ package de.vorb.tesseract.gui.view; -import de.vorb.tesseract.gui.model.ImageModel; +import de.vorb.tesseract.gui.model.Image; import java.util.Optional; public interface ImageModelComponent extends MainComponent { - void setImageModel(Optional model); + void setImageModel(Optional model); - Optional getImageModel(); + Optional getImageModel(); } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/PageListCellRenderer.java b/gui/src/main/java/de/vorb/tesseract/gui/view/PageListCellRenderer.java index e2c7249b..34419b25 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/PageListCellRenderer.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/PageListCellRenderer.java @@ -16,10 +16,6 @@ import java.awt.Component; import java.nio.file.Path; -/** - * @author Paul Vorbach - * @deprecated - */ public class PageListCellRenderer extends DefaultListCellRenderer { private static final long serialVersionUID = 1L; @@ -32,13 +28,14 @@ public class PageListCellRenderer extends DefaultListCellRenderer { private static final Border SAFE_NO_FOCUS_BORDER = new EmptyBorder(1, 1, 1, 1); private static final Border DEFAULT_NO_FOCUS_BORDER = new EmptyBorder(1, 1, 1, 1); - protected static Border noFocusBorder = DEFAULT_NO_FOCUS_BORDER; + private static Border noFocusBorder = DEFAULT_NO_FOCUS_BORDER; private Border getNoFocusBorder() { Border border = DefaultLookup.getBorder(this, ui, "List.cellNoFocusBorder"); if (System.getSecurityManager() != null) { - if (border != null) + if (border != null) { return border; + } return SAFE_NO_FOCUS_BORDER; } else { if (border != null && @@ -50,11 +47,7 @@ private Border getNoFocusBorder() { } } - public Component getListCellRendererComponent( - JList list, - Object value, - int index, - boolean isSelected, + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { setComponentOrientation(list.getComponentOrientation()); diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/PageModelComponent.java b/gui/src/main/java/de/vorb/tesseract/gui/view/PageModelComponent.java index f46930e2..a93cf293 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/PageModelComponent.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/PageModelComponent.java @@ -1,6 +1,6 @@ package de.vorb.tesseract.gui.view; -import de.vorb.tesseract.gui.model.BoxFileModel; +import de.vorb.tesseract.gui.model.BoxFile; import de.vorb.tesseract.gui.model.PageModel; import java.util.Optional; @@ -10,5 +10,5 @@ public interface PageModelComponent extends MainComponent { Optional getPageModel(); - Optional getBoxFileModel(); + Optional getBoxFileModel(); } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/PreprocessingPane.java b/gui/src/main/java/de/vorb/tesseract/gui/view/PreprocessingPane.java index 47e286bc..937314b5 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/PreprocessingPane.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/PreprocessingPane.java @@ -1,6 +1,6 @@ package de.vorb.tesseract.gui.view; -import de.vorb.tesseract.gui.model.ImageModel; +import de.vorb.tesseract.gui.model.Image; import de.vorb.tesseract.tools.preprocessing.DefaultPreprocessor; import de.vorb.tesseract.tools.preprocessing.Preprocessor; import de.vorb.tesseract.tools.preprocessing.binarization.Binarization; @@ -54,7 +54,7 @@ public class PreprocessingPane extends JPanel implements ImageModelComponent { private final JButton btnApplyToPage; private final JButton btnApplyToAllPages; - private Optional imageModel = Optional.empty(); + private Optional imageModel = Optional.empty(); /** * Create the panel. @@ -303,7 +303,7 @@ public Component asComponent() { } @Override - public void setImageModel(Optional model) { + public void setImageModel(Optional model) { imageModel = model; if (model.isPresent()) { @@ -314,7 +314,7 @@ public void setImageModel(Optional model) { } @Override - public Optional getImageModel() { + public Optional getImageModel() { return imageModel; } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/RecognitionPane.java b/gui/src/main/java/de/vorb/tesseract/gui/view/RecognitionPane.java index 1f3197e5..af68358d 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/RecognitionPane.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/RecognitionPane.java @@ -1,6 +1,6 @@ package de.vorb.tesseract.gui.view; -import de.vorb.tesseract.gui.model.BoxFileModel; +import de.vorb.tesseract.gui.model.BoxFile; import de.vorb.tesseract.gui.model.PageModel; import de.vorb.tesseract.gui.model.Scale; import de.vorb.tesseract.gui.view.renderer.RecognitionRenderer; @@ -13,7 +13,6 @@ import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; -import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; @@ -27,7 +26,6 @@ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; -import java.awt.GraphicsEnvironment; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; @@ -445,7 +443,7 @@ public void freeResources() { } @Override - public Optional getBoxFileModel() { + public Optional getBoxFileModel() { if (model.isPresent()) { return Optional.of(model.get().toBoxFileModel()); } else { diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/SymbolOverview.java b/gui/src/main/java/de/vorb/tesseract/gui/view/SymbolOverview.java index 2d766f73..19eab8f3 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/SymbolOverview.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/SymbolOverview.java @@ -1,7 +1,7 @@ package de.vorb.tesseract.gui.view; import de.vorb.tesseract.gui.event.SymbolLinkListener; -import de.vorb.tesseract.gui.model.BoxFileModel; +import de.vorb.tesseract.gui.model.BoxFile; import de.vorb.tesseract.gui.model.PageModel; import de.vorb.tesseract.gui.view.renderer.SymbolVariantListCellRenderer; import de.vorb.tesseract.util.Symbol; @@ -27,7 +27,7 @@ public class SymbolOverview extends JPanel implements BoxFileModelComponent { private final SymbolGroupList glyphSelectionPane; private final SymbolVariantList glyphListPane; - private Optional model = Optional.empty(); + private Optional model = Optional.empty(); private Optional pageModel = Optional.empty(); private final LinkedList listeners = new LinkedList<>(); @@ -70,7 +70,7 @@ public Component asComponent() { } @Override - public Optional getBoxFileModel() { + public Optional getBoxFileModel() { return model; } @@ -83,7 +83,7 @@ public SymbolVariantList getSymbolVariantList() { } @Override - public void setBoxFileModel(Optional model) { + public void setBoxFileModel(Optional model) { this.model = model; if (!model.isPresent()) { @@ -98,7 +98,7 @@ public void setBoxFileModel(Optional model) { final HashMap> glyphs = new HashMap<>(); - final BoxFileModel boxFile = model.get(); + final BoxFile boxFile = model.get(); getSymbolVariantList().getList().setModel( new DefaultListModel<>()); diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/dialogs/BatchExportDialog.java b/gui/src/main/java/de/vorb/tesseract/gui/view/dialogs/BatchExportDialog.java index 10a31d66..17b5081f 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/dialogs/BatchExportDialog.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/dialogs/BatchExportDialog.java @@ -1,7 +1,7 @@ package de.vorb.tesseract.gui.view.dialogs; import de.vorb.tesseract.gui.controller.TesseractController; -import de.vorb.tesseract.gui.model.BatchExportModel; +import de.vorb.tesseract.gui.model.BatchExport; import javax.swing.BoxLayout; import javax.swing.JButton; @@ -56,7 +56,7 @@ public class BatchExportDialog extends JDialog implements ActionListener { private final TesseractController controller; - private BatchExportModel exportModel = null; + private BatchExport exportModel = null; private JCheckBox chckbxExportImages; private JLabel lblExport; private JCheckBox chckbxXml; @@ -259,7 +259,7 @@ public JTextField getDestinationDirectoryTextField() { return tfDestinationDir; } - public static Optional showBatchExportDialog( + public static Optional showBatchExportDialog( TesseractController controller) { final BatchExportDialog dialog = new BatchExportDialog(controller); dialog.setVisible(true); @@ -272,8 +272,7 @@ public void actionPerformed(ActionEvent evt) { if (evt.getSource() == btnCancel) { this.dispose(); } else if (evt.getSource() == btnDestinationDir) { - final JFileChooser dirChooser = new JFileChooser( - controller.getProjectModel().get().getProjectDir().toFile()); + final JFileChooser dirChooser = new JFileChooser(controller.getProject().getProjectDir().toFile()); dirChooser.setDialogTitle("Choose Destination Directory"); dirChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); final int result = dirChooser.showOpenDialog(controller.getView()); @@ -303,7 +302,7 @@ public void actionPerformed(ActionEvent evt) { final boolean openDestination = chckbxOpenDestination.isSelected(); final int numThreads = (Integer) spinnerWorkerThreads.getValue(); - exportModel = new BatchExportModel( + exportModel = new BatchExport( destinationDir, exportTXT, exportHTML, exportXML, exportImages, exportReports, numThreads, openDestination); diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/dialogs/NewProjectDialog.java b/gui/src/main/java/de/vorb/tesseract/gui/view/dialogs/NewProjectDialog.java index 6bcdbf69..50efdddc 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/dialogs/NewProjectDialog.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/dialogs/NewProjectDialog.java @@ -1,6 +1,6 @@ package de.vorb.tesseract.gui.view.dialogs; -import de.vorb.tesseract.gui.model.ProjectModel; +import de.vorb.tesseract.gui.model.Project; import javax.swing.JButton; import javax.swing.JCheckBox; @@ -53,7 +53,7 @@ public class NewProjectDialog extends JDialog implements ActionListener, private final JButton btnCreate; private final JButton btnCancel; - private Optional result = Optional.empty(); + private Optional result = Optional.empty(); /** * Create the dialog. @@ -208,7 +208,7 @@ public void actionPerformed(ActionEvent evt) { // set result if settings are valid if (isStateValid()) { Path dir = Paths.get(tfPath.getText()); - this.result = Optional.of(new ProjectModel(dir, + this.result = Optional.of(new Project(dir, cbTiff.isSelected(), cbPng.isSelected(), cbJpeg.isSelected())); } @@ -258,7 +258,7 @@ private Preferences getPreferences() { return Preferences.userNodeForPackage(getClass()); } - public static Optional showDialog(Window parent) { + public static Optional showDialog(Window parent) { final NewProjectDialog dialog = new NewProjectDialog(parent); dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/i18n/package-info.java b/gui/src/main/java/de/vorb/tesseract/gui/view/i18n/package-info.java deleted file mode 100644 index 6d2298a5..00000000 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/i18n/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @author Paul Vorbach - */ -/** - * @author Paul Vorbach - * - */ -package de.vorb.tesseract.gui.view.i18n; diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/package-info.java b/gui/src/main/java/de/vorb/tesseract/gui/view/package-info.java deleted file mode 100644 index d44e9281..00000000 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * @author Paul Vorbach - */ -package de.vorb.tesseract.gui.view; diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/BoxFileRenderer.java b/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/BoxFileRenderer.java index a701c2c9..6d25488a 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/BoxFileRenderer.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/BoxFileRenderer.java @@ -1,6 +1,6 @@ package de.vorb.tesseract.gui.view.renderer; -import de.vorb.tesseract.gui.model.BoxFileModel; +import de.vorb.tesseract.gui.model.BoxFile; import de.vorb.tesseract.gui.view.BoxEditor; import de.vorb.tesseract.gui.view.Colors; import de.vorb.tesseract.gui.view.Strokes; @@ -28,7 +28,7 @@ public BoxFileRenderer(BoxEditor boxEditor) { this.boxEditor = boxEditor; } - public void render(final Optional model, final float scale) { + public void render(final Optional model, final float scale) { if (!model.isPresent()) { // remove image, if no page model is given and free resources final Icon icon = boxEditor.getCanvas().getIcon(); diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/EvaluationPaneRenderer.java b/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/EvaluationPaneRenderer.java index c2551d8c..02c43e9b 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/EvaluationPaneRenderer.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/EvaluationPaneRenderer.java @@ -26,7 +26,7 @@ public void render(Optional pageModel, float scale) { if (modelPresent) { final BufferedImage img = - pageModel.get().getImageModel().getSourceImage(); + pageModel.get().getImage().getSourceImage(); final int w = Scale.scaled(img.getWidth(), scale); final int h = Scale.scaled(img.getHeight(), scale); diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/PageListCellRenderer.java b/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/PageListCellRenderer.java index 43169957..697ea61d 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/PageListCellRenderer.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/PageListCellRenderer.java @@ -11,16 +11,14 @@ import java.awt.Component; import java.awt.Graphics2D; import java.awt.image.BufferedImage; -import java.util.Optional; -public class PageListCellRenderer extends JLabel implements - ListCellRenderer { +public class PageListCellRenderer extends JLabel implements ListCellRenderer { private static final long serialVersionUID = 1L; private static final ImageIcon ICON_PLACEHOLDER = new ImageIcon( PageListCellRenderer.class.getResource("/page_loading.png")); - public static final Color COLOR_SELECT = new Color(0x4477FF); + private static final Color COLOR_SELECT = new Color(0x4477FF); public PageListCellRenderer() { setOpaque(true); @@ -40,8 +38,7 @@ public Component getListCellRendererComponent( int index, boolean isSelected, boolean cellHasFocus) { String filename = value.getFile().getFileName().toString(); if (filename.length() > 32) { - filename = filename.substring(0, 10) + "..." - + filename.substring(filename.length() - 16); + filename = filename.substring(0, 10) + "..." + filename.substring(filename.length() - 16); } setText(filename); @@ -54,10 +51,9 @@ public Component getListCellRendererComponent( setForeground(Color.BLACK); } - final Optional opt = value.getThumbnail(); + final BufferedImage thumbnail = value.getThumbnail(); - if (opt.isPresent()) { - final BufferedImage thumbnail = opt.get(); + if (thumbnail != null) { final Graphics2D g2d = (Graphics2D) thumbnail.getGraphics(); // set color @@ -71,8 +67,7 @@ public Component getListCellRendererComponent( g2d.setColor(Color.BLACK); } - g2d.drawRect(0, 0, thumbnail.getWidth() - 1, - thumbnail.getHeight() - 1); + g2d.drawRect(0, 0, thumbnail.getWidth() - 1, thumbnail.getHeight() - 1); g2d.dispose(); setIcon(new ImageIcon(thumbnail)); diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/RecognitionRenderer.java b/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/RecognitionRenderer.java index cd01fb06..dfe28803 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/RecognitionRenderer.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/RecognitionRenderer.java @@ -87,7 +87,7 @@ public void render(Optional pageModel, final float scale) { final Page page = pageModel.get().getPage(); final BufferedImage preprocessed = - pageModel.get().getImageModel().getPreprocessedImage(); + pageModel.get().getImage().getPreprocessedImage(); final int width = preprocessed.getWidth(); final int height = preprocessed.getHeight(); diff --git a/gui/src/main/java/de/vorb/tesseract/gui/work/BatchExecutor.java b/gui/src/main/java/de/vorb/tesseract/gui/work/BatchExecutor.java index 58ca49e8..55855b23 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/work/BatchExecutor.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/work/BatchExecutor.java @@ -1,8 +1,8 @@ package de.vorb.tesseract.gui.work; import de.vorb.tesseract.gui.controller.TesseractController; -import de.vorb.tesseract.gui.model.BatchExportModel; -import de.vorb.tesseract.gui.model.ProjectModel; +import de.vorb.tesseract.gui.model.BatchExport; +import de.vorb.tesseract.gui.model.Project; import de.vorb.tesseract.gui.util.DocumentWriter; import de.vorb.tesseract.gui.view.dialogs.Dialogs; import de.vorb.tesseract.tools.preprocessing.Preprocessor; @@ -37,21 +37,22 @@ import java.util.concurrent.atomic.AtomicInteger; public class BatchExecutor { + private final TesseractController controller; - private final ProjectModel project; - private final BatchExportModel export; + private final Project project; + private final BatchExport batchExport; - public BatchExecutor(TesseractController controller, ProjectModel project, - BatchExportModel export) { + public BatchExecutor(TesseractController controller, Project project, + BatchExport batchExport) { this.controller = controller; this.project = project; - this.export = export; + this.batchExport = batchExport; } public void start(final ProgressMonitor progressMonitor, final Writer errorLog) throws IOException, InterruptedException { - final int numThreads = export.getNumThreads(); + final int numThreads = batchExport.getNumThreads(); final ExecutorService threadPool = Executors.newFixedThreadPool(numThreads); @@ -76,7 +77,7 @@ public void start(final ProgressMonitor progressMonitor, Files.createDirectories(project.getEvaluationDir()); Files.createDirectories(project.getTranscriptionDir()); Files.createDirectories(project.getOCRDir()); - Files.createDirectories(export.getDestinationDir()); + Files.createDirectories(batchExport.getDestinationDir()); // holds progress count final AtomicInteger progress = new AtomicInteger(0); @@ -96,7 +97,7 @@ public void start(final ProgressMonitor progressMonitor, controller.hasPreprocessorChanged(sourceFile); final OCRTask task = new OCRTask(sourceFile, - project, export, preprocessor, recognizers, + project, batchExport, preprocessor, recognizers, hasPreprocessorChanged, equivalencesFile, progressMonitor, progress, errorLog, errors); @@ -109,8 +110,9 @@ public boolean cancel(boolean mayInterruptIfRunning) { int cancelled = 0; for (Future future : futures) { - if (future.cancel(mayInterruptIfRunning)) + if (future.cancel(mayInterruptIfRunning)) { cancelled++; + } } return cancelled > 0; @@ -207,7 +209,7 @@ public Void call() throws IOException { } catch (InterruptedException | ExecutionException e) { } finally { all = null; - if (export.exportReports()) { + if (batchExport.exportReports()) { progressMonitor.setNote("Final report"); // create a single report for all transcriptions DirectoryStream transcriptions; @@ -224,7 +226,7 @@ public Void call() throws IOException { final Report report = new Report(batch, params); - final Path projectReport = export.getDestinationDir() + final Path projectReport = batchExport.getDestinationDir() .resolve("project.report.html"); // write report html @@ -232,7 +234,7 @@ public Void call() throws IOException { // write report csv final BufferedWriter csv = Files.newBufferedWriter( - export.getDestinationDir().resolve( + batchExport.getDestinationDir().resolve( "project.report.csv"), StandardCharsets.UTF_8); csv.write(report.getStats().asCSV("\n", ",").toString()); @@ -246,10 +248,10 @@ public Void call() throws IOException { } } - if (export.openDestination()) { + if (batchExport.openDestination()) { try { Desktop.getDesktop().browse( - export.getDestinationDir().toUri()); + batchExport.getDestinationDir().toUri()); } catch (IOException e) { errors.incrementAndGet(); @@ -279,7 +281,7 @@ public Void call() throws IOException { if (investigate) { try { Desktop.getDesktop().open( - export.getDestinationDir().resolve( + batchExport.getDestinationDir().resolve( "errors.log").toFile()); } catch (IOException e) { Dialogs.showError(controller.getView(), diff --git a/gui/src/main/java/de/vorb/tesseract/gui/work/OCRTask.java b/gui/src/main/java/de/vorb/tesseract/gui/work/OCRTask.java index 48ae8616..3ce19fbe 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/work/OCRTask.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/work/OCRTask.java @@ -1,8 +1,8 @@ package de.vorb.tesseract.gui.work; import de.vorb.tesseract.gui.io.PlainTextWriter; -import de.vorb.tesseract.gui.model.BatchExportModel; -import de.vorb.tesseract.gui.model.ProjectModel; +import de.vorb.tesseract.gui.model.BatchExport; +import de.vorb.tesseract.gui.model.Project; import de.vorb.tesseract.gui.util.DocumentWriter; import de.vorb.tesseract.tools.preprocessing.Preprocessor; import de.vorb.tesseract.tools.recognition.PageRecognitionConsumer; @@ -33,8 +33,8 @@ public class OCRTask implements Callable { private final Path sourceFile; - private final ProjectModel project; - private final BatchExportModel export; + private final Project project; + private final BatchExport export; private final Preprocessor preprocessor; private final LinkedBlockingQueue recognizers; private final boolean hasPreprocessorChanged; @@ -46,12 +46,10 @@ public class OCRTask implements Callable { private final Writer errorLog; private final AtomicInteger errors; - public OCRTask(Path sourceFile, ProjectModel project, - BatchExportModel export, Preprocessor preprocessor, - LinkedBlockingQueue recognizers, - boolean hasPreprocessorChanged, Path equivalencesFile, - ProgressMonitor progressMonitor, AtomicInteger progress, - Writer errorLog, AtomicInteger errors) { + OCRTask(Path sourceFile, Project project, BatchExport export, Preprocessor preprocessor, + LinkedBlockingQueue recognizers, boolean hasPreprocessorChanged, + Path equivalencesFile, ProgressMonitor progressMonitor, AtomicInteger progress, Writer errorLog, + AtomicInteger errors) { this.sourceFile = sourceFile; this.project = project; this.export = export; diff --git a/gui/src/main/java/de/vorb/tesseract/gui/work/PageListWorker.java b/gui/src/main/java/de/vorb/tesseract/gui/work/PageListWorker.java index 30bf4d7a..e95e75af 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/work/PageListWorker.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/work/PageListWorker.java @@ -1,22 +1,20 @@ package de.vorb.tesseract.gui.work; import de.vorb.tesseract.gui.model.PageThumbnail; -import de.vorb.tesseract.gui.model.ProjectModel; +import de.vorb.tesseract.gui.model.Project; import javax.swing.DefaultListModel; import javax.swing.SwingWorker; -import java.awt.image.BufferedImage; import java.nio.file.Path; import java.util.List; -import java.util.Optional; public class PageListWorker extends SwingWorker { - private final ProjectModel projectModel; + private final Project project; private final DefaultListModel pages; - public PageListWorker(final ProjectModel projectModel, + public PageListWorker(final Project project, DefaultListModel pages) { - this.projectModel = projectModel; + this.project = project; this.pages = pages; pages.clear(); @@ -24,12 +22,9 @@ public PageListWorker(final ProjectModel projectModel, @Override protected Void doInBackground() throws Exception { - // no thumbnail - final Optional thumbnail = Optional.empty(); - // publish a placeholder (no thumbnail) for every image file - for (final Path file : projectModel.getImageFiles()) { - publish(new PageThumbnail(file, thumbnail)); + for (final Path file : project.getImageFiles()) { + publish(new PageThumbnail(file, null)); } return null; diff --git a/gui/src/main/java/de/vorb/tesseract/gui/work/PageRecognitionProducer.java b/gui/src/main/java/de/vorb/tesseract/gui/work/PageRecognitionProducer.java index 11acc9a1..2701c9f0 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/work/PageRecognitionProducer.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/work/PageRecognitionProducer.java @@ -31,8 +31,7 @@ public class PageRecognitionProducer extends RecognitionProducer { private final TesseractController controller; private final HashMap variables = new HashMap<>(); - public PageRecognitionProducer(TesseractController controller, - Path tessdataDir, String trainingFile) { + public PageRecognitionProducer(TesseractController controller, Path tessdataDir, String trainingFile) { super(trainingFile); this.controller = controller; @@ -122,12 +121,11 @@ public List getFeaturesForSymbol(BufferedImage symbol) { g2d.dispose(); // FIXME - if (!controller.getProjectModel().isPresent()) { + if (controller.getProject() == null) { return Collections.emptyList(); } - final String symbolFile = controller.getProjectModel().get().getProjectDir().resolve( - "symbol.png").toString(); + final String symbolFile = controller.getProject().getProjectDir().resolve("symbol.png").toString(); try { ImageIO.write(symbolWithPadding, "PNG", new File(symbolFile)); } catch (IOException e) { diff --git a/gui/src/main/java/de/vorb/tesseract/gui/work/PreprocessingWorker.java b/gui/src/main/java/de/vorb/tesseract/gui/work/PreprocessingWorker.java index eee4912c..f04bacc3 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/work/PreprocessingWorker.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/work/PreprocessingWorker.java @@ -1,7 +1,7 @@ package de.vorb.tesseract.gui.work; import de.vorb.tesseract.gui.controller.TesseractController; -import de.vorb.tesseract.gui.model.ImageModel; +import de.vorb.tesseract.gui.model.Image; import de.vorb.tesseract.tools.preprocessing.Preprocessor; import de.vorb.util.FileNames; @@ -14,7 +14,7 @@ import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; -public class PreprocessingWorker extends SwingWorker { +public class PreprocessingWorker extends SwingWorker { private final TesseractController controller; private final Preprocessor preprocessor; private final Path sourceFile; @@ -29,7 +29,7 @@ public PreprocessingWorker(TesseractController controller, } @Override - protected ImageModel doInBackground() throws Exception { + protected Image doInBackground() throws Exception { Files.createDirectories(destinationDir); final Path destFile = destinationDir.resolve(FileNames.replaceExtension( @@ -40,7 +40,7 @@ protected ImageModel doInBackground() throws Exception { final BufferedImage preprocessedImg = preprocessor.process(sourceImg); ImageIO.write(preprocessedImg, "PNG", destFile.toFile()); - return new ImageModel(sourceFile, sourceImg, destFile, preprocessedImg); + return new Image(sourceFile, sourceImg, destFile, preprocessedImg); } @Override diff --git a/gui/src/main/java/de/vorb/tesseract/gui/work/RecognitionWorker.java b/gui/src/main/java/de/vorb/tesseract/gui/work/RecognitionWorker.java index afcfe1cf..5ed0809e 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/work/RecognitionWorker.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/work/RecognitionWorker.java @@ -1,7 +1,7 @@ package de.vorb.tesseract.gui.work; import de.vorb.tesseract.gui.controller.TesseractController; -import de.vorb.tesseract.gui.model.ImageModel; +import de.vorb.tesseract.gui.model.Image; import de.vorb.tesseract.gui.model.PageModel; import de.vorb.tesseract.gui.view.dialogs.Dialogs; import de.vorb.tesseract.tools.recognition.PageRecognitionConsumer; @@ -18,14 +18,14 @@ public class RecognitionWorker extends SwingWorker { private final TesseractController controller; - private final ImageModel imageModel; + private final Image image; private final String trainingFile; private final PageRecognitionProducer producer; public RecognitionWorker(TesseractController controller, - ImageModel imageModel, String trainingFile) { + Image image, String trainingFile) { this.controller = controller; - this.imageModel = imageModel; + this.image = image; this.trainingFile = trainingFile; this.producer = controller.getPageRecognitionProducer(); } @@ -44,12 +44,12 @@ protected PageModel doInBackground() throws Exception { producer.reset(); - producer.loadImage(imageModel.getPreprocessedFile()); + producer.loadImage(image.getPreprocessedFile()); final List blocks = new ArrayList<>(1); // Get images - final BufferedImage image = imageModel.getPreprocessedImage(); + final BufferedImage image = this.image.getPreprocessedImage(); producer.recognize(new PageRecognitionConsumer(blocks) { @Override @@ -58,10 +58,10 @@ public boolean isCancelled() { } }); - final Page page = new Page(imageModel.getPreprocessedFile(), + final Page page = new Page(this.image.getPreprocessedFile(), image.getWidth(), image.getHeight(), 300, blocks); - return new PageModel(imageModel, page, ""); + return new PageModel(this.image, page, ""); } @Override diff --git a/gui/src/main/java/de/vorb/tesseract/gui/work/RecognitionWriter.java b/gui/src/main/java/de/vorb/tesseract/gui/work/RecognitionWriter.java index 82da1208..9b3f7df3 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/work/RecognitionWriter.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/work/RecognitionWriter.java @@ -6,5 +6,7 @@ import java.io.Writer; public interface RecognitionWriter { + void write(Page page, Writer writer) throws IOException; + } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/work/ThumbnailWorker.java b/gui/src/main/java/de/vorb/tesseract/gui/work/ThumbnailWorker.java index c39a9e8f..184fd7f2 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/work/ThumbnailWorker.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/work/ThumbnailWorker.java @@ -1,7 +1,7 @@ package de.vorb.tesseract.gui.work; import de.vorb.tesseract.gui.model.PageThumbnail; -import de.vorb.tesseract.gui.model.ProjectModel; +import de.vorb.tesseract.gui.model.Project; import javax.imageio.ImageIO; import javax.swing.DefaultListModel; @@ -11,13 +11,12 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.List; -import java.util.Optional; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; public class ThumbnailWorker extends SwingWorker { - private final ProjectModel projectModel; + private final Project project; private final DefaultListModel pages; private final Queue tasks = new ConcurrentLinkedQueue<>(); @@ -37,9 +36,9 @@ public void cancel() { } } - public ThumbnailWorker(final ProjectModel project, + public ThumbnailWorker(final Project project, DefaultListModel pages) { - this.projectModel = project; + this.project = project; this.pages = pages; } @@ -49,7 +48,7 @@ public void submitTask(Task task) { @Override protected Void doInBackground() throws Exception { - final Path thumbsDir = projectModel.getThumbnailDir(); + final Path thumbsDir = project.getThumbnailDir(); // mkdir -p thumbsDir Files.createDirectories(thumbsDir); @@ -96,12 +95,11 @@ protected Void doInBackground() throws Exception { // release system resources used by this image img.flush(); - // write the thumnail to disk + // write the thumbnail to disk ImageIO.write(thumb, "PNG", thumbFile.toFile()); } - publish(new Task(task.index, new PageThumbnail(imageFile, - Optional.of(thumb)))); + publish(new Task(task.index, new PageThumbnail(imageFile, thumb))); } else { Thread.sleep(500L); } diff --git a/ocrevalUAtion/pom.xml b/ocrevalUAtion/pom.xml index e12af5dd..91286e93 100644 --- a/ocrevalUAtion/pom.xml +++ b/ocrevalUAtion/pom.xml @@ -37,7 +37,6 @@ org.apache.maven.plugins maven-compiler-plugin - 3.1 1.6 1.6 diff --git a/pom.xml b/pom.xml index 3045b965..88091582 100644 --- a/pom.xml +++ b/pom.xml @@ -17,8 +17,15 @@ UTF-8 - 1.8 - 1.8 + + + ${org.checkerframework:jdk8:jar} + + 2.9.0 + + 3.1.1 + 3.8.1 + 1.12.0 @@ -33,6 +40,21 @@ ocrevalUAtion ${project.version} + + org.checkerframework + checker + ${checker-framework.version} + + + org.checkerframework + checker-qual + ${checker-framework.version} + + + org.checkerframework + jdk8 + ${checker-framework.version} + @@ -41,7 +63,7 @@ com.amashchenko.maven.plugin gitflow-maven-plugin - 1.12.0 + ${gitflow-maven-plugin.version} 1 true @@ -51,6 +73,35 @@ + + + + org.apache.maven.plugins + maven-dependency-plugin + ${maven-dependency-plugin.version} + + + + properties + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + 1.8 + 1.8 + + 10000 + 10000 + + + + + diff --git a/tools/pom.xml b/tools/pom.xml index 6b619154..efeaf83c 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -36,6 +36,18 @@ de.vorb.tesseract ocrevalUAtion + + org.checkerframework + checker + + + org.checkerframework + checker-qual + + + org.checkerframework + jdk8 + junit junit @@ -44,6 +56,33 @@ + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.checkerframework + checker + ${checker-framework.version} + + + + + org.checkerframework.checker.nullness.NullnessChecker + + + + -Xbootclasspath/p:${annotatedJdk} + -Awarns + + + + + + central diff --git a/tools/src/main/java/de/vorb/tesseract/tools/package-info.java b/tools/src/main/java/de/vorb/tesseract/tools/package-info.java deleted file mode 100644 index 65644a9c..00000000 --- a/tools/src/main/java/de/vorb/tesseract/tools/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Tesseract. - * - * @author Paul Vorbach - */ -package de.vorb.tesseract.tools; - diff --git a/tools/src/main/java/de/vorb/tesseract/tools/preprocessing/package-info.java b/tools/src/main/java/de/vorb/tesseract/tools/preprocessing/package-info.java deleted file mode 100644 index 4f95cb07..00000000 --- a/tools/src/main/java/de/vorb/tesseract/tools/preprocessing/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Pre-processing tools. - * - * @author Paul Vorbach - */ -package de.vorb.tesseract.tools.preprocessing; diff --git a/tools/src/main/java/de/vorb/tesseract/tools/recognition/package-info.java b/tools/src/main/java/de/vorb/tesseract/tools/recognition/package-info.java deleted file mode 100644 index 8eb8d9ef..00000000 --- a/tools/src/main/java/de/vorb/tesseract/tools/recognition/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Recognition related tools. - * - * @author Paul Vorbach - */ -package de.vorb.tesseract.tools.recognition; diff --git a/tools/src/main/java/de/vorb/tesseract/tools/training/package-info.java b/tools/src/main/java/de/vorb/tesseract/tools/training/package-info.java deleted file mode 100644 index e83f6fcf..00000000 --- a/tools/src/main/java/de/vorb/tesseract/tools/training/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Tesseract training. - * - * @author Paul Vorbach - */ -package de.vorb.tesseract.tools.training; - diff --git a/tools/src/main/java/de/vorb/tesseract/util/package-info.java b/tools/src/main/java/de/vorb/tesseract/util/package-info.java deleted file mode 100644 index d7c06fb6..00000000 --- a/tools/src/main/java/de/vorb/tesseract/util/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Utilities for the Tesseract tools. - * - * @author Paul Vorbach - */ -package de.vorb.tesseract.util; - diff --git a/tools/src/main/java/de/vorb/util/package-info.java b/tools/src/main/java/de/vorb/util/package-info.java deleted file mode 100644 index 74b7f08f..00000000 --- a/tools/src/main/java/de/vorb/util/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Common utilities. - * - * @author Paul Vorbach - */ -package de.vorb.util; - From b3d23e9e6d70bc793151ae5b640010d4b9cf24ea Mon Sep 17 00:00:00 2001 From: Paul Vorbach Date: Thu, 11 Jul 2019 01:52:23 +0200 Subject: [PATCH 3/4] Remove usage of Optional for fields --- .../gui/controller/TesseractController.java | 301 ++++++++---------- .../vorb/tesseract/gui/io/BoxFileWriter.java | 14 +- .../gui/model/FilteredListModel.java | 49 ++- .../gui/model/{PageModel.java => Page.java} | 14 +- .../tesseract/gui/util/FilterProvider.java | 2 + .../de/vorb/tesseract/gui/view/BoxEditor.java | 212 +++++------- .../tesseract/gui/view/BoxFileCanvas.java | 15 +- .../tesseract/gui/view/BoxFileComponent.java | 11 + .../gui/view/BoxFileModelComponent.java | 9 - .../de/vorb/tesseract/gui/view/Canvas.java | 19 +- .../tesseract/gui/view/EvaluationPane.java | 36 +-- .../tesseract/gui/view/FeatureDebugger.java | 29 +- .../vorb/tesseract/gui/view/FilteredList.java | 2 +- .../tesseract/gui/view/FilteredTable.java | 9 +- .../gui/view/ImageModelComponent.java | 9 +- .../tesseract/gui/view/PageComponent.java | 18 ++ .../gui/view/PageModelComponent.java | 14 - .../de/vorb/tesseract/gui/view/PageView.java | 11 - .../tesseract/gui/view/PreprocessingPane.java | 23 +- .../tesseract/gui/view/RecognitionPane.java | 79 +++-- .../tesseract/gui/view/SymbolOverview.java | 74 ++--- .../tesseract/gui/view/TesseractFrame.java | 25 +- .../tesseract/gui/view/dialogs/Dialogs.java | 30 +- .../gui/view/renderer/BoxFileRenderer.java | 20 +- .../view/renderer/EvaluationPaneRenderer.java | 21 +- .../gui/view/renderer/PageRenderer.java | 18 +- .../view/renderer/RecognitionRenderer.java | 82 ++--- .../tesseract/gui/work/BatchExecutor.java | 5 +- .../gui/work/PageRecognitionProducer.java | 27 +- .../gui/work/PreprocessingWorker.java | 10 +- .../tesseract/gui/work/RecognitionWorker.java | 18 +- 31 files changed, 529 insertions(+), 677 deletions(-) rename gui/src/main/java/de/vorb/tesseract/gui/model/{PageModel.java => Page.java} (78%) create mode 100644 gui/src/main/java/de/vorb/tesseract/gui/view/BoxFileComponent.java delete mode 100644 gui/src/main/java/de/vorb/tesseract/gui/view/BoxFileModelComponent.java create mode 100644 gui/src/main/java/de/vorb/tesseract/gui/view/PageComponent.java delete mode 100644 gui/src/main/java/de/vorb/tesseract/gui/view/PageModelComponent.java delete mode 100644 gui/src/main/java/de/vorb/tesseract/gui/view/PageView.java diff --git a/gui/src/main/java/de/vorb/tesseract/gui/controller/TesseractController.java b/gui/src/main/java/de/vorb/tesseract/gui/controller/TesseractController.java index 6461af21..b073695d 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/controller/TesseractController.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/controller/TesseractController.java @@ -8,20 +8,20 @@ import de.vorb.tesseract.gui.model.BoxFile; import de.vorb.tesseract.gui.model.FilteredListModel; import de.vorb.tesseract.gui.model.Image; -import de.vorb.tesseract.gui.model.PageModel; +import de.vorb.tesseract.gui.model.Page; import de.vorb.tesseract.gui.model.PageThumbnail; import de.vorb.tesseract.gui.model.PreferencesUtil; import de.vorb.tesseract.gui.model.Project; import de.vorb.tesseract.gui.model.SymbolListModel; import de.vorb.tesseract.gui.model.SymbolOrder; import de.vorb.tesseract.gui.util.DocumentWriter; -import de.vorb.tesseract.gui.view.BoxFileModelComponent; +import de.vorb.tesseract.gui.view.BoxFileComponent; import de.vorb.tesseract.gui.view.EvaluationPane; import de.vorb.tesseract.gui.view.FeatureDebugger; import de.vorb.tesseract.gui.view.FilteredTable; import de.vorb.tesseract.gui.view.ImageModelComponent; import de.vorb.tesseract.gui.view.MainComponent; -import de.vorb.tesseract.gui.view.PageModelComponent; +import de.vorb.tesseract.gui.view.PageComponent; import de.vorb.tesseract.gui.view.PreprocessingPane; import de.vorb.tesseract.gui.view.SymbolOverview; import de.vorb.tesseract.gui.view.TesseractFrame; @@ -145,8 +145,6 @@ private static void setLookAndFeel() { private static final String KEY_TRAINING_FILE = "training_file"; private static final String KEY_BOX_FILE = "box_file"; - public static final Preprocessor DEFAULT_PREPROCESSOR = new DefaultPreprocessor(); - private final TesseractFrame view; private ApplicationMode mode = ApplicationMode.NONE; @@ -155,22 +153,22 @@ private static void setLookAndFeel() { private MainComponent activeComponent; private final PageRecognitionProducer pageRecognitionProducer; - private Optional preprocessingWorker = Optional.empty(); + private PreprocessingWorker preprocessingWorker = null; // IO workers, timers and tasks - private Optional thumbnailLoader = Optional.empty(); + private ThumbnailWorker thumbnailLoader = null; private final Timer pageSelectionTimer = new Timer("PageSelectionTimer"); - private Optional lastPageSelectionTask = Optional.empty(); + private TimerTask lastPageSelectionTask = null; private final Timer thumbnailLoadTimer = new Timer("ThumbnailLoadTimer"); - private Optional lastThumbnailLoadTask = Optional.empty(); + private TimerTask lastThumbnailLoadTask = null; private final List tasks = new LinkedList<>(); @Nullable private Project project = null; - private Optional pageThumbnail = Optional.empty(); + private PageThumbnail pageThumbnail = null; private String lastTraineddataFile; @@ -179,9 +177,9 @@ private static void setLookAndFeel() { private Set changedPreprocessors = new HashSet<>(); - private Optional recognitionWorker = Optional.empty(); + private RecognitionWorker recognitionWorker = null; - public TesseractController() { + private TesseractController() { // create new tesseract frame view = new TesseractFrame(); featureDebugger = new FeatureDebugger(view); @@ -356,14 +354,15 @@ public void actionPerformed(ActionEvent evt) { } } - public Optional getPageModel() { + @Nullable + private Page getPage() { final MainComponent active = view.getActiveComponent(); - if (active instanceof PageModelComponent) { - return ((PageModelComponent) active).getPageModel(); + if (active instanceof PageComponent) { + return ((PageComponent) active).getPage(); } - return Optional.empty(); + return null; } public PageRecognitionProducer getPageRecognitionProducer() { @@ -375,14 +374,11 @@ public Project getProject() { return project; } - public Optional getSelectedPage() { + @Nullable + private Path getSelectedPage() { final PageThumbnail thumbnail = view.getPages().getList().getSelectedValue(); - if (thumbnail == null) { - return Optional.empty(); - } else { - return Optional.of(thumbnail.getFile()); - } + return Optional.ofNullable(thumbnail).map(PageThumbnail::getFile).orElse(null); } public Optional getTrainingFile() { @@ -404,9 +400,9 @@ private void handleActiveComponentChange() { if (mode == ApplicationMode.BOX_FILE) { // if we're in box file mode, everything is simple if (active == view.getBoxEditor()) { - view.getBoxEditor().setBoxFileModel(view.getSymbolOverview().getBoxFileModel()); + view.getBoxEditor().setBoxFile(view.getSymbolOverview().getBoxFile()); } else { - view.getSymbolOverview().setBoxFileModel(view.getBoxEditor().getBoxFileModel()); + view.getSymbolOverview().setBoxFile(view.getBoxEditor().getBoxFile()); } } else if (mode == ApplicationMode.PROJECT) { // in project mode, it's a bit more complicated @@ -414,28 +410,28 @@ private void handleActiveComponentChange() { if (active instanceof ImageModelComponent) { if (activeComponent instanceof ImageModelComponent) { // ImageModelComponent -> ImageModelComponent - setImageModel(((ImageModelComponent) activeComponent).getImageModel()); - } else if (activeComponent instanceof PageModelComponent) { - // PageModelComponent -> ImageModelComponent - final Optional pm = ((PageModelComponent) activeComponent).getPageModel(); + setImage(((ImageModelComponent) activeComponent).getImageModel()); + } else if (activeComponent instanceof PageComponent) { + // PageComponent -> ImageModelComponent + final Page pm = ((PageComponent) activeComponent).getPage(); - if (pm.isPresent()) { - setImageModel(Optional.of(pm.get().getImage())); + if (pm != null) { + setImage(pm.getImage()); } else { - setImageModel(Optional.empty()); + setImage(null); } } else { - setImageModel(Optional.empty()); + setImage(null); } - } else if (active instanceof PageModelComponent) { - if (activeComponent instanceof PageModelComponent) { - // PageModelComponent -> PageModelComponent - setPageModel(((PageModelComponent) activeComponent).getPageModel()); + } else if (active instanceof PageComponent) { + if (activeComponent instanceof PageComponent) { + // PageComponent -> PageComponent + setPage(((PageComponent) activeComponent).getPage()); } else if (activeComponent instanceof ImageModelComponent) { - // ImageModelComponent -> PageModelComponent - setImageModel(((ImageModelComponent) activeComponent).getImageModel()); + // ImageModelComponent -> PageComponent + setImage(((ImageModelComponent) activeComponent).getImageModel()); } else { - setPageModel(Optional.empty()); + setPage(null); } } } @@ -446,19 +442,23 @@ private void handleActiveComponentChange() { private void handleOpenProjectDirectory() { if (Desktop.isDesktopSupported()) { try { - Desktop.getDesktop().browse(project.getProjectDir().toUri()); + if (project != null) { + Desktop.getDesktop().browse(project.getProjectDir().toUri()); + } else { + Dialogs.showError(view, "Exception", "No project directory defined."); + } } catch (IOException e) { - Dialogs.showError(view, "Exception", - "Project directory could not be opened."); + Dialogs.showError(view, "Exception", "Project directory could not be opened."); } } } private void handleUseOCRResult() { - if (getPageModel().isPresent()) { + final Page page = getPage(); + if (page != null) { final StringWriter ocrResult = new StringWriter(); try { - new PlainTextWriter(true).write(getPageModel().get().getPage(), ocrResult); + new PlainTextWriter(true).write(page.getPage(), ocrResult); view.getEvaluationPane().getTextAreaTranscript().setText(ocrResult.toString()); } catch (IOException e) { @@ -531,11 +531,11 @@ private void handleBatchExport() { final Optional export = BatchExportDialog.showBatchExportDialog(this); if (export.isPresent()) { - final BatchExecutor batchExec = new BatchExecutor(this, this.getProject(), export.get()); + final Project project = this.getProject(); + final BatchExecutor batchExec = new BatchExecutor(this, project, export.get()); try { - final int totalFiles = - (int) Lists.newArrayList(this.getProject().getImageFiles()).stream().count(); + final int totalFiles = Lists.newArrayList(project.getImageFiles()).size(); final ProgressMonitor progressMonitor = new ProgressMonitor(view, "Processing:", "", 0, totalFiles + 1); progressMonitor.setProgress(0); @@ -556,9 +556,9 @@ private void handleBatchExport() { private void handleCompareSymbolToPrototype() { final Symbol selected = view.getSymbolOverview().getSymbolVariantList().getList().getSelectedValue(); - final Optional pm = getPageModel(); - if (pm.isPresent()) { - final BufferedImage pageImg = pm.get().getImage().getPreprocessedImage(); + final Page pm = getPage(); + if (pm != null) { + final BufferedImage pageImg = pm.getImage().getPreprocessedImage(); final Box symbolBox = selected.getBoundingBox(); final BufferedImage symbolImg = pageImg.getSubimage( symbolBox.getX(), symbolBox.getY(), @@ -579,7 +579,7 @@ private void handleGenerateReport() { return; } - final Path sourceFile = getPageModel().get().getImage().getSourceFile(); + final Path sourceFile = getPage().getImage().getSourceFile(); final Path fname = FileNames.replaceExtension(sourceFile, "txt").getFileName(); final Path repName = FileNames.replaceExtension(fname, "html"); final Path plain = project.getOCRDir().resolve(fname); @@ -633,13 +633,12 @@ public Path prepareReports() throws IOException { private Optional handleTranscriptionSave() { try { - if (project != null && getPageModel().isPresent()) { + final Page page = getPage(); + if (project != null && page != null) { Files.createDirectories(project.getTranscriptionDir()); - final Path sourceFile = - getPageModel().get().getImage().getSourceFile(); - final Path fileName = - FileNames.replaceExtension(sourceFile, "txt").getFileName(); + final Path sourceFile = page.getImage().getSourceFile(); + final Path fileName = FileNames.replaceExtension(sourceFile, "txt").getFileName(); final Path transcriptionFile = project.getTranscriptionDir().resolve(fileName); @@ -678,9 +677,8 @@ private void handleNewProject() { final DefaultListModel pages = view.getPages().getListModel(); - final ThumbnailWorker thumbnailLoader = new ThumbnailWorker(project, pages); + this.thumbnailLoader = new ThumbnailWorker(project, pages); thumbnailLoader.execute(); - this.thumbnailLoader = Optional.of(thumbnailLoader); final PageListWorker pageListLoader = new PageListWorker(project, pages); @@ -753,7 +751,7 @@ public boolean accept(File f) { PreferencesUtil.getPreferences().put(KEY_BOX_FILE, boxFile.toAbsolutePath().toString()); - setBoxFileModel(Optional.of(new BoxFile(boxFile, image, boxes))); + setBoxFile(new BoxFile(boxFile, image, boxes)); } catch (IOException | IndexOutOfBoundsException e) { Dialogs.showError(view, "Error", "Box file could not be opened."); } @@ -808,11 +806,11 @@ public boolean accept(File f) { } private void handleSaveBoxFile() { - final Optional boxFileModel = getBoxFileModel(); + final BoxFile boxFile = getBoxFile(); - if (boxFileModel.isPresent()) { + if (boxFile != null) { try { - BoxFileWriter.writeBoxFile(boxFileModel.get()); + BoxFileWriter.writeBoxFile(boxFile); Dialogs.showInfo(view, "Saved", "The box file has been saved."); } catch (IOException e) { @@ -823,25 +821,25 @@ private void handleSaveBoxFile() { } } - private Optional getBoxFileModel() { + @Nullable + private BoxFile getBoxFile() { if (mode == ApplicationMode.NONE) { - return Optional.empty(); + return null; } else if (mode == ApplicationMode.BOX_FILE) { // first check box editor, then symbol overview - final Optional model = view.getBoxEditor().getBoxFileModel(); - - if (model.isPresent()) { - return model; - } else { - return view.getSymbolOverview().getBoxFileModel(); + final TesseractFrame view = getView(); + if (view == null) { + return null; } + return Optional.ofNullable(view.getBoxEditor().getBoxFile()) + .orElseGet(() -> view.getSymbolOverview().getBoxFile()); } else { final MainComponent active = view.getActiveComponent(); - if (active instanceof PageModelComponent) { - return ((PageModelComponent) active).getBoxFileModel(); + if (active instanceof PageComponent) { + return ((PageComponent) active).getBoxFile(); } else { - return Optional.empty(); + return null; } } } @@ -850,7 +848,7 @@ private boolean handleCloseProject() { final boolean really = Dialogs.ask(view, "Confirmation", "Do you really want to close this project?"); if (really) { - setPageModel(Optional.empty()); + setPage(null); setProject(null); setApplicationMode(ApplicationMode.NONE); } @@ -863,7 +861,7 @@ private boolean handleCloseBoxFile() { "Do you really want to close this box file? All unsaved changes will be lost."); if (really) { - setBoxFileModel(Optional.empty()); + setBoxFile(null); setApplicationMode(ApplicationMode.NONE); } @@ -891,7 +889,7 @@ private void handlePageSelection() { if (!changePage) { // reselect the old page - view.getPages().getList().setSelectedValue(pageThumbnail.get(), true); + view.getPages().getList().setSelectedValue(pageThumbnail, true); // don't change the page return; } @@ -899,11 +897,11 @@ private void handlePageSelection() { view.getSymbolOverview().freeResources(); } - pageThumbnail = Optional.of(pt); + pageThumbnail = pt; // cancel the last page loading task if it is present - if (lastPageSelectionTask.isPresent()) { - lastPageSelectionTask.get().cancel(); + if (lastPageSelectionTask != null) { + lastPageSelectionTask.cancel(); } // new task @@ -911,18 +909,16 @@ private void handlePageSelection() { @Override public void run() { // cancel last task - if (preprocessingWorker.isPresent()) { - preprocessingWorker.get().cancel(false); + if (preprocessingWorker != null) { + preprocessingWorker.cancel(false); } // create SwingWorker to preprocess page - final PreprocessingWorker pw = new PreprocessingWorker( - TesseractController.this, - getPreprocessor(pt.getFile()), pt.getFile(), - getProject().getPreprocessedDir()); + final PreprocessingWorker pw = new PreprocessingWorker(TesseractController.this, + getPreprocessor(pt.getFile()), pt.getFile(), getProject().getPreprocessedDir()); // save reference - preprocessingWorker = Optional.of(pw); + preprocessingWorker = pw; view.getProgressBar().setIndeterminate(true); // execute it @@ -935,7 +931,7 @@ public void run() { pageSelectionTimer.schedule(task, 500); // set as new timer task - lastPageSelectionTask = Optional.of(task); + lastPageSelectionTask = task; } private void handleShowSymbolInBoxEditor() { @@ -961,8 +957,9 @@ private void handleShowSymbolInBoxEditor() { } private void handleSymbolGroupSelection() { - final JList>> selectionList = - view.getSymbolOverview().getSymbolGroupList().getList(); + final JList>> selectionList = view.getSymbolOverview() + .getSymbolGroupList() + .getList(); final int index = selectionList.getSelectedIndex(); if (index == -1) { @@ -971,13 +968,13 @@ private void handleSymbolGroupSelection() { final List symbols = selectionList.getModel().getElementAt(index).getValue(); - final Optional bfm = view.getSymbolOverview().getBoxFileModel(); + final BoxFile boxFile = view.getSymbolOverview().getBoxFile(); - if (!bfm.isPresent()) { + if (boxFile == null) { return; } - final SymbolListModel model = new SymbolListModel(bfm.get().getImage()); + final SymbolListModel model = new SymbolListModel(boxFile.getImage()); symbols.forEach(model::addElement); // get combo box @@ -1002,16 +999,18 @@ private void handleSymbolReordering() { } private void handleThumbnailLoading() { - if (!thumbnailLoader.isPresent()) { + if (thumbnailLoader == null) { return; } - final ThumbnailWorker thumbnailLoader = this.thumbnailLoader.get(); + final ThumbnailWorker thumbnailLoader = this.thumbnailLoader; tasks.forEach(Task::cancel); tasks.clear(); - lastThumbnailLoadTask.ifPresent(TimerTask::cancel); + if (lastThumbnailLoadTask != null) { + lastThumbnailLoadTask.cancel(); + } thumbnailLoadTimer.schedule(new TimerTask() { @Override @@ -1067,10 +1066,10 @@ private void handleTraineddataFileSelection() { } private void handlePreprocessorPreview() { - final Optional selectedPage = getSelectedPage(); + final Path selectedPage = getSelectedPage(); // if no page is selected, simply ignore it - if (!selectedPage.isPresent()) { + if (selectedPage == null) { Dialogs.showWarning(view, "No page selection", "No page has been selected. You need to select a page first."); return; @@ -1087,13 +1086,14 @@ private void handlePreprocessorPreview() { final Preprocessor preprocessor = view.getPreprocessingPane().getPreprocessor(); - preprocessingWorker.ifPresent(worker -> worker.cancel(false)); + if (preprocessingWorker != null) { + preprocessingWorker.cancel(false); + } - final PreprocessingWorker pw = new PreprocessingWorker(this, - preprocessor, selectedPage.get(), + final PreprocessingWorker pw = new PreprocessingWorker(this, preprocessor, selectedPage, project.getProjectDir()); - preprocessingWorker = Optional.of(pw); + preprocessingWorker = pw; view.getProgressBar().setIndeterminate(true); pw.execute(); @@ -1108,11 +1108,11 @@ private void handlePreprocessorChange(boolean allPages) { defaultPreprocessor = preprocessor; preprocessors.clear(); - if (getSelectedPage().isPresent()) { + if (getSelectedPage() != null) { handlePreprocessorPreview(); } - } else if (getSelectedPage().isPresent()) { - setPreprocessor(getSelectedPage().get(), preprocessor); + } else if (getSelectedPage() != null) { + setPreprocessor(getSelectedPage(), preprocessor); handlePreprocessorPreview(); } @@ -1235,12 +1235,14 @@ private void handleTesseractTrainer() { trainer.setVisible(true); } - public void setPageModel(Optional model) { - if (project != null && model.isPresent()) { + public void setPage(@Nullable final Page page) { + + Page updatedPage = page; + if (project != null && page != null) { try { // plain text file name final Path filename = - FileNames.replaceExtension(model.get().getImage().getSourceFile().getFileName(), "txt"); + FileNames.replaceExtension(page.getImage().getSourceFile().getFileName(), "txt"); // create ocr directory Files.createDirectories(project.getOCRDir()); @@ -1249,7 +1251,7 @@ public void setPageModel(Optional model) { final Path plain = project.getOCRDir().resolve(filename); final Writer writer = Files.newBufferedWriter(plain, StandardCharsets.UTF_8); - new PlainTextWriter(true).write(model.get().getPage(), writer); + new PlainTextWriter(true).write(page.getPage(), writer); writer.close(); // read the transcription file @@ -1259,7 +1261,7 @@ public void setPageModel(Optional model) { final byte[] bytes = Files.readAllBytes(transcriptionFile); final String transcription = new String(bytes, StandardCharsets.UTF_8); - model = Optional.of(model.get().withTranscription(transcription)); + updatedPage = page.withTranscription(transcription); } } catch (IOException e) { e.printStackTrace(); @@ -1268,35 +1270,34 @@ public void setPageModel(Optional model) { final MainComponent active = view.getActiveComponent(); - if (active instanceof PageModelComponent) { - ((PageModelComponent) active).setPageModel(model); - } else if (active instanceof BoxFileModelComponent) { - if (model.isPresent()) { - ((BoxFileModelComponent) active).setBoxFileModel(Optional.of(model.get().toBoxFileModel())); - } else { - ((BoxFileModelComponent) active).setBoxFileModel(Optional.empty()); - } + if (active instanceof PageComponent) { + ((PageComponent) active).setPage(updatedPage); + } + + if (active instanceof BoxFileComponent) { + final BoxFile boxFile = Optional.ofNullable(updatedPage).map(Page::toBoxFileModel).orElse(null); + ((BoxFileComponent) active).setBoxFile(boxFile); } } - public void setBoxFileModel(Optional model) { + private void setBoxFile(@Nullable BoxFile model) { final MainComponent active = view.getActiveComponent(); - if (active instanceof BoxFileModelComponent) { - ((BoxFileModelComponent) active).setBoxFileModel(model); + if (active instanceof BoxFileComponent) { + ((BoxFileComponent) active).setBoxFile(model); } else { Dialogs.showWarning(view, "Illegal Action", "Could not set the box file"); } } - public void setImageModel(Optional model) { + public void setImage(@Nullable Image model) { view.getProgressBar().setIndeterminate(false); final MainComponent active = view.getActiveComponent(); - if (active instanceof PageModelComponent) { - ((PageModelComponent) active).setPageModel(Optional.empty()); + if (active instanceof PageComponent) { + ((PageComponent) active).setPage(null); - if (recognitionWorker.isPresent()) { - recognitionWorker.get().cancel(false); + if (recognitionWorker != null) { + recognitionWorker.cancel(false); } final Optional trainingFile = getTrainingFile(); @@ -1304,32 +1305,31 @@ public void setImageModel(Optional model) { if (!trainingFile.isPresent()) { Dialogs.showWarning(view, "Warning", "Please select a traineddata file."); return; - } else if (!model.isPresent()) { + } else if (model == null) { return; } - final RecognitionWorker rw = new RecognitionWorker(this, model.get(), trainingFile.get()); + final RecognitionWorker rw = new RecognitionWorker(this, model, trainingFile.get()); rw.execute(); - recognitionWorker = Optional.of(rw); + recognitionWorker = rw; return; } else if (!(active instanceof ImageModelComponent)) { return; } - if (!model.isPresent()) { - ((ImageModelComponent) active).setImageModel(model); + if (model == null) { + ((ImageModelComponent) active).setImageModel(null); return; } - final Path sourceFile = model.get().getSourceFile(); - final Optional selectedPage = getSelectedPage(); + final Path sourceFile = model.getSourceFile(); + final Path selectedPage = getSelectedPage(); - if (!selectedPage.isPresent() || !sourceFile.equals(selectedPage.get())) { - - ((ImageModelComponent) active).setImageModel(Optional.empty()); + if (!sourceFile.equals(selectedPage)) { + ((ImageModelComponent) active).setImageModel(null); return; } @@ -1420,12 +1420,12 @@ public void windowClosing(WindowEvent e) { pageSelectionTimer.cancel(); thumbnailLoadTimer.cancel(); - if (preprocessingWorker.isPresent()) { - preprocessingWorker.get().cancel(true); + if (preprocessingWorker != null) { + preprocessingWorker.cancel(true); } - if (recognitionWorker.isPresent()) { - recognitionWorker.get().cancel(true); + if (recognitionWorker != null) { + recognitionWorker.cancel(true); } view.dispose(); @@ -1442,10 +1442,6 @@ public void windowClosed(WindowEvent evt) { } } - public Preprocessor getDefaultPreprocessor() { - return defaultPreprocessor; - } - public Preprocessor getPreprocessor(Path sourceFile) { final Preprocessor preprocessor = preprocessors.get(sourceFile); @@ -1461,11 +1457,7 @@ public boolean hasPreprocessorChanged(Path sourceFile) { return changedPreprocessors.contains(sourceFile); } - public void setDefaultPreprocessor(Preprocessor preprocessor) { - defaultPreprocessor = preprocessor; - } - - public void setPreprocessor(Path sourceFile, Preprocessor preprocessor) { + private void setPreprocessor(Path sourceFile, Preprocessor preprocessor) { if (preprocessor.equals(defaultPreprocessor)) { preprocessors.remove(sourceFile); } else { @@ -1473,15 +1465,7 @@ public void setPreprocessor(Path sourceFile, Preprocessor preprocessor) { } } - public void setPreprocessorChanged(Path sourceFile, boolean changed) { - if (changed) { - changedPreprocessors.add(sourceFile); - } else { - changedPreprocessors.remove(sourceFile); - } - } - - public void setApplicationMode(ApplicationMode mode) { + private void setApplicationMode(ApplicationMode mode) { this.mode = mode; final JTabbedPane mainTabs = view.getMainTabs(); @@ -1529,7 +1513,4 @@ public void setApplicationMode(ApplicationMode mode) { .setVisible(projectEnabled); } - public ApplicationMode getApplicationMode() { - return mode; - } } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/io/BoxFileWriter.java b/gui/src/main/java/de/vorb/tesseract/gui/io/BoxFileWriter.java index 69477b0a..ffda1dfe 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/io/BoxFileWriter.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/io/BoxFileWriter.java @@ -18,14 +18,13 @@ public final class BoxFileWriter { private BoxFileWriter() { } - public static void writeBoxFile(BoxFile model) throws IOException { - try ( - final BufferedWriter boxFileWriter = Files.newBufferedWriter(model.getFilePath(), - StandardCharsets.UTF_8, CREATE, TRUNCATE_EXISTING, WRITE)) { + public static void writeBoxFile(BoxFile boxFile) throws IOException { + try (final BufferedWriter boxFileWriter = Files.newBufferedWriter(boxFile.getFilePath(), + StandardCharsets.UTF_8, CREATE, TRUNCATE_EXISTING, WRITE)) { - final int pageHeight = model.getImage().getHeight(); + final int pageHeight = boxFile.getImage().getHeight(); - for (Symbol symbol : model.getBoxes()) { + for (Symbol symbol : boxFile.getBoxes()) { final Box boundingBox = symbol.getBoundingBox(); final int x0 = boundingBox.getX(); @@ -33,8 +32,7 @@ public static void writeBoxFile(BoxFile model) throws IOException { final int x1 = x0 + boundingBox.getWidth(); final int y1 = y0 + boundingBox.getHeight(); - boxFileWriter.write(String.format("%s %d %d %d %d 0\n", - symbol.getText(), x0, y0, x1, y1)); + boxFileWriter.write(String.format("%s %d %d %d %d 0\n", symbol.getText(), x0, y0, x1, y1)); } } } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/model/FilteredListModel.java b/gui/src/main/java/de/vorb/tesseract/gui/model/FilteredListModel.java index a86d247d..37c18504 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/model/FilteredListModel.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/model/FilteredListModel.java @@ -2,26 +2,26 @@ import de.vorb.tesseract.gui.util.Filter; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + import javax.swing.AbstractListModel; import javax.swing.ListModel; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; import java.util.ArrayList; -import java.util.Optional; public class FilteredListModel extends AbstractListModel { + private static final long serialVersionUID = 1L; private final ListModel source; private final ArrayList filtered = new ArrayList<>(); - // if filter is absent, all items are shown - private Optional> filter = Optional.empty(); + @NonNull + private Filter filter = createMatchAllFilter(); - public FilteredListModel(ListModel source) { - if (source == null) { - throw new IllegalArgumentException("model was null"); - } + public FilteredListModel(@NonNull ListModel source) { this.source = source; @@ -45,17 +45,14 @@ public void contentsChanged(ListDataEvent evt) { } private void applyFilter() { - if (filter.isPresent()) { - final Filter f = filter.get(); - filtered.clear(); - - // apply filter to every item in source model - final int sourceSize = source.getSize(); - for (int i = 0; i < sourceSize; ++i) { - final T item = source.getElementAt(i); - if (f.accept(item)) { - filtered.add(item); - } + filtered.clear(); + + // apply filter to every item in source model + final int sourceSize = source.getSize(); + for (int i = 0; i < sourceSize; ++i) { + final T item = source.getElementAt(i); + if (filter.accept(item)) { + filtered.add(item); } } @@ -63,34 +60,32 @@ private void applyFilter() { fireContentsChanged(this, 0, getSize() - 1); } - public void setFilter(Optional> filter) { + public void setFilter(@NonNull Filter filter) { this.filter = filter; applyFilter(); } + @Nullable @Override public T getElementAt(int index) { if (index < 0) { return null; } - if (!filter.isPresent()) { - return source.getElementAt(index); - } - return filtered.get(index); } @Override public int getSize() { - if (!filter.isPresent()) { - return source.getSize(); - } - return filtered.size(); } public ListModel getSource() { return source; } + + public static Filter createMatchAllFilter() { + return item -> true; + } + } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/model/PageModel.java b/gui/src/main/java/de/vorb/tesseract/gui/model/Page.java similarity index 78% rename from gui/src/main/java/de/vorb/tesseract/gui/model/PageModel.java rename to gui/src/main/java/de/vorb/tesseract/gui/model/Page.java index 1849a01f..3b3840fd 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/model/PageModel.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/model/Page.java @@ -1,6 +1,5 @@ package de.vorb.tesseract.gui.model; -import de.vorb.tesseract.util.Page; import de.vorb.tesseract.util.Symbol; import de.vorb.util.FileNames; @@ -9,19 +8,19 @@ import java.util.Iterator; import java.util.LinkedList; -public class PageModel { +public class Page { private final Image image; - private final Page page; + private final de.vorb.tesseract.util.Page page; private final String transcription; - public PageModel(Image image, Page page, String string) { + public Page(Image image, de.vorb.tesseract.util.Page page, String string) { this.image = image; this.page = page; this.transcription = string; } - public Page getPage() { + public de.vorb.tesseract.util.Page getPage() { return page; } @@ -33,12 +32,12 @@ public String getTranscription() { return transcription; } - public PageModel withTranscription(String transcription) { + public Page withTranscription(String transcription) { if (transcription.equals(this.transcription)) { return this; } - return new PageModel(image, page, transcription); + return new Page(image, page, transcription); } public BoxFile toBoxFileModel() { @@ -53,4 +52,5 @@ public BoxFile toBoxFileModel() { return new BoxFile(boxFile, image, boxes); } + } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/util/FilterProvider.java b/gui/src/main/java/de/vorb/tesseract/gui/util/FilterProvider.java index 353a1b69..fb7f7958 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/util/FilterProvider.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/util/FilterProvider.java @@ -3,5 +3,7 @@ import java.util.Optional; public interface FilterProvider { + Optional> getFilterFor(String filterText); + } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/BoxEditor.java b/gui/src/main/java/de/vorb/tesseract/gui/view/BoxEditor.java index b86c78cf..fcf3b836 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/BoxEditor.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/BoxEditor.java @@ -1,7 +1,7 @@ package de.vorb.tesseract.gui.view; import de.vorb.tesseract.gui.model.BoxFile; -import de.vorb.tesseract.gui.model.PageModel; +import de.vorb.tesseract.gui.model.Page; import de.vorb.tesseract.gui.model.Scale; import de.vorb.tesseract.gui.model.SingleSelectionModel; import de.vorb.tesseract.gui.model.SymbolTableModel; @@ -11,6 +11,8 @@ import de.vorb.tesseract.util.Point; import de.vorb.tesseract.util.Symbol; +import org.checkerframework.checker.nullness.qual.Nullable; + import javax.swing.DefaultListModel; import javax.swing.ImageIcon; import javax.swing.JButton; @@ -27,8 +29,6 @@ import javax.swing.ListSelectionModel; import javax.swing.UIManager; import javax.swing.border.EmptyBorder; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; import javax.swing.event.ListSelectionEvent; @@ -47,15 +47,13 @@ import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.util.ArrayList; import java.util.Iterator; -import java.util.List; import java.util.Optional; import static de.vorb.tesseract.gui.model.Scale.scaled; import static de.vorb.tesseract.gui.model.Scale.unscaled; -public class BoxEditor extends JPanel implements BoxFileModelComponent { +public class BoxEditor extends JPanel implements BoxFileComponent { private static final long serialVersionUID = 1L; private static final Dimension DEFAULT_SPINNER_DIMENSION = @@ -63,12 +61,12 @@ public class BoxEditor extends JPanel implements BoxFileModelComponent { private final BoxFileRenderer renderer; - // state private final Scale scale; private boolean changed = false; - private Optional model = Optional.empty(); - private Optional pageModel = Optional.empty(); + @Nullable + private BoxFile boxFile = null; + private Page page = null; private final SingleSelectionModel selectionModel = new SingleSelectionModel(); @@ -82,58 +80,7 @@ public class BoxEditor extends JPanel implements BoxFileModelComponent { private final JSpinner spinnerWidth; private final JSpinner spinnerHeight; - // events - private final List changeListeners = new ArrayList<>(); - - private final PropertyChangeListener spinnerListener = - new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - if (!evt.getPropertyName().startsWith("SPIN")) { - return; - } - - // don't do anything if no symbol is selected - final Optional currentSymbol = getSelectedSymbol(); - if (!currentSymbol.isPresent()) { - return; - } - - final Object source = evt.getSource(); - - // if the source is one of the JSpinners for x, y, width and - // height, update the bounding box - if (source instanceof JSpinner) { - // get coordinates - final int x = (int) spinnerX.getValue(); - final int y = (int) spinnerY.getValue(); - final int width = (int) spinnerWidth.getValue(); - final int height = (int) spinnerHeight.getValue(); - - // update bounding box - final Box boundingBox = currentSymbol.get().getBoundingBox(); - boundingBox.setX(x); - boundingBox.setY(y); - boundingBox.setWidth(width); - boundingBox.setHeight(height); - - // re-render the whole model - renderer.render(getBoxFileModel(), scale.current()); - } - - // propagate table change - final JTable table = tabSymbols.getTable(); - table.tableChanged(new TableModelEvent(table.getModel(), - table.getSelectedRow())); - - changed = true; - } - }; - - /** - * Create the panel. - */ - public BoxEditor(final Scale scale) { + BoxEditor(final Scale scale) { setLayout(new BorderLayout(0, 0)); renderer = new BoxFileRenderer(this); @@ -190,7 +137,7 @@ public void contentsChanged(ListDataEvent evt) { private void update() { long now = System.currentTimeMillis(); if (now - last > 1000) { - renderer.render(model, scale.current()); + renderer.render(boxFile, scale.current()); } last = now; } @@ -244,7 +191,7 @@ public void valueChanged(ListSelectionEvent e) { selectedRow, 0, true); tabSymbols.getTable().scrollRectToVisible(cell); - renderer.render(model, scale.current()); + renderer.render(boxFile, scale.current()); } }); @@ -256,11 +203,10 @@ public void valueChanged(ListSelectionEvent e) { JSplitPane splitMain = new JSplitPane(); add(splitMain, BorderLayout.CENTER); GridBagLayout gbl_toolbar = new GridBagLayout(); - gbl_toolbar.columnWidths = new int[]{0, 56, 15, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 36, 0, 0}; + gbl_toolbar.columnWidths = new int[]{0, 56, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0}; gbl_toolbar.rowHeights = new int[]{0, 0}; - gbl_toolbar.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, Double.MIN_VALUE}; + gbl_toolbar.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, + Double.MIN_VALUE}; gbl_toolbar.rowWeights = new double[]{0.0, Double.MIN_VALUE}; toolbar.setLayout(gbl_toolbar); @@ -402,7 +348,7 @@ public void valueChanged(ListSelectionEvent e) { btnZoomOut.addActionListener(evt -> { if (scale.hasPrevious()) { - renderer.render(getBoxFileModel(), scale.previous()); + renderer.render(getBoxFile(), scale.previous()); } if (!scale.hasPrevious()) { @@ -414,7 +360,7 @@ public void valueChanged(ListSelectionEvent e) { btnZoomIn.addActionListener(evt -> { if (scale.hasNext()) { - renderer.render(getBoxFileModel(), scale.next()); + renderer.render(getBoxFile(), scale.next()); } if (!scale.hasNext()) { @@ -452,7 +398,7 @@ public void mouseReleased(MouseEvent e) { } private void clicked(MouseEvent e) { - if (!model.isPresent()) { + if (boxFile == null) { // ignore clicks if no model is present return; } @@ -460,11 +406,9 @@ private void clicked(MouseEvent e) { final Point p = new Point(unscaled(e.getX(), scale.current()), unscaled(e.getY(), scale.current())); - final Iterator it = - model.get().getBoxes().iterator(); + final Iterator it = boxFile.getBoxes().iterator(); - final ListSelectionModel sel = - tabSymbols.getTable().getSelectionModel(); + final ListSelectionModel sel = tabSymbols.getTable().getSelectionModel(); boolean selection = false; for (int i = 0; it.hasNext(); i++) { @@ -485,7 +429,7 @@ private void clicked(MouseEvent e) { contextMenu.show(e.getComponent(), e.getX(), e.getY()); } - renderer.render(model, scale.current()); + renderer.render(boxFile, scale.current()); } }); @@ -518,6 +462,54 @@ private void clicked(MouseEvent e) { lblCanvas.scrollRectToVisible(boundingBox.toRectangle()); }); + // don't do anything if no symbol is selected + // if the source is one of the JSpinners for x, y, width and + // height, update the bounding box + // get coordinates + // update bounding box + // re-render the whole boxFile + // propagate table change + final PropertyChangeListener spinnerListener = (PropertyChangeEvent propertyChangeEvent) -> { + if (!propertyChangeEvent.getPropertyName().startsWith("SPIN")) { + return; + } + + // don't do anything if no symbol is selected + final Optional currentSymbol = getSelectedSymbol(); + if (!currentSymbol.isPresent()) { + return; + } + + final Object source = propertyChangeEvent.getSource(); + + // if the source is one of the JSpinners for x, y, width and + // height, update the bounding box + if (source instanceof JSpinner) { + // get coordinates + final int x = (int) spinnerX.getValue(); + final int y = (int) spinnerY.getValue(); + final int width = (int) spinnerWidth.getValue(); + final int height = (int) spinnerHeight.getValue(); + + // update bounding box + final Box boundingBox = currentSymbol.get().getBoundingBox(); + boundingBox.setX(x); + boundingBox.setY(y); + boundingBox.setWidth(width); + boundingBox.setHeight(height); + + // re-render the whole boxFile + renderer.render(getBoxFile(), scale.current()); + } + + // propagate table change + final JTable table1 = tabSymbols.getTable(); + table1.tableChanged(new TableModelEvent(table1.getModel(), + table1.getSelectedRow())); + + changed = true; + }; + spinnerX.addPropertyChangeListener(spinnerListener); spinnerY.addPropertyChangeListener(spinnerListener); spinnerWidth.addPropertyChangeListener(spinnerListener); @@ -525,8 +517,8 @@ private void clicked(MouseEvent e) { } @Override - public void setBoxFileModel(Optional model) { - this.model = model; + public void setBoxFile(@Nullable BoxFile boxFile) { + this.boxFile = boxFile; final SymbolTableModel tabModel = (SymbolTableModel) tabSymbols.getTable().getModel(); @@ -536,33 +528,27 @@ public void setBoxFileModel(Optional model) { source.clear(); - if (model.isPresent()) { + if (boxFile != null) { // fill table model and render the page - model.get().getBoxes().forEach(source::addElement); + boxFile.getBoxes().forEach(source::addElement); } - renderer.render(model, scale.current()); + renderer.render(boxFile, scale.current()); } - @Override - public void setPageModel(Optional model) { - if (model.isPresent()) { - setBoxFileModel(Optional.of(model.get().toBoxFileModel())); - pageModel = model; - } else { - setBoxFileModel(Optional.empty()); - pageModel = model; - } + public void setPage(Page page) { + this.page = page; + setBoxFile(Optional.ofNullable(page).map(Page::toBoxFileModel).orElse(null)); } @Override - public Optional getBoxFileModel() { - return model; + public @Nullable BoxFile getBoxFile() { + return null; } @Override - public Optional getPageModel() { - return pageModel; + public Page getPage() { + return page; } public JLabel getCanvas() { @@ -578,7 +564,7 @@ public Component asComponent() { return this; } - public Optional getSelectedSymbol() { + private Optional getSelectedSymbol() { final int index = tabSymbols.getTable().getSelectedRow(); if (index < 0) { @@ -589,49 +575,13 @@ public Optional getSelectedSymbol() { .getSymbol(index)); } - public JTextField getSymbolTextField() { - return tfSymbol; - } - - public JSpinner getXSpinner() { - return spinnerX; - } - - public JSpinner getYSpinner() { - return spinnerY; - } - - public JSpinner getWidthSpinner() { - return spinnerWidth; - } - - public JSpinner getHeightSpinner() { - return spinnerHeight; - } - - public void addChangeListener(ChangeListener listener) { - changeListeners.add(listener); - } - - public void removeChangeListener(ChangeListener listener) { - changeListeners.remove(listener); - } - public boolean hasChanged() { return changed; } - public void setChanged(boolean b) { - changed = b; - - final ChangeEvent evt = new ChangeEvent(this); - for (ChangeListener l : changeListeners) { - l.stateChanged(evt); - } - } - @Override public void freeResources() { lblCanvas.setIcon(null); } + } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/BoxFileCanvas.java b/gui/src/main/java/de/vorb/tesseract/gui/view/BoxFileCanvas.java index 827d5e13..f66363fa 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/BoxFileCanvas.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/BoxFileCanvas.java @@ -3,19 +3,21 @@ import de.vorb.tesseract.util.Box; import de.vorb.tesseract.util.Symbol; +import org.checkerframework.checker.nullness.qual.Nullable; + import javax.swing.ListModel; import java.awt.Graphics; import java.awt.Graphics2D; -import java.util.Optional; import static de.vorb.tesseract.gui.model.Scale.scaled; public class BoxFileCanvas extends Canvas { + private static final long serialVersionUID = 1L; private float scale; - private Optional> symbols = - Optional.empty(); + @Nullable + private ListModel symbols = null; private int selectedIndex = -1; public BoxFileCanvas() { @@ -25,8 +27,7 @@ public void setScale(float scale) { this.scale = scale; } - public void setSymbols(Optional> symbols, - int selectedIndex) { + public void setSymbols(@Nullable ListModel symbols, int selectedIndex) { this.symbols = symbols; this.selectedIndex = -1; } @@ -35,10 +36,10 @@ public void setSymbols(Optional> symbols, public void paintComponent(Graphics g) { super.paintComponent(g); - if (!this.symbols.isPresent()) + if (symbols == null) { return; + } - final ListModel symbols = this.symbols.get(); final int size = symbols.getSize(); for (int i = 0; i < size; i++) { diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/BoxFileComponent.java b/gui/src/main/java/de/vorb/tesseract/gui/view/BoxFileComponent.java new file mode 100644 index 00000000..407e92f0 --- /dev/null +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/BoxFileComponent.java @@ -0,0 +1,11 @@ +package de.vorb.tesseract.gui.view; + +import de.vorb.tesseract.gui.model.BoxFile; + +import org.checkerframework.checker.nullness.qual.Nullable; + +public interface BoxFileComponent extends PageComponent { + + void setBoxFile(@Nullable BoxFile model); + +} diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/BoxFileModelComponent.java b/gui/src/main/java/de/vorb/tesseract/gui/view/BoxFileModelComponent.java deleted file mode 100644 index fb65a12d..00000000 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/BoxFileModelComponent.java +++ /dev/null @@ -1,9 +0,0 @@ -package de.vorb.tesseract.gui.view; - -import de.vorb.tesseract.gui.model.BoxFile; - -import java.util.Optional; - -public interface BoxFileModelComponent extends PageModelComponent { - void setBoxFileModel(Optional model); -} diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/Canvas.java b/gui/src/main/java/de/vorb/tesseract/gui/view/Canvas.java index df2d98fc..5674f9d8 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/Canvas.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/Canvas.java @@ -1,24 +1,26 @@ package de.vorb.tesseract.gui.view; +import org.checkerframework.checker.nullness.qual.Nullable; + import javax.swing.JComponent; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Image; import java.awt.Rectangle; -import java.util.Optional; public class Canvas extends JComponent { private static final long serialVersionUID = 1L; private static final Dimension DIM_EMPTY = new Dimension(0, 0); - private Optional image = Optional.empty(); + @Nullable + private Image image = null; - public Canvas() { + Canvas() { } - public void setImage(Optional image) { + public void setImage(@Nullable Image image) { this.image = image; } @@ -26,9 +28,9 @@ public void setImage(Optional image) { public void paintComponent(Graphics g) { final Rectangle rect = getVisibleRect(); - if (image.isPresent()) { + if (image != null) { g.setClip(rect.x, rect.y, rect.width, rect.height); - g.drawImage(image.get(), 0, 0, null); + g.drawImage(image, 0, 0, null); } else { g.setColor(Color.WHITE); g.fillRect((int) rect.getX(), (int) rect.getY(), @@ -38,11 +40,10 @@ public void paintComponent(Graphics g) { @Override public Dimension getPreferredSize() { - if (!image.isPresent()) { + if (image == null) { return DIM_EMPTY; } - return new Dimension(image.get().getWidth(null), image.get().getHeight( - null)); + return new Dimension(image.getWidth(null), image.getHeight(null)); } } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/EvaluationPane.java b/gui/src/main/java/de/vorb/tesseract/gui/view/EvaluationPane.java index 5af7e163..8bc1e092 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/EvaluationPane.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/EvaluationPane.java @@ -1,10 +1,12 @@ package de.vorb.tesseract.gui.view; import de.vorb.tesseract.gui.model.BoxFile; -import de.vorb.tesseract.gui.model.PageModel; +import de.vorb.tesseract.gui.model.Page; import de.vorb.tesseract.gui.model.Scale; import de.vorb.tesseract.gui.view.renderer.EvaluationPaneRenderer; +import org.checkerframework.checker.nullness.qual.Nullable; + import javax.swing.Box; import javax.swing.ImageIcon; import javax.swing.JButton; @@ -24,9 +26,9 @@ import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.Optional; -public class EvaluationPane extends JPanel implements PageModelComponent { +public class EvaluationPane extends JPanel implements PageComponent { + private static final long serialVersionUID = 1L; private static final Insets BUTTON_MARGIN = new Insets(2, 4, 2, 4); @@ -34,7 +36,8 @@ public class EvaluationPane extends JPanel implements PageModelComponent { private final Scale scale; private final EvaluationPaneRenderer renderer; - private Optional model; + @Nullable + private Page model; private final JLabel lblOriginal; private final JTextArea textAreaTranscript; private final JButton btnSaveTranscription; @@ -44,12 +47,7 @@ public class EvaluationPane extends JPanel implements PageModelComponent { private final JButton btnZoomIn; private final JButton btnUseOcrResult; - /** - * Create the panel. - * - * @param scale - */ - public EvaluationPane(final Scale scale, final String editorFont) { + EvaluationPane(final Scale scale, final String editorFont) { setLayout(new BorderLayout(0, 0)); this.scale = scale; @@ -134,7 +132,7 @@ public EvaluationPane(final Scale scale, final String editorFont) { btnZoomOut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { if (scale.hasPrevious()) { - renderer.render(getPageModel(), scale.previous()); + renderer.render(getPage(), scale.previous()); } if (!scale.hasPrevious()) { @@ -175,7 +173,7 @@ public void actionPerformed(ActionEvent evt) { btnZoomIn.addActionListener(evt -> { if (scale.hasNext()) { - renderer.render(getPageModel(), scale.next()); + renderer.render(getPage(), scale.next()); } if (!scale.hasNext()) { @@ -212,14 +210,14 @@ public JTextArea getTextAreaTranscript() { } @Override - public void setPageModel(Optional model) { + public void setPage(@Nullable Page model) { this.model = model; renderer.render(model, scale.current()); } @Override - public Optional getPageModel() { + public @Nullable Page getPage() { return model; } @@ -229,15 +227,15 @@ public void freeResources() { } @Override - public Optional getBoxFileModel() { - if (model.isPresent()) { - return Optional.of(model.get().toBoxFileModel()); + public @Nullable BoxFile getBoxFile() { + if (model != null) { + return model.toBoxFileModel(); } else { - return Optional.empty(); + return null; } } - public void setEditorFont(String editorFont) { + public void setEditorFont(@Nullable String editorFont) { textAreaTranscript.setFont(new Font(editorFont, Font.PLAIN, 13)); } } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/FeatureDebugger.java b/gui/src/main/java/de/vorb/tesseract/gui/view/FeatureDebugger.java index 52142fa1..e5a0c9ca 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/FeatureDebugger.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/FeatureDebugger.java @@ -5,6 +5,8 @@ import de.vorb.tesseract.util.feat.Feature3D; import de.vorb.tesseract.util.feat.Feature4D; +import org.checkerframework.checker.nullness.qual.Nullable; + import javax.swing.ImageIcon; import javax.swing.JDialog; import javax.swing.JLabel; @@ -20,29 +22,23 @@ import java.awt.geom.Line2D.Double; import java.awt.image.BufferedImage; import java.util.List; -import java.util.Optional; public class FeatureDebugger extends JDialog { + private static final long serialVersionUID = 1L; private static final double PI2 = Math.PI + Math.PI; - private static final double FEATURE_RADIUS = 3.5d; + private static final double FEATURE_RADIUS = 3.5; private static final int WIDTH = 256; private static final int HEIGHT = 256; - private final JPanel contentPanel = new JPanel(); - private final BufferedImage canvas = new BufferedImage(WIDTH, HEIGHT, - BufferedImage.TYPE_INT_RGB); + private final BufferedImage canvas = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB); private final JLabel lblCanvas; private List features; - private Optional prototypes = Optional.empty(); + @Nullable + private IntTemplates prototypes = null; - /** - * Create the dialog. - * - * @param parent - */ public FeatureDebugger(Window parent) { super(parent); setLocationByPlatform(true); @@ -50,6 +46,7 @@ public FeatureDebugger(Window parent) { setModalityType(ModalityType.APPLICATION_MODAL); getContentPane().setLayout(new BorderLayout()); + final JPanel contentPanel = new JPanel(); contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); getContentPane().add(contentPanel, BorderLayout.CENTER); contentPanel.setLayout(new BorderLayout(0, 0)); @@ -68,10 +65,6 @@ public void setFeatures(List features) { redraw(); } - public void setPrototypes(Optional prototypes) { - this.prototypes = prototypes; - } - private void redraw() { final Graphics2D g2d = canvas.createGraphics(); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, @@ -81,11 +74,11 @@ private void redraw() { g2d.clearRect(0, 0, WIDTH, HEIGHT); final Double line = new Line2D.Double(0d, 0d, 0d, 0d); - if (prototypes.isPresent()) { - final List classes = prototypes.get().getClasses(); + if (prototypes != null) { + final List classes = prototypes.getClasses(); for (final Feature4D feat : classes.get(0).getProtoSets().get(0).getProtos()) { // transform the angle back to radians - final double angle = feat.getAngle() / 256d * PI2; + final double angle = feat.getAngle() / 256.0 * PI2; final double dx = Math.cos(angle) * feat.getC(); final double dy = Math.sin(angle) * feat.getC(); final double x1 = feat.getA(); diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/FilteredList.java b/gui/src/main/java/de/vorb/tesseract/gui/view/FilteredList.java index 1062fb53..2206a1a7 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/FilteredList.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/FilteredList.java @@ -71,7 +71,7 @@ private void filter() { filterField.getTextField().getText(); filteredModel.setFilter( - filterProvider.getFilterFor(query)); + filterProvider.getFilterFor(query).orElseGet(FilteredListModel::createMatchAllFilter)); } }); } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/FilteredTable.java b/gui/src/main/java/de/vorb/tesseract/gui/view/FilteredTable.java index b1e619c4..a8f95a8b 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/FilteredTable.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/FilteredTable.java @@ -1,5 +1,6 @@ package de.vorb.tesseract.gui.view; +import de.vorb.tesseract.gui.model.FilteredListModel; import de.vorb.tesseract.gui.model.FilteredTableModel; import de.vorb.tesseract.gui.util.FilterProvider; @@ -16,15 +17,13 @@ import java.awt.SystemColor; public class FilteredTable extends JPanel { + private static final long serialVersionUID = 1L; private final JTable table; private final SearchField filterField; - /** - * Create the panel. - */ - public FilteredTable(final FilteredTableModel model, + FilteredTable(final FilteredTableModel model, final FilterProvider filterProvider) { setLayout(new BorderLayout(0, 0)); @@ -73,7 +72,7 @@ private void filter() { filterField.getTextField().getText(); filteredModel.getSource().setFilter( - filterProvider.getFilterFor(query)); + filterProvider.getFilterFor(query).orElseGet(FilteredListModel::createMatchAllFilter)); } }); } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/ImageModelComponent.java b/gui/src/main/java/de/vorb/tesseract/gui/view/ImageModelComponent.java index d3e16124..7de378a8 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/ImageModelComponent.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/ImageModelComponent.java @@ -2,10 +2,13 @@ import de.vorb.tesseract.gui.model.Image; -import java.util.Optional; +import org.checkerframework.checker.nullness.qual.Nullable; public interface ImageModelComponent extends MainComponent { - void setImageModel(Optional model); - Optional getImageModel(); + void setImageModel(@Nullable Image model); + + @Nullable + Image getImageModel(); + } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/PageComponent.java b/gui/src/main/java/de/vorb/tesseract/gui/view/PageComponent.java new file mode 100644 index 00000000..0803d177 --- /dev/null +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/PageComponent.java @@ -0,0 +1,18 @@ +package de.vorb.tesseract.gui.view; + +import de.vorb.tesseract.gui.model.BoxFile; +import de.vorb.tesseract.gui.model.Page; + +import org.checkerframework.checker.nullness.qual.Nullable; + +public interface PageComponent extends MainComponent { + + void setPage(@Nullable Page model); + + @Nullable + Page getPage(); + + @Nullable + BoxFile getBoxFile(); + +} diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/PageModelComponent.java b/gui/src/main/java/de/vorb/tesseract/gui/view/PageModelComponent.java deleted file mode 100644 index a93cf293..00000000 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/PageModelComponent.java +++ /dev/null @@ -1,14 +0,0 @@ -package de.vorb.tesseract.gui.view; - -import de.vorb.tesseract.gui.model.BoxFile; -import de.vorb.tesseract.gui.model.PageModel; - -import java.util.Optional; - -public interface PageModelComponent extends MainComponent { - void setPageModel(Optional model); - - Optional getPageModel(); - - Optional getBoxFileModel(); -} diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/PageView.java b/gui/src/main/java/de/vorb/tesseract/gui/view/PageView.java deleted file mode 100644 index d624ae18..00000000 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/PageView.java +++ /dev/null @@ -1,11 +0,0 @@ -package de.vorb.tesseract.gui.view; - -import de.vorb.tesseract.gui.model.PageModel; - -import java.util.Optional; - -public interface PageView { - void setPageModel(Optional pageModel); - - Optional getPageModel(); -} diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/PreprocessingPane.java b/gui/src/main/java/de/vorb/tesseract/gui/view/PreprocessingPane.java index 937314b5..b17bbb61 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/PreprocessingPane.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/PreprocessingPane.java @@ -40,6 +40,7 @@ import java.util.Optional; public class PreprocessingPane extends JPanel implements ImageModelComponent { + private static final long serialVersionUID = 1L; private final JComboBox comboBinarization; @@ -54,12 +55,9 @@ public class PreprocessingPane extends JPanel implements ImageModelComponent { private final JButton btnApplyToPage; private final JButton btnApplyToAllPages; - private Optional imageModel = Optional.empty(); + private Image imageModel = null; - /** - * Create the panel. - */ - public PreprocessingPane() { + PreprocessingPane() { setBackground(Color.WHITE); setLayout(new BorderLayout(0, 0)); @@ -234,7 +232,7 @@ public JLabel getPreviewLabel() { return lblPreview; } - public Binarization getBinarization() { + private Binarization getBinarization() { final BinarizationMethod method = (BinarizationMethod) comboBinarization.getSelectedItem(); @@ -253,7 +251,7 @@ public Binarization getBinarization() { return binarization; } - public List getFilters() { + private List getFilters() { int min = (int) spinnerBlobMinSize.getModel().getValue(); int max = (int) spinnerBlobMaxSize.getModel().getValue(); @@ -303,18 +301,15 @@ public Component asComponent() { } @Override - public void setImageModel(Optional model) { + public void setImageModel(Image model) { imageModel = model; - if (model.isPresent()) { - lblPreview.setIcon(new ImageIcon(model.get().getPreprocessedImage())); - } else { - lblPreview.setIcon(null); - } + lblPreview.setIcon( + Optional.ofNullable(model).map(Image::getPreprocessedImage).map(ImageIcon::new).orElse(null)); } @Override - public Optional getImageModel() { + public Image getImageModel() { return imageModel; } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/RecognitionPane.java b/gui/src/main/java/de/vorb/tesseract/gui/view/RecognitionPane.java index af68358d..ca6c9d4b 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/RecognitionPane.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/RecognitionPane.java @@ -1,7 +1,7 @@ package de.vorb.tesseract.gui.view; import de.vorb.tesseract.gui.model.BoxFile; -import de.vorb.tesseract.gui.model.PageModel; +import de.vorb.tesseract.gui.model.Page; import de.vorb.tesseract.gui.model.Scale; import de.vorb.tesseract.gui.view.renderer.RecognitionRenderer; import de.vorb.tesseract.util.AlternativeChoice; @@ -9,6 +9,8 @@ import de.vorb.tesseract.util.Symbol; import de.vorb.tesseract.util.Word; +import org.checkerframework.checker.nullness.qual.Nullable; + import javax.swing.Box; import javax.swing.ImageIcon; import javax.swing.JButton; @@ -37,7 +39,7 @@ import java.util.Timer; import java.util.TimerTask; -public class RecognitionPane extends JPanel implements PageModelComponent { +public class RecognitionPane extends JPanel implements PageComponent { private static final long serialVersionUID = 1L; private static final int SCROLL_UNITS = 12; @@ -55,7 +57,8 @@ public class RecognitionPane extends JPanel implements PageModelComponent { private final JCheckBox cbLineNumbers; private final JCheckBox cbBaselines; - private Optional model = Optional.empty(); + @Nullable + private Page page = null; private final Timer delayer = new Timer(true); private JButton btZoomOut; @@ -299,7 +302,7 @@ public void itemStateChanged(ItemEvent ev) { RecognitionPane.class.getResource("/icons/zoom_out.png"))); btZoomOut.addActionListener(ev -> { if (scale.hasPrevious()) { - renderer.render(getPageModel(), scale.previous()); + renderer.render(getPage(), scale.previous()); } if (!scale.hasPrevious()) { @@ -321,7 +324,7 @@ public void itemStateChanged(ItemEvent ev) { RecognitionPane.class.getResource("/icons/zoom_in.png"))); btZoomIn.addActionListener(ev -> { if (scale.hasNext()) { - renderer.render(getPageModel(), scale.next()); + renderer.render(getPage(), scale.next()); } if (!scale.hasPrevious()) { @@ -356,25 +359,14 @@ public void itemStateChanged(ItemEvent ev) { } private Optional findSymbolAt(int x, int y) { - if (!model.isPresent()) { + if (page == null) { return Optional.empty(); } - final Iterator symbolIt = - model.get().getPage().symbolIterator(); + final Iterator symbolIt = page.getPage().symbolIterator(); while (symbolIt.hasNext()) { final Symbol symb = symbolIt.next(); - final de.vorb.tesseract.util.Box bbox = symb.getBoundingBox(); - - final int scaledX0 = Scale.scaled(bbox.getX(), scale.current()); - final int scaledY0 = Scale.scaled(bbox.getY(), scale.current()); - final int scaledX1 = scaledX0 - + Scale.scaled(bbox.getWidth(), scale.current()); - final int scaledY1 = scaledY0 - + Scale.scaled(bbox.getHeight(), scale.current()); - - if (x >= scaledX0 && x <= scaledX1 && y >= scaledY0 - && y <= scaledY1) { + if (boundingBoxContainsPoint(symb.getBoundingBox(), x, y)) { return Optional.of(symb); } } @@ -383,26 +375,15 @@ private Optional findSymbolAt(int x, int y) { } private Optional findWordAt(int x, int y) { - if (!model.isPresent()) { + if (page == null) { return Optional.empty(); } - final Iterator wordIt = - model.get().getPage().wordIterator(); + final Iterator wordIt = page.getPage().wordIterator(); while (wordIt.hasNext()) { final Word word = wordIt.next(); - final de.vorb.tesseract.util.Box bbox = word.getBoundingBox(); - - final int scaledX0 = Scale.scaled(bbox.getX(), scale.current()); - final int scaledY0 = Scale.scaled(bbox.getY(), scale.current()); - final int scaledX1 = scaledX0 - + Scale.scaled(bbox.getWidth(), scale.current()); - final int scaledY1 = scaledY0 - + Scale.scaled(bbox.getHeight(), scale.current()); - - if (x >= scaledX0 && x <= scaledX1 && y >= scaledY0 - && y <= scaledY1) { + if (boundingBoxContainsPoint(word.getBoundingBox(), x, y)) { return Optional.of(word); } } @@ -410,12 +391,24 @@ private Optional findWordAt(int x, int y) { return Optional.empty(); } - public Optional getPageModel() { - return model; + private boolean boundingBoxContainsPoint(de.vorb.tesseract.util.Box boundingBox, int x, int y) { + + final int scaledX0 = Scale.scaled(boundingBox.getX(), scale.current()); + final int scaledY0 = Scale.scaled(boundingBox.getY(), scale.current()); + final int scaledX1 = scaledX0 + Scale.scaled(boundingBox.getWidth(), scale.current()); + final int scaledY1 = scaledY0 + Scale.scaled(boundingBox.getHeight(), scale.current()); + + return x >= scaledX0 && x <= scaledX1 && y >= scaledY0 && y <= scaledY1; + } + + @Override + public @Nullable Page getPage() { + return page; } - public void setPageModel(Optional page) { - model = page; + @Override + public void setPage(@Nullable Page page) { + this.page = page; render(); } @@ -426,7 +419,7 @@ public void render() { delayer.schedule(new TimerTask() { @Override public void run() { - renderer.render(model, scale.current()); + renderer.render(page, scale.current()); } }, 200); } @@ -443,11 +436,11 @@ public void freeResources() { } @Override - public Optional getBoxFileModel() { - if (model.isPresent()) { - return Optional.of(model.get().toBoxFileModel()); + public @Nullable BoxFile getBoxFile() { + if (page != null) { + return page.toBoxFileModel(); } else { - return Optional.empty(); + return null; } } @@ -483,7 +476,7 @@ public JCheckBox getParagraphs() { return cbParagraphs; } - public void setRenderingFont(String renderingFont) { + public void setRenderingFont(@Nullable String renderingFont) { renderer.setRenderingFont(renderingFont); } } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/SymbolOverview.java b/gui/src/main/java/de/vorb/tesseract/gui/view/SymbolOverview.java index 19eab8f3..8cff536b 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/SymbolOverview.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/SymbolOverview.java @@ -1,11 +1,12 @@ package de.vorb.tesseract.gui.view; -import de.vorb.tesseract.gui.event.SymbolLinkListener; import de.vorb.tesseract.gui.model.BoxFile; -import de.vorb.tesseract.gui.model.PageModel; +import de.vorb.tesseract.gui.model.Page; import de.vorb.tesseract.gui.view.renderer.SymbolVariantListCellRenderer; import de.vorb.tesseract.util.Symbol; +import org.checkerframework.checker.nullness.qual.Nullable; + import javax.swing.DefaultListModel; import javax.swing.JList; import javax.swing.JPanel; @@ -13,40 +14,30 @@ import java.awt.BorderLayout; import java.awt.Component; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.HashMap; -import java.util.LinkedList; import java.util.List; import java.util.Map.Entry; import java.util.Optional; -public class SymbolOverview extends JPanel implements BoxFileModelComponent { +public class SymbolOverview extends JPanel implements BoxFileComponent { + private static final long serialVersionUID = 1L; private final SymbolGroupList glyphSelectionPane; private final SymbolVariantList glyphListPane; - private Optional model = Optional.empty(); - private Optional pageModel = Optional.empty(); + @Nullable + private BoxFile boxFile = null; + private Page page = null; - private final LinkedList listeners = new LinkedList<>(); - - public static final Comparator>> SYMBOL_GROUP_COMP = - (o1, o2) -> o2.getValue().size() - o1.getValue().size(); - - public static final Comparator SYMBOL_COMP = (o1, o2) -> { - if (o2.getConfidence() >= o1.getConfidence()) { - return 1; - } - - return -1; - }; + private static final Comparator>> SYMBOL_GROUP_COMP = + Comparator.comparingInt(symbolGroup -> symbolGroup.getValue().size()); /** * Create the panel. */ - public SymbolOverview() { + SymbolOverview() { super(); setLayout(new BorderLayout(0, 0)); @@ -60,18 +51,14 @@ public SymbolOverview() { splitPane.setRightComponent(glyphListPane); } - public void addSymbolLinkListener(SymbolLinkListener listener) { - listeners.add(listener); - } - @Override public Component asComponent() { return this; } @Override - public Optional getBoxFileModel() { - return model; + public @Nullable BoxFile getBoxFile() { + return boxFile; } public SymbolGroupList getSymbolGroupList() { @@ -83,12 +70,11 @@ public SymbolVariantList getSymbolVariantList() { } @Override - public void setBoxFileModel(Optional model) { - this.model = model; + public void setBoxFile(@Nullable BoxFile boxFile) { + this.boxFile = boxFile; - if (!model.isPresent()) { - glyphSelectionPane.getList().setModel( - new DefaultListModel<>()); + if (boxFile == null) { + glyphSelectionPane.getList().setModel(new DefaultListModel<>()); glyphListPane.getList().setModel(new DefaultListModel<>()); return; } @@ -98,8 +84,6 @@ public void setBoxFileModel(Optional model) { final HashMap> glyphs = new HashMap<>(); - final BoxFile boxFile = model.get(); - getSymbolVariantList().getList().setModel( new DefaultListModel<>()); @@ -121,7 +105,7 @@ public void setBoxFileModel(Optional model) { final ArrayList>> entries = new ArrayList<>( glyphs.entrySet()); - Collections.sort(entries, SYMBOL_GROUP_COMP); + entries.sort(SYMBOL_GROUP_COMP); final DefaultListModel>> listModel = new DefaultListModel<>(); @@ -132,26 +116,20 @@ public void setBoxFileModel(Optional model) { } @Override - public void setPageModel(Optional model) { - if (model.isPresent()) { - setBoxFileModel(Optional.of(model.get().toBoxFileModel())); - pageModel = model; - } else { - setBoxFileModel(Optional.empty()); - pageModel = model; - } + public void setPage(Page page) { + this.page = page; + setBoxFile(Optional.ofNullable(page).map(Page::toBoxFileModel).orElse(null)); } @Override - public Optional getPageModel() { - return pageModel; + public @Nullable Page getPage() { + return page; } @Override public void freeResources() { - getSymbolGroupList().getList().setModel( - new DefaultListModel<>()); - getSymbolVariantList().getList().setModel( - new DefaultListModel<>()); + getSymbolGroupList().getList().setModel(new DefaultListModel<>()); + getSymbolVariantList().getList().setModel(new DefaultListModel<>()); } + } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/TesseractFrame.java b/gui/src/main/java/de/vorb/tesseract/gui/view/TesseractFrame.java index 6ee2b806..04137b11 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/TesseractFrame.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/TesseractFrame.java @@ -9,6 +9,8 @@ import de.vorb.tesseract.gui.view.i18n.Labels; import de.vorb.tesseract.gui.view.renderer.PageListCellRenderer; +import org.checkerframework.checker.nullness.qual.NonNull; + import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JFrame; @@ -224,8 +226,7 @@ public TesseractFrame() { mnBatchExport = new JMenuItem("Batch Export..."); mnBatchExport.setEnabled(false); - mnBatchExport.setIcon(new ImageIcon( - TesseractFrame.class.getResource("/icons/book_next.png"))); + mnBatchExport.setIcon(new ImageIcon(TesseractFrame.class.getResource("/icons/book_next.png"))); mnBatchExport.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK)); mnFile.add(mnBatchExport); @@ -242,8 +243,7 @@ public TesseractFrame() { menuBar.add(mnEdit); mnPreferences = new JMenuItem("Preferences"); - mnPreferences.setIcon(new ImageIcon( - TesseractFrame.class.getResource("/icons/cog.png"))); + mnPreferences.setIcon(new ImageIcon(TesseractFrame.class.getResource("/icons/cog.png"))); mnEdit.add(mnPreferences); mnTools = new JMenu("Tools"); @@ -256,16 +256,15 @@ public TesseractFrame() { mnTools.add(mnInspectUnicharset); mnTesseractTrainer = new JMenuItem("Tesseract Trainer..."); - mnTesseractTrainer.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, - InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK)); + mnTesseractTrainer.setAccelerator( + KeyStroke.getKeyStroke(KeyEvent.VK_T, InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK)); mnTools.add(mnTesseractTrainer); final JMenu mnHelp = new JMenu( Labels.getLabel(getLocale(), "menu_help")); menuBar.add(mnHelp); - final JMenuItem mntmAbout = new JMenuItem(Labels.getLabel(getLocale(), - "menu_about")); + final JMenuItem mntmAbout = new JMenuItem(Labels.getLabel(getLocale(), "menu_about")); mntmAbout.setIcon(new ImageIcon( TesseractFrame.class.getResource("/icons/information.png"))); mntmAbout.addActionListener(e -> JOptionPane.showMessageDialog(TesseractFrame.this, @@ -304,10 +303,10 @@ public TesseractFrame() { gbc_lblScaleFactor.gridy = 0; panel.add(lblScaleFactor, gbc_lblScaleFactor); - GridBagConstraints gbc_pbRegognitionProgress = new GridBagConstraints(); - gbc_pbRegognitionProgress.gridx = 3; - gbc_pbRegognitionProgress.gridy = 0; - panel.add(pbLoadPage, gbc_pbRegognitionProgress); + GridBagConstraints gbc_pbRecognitionProgress = new GridBagConstraints(); + gbc_pbRecognitionProgress.gridx = 3; + gbc_pbRecognitionProgress.gridy = 0; + panel.add(pbLoadPage, gbc_pbRecognitionProgress); getContentPane().add(spMain, BorderLayout.CENTER); tabsMain = new JTabbedPane(); @@ -424,7 +423,7 @@ public JLabel getScaleLabel() { return lblScaleFactor; } - public SymbolOverview getSymbolOverview() { + public @NonNull SymbolOverview getSymbolOverview() { return glyphOverview; } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/dialogs/Dialogs.java b/gui/src/main/java/de/vorb/tesseract/gui/view/dialogs/Dialogs.java index 8f88bb42..4c26db77 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/dialogs/Dialogs.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/dialogs/Dialogs.java @@ -1,33 +1,31 @@ package de.vorb.tesseract.gui.view.dialogs; +import com.drew.lang.annotations.NotNull; +import org.checkerframework.checker.nullness.qual.Nullable; + import javax.swing.JOptionPane; import java.awt.Component; public final class Dialogs { - private Dialogs() {} + private Dialogs() { + } - public static void showInfo(Component parent, String title, - String message) { - JOptionPane.showMessageDialog(parent, message, title, - JOptionPane.INFORMATION_MESSAGE); + public static void showInfo(@Nullable Component parent, @NotNull String title, @NotNull String message) { + JOptionPane.showMessageDialog(parent, message, title, JOptionPane.INFORMATION_MESSAGE); } - public static void showWarning(Component parent, String title, - String message) { - JOptionPane.showMessageDialog(parent, message, title, - JOptionPane.WARNING_MESSAGE); + public static void showWarning(@Nullable Component parent, @NotNull String title, @NotNull String message) { + JOptionPane.showMessageDialog(parent, message, title, JOptionPane.WARNING_MESSAGE); } - public static void showError(Component parent, String title, - String message) { - JOptionPane.showMessageDialog(parent, message, title, - JOptionPane.ERROR_MESSAGE); + public static void showError(@Nullable Component parent, @NotNull String title, @NotNull String message) { + JOptionPane.showMessageDialog(parent, message, title, JOptionPane.ERROR_MESSAGE); } - public static boolean ask(Component parent, String title, String question) { - int result = JOptionPane.showConfirmDialog(parent, question, title, - JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); + public static boolean ask(@Nullable Component parent, @NotNull String title, @NotNull String question) { + final int result = JOptionPane.showConfirmDialog(parent, question, title, JOptionPane.OK_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE); return result == JOptionPane.OK_OPTION; } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/BoxFileRenderer.java b/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/BoxFileRenderer.java index 6d25488a..2c023bc3 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/BoxFileRenderer.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/BoxFileRenderer.java @@ -7,13 +7,14 @@ import de.vorb.tesseract.util.Box; import de.vorb.tesseract.util.Symbol; +import org.checkerframework.checker.nullness.qual.Nullable; + import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.ListModel; import javax.swing.SwingWorker; import java.awt.Graphics2D; import java.awt.image.BufferedImage; -import java.util.Optional; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; @@ -22,17 +23,18 @@ public class BoxFileRenderer { private final BoxEditor boxEditor; + @Nullable private SwingWorker renderWorker; public BoxFileRenderer(BoxEditor boxEditor) { this.boxEditor = boxEditor; } - public void render(final Optional model, final float scale) { - if (!model.isPresent()) { + public void render(@Nullable final BoxFile boxFile, final float scale) { + if (boxFile == null) { // remove image, if no page model is given and free resources final Icon icon = boxEditor.getCanvas().getIcon(); - if (icon != null && icon instanceof ImageIcon) { + if (icon instanceof ImageIcon) { ((ImageIcon) icon).getImage().flush(); } @@ -43,9 +45,8 @@ public void render(final Optional model, final float scale) { return; } - // TODO add a version of render() that takes two rectangles and a new - // box and updates the necessary area only - final BufferedImage image = model.get().getImage(); + // TODO add a version of render() that takes two rectangles and a new box and updates the necessary area only + final BufferedImage image = boxFile.getImage(); // calculate image dimensions final int w = image.getWidth(); @@ -83,7 +84,7 @@ public void render(final Optional model, final float scale) { // worker that renders the boxes to a new buffered image renderWorker = new SwingWorker() { @Override - protected BufferedImage doInBackground() throws Exception { + protected BufferedImage doInBackground() { final BufferedImage rendered = new BufferedImage(scaledW, scaledH, BufferedImage.TYPE_INT_RGB); @@ -94,8 +95,7 @@ protected BufferedImage doInBackground() throws Exception { g2d.setStroke(Strokes.NORMAL); // draw the scaled image - g2d.drawImage(image, 0, 0, scaledW, scaledH, 0, 0, - w - 1, h - 1, null); + g2d.drawImage(image, 0, 0, scaledW, scaledH, 0, 0, w - 1, h - 1, null); for (final Symbol symbol : symbols) { final boolean isSelected = symbol == selectedSymbol; diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/EvaluationPaneRenderer.java b/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/EvaluationPaneRenderer.java index 02c43e9b..73516f9c 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/EvaluationPaneRenderer.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/EvaluationPaneRenderer.java @@ -1,15 +1,17 @@ package de.vorb.tesseract.gui.view.renderer; -import de.vorb.tesseract.gui.model.PageModel; +import de.vorb.tesseract.gui.model.Page; import de.vorb.tesseract.gui.model.Scale; import de.vorb.tesseract.gui.view.EvaluationPane; +import org.checkerframework.checker.nullness.qual.Nullable; + import javax.swing.ImageIcon; import java.awt.Image; import java.awt.image.BufferedImage; -import java.util.Optional; public class EvaluationPaneRenderer implements PageRenderer { + private final EvaluationPane evaluationPane; public EvaluationPaneRenderer(EvaluationPane evaluationPane) { @@ -17,28 +19,25 @@ public EvaluationPaneRenderer(EvaluationPane evaluationPane) { } @Override - public void render(Optional pageModel, float scale) { - final boolean modelPresent = pageModel.isPresent(); + public void render(@Nullable Page page, float scale) { + final boolean modelPresent = page != null; evaluationPane.getSaveTranscriptionButton().setEnabled(modelPresent); evaluationPane.getGenerateReportButton().setEnabled(modelPresent); evaluationPane.getTextAreaTranscript().setEnabled(modelPresent); if (modelPresent) { - final BufferedImage img = - pageModel.get().getImage().getSourceImage(); + final BufferedImage img = page.getImage().getSourceImage(); final int w = Scale.scaled(img.getWidth(), scale); final int h = Scale.scaled(img.getHeight(), scale); - evaluationPane.getOriginal().setIcon( - new ImageIcon(img.getScaledInstance(w, h, - Image.SCALE_SMOOTH))); - evaluationPane.getTextAreaTranscript().setText( - pageModel.get().getTranscription()); + evaluationPane.getOriginal().setIcon(new ImageIcon(img.getScaledInstance(w, h, Image.SCALE_SMOOTH))); + evaluationPane.getTextAreaTranscript().setText(page.getTranscription()); } else { evaluationPane.getOriginal().setIcon(null); evaluationPane.getTextAreaTranscript().setText(""); } } + } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/PageRenderer.java b/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/PageRenderer.java index cd2267bf..72617582 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/PageRenderer.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/PageRenderer.java @@ -1,21 +1,11 @@ package de.vorb.tesseract.gui.view.renderer; -import de.vorb.tesseract.gui.model.PageModel; +import de.vorb.tesseract.gui.model.Page; -import java.util.Optional; +import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Page renderer. - * - * @author Paul Vorbach - */ public interface PageRenderer { - /** - * Renders the information of a page on an optionally given background. - * - * @param pageModel page model to render - * @param scale scaling factor - */ - void render(final Optional pageModel, final float scale); + void render(@Nullable final Page page, final float scale); + } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/RecognitionRenderer.java b/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/RecognitionRenderer.java index dfe28803..7c026011 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/RecognitionRenderer.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/renderer/RecognitionRenderer.java @@ -1,6 +1,6 @@ package de.vorb.tesseract.gui.view.renderer; -import de.vorb.tesseract.gui.model.PageModel; +import de.vorb.tesseract.gui.model.Page; import de.vorb.tesseract.gui.view.Colors; import de.vorb.tesseract.gui.view.RecognitionPane; import de.vorb.tesseract.util.Baseline; @@ -8,11 +8,12 @@ import de.vorb.tesseract.util.Box; import de.vorb.tesseract.util.FontAttributes; import de.vorb.tesseract.util.Line; -import de.vorb.tesseract.util.Page; import de.vorb.tesseract.util.Paragraph; import de.vorb.tesseract.util.Symbol; import de.vorb.tesseract.util.Word; +import org.checkerframework.checker.nullness.qual.Nullable; + import javax.swing.ImageIcon; import javax.swing.SwingWorker; import java.awt.Color; @@ -21,7 +22,6 @@ import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.util.Iterator; -import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import static de.vorb.tesseract.gui.model.Scale.scaled; @@ -33,12 +33,19 @@ public class RecognitionRenderer implements PageRenderer { private static final Font FONT_LINE_NUMBERS = new Font("Dialog", Font.PLAIN, DEFAULT_FONT_SIZE); private final RecognitionPane recognitionPane; + + @Nullable private SwingWorker renderWorker; - private PageModel lastPageModel = null; + @Nullable + private Page lastPage = null; + + @Nullable private BufferedImage original = null; + + @Nullable private BufferedImage recognition = null; - private float minimumConfidence = 0; + private float lastScale; private final AtomicReference fontNormal = new AtomicReference<>(); @@ -52,28 +59,21 @@ public RecognitionRenderer(RecognitionPane pane, String renderingFont) { setRenderingFont(renderingFont); } - public void setRenderingFont(String renderingFont) { - final String selectedFontFamily = renderingFont; - - fontNormal.set(new Font(selectedFontFamily, Font.PLAIN, DEFAULT_FONT_SIZE)); - fontBold.set(new Font(selectedFontFamily, Font.BOLD, DEFAULT_FONT_SIZE)); - fontItalic.set(new Font(selectedFontFamily, Font.ITALIC, DEFAULT_FONT_SIZE)); - fontBoldItalic.set(new Font(selectedFontFamily, Font.BOLD | Font.ITALIC, DEFAULT_FONT_SIZE)); - } - - public void setMinimumConfidence(float min) { - this.minimumConfidence = min; + public void setRenderingFont(@Nullable String renderingFont) { + fontNormal.set(new Font(renderingFont, Font.PLAIN, DEFAULT_FONT_SIZE)); + fontBold.set(new Font(renderingFont, Font.BOLD, DEFAULT_FONT_SIZE)); + fontItalic.set(new Font(renderingFont, Font.ITALIC, DEFAULT_FONT_SIZE)); + fontBoldItalic.set(new Font(renderingFont, Font.BOLD | Font.ITALIC, DEFAULT_FONT_SIZE)); } @Override - public void render(Optional pageModel, final float scale) { - if (renderWorker != null && !renderWorker.isCancelled() - && !renderWorker.isDone()) { + public void render(@Nullable Page page, final float scale) { + if (renderWorker != null && !renderWorker.isCancelled() && !renderWorker.isDone()) { renderWorker.cancel(true); } // if no page model is present, remove the images and render worker - if (!pageModel.isPresent()) { + if (page == null) { renderWorker = null; recognitionPane.getCanvasOriginal().setIcon(null); @@ -85,18 +85,17 @@ public void render(Optional pageModel, final float scale) { return; } - final Page page = pageModel.get().getPage(); - final BufferedImage preprocessed = - pageModel.get().getImage().getPreprocessedImage(); + final de.vorb.tesseract.util.Page internalPage = page.getPage(); + final BufferedImage preprocessed = page.getImage().getPreprocessedImage(); final int width = preprocessed.getWidth(); final int height = preprocessed.getHeight(); final int scaledWidth; final int scaledHeight; - if (lastPageModel != pageModel.get() || lastScale != scale) { + if (lastPage != page || lastScale != scale) { // prepare the images if the model has changed - lastPageModel = pageModel.get(); + lastPage = page; lastScale = scale; // calculate the width and height of the scene @@ -114,12 +113,6 @@ public void render(Optional pageModel, final float scale) { scaledHeight = original.getHeight(); } - // set the base fonts - final Font baseFontNormal; - final Font baseFontItalic; - final Font baseFontBold; - final Font baseFontBoldItalic; - final boolean showWordBoxes = recognitionPane.getWordBoxes().isSelected(); final boolean showSymbolBoxes = recognitionPane.getSymbolBoxes().isSelected(); final boolean showLineNumbers = recognitionPane.getLineNumbers().isSelected(); @@ -137,8 +130,7 @@ private void drawLineNumber(final Line line, final int lineNumber) { final String num = String.valueOf(lineNumber); final int x = scaled(20, scale); - final int y = scaled(box.getY() + box.getHeight() - - line.getBaseline().getYOffset(), scale); + final int y = scaled(box.getY() + box.getHeight() - line.getBaseline().getYOffset(), scale); origGfx.setFont(FONT_LINE_NUMBERS); origGfx.setPaint(Colors.LINE_NUMBER); @@ -149,7 +141,7 @@ private void drawLineNumber(final Line line, final int lineNumber) { recogGfx.drawString(num, x, y); } - private void drawWord(final Line line, final Word word) { + private void drawWord(final Word word) { // bounding box final Box box = word.getBoundingBox(); @@ -181,7 +173,7 @@ private void drawWord(final Line line, final Word word) { final int scH = scaled(bH, scale); // text coordinates - final int tx = scX; + @SuppressWarnings("UnnecessaryLocalVariable") final int tx = scX; final int ty = scaled(bY + bH - word.getBaseline().getYOffset(), scale); // set font @@ -190,7 +182,7 @@ private void drawWord(final Line line, final Word word) { font = fontNormal.get().deriveFont(scFontSize); } else if (italic && !bold) { font = fontItalic.get().deriveFont(scFontSize); - } else if (bold && !italic) { + } else if (!italic) { font = fontBold.get().deriveFont(scFontSize); } else { font = fontBoldItalic.get().deriveFont(scFontSize); @@ -205,7 +197,7 @@ private void drawWord(final Line line, final Word word) { if (showWordBoxes) { origGfx.drawRect(scX, scY, scW, scH); recogGfx.drawRect(scX, scY, scW, scH); - } else if (showSymbolBoxes) { + } else { for (final Symbol sym : word.getSymbols()) { final Box symbolBoundingBox = sym.getBoundingBox(); @@ -258,7 +250,7 @@ private void drawWord(final Line line, final Word word) { } @Override - protected Void doInBackground() throws Exception { + protected Void doInBackground() { // init graphics contexts origGfx = original.createGraphics(); recogGfx = recognition.createGraphics(); @@ -277,7 +269,7 @@ protected Void doInBackground() throws Exception { if (showBlocks) { origGfx.setPaint(Colors.BLOCK); recogGfx.setPaint(Colors.BLOCK); - final Iterator blocks = page.blockIterator(); + final Iterator blocks = internalPage.blockIterator(); while (blocks.hasNext()) { final Block block = blocks.next(); final Box boundingBox = block.getBoundingBox(); @@ -295,7 +287,7 @@ protected Void doInBackground() throws Exception { if (showParagraphs) { origGfx.setPaint(Colors.PARAGRAPH); recogGfx.setPaint(Colors.PARAGRAPH); - final Iterator paragraphs = page.paragraphIterator(); + final Iterator paragraphs = internalPage.paragraphIterator(); while (paragraphs.hasNext()) { final Paragraph paragraph = paragraphs.next(); final Box boundingBox = paragraph.getBoundingBox(); @@ -311,7 +303,7 @@ protected Void doInBackground() throws Exception { } int lineNumber = 1; - final Iterator lines = page.lineIterator(); + final Iterator lines = internalPage.lineIterator(); while (lines.hasNext()) { final Line line = lines.next(); if (scale >= 0.5f && showLineNumbers) { @@ -323,7 +315,7 @@ protected Void doInBackground() throws Exception { RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); for (final Word word : line.getWords()) { - drawWord(line, word); + drawWord(word); } lineNumber++; @@ -336,8 +328,7 @@ protected Void doInBackground() throws Exception { protected void done() { try { recognitionPane.getCanvasOriginal().setIcon(new ImageIcon(original)); - recognitionPane.getCanvasRecognition().setIcon( - new ImageIcon(recognition)); + recognitionPane.getCanvasRecognition().setIcon(new ImageIcon(recognition)); } catch (Exception e) { } finally { System.gc(); @@ -348,7 +339,4 @@ protected void done() { renderWorker.execute(); } - public void freeResources() { - lastPageModel = null; - } } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/work/BatchExecutor.java b/gui/src/main/java/de/vorb/tesseract/gui/work/BatchExecutor.java index 55855b23..94552041 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/work/BatchExecutor.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/work/BatchExecutor.java @@ -12,6 +12,7 @@ import eu.digitisation.input.Parameters; import eu.digitisation.input.WarningException; import eu.digitisation.output.Report; +import org.checkerframework.checker.nullness.qual.NonNull; import javax.swing.ProgressMonitor; import javax.swing.SwingUtilities; @@ -42,8 +43,8 @@ public class BatchExecutor { private final Project project; private final BatchExport batchExport; - public BatchExecutor(TesseractController controller, Project project, - BatchExport batchExport) { + public BatchExecutor(@NonNull TesseractController controller, @NonNull Project project, + @NonNull BatchExport batchExport) { this.controller = controller; this.project = project; diff --git a/gui/src/main/java/de/vorb/tesseract/gui/work/PageRecognitionProducer.java b/gui/src/main/java/de/vorb/tesseract/gui/work/PageRecognitionProducer.java index 2701c9f0..c1a6d527 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/work/PageRecognitionProducer.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/work/PageRecognitionProducer.java @@ -22,11 +22,11 @@ import java.util.LinkedList; import java.util.List; import java.util.Map.Entry; -import java.util.Optional; public class PageRecognitionProducer extends RecognitionProducer { + private final Path tessdataDir; - private Optional lastPix = Optional.empty(); + private lept.PIX lastPix = null; private final TesseractController controller; private final HashMap variables = new HashMap<>(); @@ -75,34 +75,34 @@ public void reset() throws IOException { } @Override - public void close() throws IOException { + public void close() { tesseract.TessBaseAPIDelete(getHandle()); } - public void loadImage(Path imageFile) { - if (lastPix.isPresent()) { + void loadImage(Path imageFile) { + if (lastPix != null) { // destroy old pix - lept.pixDestroy(lastPix.get()); + lept.pixDestroy(lastPix); } final lept.PIX pix = lept.pixRead(imageFile.toString()); tesseract.TessBaseAPISetImage2(getHandle(), pix); - lastPix = Optional.of(pix); + lastPix = pix; } - public Optional getImage() { + public lept.PIX getImage() { return lastPix; } - public Optional getThresholdedImage() { - return Optional.ofNullable(tesseract.TessBaseAPIGetThresholdedImage(getHandle())); + public lept.PIX getThresholdedImage() { + return tesseract.TessBaseAPIGetThresholdedImage(getHandle()); } public List getFeaturesForSymbol(BufferedImage symbol) { - if (!lastPix.isPresent()) { - return new LinkedList<>(); + if (lastPix == null) { + return Collections.emptyList(); } final int padding = 5; @@ -164,7 +164,4 @@ public List getFeaturesForSymbol(BufferedImage symbol) { } } - public void setVariable(String key, String value) { - variables.put(key, value); - } } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/work/PreprocessingWorker.java b/gui/src/main/java/de/vorb/tesseract/gui/work/PreprocessingWorker.java index f04bacc3..8bbbb66b 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/work/PreprocessingWorker.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/work/PreprocessingWorker.java @@ -5,12 +5,13 @@ import de.vorb.tesseract.tools.preprocessing.Preprocessor; import de.vorb.util.FileNames; +import org.checkerframework.checker.nullness.qual.NonNull; + import javax.imageio.ImageIO; import javax.swing.SwingWorker; import java.awt.image.BufferedImage; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Optional; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; @@ -21,7 +22,7 @@ public class PreprocessingWorker extends SwingWorker { private final Path destinationDir; public PreprocessingWorker(TesseractController controller, - Preprocessor preprocessor, Path sourceFile, Path destinationDir) { + Preprocessor preprocessor, Path sourceFile, @NonNull Path destinationDir) { this.controller = controller; this.preprocessor = preprocessor; this.sourceFile = sourceFile; @@ -46,9 +47,8 @@ protected Image doInBackground() throws Exception { @Override protected void done() { try { - controller.setImageModel(Optional.of(get())); - } catch (InterruptedException | ExecutionException - | CancellationException e) { + controller.setImage(get()); + } catch (InterruptedException | ExecutionException | CancellationException e) { } finally { controller.getView().getProgressBar().setIndeterminate(false); } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/work/RecognitionWorker.java b/gui/src/main/java/de/vorb/tesseract/gui/work/RecognitionWorker.java index 5ed0809e..9543c1d9 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/work/RecognitionWorker.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/work/RecognitionWorker.java @@ -2,21 +2,19 @@ import de.vorb.tesseract.gui.controller.TesseractController; import de.vorb.tesseract.gui.model.Image; -import de.vorb.tesseract.gui.model.PageModel; +import de.vorb.tesseract.gui.model.Page; import de.vorb.tesseract.gui.view.dialogs.Dialogs; import de.vorb.tesseract.tools.recognition.PageRecognitionConsumer; import de.vorb.tesseract.util.Block; -import de.vorb.tesseract.util.Page; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.List; -import java.util.Optional; import java.util.concurrent.ExecutionException; -public class RecognitionWorker extends SwingWorker { +public class RecognitionWorker extends SwingWorker { private final TesseractController controller; private final Image image; private final String trainingFile; @@ -31,10 +29,10 @@ public RecognitionWorker(TesseractController controller, } @Override - protected PageModel doInBackground() throws Exception { + protected Page doInBackground() throws Exception { // set the progress bar state to indeterminate SwingUtilities.invokeLater(() -> { - controller.setPageModel(Optional.empty()); + controller.setPage(null); controller.getView().getProgressBar().setIndeterminate(true); }); @@ -58,22 +56,22 @@ public boolean isCancelled() { } }); - final Page page = new Page(this.image.getPreprocessedFile(), + final de.vorb.tesseract.util.Page page = new de.vorb.tesseract.util.Page(this.image.getPreprocessedFile(), image.getWidth(), image.getHeight(), 300, blocks); - return new PageModel(this.image, page, ""); + return new Page(this.image, page, ""); } @Override protected void done() { try { - controller.setPageModel(Optional.of(get())); + controller.setPage(get()); } catch (ExecutionException e) { e.printStackTrace(); final String message = "The image could not be recognized"; - controller.setPageModel(Optional.empty()); + controller.setPage(null); Dialogs.showError(controller.getView(), "Error during recognition", message); From 34fd57cfaa314a1038eca10d514dd99e6c226b68 Mon Sep 17 00:00:00 2001 From: Paul Vorbach Date: Sat, 13 Jul 2019 22:52:16 +0200 Subject: [PATCH 4/4] Improve IO related code --- .../gui/controller/TesseractController.java | 99 ++++++++++--------- .../vorb/tesseract/gui/io/BoxFileReader.java | 41 ++++---- .../de/vorb/tesseract/gui/model/Page.java | 2 +- .../de/vorb/tesseract/gui/view/BoxEditor.java | 2 +- .../tesseract/gui/view/BoxFileComponent.java | 2 +- .../tesseract/gui/view/EvaluationPane.java | 8 +- ...odelComponent.java => ImageComponent.java} | 6 +- .../tesseract/gui/view/PageComponent.java | 2 +- .../tesseract/gui/view/PreprocessingPane.java | 10 +- .../tesseract/gui/view/RecognitionPane.java | 2 +- .../tesseract/gui/view/SymbolOverview.java | 2 +- .../tesseract/gui/view/TesseractFrame.java | 2 + 12 files changed, 96 insertions(+), 82 deletions(-) rename gui/src/main/java/de/vorb/tesseract/gui/view/{ImageModelComponent.java => ImageComponent.java} (54%) diff --git a/gui/src/main/java/de/vorb/tesseract/gui/controller/TesseractController.java b/gui/src/main/java/de/vorb/tesseract/gui/controller/TesseractController.java index b073695d..a5ae56f1 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/controller/TesseractController.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/controller/TesseractController.java @@ -19,7 +19,7 @@ import de.vorb.tesseract.gui.view.EvaluationPane; import de.vorb.tesseract.gui.view.FeatureDebugger; import de.vorb.tesseract.gui.view.FilteredTable; -import de.vorb.tesseract.gui.view.ImageModelComponent; +import de.vorb.tesseract.gui.view.ImageComponent; import de.vorb.tesseract.gui.view.MainComponent; import de.vorb.tesseract.gui.view.PageComponent; import de.vorb.tesseract.gui.view.PreprocessingPane; @@ -92,6 +92,7 @@ import java.io.Writer; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.OpenOption; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; @@ -110,6 +111,10 @@ import java.util.TreeMap; import java.util.prefs.Preferences; +import static java.nio.file.StandardOpenOption.CREATE; +import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; +import static java.nio.file.StandardOpenOption.WRITE; + public class TesseractController extends WindowAdapter implements ActionListener, ListSelectionListener, Observer, ChangeListener { @@ -144,6 +149,7 @@ private static void setLookAndFeel() { private static final String KEY_TRAINING_FILE = "training_file"; private static final String KEY_BOX_FILE = "box_file"; + private static final OpenOption[] CREATE_OR_REPLACE = {CREATE, WRITE, TRUNCATE_EXISTING}; private final TesseractFrame view; @@ -407,12 +413,12 @@ private void handleActiveComponentChange() { } else if (mode == ApplicationMode.PROJECT) { // in project mode, it's a bit more complicated - if (active instanceof ImageModelComponent) { - if (activeComponent instanceof ImageModelComponent) { - // ImageModelComponent -> ImageModelComponent - setImage(((ImageModelComponent) activeComponent).getImageModel()); + if (active instanceof ImageComponent) { + if (activeComponent instanceof ImageComponent) { + // ImageComponent -> ImageComponent + setImage(((ImageComponent) activeComponent).getImage()); } else if (activeComponent instanceof PageComponent) { - // PageComponent -> ImageModelComponent + // PageComponent -> ImageComponent final Page pm = ((PageComponent) activeComponent).getPage(); if (pm != null) { @@ -427,9 +433,9 @@ private void handleActiveComponentChange() { if (activeComponent instanceof PageComponent) { // PageComponent -> PageComponent setPage(((PageComponent) activeComponent).getPage()); - } else if (activeComponent instanceof ImageModelComponent) { - // ImageModelComponent -> PageComponent - setImage(((ImageModelComponent) activeComponent).getImageModel()); + } else if (activeComponent instanceof ImageComponent) { + // ImageComponent -> PageComponent + setImage(((ImageComponent) activeComponent).getImage()); } else { setPage(null); } @@ -485,35 +491,36 @@ private void handleImportTranscriptions() { // for every file for (final Path imgFile : project.getImageFiles()) { + final Path filename = FileNames.replaceExtension(imgFile, "txt").getFileName(); final Path transcription = project.getTranscriptionDir().resolve(filename); - final BufferedWriter writer = Files.newBufferedWriter(transcription, StandardCharsets.UTF_8); + try (final BufferedWriter writer = Files.newBufferedWriter(transcription, + StandardCharsets.UTF_8, CREATE_OR_REPLACE)) { + + int lines = 0; - int lines = 0; + // read file line by line + String line; + while ((line = reader.readLine()) != null) { + // if the line equals the separator, create the next file + if (line.equals(sep)) { + break; + } - // read file line by line - String line; - while ((line = reader.readLine()) != null) { - // if the line equals the separator, create the next - // file - if (line.equals(sep)) { - break; + lines++; + // otherwise write the line to the current file + writer.write(line); + writer.write('\n'); } - lines++; - // otherwise write the line to the current file - writer.write(line); - writer.write('\n'); - } + // if a transcription file is empty, delete it + if (lines == 0) { + Files.deleteIfExists(transcription); + } - // if a transcription file is empty, delete it - if (lines == 0) { - Files.delete(transcription); + writer.write('\n'); } - - writer.write('\n'); - writer.close(); } } @@ -541,8 +548,8 @@ private void handleBatchExport() { progressMonitor.setProgress(0); try (final BufferedWriter errorLog = Files.newBufferedWriter( - export.get().getDestinationDir().resolve("errors.log"), - StandardCharsets.UTF_8)) { + export.get().getDestinationDir().resolve("errors.log"), StandardCharsets.UTF_8, + CREATE_OR_REPLACE)) { batchExec.start(progressMonitor, errorLog); @@ -642,7 +649,8 @@ private Optional handleTranscriptionSave() { final Path transcriptionFile = project.getTranscriptionDir().resolve(fileName); - try (final Writer writer = Files.newBufferedWriter(transcriptionFile, StandardCharsets.UTF_8)) { + try (final Writer writer = Files.newBufferedWriter(transcriptionFile, StandardCharsets.UTF_8, + CREATE_OR_REPLACE)) { final String transcription = view.getEvaluationPane().getTextAreaTranscript().getText(); @@ -1166,8 +1174,7 @@ public boolean accept(File f) { if (approved == JFileChooser.APPROVE_OPTION) { final Path textFile = fc.getSelectedFile().toPath(); - try { - final BufferedReader reader = Files.newBufferedReader(textFile, StandardCharsets.UTF_8); + try (final BufferedReader reader = Files.newBufferedReader(textFile, StandardCharsets.UTF_8)) { final Map histogram = new TreeMap<>(); @@ -1275,21 +1282,21 @@ public void setPage(@Nullable final Page page) { } if (active instanceof BoxFileComponent) { - final BoxFile boxFile = Optional.ofNullable(updatedPage).map(Page::toBoxFileModel).orElse(null); + final BoxFile boxFile = Optional.ofNullable(updatedPage).map(Page::toBoxFile).orElse(null); ((BoxFileComponent) active).setBoxFile(boxFile); } } - private void setBoxFile(@Nullable BoxFile model) { + private void setBoxFile(@Nullable BoxFile boxFile) { final MainComponent active = view.getActiveComponent(); if (active instanceof BoxFileComponent) { - ((BoxFileComponent) active).setBoxFile(model); + ((BoxFileComponent) active).setBoxFile(boxFile); } else { Dialogs.showWarning(view, "Illegal Action", "Could not set the box file"); } } - public void setImage(@Nullable Image model) { + public void setImage(@Nullable Image image) { view.getProgressBar().setIndeterminate(false); final MainComponent active = view.getActiveComponent(); @@ -1305,35 +1312,35 @@ public void setImage(@Nullable Image model) { if (!trainingFile.isPresent()) { Dialogs.showWarning(view, "Warning", "Please select a traineddata file."); return; - } else if (model == null) { + } else if (image == null) { return; } - final RecognitionWorker rw = new RecognitionWorker(this, model, trainingFile.get()); + final RecognitionWorker rw = new RecognitionWorker(this, image, trainingFile.get()); rw.execute(); recognitionWorker = rw; return; - } else if (!(active instanceof ImageModelComponent)) { + } else if (!(active instanceof ImageComponent)) { return; } - if (model == null) { - ((ImageModelComponent) active).setImageModel(null); + if (image == null) { + ((ImageComponent) active).setImage(null); return; } - final Path sourceFile = model.getSourceFile(); + final Path sourceFile = image.getSourceFile(); final Path selectedPage = getSelectedPage(); if (!sourceFile.equals(selectedPage)) { - ((ImageModelComponent) active).setImageModel(null); + ((ImageComponent) active).setImage(null); return; } - ((ImageModelComponent) active).setImageModel(model); + ((ImageComponent) active).setImage(image); } // TODO prototype loading? diff --git a/gui/src/main/java/de/vorb/tesseract/gui/io/BoxFileReader.java b/gui/src/main/java/de/vorb/tesseract/gui/io/BoxFileReader.java index dacafefc..68eb3733 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/io/BoxFileReader.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/io/BoxFileReader.java @@ -3,43 +3,48 @@ import de.vorb.tesseract.util.Box; import de.vorb.tesseract.util.Symbol; -import java.io.BufferedReader; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.LinkedList; import java.util.List; +import java.util.Objects; +import java.util.function.Function; +import java.util.regex.Pattern; +import java.util.stream.Collectors; public final class BoxFileReader { - private BoxFileReader() {} + private BoxFileReader() { + } + + private static final Pattern WHITESPACE_PATTERN = Pattern.compile("\\s+"); public static List readBoxFile(Path boxFile, int pageHeight) throws IOException { - final List boxes = new LinkedList<>(); - try (final BufferedReader boxReader = Files.newBufferedReader(boxFile, StandardCharsets.UTF_8)) { - String line; - while ((line = boxReader.readLine()) != null) { - final String[] components = line.split("\\s+"); - if (components.length < 5) { - continue; - } + return Files.lines(boxFile, StandardCharsets.UTF_8) + .map(WHITESPACE_PATTERN::split) + .filter(components -> components.length >= 5) + .map(symbolParser(pageHeight)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + private static Function symbolParser(int pageHeight) { + return (String[] components) -> { + try { final String text = components[0]; final int x = Integer.parseInt(components[1]); final int y = Integer.parseInt(components[2]); final int w = Integer.parseInt(components[3]) - x; final int h = Integer.parseInt(components[4]) - y; - boxes.add(new Symbol(text, - new Box(x, pageHeight - y - h, w, h), 0f)); + final Box boundingBox = new Box(x, pageHeight - y - h, w, h); + return new Symbol(text, boundingBox, 0f); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Could not parse line \"" + String.join(" ", components) + '"', e); } - } catch (NumberFormatException e) { - throw new IOException(); - } - - return boxes; + }; } } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/model/Page.java b/gui/src/main/java/de/vorb/tesseract/gui/model/Page.java index 3b3840fd..8b1ad655 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/model/Page.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/model/Page.java @@ -40,7 +40,7 @@ public Page withTranscription(String transcription) { return new Page(image, page, transcription); } - public BoxFile toBoxFileModel() { + public BoxFile toBoxFile() { final Path boxFile = FileNames.replaceExtension(image.getPreprocessedFile(), "box"); final BufferedImage image = this.image.getPreprocessedImage(); diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/BoxEditor.java b/gui/src/main/java/de/vorb/tesseract/gui/view/BoxEditor.java index fcf3b836..5c3244c8 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/BoxEditor.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/BoxEditor.java @@ -538,7 +538,7 @@ public void setBoxFile(@Nullable BoxFile boxFile) { public void setPage(Page page) { this.page = page; - setBoxFile(Optional.ofNullable(page).map(Page::toBoxFileModel).orElse(null)); + setBoxFile(Optional.ofNullable(page).map(Page::toBoxFile).orElse(null)); } @Override diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/BoxFileComponent.java b/gui/src/main/java/de/vorb/tesseract/gui/view/BoxFileComponent.java index 407e92f0..d37092e6 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/BoxFileComponent.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/BoxFileComponent.java @@ -6,6 +6,6 @@ public interface BoxFileComponent extends PageComponent { - void setBoxFile(@Nullable BoxFile model); + void setBoxFile(@Nullable BoxFile boxFile); } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/EvaluationPane.java b/gui/src/main/java/de/vorb/tesseract/gui/view/EvaluationPane.java index 8bc1e092..f5dd6033 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/EvaluationPane.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/EvaluationPane.java @@ -210,10 +210,10 @@ public JTextArea getTextAreaTranscript() { } @Override - public void setPage(@Nullable Page model) { - this.model = model; + public void setPage(@Nullable Page page) { + this.model = page; - renderer.render(model, scale.current()); + renderer.render(page, scale.current()); } @Override @@ -229,7 +229,7 @@ public void freeResources() { @Override public @Nullable BoxFile getBoxFile() { if (model != null) { - return model.toBoxFileModel(); + return model.toBoxFile(); } else { return null; } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/ImageModelComponent.java b/gui/src/main/java/de/vorb/tesseract/gui/view/ImageComponent.java similarity index 54% rename from gui/src/main/java/de/vorb/tesseract/gui/view/ImageModelComponent.java rename to gui/src/main/java/de/vorb/tesseract/gui/view/ImageComponent.java index 7de378a8..a0b38213 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/ImageModelComponent.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/ImageComponent.java @@ -4,11 +4,11 @@ import org.checkerframework.checker.nullness.qual.Nullable; -public interface ImageModelComponent extends MainComponent { +public interface ImageComponent extends MainComponent { - void setImageModel(@Nullable Image model); + void setImage(@Nullable Image image); @Nullable - Image getImageModel(); + Image getImage(); } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/PageComponent.java b/gui/src/main/java/de/vorb/tesseract/gui/view/PageComponent.java index 0803d177..ff7ef3fc 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/PageComponent.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/PageComponent.java @@ -7,7 +7,7 @@ public interface PageComponent extends MainComponent { - void setPage(@Nullable Page model); + void setPage(@Nullable Page page); @Nullable Page getPage(); diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/PreprocessingPane.java b/gui/src/main/java/de/vorb/tesseract/gui/view/PreprocessingPane.java index b17bbb61..3ff8fa21 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/PreprocessingPane.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/PreprocessingPane.java @@ -39,7 +39,7 @@ import java.util.List; import java.util.Optional; -public class PreprocessingPane extends JPanel implements ImageModelComponent { +public class PreprocessingPane extends JPanel implements ImageComponent { private static final long serialVersionUID = 1L; @@ -301,15 +301,15 @@ public Component asComponent() { } @Override - public void setImageModel(Image model) { - imageModel = model; + public void setImage(Image image) { + imageModel = image; lblPreview.setIcon( - Optional.ofNullable(model).map(Image::getPreprocessedImage).map(ImageIcon::new).orElse(null)); + Optional.ofNullable(image).map(Image::getPreprocessedImage).map(ImageIcon::new).orElse(null)); } @Override - public Image getImageModel() { + public Image getImage() { return imageModel; } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/RecognitionPane.java b/gui/src/main/java/de/vorb/tesseract/gui/view/RecognitionPane.java index ca6c9d4b..01e3ecba 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/RecognitionPane.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/RecognitionPane.java @@ -438,7 +438,7 @@ public void freeResources() { @Override public @Nullable BoxFile getBoxFile() { if (page != null) { - return page.toBoxFileModel(); + return page.toBoxFile(); } else { return null; } diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/SymbolOverview.java b/gui/src/main/java/de/vorb/tesseract/gui/view/SymbolOverview.java index 8cff536b..e58b3471 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/SymbolOverview.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/SymbolOverview.java @@ -118,7 +118,7 @@ public void setBoxFile(@Nullable BoxFile boxFile) { @Override public void setPage(Page page) { this.page = page; - setBoxFile(Optional.ofNullable(page).map(Page::toBoxFileModel).orElse(null)); + setBoxFile(Optional.ofNullable(page).map(Page::toBoxFile).orElse(null)); } @Override diff --git a/gui/src/main/java/de/vorb/tesseract/gui/view/TesseractFrame.java b/gui/src/main/java/de/vorb/tesseract/gui/view/TesseractFrame.java index 04137b11..55a422f5 100644 --- a/gui/src/main/java/de/vorb/tesseract/gui/view/TesseractFrame.java +++ b/gui/src/main/java/de/vorb/tesseract/gui/view/TesseractFrame.java @@ -47,7 +47,9 @@ * Swing component that allows to compare the results of Tesseract. */ public class TesseractFrame extends JFrame { + private static final long serialVersionUID = 1L; + private final FilteredList listPages; private final FilteredList listTrainingFiles; private final PreprocessingPane preprocessingPane;