diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 19c25a3..bbf545a 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -7,6 +7,7 @@
+
diff --git a/pom.xml b/pom.xml
index ee2953a..621ac24 100644
--- a/pom.xml
+++ b/pom.xml
@@ -43,6 +43,12 @@
5.8.26
+
+ org.xerial
+ sqlite-jdbc
+ 3.14.2.1
+
+
com.melloware
diff --git a/src/main/java/xyz/wbsite/jmacro/JMacro.java b/src/main/java/xyz/wbsite/jmacro/JMacro.java
index 625f5b7..6e95d7c 100644
--- a/src/main/java/xyz/wbsite/jmacro/JMacro.java
+++ b/src/main/java/xyz/wbsite/jmacro/JMacro.java
@@ -11,6 +11,7 @@ import xyz.wbsite.jmacro.util.*;
import java.awt.*;
import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
@@ -300,6 +301,26 @@ public abstract class JMacro {
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
}
+ /**
+ * 执行复制命令
+ */
+ public void sendCopyCommand() {
+ robot.keyPress(KeyEvent.VK_CONTROL);
+ robot.keyPress(KeyEvent.VK_C);
+ robot.keyRelease(KeyEvent.VK_C);
+ robot.keyRelease(KeyEvent.VK_CONTROL);
+ }
+
+ /**
+ * 执行粘贴命令
+ */
+ public void sendPasteCommand() {
+ robot.keyPress(KeyEvent.VK_CONTROL);
+ robot.keyPress(KeyEvent.VK_V);
+ robot.keyRelease(KeyEvent.VK_V);
+ robot.keyRelease(KeyEvent.VK_CONTROL);
+ }
+
/**
* 捕获指定区域屏幕
*/
diff --git a/src/main/java/xyz/wbsite/jmacro/JMainController.java b/src/main/java/xyz/wbsite/jmacro/JMainController.java
index e7aecbb..82283db 100644
--- a/src/main/java/xyz/wbsite/jmacro/JMainController.java
+++ b/src/main/java/xyz/wbsite/jmacro/JMainController.java
@@ -1,5 +1,12 @@
package xyz.wbsite.jmacro;
+import cn.hutool.core.collection.BoundedPriorityQueue;
+import cn.hutool.core.util.StrUtil;
+import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+import javafx.scene.control.TextArea;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
import xyz.wbsite.jmacro.base.Legend;
import xyz.wbsite.jmacro.base.ViewRect;
import xyz.wbsite.jmacro.tool.Measure;
@@ -7,10 +14,6 @@ import xyz.wbsite.jmacro.tool.PickLegend;
import xyz.wbsite.jmacro.tool.PickPoint;
import xyz.wbsite.jmacro.tool.PickRect;
import xyz.wbsite.jmacro.util.DialogUtil;
-import javafx.fxml.FXML;
-import javafx.scene.control.Button;
-import javafx.scene.image.Image;
-import javafx.scene.image.ImageView;
import java.awt.*;
import java.util.concurrent.Semaphore;
@@ -32,6 +35,11 @@ public class JMainController {
private Button capture;
@FXML
private ImageView preview;
+ @FXML
+ private TextArea console;
+
+ private final int MAX_LENGTH = 100;
+ private final BoundedPriorityQueue logs = new BoundedPriorityQueue<>(MAX_LENGTH);
private Semaphore semaphore = new Semaphore(1);
@@ -127,7 +135,7 @@ public class JMainController {
/**
* 预览
*
- * @param image
+ * @param image 图片
*/
public void preview(Image image) {
try {
@@ -143,4 +151,20 @@ public class JMainController {
throw new RuntimeException(e);
}
}
+
+ /**
+ * 日志窗口
+ *
+ * @param log 格式化
+ * @param args 参数
+ */
+ public synchronized void println(String log, Object... args) {
+ String format = StrUtil.format(log, args) + "\n";
+ if (logs.size() >= MAX_LENGTH) {
+ String poll = logs.poll();
+ console.deleteText(0, poll.length());
+ }
+ logs.add(format);
+ console.appendText(format);
+ }
}
diff --git a/src/main/java/xyz/wbsite/jmacro/db/Client.java b/src/main/java/xyz/wbsite/jmacro/db/Client.java
new file mode 100644
index 0000000..8f4ef54
--- /dev/null
+++ b/src/main/java/xyz/wbsite/jmacro/db/Client.java
@@ -0,0 +1,151 @@
+package xyz.wbsite.jmacro.db;
+
+import java.io.File;
+import java.sql.Connection;
+import java.sql.Date;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Time;
+import java.sql.Types;
+
+/**
+ * xyz.wbsite.wsqlite.Client
+ *
+ * @author wangbing
+ */
+public class Client {
+
+ Connection connection;
+ ResultSet resultSet;
+ String dbFilePath;
+
+ /**
+ * 构造函数
+ *
+ * @param dbFile 文件
+ * @throws ClassNotFoundException
+ * @throws SQLException
+ */
+ public Client(File dbFile) throws ClassNotFoundException, SQLException {
+ this.dbFilePath = dbFile.getAbsolutePath();
+ if (!dbFile.exists()) {
+ connection = getConnection();
+ }
+ }
+
+ /**
+ * 执行sql语句
+ *
+ * @param sql
+ * @throws SQLException
+ * @throws ClassNotFoundException
+ */
+ public void execute(String sql) throws SQLException, ClassNotFoundException {
+ try {
+ executeUpdate(sql);
+ } finally {
+ destroyed();
+ }
+ }
+
+ /**
+ * 执行sql查询语句
+ *
+ * @param sql
+ * @throws SQLException
+ * @throws ClassNotFoundException
+ */
+ public ResultSet executeQuery(String sql, Object... args) throws SQLException, ClassNotFoundException {
+ PreparedStatement preparedStatement = getConnection().prepareStatement(sql);
+ setArg(preparedStatement, args);
+ return preparedStatement.executeQuery();
+ }
+
+ /**
+ * 执行sql语句
+ *
+ * @param sql
+ * @throws SQLException
+ * @throws ClassNotFoundException
+ */
+ public int executeUpdate(String sql, Object... args) throws SQLException, ClassNotFoundException {
+ try {
+ PreparedStatement preparedStatement = getConnection().prepareStatement(sql);
+ setArg(preparedStatement, args);
+ return preparedStatement.executeUpdate();
+ } finally {
+ destroyed();
+ }
+ }
+
+ private void setArg(PreparedStatement ps, Object... args) throws SQLException {
+ for (int i = 0; i < args.length; i++) {
+ Object arg = args[i];
+
+ if (arg == null) {
+ ps.setNull(i + 1, Types.NULL);
+ } else if (arg instanceof String) {
+ ps.setString(i + 1, (String) arg);
+ } else if (arg instanceof Date) {
+ ps.setDate(i + 1, (Date) arg);
+ } else if (arg instanceof Time) {
+ ps.setTime(i + 1, (Time) arg);
+ } else if (arg instanceof java.util.Date) {
+ ps.setLong(i + 1, ((java.util.Date) arg).getTime());
+ } else if (arg instanceof Boolean) {
+ ps.setBoolean(i + 1, (Boolean) arg);
+ } else if (arg instanceof Byte) {
+ ps.setByte(i + 1, (Byte) arg);
+ } else if (arg instanceof Short) {
+ ps.setShort(i + 1, (Short) arg);
+ } else if (arg instanceof Integer) {
+ ps.setInt(i + 1, (int) arg);
+ } else if (arg instanceof Long) {
+ ps.setLong(i + 1, (long) arg);
+ } else if (arg instanceof Float) {
+ ps.setFloat(i + 1, (float) arg);
+ } else if (arg instanceof Double) {
+ ps.setDouble(i + 1, (double) arg);
+ } else if (arg instanceof byte[]) {
+ ps.setBytes(i + 1, (byte[]) arg);
+ }
+ }
+ }
+
+ /**
+ * 获取数据库连接
+ *
+ * @return 数据库连接
+ * @throws ClassNotFoundException
+ * @throws SQLException
+ */
+ Connection getConnection() throws ClassNotFoundException, SQLException {
+ if (null == connection) {
+ Class.forName("org.sqlite.JDBC");
+ connection = DriverManager.getConnection("jdbc:sqlite:" + dbFilePath);
+ }
+ return connection;
+ }
+
+ /**
+ * 数据库资源关闭和释放
+ */
+ public void destroyed() {
+ try {
+ if (null != resultSet) {
+ resultSet.close();
+ resultSet = null;
+ }
+
+ if (null != connection) {
+ connection.close();
+ connection = null;
+ }
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/wbsite/jmacro/db/ObjectClient.java b/src/main/java/xyz/wbsite/jmacro/db/ObjectClient.java
new file mode 100644
index 0000000..9c55b20
--- /dev/null
+++ b/src/main/java/xyz/wbsite/jmacro/db/ObjectClient.java
@@ -0,0 +1,323 @@
+package xyz.wbsite.jmacro.db;
+
+
+import xyz.wbsite.jmacro.db.anonation.TableField;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * xyz.wbsite.wsqlite.Client
+ *
+ * @author wangbing
+ */
+public class ObjectClient extends Client {
+
+ private Map classMap = new HashMap<>();
+
+ /**
+ * 构造函数
+ *
+ * @param dbFile 文件
+ * @param classList 注册对象
+ * @throws ClassNotFoundException
+ * @throws SQLException
+ */
+ public ObjectClient(File dbFile, List classList) throws ClassNotFoundException, SQLException {
+ super(dbFile);
+ for (Class aClass : classList) {
+ classMap.put(aClass.getName(), aClass);
+ }
+ for (String key : classMap.keySet()) {
+ Class object = classMap.get(key);
+ StringBuffer sql = new StringBuffer();
+ String name = object.getSimpleName();
+
+ sql.append("CREATE TABLE IF NOT EXISTS ");
+ sql.append(name);
+ sql.append(" (");
+
+ Field[] fields = object.getDeclaredFields();
+ for (Field f : fields) {
+ if (f.isAnnotationPresent(TableField.class)) {
+ TableField bind = f.getAnnotation(TableField.class);
+ int length = bind.value();
+
+ if (f.getType() == String.class) {
+ sql.append(f.getName().toUpperCase());
+ sql.append(" VARCHAR(" + length + "),");
+ } else if (f.getType() == Boolean.class || f.getType() == boolean.class) {
+ sql.append(f.getName().toUpperCase());
+ sql.append(" BOOLEAN,");
+ } else if (f.getType() == Byte.class || f.getType() == byte.class ||
+ f.getType() == Short.class || f.getType() == short.class ||
+ f.getType() == Character.class || f.getType() == char.class ||
+ f.getType() == Integer.class || f.getType() == int.class ||
+ f.getType() == Long.class || f.getType() == long.class) {
+ sql.append(f.getName().toUpperCase());
+ sql.append(" INTEGER,");
+ } else if (f.getType() == Float.class || f.getType() == float.class ||
+ f.getType() == Double.class || f.getType() == double.class) {
+ sql.append(f.getName().toUpperCase());
+ sql.append(" REAL,");
+ } else if (f.getType() == Byte[].class || f.getType() == byte[].class) {
+ sql.append(f.getName().toUpperCase());
+ sql.append(" BLOB,");
+ } else if (f.getType() == Date.class) {
+ sql.append(f.getName().toUpperCase());
+ sql.append(" TIMESTAMP,");
+ }
+ }
+ }
+
+ sql.replace(sql.length() - 1, sql.length(), "");
+ sql.append(")");
+ System.out.println("SQL ==> " + sql.toString());
+ execute(sql.toString());
+ }
+ }
+
+ public int insert(Class poClass, T po) throws SQLException, ClassNotFoundException {
+ try {
+ Class aClass = classMap.get(poClass.getName());
+ if (aClass == null) {
+ System.err.println(poClass.getName() + " not found.");
+ } else {
+ StringBuffer sql = new StringBuffer();
+ sql.append("INSERT INTO ");
+ sql.append(aClass.getSimpleName());
+ sql.append("(");
+
+ //获取字段列表
+ List fs = getFields(poClass);
+
+ StringBuffer fieldsSql = new StringBuffer();
+ StringBuffer valueSql = new StringBuffer();
+ Object[] values = new Object[fs.size()];
+
+ for (int i = 0; i < fs.size(); i++) {
+ Field f = fs.get(i);
+ f.setAccessible(true);
+ fieldsSql.append(f.getName().toUpperCase());
+ valueSql.append("?");
+ values[i] = f.get(po);
+ if (i != fs.size() - 1) {
+ fieldsSql.append(",");
+ valueSql.append(",");
+ }
+ }
+
+ sql.append(fieldsSql);
+ sql.append(") VALUES (");
+ sql.append(valueSql);
+ sql.append(")");
+ System.out.println("SQL ==> " + sql.toString());
+ return executeUpdate(sql.toString(), values);
+ }
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } finally {
+ destroyed();
+ }
+ return 0;
+ }
+
+ public int delete(Class poClass, Where where) throws SQLException, ClassNotFoundException {
+ try {
+ Class aClass = classMap.get(poClass.getName());
+ if (aClass == null) {
+ System.err.println(poClass.getName() + " not found.");
+ } else {
+ StringBuffer sql = new StringBuffer();
+ sql.append("DELETE FROM ");
+ sql.append(aClass.getSimpleName());
+ sql.append(where.getSql());
+ System.out.println("SQL ==> " + sql.toString());
+ return executeUpdate(sql.toString(), where.getArgs());
+ }
+ } finally {
+ destroyed();
+ }
+ return 0;
+ }
+
+ public int update(Class poClass, T po, Where where) throws SQLException, ClassNotFoundException {
+ try {
+ Class aClass = classMap.get(poClass.getName());
+ if (aClass == null) {
+ System.err.println(poClass.getName() + " not found.");
+ } else {
+ //获取字段列表
+ List fs = getFields(poClass);
+
+ StringBuffer sql = new StringBuffer();
+ Object[] values = new Object[fs.size()];
+ sql.append("UPDATE ");
+ sql.append(aClass.getSimpleName());
+ sql.append(" SET ");
+
+ for (int i = 0; i < fs.size(); i++) {
+ Field f = fs.get(i);
+ f.setAccessible(true);
+ sql.append(f.getName());
+ sql.append(" = ?");
+ values[i] = f.get(po);
+ if (i != fs.size() - 1) {
+ sql.append(",");
+ }
+ }
+
+ // 条件
+ sql.append(where.getSql());
+
+ System.out.println("SQL ==> " + sql.toString());
+ return executeUpdate(sql.toString(), concat(values, where.getArgs()));
+ }
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } finally {
+ destroyed();
+ }
+ return 0;
+ }
+
+ public List select(Class poClass, Where where, int pageNumber, int pageSize) throws SQLException, ClassNotFoundException {
+ ArrayList list = new ArrayList<>();
+ try {
+ Class aClass = classMap.get(poClass.getName());
+ if (aClass == null) {
+ System.err.println(poClass.getName() + " not found.");
+ } else {
+ StringBuffer sql = new StringBuffer();
+ sql.append("SELECT ");
+
+ //获取字段列表
+ List fs = getFields(poClass);
+
+ for (int i = 0; i < fs.size(); i++) {
+ Field f = fs.get(i);
+ sql.append(f.getName().toUpperCase());
+ if (i != fs.size() - 1) {
+ sql.append(",");
+ }
+ }
+
+ sql.append(" FROM ");
+ sql.append(aClass.getSimpleName());
+
+ // 条件
+ sql.append(where.getSql());
+
+ //分页参数
+ if (pageSize > 0) {
+ sql.append(" LIMIT " + (pageNumber - 1) + "," + pageSize);
+ }
+
+ System.out.println("SQL ==> " + sql.toString());
+ list.addAll(executeQuery(poClass, sql.toString(), where.getArgs()));
+ }
+ } finally {
+ destroyed();
+ }
+ return list;
+ }
+
+ /**
+ * 执行select查询,返回结果列表
+ *
+ * @param sql sql select 语句
+ * @param poClass 结果集的行数据处理类对象
+ * @return
+ * @throws SQLException
+ * @throws ClassNotFoundException
+ */
+ public List executeQuery(Class poClass, String sql, Object... args) throws SQLException, ClassNotFoundException {
+ List rsList = new ArrayList();
+ try {
+ resultSet = executeQuery(sql, args);
+
+ //获取字段列表
+ List fs = getFields(poClass);
+
+ while (resultSet.next()) {
+ try {
+ T o = poClass.newInstance();
+ for (int i = 0; i < fs.size(); i++) {
+ Field f = fs.get(i);
+ f.setAccessible(true);
+
+ if (f.getType() == String.class) {
+ String v = resultSet.getString(f.getName());
+ f.set(o, v);
+ } else if (f.getType() == Boolean.class || f.getType() == boolean.class) {
+ boolean v = resultSet.getBoolean(f.getName());
+ f.set(o, v);
+ } else if (f.getType() == Byte.class || f.getType() == byte.class) {
+ byte v = resultSet.getByte(f.getName());
+ f.set(o, v);
+ } else if (f.getType() == Short.class || f.getType() == short.class) {
+ short v = resultSet.getShort(f.getName());
+ f.set(o, v);
+ } else if (f.getType() == Character.class || f.getType() == char.class) {
+ short v = resultSet.getShort(f.getName());
+ f.set(o, (char) v);
+ } else if (f.getType() == Integer.class || f.getType() == int.class) {
+ int v = resultSet.getInt(f.getName());
+ f.set(o, v);
+ } else if (f.getType() == Long.class || f.getType() == long.class) {
+ long v = resultSet.getLong(f.getName());
+ f.set(o, v);
+ } else if (f.getType() == Float.class || f.getType() == float.class) {
+ float v = resultSet.getFloat(f.getName());
+ f.set(o, v);
+ } else if (f.getType() == Double.class || f.getType() == double.class) {
+ double v = resultSet.getDouble(f.getName());
+ f.set(o, v);
+ } else if (f.getType() == Byte[].class || f.getType() == byte[].class) {
+ byte[] v = resultSet.getBytes(f.getName());
+ f.set(o, v);
+ } else if (f.getType() == Date.class) {
+ Date v = resultSet.getDate(f.getName());
+ f.set(o, v);
+ } else {
+ String v = resultSet.getString(f.getName());
+ f.set(o, v);
+ }
+ }
+ rsList.add(o);
+ } catch (InstantiationException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+ } finally {
+ destroyed();
+ }
+ return rsList;
+ }
+
+ private List getFields(Class aClass) {
+ List fs = new ArrayList<>();
+ for (Field f : aClass.getDeclaredFields()) {
+ if (f.isAnnotationPresent(TableField.class)) {
+ fs.add(f);
+ }
+ }
+ return fs;
+ }
+
+ private T[] concat(T[] arr1, T[] arr2) {
+ List temp = new ArrayList<>();
+ temp.addAll(Arrays.asList(arr1));
+ temp.addAll(Arrays.asList(arr2));
+ return (T[]) temp.toArray();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/xyz/wbsite/jmacro/db/Where.java b/src/main/java/xyz/wbsite/jmacro/db/Where.java
new file mode 100644
index 0000000..13f66f9
--- /dev/null
+++ b/src/main/java/xyz/wbsite/jmacro/db/Where.java
@@ -0,0 +1,94 @@
+package xyz.wbsite.jmacro.db;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Where {
+ private String sql;
+ private Object[] args;
+
+ private Where() {
+ }
+
+ public String getSql() {
+ return sql;
+ }
+
+ public void setSql(String sql) {
+ this.sql = sql;
+ }
+
+ public Object[] getArgs() {
+ return args;
+ }
+
+ public void setArgs(Object[] args) {
+ this.args = args;
+ }
+
+ public Where(String sql, Object[] args) {
+ this.sql = sql;
+ this.args = args;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private StringBuilder sb = new StringBuilder();
+ private List