diff --git a/.gitignore b/.gitignore index eb68f493e738eb6e3417eb7ad47a1d5183c002c0..47fa028e9763adbc073c260252a6486bd999cf46 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,15 @@ # Default ignored files #/.gitignore -/.idea -/xJavaFxTool.iml -/logs -/target +.idea/ +*.iml +logs/ +target/ libs/ + system_plugin_list.json RUNNING_PID +gradle +.gradle +build +out diff --git a/README.md b/README.md index f35a1f48be3580f95f65e1be9f16d77c171b6bed..1d8c6a472b7de405a028cd34b863e5d4cea20481 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,13 @@ **腾讯云开发平台地址:**[xJavaFxTool](https://dev.tencent.com/u/xwintop/p/xJavaFxTool) -![](https://img.shields.io/:license-apache-blue.svg) ![](https://img.shields.io/badge/JDK-1.8+-green.svg) ![](https://gitee.com/xwintop/xJavaFxTool/badge/star.svg?theme=dark) ![](https://img.shields.io/github/stars/864381832/xJavaFxTool.svg?style=social) +[![](https://img.shields.io/:license-apache-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) +[![](https://img.shields.io/badge/JDK-17+-green.svg)](https://www.oracle.com/technetwork/java/javase/downloads/index.html) +[![](https://img.shields.io/badge/maven-v3.6.3-blue)](https://maven.apache.org) +[![](https://gitee.com/xwintop/xJavaFxTool/badge/star.svg?theme=dark)](https://gitee.com/xwintop/xJavaFxTool/stargazers) +[![](https://img.shields.io/github/stars/864381832/xJavaFxTool.svg?style=social)](https://github.com/864381832/xJavaFxTool) [![](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=xJavaFxTool) +![系统](https://img.shields.io/badge/系统-win%20%7C%20mac%20%7C%20linux-007EC6) [英文说明/English Documentation](README_EN.md) @@ -18,7 +23,7 @@ xJavaFxTool是使用javaFx开发的实用小工具集,利用业余时间把工 由于SpringBoot的火热,项目已经出SpringBoot-javafx版本,[xJavaFxTool-spring](https://gitee.com/xwintop/xJavaFxTool-spring) 欢迎参考,谢谢。 #### 下载试用地址: -- 可直接运行的jar包(本地需要有jdk1.8环境)[xJavaFxTool-0.2.3.jar](https://xwintop.gitee.io/maven/package/xJavaFxTool/xJavaFxTool-0.2.3.jar) +- 可直接运行的jar包(本地需要有jdk17环境)[xJavaFxTool-0.2.3-jdk11.jar](https://xwintop.gitee.io/maven/package/xJavaFxTool/xJavaFxTool-0.2.3-jdk11.jar) - Windows x86安装包(兼容xp、windows7、8、10等系统)(请在下面网盘中下载) - Windows x64安装包(兼容xp、windows7、8、10等系统)[xJavaFxTool-0.2.3-windows-x64.exe](https://xwintop.gitee.io/maven/package/xJavaFxTool/xJavaFxTool-0.2.3-windows-x64.exe) - Linux x64 (请在下面网盘中下载) @@ -35,13 +40,13 @@ xJavaFxTool是使用javaFx开发的实用小工具集,利用业余时间把工 - [相关小游戏](https://gitee.com/xwintop/xJavaFxTool-Games) #### 环境搭建说明: -- 开发环境为jdk1.8,基于maven构建 -- 使用eclipase或Intellij Idea开发,推荐使用[Intellij Idea](https://www.jetbrains.com/?from=xJavaFxTool) +- 开发环境为jdk17,基于maven3.6.3构建 +- 使用eclipase或Intellij Idea开发,推荐使用[Intellij Idea](https://www.jetbrains.com/idea/?from=xJavaFxTool) - 本项目使用了[lombok](https://projectlombok.org/),在查看本项目时如果您没有下载lombok 插件,请先安装,不然找不到get/set等方法 - 依赖的[xcore包](https://gitee.com/xwintop/xcore)已上传至git托管的maven平台,git托管maven可参考教程(若无法下载请拉取项目自行编译)。[教程地址:点击进入](http://blog.csdn.net/u011747754/article/details/78574026) -- 使用[javafx-maven-plugin](https://github.com/javafx-maven-plugin/javafx-maven-plugin)插件进行打包操作(可打包windows、Linux、Mac安装包) -- 使用[exe4j](https://www.ej-technologies.com/download/exe4j/files)将jar包转成exe执行文件(仅供参考,可使用其它程序打包) +- 使用[javapackager](https://github.com/fvarrui/JavaPackager)插件进行打包操作(可打包windows、Linux、Mac安装包) - 使用[InnoSetup](http://www.jrsoftware.org/)可进行制作windows安装包 +- jdk11启动需添加参数java --add-opens java.base/jdk.internal.loader=ALL-UNNAMED --add-opens jdk.zipfs/jdk.nio.zipfs=ALL-UNNAMED -jar xJavaFxTool.jar [参考](https://blog.csdn.net/fighting_boss/article/details/91043555) #### 目前集成的小工具有(点击中文名可进入对应小工具的开源地址): | 序号 | 英文名 | 中文名 | 简介 | diff --git a/README_EN.md b/README_EN.md index 17c89c69719fb6cd7f58836868d48b3b8672f647..09f81bcd1dd6b02982ea119a99fcae10a0b5483c 100644 --- a/README_EN.md +++ b/README_EN.md @@ -4,20 +4,12 @@ **Tencent Cloud Development Platform Address:**[xJavaFxTool](https://dev.tencent.com/u/xwintop/p/xJavaFxTool) -

- - - - - - - - gitee star - - - github star - -

