Browse Source

first working version

main
Stephan Richter 2 years ago
parent
commit
79fad80496
  1. 4
      .classpath
  2. 65
      pom.xml
  3. 20
      resources/logback.xml
  4. 0
      resources/translations/Application.de.translation
  5. 10
      src/main/java/de/srsoftware/belegscanner/Configuration.java
  6. 200
      src/main/java/de/srsoftware/belegscanner/gui/MainFrame.java
  7. 10
      src/main/java/de/srsoftware/belegscanner/gui/StatusBar.java
  8. 94
      src/main/java/de/srsoftware/belegscanner/gui/Toolbar.java

4
.classpath

@ -6,16 +6,18 @@ @@ -6,16 +6,18 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
<attributes>
<attribute name="module" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">

65
pom.xml

@ -4,8 +4,36 @@ @@ -4,8 +4,36 @@
<modelVersion>4.0.0</modelVersion>
<groupId>BelegScanner</groupId>
<artifactId>BelegScanner</artifactId>
<version>0.0.2</version>
<version>0.0.3</version>
<name>BelegScanner</name>
<packaging>jar</packaging>
<description>BelegScanner</description>
<url>https://github.com/srsoftware-de/Belegscanner</url>
<organization>
<name>SRSoftware</name>
<url>https://srsoftware.de</url>
</organization>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<licenses>
<license>
<name>MIT License</name>
<url>http://www.opensource.org/licenses/mit-license.php</url>
</license>
</licenses>
<developers>
<developer>
<name>Stephan Richter</name>
<email>s.richter@srsoftware.de</email>
<organization>SRSoftware</organization>
<organizationUrl>http://www.srsoftware.de</organizationUrl>
</developer>
</developers>
<dependencies>
<dependency>
@ -47,6 +75,41 @@ @@ -47,6 +75,41 @@
<release>11</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>
de.srsoftware.web4rail.Application
</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.4.0</version>
<configuration>
<mainClass>de.srsoftware.web4rail.Application</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>

20
resources/logback.xml

@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
<configuration scan="true" scanPeriod="30 seconds" debug="true">
<!-- scan="true" enables automatic updates if config file changes, see http://logback.qos.ch/manual/configuration.html -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<logger name="de.srsoftware.belegscanner.gui.MainFrame" level="info" additivity="false">
<appender-ref ref="CONSOLE"/>
</logger>
<root level="error">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>

0
resources/translations/Application.de.translation

10
src/main/java/de/srsoftware/belegscanner/Configuration.java

@ -128,11 +128,13 @@ public class Configuration { @@ -128,11 +128,13 @@ public class Configuration {
String localKey = parts[i];
LOG.debug("localKey = {}",localKey);
boolean lastPart = i == parts.length-1;
if (!localJson.has(localKey)) {
LOG.debug("{} not present in {}, creating…",localKey,localJson);
localJson.put(localKey, lastPart ? value : new JSONObject());
if (!lastPart && !localJson.has(localKey)) {
localJson.put(localKey, new JSONObject());
}
if (lastPart) {
localJson.put(localKey, value);
break;
}
if (lastPart) break;
localJson = localJson.getJSONObject(localKey);
}
LOG.debug("altered json: {}",json);

200
src/main/java/de/srsoftware/belegscanner/gui/MainFrame.java

@ -2,9 +2,18 @@ package de.srsoftware.belegscanner.gui; @@ -2,9 +2,18 @@ package de.srsoftware.belegscanner.gui;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Vector;
import java.util.regex.Matcher;
@ -12,6 +21,7 @@ import java.util.regex.Pattern; @@ -12,6 +21,7 @@ import java.util.regex.Pattern;
import javax.swing.JFrame;
import org.json.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -25,6 +35,7 @@ public class MainFrame extends JFrame { @@ -25,6 +35,7 @@ public class MainFrame extends JFrame {
private static final String HOME = System.getProperty("user.home");
private static final Pattern MARKEN = Pattern.compile("\\$([a-zA-Z]+)");
private static FilenameFilter PAGES = (dir,name) -> name.toLowerCase().endsWith("pdf") && name.toLowerCase().startsWith("page");
private StatusBar statusBar;
private Toolbar toolbar;
@ -41,7 +52,13 @@ public class MainFrame extends JFrame { @@ -41,7 +52,13 @@ public class MainFrame extends JFrame {
private Configuration config;
private int xSize = 209;
private int ySize = 297;
private int resoultion = 150;
private String mode = "Color";
public MainFrame(Configuration config) {
super("BelegScanner");
this.config = config;
int width = config.getOrCreate("app.main.dimenstion.w",800);
int height = config.getOrCreate("app.main.dimenstion.h",600);
@ -57,8 +74,14 @@ public class MainFrame extends JFrame { @@ -57,8 +74,14 @@ public class MainFrame extends JFrame {
toolbar.addCategoryListener(this::setCategory)
.addDateListener(this::setDate)
.addFieldListener(this::setField)
.addFolderListener(this::openFolder)
.addJoinListener(this::join)
.addPathListener(this::setPath)
.addScanListener(this::scan);
.addScanListener(this::scan);
int x = config.getOrCreate("app.main.position.x", 20);
int y = config.getOrCreate("app.main.position.y", 20);
setLocation(new Point(x, y));
setPreferredSize(new Dimension(width,height));
pack();
@ -72,9 +95,159 @@ public class MainFrame extends JFrame { @@ -72,9 +95,159 @@ public class MainFrame extends JFrame {
toolbar.addFieldsFor(marks);
};
private void join(ActionEvent ev) {
new Thread(() -> joinFiles(patchedPath)).start();
}
private void joinFiles(String path) {
LOG.debug("joinFiles({})",path);
File folder = new File(path);
if (!folder.exists()) return;
List<String> pdfs = Arrays.asList(folder.list(PAGES));
Collections.sort(pdfs);
Vector<String> cmd = new Vector<>();
cmd.add("pdftk");
cmd.addAll(pdfs);
cmd.add("cat");
cmd.add("output");
cmd.add(folder.getName()+".pdf");
LOG.debug("executing {}",cmd);
ProcessBuilder builder = new ProcessBuilder(cmd);
builder.directory(folder);
try {
Process process = builder.start();
statusBar.setAction("Verbinde PDFs…");
int errorCode = process.waitFor();
if (errorCode != 0) {
LOG.error("error code: {} for {}",errorCode,cmd);
} else LOG.debug("error code: {}",errorCode);
} catch (InterruptedException | IOException e) {
LOG.error("{} terminated: ",builder,e);
}
for (String page : pdfs) Path.of(path,page).toFile().delete();
statusBar.setAction("Bereit.");
}
private void openFolder(ActionEvent ev) {
new Thread(() -> openFolder(patchedPath)).start();
}
private void openFolder(String path) {
File folder = new File(path);
if (!folder.exists()) return;
ProcessBuilder builder = new ProcessBuilder(List.of("killall","thunar"));
builder.directory(folder);
try {
builder.start().waitFor();
} catch (IOException | InterruptedException e) {
LOG.error("{} terminated: ",builder,e);
}
builder = new ProcessBuilder("thunar");
builder.directory(folder);
try {
builder.start();
} catch (IOException e) {
LOG.error("{} terminated: ",builder,e);
}
}
private void performScan(String path) {
LOG.debug("performScan({})",path);
toolbar.readyToScan(false);
File folder = new File(path);
if (!folder.exists()) {
LOG.warn("Path '{}' does not exist!",path);
folder.mkdirs();
}
long timestamp = new Date().getTime();
String raw = timestamp+".jpg";
Vector<String> cmd = new Vector<>();
cmd.add("scanimage");
cmd.add("-x");
cmd.add(xSize+"");
cmd.add("-y");
cmd.add(ySize+"");
cmd.add("--mode");
cmd.add(mode);
cmd.add("--resolution");
cmd.add(resoultion+"");
cmd.add("-o");
cmd.add(raw);
LOG.debug("executing {}",cmd);
ProcessBuilder builder = new ProcessBuilder(cmd);
builder.directory(folder);
try {
Process process = builder.start();
statusBar.setAction("Scanne nach "+path+"…");
int errorCode = process.waitFor();
if (errorCode != 0) {
LOG.error("error code: {} for {}",errorCode,cmd);
} else LOG.debug("error code: {}",errorCode);
} catch (InterruptedException | IOException e) {
LOG.error("{} terminated: ",builder,e);
}
String pdf = "page."+timestamp+".pdf";
cmd = new Vector<>();
cmd.add("convert");
cmd.add(raw);
cmd.add(pdf);
builder = new ProcessBuilder(cmd);
builder.directory(folder);
try {
Process process = builder.start();
statusBar.setAction("Kovertiere zu PDF…");
toolbar.readyToScan(true);
int errorCode = process.waitFor();
if (errorCode != 0) {
LOG.error("error code: {} for {}",errorCode,cmd);
} else LOG.debug("error code: {}",errorCode);
} catch (InterruptedException | IOException e) {
LOG.error("{} terminated: ",builder,e);
}
Path.of(path, raw).toFile().delete();
String ocr = "page."+timestamp+".ocr.pdf";
cmd = new Vector<>();
cmd.add("pdfsandwich");
cmd.add("-lang");
cmd.add("deu");
cmd.add("-rgb");
cmd.add("-o");
cmd.add(ocr);
cmd.add(pdf);
builder = new ProcessBuilder(cmd);
builder.directory(folder);
try {
Process process = builder.start();
statusBar.setAction("Texterkennung…");
toolbar.readyToScan(true);
int errorCode = process.waitFor();
if (errorCode != 0) {
LOG.error("error code: {} for {}",errorCode,cmd);
} else LOG.debug("error code: {}",errorCode);
} catch (InterruptedException | IOException e) {
LOG.error("{} terminated: ",builder,e);
}
Path.of(path, pdf).toFile().delete();
statusBar.setAction("Bereit.");
}
private void scan(ActionEvent ev) {
LOG.debug("Scanning into '{}'",patchedPath);
config.set("app.categories."+category+".path",path);
updateConfig();
new Thread(() -> performScan(patchedPath)).start();
}
private void setCategory(String category) {
@ -89,7 +262,9 @@ public class MainFrame extends JFrame { @@ -89,7 +262,9 @@ public class MainFrame extends JFrame {
}
private void setField(String key, String val) {
fields.put(key, val);
if (val == null || val.isEmpty()) {
fields.remove(key);
} else fields.put(key, val);
updatePath();
}
@ -99,6 +274,23 @@ public class MainFrame extends JFrame { @@ -99,6 +274,23 @@ public class MainFrame extends JFrame {
updatePath();
}
private void updateConfig() {
String prefix = "app.categories."+category+".";
for (Entry<String, String> entry : fields.entrySet()) {
String key = entry.getKey();
String val = entry.getValue();
JSONArray arr = config.getOrCreateArray(prefix+"fields."+key);
HashSet<Object> existing = new HashSet<>();
arr.forEach(existing::add);
if (!existing.contains(val)) arr.put(val);
}
config.set(prefix+"path",path);
Point loc = getLocation();
config.set("app.main.position.x", loc.x);
config.set("app.main.position.y", loc.y);
}
@SuppressWarnings("deprecation")
private void updatePath() {
LOG.debug("updatePath() [path = {}]",path);

10
src/main/java/de/srsoftware/belegscanner/gui/StatusBar.java

@ -14,9 +14,12 @@ public class StatusBar extends JPanel { @@ -14,9 +14,12 @@ public class StatusBar extends JPanel {
private static final long serialVersionUID = 8102800846089594705L;
private JLabel path;
private JLabel action;
public StatusBar() {
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
add(path = new JLabel());
add(action = new JLabel("Bereit."));
add(path = new JLabel("Kein Pfad gewält."));
}
public StatusBar setPath(String path) {
@ -24,4 +27,9 @@ public class StatusBar extends JPanel { @@ -24,4 +27,9 @@ public class StatusBar extends JPanel {
this.path.setText(path);
return this;
}
public StatusBar setAction(String action) {
this.action.setText(action);
return this;
}
}

94
src/main/java/de/srsoftware/belegscanner/gui/Toolbar.java

@ -16,6 +16,7 @@ import javax.swing.JButton; @@ -16,6 +16,7 @@ import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -47,15 +48,19 @@ public class Toolbar extends JPanel { @@ -47,15 +48,19 @@ public class Toolbar extends JPanel {
private static final long serialVersionUID = -5834326573752788233L;
private static final int OFFSET = 4;
private Vector<Object> categories = new Vector<>();
private Vector<Object> paths = new Vector<>();
private HashMap<String,JPanel> additonalComponents = new HashMap<>();
private HashSet<CategoryListener> categoryListeners = new HashSet<>();
private HashSet<DateListener> dateListeners = new HashSet<>();
private HashSet<FieldListener> fieldListeners = new HashSet<>();
private HashSet<PathListener> pathListeners = new HashSet<>();
private HashSet<ActionListener> folderListeners = new HashSet<>();
private HashSet<ActionListener> joinListeners = new HashSet<>();
private HashSet<ActionListener> scanListeners = new HashSet<>();
private HashMap<String,Component> additonalComponents = new HashMap<>();
private DateChooser date;
@ -63,8 +68,11 @@ public class Toolbar extends JPanel { @@ -63,8 +68,11 @@ public class Toolbar extends JPanel {
private SelectComboBox pathPicker;
private JButton scanButton;
private JButton joinButton;
private JButton folderButton;
public Toolbar(Configuration config) {
this.config = config;
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
@ -72,6 +80,8 @@ public class Toolbar extends JPanel { @@ -72,6 +80,8 @@ public class Toolbar extends JPanel {
add(input("Kategorie",categoryPicker(config)));
add(input("Pfad",pathPicker = pathPicker()));
add(scanButton());
add(joinButton());
add(folderButton());
add(externButton());
}
@ -83,10 +93,10 @@ public class Toolbar extends JPanel { @@ -83,10 +93,10 @@ public class Toolbar extends JPanel {
for (String name : marks) {
if (additonalComponents.containsKey(name)) continue;
List<Object> knownValues = List.of();
Vector<Object> knownValues = new Vector<>();
SelectComboBox valuePicker = new SelectComboBox(knownValues).onUpdateText(newText -> updateField(name,newText));
Component input = input(name, valuePicker);
add(input,getComponentCount()-2);
JPanel input = input(name, valuePicker);
add(input,getComponentCount()-OFFSET);
additonalComponents.put(name, input);
}
}
@ -105,6 +115,17 @@ public class Toolbar extends JPanel { @@ -105,6 +115,17 @@ public class Toolbar extends JPanel {
fieldListeners.add(listener);
return this;
}
public Toolbar addFolderListener(ActionListener listener) {
folderListeners.add(listener);
return this;
}
public Toolbar addJoinListener(ActionListener listener) {
joinListeners.add(listener);
return this;
}
public Toolbar addPathListener(PathListener listener){
pathListeners.add(listener);
@ -136,7 +157,31 @@ public class Toolbar extends JPanel { @@ -136,7 +157,31 @@ public class Toolbar extends JPanel {
return btn;
}
private Component input(String caption, Component component) {
private Component folderButton() {
folderButton = new JButton("Ordner öffnen!");
folderButton.addActionListener(this::folderPressed);
return folderButton;
}
private void folderPressed(ActionEvent evt) {
folderListeners.forEach(l->l.actionPerformed(evt));
}
public Date getDate() {
return date.getSelectedDate();
}
public SelectComboBox getSelector(JPanel panel) {
if (panel != null && panel.getComponentCount()>1) {
Component child = panel.getComponent(1);
if (child instanceof SelectComboBox) return (SelectComboBox) child;
}
return null;
}
private JPanel input(String caption, Component component) {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
panel.add(new JLabel(caption+" "));
@ -144,11 +189,17 @@ public class Toolbar extends JPanel { @@ -144,11 +189,17 @@ public class Toolbar extends JPanel {
return panel;
}
public Date getDate() {
return date.getSelectedDate();
private Component joinButton() {
joinButton = new JButton("zusammenfügen!");
joinButton.addActionListener(this::joinPressed);
return joinButton;
}
private void joinPressed(ActionEvent evt) {
joinListeners.forEach(l->l.actionPerformed(evt));
}
private SelectComboBox pathPicker() {
JSONObject cats = config.getOrCreate("app.categories",new JSONObject());
for (String catName : cats.keySet()) {
@ -160,7 +211,7 @@ public class Toolbar extends JPanel { @@ -160,7 +211,7 @@ public class Toolbar extends JPanel {
}
private Component scanButton() {
JButton scanButton = new JButton("scannen!");
scanButton = new JButton("scannen!");
scanButton.addActionListener(this::scanPressed);
return scanButton;
}
@ -169,15 +220,34 @@ public class Toolbar extends JPanel { @@ -169,15 +220,34 @@ public class Toolbar extends JPanel {
scanListeners.forEach(l->l.actionPerformed(evt));
}
public void readyToScan(boolean val) {
scanButton.setEnabled(val);
}
protected void updateCat(String newCat) {
LOG.debug("updateCat({})",newCat);
categoryListeners.forEach(l -> l.setCategory(newCat));
if (!newCat.isEmpty()) {
String path = config.get("app.categories."+newCat+".path");
LOG.debug("path: {}",path);
String prefix = "app.categories."+newCat+".";
String path = config.get(prefix+"path");
if (path != null) {
pathPicker.setSelectedItem(path);
updatePath(path);
}
JSONObject fields = config.get(prefix+"fields");
if (fields == null) return;
LOG.debug("fields: {}",fields);
for (String fieldName : fields.keySet()) {
path = prefix+"fields."+fieldName;
JSONArray arr = config.getOrCreateArray(path);
HashSet<Object> values = new HashSet<>();
arr.forEach(values::add);
SelectComboBox selector = getSelector(additonalComponents.get(fieldName));
if (selector != null) selector.setElements(values);
}
}
}

Loading…
Cancel
Save