+[![](https://img.shields.io/:license-apache-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) +[![](https://img.shields.io/badge/JDK-17+-green.svg)](https://www.oracle.com/technetwork/java/javase/downloads/index.html) +[![](https://img.shields.io/badge/maven-v3.6.3-blue)](https://maven.apache.org) +[![](https://gitee.com/xwintop/xJavaFxTool/badge/star.svg?theme=dark)](https://gitee.com/xwintop/xJavaFxTool/stargazers) +[![](https://img.shields.io/github/stars/864381832/xJavaFxTool.svg?style=social)](https://github.com/864381832/xJavaFxTool) +[![](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=xJavaFxTool) [中文说明/Chinese Documentation](README.md) @@ -40,7 +32,7 @@ Due to the hot SpringBoot, the project has been released SpringBoot-javafx versi the plug-in jar package can be automatically loaded under the root directory libs (see the open source project [xJavaFxTool-plugin](https://gitee.com/xwintop/xJavaFxTool-plugin) for plug-in development examples , and the next step is to split the gadget into each plug-in and load it as needed. Currently, the plug-in function is not perfect, follow-up Split each function into modules and load them as needed to reduce the size of the jar package); #### Environmental construction instructions: -- The development environment is jdk1.8, based on maven build +- The development environment is jdk17, based on maven3.6.3 build - Developed with eclipase or Intellij Idea (Recommended to use [Intellij Idea](https://www.jetbrains.com/idea/) ) - This project uses [lombok](https://projectlombok.org/) . If you have not downloaded the lombok plugin when viewing this project, please install it first, otherwise you can't find the get/set method. - The dependent [xcore](https://gitee.com/xwintop/xcore) package has been uploaded to the git-hosted maven platform. The git hosting maven can refer to the tutorial (if you can't download it, please pull the project to compile it yourself ). Tutorial address: Click to enter diff --git a/assets/linux/xJavaFxTool.png b/assets/linux/xJavaFxTool.png new file mode 100644 index 0000000000000000000000000000000000000000..1a58fdd65ac5ad8297daf332e16c20c1ed4ddde3 Binary files /dev/null and b/assets/linux/xJavaFxTool.png differ diff --git a/assets/mac/xJavaFxTool.icns b/assets/mac/xJavaFxTool.icns new file mode 100644 index 0000000000000000000000000000000000000000..9c433da283392920a1bb07de88d09d4835ac3ae0 Binary files /dev/null and b/assets/mac/xJavaFxTool.icns differ diff --git a/assets/windows/xJavaFxTool.ico b/assets/windows/xJavaFxTool.ico new file mode 100644 index 0000000000000000000000000000000000000000..0c93826acadc11506faa1fa0275e16bb0bc95e58 Binary files /dev/null and b/assets/windows/xJavaFxTool.ico differ diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..fabe58bec91afc8cb92674adc6a208b377b7ea23 --- /dev/null +++ b/build.gradle @@ -0,0 +1,72 @@ +buildscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath 'org.openjfx:javafx-plugin:0.0.12' + } +} + +plugins { + id 'java' + id 'application' + id 'maven-publish' + id 'org.openjfx.javafxplugin' version '0.0.12' + id 'org.beryx.jlink' version '2.24.4' +} + +apply plugin: 'org.openjfx.javafxplugin' + +repositories { + mavenLocal() + maven { + url = uri('https://maven.aliyun.com/repository/public') + } + + maven { + url = uri('https://jitpack.io') + } +} + +dependencies { + implementation 'org.openjfx:javafx-controls:17.0.2' + implementation 'org.openjfx:javafx-base:17.0.2' + implementation 'org.openjfx:javafx-graphics:17.0.2' + implementation 'org.openjfx:javafx-fxml:17.0.2' + implementation 'org.openjfx:javafx-swing:17.0.2' + implementation 'org.openjfx:javafx-media:17.0.2' + implementation 'org.openjfx:javafx-web:17.0.2' + implementation 'org.openjfx:javafx-graphics:17.0.2' + implementation 'org.openjfx:javafx-graphics:17.0.2' + implementation 'org.openjfx:javafx-graphics:17.0.2' + implementation 'io.github.classgraph:classgraph:4.8.100' + implementation 'com.gitee.xwintop:xcore:0.0.6-jdk17' + implementation 'com.github.oshi:oshi-core:5.7.5' + testImplementation 'junit:junit:4.12' + compileOnly 'org.projectlombok:lombok:1.18.22' +} + +group = 'com.xwintop' +version = '0.2.3-jdk17' +description = 'xJavaFxTool' +sourceCompatibility = '17' + +javafx { + version = "17.0.2" + modules = ['javafx.controls', 'javafx.fxml', 'javafx.media', 'javafx.swing', 'javafx.web'] + configuration = 'compileOnly' +} + +jlink { +// mergedModule { +// requires 'java.naming' +// requires 'java.xml' +// } + launcher{ + name = 'xJavaFxTool' + mainClassName = 'com.xwintop.xJavaFxTool.XJavaFxToolMain' + jvmArgs = ['-Dlogback.configurationFile=./logback.xml'] + } +} diff --git a/gradlew b/gradlew new file mode 100755 index 0000000000000000000000000000000000000000..4f906e0c811fc9e230eb44819f509cd0627f2600 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000000000000000000000000000000000000..107acd32c4e687021ef32db511e8a206129b88ec --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/pom.xml b/pom.xml index 944033170fb1da4d4815db0212102c9daffebbc7..ba48e21c8e2a8b7aafac0611fda66cab70041171 100755 --- a/pom.xml +++ b/pom.xml @@ -1,20 +1,25 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.xwintop xJavaFxTool - 0.2.3 + 0.3.1 jar xJavaFxTool 基于JavaFx搭建的实用小工具集合 + + xwintop + https://gitee.com/xwintop + https://gitee.com/xwintop/xJavaFxTool UTF-8 true - 1.8 - 1.8 + 17 + 17 + 17.0.2 @@ -25,65 +30,49 @@ jitpack.io https://jitpack.io - - spring-snapshots - http://repo.spring.io/snapshot - - true - - - - spring-milestones - http://repo.spring.io/milestone - junit junit - 4.12 + 4.13.2 test + com.gitee.xwintop xcore - 0.0.6 + 0.0.7 org.projectlombok lombok - 1.18.6 + 1.18.22 true provided - - - jaxen - jaxen - 1.2.0 - - + + - com.github.oshi - oshi-core - 3.9.1 + io.github.classgraph + classgraph + 4.8.100 - org.apache.maven.plugins maven-assembly-plugin - 2.5.5 + 3.3.0 xJavaFxTool false utf-8 - com.xwintop.xJavaFxTool.Main + com.xwintop.xJavaFxTool.XJavaFxToolMain @@ -100,37 +89,46 @@ + + + + + + + + - com.zenjava - javafx-maven-plugin - 8.8.3 + io.github.fvarrui + javapackager + 1.6.5 - com.xwintop.xJavaFxTool.Main - xwintop - xJavaFxTool + true + com.xwintop.xJavaFxTool.XJavaFxToolMain + true + auto + true + true + + + true + false + + installForAllUsers + true + false + false + false + false + false + + compiler:Default.isl + compiler:Languages\English.isl + + + + - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.1.1 - - private - true - - -Xdoclint:none - - - - - attach-javadocs - - jar - - - - diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000000000000000000000000000000000000..2cda093ed4757f6539ead2bbd970f0b0eb4732f2 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,5 @@ +/* + * This file was generated by the Gradle 'init' task. + */ + +rootProject.name = 'xJavaFxTool' diff --git a/src/main/java/com/xwintop/xJavaFxTool/Main.java b/src/main/java/com/xwintop/xJavaFxTool/XJavaFxToolApplication.java similarity index 56% rename from src/main/java/com/xwintop/xJavaFxTool/Main.java rename to src/main/java/com/xwintop/xJavaFxTool/XJavaFxToolApplication.java index 6f2ba1304f5cb6af04436fb2f3c42c3ed5a9bc4d..553814030366a5233dd4e6fada943566f49b98e8 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/Main.java +++ b/src/main/java/com/xwintop/xJavaFxTool/XJavaFxToolApplication.java @@ -1,16 +1,12 @@ package com.xwintop.xJavaFxTool; -import com.jfoenix.controls.JFXDecorator; import com.xwintop.xJavaFxTool.controller.IndexController; import com.xwintop.xJavaFxTool.utils.Config; import com.xwintop.xJavaFxTool.utils.Config.Keys; import com.xwintop.xJavaFxTool.utils.StageUtils; -import com.xwintop.xJavaFxTool.utils.XJavaFxSystemUtil; +import com.xwintop.xJavaFxTool.utils.VersionChecker; import com.xwintop.xcore.javafx.FxApp; import com.xwintop.xcore.javafx.dialog.FxAlerts; -import com.xwintop.xcore.util.javafx.JavaFxViewUtil; -import java.io.IOException; -import java.util.ResourceBundle; import javafx.application.Application; import javafx.application.Platform; import javafx.event.Event; @@ -20,14 +16,14 @@ import javafx.scene.Scene; import javafx.stage.Stage; import lombok.extern.slf4j.Slf4j; +import java.io.IOException; +import java.util.ResourceBundle; + /** - * @ClassName: Main - * @Description: 启动类 - * @author: xufeng - * @date: 2017年11月10日 下午4:34:11 + * JavaFX 入口,从 Java 9+ 开始入口类不应再包含 main 方法。 */ @Slf4j -public class Main extends Application { +public class XJavaFxToolApplication extends Application { public static final String LOGO_PATH = "/images/icon.jpg"; @@ -35,61 +31,40 @@ public class Main extends Application { private static Stage stage; - public static void main(String[] args) { - - XJavaFxSystemUtil.initSystemLocal(); // 初始化本地语言 - XJavaFxSystemUtil.addJarByLibs(); // 添加外部jar包 - - launch(args); - } - @Override public void start(Stage primaryStage) throws Exception { stage = primaryStage; // 初始化 JavaFX 全局设置 FxApp.init(primaryStage, LOGO_PATH); - FxApp.setupIcon(primaryStage); - FxApp.styleSheets.add(Main.class.getResource("/css/jfoenix-main.css").toExternalForm()); + FxApp.styleSheets.add(XJavaFxToolApplication.class.getResource("/css/jfoenix-main.css").toExternalForm()); + +// if (SystemUtil.getOsInfo().isMac()) { + //Mac下设置dock栏图标 +// Taskbar.getTaskbar().setIconImage(ImageIO.read(XJavaFxToolApplication.class.getResourceAsStream(LOGO_PATH))); +// } primaryStage.setResizable(true); primaryStage.setTitle(RESOURCE_BUNDLE.getString("Title") + Config.xJavaFxToolVersions); primaryStage.setOnCloseRequest(this::confirmExit); - if (Config.getBoolean(Keys.NewLauncher, false)) { - loadNewUI(primaryStage); - } else { - loadClassicUI(primaryStage); - } + // 只启用新UI,因为: + // 1. 新UI启动时不扫描插件目录,启动更快; + // 2. 新UI使用独立的ClassLoader加载插件,兼容性更好; + // 3. 新UI本身体验较好。 + loadClassicUI(primaryStage); StageUtils.loadPrimaryStageBound(primaryStage); + primaryStage.setOnShown(windowEvent -> { + VersionChecker.checkNewVersion(); + }); primaryStage.show(); - StageUtils.updateStageStyle(primaryStage); - } - - private void loadNewUI(Stage primaryStage) throws IOException { - FXMLLoader fxmlLoader = new FXMLLoader(); - fxmlLoader.setLocation(Main.class.getResource("/com/xwintop/xJavaFxTool/fxmlView/newui/main.fxml")); - fxmlLoader.setResources(RESOURCE_BUNDLE); - - Parent root = fxmlLoader.load(); - primaryStage.setScene(new Scene(root)); } private void loadClassicUI(Stage primaryStage) throws IOException { FXMLLoader fXMLLoader = IndexController.getFXMLLoader(); Parent root = fXMLLoader.load(); - - JFXDecorator decorator = JavaFxViewUtil.getJFXDecorator( - primaryStage, - RESOURCE_BUNDLE.getString("Title") + Config.xJavaFxToolVersions, - LOGO_PATH, - root - ); - decorator.setOnCloseButtonAction(() -> confirmExit(null)); - - Scene scene = JavaFxViewUtil.getJFXDecoratorScene(decorator); - primaryStage.setScene(scene); + primaryStage.setScene(new Scene(root)); } private void confirmExit(Event event) { @@ -115,6 +90,6 @@ public class Main extends Application { } public static void setStage(Stage stage) { - Main.stage = stage; + XJavaFxToolApplication.stage = stage; } } diff --git a/src/main/java/com/xwintop/xJavaFxTool/XJavaFxToolMain.java b/src/main/java/com/xwintop/xJavaFxTool/XJavaFxToolMain.java new file mode 100644 index 0000000000000000000000000000000000000000..7d25db2f36c28a6150acb6e01308ac3ae10042cf --- /dev/null +++ b/src/main/java/com/xwintop/xJavaFxTool/XJavaFxToolMain.java @@ -0,0 +1,17 @@ +package com.xwintop.xJavaFxTool; + +import com.xwintop.xJavaFxTool.utils.XJavaFxSystemUtil; +import javafx.application.Application; +import lombok.extern.slf4j.Slf4j; + +/** + * 程序入口 + */ +@Slf4j +public class XJavaFxToolMain { + + public static void main(String[] args) { + XJavaFxSystemUtil.initSystemLocal(); // 初始化本地语言 + Application.launch(XJavaFxToolApplication.class, args); + } +} diff --git a/src/main/java/com/xwintop/xJavaFxTool/controller/IndexController.java b/src/main/java/com/xwintop/xJavaFxTool/controller/IndexController.java index 0910b2e8ca145df1ab143ba9609aaecc87385b5a..8fe8e0ac188d4163c5f5d8c70eea17e07f68b5f6 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/controller/IndexController.java +++ b/src/main/java/com/xwintop/xJavaFxTool/controller/IndexController.java @@ -1,52 +1,42 @@ package com.xwintop.xJavaFxTool.controller; -import static com.xwintop.xJavaFxTool.Main.RESOURCE_BUNDLE; -import static com.xwintop.xJavaFxTool.utils.Config.Keys.NotepadEnabled; - +import com.xwintop.xJavaFxTool.XJavaFxToolApplication; import com.xwintop.xJavaFxTool.controller.index.PluginManageController; -import com.xwintop.xJavaFxTool.model.ToolFxmlLoaderConfiguration; +import com.xwintop.xJavaFxTool.event.AppEvents; +import com.xwintop.xJavaFxTool.event.PluginEvent; +import com.xwintop.xJavaFxTool.model.PluginJarInfo; +import com.xwintop.xJavaFxTool.newui.PluginCategoryController; +import com.xwintop.xJavaFxTool.newui.PluginItemController; import com.xwintop.xJavaFxTool.plugin.PluginManager; +import com.xwintop.xJavaFxTool.plugin.PluginParser; import com.xwintop.xJavaFxTool.services.IndexService; -import com.xwintop.xJavaFxTool.services.index.PluginManageService; import com.xwintop.xJavaFxTool.services.index.SystemSettingService; import com.xwintop.xJavaFxTool.utils.Config; import com.xwintop.xJavaFxTool.view.IndexView; +import com.xwintop.xcore.javafx.FxApp; +import com.xwintop.xcore.javafx.dialog.FxDialog; import com.xwintop.xcore.util.ConfigureUtil; import com.xwintop.xcore.util.HttpClientUtil; import com.xwintop.xcore.util.javafx.AlertUtil; import com.xwintop.xcore.util.javafx.JavaFxSystemUtil; -import com.xwintop.xcore.util.javafx.JavaFxViewUtil; -import java.io.File; -import java.io.InputStream; -import java.net.URL; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.ResourceBundle; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; import javafx.application.Platform; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; -import javafx.scene.Parent; -import javafx.scene.control.ContextMenu; import javafx.scene.control.Menu; import javafx.scene.control.MenuItem; +import javafx.scene.control.Tab; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.beanutils.BeanUtils; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang3.time.DateFormatUtils; -import org.dom4j.Attribute; -import org.dom4j.Document; -import org.dom4j.Element; -import org.dom4j.io.SAXReader; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; + +import java.io.File; +import java.net.URL; +import java.util.*; /** * @ClassName: IndexController @@ -58,184 +48,147 @@ import org.dom4j.io.SAXReader; @Getter @Setter public class IndexController extends IndexView { - public static final String QQ_URL = "https://support.qq.com/product/127577"; public static final String STATISTICS_URL = "https://xwintop.gitee.io/maven/tongji/xJavaFxTool.html"; - private Map menuMap = new HashMap<>(); + public static final String FAVORITE_CATEGORY_NAME = XJavaFxToolApplication.RESOURCE_BUNDLE.getString("favoriteCategory"); private Map menuItemMap = new HashMap<>(); private IndexService indexService = new IndexService(this); - private ContextMenu contextMenu = new ContextMenu(); + // 实现搜索用 + private List pluginItemControllers = new ArrayList<>(); + + private Map categoryControllers = new HashMap<>(); public static FXMLLoader getFXMLLoader() { - URL url = Object.class.getResource("/com/xwintop/xJavaFxTool/fxmlView/Index.fxml"); - return new FXMLLoader(url, RESOURCE_BUNDLE); + URL url = IndexController.class.getResource("/com/xwintop/xJavaFxTool/fxmlView/Index.fxml"); + return new FXMLLoader(url, XJavaFxToolApplication.RESOURCE_BUNDLE); } @Override public void initialize(URL location, ResourceBundle resources) { this.bundle = resources; - initView(); initEvent(); initService(); initNotepad(); - - this.indexService.addWebView(RESOURCE_BUNDLE.getString("feedback"), QQ_URL, null); - this.tongjiWebView.getEngine().load(STATISTICS_URL); } private void initNotepad() { - if (Config.getBoolean(NotepadEnabled, true)) { - addNodepadAction(null); - } +// if (Config.getBoolean(Config.Keys.NotepadEnabled, true)) { +// addNodepadAction(null); +// } } private void initView() { - menuMap.put("toolsMenu", toolsMenu); - menuMap.put("moreToolsMenu", moreToolsMenu); - File libPath = new File("libs/"); - // 获取所有的.jar和.zip文件 - File[] jarFiles = libPath.listFiles((dir, name) -> name.endsWith(".jar")); - if (jarFiles != null) { - for (File jarFile : jarFiles) { - if (!PluginManageService.isPluginEnabled(jarFile.getName())) { - continue; - } - try { - this.addToolMenu(jarFile); - } catch (Exception e) { - log.error("加载工具出错:", e); - } - } - } + this.indexService.addWebView(XJavaFxToolApplication.RESOURCE_BUNDLE.getString("feedback"), QQ_URL, null); + this.tongjiWebView.getEngine().load(STATISTICS_URL); + this.tabPaneMain.getSelectionModel().select(0); } private void initEvent() { + mainMenuBar.setUseSystemMenuBar(true); myTextField.textProperty().addListener((observable, oldValue, newValue) -> selectAction(newValue)); - myButton.setOnAction(arg0 -> { - selectAction(myTextField.getText()); - }); } private void initService() { + loadPlugins(); // 加载插件列表到界面上 + AppEvents.addEventHandler(PluginEvent.PLUGIN_DOWNLOADED, pluginEvent -> { + loadPlugins(); + }); } - public void addToolMenu(File file) throws Exception { - Map toolMap = new HashMap<>(); - List toolList = new ArrayList<>(); - - try (JarFile jarFile = new JarFile(file)) { - JarEntry entry = jarFile.getJarEntry("config/toolFxmlLoaderConfiguration.xml"); - if (entry == null) { - return; - } - InputStream input = jarFile.getInputStream(entry); - SAXReader saxReader = new SAXReader(); - Document document = saxReader.read(input); - Element root = document.getRootElement(); - List elements = root.elements("ToolFxmlLoaderConfiguration"); - for (Element configurationNode : elements) { - ToolFxmlLoaderConfiguration toolFxmlLoaderConfiguration = new ToolFxmlLoaderConfiguration(); - List attributes = configurationNode.attributes(); - for (Attribute configuration : attributes) { - BeanUtils.copyProperty(toolFxmlLoaderConfiguration, configuration.getName(), configuration.getValue()); - } - List childrenList = configurationNode.elements(); - for (Element configuration : childrenList) { - BeanUtils.copyProperty(toolFxmlLoaderConfiguration, configuration.getName(), configuration.getStringValue()); - } - if (StringUtils.isEmpty(toolFxmlLoaderConfiguration.getMenuParentId())) { - toolFxmlLoaderConfiguration.setMenuParentId("moreToolsMenu"); - } - if (toolFxmlLoaderConfiguration.getIsMenu()) { - if (menuMap.get(toolFxmlLoaderConfiguration.getMenuId()) == null) { - toolMap.putIfAbsent(toolFxmlLoaderConfiguration.getMenuId(), toolFxmlLoaderConfiguration); - } - } else { - toolList.add(toolFxmlLoaderConfiguration); - } - } - } - toolList.addAll(toolMap.values()); - this.addMenu(toolList); + /** + * 加载/刷新插件列表 + */ + public void loadPlugins() { + this.pluginCategories.getChildren().clear(); + this.pluginItemControllers.clear(); + this.categoryControllers.clear(); + this.menuItemMap.clear(); + this.moreToolsMenu.getItems().clear(); + + PluginManager pluginManager = PluginManager.getInstance(); + pluginManager.loadLocalPlugins(); + pluginManager.getEnabledPluginList().forEach(this::loadPlugin); } - private void addMenu(List toolList) { - for (ToolFxmlLoaderConfiguration toolConfig : toolList) { - try { - if (StringUtils.isEmpty(toolConfig.getResourceBundleName())) { - if (StringUtils.isNotEmpty(bundle.getString(toolConfig.getTitle()))) { - toolConfig.setTitle(bundle.getString(toolConfig.getTitle())); - } - } else { - ResourceBundle resourceBundle = ResourceBundle.getBundle(toolConfig.getResourceBundleName(), Config.defaultLocale); - if (StringUtils.isNotEmpty(resourceBundle.getString(toolConfig.getTitle()))) { - toolConfig.setTitle(resourceBundle.getString(toolConfig.getTitle())); - } - } - } catch (Exception e) { - log.error("加载菜单失败", e); - } - if (toolConfig.getIsMenu()) { - Menu menu = new Menu(toolConfig.getTitle()); - if (StringUtils.isNotEmpty(toolConfig.getIconPath())) { - ImageView imageView = new ImageView(new Image(toolConfig.getIconPath())); - imageView.setFitHeight(18); - imageView.setFitWidth(18); - menu.setGraphic(imageView); - } - menuMap.put(toolConfig.getMenuId(), menu); + /** + * 加载单个插件到界面,要求插件已经经过 {@link PluginParser#parse(File, PluginJarInfo)} 解析 + * + * @param jarInfo 插件信息 + */ + private void loadPlugin(PluginJarInfo jarInfo) { + if (!jarInfo.getFile().exists()) { + log.info("跳过插件 {}: 文件不存在", jarInfo.getName()); + return; + } + if (BooleanUtils.isFalse(jarInfo.getIsEnable())) { + log.info("跳过插件 {}: 插件未启用", jarInfo.getName()); + return; + } + String menuParentTitle = jarInfo.getMenuParentTitle(); + if (menuParentTitle == null) { + log.info("跳过插件 {}: menuParentTitle 为空", jarInfo.getName()); + return; + } + String categoryName = jarInfo.getIsFavorite() ? FAVORITE_CATEGORY_NAME : XJavaFxToolApplication.RESOURCE_BUNDLE.getString(menuParentTitle); + PluginCategoryController category = categoryControllers.computeIfAbsent( + categoryName, __ -> { + PluginCategoryController _category = PluginCategoryController.newInstance(categoryName); + addCategory(_category); + return _category; } + ); + + PluginItemController item = PluginItemController.newInstance(jarInfo); + item.setIndexController(this); + category.addItem(item); + + if (!pluginItemControllers.contains(item)) { + pluginItemControllers.add(item); } - for (ToolFxmlLoaderConfiguration toolConfig : toolList) { - if (toolConfig.getIsMenu()) { - menuMap.get(toolConfig.getMenuParentId()).getItems().add(menuMap.get(toolConfig.getMenuId())); - } + addMenu(jarInfo); + } + + private void addCategory(PluginCategoryController category) { + if (category.lblCategoryName.getText().equals(FAVORITE_CATEGORY_NAME)) { + this.pluginCategories.getChildren().add(0, category.root); + } else { + this.pluginCategories.getChildren().add(category.root); } + } - for (ToolFxmlLoaderConfiguration toolConfig : toolList) { - if (toolConfig.getIsMenu()) { - continue; + private void addMenu(PluginJarInfo jarInfo) { + MenuItem menu = moreToolsMenu.getItems().stream().filter(menuItem1 -> jarInfo.getMenuParentId().equals(menuItem1.getId())).findAny().orElse(null); + if (menu == null) { + menu = new Menu(XJavaFxToolApplication.RESOURCE_BUNDLE.getString(jarInfo.getMenuParentTitle())); + menu.setId(jarInfo.getMenuParentId()); + moreToolsMenu.getItems().add(menu); } - MenuItem menuItem = new MenuItem(toolConfig.getTitle()); - if (StringUtils.isNotEmpty(toolConfig.getIconPath())) { - ImageView imageView = new ImageView(new Image(toolConfig.getIconPath())); + MenuItem menuItem = new MenuItem(jarInfo.getTitle()); + if (StringUtils.isNotEmpty(jarInfo.getIconPath())) { + ImageView imageView = new ImageView(new Image(jarInfo.getIconPath())); imageView.setFitHeight(18); imageView.setFitWidth(18); menuItem.setGraphic(imageView); } - if ("Node".equals(toolConfig.getControllerType())) { - menuItem.setOnAction((ActionEvent event) -> { - indexService.addContent(menuItem.getText(), toolConfig.getUrl(), toolConfig.getResourceBundleName(), toolConfig.getIconPath()); - }); - if (toolConfig.getIsDefaultShow()) { - indexService.addContent(menuItem.getText(), toolConfig.getUrl(), toolConfig.getResourceBundleName(), toolConfig.getIconPath()); - } - } else if ("WebView".equals(toolConfig.getControllerType())) { - menuItem.setOnAction((ActionEvent event) -> { - indexService.addWebView(menuItem.getText(), toolConfig.getUrl(), toolConfig.getIconPath()); - }); - if (toolConfig.getIsDefaultShow()) { - indexService.addWebView(menuItem.getText(), toolConfig.getUrl(), toolConfig.getIconPath()); - } - } - menuMap.get(toolConfig.getMenuParentId()).getItems().add(menuItem); + menuItem.setOnAction((ActionEvent event) -> { + indexService.loadPlugin(jarInfo); + }); + ((Menu)menu).getItems().add(menuItem); menuItemMap.put(menuItem.getText(), menuItem); - } } public void selectAction(String selectText) { - if (contextMenu.isShowing()) { - contextMenu.hide(); - } - contextMenu = indexService.getSelectContextMenu(selectText); - contextMenu.show(myTextField, null, 0, myTextField.getHeight()); + boolean notSearching = StringUtils.isBlank(selectText); + pluginItemControllers.forEach(itemController -> { + itemController.setVisible(notSearching || itemController.matchKeyword(selectText)); + }); } @FXML @@ -246,7 +199,7 @@ public class IndexController extends IndexView { @FXML private void closeAllTabAction() { - tabPaneMain.getTabs().clear(); + tabPaneMain.getTabs().removeIf(Tab::isClosable); } @FXML @@ -268,18 +221,17 @@ public class IndexController extends IndexView { @FXML private void pluginManageAction() throws Exception { - FXMLLoader fXMLLoader = PluginManageController.getFXMLLoader(); - Parent root = fXMLLoader.load(); - PluginManageController pluginManageController = fXMLLoader.getController(); - pluginManageController.setOnPluginDownloaded(jarFile -> { - try { - this.addToolMenu(jarFile); - PluginManager.getInstance().loadLocalPlugins(); - } catch (Exception e) { - log.error("加载工具出错:", e); - } - }); - JavaFxViewUtil.openNewWindow(bundle.getString("plugin_manage"), root); +// FXMLLoader fXMLLoader = PluginManageController.getFXMLLoader(); +// Parent root = fXMLLoader.load(); +// JavaFxViewUtil.openNewWindow(bundle.getString("plugin_manage"), root); + new FxDialog() + .setBodyFxml(PluginManageController.FXML) + .setOwner(FxApp.primaryStage) + .setResizable(true) + .setTitle(XJavaFxToolApplication.RESOURCE_BUNDLE.getString("plugin_manage")) + .setPrefWidth(800) + .withStage(stage -> stage.setOnCloseRequest(event -> loadPlugins())) + .show(); } @FXML @@ -300,7 +252,7 @@ public class IndexController extends IndexView { @FXML private void openLogFileAction() { - String filePath = "logs/logFile." + DateFormatUtils.format(new Date(), "yyyy-MM-dd") + ".log"; + String filePath = "logs/logFile.log"; JavaFxSystemUtil.openDirectory(filePath); } diff --git a/src/main/java/com/xwintop/xJavaFxTool/controller/NotepadController.java b/src/main/java/com/xwintop/xJavaFxTool/controller/NotepadController.java deleted file mode 100644 index e32b839e8395cd91d760b81108635e39862609a2..0000000000000000000000000000000000000000 --- a/src/main/java/com/xwintop/xJavaFxTool/controller/NotepadController.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.xwintop.xJavaFxTool.controller; - -import com.xwintop.xJavaFxTool.utils.NodeUtils; -import com.xwintop.xJavaFxTool.view.NotepadView; -import java.io.IOException; -import javafx.fxml.FXMLLoader; -import javafx.scene.Node; -import javafx.scene.control.CheckMenuItem; -import javafx.scene.control.ContextMenu; -import javafx.scene.control.Tab; -import javafx.scene.control.TextArea; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class NotepadController extends NotepadView { - - private int counter = 0; - - public void initialize() { - tabPane.getSelectionModel().selectedIndexProperty().addListener(((observable, oldValue, newValue) -> { - int index = newValue.intValue(); - if (index + 1 == tabPane.getTabs().size()) { - tabPane.getTabs().add(index, createTab()); - tabPane.getSelectionModel().select(index); - } - })); - - Tab firstTab = tabPane.getTabs().get(0); - setupTab(firstTab, firstTab.getContent()); - } - - private Tab createTab() { - counter += 1; - Tab tab = new Tab("未命名" + counter); - - try { - Node content = FXMLLoader.load(NotepadController.class - .getResource("/com/xwintop/xJavaFxTool/fxmlView/notepad-tab.fxml") - ); - - setupTab(tab, content); - - tab.setContent(content); - } catch (IOException e) { - log.error("读取 FXML 失败", e); - } - return tab; - } - - private void setupTab(Tab tab, Node content) { - - TextArea textArea = (TextArea) content.lookup(".text-area"); - if (textArea != null) { - NodeUtils.setUserData(textArea, "id", counter); - textArea.textProperty().addListener((_ob, _old, _new) -> { - if (_new.trim().length() == 0) { - tab.setText("未命名" + NodeUtils.getUserData(textArea, "id")); - } else if (_new.contains("\n")) { - tab.setText(_new.substring(0, _new.indexOf("\n"))); - } else { - tab.setText(_new); - } - }); - } - - tab.setContextMenu(new ContextMenu( - wrapTextMenuItem(textArea) - )); - } - - private CheckMenuItem wrapTextMenuItem(TextArea textArea) { - CheckMenuItem menuItem = new CheckMenuItem("自动换行"); - if (textArea != null) { - menuItem.setOnAction(event -> textArea.setWrapText(menuItem.isSelected())); - } - return menuItem; - } -} diff --git a/src/main/java/com/xwintop/xJavaFxTool/controller/index/PluginManageController.java b/src/main/java/com/xwintop/xJavaFxTool/controller/index/PluginManageController.java index 76be6cc7aeda5a9c5d889331290bba224c99b7ab..e8063f104578f4a9d68acb8fd6de4a9115c0d434 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/controller/index/PluginManageController.java +++ b/src/main/java/com/xwintop/xJavaFxTool/controller/index/PluginManageController.java @@ -10,25 +10,16 @@ import com.xwintop.xJavaFxTool.plugin.PluginManager; import com.xwintop.xJavaFxTool.plugin.PluginParser; import com.xwintop.xJavaFxTool.services.index.PluginManageService; import com.xwintop.xJavaFxTool.view.index.PluginManageView; +import com.xwintop.xcore.javafx.dialog.FxAlerts; import com.xwintop.xcore.util.javafx.FileChooserUtil; import com.xwintop.xcore.util.javafx.JavaFxViewUtil; import com.xwintop.xcore.util.javafx.TooltipUtil; -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.util.Map; -import java.util.ResourceBundle; -import java.util.function.Consumer; +import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.collections.transformation.FilteredList; import javafx.fxml.FXMLLoader; -import javafx.scene.control.Button; -import javafx.scene.control.ContentDisplay; -import javafx.scene.control.ContextMenu; -import javafx.scene.control.MenuItem; -import javafx.scene.control.TableCell; -import javafx.scene.control.TableColumn; +import javafx.scene.control.*; import javafx.stage.FileChooser.ExtensionFilter; import javafx.stage.Window; import javafx.util.Callback; @@ -36,6 +27,12 @@ import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.Map; +import java.util.ResourceBundle; + /** * 插件管理 * @@ -47,7 +44,6 @@ import lombok.extern.slf4j.Slf4j; @Setter @Slf4j public class PluginManageController extends PluginManageView { - public static final String FXML = "/com/xwintop/xJavaFxTool/fxmlView/index/PluginManage.fxml"; private PluginManageService pluginManageService = new PluginManageService(this); @@ -71,10 +67,6 @@ public class PluginManageController extends PluginManageView { return this.pluginDataTableView.getScene().getWindow(); } - public void setOnPluginDownloaded(Consumer onPluginDownloaded) { - this.pluginManageService.setOnPluginDownloaded(onPluginDownloaded); - } - private void initView() { addLocalPluginButton.setVisible(Boolean.parseBoolean(System.getProperty("localPluginEnabled", "false"))); @@ -86,13 +78,11 @@ public class PluginManageController extends PluginManageView { (mouseEvent, index) -> pluginManageService.setIsEnableTableColumn(index) ); - // TODO 实现插件的启用禁用 - downloadTableColumn.setCellFactory( - new Callback, String>, TableCell, String>>() { + new Callback<>() { @Override public TableCell, String> call(TableColumn, String> param) { - return new TableCell, String>() { + return new TableCell<>() { @Override protected void updateItem(String item, boolean empty) { super.updateItem(item, empty); @@ -118,39 +108,46 @@ public class PluginManageController extends PluginManageView { private void downloadPlugin(Map dataRow, Button downloadButton) { try { - PluginJarInfo pluginJarInfo = pluginManageService.downloadPluginJar(dataRow); - afterDownload(dataRow, downloadButton, pluginJarInfo); + pluginManageService.downloadPluginJar(dataRow, pluginJarInfo -> + Platform.runLater(() -> afterDownload(dataRow, downloadButton, pluginJarInfo)) + ); } catch (Exception e) { log.error("下载插件失败:", e); TooltipUtil.showToast("下载插件失败:" + e.getMessage()); } } - private void afterDownload( - Map dataRow, Button downloadButton, PluginJarInfo pluginJarInfo - ) throws IOException { + private void afterDownload(Map dataRow, Button downloadButton, PluginJarInfo pluginJarInfo) { + // 没有下载成功不做处理 + if (pluginJarInfo.getIsDownload() == null || !pluginJarInfo.getIsDownload()) { + return; + } - dataRow.put("isEnableTableColumn", "true"); - dataRow.put("isDownloadTableColumn", "已下载"); + try { + PluginManager.getInstance().saveToFile(); + TooltipUtil.showToast("插件 " + dataRow.get("nameTableColumn") + " 下载完成"); - downloadButton.setText("已下载"); - downloadButton.setDisable(true); + PluginClassLoader tempClassLoader = PluginClassLoader.create(pluginJarInfo.getFile()); + PluginParser.parse(pluginJarInfo.getFile(), pluginJarInfo, tempClassLoader); - pluginDataTableView.refresh(); - PluginManager.getInstance().saveToFile(); - TooltipUtil.showToast("插件 " + dataRow.get("nameTableColumn") + " 下载完成"); + dataRow.put("isEnableTableColumn", "true"); + dataRow.put("isDownloadTableColumn", "已下载"); - PluginClassLoader tempClassLoader = new PluginClassLoader(pluginJarInfo.getFile()); - PluginParser.parse(pluginJarInfo.getFile(), pluginJarInfo, tempClassLoader); + downloadButton.setText("已下载"); + downloadButton.setDisable(true); - AppEvents.fire(new PluginEvent(PluginEvent.PLUGIN_DOWNLOADED, pluginJarInfo)); + pluginDataTableView.refresh(); + AppEvents.fire(new PluginEvent(PluginEvent.PLUGIN_DOWNLOADED, pluginJarInfo)); + } catch (IOException e) { + log.error("", e); + FxAlerts.error("处理文件失败", e); + } } private void initEvent() { - // 右键菜单 - MenuItem mnuSavePluginConfig = new MenuItem("保存配置"); - mnuSavePluginConfig.setOnAction(ev -> { + ContextMenu contextMenu = new ContextMenu(); + JavaFxViewUtil.addMenuItem(contextMenu,"保存配置", actionEvent -> { try { PluginManager.getInstance().saveToFile(); TooltipUtil.showToast("保存配置成功"); @@ -158,14 +155,12 @@ public class PluginManageController extends PluginManageView { log.error("保存插件配置失败", ex); } }); - - ContextMenu contextMenu = new ContextMenu(mnuSavePluginConfig); + JavaFxViewUtil.addMenuItem(contextMenu,"删除插件", actionEvent -> { + pluginManageService.deletePlugin(); + }); pluginDataTableView.setContextMenu(contextMenu); - // 搜索 - selectPluginTextField.textProperty().addListener((_ob, _old, _new) -> { - pluginManageService.searchPlugin(_new); - }); + selectPluginTextField.textProperty().addListener((_ob, _old, _new) -> pluginManageService.searchPlugin(_new)); } private void initService() { diff --git a/src/main/java/com/xwintop/xJavaFxTool/controller/index/SystemSettingController.java b/src/main/java/com/xwintop/xJavaFxTool/controller/index/SystemSettingController.java index 3530046f8b96a962bc7a24da5d457a08af0e1179..d7ea8888e1e45f0e1fcc86db797a9aa7f45f1f03 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/controller/index/SystemSettingController.java +++ b/src/main/java/com/xwintop/xJavaFxTool/controller/index/SystemSettingController.java @@ -3,18 +3,18 @@ package com.xwintop.xJavaFxTool.controller.index; import com.xwintop.xJavaFxTool.utils.Config; import com.xwintop.xJavaFxTool.utils.Config.Keys; import com.xwintop.xJavaFxTool.view.index.SystemSettingView; -import java.net.URL; -import java.util.ResourceBundle; import javafx.stage.Stage; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import java.net.URL; +import java.util.ResourceBundle; + /** - * @ClassName: SystemSettingController - * @Description: 设置页面 - * @author: xufeng - * @date: 2020/2/25 0025 16:44 + * 设置页面 + * + * @author xufeng */ @Getter @@ -34,7 +34,6 @@ public class SystemSettingController extends SystemSettingView { exitShowAlertCheckBox.setSelected(Config.getBoolean(Keys.ConfirmExit, true)); addNotepadCheckBox.setSelected(Config.getBoolean(Keys.NotepadEnabled, true)); saveStageBoundCheckBox.setSelected(Config.getBoolean(Keys.RememberWindowLocation, true)); - chkNewLauncher.setSelected(Config.getBoolean(Keys.NewLauncher, false)); } catch (Exception e) { log.error("加载配置失败:", e); } @@ -45,7 +44,6 @@ public class SystemSettingController extends SystemSettingView { Config.set(Keys.ConfirmExit, exitShowAlertCheckBox.isSelected()); Config.set(Keys.NotepadEnabled, addNotepadCheckBox.isSelected()); Config.set(Keys.RememberWindowLocation, saveStageBoundCheckBox.isSelected()); - Config.set(Keys.NewLauncher, chkNewLauncher.isSelected()); if (newStage != null) { newStage.close(); diff --git a/src/main/java/com/xwintop/xJavaFxTool/event/AppEvents.java b/src/main/java/com/xwintop/xJavaFxTool/event/AppEvents.java index d6e6559d1e6559c82b988b83fa741b6844424b35..2001e5654af30a8eba0ab3d9fbebabf4d0458238 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/event/AppEvents.java +++ b/src/main/java/com/xwintop/xJavaFxTool/event/AppEvents.java @@ -11,7 +11,6 @@ import javafx.event.EventType; /** * 应用全局事件注册和触发 */ -@SuppressWarnings({"unchecked", "rawtypes"}) public class AppEvents { private static final AppEvents instance = new AppEvents(); @@ -22,8 +21,7 @@ public class AppEvents { * @param appEvent 事件对象 */ public static void fire(AppEvent appEvent) { - List handlers = instance.listeners - .getOrDefault(appEvent.getEventType(), Collections.emptyList()); + List handlers = instance.listeners.getOrDefault(appEvent.getEventType(), Collections.emptyList()); for (Consumer handler : handlers) { handler.accept(appEvent); diff --git a/src/main/java/com/xwintop/xJavaFxTool/model/PluginJarInfo.java b/src/main/java/com/xwintop/xJavaFxTool/model/PluginJarInfo.java index ba5ed1189eafeaa7ab8f0ea5952cfc22c8134657..d1500989b0d6e845aeb97aefec813bdefab1bbbf 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/model/PluginJarInfo.java +++ b/src/main/java/com/xwintop/xJavaFxTool/model/PluginJarInfo.java @@ -32,11 +32,11 @@ public class PluginJarInfo { ///////////////////////////////////////// 下面的属性在远程插件列表中不存在 - private Boolean isDownload; // 是否下载 + private Boolean isDownload; // 是否下载 - private Boolean isEnable; // 是否启用 + private Boolean isEnable = true; // 是否启用 - private Boolean isFavorite; // 是否置顶 + private Boolean isFavorite; // 是否置顶 private Integer localVersionNumber; // 插件本地版本 @@ -81,7 +81,6 @@ public class PluginJarInfo { @JSONField(serialize = false) public String getDefaultIconPath() { - return bundleName == null ? "" : - (bundleName.replace("locale.", "/logo/") + ".png"); + return bundleName == null ? "" : (bundleName.replace("locale.", "/logo/") + ".png"); } } diff --git a/src/main/java/com/xwintop/xJavaFxTool/newui/NewLauncherController.java b/src/main/java/com/xwintop/xJavaFxTool/newui/NewLauncherController.java index a3317e81e6ebc75f9e44bcc16b92b7b415ecaaf6..64211858d9e31edb0286bdeb7d29f420873cfc71 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/newui/NewLauncherController.java +++ b/src/main/java/com/xwintop/xJavaFxTool/newui/NewLauncherController.java @@ -1,224 +1,188 @@ -package com.xwintop.xJavaFxTool.newui; - -import static com.xwintop.xJavaFxTool.utils.BoolUtils.isNot; - -import com.xwintop.xJavaFxTool.Main; -import com.xwintop.xJavaFxTool.controller.IndexController; -import com.xwintop.xJavaFxTool.controller.index.PluginManageController; -import com.xwintop.xJavaFxTool.event.AppEvents; -import com.xwintop.xJavaFxTool.event.PluginEvent; -import com.xwintop.xJavaFxTool.model.PluginJarInfo; -import com.xwintop.xJavaFxTool.newui.creator.CreatePluginProjectService; -import com.xwintop.xJavaFxTool.newui.creator.PluginProjectInfo; -import com.xwintop.xJavaFxTool.plugin.PluginManager; -import com.xwintop.xJavaFxTool.plugin.PluginParser; -import com.xwintop.xJavaFxTool.services.index.SystemSettingService; -import com.xwintop.xcore.javafx.FxApp; -import com.xwintop.xcore.javafx.dialog.FxAlerts; -import com.xwintop.xcore.javafx.dialog.FxDialog; -import java.awt.Desktop; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import javafx.beans.Observable; -import javafx.scene.control.ButtonType; -import javafx.scene.control.CheckMenuItem; -import javafx.scene.control.ContextMenu; -import javafx.scene.control.Hyperlink; -import javafx.scene.control.TabPane; -import javafx.scene.control.TextField; -import javafx.scene.layout.VBox; -import javafx.scene.web.WebView; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; - -@Slf4j -public class NewLauncherController { - - public static final String FAVORITE_CATEGORY_NAME = "置顶"; - - public VBox pluginCategories; - - public WebView startWebView; - - public TabPane tabPane; - - public TextField txtSearch; - - public Hyperlink lnkCreatePlugin; - - private ContextMenu itemContextMenu; - - // 实现搜索用 - private final List pluginItemControllers = new ArrayList<>(); - - private final Map categoryControllers = new HashMap<>(); - - public void initialize() { - NewLauncherService.getInstance().setController(this); - txtSearch.textProperty().addListener(this::onSearchKeywordChanged); - - initContextMenu(); - loadPlugins(); // 加载插件列表到界面上 - - startWebView.getEngine().load(IndexController.QQ_URL); // 额外再打开一个反馈页面,可关闭 - - AppEvents.addEventHandler(PluginEvent.PLUGIN_DOWNLOADED, pluginEvent -> { - loadPlugins(); - }); - } - - private void initContextMenu() { - CheckMenuItem chkFavorite = new CheckMenuItem("置顶"); - chkFavorite.setStyle("-fx-padding: 0 35 0 0"); - - this.itemContextMenu = new ContextMenu(chkFavorite); - - chkFavorite.setOnAction(event -> { - CheckMenuItem _this = (CheckMenuItem) event.getSource(); - PluginItemController pluginItemController = - NewLauncherService.getInstance().getCurrentPluginItem(); - setFavorite(pluginItemController, _this.isSelected()); - }); - } - - public void onSearchKeywordChanged(Observable ob, String _old, String keyword) { - boolean notSearching = StringUtils.isBlank(keyword); - pluginItemControllers.forEach(itemController -> { - itemController.setVisible(notSearching || itemController.matchKeyword(keyword)); - }); - } - - private void setFavorite(PluginItemController itemController, boolean isFavorite) { - if (itemController == null) { - return; - } - - itemController.getPluginJarInfo().setIsFavorite(isFavorite); - PluginManager.getInstance().saveToFileQuietly(); - loadPlugins(); - } - - /** - * 加载/刷新插件列表 - */ - private void loadPlugins() { - - this.pluginCategories.getChildren().clear(); - this.pluginItemControllers.clear(); - this.categoryControllers.clear(); - - List pluginList = PluginManager.getInstance().getPluginList(); - pluginList.forEach(this::loadPlugin); - } - - /** - * 加载单个插件到界面,要求插件已经经过 {@link PluginParser#parse(File, PluginJarInfo)} 解析 - * - * @param jarInfo 插件信息 - */ - private void loadPlugin(PluginJarInfo jarInfo) { - - if (!jarInfo.getFile().exists()) { - log.info("跳过插件 {}: 文件不存在", jarInfo.getName()); - return; - } - - if (isNot(jarInfo.getIsEnable())) { - log.info("跳过插件 {}: 插件未启用", jarInfo.getName()); - return; - } - - String menuParentTitle = jarInfo.getMenuParentTitle(); - if (menuParentTitle == null) { - log.info("跳过插件 {}: menuParentTitle 为空", jarInfo.getName()); - return; - } - - String categoryName = jarInfo.getIsFavorite() ? - FAVORITE_CATEGORY_NAME : Main.RESOURCE_BUNDLE.getString(menuParentTitle); - - PluginCategoryController category = categoryControllers.computeIfAbsent( - categoryName, __ -> { - PluginCategoryController _category = - PluginCategoryController.newInstance(categoryName); - addCategory(_category); - return _category; - } - ); - - PluginItemController item = PluginItemController.newInstance(jarInfo); - item.setContextMenu(itemContextMenu); - category.addItem(item); - - if (!pluginItemControllers.contains(item)) { - pluginItemControllers.add(item); - } - } - - private void addCategory(PluginCategoryController category) { - if (category.lblCategoryName.getText().equals(FAVORITE_CATEGORY_NAME)) { - this.pluginCategories.getChildren().add(0, category.root); - } else { - this.pluginCategories.getChildren().add(category.root); - } - } - - public TabPane getTabPane() { - return tabPane; - } - - public void openConfigDialog() { - SystemSettingService.openSystemSettings("设置"); - } - - public void openPluginManager() { - new FxDialog() - .setBodyFxml(PluginManageController.FXML) - .setOwner(FxApp.primaryStage) - .setResizable(true) - .setTitle(Main.RESOURCE_BUNDLE.getString("plugin_manage")) - .setPrefWidth(800) - .show(); - } - - public void openProjectUrl() { - try { - Desktop.getDesktop().browse(new URI("https://gitee.com/xwintop/xJavaFxTool")); - } catch (Exception e) { - log.error("打开项目地址失败", e); - } - } - - public void openPluginCreator() { - - FxDialog dialog = new FxDialog() - .setTitle("创建自己的插件") - .setBodyFxml("/com/xwintop/xJavaFxTool/fxmlView/newui/plugin-creator.fxml") - .setOwner(FxApp.primaryStage) - .setResizable(true) - .setButtonTypes(ButtonType.OK, ButtonType.CANCEL); - - PluginCreatorController controller = dialog.show(); - - dialog - .setButtonHandler(ButtonType.OK, (actionEvent, stage) -> { - if (controller.isStartCreation()) { - try { - PluginProjectInfo info = controller.getPluginProjectInfo(); - CreatePluginProjectService.getInstance().createProject(info); - FxAlerts.info("创建成功", "项目 '" + info.getArtifactId() + "' 已经创建完毕。"); - Desktop.getDesktop().open(new File(info.getLocation())); - } catch (IOException e) { - FxAlerts.error("打开目标文件夹失败", e); - } - } - stage.close(); - }) - .setButtonHandler(ButtonType.CANCEL, (actionEvent, stage) -> stage.close()); - } -} +//package com.xwintop.xJavaFxTool.newui; +// +//import com.xwintop.xJavaFxTool.XJavaFxToolApplication; +//import com.xwintop.xJavaFxTool.controller.IndexController; +//import com.xwintop.xJavaFxTool.controller.index.PluginManageController; +//import com.xwintop.xJavaFxTool.event.AppEvents; +//import com.xwintop.xJavaFxTool.event.PluginEvent; +//import com.xwintop.xJavaFxTool.model.PluginJarInfo; +//import com.xwintop.xJavaFxTool.plugin.PluginManager; +//import com.xwintop.xJavaFxTool.plugin.PluginParser; +//import com.xwintop.xJavaFxTool.services.index.SystemSettingService; +//import com.xwintop.xcore.javafx.FxApp; +//import com.xwintop.xcore.javafx.dialog.FxDialog; +//import javafx.beans.Observable; +//import javafx.scene.control.CheckMenuItem; +//import javafx.scene.control.ContextMenu; +//import javafx.scene.control.TabPane; +//import javafx.scene.control.TextField; +//import javafx.scene.layout.VBox; +//import javafx.scene.web.WebView; +//import lombok.extern.slf4j.Slf4j; +//import org.apache.commons.lang3.BooleanUtils; +//import org.apache.commons.lang3.StringUtils; +// +//import java.awt.*; +//import java.io.File; +//import java.net.URI; +//import java.util.ArrayList; +//import java.util.HashMap; +//import java.util.List; +//import java.util.Map; +// +//@Slf4j +//public class NewLauncherController { +// +// public static final String FAVORITE_CATEGORY_NAME = "置顶"; +// +// public VBox pluginCategories; +// +// public WebView startWebView; +// +// public TabPane tabPane; +// +// public TextField txtSearch; +// +// private ContextMenu itemContextMenu; +// +// // 实现搜索用 +// private final List pluginItemControllers = new ArrayList<>(); +// +// private final Map categoryControllers = new HashMap<>(); +// +// public void initialize() { +// NewLauncherService.getInstance().setTabPane(tabPane); +// txtSearch.textProperty().addListener(this::onSearchKeywordChanged); +// +// initContextMenu(); +// loadPlugins(); // 加载插件列表到界面上 +// +// startWebView.getEngine().load(IndexController.QQ_URL); // 额外再打开一个反馈页面,可关闭 +// +// AppEvents.addEventHandler(PluginEvent.PLUGIN_DOWNLOADED, pluginEvent -> { +// loadPlugins(); +// }); +// } +// +// private void initContextMenu() { +// CheckMenuItem chkFavorite = new CheckMenuItem("置顶"); +// chkFavorite.setStyle("-fx-padding: 0 35 0 0"); +// +// this.itemContextMenu = new ContextMenu(chkFavorite); +// +// chkFavorite.setOnAction(event -> { +// CheckMenuItem _this = (CheckMenuItem) event.getSource(); +// PluginItemController pluginItemController = NewLauncherService.getInstance().getCurrentPluginItem(); +// setFavorite(pluginItemController, _this.isSelected()); +// }); +// } +// +// public void onSearchKeywordChanged(Observable ob, String _old, String keyword) { +// boolean notSearching = StringUtils.isBlank(keyword); +// pluginItemControllers.forEach(itemController -> { +// itemController.setVisible(notSearching || itemController.matchKeyword(keyword)); +// }); +// } +// +// private void setFavorite(PluginItemController itemController, boolean isFavorite) { +// if (itemController == null) { +// return; +// } +// +// itemController.getPluginJarInfo().setIsFavorite(isFavorite); +// PluginManager.getInstance().saveToFileQuietly(); +// loadPlugins(); +// } +// +// /** +// * 加载/刷新插件列表 +// */ +// private void loadPlugins() { +// +// this.pluginCategories.getChildren().clear(); +// this.pluginItemControllers.clear(); +// this.categoryControllers.clear(); +// +// PluginManager pluginManager = PluginManager.getInstance(); +// pluginManager.loadLocalPlugins(); +// pluginManager.getEnabledPluginList().forEach(this::loadPlugin); +// } +// +// /** +// * 加载单个插件到界面,要求插件已经经过 {@link PluginParser#parse(File, PluginJarInfo)} 解析 +// * +// * @param jarInfo 插件信息 +// */ +// private void loadPlugin(PluginJarInfo jarInfo) { +// +// if (!jarInfo.getFile().exists()) { +// log.info("跳过插件 {}: 文件不存在", jarInfo.getName()); +// return; +// } +// +// if (BooleanUtils.isFalse(jarInfo.getIsEnable())) { +// log.info("跳过插件 {}: 插件未启用", jarInfo.getName()); +// return; +// } +// +// String menuParentTitle = jarInfo.getMenuParentTitle(); +// if (menuParentTitle == null) { +// log.info("跳过插件 {}: menuParentTitle 为空", jarInfo.getName()); +// return; +// } +// +// String categoryName = jarInfo.getIsFavorite() ? FAVORITE_CATEGORY_NAME : XJavaFxToolApplication.RESOURCE_BUNDLE.getString(menuParentTitle); +// +// PluginCategoryController category = categoryControllers.computeIfAbsent( +// categoryName, __ -> { +// PluginCategoryController _category = +// PluginCategoryController.newInstance(categoryName); +// addCategory(_category); +// return _category; +// } +// ); +// +// PluginItemController item = PluginItemController.newInstance(jarInfo); +// item.setContextMenu(itemContextMenu); +// category.addItem(item); +// +// if (!pluginItemControllers.contains(item)) { +// pluginItemControllers.add(item); +// } +// } +// +// private void addCategory(PluginCategoryController category) { +// if (category.lblCategoryName.getText().equals(FAVORITE_CATEGORY_NAME)) { +// this.pluginCategories.getChildren().add(0, category.root); +// } else { +// this.pluginCategories.getChildren().add(category.root); +// } +// } +// +// public TabPane getTabPane() { +// return tabPane; +// } +// +// public void openConfigDialog() { +// SystemSettingService.openSystemSettings("设置"); +// } +// +// public void openPluginManager() { +// new FxDialog() +// .setBodyFxml(PluginManageController.FXML) +// .setOwner(FxApp.primaryStage) +// .setResizable(true) +// .setTitle(XJavaFxToolApplication.RESOURCE_BUNDLE.getString("plugin_manage")) +// .setPrefWidth(800) +// .withStage(stage -> stage.setOnCloseRequest(event -> loadPlugins())) +// .show(); +// } +// +// public void openProjectUrl() { +// try { +// Desktop.getDesktop().browse(new URI("https://gitee.com/xwintop/xJavaFxTool")); +// } catch (Exception e) { +// log.error("打开项目地址失败", e); +// } +// } +//} diff --git a/src/main/java/com/xwintop/xJavaFxTool/newui/NewLauncherService.java b/src/main/java/com/xwintop/xJavaFxTool/newui/NewLauncherService.java deleted file mode 100644 index a507119eddd49cdec9e6c43cbaccb79eef688d3c..0000000000000000000000000000000000000000 --- a/src/main/java/com/xwintop/xJavaFxTool/newui/NewLauncherService.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.xwintop.xJavaFxTool.newui; - -import com.xwintop.xJavaFxTool.AppException; -import com.xwintop.xJavaFxTool.model.PluginJarInfo; -import com.xwintop.xJavaFxTool.plugin.PluginLoader; -import javafx.scene.control.Tab; -import javafx.scene.control.TabPane; -import lombok.extern.slf4j.Slf4j; - -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -/** - * 新界面中负责与插件操作相关的逻辑 - */ -@Slf4j -public class NewLauncherService { - - private static final NewLauncherService instance = new NewLauncherService(); - - private NewLauncherController newLauncherController; - - private Map jarInfoMap = new HashMap<>(); - - private PluginItemController currentPluginItem; - - public static NewLauncherService getInstance() { - return instance; - } - - private NewLauncherService() { - - } - - public void setController(NewLauncherController newLauncherController) { - this.newLauncherController = newLauncherController; - } - - public void setCurrentPluginItem(PluginItemController currentPluginItem) { - this.currentPluginItem = currentPluginItem; - } - - public PluginItemController getCurrentPluginItem() { - return currentPluginItem; - } - - public void loadPlugin(PluginJarInfo pluginJarInfo) { - log.info("加载插件 {}: {}", pluginJarInfo.getName(), pluginJarInfo.getFile().getAbsolutePath()); - - TabPane tabPane = this.newLauncherController.getTabPane(); - - for (Entry entry : jarInfoMap.entrySet()) { - if (entry.getValue() == pluginJarInfo) { - tabPane.getSelectionModel().select(entry.getKey()); - return; - } - } - - Tab tab; - String controllerType = pluginJarInfo.getControllerType(); - - if (controllerType.equals("Node")) { - tab = PluginLoader.loadIsolatedPluginAsTab(pluginJarInfo, tabPane); - } else if (controllerType.equals("WebView")) { - tab = PluginLoader.loadWebViewAsTab(pluginJarInfo, tabPane); - } else { - throw new AppException("找不到 controllerType=" + controllerType + " 的加载方式"); - } - - if (tab != null) { - tab.setOnClosed(event -> this.jarInfoMap.remove(tab)); - jarInfoMap.put(tab, pluginJarInfo); - } - } - - -} diff --git a/src/main/java/com/xwintop/xJavaFxTool/newui/PluginCreatorController.java b/src/main/java/com/xwintop/xJavaFxTool/newui/PluginCreatorController.java deleted file mode 100644 index 69430f3448ec2472e342da002a3154b8c6a1381f..0000000000000000000000000000000000000000 --- a/src/main/java/com/xwintop/xJavaFxTool/newui/PluginCreatorController.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.xwintop.xJavaFxTool.newui; - -import com.xwintop.xJavaFxTool.newui.creator.PluginProjectInfo; -import com.xwintop.xcore.util.javafx.FileChooserUtil; -import java.io.File; -import java.net.MalformedURLException; -import javafx.scene.Node; -import javafx.scene.control.Label; -import javafx.scene.control.TextField; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.layout.StackPane; -import javafx.stage.FileChooser; - -public class PluginCreatorController { - - public static final String WELCOME = "你想创建自己的插件项目吗?\n\n" - + "这个工具帮你搭建一个插件的脚手架项目,帮助你尽快开始功能开发。\n\n" - + "完成插件开发需要以下知识:" - + "\n1、会使用 Java 开发工具;" - + "\n2、会使用 Maven;" - + "\n3、熟悉 JavaFX 桌面框架。\n\n" - + "若想开始创建插件项目,请点击“下一步”。"; - - public TextField txtLocation; - - public StackPane stackPane; - - public Label txtWelcome; - - public ImageView imgPluginLogo; - - public TextField txtGroupId; - - public TextField txtArtifactId; - - public TextField txtVersion; - - public TextField txtPluginName; - - public TextField txtPluginTitle; - - private boolean startCreation; - - private void showStack(int index) { - for (int i = 0; i < stackPane.getChildren().size(); i++) { - Node node = stackPane.getChildren().get(i); - node.setVisible(i == index); - } - } - - public void initialize() { - this.txtWelcome.setText(WELCOME); - } - - public void showCreatorForm() { - showStack(1); - this.startCreation = true; - } - - public boolean isStartCreation() { - return startCreation; - } - - public void choosePluginLogo() { - File imgFile = FileChooserUtil.chooseFile( - new FileChooser.ExtensionFilter("图片文件", "*.png", "*.jpg") - ); - - if (imgFile != null) { - try { - this.imgPluginLogo.setImage(new Image(imgFile.toURI().toURL().toExternalForm())); - } catch (MalformedURLException e) { - e.printStackTrace(); - } - } - } - - public void choosePluginLocation() { - File pluginLocation = FileChooserUtil.chooseDirectory(); - if (pluginLocation != null) { - this.txtLocation.setText(pluginLocation.getAbsolutePath()); - } - } - - public PluginProjectInfo getPluginProjectInfo() { - PluginProjectInfo pluginProjectInfo = new PluginProjectInfo(); - pluginProjectInfo.setLocation(this.txtLocation.getText()); - pluginProjectInfo.setGroupId(this.txtGroupId.getText()); - pluginProjectInfo.setArtifactId(this.txtArtifactId.getText()); - pluginProjectInfo.setVersion(this.txtVersion.getText()); - pluginProjectInfo.setPluginName(this.txtPluginName.getText()); - pluginProjectInfo.setPluginTitle(this.txtPluginTitle.getText()); - pluginProjectInfo.setPluginLogo(this.imgPluginLogo.getImage()); - return pluginProjectInfo; - } -} diff --git a/src/main/java/com/xwintop/xJavaFxTool/newui/PluginItemController.java b/src/main/java/com/xwintop/xJavaFxTool/newui/PluginItemController.java index 17747ea7d5dbe1bc92af73d96faa074a222d765b..5542436020a61e8d3186aba95996df950d4c3500 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/newui/PluginItemController.java +++ b/src/main/java/com/xwintop/xJavaFxTool/newui/PluginItemController.java @@ -1,9 +1,10 @@ package com.xwintop.xJavaFxTool.newui; +import com.xwintop.xJavaFxTool.controller.IndexController; import com.xwintop.xJavaFxTool.model.PluginJarInfo; +import com.xwintop.xJavaFxTool.plugin.PluginManager; import com.xwintop.xJavaFxTool.utils.ResourceUtils; import com.xwintop.xcore.javafx.helper.FxmlHelper; -import java.net.URL; import javafx.fxml.FXMLLoader; import javafx.scene.control.CheckMenuItem; import javafx.scene.control.ContextMenu; @@ -13,13 +14,15 @@ import javafx.scene.image.ImageView; import javafx.scene.input.MouseButton; import javafx.scene.input.MouseEvent; import javafx.scene.layout.VBox; +import lombok.Data; import lombok.extern.slf4j.Slf4j; +import java.net.URL; + +@Data @Slf4j public class PluginItemController { - public static final String FXML_PATH = "/com/xwintop/xJavaFxTool/fxmlView/newui/plugin-item.fxml"; - public static PluginItemController newInstance(PluginJarInfo pluginJarInfo) { FXMLLoader fxmlLoader = FxmlHelper.loadFromResource(FXML_PATH); PluginItemController controller = fxmlLoader.getController(); @@ -27,8 +30,6 @@ public class PluginItemController { return controller; } - /////////////////////////////////////////////////////////////// - private PluginJarInfo pluginJarInfo; private ContextMenu contextMenu; @@ -39,10 +40,11 @@ public class PluginItemController { public ImageView imgLogo; + private IndexController indexController; + public void initialize() { // 当元素不可见时也从布局流中去掉 this.root.managedProperty().bind(this.root.visibleProperty()); - this.root.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> { if (event.getButton() == MouseButton.PRIMARY) { onMouseLeftClicked(event); @@ -50,26 +52,28 @@ public class PluginItemController { onMouseRightClicked(event); } }); + CheckMenuItem chkFavorite = new CheckMenuItem(IndexController.FAVORITE_CATEGORY_NAME); + chkFavorite.setStyle("-fx-padding: 0 35 0 0"); + this.contextMenu = new ContextMenu(chkFavorite); + chkFavorite.setOnAction(event2 -> { + this.pluginJarInfo.setIsFavorite(chkFavorite.isSelected()); + PluginManager.getInstance().saveToFileQuietly(); + indexController.loadPlugins(); + }); } private void onMouseRightClicked(MouseEvent event) { - NewLauncherService.getInstance().setCurrentPluginItem(this); CheckMenuItem chkFavorite = (CheckMenuItem) this.contextMenu.getItems().get(0); chkFavorite.setSelected(this.pluginJarInfo.getIsFavorite()); this.contextMenu.show(this.root, event.getScreenX(), event.getScreenY()); } private void onMouseLeftClicked(MouseEvent event) { - NewLauncherService.getInstance().loadPlugin(this.pluginJarInfo); + indexController.getIndexService().loadPlugin(pluginJarInfo); } private void updateIcon() { - URL iconUrl = ResourceUtils.getResource( - this.pluginJarInfo.getIconPath(), - this.pluginJarInfo.getDefaultIconPath(), - "/logo/plugin.png" - ); - + URL iconUrl = ResourceUtils.getResource(this.pluginJarInfo.getIconPath(), this.pluginJarInfo.getDefaultIconPath(), "/logo/plugin.png"); if (iconUrl != null) { String url = iconUrl.toExternalForm(); if (url.endsWith("plugin.png")) { @@ -79,20 +83,12 @@ public class PluginItemController { } } - public void setContextMenu(ContextMenu contextMenu) { - this.contextMenu = contextMenu; - } - private void setPluginInfo(PluginJarInfo pluginJarInfo) { this.pluginJarInfo = pluginJarInfo; this.pluginName.setText(pluginJarInfo.getName()); updateIcon(); } - public PluginJarInfo getPluginJarInfo() { - return pluginJarInfo; - } - public boolean matchKeyword(String keyword) { return this.pluginJarInfo.getName().toLowerCase().contains(keyword.toLowerCase()); } diff --git a/src/main/java/com/xwintop/xJavaFxTool/newui/creator/CreatePluginProjectService.java b/src/main/java/com/xwintop/xJavaFxTool/newui/creator/CreatePluginProjectService.java deleted file mode 100644 index 733eabb824b6153ca3e3ce50dbc3e6ef3627aeb4..0000000000000000000000000000000000000000 --- a/src/main/java/com/xwintop/xJavaFxTool/newui/creator/CreatePluginProjectService.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.xwintop.xJavaFxTool.newui.creator; - -import static com.xwintop.xJavaFxTool.utils.ResourceBundleUtils.toNativeAscii; - -import com.xwintop.xJavaFxTool.utils.ResourceUtils; -import com.xwintop.xcore.javafx.dialog.FxAlerts; -import java.io.File; -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import org.apache.commons.io.FileUtils; - -public class CreatePluginProjectService { - - private static final CreatePluginProjectService INSTANCE = new CreatePluginProjectService(); - - public static final Charset CHARSET = StandardCharsets.UTF_8; - - public static CreatePluginProjectService getInstance() { - return INSTANCE; - } - - public void createProject(PluginProjectInfo pluginProjectInfo) { - try { - FileUtils.forceMkdir(new File(pluginProjectInfo.getLocation())); - savePom(pluginProjectInfo); - saveConfiguration(pluginProjectInfo); - saveResourceBundle(pluginProjectInfo); - saveFxml(pluginProjectInfo); - saveControllerClass(pluginProjectInfo); - saveMainClass(pluginProjectInfo); - } catch (Exception e) { - FxAlerts.error("创建失败", e); - } - } - - private void saveMainClass(PluginProjectInfo info) throws Exception { - String java = ResourceUtils.readResource("/plugin-template/PLUGIN_NAMEMain.java", CHARSET); - java = java - .replace("[PACKAGE]", info.getPackageName()) - .replace("[PLUGIN_NAME]", info.getPluginName()) - .replace("[CLASS_NAME]", info.getMainClass()); - String javaPath = "src/main/java/" + info.getMainFullClass().replace(".", "/") + ".java"; - writeFile(Paths.get(info.getLocation(), javaPath), java); - } - - private void saveControllerClass(PluginProjectInfo info) throws Exception { - String java = ResourceUtils.readResource("/plugin-template/PLUGIN_NAMEController.java", CHARSET); - java = java - .replace("[PACKAGE]", info.getPackageName()) - .replace("[CLASS_NAME]", info.getControllerClass()); - String javaPath = "src/main/java/" + info.getControllerFullClass().replace(".", "/") + ".java"; - writeFile(Paths.get(info.getLocation(), javaPath), java); - } - - private void saveFxml(PluginProjectInfo info) throws Exception { - String fxml = ResourceUtils.readResource("/plugin-template/PLUGIN_NAME.fxml", CHARSET); - fxml = fxml - .replace("[CONTROLLER]", info.getControllerFullClass()) - .replace("[PLUGIN_NAME]", info.getPluginName()); - String resourceBundlePath = "src/main/resources/fxml/" + info.getPluginName() + ".fxml"; - writeFile(Paths.get(info.getLocation(), resourceBundlePath), fxml); - } - - private void saveResourceBundle(PluginProjectInfo info) throws Exception { - String resourceBundle = ResourceUtils.readResource("/plugin-template/PLUGIN_NAME.properties", CHARSET); - resourceBundle = resourceBundle.replace("[TITLE]", toNativeAscii(info.getPluginTitle(), false, true)); - String resourceBundlePath = "src/main/resources/locale/" + info.getPluginName() + ".properties"; - writeFile(Paths.get(info.getLocation(), resourceBundlePath), resourceBundle); - } - - private void saveConfiguration(PluginProjectInfo info) throws Exception { - String config = ResourceUtils.readResource("/plugin-template/toolFxmlLoaderConfiguration.xml", CHARSET); - config = config.replace("[PLUGIN_NAME]", info.getPluginName()); - writeFile(Paths.get(info.getLocation(), "src/main/resources/config/toolFxmlLoaderConfiguration.xml"), config); - } - - private void savePom(PluginProjectInfo info) throws Exception { - String pom = ResourceUtils.readResource("/plugin-template/pom.xml", CHARSET); - pom = pom - .replace("[GROUPID]", info.getGroupId()) - .replace("[ARTIFACTID]", info.getArtifactId()) - .replace("[VERSION]", info.getVersion()); - Files.write(Paths.get(info.getLocation(), "pom.xml"), pom.getBytes(CHARSET)); - } - - private void writeFile(Path path, String fileContent) throws IOException { - FileUtils.forceMkdirParent(path.toFile()); - Files.write(path, fileContent.getBytes(CHARSET)); - } -} diff --git a/src/main/java/com/xwintop/xJavaFxTool/newui/creator/PluginProjectInfo.java b/src/main/java/com/xwintop/xJavaFxTool/newui/creator/PluginProjectInfo.java deleted file mode 100644 index 8e799bd80e06bd2a519a60da30bee266bc77cd12..0000000000000000000000000000000000000000 --- a/src/main/java/com/xwintop/xJavaFxTool/newui/creator/PluginProjectInfo.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.xwintop.xJavaFxTool.newui.creator; - -import javafx.scene.image.Image; -import lombok.Data; - -@Data -public class PluginProjectInfo { - - private String location; - - private String groupId; - - private String artifactId; - - private String version; - - private String pluginName; - - private String pluginTitle; - - private Image pluginLogo; - - ////////////////////////////////////////////////////////////// - - public String getPackageName() { - return groupId + "." + toClassName(artifactId).toLowerCase(); - } - - public String getControllerClass() { - return toClassName(artifactId) + "Controller"; - } - - public String getControllerFullClass() { - return getPackageName() + "." + getControllerClass(); - } - - public String getMainClass() { - return toClassName(artifactId) + "Main"; - } - - public String getMainFullClass() { - return getPackageName() + "." + getMainClass(); - } - - private String toClassName(String hyphens) { - StringBuilder sb = new StringBuilder(); - for (String s : hyphens.split("-")) { - sb.append(Character.toUpperCase(s.charAt(0))); - if (s.length() > 1) { - sb.append(s.substring(1).toLowerCase()); - } - } - return sb.toString(); - } -} diff --git a/src/main/java/com/xwintop/xJavaFxTool/plugin/PluginClassLoader.java b/src/main/java/com/xwintop/xJavaFxTool/plugin/PluginClassLoader.java index dcd4a8ef3f73c299329b98295b97e3135bf1f390..808e934ad2de31ebc0679965b0904dc990a02b30 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/plugin/PluginClassLoader.java +++ b/src/main/java/com/xwintop/xJavaFxTool/plugin/PluginClassLoader.java @@ -1,28 +1,40 @@ package com.xwintop.xJavaFxTool.plugin; +import io.github.classgraph.ClassGraph; + import java.io.File; import java.net.MalformedURLException; +import java.net.URI; import java.net.URL; import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.List; /** * 用于加载插件的 ClassLoader */ public class PluginClassLoader extends URLClassLoader { - private static URL fromFile(File file) { - try { - return file.toURI().toURL(); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } + public static PluginClassLoader create(File jarFile) { + return create(getSystemClassLoader(), jarFile); } - public PluginClassLoader(ClassLoader parent, File appFile) { - super(new URL[]{fromFile(appFile)}, parent); + public static PluginClassLoader create(ClassLoader parent, File jarFile) { + List uris = new ArrayList<>(new ClassGraph().getClasspathURIs()); + uris.add(jarFile.toURI()); + + URL[] urls = uris.stream().map(uri -> { + try { + return uri.toURL(); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + }).toArray(URL[]::new); + + return new PluginClassLoader(urls, parent); } - public PluginClassLoader(File appFile) { - this(getSystemClassLoader(), appFile); + private PluginClassLoader(URL[] urls, ClassLoader parent) { + super(urls, parent); } } diff --git a/src/main/java/com/xwintop/xJavaFxTool/plugin/PluginContainer.java b/src/main/java/com/xwintop/xJavaFxTool/plugin/PluginContainer.java index 0ea56b944597d2f79b2dcc59f3cddf190b34c70f..1361937319c6f1c5e2cce43642b5c7704ab66a79 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/plugin/PluginContainer.java +++ b/src/main/java/com/xwintop/xJavaFxTool/plugin/PluginContainer.java @@ -4,10 +4,13 @@ import com.xwintop.xJavaFxTool.AppException; import com.xwintop.xJavaFxTool.model.PluginJarInfo; import com.xwintop.xJavaFxTool.utils.Config; import com.xwintop.xcore.javafx.dialog.FxAlerts; +import com.xwintop.xcore.plugin.PluginEvent; import javafx.fxml.FXMLLoader; +import javafx.scene.Node; import org.apache.commons.lang3.StringUtils; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.util.ResourceBundle; @@ -20,19 +23,25 @@ public class PluginContainer { private final PluginJarInfo pluginJarInfo; + private Node rootNode; + public PluginContainer(PluginJarInfo pluginJarInfo) { this(ClassLoader.getSystemClassLoader(), pluginJarInfo); } public PluginContainer(ClassLoader parentClassLoader, PluginJarInfo pluginJarInfo) { this.pluginJarInfo = pluginJarInfo; - this.pluginClassLoader = new PluginClassLoader(parentClassLoader, pluginJarInfo.getFile()); + this.pluginClassLoader = PluginClassLoader.create(parentClassLoader, pluginJarInfo.getFile()); + } + + public void setRootNode(Node rootNode) { + this.rootNode = rootNode; } public T createInstance(Class type) { try { - return type.newInstance(); - } catch (InstantiationException | IllegalAccessException e) { + return type.getDeclaredConstructor().newInstance(); + } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { throw new AppException(e); } } @@ -51,23 +60,20 @@ public class PluginContainer { */ public FXMLLoader createFXMLLoader() { try { - FXMLLoader pluginFxmlLoader = (FXMLLoader) - pluginClassLoader.loadClass("javafx.fxml.FXMLLoader").newInstance(); + FXMLLoader pluginFxmlLoader = (FXMLLoader) pluginClassLoader.loadClass("javafx.fxml.FXMLLoader").getDeclaredConstructor().newInstance(); pluginFxmlLoader.setClassLoader(pluginClassLoader); URL resource = getResource(pluginJarInfo.getFxmlPath()); if (resource == null) { - FxAlerts.error("加载失败", "无法在插件 " + pluginJarInfo.getFile().getName() + - " 内找到所需资源 " + pluginJarInfo.getFxmlPath()); + FxAlerts.error("加载失败", "无法在插件 " + pluginJarInfo.getFile().getName() + " 内找到所需资源 " + pluginJarInfo.getFxmlPath()); return null; } pluginFxmlLoader.setLocation(resource); if (StringUtils.isNotEmpty(pluginJarInfo.getBundleName())) { - ResourceBundle resourceBundle = ResourceBundle - .getBundle(pluginJarInfo.getBundleName(), Config.defaultLocale, pluginClassLoader); + ResourceBundle resourceBundle = ResourceBundle.getBundle(pluginJarInfo.getBundleName(), Config.defaultLocale, pluginClassLoader); pluginFxmlLoader.setResources(resourceBundle); } return pluginFxmlLoader; @@ -81,9 +87,18 @@ public class PluginContainer { */ public void unload() { try { + if (this.rootNode != null) { + this.rootNode.fireEvent(new PluginEvent(this.rootNode, PluginEvent.PLUGIN_UNLOADING)); + } this.pluginClassLoader.close(); } catch (IOException e) { throw new AppException(e); } } + + public void onPluginInitialized() { + if (this.rootNode != null) { + this.rootNode.fireEvent(new PluginEvent(this.rootNode, PluginEvent.PLUGIN_INITIALIZED)); + } + } } diff --git a/src/main/java/com/xwintop/xJavaFxTool/plugin/PluginLoader.java b/src/main/java/com/xwintop/xJavaFxTool/plugin/PluginLoader.java deleted file mode 100644 index eb385198bd46622d62db52660f422b2a6446f0fa..0000000000000000000000000000000000000000 --- a/src/main/java/com/xwintop/xJavaFxTool/plugin/PluginLoader.java +++ /dev/null @@ -1,158 +0,0 @@ -package com.xwintop.xJavaFxTool.plugin; - -import com.xwintop.xJavaFxTool.model.PluginJarInfo; -import com.xwintop.xJavaFxTool.utils.Config; -import com.xwintop.xcore.javafx.dialog.FxAlerts; -import com.xwintop.xcore.util.javafx.JavaFxViewUtil; -import javafx.fxml.FXMLLoader; -import javafx.scene.Node; -import javafx.scene.control.Tab; -import javafx.scene.control.TabPane; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.web.WebEngine; -import javafx.scene.web.WebView; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; - -import java.lang.ref.WeakReference; -import java.net.URL; -import java.util.ResourceBundle; - -@Slf4j -public class PluginLoader { - - /** - * 以新窗口方式打开插件 - */ - public static void loadPluginAsWindow(PluginJarInfo plugin) { - try { - FXMLLoader generatingCodeFXMLLoader = new FXMLLoader(PluginLoader.class.getResource(plugin.getFxmlPath())); - - if (StringUtils.isNotEmpty(plugin.getBundleName())) { - ResourceBundle resourceBundle = ResourceBundle.getBundle(plugin.getBundleName(), Config.defaultLocale); - generatingCodeFXMLLoader.setResources(resourceBundle); - } - - JavaFxViewUtil.getNewStage(plugin.getTitle(), plugin.getIconPath(), generatingCodeFXMLLoader); - } catch (Exception e) { - log.error("加载插件失败", e); - } - } - - /** - * 以新 Tab 方式打开插件 - */ - public static Tab loadPluginAsTab(PluginJarInfo plugin, TabPane tabPane) { - try { - URL resource = PluginLoader.class.getResource(plugin.getFxmlPath()); - if (resource == null) { - FxAlerts.error("加载插件失败", "无法读取资源文件 '" + plugin.getFxmlPath() + "'"); - return null; - } - - FXMLLoader generatingCodeFXMLLoader = new FXMLLoader(resource); - - if (StringUtils.isNotEmpty(plugin.getBundleName())) { - ResourceBundle resourceBundle = ResourceBundle.getBundle(plugin.getBundleName(), Config.defaultLocale); - generatingCodeFXMLLoader.setResources(resourceBundle); - } - - Tab tab = new Tab(plugin.getTitle()); - - if (StringUtils.isNotEmpty(plugin.getIconPath())) { - ImageView imageView = new ImageView(new Image(plugin.getIconPath())); - imageView.setFitHeight(18); - imageView.setFitWidth(18); - tab.setGraphic(imageView); - } - - tab.setContent(generatingCodeFXMLLoader.load()); - tabPane.getTabs().add(tab); - tabPane.getSelectionModel().select(tab); - - tab.setOnCloseRequest( - event -> JavaFxViewUtil.setControllerOnCloseRequest(generatingCodeFXMLLoader.getController(), event) - ); - - return tab; - } catch (Exception e) { - log.error("加载插件失败", e); - } - - return null; - } - - /** - * 以新 Tab 方式打开插件,但使用独立的 ClassLoader - */ - public static Tab loadIsolatedPluginAsTab(PluginJarInfo plugin, TabPane tabPane) { - try { - Tab tab = new Tab(plugin.getTitle()); - - if (StringUtils.isNotEmpty(plugin.getIconPath())) { - ImageView imageView = new ImageView(new Image(plugin.getIconPath())); - imageView.setFitHeight(18); - imageView.setFitWidth(18); - tab.setGraphic(imageView); - } - - PluginContainer pluginContainer = new PluginContainer(PluginLoader.class.getClassLoader(), plugin); - WeakReference containerRef = new WeakReference<>(pluginContainer); - FXMLLoader generatingCodeFXMLLoader = pluginContainer.createFXMLLoader(); - if (generatingCodeFXMLLoader == null) { - return null; - } - - Node root = generatingCodeFXMLLoader.load(); - Object controller = generatingCodeFXMLLoader.getController(); - WeakReference controllerRef = new WeakReference<>(controller); - - tab.setContent(root); - tabPane.getTabs().add(tab); - tabPane.getSelectionModel().select(tab); - - tab.setOnCloseRequest( - event -> { - Object ctrl = controllerRef.get(); - if (ctrl != null) { - JavaFxViewUtil.setControllerOnCloseRequest(ctrl, event); - } - - PluginContainer container = containerRef.get(); - if (container != null) { - log.info("插件关闭:" + container.getPluginJarInfo().getName()); - container.unload(); - } - } - ); - - return tab; - } catch (Exception e) { - log.error("加载插件失败", e); - FxAlerts.error("插件加载失败", e); - } - - return null; - } - - public static Tab loadWebViewAsTab(PluginJarInfo plugin, TabPane tabPane) { - PluginContainer pluginContainer = new PluginContainer(plugin); - WebView browser = pluginContainer.createInstance(WebView.class); - WebEngine webEngine = browser.getEngine(); - String url = plugin.getPagePath(); - String title = plugin.getTitle(); - - if (url.startsWith("http")) { - webEngine.load(url); - } else { - webEngine.load(pluginContainer.getResource(url).toExternalForm()); - } - - Tab tab = new Tab(title); - tab.setContent(browser); - tabPane.getTabs().add(tab); - tabPane.getSelectionModel().select(tab); - return tab; - } -} diff --git a/src/main/java/com/xwintop/xJavaFxTool/plugin/PluginManager.java b/src/main/java/com/xwintop/xJavaFxTool/plugin/PluginManager.java index e7cc86ab7fba7fe6eed540abf16e6f4bfa42f549..a63a3bd836ac1ad37a6dd666d88d56cc2042072d 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/plugin/PluginManager.java +++ b/src/main/java/com/xwintop/xJavaFxTool/plugin/PluginManager.java @@ -18,7 +18,6 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -30,6 +29,7 @@ import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.stream.Collectors; @Slf4j public class PluginManager { @@ -38,8 +38,6 @@ public class PluginManager { public static final String LOCAL_PLUGINS_PATH = "./system_plugin_list.json"; - public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; - /** * 当下载插件时,模拟数种 UA */ @@ -53,22 +51,17 @@ public class PluginManager { public static PluginManager getInstance() { if (instance == null) { - instance = new PluginManager(LOCAL_PLUGINS_PATH); + instance = new PluginManager(); } return instance; } ////////////////////////////////////////////////////////////// - - private final String localPluginsPath; - - private final OkHttpClient pluginDownloader = - new OkHttpClient.Builder().addInterceptor(new DownloadProgressInterceptor()).build(); + private final OkHttpClient pluginDownloader = new OkHttpClient.Builder().addInterceptor(new DownloadProgressInterceptor()).build(); private final List pluginList = new ArrayList<>(); // 插件列表 - public PluginManager(String localPluginsPath) { - this.localPluginsPath = localPluginsPath; + public PluginManager() { this.loadLocalPluginConfiguration(); } @@ -78,6 +71,9 @@ public class PluginManager { return Collections.unmodifiableList(this.pluginList); } + public List getEnabledPluginList() { + return getPluginList().stream().filter(PluginJarInfo::getIsEnable).collect(Collectors.toList()); + } public PluginJarInfo getPlugin(String jarName) { return this.pluginList.stream() @@ -98,12 +94,12 @@ public class PluginManager { */ private void loadLocalPluginConfiguration() { try { - Path path = Paths.get(this.localPluginsPath); + Path path = Paths.get(LOCAL_PLUGINS_PATH); if (!Files.exists(path)) { return; } - String json = new String(Files.readAllBytes(path), DEFAULT_CHARSET); + String json = Files.readString(path, StandardCharsets.UTF_8); JSON.parseArray(json, PluginJarInfo.class).forEach(plugin -> { this.addOrUpdatePlugin(plugin, exist -> { exist.setLocalVersionNumber(plugin.getLocalVersionNumber()); @@ -121,9 +117,10 @@ public class PluginManager { */ public void loadLocalPlugins() { this.pluginList.forEach(plugin -> { - if (plugin.getIsDownload() != null && plugin.getIsDownload()) { + File pluginFile = plugin.getFile(); + if (pluginFile.exists()) { try { - PluginParser.parse(plugin.getFile(), plugin); + PluginParser.parse(pluginFile, plugin); } catch (Exception e) { log.error("解析失败", e); } @@ -137,7 +134,7 @@ public class PluginManager { * @param jarFile 插件文件 */ public AddPluginResult addPluginJar(File jarFile) { - PluginClassLoader tmpClassLoader = new PluginClassLoader(jarFile); + PluginClassLoader tmpClassLoader = PluginClassLoader.create(jarFile); PluginJarInfo newJarInfo = new PluginJarInfo(); newJarInfo.setLocalPath(jarFile.getAbsolutePath()); newJarInfo.setIsEnable(true); @@ -172,6 +169,7 @@ public class PluginManager { exist.setDownloadUrl(plugin.getDownloadUrl()); }); }); + log.info("下载插件列表完成。"); } catch (Exception e) { log.error("下载插件列表失败", e); } @@ -200,9 +198,7 @@ public class PluginManager { ////////////////////////////////////////////////////////////// 下载插件 - public File downloadPlugin( - PluginJarInfo pluginJarInfo, BiConsumer onProgressUpdate - ) throws IOException { + public File downloadPlugin(PluginJarInfo pluginJarInfo, BiConsumer onProgressUpdate) throws IOException { PluginJarInfo plugin = getPlugin(pluginJarInfo.getJarName()); if (plugin == null) { @@ -212,14 +208,13 @@ public class PluginManager { File file = pluginJarInfo.getFile(); FileUtils.forceMkdirParent(file); - this.currentProgressListener = - (bytesRead, contentLength, done) -> onProgressUpdate.accept(contentLength, bytesRead); + this.currentProgressListener = (bytesRead, contentLength, done) -> onProgressUpdate.accept(contentLength, bytesRead); // 使用多个 UA 尝试下载 Throwable downloadFailure = null; for (String ua : OPTIONAL_UA_LIST) { try { - tryDownload(pluginJarInfo.getDownloadUrl(), ua, file); + tryDownload(plugin.getName(), pluginJarInfo.getDownloadUrl(), ua, file); downloadFailure = null; break; } catch (Exception e) { @@ -231,7 +226,7 @@ public class PluginManager { if (downloadFailure instanceof IOException) { throw (IOException) downloadFailure; } else { - throw new IOException("插件下载失败 " + pluginJarInfo.getJarName(), downloadFailure); + throw new IOException("插件 '" + plugin.getName() + "' 下载失败 " + pluginJarInfo.getJarName(), downloadFailure); } } @@ -250,18 +245,18 @@ public class PluginManager { /** * 尝试指定的 UA 进行下载,如果下载失败则抛出异常 * - * @param url 下载地址 - * @param ua UA 字符串 - * @param file 下载到的目标文件 - * + * @param pluginName 插件名称 + * @param url 下载地址 + * @param ua UA 字符串 + * @param file 下载到的目标文件 * @throws IOException 如果下载失败 */ - private void tryDownload(String url, String ua, File file) throws IOException { + private void tryDownload(String pluginName, String url, String ua, File file) throws IOException { Request request = new Builder().header("User-Agent", ua).url(url).build(); try (Response response = pluginDownloader.newCall(request).execute()) { if (response.code() != HttpStatus.HTTP_OK) { - throw new IOException("插件下载失败 : HTTP " + response.code()); + throw new IOException("插件 '" + pluginName + "' 下载失败 : HTTP " + response.code()); } InputStream inputStream = Objects.requireNonNull(response.body()).byteStream(); @@ -276,11 +271,11 @@ public class PluginManager { // 保存配置,如果失败则抛出异常 public void saveToFile() throws IOException { String json = JSON.toJSONString(this.pluginList, true); - Path path = Paths.get(this.localPluginsPath); + Path path = Paths.get(LOCAL_PLUGINS_PATH); if (!Files.exists(path)) { Files.createFile(path); } - Files.write(path, json.getBytes(DEFAULT_CHARSET)); + Files.writeString(path, json, StandardCharsets.UTF_8); } // 保存配置,如果失败不抛出异常 @@ -346,9 +341,7 @@ public class PluginManager { private Source source(Source source) { return new ForwardingSource(source) { - long totalBytesRead = 0L; - @Override public long read(Buffer sink, long byteCount) throws IOException { long bytesRead = super.read(sink, byteCount); @@ -362,7 +355,6 @@ public class PluginManager { } interface ProgressListener { - void update(long bytesRead, long contentLength, boolean done); } } diff --git a/src/main/java/com/xwintop/xJavaFxTool/plugin/PluginParser.java b/src/main/java/com/xwintop/xJavaFxTool/plugin/PluginParser.java index 6e51d340cfa28d8e7b5e911637ff3fe98642fc6b..da61bbd49ae0b2a5a11db99f9e130555a14b71d4 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/plugin/PluginParser.java +++ b/src/main/java/com/xwintop/xJavaFxTool/plugin/PluginParser.java @@ -21,8 +21,6 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.stream.Collectors; -import static org.apache.commons.lang.StringUtils.defaultString; - /** * 用来解析插件文件中的 toolFxmlLoaderConfiguration.xml */ @@ -42,19 +40,16 @@ public class PluginParser { * 解析插件文件,补完 pluginJarInfo 属性 */ public static void parse(File pluginFile, PluginJarInfo pluginJarInfo, ClassLoader classLoader) { - if (!pluginFile.exists()) { log.error("插件 {} 文件不存在: {}", pluginJarInfo.getName(), pluginFile.getAbsolutePath()); return; } try (JarFile jarFile = new JarFile(pluginFile)) { - JarEntry entry = jarFile.getJarEntry(ENTRY_NAME); if (entry == null) { return; } - Element root = createRootElement(jarFile, entry); List menuElements = selectElements(root, "/root/ToolFxmlLoaderConfiguration[@isMenu='true']"); Element pluginElement = selectSingleElement(root, "/root/ToolFxmlLoaderConfiguration[not(@isMenu)]"); @@ -71,6 +66,7 @@ public class PluginParser { String controllerType = getChildNodeText(pluginElement, "controllerType"); String menuTitle = menuTitles.get(menuId); + pluginJarInfo.setMenuParentId(menuId); pluginJarInfo.setMenuParentTitle(menuTitle); pluginJarInfo.setBundleName(resourceBundleName); pluginJarInfo.setControllerType(controllerType); @@ -83,19 +79,17 @@ public class PluginParser { } pluginJarInfo.setName(StringUtils.defaultString(pluginJarInfo.getName(), title)); - } catch (IOException | DocumentException e) { throw new AppException(e); } } - private static String getTitleFromResourceBundle( - File pluginFile, ClassLoader classLoader, Element pluginElement, String bundleName - ) { + private static String getTitleFromResourceBundle(File pluginFile, ClassLoader classLoader, Element pluginElement, String bundleName) { String titleResourceBundleKey = getChildNodeText(pluginElement, "title"); - ClassLoader tmpClassLoader = classLoader == null ? new PluginClassLoader(pluginFile) : classLoader; + ClassLoader tmpClassLoader = classLoader == null ? PluginClassLoader.create(pluginFile) : classLoader; ResourceBundle resourceBundle = ResourceBundle.getBundle(bundleName, Config.defaultLocale, tmpClassLoader); - return resourceBundle.getString(defaultString(titleResourceBundleKey, "Title")); } + return resourceBundle.getString(StringUtils.defaultString(titleResourceBundleKey, "Title")); + } private static String getChildNodeText(Element element, String childNode) { return element.selectSingleNode("child::" + childNode).getText(); diff --git a/src/main/java/com/xwintop/xJavaFxTool/services/IndexService.java b/src/main/java/com/xwintop/xJavaFxTool/services/IndexService.java index 2a502967fc80e88779974bbf5e09e2997cd8277c..4f32e7a211737822fffcae6945ea96169909a2d5 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/services/IndexService.java +++ b/src/main/java/com/xwintop/xJavaFxTool/services/IndexService.java @@ -1,21 +1,24 @@ package com.xwintop.xJavaFxTool.services; +import com.xwintop.xJavaFxTool.AppException; +import com.xwintop.xJavaFxTool.XJavaFxToolApplication; import com.xwintop.xJavaFxTool.common.logback.ConsoleLogAppender; import com.xwintop.xJavaFxTool.controller.IndexController; import com.xwintop.xJavaFxTool.model.PluginJarInfo; -import com.xwintop.xJavaFxTool.plugin.PluginLoader; -import com.xwintop.xJavaFxTool.plugin.PluginManager; +import com.xwintop.xJavaFxTool.plugin.PluginClassLoader; +import com.xwintop.xJavaFxTool.plugin.PluginContainer; import com.xwintop.xJavaFxTool.utils.Config; -import com.xwintop.xJavaFxTool.utils.FxmlUtils; +import com.xwintop.xJavaFxTool.utils.XJavaFxSystemUtil; import com.xwintop.xcore.javafx.dialog.FxAlerts; +import com.xwintop.xcore.util.javafx.AlertUtil; import com.xwintop.xcore.util.javafx.JavaFxViewUtil; -import java.util.Locale; +import javafx.application.Platform; import javafx.event.ActionEvent; import javafx.event.Event; -import javafx.scene.Parent; -import javafx.scene.control.ContextMenu; -import javafx.scene.control.MenuItem; +import javafx.fxml.FXMLLoader; +import javafx.scene.Node; import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; import javafx.scene.control.TextArea; import javafx.scene.image.Image; import javafx.scene.image.ImageView; @@ -23,14 +26,21 @@ import javafx.scene.layout.BorderPane; import javafx.scene.web.WebEngine; import javafx.scene.web.WebView; import javafx.stage.Stage; -import lombok.Setter; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -@Setter -public class IndexService { +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +@Data +@Slf4j +public class IndexService { private IndexController indexController; + private Map jarInfoMap = new HashMap<>(); + public IndexService(IndexController indexController) { this.indexController = indexController; } @@ -41,28 +51,21 @@ public class IndexService { } else if ("English".equals(languageType)) { Config.set(Config.Keys.Locale, Locale.US); } - - FxAlerts.info("", indexController.getBundle().getString("SetLanguageText")); - } - - public ContextMenu getSelectContextMenu(String selectText) { - selectText = selectText.toLowerCase(); - ContextMenu contextMenu = new ContextMenu(); - for (MenuItem menuItem : indexController.getMenuItemMap().values()) { - if (menuItem.getText().toLowerCase().contains(selectText)) { - MenuItem menu_tab = new MenuItem(menuItem.getText(), menuItem.getGraphic()); - menu_tab.setOnAction(event1 -> { - menuItem.fire(); - }); - contextMenu.getItems().add(menu_tab); + AlertUtil.showInfoAlert(indexController.getBundle().getString("SetLanguageText")); + XJavaFxToolApplication.getStage().close(); + Platform.runLater(() -> { + try { + XJavaFxSystemUtil.initSystemLocal(); // 初始化本地语言 + new XJavaFxToolApplication().start(new Stage()); + } catch (Exception e) { + e.printStackTrace(); } - } - return contextMenu; + }); } public void addNodepadAction(ActionEvent event) { - Parent notepad = FxmlUtils.load("/com/xwintop/xJavaFxTool/fxmlView/notepad.fxml"); - if (indexController.getSingleWindowBootCheckBox().isSelected()) { + TextArea notepad = new TextArea(); + if (indexController.getSingleWindowBootCheckMenuItem().isSelected()) { JavaFxViewUtil.getNewStage(indexController.getBundle().getString("addNodepad"), null, notepad); } else { Tab tab = new Tab(indexController.getBundle().getString("addNodepad")); @@ -78,9 +81,8 @@ public class IndexService { TextArea textArea = new TextArea(); textArea.setFocusTraversable(true); ConsoleLogAppender.textAreaList.add(textArea); - if (indexController.getSingleWindowBootCheckBox().isSelected()) { - Stage newStage = JavaFxViewUtil - .getNewStage(indexController.getBundle().getString("addLogConsole"), null, textArea); + if (indexController.getSingleWindowBootCheckMenuItem().isSelected()) { + Stage newStage = JavaFxViewUtil.getNewStage(indexController.getBundle().getString("addLogConsole"), null, textArea); newStage.setOnCloseRequest(event1 -> { ConsoleLogAppender.textAreaList.remove(textArea); }); @@ -98,48 +100,118 @@ public class IndexService { } /** - * 添加Content内容 + * @Title: addWebView + * @Description: 添加WebView视图 */ - public void addContent(String title, String fxmlPath, String resourceBundleName, String iconPath) { + public void addWebView(String title, String url, String iconPath) { + PluginJarInfo pluginJarInfo = new PluginJarInfo(); + pluginJarInfo.setTitle(title); + pluginJarInfo.setIconPath(iconPath); + pluginJarInfo.setPagePath(url); + pluginJarInfo.setControllerType("WebView"); + loadPlugin(pluginJarInfo); + } - PluginJarInfo pluginJarInfo = PluginManager.getInstance().getPluginByFxmlPath(fxmlPath); - if (pluginJarInfo == null) { - FxAlerts.error("打开失败", "没有找到指定的插件"); - return; + public void loadPlugin(PluginJarInfo pluginJarInfo) { + if (!indexController.getSingleInstanceBootCheckMenuItem().isSelected() && !indexController.getSingleWindowBootCheckMenuItem().isSelected()) { + if (jarInfoMap.containsKey(pluginJarInfo)) { + indexController.getTabPaneMain().getSelectionModel().select(jarInfoMap.get(pluginJarInfo)); + return; + } } + Tab tab = null; + String controllerType = pluginJarInfo.getControllerType(); - if (indexController.getSingleWindowBootCheckBox().isSelected()) { - PluginLoader.loadPluginAsWindow(pluginJarInfo); + if (controllerType.equals("Node")) { + tab = loadIsolatedPluginAsTab(pluginJarInfo, indexController.getTabPaneMain(), indexController.getSingleWindowBootCheckMenuItem().isSelected()); + } else if (controllerType.equals("WebView")) { + tab = loadWebViewAsTab(pluginJarInfo, indexController.getTabPaneMain(), indexController.getSingleWindowBootCheckMenuItem().isSelected()); } else { - PluginLoader.loadPluginAsTab(pluginJarInfo, indexController.getTabPaneMain()); + throw new AppException("找不到 controllerType=" + controllerType + " 的加载方式"); + } + + if (tab != null) { + tab.setOnClosed(event -> this.jarInfoMap.remove(pluginJarInfo)); + jarInfoMap.put(pluginJarInfo, tab); } } /** - * @Title: addWebView - * @Description: 添加WebView视图 + * 以新 Tab 方式打开插件,但使用独立的 ClassLoader */ - public void addWebView(String title, String url, String iconPath) { + public static Tab loadIsolatedPluginAsTab(PluginJarInfo plugin, TabPane tabPane, boolean singleWindowBoot) { + try { + PluginContainer pluginContainer = new PluginContainer(PluginClassLoader.class.getClassLoader(), plugin); + FXMLLoader generatingCodeFXMLLoader = pluginContainer.createFXMLLoader(); + if (generatingCodeFXMLLoader == null) { + return null; + } + + if (singleWindowBoot) { + JavaFxViewUtil.getNewStage(plugin.getTitle(), plugin.getIconPath(), generatingCodeFXMLLoader); + return null; + } + + Tab tab = new Tab(plugin.getTitle()); + if (StringUtils.isNotEmpty(plugin.getIconPath())) { + ImageView imageView = new ImageView(new Image(plugin.getIconPath())); + imageView.setFitHeight(18); + imageView.setFitWidth(18); + tab.setGraphic(imageView); + } + + Node root = generatingCodeFXMLLoader.load(); + + tab.setContent(root); + tabPane.getTabs().add(tab); + tabPane.getSelectionModel().select(tab); + + pluginContainer.setRootNode(root); + pluginContainer.onPluginInitialized(); + tab.setOnCloseRequest( + event -> { + JavaFxViewUtil.setControllerOnCloseRequest(generatingCodeFXMLLoader.getController(), event); + log.info("插件关闭:" + pluginContainer.getPluginJarInfo().getName()); + pluginContainer.unload(); + } + ); + + return tab; + } catch (Exception e) { + log.error("加载插件失败", e); + FxAlerts.error("插件加载失败", e); + } + + return null; + } + + public static Tab loadWebViewAsTab(PluginJarInfo plugin, TabPane tabPane, boolean singleWindowBoot) { WebView browser = new WebView(); WebEngine webEngine = browser.getEngine(); + String url = plugin.getPagePath(); + String title = plugin.getTitle(); + if (url.startsWith("http")) { webEngine.load(url); } else { - webEngine.load(IndexController.class.getResource(url).toExternalForm()); + PluginContainer pluginContainer = new PluginContainer(plugin); + webEngine.load(pluginContainer.getResource(url).toExternalForm()); } - if (indexController.getSingleWindowBootCheckBox().isSelected()) { - JavaFxViewUtil.getNewStage(title, iconPath, new BorderPane(browser)); - return; + + if (singleWindowBoot) { + JavaFxViewUtil.getNewStage(title, plugin.getIconPath(), new BorderPane(browser)); + return null; } Tab tab = new Tab(title); - if (StringUtils.isNotEmpty(iconPath)) { - ImageView imageView = new ImageView(new Image(iconPath)); + if (StringUtils.isNotEmpty(plugin.getIconPath())) { + ImageView imageView = new ImageView(new Image(plugin.getIconPath())); imageView.setFitHeight(18); imageView.setFitWidth(18); tab.setGraphic(imageView); } tab.setContent(browser); - indexController.getTabPaneMain().getTabs().add(tab); - indexController.getTabPaneMain().getSelectionModel().select(tab); + tabPane.getTabs().add(tab); + tabPane.getSelectionModel().select(tab); + return tab; } } diff --git a/src/main/java/com/xwintop/xJavaFxTool/services/index/PluginManageService.java b/src/main/java/com/xwintop/xJavaFxTool/services/index/PluginManageService.java index d7b7dc8cfbaa81188a5ecd5bd7e77b09551f5b0e..11e6250ebb95d34748ad3a848312be042fdaf813 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/services/index/PluginManageService.java +++ b/src/main/java/com/xwintop/xJavaFxTool/services/index/PluginManageService.java @@ -1,22 +1,27 @@ package com.xwintop.xJavaFxTool.services.index; -import static org.apache.commons.lang3.StringUtils.substringBeforeLast; - import com.xwintop.xJavaFxTool.AppException; import com.xwintop.xJavaFxTool.controller.index.PluginManageController; +import com.xwintop.xJavaFxTool.event.AppEvents; +import com.xwintop.xJavaFxTool.event.PluginEvent; import com.xwintop.xJavaFxTool.model.PluginJarInfo; import com.xwintop.xJavaFxTool.plugin.PluginManager; +import com.xwintop.xcore.javafx.dialog.FxAlerts; import com.xwintop.xcore.javafx.dialog.FxProgressDialog; import com.xwintop.xcore.javafx.dialog.ProgressTask; -import java.io.File; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Consumer; +import javafx.stage.Window; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; + /** * 插件管理 * @@ -26,17 +31,10 @@ import org.apache.commons.lang3.StringUtils; @Setter @Slf4j public class PluginManageService { - - public static final String PLUGIN_LIST_URL = "https://xwintop.gitee.io/maven/plugin-libs/plugin-list.json"; - - public static final String PLUGIN_LIST_PATH = "system_plugin_list.json"; - private PluginManageController pluginManageController; private PluginManager pluginManager = PluginManager.getInstance(); - private Consumer onPluginDownloaded; - public PluginManageService(PluginManageController pluginManageController) { this.pluginManageController = pluginManageController; } @@ -47,7 +45,6 @@ public class PluginManageService { } public void addDataRow(PluginJarInfo plugin) { - Map dataRow = new HashMap<>(); dataRow.put("nameTableColumn", plugin.getName()); dataRow.put("synopsisTableColumn", plugin.getSynopsis()); @@ -72,7 +69,7 @@ public class PluginManageService { pluginManageController.getOriginPluginData().add(dataRow); } - public PluginJarInfo downloadPluginJar(Map dataRow) throws Exception { + public void downloadPluginJar(Map dataRow, Consumer afterDownload) { String jarName = dataRow.get("jarName"); PluginJarInfo pluginJarInfo = pluginManager.getPlugin(jarName); @@ -80,25 +77,34 @@ public class PluginManageService { ProgressTask progressTask = new ProgressTask() { @Override protected void execute() throws Exception { - File file = pluginManager.downloadPlugin( + pluginManager.downloadPlugin( pluginJarInfo, (total, current) -> updateProgress(current, total) ); - if (onPluginDownloaded != null) { - onPluginDownloaded.accept(file); + if (afterDownload != null) { + afterDownload.accept(pluginJarInfo); } } }; + Window controllerWindow = pluginManageController.getWindow(); + FxProgressDialog dialog = FxProgressDialog.create(controllerWindow, progressTask, "正在下载插件 " + pluginJarInfo.getName() + "..."); + progressTask.setOnCancelled(event -> { throw new AppException("下载被取消。"); }); - FxProgressDialog - .create(pluginManageController.getWindow(), progressTask, "正在下载插件 " + pluginJarInfo.getName() + "...") - .showAndWait(); + progressTask.setOnFailed(event -> { + Throwable e = event.getSource().getException(); + if (e != null) { + log.error("", e); + FxAlerts.error(controllerWindow, "下载插件失败", e); + } else { + FxAlerts.error(controllerWindow, "下载失败", event.getSource().getMessage()); + } + }); - return pluginJarInfo; + dialog.show(); } public void setIsEnableTableColumn(Integer index) { @@ -122,18 +128,15 @@ public class PluginManageService { private boolean isPluginDataMatch(Map map, String keyword) { return map.entrySet().stream().anyMatch( - entry -> - !entry.getKey().equals("downloadUrl") && - entry.getValue().toLowerCase().contains(keyword.toLowerCase()) + entry -> !entry.getKey().equals("downloadUrl") && entry.getValue().toLowerCase().contains(keyword.toLowerCase()) ); } /** * 判断插件是否启用 */ - @SuppressWarnings("BooleanMethodIsAlwaysInverted") public static boolean isPluginEnabled(String fileName) { - String jarName = substringBeforeLast(fileName, "-"); + String jarName = StringUtils.substringBeforeLast(fileName, "-"); PluginJarInfo pluginJarInfo = PluginManager.getInstance().getPlugin(jarName); if (pluginJarInfo == null) { return false; @@ -141,4 +144,36 @@ public class PluginManageService { Boolean isEnable = pluginJarInfo.getIsEnable(); return isEnable != null && isEnable; } + + //删除插件 + public void deletePlugin() { + Integer index = pluginManageController.getPluginDataTableView().getSelectionModel().getSelectedIndex(); + if (index == null || index == -1) { + return; + } + Map dataRow = pluginManageController.getOriginPluginData().get(index); + String jarName = dataRow.get("jarName"); + PluginJarInfo pluginJarInfo = this.pluginManager.getPlugin(jarName); + if(BooleanUtils.isNotTrue(pluginJarInfo.getIsDownload())){ + FxAlerts.info("提示",pluginJarInfo.getName() + " 该插件未下载"); + return; + } + if (!FxAlerts.confirmYesNo("删除插件", String.format("确定要删除插件 %s 吗?", pluginJarInfo.getName()))) { + return; + } + if (pluginJarInfo != null) { + try { + FileUtils.delete(pluginJarInfo.getFile()); + dataRow.put("isEnableTableColumn", "false"); + dataRow.put("isDownloadTableColumn", "下载"); + pluginJarInfo.setIsEnable(false); + pluginJarInfo.setIsDownload(false); + PluginManager.getInstance().saveToFile(); + pluginManageController.getPluginDataTableView().refresh(); + AppEvents.fire(new PluginEvent(PluginEvent.PLUGIN_DOWNLOADED, pluginJarInfo)); + } catch (IOException e) { + log.error("删除插件失败", e); + } + } + } } diff --git a/src/main/java/com/xwintop/xJavaFxTool/services/index/SystemSettingService.java b/src/main/java/com/xwintop/xJavaFxTool/services/index/SystemSettingService.java index 5da7176abf4f0c1e73bc5c3ef421d78e6ae78344..bdc3772f0387258108c7244b64947c856eba4595 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/services/index/SystemSettingService.java +++ b/src/main/java/com/xwintop/xJavaFxTool/services/index/SystemSettingService.java @@ -1,6 +1,6 @@ package com.xwintop.xJavaFxTool.services.index; -import com.xwintop.xJavaFxTool.Main; +import com.xwintop.xJavaFxTool.XJavaFxToolApplication; import com.xwintop.xJavaFxTool.controller.index.SystemSettingController; import com.xwintop.xcore.javafx.FxApp; import com.xwintop.xcore.javafx.dialog.FxDialog; @@ -24,7 +24,7 @@ public class SystemSettingService { public static void openSystemSettings(String title) { FxDialog dialog = new FxDialog() - .setResourceBundle(Main.RESOURCE_BUNDLE) + .setResourceBundle(XJavaFxToolApplication.RESOURCE_BUNDLE) .setTitle(title) .setBodyFxml("/com/xwintop/xJavaFxTool/fxmlView/index/SystemSetting.fxml") .setOwner(FxApp.primaryStage) @@ -32,11 +32,9 @@ public class SystemSettingService { SystemSettingController controller = dialog.show(); - dialog - .setButtonHandler(ButtonType.OK, (actionEvent, stage) -> { + dialog.setButtonHandler(ButtonType.OK, (actionEvent, stage) -> { controller.applySettings(); stage.close(); - }) - .setButtonHandler(ButtonType.CANCEL, (actionEvent, stage) -> stage.close()); + }).setButtonHandler(ButtonType.CANCEL, (actionEvent, stage) -> stage.close()); } } diff --git a/src/main/java/com/xwintop/xJavaFxTool/utils/BoolUtils.java b/src/main/java/com/xwintop/xJavaFxTool/utils/BoolUtils.java deleted file mode 100644 index 9978111239c0c09ec830eb8dc5c16ecced081044..0000000000000000000000000000000000000000 --- a/src/main/java/com/xwintop/xJavaFxTool/utils/BoolUtils.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.xwintop.xJavaFxTool.utils; - -public class BoolUtils { - - public static boolean is(Boolean b) { - return b != null && b; - } - - public static boolean isNot(Boolean b) { - return !is(b); - } -} diff --git a/src/main/java/com/xwintop/xJavaFxTool/utils/Config.java b/src/main/java/com/xwintop/xJavaFxTool/utils/Config.java index c2a0684ef1af694cef0346c30f9e9c7eae0b1aa8..f409e2117092a186d5cf58dca85f85a524474f68 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/utils/Config.java +++ b/src/main/java/com/xwintop/xJavaFxTool/utils/Config.java @@ -1,9 +1,11 @@ package com.xwintop.xJavaFxTool.utils; import com.xwintop.xcore.util.ConfigureUtil; +import org.apache.commons.configuration.PropertiesConfiguration; +import org.apache.commons.lang3.math.NumberUtils; + import java.io.File; import java.util.Locale; -import org.apache.commons.configuration.PropertiesConfiguration; /* * 存取框架配置 @@ -14,7 +16,7 @@ public class Config { public static Locale defaultLocale = Locale.getDefault();// 设置系统语言 - public static final String xJavaFxToolVersions = "V0.2.3";// xJavaFxTool版本信息 + public static final String xJavaFxToolVersions = "V0.3.1";// xJavaFxTool版本信息 /////////////////////////////////////////////////////////////// @@ -57,16 +59,8 @@ public class Config { return value == null ? def : value.toString(); } - public static int getInt(Keys key, int def) { - return Integer.parseInt(get(key, String.valueOf(def))); - } - public static double getDouble(Keys key, double def) { - return Double.parseDouble(get(key, String.valueOf(def))); - } - - public static long getLong(Keys key, long def) { - return Long.parseLong(get(key, String.valueOf(def))); + return NumberUtils.toDouble(get(key, null), def); } public static boolean getBoolean(Keys key, boolean def) { diff --git a/src/main/java/com/xwintop/xJavaFxTool/utils/FxmlUtils.java b/src/main/java/com/xwintop/xJavaFxTool/utils/FxmlUtils.java deleted file mode 100644 index 9c689a6d3e2552c63c775dc3969e6c0ee9bd415a..0000000000000000000000000000000000000000 --- a/src/main/java/com/xwintop/xJavaFxTool/utils/FxmlUtils.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.xwintop.xJavaFxTool.utils; - -import java.io.IOException; -import javafx.fxml.FXMLLoader; -import javafx.scene.Parent; -import javafx.scene.control.Alert; -import javafx.scene.control.Alert.AlertType; -import javafx.scene.control.ButtonType; -import javafx.scene.layout.Pane; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class FxmlUtils { - - /** - * Load fxml without throwing exceptions - */ - public static Parent load(String source) { - try { - return FXMLLoader.load(FxmlUtils.class.getResource(source)); - } catch (IOException e) { - log.error("", e); - new Alert(AlertType.ERROR, "Unable to load " + source + "\n" + e.toString(), ButtonType.OK).show(); - return new Pane(); - } - } -} diff --git a/src/main/java/com/xwintop/xJavaFxTool/utils/NodeUtils.java b/src/main/java/com/xwintop/xJavaFxTool/utils/NodeUtils.java deleted file mode 100644 index 3fec01b49c1602b1204862af2a9130dfc0b93c89..0000000000000000000000000000000000000000 --- a/src/main/java/com/xwintop/xJavaFxTool/utils/NodeUtils.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.xwintop.xJavaFxTool.utils; - -import java.util.HashMap; -import java.util.Map; -import javafx.scene.Node; -import javafx.stage.Window; - -@SuppressWarnings("unchecked") -public class NodeUtils { - - public static T getUserData(Node node, String key) { - return node.getUserData() == null ? null : - !(node.getUserData() instanceof Map) ? null : - (T) ((Map) node.getUserData()).get(key); - } - - public static void setUserData(Node node, String key, Object value) { - Map map = (Map) node.getUserData(); - if (map == null) { - map = new HashMap<>(); - node.setUserData(map); - } - map.put(key, value); - } - - public static T getUserData(Window window, String key) { - return window.getUserData() == null ? null : - !(window.getUserData() instanceof Map) ? null : - (T) ((Map) window.getUserData()).get(key); - } - - public static void setUserData(Window window, String key, Object value) { - Map map = (Map) window.getUserData(); - if (map == null) { - map = new HashMap<>(); - window.setUserData(map); - } - map.put(key, value); - } -} diff --git a/src/main/java/com/xwintop/xJavaFxTool/utils/ResourceBundleUtils.java b/src/main/java/com/xwintop/xJavaFxTool/utils/ResourceBundleUtils.java deleted file mode 100644 index 5db7cbf4d75dc5ece520cc090082b9305b76ff60..0000000000000000000000000000000000000000 --- a/src/main/java/com/xwintop/xJavaFxTool/utils/ResourceBundleUtils.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.xwintop.xJavaFxTool.utils; - -public class ResourceBundleUtils { - - /** - * 参考 {@link java.util.Properties} 的 saveConvert() 方法 - */ - public static String toNativeAscii(String theString, - boolean escapeSpace, - boolean escapeUnicode) { - int len = theString.length(); - int bufLen = len * 2; - if (bufLen < 0) { - bufLen = Integer.MAX_VALUE; - } - StringBuilder outBuffer = new StringBuilder(bufLen); - - for(int x=0; x 61) && (aChar < 127)) { - if (aChar == '\\') { - outBuffer.append('\\'); outBuffer.append('\\'); - continue; - } - outBuffer.append(aChar); - continue; - } - switch(aChar) { - case ' ': - if (x == 0 || escapeSpace) - outBuffer.append('\\'); - outBuffer.append(' '); - break; - case '\t':outBuffer.append('\\'); outBuffer.append('t'); - break; - case '\n':outBuffer.append('\\'); outBuffer.append('n'); - break; - case '\r':outBuffer.append('\\'); outBuffer.append('r'); - break; - case '\f':outBuffer.append('\\'); outBuffer.append('f'); - break; - case '=': // Fall through - case ':': // Fall through - case '#': // Fall through - case '!': - outBuffer.append('\\'); outBuffer.append(aChar); - break; - default: - if (((aChar < 0x0020) || (aChar > 0x007e)) & escapeUnicode ) { - outBuffer.append('\\'); - outBuffer.append('u'); - outBuffer.append(toHex((aChar >> 12) & 0xF)); - outBuffer.append(toHex((aChar >> 8) & 0xF)); - outBuffer.append(toHex((aChar >> 4) & 0xF)); - outBuffer.append(toHex( aChar & 0xF)); - } else { - outBuffer.append(aChar); - } - } - } - return outBuffer.toString(); - } - - /** - * Convert a nibble to a hex character - * @param nibble the nibble to convert. - */ - private static char toHex(int nibble) { - return hexDigit[(nibble & 0xF)]; - } - - /** A table of hex digits */ - private static final char[] hexDigit = { - '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' - }; - -} diff --git a/src/main/java/com/xwintop/xJavaFxTool/utils/ResourceUtils.java b/src/main/java/com/xwintop/xJavaFxTool/utils/ResourceUtils.java index 919bb128ad0cb268a47527d2ddd3b964ad93fe17..75dceb472733511645b187997c5a029391412c7e 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/utils/ResourceUtils.java +++ b/src/main/java/com/xwintop/xJavaFxTool/utils/ResourceUtils.java @@ -7,7 +7,7 @@ import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; public class ResourceUtils { diff --git a/src/main/java/com/xwintop/xJavaFxTool/utils/StageUtils.java b/src/main/java/com/xwintop/xJavaFxTool/utils/StageUtils.java index ad85ca462f1baa82f6d3e4626a0ee4e451a9c651..3005d213970eb8e0d6ebc7ecfc8efd98c7095cd1 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/utils/StageUtils.java +++ b/src/main/java/com/xwintop/xJavaFxTool/utils/StageUtils.java @@ -1,21 +1,9 @@ package com.xwintop.xJavaFxTool.utils; -import com.sun.javafx.tk.TKStage; -import com.sun.jna.LastErrorException; -import com.sun.jna.Native; -import com.sun.jna.Platform; -import com.sun.jna.Pointer; -import com.sun.jna.platform.win32.User32; -import com.sun.jna.platform.win32.WinDef; -import com.sun.jna.platform.win32.WinUser; -import com.sun.jna.win32.StdCallLibrary; -import com.sun.jna.win32.W32APIOptions; import com.xwintop.xJavaFxTool.utils.Config.Keys; import javafx.stage.Stage; import lombok.extern.slf4j.Slf4j; -import java.lang.reflect.Method; - /** * @ClassName: StageUtils * @Description: 更新场景工具类(解决点击任务栏图标无法最小化问题) @@ -25,45 +13,6 @@ import java.lang.reflect.Method; @Slf4j public class StageUtils { - - static interface ExtUser32 extends StdCallLibrary, User32 { - - ExtUser32 INSTANCE = (ExtUser32) Native.loadLibrary("user32", ExtUser32.class, W32APIOptions.DEFAULT_OPTIONS); - - WinDef.LRESULT CallWindowProcW(Pointer lpWndProc, Pointer hWnd, int msg, WinDef.WPARAM wParam, WinDef.LPARAM lParam); - - int SetWindowLong(HWND hWnd, int nIndex, com.sun.jna.Callback wndProc) throws LastErrorException; - } - - // update default javafx stage style - public static void updateStageStyle(Stage stage) { - if (Platform.isWindows()) { - Pointer pointer = getWindowPointer(stage); - WinDef.HWND hwnd = new WinDef.HWND(pointer); - - final User32 user32 = User32.INSTANCE; - int oldStyle = user32.GetWindowLong(hwnd, WinUser.GWL_STYLE); - int newStyle = oldStyle | 0x00020000; // WS_MINIMIZEBOX - user32.SetWindowLong(hwnd, WinUser.GWL_STYLE, newStyle); - } - } - - private static Pointer getWindowPointer(Stage stage) { - try { - TKStage tkStage = stage.impl_getPeer(); - Method getPlatformWindow = tkStage.getClass().getDeclaredMethod("getPlatformWindow"); - getPlatformWindow.setAccessible(true); - Object platformWindow = getPlatformWindow.invoke(tkStage); - Method getNativeHandle = platformWindow.getClass().getMethod("getNativeHandle"); - getNativeHandle.setAccessible(true); - Object nativeHandle = getNativeHandle.invoke(platformWindow); - return new Pointer((Long) nativeHandle); - } catch (Throwable e) { - e.printStackTrace(); - return null; - } - } - //加载Stage边框位置 public static void loadPrimaryStageBound(Stage stage) { try { diff --git a/src/main/java/com/xwintop/xJavaFxTool/utils/VersionChecker.java b/src/main/java/com/xwintop/xJavaFxTool/utils/VersionChecker.java new file mode 100644 index 0000000000000000000000000000000000000000..21c256062820b528bc880d0d31f159613648ca86 --- /dev/null +++ b/src/main/java/com/xwintop/xJavaFxTool/utils/VersionChecker.java @@ -0,0 +1,64 @@ +package com.xwintop.xJavaFxTool.utils; + +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.xwintop.xcore.javafx.dialog.FxAlerts; +import com.xwintop.xcore.util.HttpClientUtil; +import lombok.extern.slf4j.Slf4j; + +/** + * @ClassName: VersionChecker + * @Description: 新版本检查 + * @author: xufeng + * @date: 2022/3/28 14:59 + */ + +@Slf4j +public class VersionChecker { + public static void checkNewVersion() { + try { + String json = HttpUtil.get("https://gitee.com/api/v5/repos/xwintop/xJavaFxTool/releases/latest?access_token=d0486279db39a5996eca48c620abeee1"); + log.info("检查新版本:" + json); + JSONObject node = JSON.parseObject(json); + final String latestVersion = node.getString("tag_name"); + final String features = node.getString("body"); + if (isLargerThanCurrent(latestVersion)) { + final String content = new StringBuilder() + .append("版本名:").append(node.getString("name")).append("\r\n") + .append("更新内容: \r\n").append(features) + .toString(); + if (FxAlerts.confirmOkCancel("发现新版本 " + latestVersion, content)) { + HttpClientUtil.openBrowseURLThrowsException("https://gitee.com/xwintop/xJavaFxTool/releases"); + } + } + } catch (Exception e) { + log.error("检查新版本失败!", e); + } + } + + private static Boolean isLargerThanCurrent(String remoteVersion) { + final String[] arr = remoteVersion.split("v"); + String r = remoteVersion; + if (arr.length == 2) { + r = arr[1]; + } + + final String[] localVersionArr = Config.xJavaFxToolVersions.substring(1).split("\\."); + final String[] remoteVersionArr = r.split("\\."); + for (int i = 0; i < localVersionArr.length; i++) { + try { + final int localVersionSymbol = Integer.parseInt(localVersionArr[i]); + final int remoteVersionSymbol = Integer.parseInt(remoteVersionArr[i]); + if (localVersionSymbol < remoteVersionSymbol) { + return true; + } else if (localVersionSymbol > remoteVersionSymbol) { + return false; + } + } catch (Exception e) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/com/xwintop/xJavaFxTool/utils/XJavaFxSystemUtil.java b/src/main/java/com/xwintop/xJavaFxTool/utils/XJavaFxSystemUtil.java index 698b42e4a08ae812e6614143f117d8e52fa49bf9..e3e83bd14a5f020d44e5dbe821e210f2dac1bdfb 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/utils/XJavaFxSystemUtil.java +++ b/src/main/java/com/xwintop/xJavaFxTool/utils/XJavaFxSystemUtil.java @@ -1,16 +1,18 @@ package com.xwintop.xJavaFxTool.utils; -import com.xwintop.xJavaFxTool.Main; +import com.xwintop.xJavaFxTool.XJavaFxToolApplication; import com.xwintop.xJavaFxTool.plugin.PluginManager; import com.xwintop.xJavaFxTool.services.index.PluginManageService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + import java.io.File; +import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.Locale; import java.util.ResourceBundle; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; /** * @ClassName: XJavaFxSystemUtil @@ -34,7 +36,7 @@ public class XJavaFxSystemUtil { Config.defaultLocale = new Locale(locale1[0], locale1[1]); } - Main.RESOURCE_BUNDLE = ResourceBundle.getBundle("locale.Menu", Config.defaultLocale); + XJavaFxToolApplication.RESOURCE_BUNDLE = ResourceBundle.getBundle("locale.Menu", Config.defaultLocale); } catch (Exception e) { log.error("初始化本地语言失败", e); } @@ -51,7 +53,7 @@ public class XJavaFxSystemUtil { File libPath = new File("libs/"); // 获取所有的.jar和.zip文件 File[] jarFiles = libPath.listFiles( - (dir, name) -> name.endsWith(".jar") + (dir, name) -> name.endsWith(".jar") ); if (jarFiles != null) { for (File file : jarFiles) { @@ -73,13 +75,36 @@ public class XJavaFxSystemUtil { */ public static void addJarClass(File jarFile) { try { - log.info("Reading lib file: " + jarFile.getName()); - Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); - method.setAccessible(true); // 设置方法的访问权限 - // 获取系统类加载器 - URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); + ClassLoader classLoader = ClassLoader.getSystemClassLoader(); URL url = jarFile.toURI().toURL(); - method.invoke(classLoader, url); + if (classLoader instanceof URLClassLoader) { + System.out.println("DEB: classLoader instanceof URLClassLoader"); + URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader(); + Class sysclass = URLClassLoader.class; + try { + Method method = sysclass.getDeclaredMethod("addURL", URL.class); + method.setAccessible(true); + method.invoke(sysloader, url); + } catch (Exception var5) { + var5.printStackTrace(); + throw new IllegalStateException(var5.getMessage(), var5); + } + } else { + try { + Field field = classLoader.getClass().getDeclaredField("ucp"); + field.setAccessible(true); + Object ucp = field.get(classLoader); + + System.out.println("DEB: invoke method!"); + Method method = ucp.getClass().getDeclaredMethod("addURL", URL.class); + method.setAccessible(true); + + method.invoke(ucp, url); + } catch (Exception exception) { + exception.printStackTrace(); + throw new IllegalStateException(exception.getMessage(), exception); + } + } } catch (Exception e) { log.error("添加libs中jar包到系统中异常:", e); } diff --git a/src/main/java/com/xwintop/xJavaFxTool/view/IndexView.java b/src/main/java/com/xwintop/xJavaFxTool/view/IndexView.java index 378b7a7ba680de5b098879abb5b91163fd137a99..d99872e01fa1d7c7722a6600b51b9e035352d82d 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/view/IndexView.java +++ b/src/main/java/com/xwintop/xJavaFxTool/view/IndexView.java @@ -1,14 +1,11 @@ package com.xwintop.xJavaFxTool.view; import java.util.ResourceBundle; + import javafx.fxml.FXML; import javafx.fxml.Initializable; -import javafx.scene.control.Button; -import javafx.scene.control.CheckBox; -import javafx.scene.control.Menu; -import javafx.scene.control.MenuBar; -import javafx.scene.control.TabPane; -import javafx.scene.control.TextField; +import javafx.scene.control.*; +import javafx.scene.layout.VBox; import javafx.scene.web.WebView; import lombok.Getter; import lombok.Setter; @@ -19,12 +16,6 @@ public abstract class IndexView implements Initializable { protected ResourceBundle bundle; - @FXML - protected Button myButton; - - @FXML - protected CheckBox singleWindowBootCheckBox; - @FXML protected TextField myTextField; @@ -33,12 +24,13 @@ public abstract class IndexView implements Initializable { @FXML protected MenuBar mainMenuBar; - @FXML - protected Menu fileMenu; + protected CheckMenuItem singleWindowBootCheckMenuItem; + @FXML + protected CheckMenuItem singleInstanceBootCheckMenuItem; @FXML - protected Menu toolsMenu; + protected Menu fileMenu; @FXML protected Menu moreToolsMenu; @@ -48,4 +40,7 @@ public abstract class IndexView implements Initializable { @FXML protected WebView tongjiWebView; + + @FXML + protected VBox pluginCategories; } diff --git a/src/main/java/com/xwintop/xJavaFxTool/view/NotepadView.java b/src/main/java/com/xwintop/xJavaFxTool/view/NotepadView.java deleted file mode 100644 index 5352a472140123bee6bef3d823ccd7f0f0110064..0000000000000000000000000000000000000000 --- a/src/main/java/com/xwintop/xJavaFxTool/view/NotepadView.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.xwintop.xJavaFxTool.view; - -import javafx.fxml.FXML; -import javafx.scene.control.TabPane; - -public abstract class NotepadView { - - @FXML - protected TabPane tabPane; -} diff --git a/src/main/java/com/xwintop/xJavaFxTool/view/index/SystemSettingView.java b/src/main/java/com/xwintop/xJavaFxTool/view/index/SystemSettingView.java index 705402293caa5a10c065ab354411e862ad4d1811..8c85c848551c6f27e74ba62fbad6f2931c80ebf5 100644 --- a/src/main/java/com/xwintop/xJavaFxTool/view/index/SystemSettingView.java +++ b/src/main/java/com/xwintop/xJavaFxTool/view/index/SystemSettingView.java @@ -8,10 +8,9 @@ import lombok.Getter; import lombok.Setter; /** - * @ClassName: SystemSettingView - * @Description: 设置页面 - * @author: xufeng - * @date: 2020/2/25 0025 16:44 + * 设置页面 + * + * @author xufeng */ @Getter @@ -27,9 +26,6 @@ public abstract class SystemSettingView implements Initializable { @FXML protected CheckBox saveStageBoundCheckBox; - @FXML - protected CheckBox chkNewLauncher; - @FXML protected Button saveButton; diff --git a/src/main/java/module-info.java.bak b/src/main/java/module-info.java.bak new file mode 100644 index 0000000000000000000000000000000000000000..2f655fbb2b1594bdc23a7237c9655cd49bd03b7c --- /dev/null +++ b/src/main/java/module-info.java.bak @@ -0,0 +1,23 @@ +//module com.xwintop.xJavaFxTool { +// exports com.xwintop.xJavaFxTool; +// requires java.base; +// requires javafx.base; +// requires javafx.controls; +// requires javafx.fxml; +// requires javafx.graphics; +// requires xcore; +// requires lombok; +// requires org.slf4j; +// requires fastjson; +// requires org.apache.commons.lang3; +// requires javafx.web; +// requires io.github.classgraph; +// requires dom4j; +// requires hutool.all; +// requires okhttp3; +// requires org.apache.commons.io; +// requires okio; +// requires commons.configuration; +// requires logback.classic; +// requires logback.core; +//} \ No newline at end of file diff --git a/src/main/resources/com/xwintop/xJavaFxTool/fxmlView/Index.fxml b/src/main/resources/com/xwintop/xJavaFxTool/fxmlView/Index.fxml index 96536154118722f2e55a1279c33106a5ce4ed705..48c7d76c43c1463bae15173cd221547bcad50ea9 100644 --- a/src/main/resources/com/xwintop/xJavaFxTool/fxmlView/Index.fxml +++ b/src/main/resources/com/xwintop/xJavaFxTool/fxmlView/Index.fxml @@ -1,81 +1,80 @@ - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/com/xwintop/xJavaFxTool/fxmlView/index/SystemSetting.fxml b/src/main/resources/com/xwintop/xJavaFxTool/fxmlView/index/SystemSetting.fxml index 09d4fdb240a3e60d7d71a6a91941b570998aed88..90c0712fbeb6a96d25d33ce0bd4179d84b9f29b1 100644 --- a/src/main/resources/com/xwintop/xJavaFxTool/fxmlView/index/SystemSetting.fxml +++ b/src/main/resources/com/xwintop/xJavaFxTool/fxmlView/index/SystemSetting.fxml @@ -4,8 +4,8 @@ + xmlns:fx="http://javafx.com/fxml/1" spacing="15" + fx:controller="com.xwintop.xJavaFxTool.controller.index.SystemSettingController"> @@ -14,5 +14,4 @@ - diff --git a/src/main/resources/com/xwintop/xJavaFxTool/fxmlView/newui/main.css b/src/main/resources/com/xwintop/xJavaFxTool/fxmlView/newui/main.css index 07edf53fa473a9ad9f1c34a5f0323e3578ad7fe0..9dfe216481241a887fac7139cf5cdf2fd1e82396 100644 --- a/src/main/resources/com/xwintop/xJavaFxTool/fxmlView/newui/main.css +++ b/src/main/resources/com/xwintop/xJavaFxTool/fxmlView/newui/main.css @@ -52,3 +52,15 @@ -fx-focus-color: transparent; -fx-faint-focus-color: transparent; } + +.main-menu-bar { + -fx-background-color: transparent; +} + +.main-menu-bar .menu .label { + -fx-text-fill: white; +} + +.main-menu-bar .menu-item .label { + -fx-text-fill: inherit; +} diff --git a/src/main/resources/com/xwintop/xJavaFxTool/fxmlView/newui/main.fxml b/src/main/resources/com/xwintop/xJavaFxTool/fxmlView/newui/main.fxml index dff369f8dd86206df8c873f98ff9147665965a26..810ce198f00ecd47237249052627b06561c231ae 100644 --- a/src/main/resources/com/xwintop/xJavaFxTool/fxmlView/newui/main.fxml +++ b/src/main/resources/com/xwintop/xJavaFxTool/fxmlView/newui/main.fxml @@ -35,7 +35,6 @@ text="https://gitee.com/xwintop/xJavaFxTool"/> - diff --git a/src/main/resources/com/xwintop/xJavaFxTool/fxmlView/newui/plugin-creator.fxml b/src/main/resources/com/xwintop/xJavaFxTool/fxmlView/newui/plugin-creator.fxml deleted file mode 100644 index ee092d7e513235edaa63eb1d2e3ed07a56a5686b..0000000000000000000000000000000000000000 --- a/src/main/resources/com/xwintop/xJavaFxTool/fxmlView/newui/plugin-creator.fxml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - -