16 Commits

Author SHA1 Message Date
tzdwindows 7
52231ccb22 fix(StateManager): 修复配置值为空时的解析异常
- 在 getStateAsInt、getStateAsLong、getStateAsFloat、getStateAsBoolean、
  getStateAsDouble、getStateAsChar、getStateAsByte 和 getStateAsShort 方法中
  增加了对配置值为空的检查
- 避免了空指针异常和 NumberFormatException
- 提高了代码的健壮性和可靠性
2025-08-17 20:31:54 +08:00
tzdwindows 7
20567a6211 feat(browser): 添加自定义浏览器创建回调和链接打开方式设置
- 新增 BrowserCreationCallback 接口,用于自定义浏览器布局
- 在 Builder 中添加 setBrowserCreationCallback 方法设置回调
- 增加 openLinksInBrowser 方法设置链接打开方式
- 修改 onBeforePopup 和 onBeforeBrowse 方法以支持新设置
- 优化 CefAppManager 中的语言设置和暗黑模式配置
- 更新 MainApplication 中的浏览器窗口创建方式
2025-08-17 15:57:46 +08:00
tzdwindows 7
be88f3829a refactor(browser): 更新浏览器窗口 HTML 加载方式
- 修复空指针bug:在 BrowserWindow 和 BrowserWindowJDialog 类中初始化 htmlUrl 变量为空字符串
2025-08-17 14:14:11 +08:00
tzdwindows 7
2598e25168 feat(browser): 支持 URL 加载并添加黑暗模式支持
- 在 BrowserWindow 和 BrowserWindowJDialog 中添加 htmlUrl 属性,用于支持 URL 加载
- 在 CefAppManager 中添加黑暗模式支持,根据系统主题动态调整浏览器设置
- 在 MainApplication 中使用 htmlUrl 属性创建主窗口
- 移除 ThemeColors 中的 isDarkMode 方法,改用 AxisInnovatorsBox.getMain().getRegistrationTopic().isDarkMode() 判断黑暗模式
2025-08-17 14:00:43 +08:00
tzdwindows 7
c276e35204 refactor(logging): 修改控制台日志输出格式
- 在 PatternLayout 中增加了日志记录器名称和方法信息
- 调整了日志级别格式,去除了多余的空格
2025-08-16 11:38:20 +08:00
tzdwindows 7
7d07e6d0e1 feat(theme): 实现深色和浅色主题支持
- 在 MainWindow 中添加深色主题支持
- 修改 ModernJarViewer 以适配不同主题
- 在 build.gradle 中添加系统类加载器配置
2025-08-16 10:33:48 +08:00
tzdwindows 7
1a1750d5a6 feat(theme): 动态主题适配及 UI 组件样式优化- 新增 updateTheme 方法以支持动态主题更新
- 优化 MainWindow 中的组件样式,包括按钮、滚动条等
- 调整侧边栏样式,增加选中状态和悬停效果
- 优化卡片背景和边框颜色,适应不同主题
- 修复部分组件在深色主题下的显示问题
2025-08-15 18:59:39 +08:00
tzdwindows 7
78bae01544 fix: 让FridaWindow适配主题 2025-08-15 14:08:23 +08:00
tzdwindows 7
a41b894ee8 feat(gui): 添加 MaterialLookAndFeel 主题并优化搜索框样式
- 在系统主题中添加 MaterialLookAndFeel 的暗色、浅色和深色主题
- 实现自定义圆角搜索文本框,增加聚焦动画和发光效果
- 移除 FridaWindow 中的静态代码块- 更新 MainWindow 中的标题样式和搜索框实现
- 在语言文件中添加新主题的翻译
2025-08-14 21:50:40 +08:00
tzdwindows 7
62c521a5ea refactor(window): 重构窗口相关代码并优化主题设置
-将 gui 包名改为 window,统一窗口相关代码
- 在 RegistrationTopic 中添加 isDarkMode 方法判断主题是否为暗黑模式
- 在 WindowsJDialog 中添加 isTopicDarkMode 方法检测当前主题
- 优化 AxisInnovatorsBox 中的主题注册和设置逻辑
- 更新相关类和方法以适应新的包结构和主题设置逻辑
2025-08-14 15:50:17 +08:00
tzdwindows 7
5da71f05e7 feat(gui): 添加深色模式支持并优化主题
- 增加了对 macOS、Windows 和 Linux 深色模式的检测- 添加了多个 FlatLaf 主题支持
- 优化了窗口主题设置逻辑,根据系统模式自动选择深浅主题
-调整了侧边栏、卡片背景和文本颜色等样式,以适应不同主题
- 更新了语言文件,增加了新主题的翻译
2025-08-14 15:23:25 +08:00
tzdwindows 7
9136ad8827 build(gradle): 优化项目构建并添加 ProGuard 混淆
- 移除了不必要的依赖项和构建配置
- 添加了 ProGuard 混淆任务
- 优化了 CEF 设置,提高了性能和减少了日志输出
- 调整了项目结构,使构建过程更加清晰和高效
2025-08-14 14:32:46 +08:00
tzdwindows 7
a5b3b90249 fix: 修改文件名大小写
- 添加反编译工具新的功能:**本地注解** 修正混淆表加载逻辑让他能快速打开文件
- 重构**ProgressBarManager(启动窗口的任务系统)** 增强视觉效果
2025-08-14 11:13:33 +08:00
tzdwindows 7
692ec3dc8d chore(language): 更新加载语言的时间戳
- 将语言加载时间从 2025 年 7 月 2 日20:11:55 修改为 2025年 8 月 12 日 21:57:11
- 保持加载的语言为系统默认的简体中文(zh_CN)
- 重写主窗口界面
2025-08-12 22:10:55 +08:00
tzdwindows 7
e4761d34e0 feat(gui): 重构登录界面为现代单窗口布局
- 设计并实现单窗口多视图的登录/注册/找回密码界面- 添加平滑的视图切换动画效果
- 优化输入框和按钮的样式,提升用户体验- 重构部分验证逻辑,提高代码可读性
2025-08-12 21:22:24 +08:00
tzdwindows 7
9d684b310f feat(gui): 重构主界面并添加新功能
- 重新设计了主窗口布局,增加了侧边栏和内容面板
- 添加了分类按钮和设置按钮
- 实现了内存分析面板的自动补全功能
- 优化了日志文件生成和异常处理机制- 更新了依赖库版本
2025-08-12 20:30:41 +08:00
64 changed files with 7636 additions and 3323 deletions

2
.idea/encodings.xml generated
View File

@@ -4,7 +4,7 @@
<file url="file://$PROJECT_DIR$/language" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/plug-in/python/Testing/main.py" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/Cpp/LM/org_tzd_lm_LM.cpp" charset="GBK" />
<file url="file://$PROJECT_DIR$/src/main/java/com/axis/innovators/box/gui/FridaWindow.java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/java/com/axis/innovators/box/window/FridaWindow.java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/java/org/tzd/lm/LM.java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/java/org/tzd/lm/LMApi.java" charset="UTF-8" />
</component>

View File

@@ -5,10 +5,12 @@ plugins {
id 'org.openjfx.javafxplugin' version '0.1.0'
id 'org.springframework.boot' version '3.2.0'
id 'io.spring.dependency-management' version '1.1.4'
id 'com.github.johnrengelman.shadow' version '8.1.1' apply false // 关闭 shadow
}
configurations {
all*.exclude group: 'org.openjfx', module: 'javafx'
proguardLib
}
// JDK 版本检查
@@ -22,237 +24,156 @@ group = 'com.axis.innovators.box'
version = '0.0.1'
repositories {
maven {
url 'https://maven.aliyun.com/repository/public'
metadataSources {
mavenPom()
artifact()
ignoreGradleMetadataRedirection()
}
}
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
maven { url 'https://maven.aliyun.com/repository/public' }
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
maven { url 'https://jitpack.io' }
mavenCentral()
}
configurations.all {
resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
}
//tasks.named("bootJar") {
// enabled = false
//}
dependencies {
proguardLib files('libs/proguard.jar')
testImplementation platform('org.junit:junit-bom:5.10.0')
testImplementation 'org.junit.jupiter:junit-jupiter'
implementation 'org.commonmark:commonmark:0.24.0'
implementation 'org.commonjava.googlecode.markdown4j:markdown4j:2.2-cj-1.1'
implementation 'com.google.code.gson:gson:2.8.9'
implementation 'org.apache.logging.log4j:log4j-api:2.20.0'
implementation 'org.apache.logging.log4j:log4j-core:2.20.0'
implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.20.0'
implementation 'org.ow2.asm:asm:9.7.1'
implementation 'org.ow2.asm:asm-commons:9.7.1'
implementation 'org.ow2.asm:asm-analysis:9.7.1'
implementation 'org.ow2.asm:asm-util:9.7.1'
implementation 'org.ow2.asm:asm-tree:9.7.1'
implementation 'net.bytebuddy:byte-buddy:1.17.6'
implementation 'org.jsoup:jsoup:1.17.2'
implementation 'com.google.code.gson:gson:2.8.9'
//implementation 'com.formdev:flatlaf:0.26'
implementation 'commons-io:commons-io:2.14.0'
implementation 'com.formdev:flatlaf:3.2.1' // FlatLaf核心
implementation 'com.formdev:flatlaf-extras:3.2.1' // 扩展组件
implementation 'com.formdev:flatlaf-intellij-themes:3.2.1' // 官方主题包
implementation 'com.formdev:flatlaf:3.2.1'
implementation 'com.formdev:flatlaf-extras:3.2.1'
implementation 'com.formdev:flatlaf-intellij-themes:3.2.1'
implementation 'io.github.vincenzopalazzo:material-ui-swing:1.1.2'
implementation 'org.python:jython-standalone:2.7.3'
implementation 'org.graalvm.python:python-embedding:24.2.1'
implementation files('libs/JNC-1.0-jnc.jar')
implementation files('libs/dog api 1.3.jar')
implementation 'org.fxmisc.richtext:richtextfx:0.11.0' // 更新后的richtextfx
implementation 'org.bitbucket.mstrobel:procyon-core:0.5.36' // 使用JitPack版本
implementation files('libs/DesktopWallpaperSdk-1.0-SNAPSHOT.jar')
implementation 'org.fxmisc.richtext:richtextfx:0.11.0'
implementation 'org.bitbucket.mstrobel:procyon-core:0.5.36'
implementation 'org.bitbucket.mstrobel:procyon-compilertools:0.5.36'
// 必须的核心依赖
implementation 'com.fifesoft:rsyntaxtextarea:3.5.4'
// 可选UI增强
implementation 'com.fifesoft:rstaui:3.3.1'
implementation 'com.fifesoft:languagesupport:3.3.0'
implementation 'com.fifesoft:autocomplete:3.3.2'
implementation 'org.apache.commons:commons-compress:1.23.0'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'
implementation 'org.controlsfx:controlsfx:11.1.2' // 现代化UI组件
implementation 'com.dlsc.formsfx:formsfx-core:11.6.0' // 表单组件
implementation 'net.sourceforge.plantuml:plantuml:8059' // UML支持可选)
implementation 'org.controlsfx:controlsfx:11.1.2'
implementation 'com.dlsc.formsfx:formsfx-core:11.6.0'
implementation 'net.sourceforge.plantuml:plantuml:8059'
implementation 'com.google.code.gson:gson:2.10.1'
implementation 'org.openjfx:javafx-controls:21'
implementation 'org.benf:cfr:0.152'
implementation 'com.github.javaparser:javaparser-core:3.25.1'
implementation 'com.1stleg:jnativehook:2.1.0'
//implementation 'org.springframework.boot:spring-boot-starter-web' // Web支持
//implementation 'org.springframework.boot:spring-boot-starter-data-jpa' // JPA数据库支持
//implementation 'org.springframework.boot:spring-boot-starter-validation' // 参数校验
// 安全相关依赖
//implementation 'org.springframework.boot:spring-boot-starter-security' // Spring Security
//implementation 'io.jsonwebtoken:jjwt-api:0.12.3' // JWT API
//runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3', // JWT实现
// 'io.jsonwebtoken:jjwt-jackson:0.12.3' // JWT序列化
implementation 'org.json:json:20230618'
implementation 'org.lwjgl:lwjgl:3.3.1'
implementation 'org.lwjgl:lwjgl-glfw:3.3.1'
implementation 'org.lwjgl:lwjgl-opengl:3.3.1'
implementation 'org.lwjgl:lwjgl:3.3.1:natives-windows'
implementation 'org.lwjgl:lwjgl-glfw:3.3.1:natives-windows'
implementation 'org.lwjgl:lwjgl-opengl:3.3.1:natives-windows'
implementation 'org.bytedeco:javacv-platform:1.5.7'
implementation 'org.bytedeco:javacpp-platform:1.5.7'
implementation 'com.madgag:animated-gif-lib:1.4'
implementation 'org.openjfx:javafx-web:17'
runtimeOnly 'com.mysql:mysql-connector-j'
// 开发工具
developmentOnly 'org.springframework.boot:spring-boot-devtools'
// 测试依赖
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
implementation 'com.kitfox.svg:svg-salamander:1.0'
implementation 'com.vladsch.flexmark:flexmark:0.64.8'
// SystemTray4J 核心库
implementation 'com.github.kwhat:jnativehook:2.2.2'
implementation 'com.dustinredmond.fxtrayicon:FXTrayIcon:4.0.1' // 增强版
// JavaFX 模块
implementation 'com.dustinredmond.fxtrayicon:FXTrayIcon:4.0.1'
implementation 'org.openjfx:javafx-graphics:21'
implementation 'me.friwi:jcefmaven:122.1.10'
implementation 'com.alphacephei:vosk:0.3.45' // Java API
implementation 'net.java.dev.jna:jna:5.12.1' // 本地库加载
// 高性能音频处理
implementation 'com.alphacephei:vosk:0.3.45'
implementation 'net.java.dev.jna:jna:5.13.0'
implementation 'net.java.dev.jna:jna-platform:5.13.0'
implementation 'org.apache.commons:commons-math3:3.6.1'
implementation 'com.google.guava:guava:31.1-jre'
// 中文拼音处理
implementation 'com.github.javaparser:javaparser-symbol-solver-core:3.25.9'
implementation 'org.bitbucket.mstrobel:procyon-core:0.6.0'
implementation 'org.bitbucket.mstrobel:procyon-compilertools:0.6.0'
implementation 'com.belerweb:pinyin4j:2.5.1'
// 音频I/O
implementation 'commons-io:commons-io:2.18.0'
implementation 'jflac:jflac:1.3' // FLAC支持
implementation 'jflac:jflac:1.3'
implementation 'com.github.axet:TarsosDSP:2.4'
implementation 'org.json:json:20231013'
// Eclipse 组件
// https://mvnrepository.com/artifact/org.eclipse.swt/org.eclipse.swt.win32.win32.x86_64
//implementation 'org.eclipse.swt:org.eclipse.swt.win32.win32.x86_64:4.3'
//
//// 基础 Eclipse 组件
//implementation 'org.eclipse.platform:org.eclipse.jface:3.36.0'
//implementation 'org.eclipse.platform:org.eclipse.jface.text:3.27.0' // 使用兼容版本
//implementation 'org.eclipse.platform:org.eclipse.core.runtime:3.33.0'
//implementation 'org.eclipse.platform:org.eclipse.equinox.common:3.20.0'
}
// 分离依赖项到 libs 目录
configurations.all {
resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
}
// 复制依赖到 libs 目录
task copyDependencies(type: Copy) {
from configurations.runtimeClasspath
into "$buildDir/libs/libs"
}
// 执行我生成jar
jar {
manifest {
attributes 'Main-Class': 'com.axis.innovators.box.Main',
'Class-Path': configurations.runtimeClasspath.files.collect { "libs/$it.name" }.join(' ')
}
// 原始 jar 打包(不含依赖)
tasks.jar {
dependsOn copyDependencies
archiveBaseName.set("${rootProject.name}")
archiveVersion.set("${version}")
}
// 测试配置
test {
useJUnitPlatform()
systemProperty "java.system.class.loader", "com.axis.innovators.box.plugins.BoxClassLoader"
// ProGuard 混淆任务
task obfuscateJar(type: JavaExec) {
dependsOn jar
group = "build"
description = "使用 ProGuard 混淆并生成映射表"
// 确保测试能看到依赖
classpath = files(sourceSets.test.output) +
files("$buildDir/libs/libs") +
configurations.testRuntimeClasspath
}
mainClass = 'proguard.ProGuard'
classpath = configurations.proguardLib
// 处理开源文档文件
sourceSets {
main {
resources {
exclude '**/*.md'
}
}
openSourceDocs {
resources {
srcDir 'src/main/resources'
include '**/*.md'
}
}
}
tasks.withType(JavaExec).configureEach {
jvmArgs = [
'-Djava.system.class.loader=com.axis.innovators.box.plugins.BoxClassLoader'
args = [
'-injars', "$buildDir/libs/${rootProject.name}-${version}.jar",
'-outjars', "$buildDir/libs/${rootProject.name}-${version}-obf.jar",
'-libraryjars', "${System.getProperty('java.home')}/jmods/java.base.jmod",
'-printmapping', "$buildDir/libs/output.srg",
'-keep class com.axis.innovators.box.plugins.**',
'-keep class com.axis.innovators.box.plugins.BoxClassLoader{*;}',
'-keeppackagenames', 'com.axis.innovators.box',
'-keeppackagenames', 'com.axis.innovators.box.plugins',
'-keepnames', 'class com.axis.innovators.box.**',
'-keepnames', 'class com.axis.innovators.box.plugins.**',
'-dontwarn',
'-dontoptimize',
'-dontshrink',
'-keepattributes', 'Signature,InnerClasses,EnclosingMethod,RuntimeVisibleAnnotations,RuntimeInvisibleAnnotations,RuntimeVisibleParameterAnnotations,RuntimeInvisibleParameterAnnotations,Deprecated,SourceFile,LineNumberTable,LocalVariableTable,LocalVariableTypeTable'
]
}
javafx {
version = "21"
modules = [ 'javafx.controls', 'javafx.fxml' ]
build {
dependsOn obfuscateJar
}
// 单独打包文档
task packageOpenSourceDocs(type: Jar) {
archiveClassifier = 'docs'
from sourceSets.openSourceDocs.resources
destinationDirectory = file("$buildDir/libs/docs")
}
// 完整的 application 配置
application {
mainClass = 'com.axis.innovators.box.Main'
}
// 确保运行时参数生效
applicationDefaultJvmArgs = [
"-Djava.system.class.loader=com.axis.innovators.box.plugins.BoxClassLoader",
"-Dloader.library.path=$buildDir/libs/libs",
'-Dfile.encoding=UTF-8'
task runClient(type: JavaExec) {
group = "application"
description = "运行 com.axis.innovators.box.Main"
classpath = sourceSets.main.runtimeClasspath
mainClass = "com.axis.innovators.box.Main"
jvmArgs = [
"-Dfile.encoding=UTF-8",
"-Djava.system.class.loader=com.axis.innovators.box.plugins.BoxClassLoader"
]
}
// 创建可运行分发
tasks.register('release') {
dependsOn build, packageOpenSourceDocs
doLast {
copy {
from "$buildDir/libs"
into "$buildDir/dist"
include '*.jar'
include 'docs/**'
include 'libs/**'
}
println "Release package ready at: $buildDir/dist"
}
}
// 默认构建任务
build.dependsOn release

View File

@@ -1,3 +1,3 @@
#Current Loaded Language
#Sat May 31 10:30:35 CST 2025
#Sat Aug 16 18:11:03 CST 2025
loadedLanguage=system\:zh_CN

View File

@@ -1,9 +1,43 @@
default_theme.system.topicName=\u9ED8\u8BA4\u4E3B\u9898
default_theme.default.tip=\u9ED8\u8BA4\u7684\u4E3B\u9898
metal_theme.system.topicName=Metal\u98CE\u683C
metal_theme.default.tip=Metal\u98CE\u683C
motif_theme.system.topicName=Motif\u98CE\u683C
motif_theme.default.tip=Motif\u98CE\u683C
# \u9ED8\u8BA4\u4E3B\u9898
default_theme.system.topicName=\u7CFB\u7EDF\u9ED8\u8BA4\u4E3B\u9898
default_theme.default.tip=\u4F7F\u7528\u64CD\u4F5C\u7CFB\u7EDF\u9ED8\u8BA4\u5916\u89C2
# Metal \u4E3B\u9898
metal_theme.system.topicName=Metal \u4E3B\u9898 (Java \u7ECF\u5178)
metal_theme.default.tip=Java \u9ED8\u8BA4\u7684 Metal \u98CE\u683C\u754C\u9762
# Motif \u4E3B\u9898
motif_theme.system.topicName=Motif \u4E3B\u9898 (UNIX \u98CE\u683C)
motif_theme.default.tip=\u4F20\u7EDF\u7684 UNIX Motif \u5916\u89C2
# FlatLaf \u4E3B\u9898
flatLight_theme.system.topicName=Flat Light (\u6D45\u8272)
flatLight_theme.default.tip=\u73B0\u4EE3\u5316\u6D45\u8272\u4E3B\u9898\uFF0C\u7B80\u6D01\u660E\u4EAE
flatDark_theme.system.topicName=Flat Dark (\u6DF1\u8272)
flatDark_theme.default.tip=\u73B0\u4EE3\u5316\u6DF1\u8272\u4E3B\u9898\uFF0C\u62A4\u773C\u8212\u9002
flatIntelliJ_theme.system.topicName=IntelliJ \u6D45\u8272
flatIntelliJ_theme.default.tip=\u7C7B\u4F3C IntelliJ IDEA \u7684\u6D45\u8272\u4E3B\u9898
flatDarcula_theme.system.topicName=Darcula \u6DF1\u8272
flatDarcula_theme.default.tip=\u7C7B\u4F3C IntelliJ IDEA \u7684 Darcula \u6DF1\u8272\u4E3B\u9898
flatMacLight_theme.system.topicName=macOS \u6D45\u8272
flatMacLight_theme.default.tip=\u7C7B\u4F3C macOS \u7684\u6D45\u8272\u98CE\u683C
flatMacDark_theme.system.topicName=macOS \u6DF1\u8272
flatMacDark_theme.default.tip=\u7C7B\u4F3C macOS \u7684\u6DF1\u8272\u6A21\u5F0F\uFF0C\u4F18\u96C5\u73B0\u4EE3
mars_dark_theme.system.topicName=MaterialLookAndFeel\u7684\u6697\u8272
mars_dark_theme.default.tip=\u57FA\u4E8E MaterialLookAndFeel \u7684\u6697\u8272\u4E3B\u9898
material_lite_theme.system.topicName=MaterialLookAndFeel\u7684\u6D45\u8272
material_lite_theme.default.tip=\u57FA\u4E8E MaterialLookAndFeel \u7684\u6D45\u8272\u4E3B\u9898\uFF0CMaterial Design \u98CE\u683C
material_oceanic_theme.system.topicName=MaterialLookAndFeel\u7684\u6DF1\u8272
material_oceanic_theme.default.tip=\u57FA\u4E8E MaterialLookAndFeel \u7684\u6D45\u8272\u4E3B\u9898\uFF0CMaterial Design \u98CE\u683C
flatLightLaf_theme.system.topicName=flatLightLaf\u98CE\u683C
flatLightLaf_theme.default.tip=flatLightLaf\u98CE\u683C
@@ -71,6 +105,66 @@ localWindow.prompt.system=\u4F60\u662F\u4E00\u4E2A\u4E50\u4E8E\u52A9\u4EBA\u7684
localWindow.prompt.system.2=\u4F60\u662F\u4E00\u4E2A\u4E13\u6CE8\u68C0\u7D22\u641C\u7D22\u4FE1\u606F\u7684\u52A9\u624B\uFF0C\u7528\u6237\u5C06\u63D0\u4F9B\u4E00\u4E9B\u94FE\u63A5\u3001\u6458\u8981\u3001\u6807\u9898\u3001\u722C\u53D6\u5230\u7684\u5185\u5BB9\uFF0C\u4F60\u7684\u4F5C\u7528\u5C31\u662F\u8F93\u51FA\u4E3B\u8981\u5185\u5BB9\u4E0E\u7528\u6237\u95EE\u9898\u76F8\u5173\u7684\u5185\u5BB9\u3002
localWindow.prompt.name=\u3010\u7528\u6237\u3011
# \u8F93\u5165\u6846\u63D0\u793A
fridaWindow.pid.placeholder=\u8F93\u5165\u8FDB\u7A0BPID
fridaWindow.process.tooltip=\u9009\u62E9\u76EE\u6807\u8FDB\u7A0B
# \u9762\u677F\u6807\u9898
fridaWindow.script.title=\u811A\u672C\u7F16\u8F91\u5668
fridaWindow.log.title=\u8F93\u51FA\u65E5\u5FD7
# \u8FDB\u7A0B\u76F8\u5173
fridaWindow.process.name=\u8FDB\u7A0B\u540D\u79F0
fridaWindow.process.pid=\u8FDB\u7A0BID
fridaWindow.processContext.inject=\u6CE8\u5165\u6B64\u8FDB\u7A0B
fridaWindow.search.placeholder=\u641C\u7D22\u8FDB\u7A0B...
# \u9519\u8BEF\u63D0\u793A
fridaWindow.error.title=\u9519\u8BEF
fridaWindow.error.noPid=\u8BF7\u5148\u8F93\u5165\u8FDB\u7A0BPID
fridaWindow.error.invalidPid=\u65E0\u6548\u7684\u8FDB\u7A0BID
fridaWindow.error.injectFail=\u6CE8\u5165\u5931\u8D25
fridaWindow.error.open=\u6587\u4EF6\u6253\u5F00\u5931\u8D25
fridaWindow.error.save=\u6587\u4EF6\u4FDD\u5B58\u5931\u8D25
# \u6587\u4EF6\u8FC7\u6EE4
fridaWindow.fileFilter=Frida\u811A\u672C\u6587\u4EF6 (*.frida)
# \u8BBE\u7F6E\u7A97\u53E3
fridaWindow.settings.tab.color=\u8BED\u6CD5\u9AD8\u4EAE
fridaWindow.settings.tab.font=\u5B57\u4F53\u8BBE\u7F6E
fridaWindow.settings.save=\u4FDD\u5B58
fridaWindow.settings.default=\u6062\u590D\u9ED8\u8BA4
fridaWindow.settings.cancel=\u53D6\u6D88
fridaWindow.chooseColor=\u9009\u62E9\u989C\u8272
# \u8BED\u6CD5\u9AD8\u4EAE\u8BBE\u7F6E
fridaWindow.col.syntax=\u8BED\u6CD5\u5143\u7D20
fridaWindow.col.color=\u989C\u8272
fridaWindow.syntax.keyword=\u5173\u952E\u5B57
fridaWindow.syntax.stdlib=\u6807\u51C6\u5E93
fridaWindow.syntax.builtin=\u5185\u7F6E\u51FD\u6570
fridaWindow.syntax.string=\u5B57\u7B26\u4E32
fridaWindow.syntax.number=\u6570\u5B57
fridaWindow.syntax.comment=\u6CE8\u91CA
fridaWindow.syntax.operator=\u8FD0\u7B97\u7B26
fridaWindow.syntax.identifier=\u6807\u8BC6\u7B26
fridaWindow.syntax.separator=\u5206\u9694\u7B26
fridaWindow.syntax.regex=\u6B63\u5219\u8868\u8FBE\u5F0F
# \u5B57\u4F53\u8BBE\u7F6E
fridaWindow.font.name=\u5B57\u4F53\u540D\u79F0
fridaWindow.font.size=\u5B57\u4F53\u5927\u5C0F
fridaWindow.font.style=\u5B57\u4F53\u6837\u5F0F
fridaWindow.font.bold=\u7C97\u4F53
fridaWindow.font.italic=\u659C\u4F53
fridaWindow.font.previewLabel=\u9884\u89C8
fridaWindow.font.preview=\u793A\u4F8B\u6587\u672C\uFF1Aconsole.log("Hello Frida");
# \u5173\u4E8E\u7A97\u53E3
fridaWindow.about.title=\u5173\u4E8E
fridaWindow.about.content=\u57FA\u4E8EFrida\u7684\u73B0\u4EE3\u6CE8\u5165\u5DE5\u5177\n\n\u7248\u6743\u6240\u6709 \u00A9 {0}
settings.1.title=\u63D2\u4EF6
settings.2.title=\u57FA\u7840\u8BBE\u7F6E
settings.3.title=\u5173\u4E8E

Binary file not shown.

BIN
libs/proguard.jar Normal file

Binary file not shown.

BIN
logo.ico

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -3,7 +3,7 @@ package com.axis.innovators.box;
import com.axis.innovators.box.events.GlobalEventBus;
import com.axis.innovators.box.events.OpenFileEvents;
import com.axis.innovators.box.events.StartupEvent;
import com.axis.innovators.box.gui.*;
import com.axis.innovators.box.window.*;
import com.axis.innovators.box.plugins.PluginDescriptor;
import com.axis.innovators.box.plugins.PluginLoader;
import com.axis.innovators.box.plugins.PluginPyLoader;
@@ -16,7 +16,13 @@ import com.axis.innovators.box.util.PythonResult;
import com.axis.innovators.box.util.Tray;
import com.axis.innovators.box.util.UserLocalInformation;
import com.axis.innovators.box.verification.UserTags;
import com.formdev.flatlaf.FlatLightLaf;
import com.formdev.flatlaf.themes.FlatMacDarkLaf;
import com.formdev.flatlaf.themes.FlatMacLightLaf;
import com.sun.management.HotSpotDiagnosticMXBean;
import mdlaf.MaterialLookAndFeel;
import mdlaf.themes.JMarsDarkTheme;
import mdlaf.themes.MaterialLiteTheme;
import mdlaf.themes.MaterialOceanicTheme;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.Appender;
@@ -78,6 +84,10 @@ public class AxisInnovatorsBox {
public AxisInnovatorsBox(String[] args, boolean isDebug) {
this.args = args;
this.isDebug = isDebug;
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
organizingCrashReports(throwable instanceof Exception ?
(Exception) throwable : new Exception(throwable));
});
}
/**
@@ -358,7 +368,7 @@ public class AxisInnovatorsBox {
if (appender instanceof FileAppender fileAppender) {
String fileName = fileAppender.getFileName();
if (fileName != null && !addedFiles.contains(fileName)) {
addFileToZip(zos, new File(fileName), "logs/");
addFileToZip(zos, new File(fileName), "logs/" + new File(fileName).getName());
addedFiles.add(fileName);
}
}
@@ -387,7 +397,7 @@ public class AxisInnovatorsBox {
for (File file : logFiles) {
String absolutePath = file.getAbsolutePath();
if (!addedFiles.contains(absolutePath)) {
addFileToZip(zos, file, "logs/");
addFileToZip(zos, file, "logs/" + file.getName());
addedFiles.add(absolutePath);
}
}
@@ -436,6 +446,24 @@ public class AxisInnovatorsBox {
addFileToZip(zos, generateSystemProperties(), "debug_files/system_properties.txt");
// 7. 添加环境变量
addFileToZip(zos, generateEnvironmentVariables(), "debug_files/environment_variables.txt");
// 8.生成dump文件
addFileToZip(zos, generateFileDump(), "debug_files/dump.hprof");
}
private File generateFileDump() throws IOException {
final String javaLibraryPath = System.getProperty("java.library.path");
String jvmFolder = javaLibraryPath.contains(";")
? javaLibraryPath.substring(0, javaLibraryPath.indexOf(';'))
: javaLibraryPath;
logger.info("JVM folder: {}", jvmFolder);
File dumpFile = File.createTempFile("dump", ".hprof");
String dumpFilePath = dumpFile.getAbsolutePath();
if (!dumpFile.delete()) {
throw new IOException("Failed to delete temporary placeholder file");
}
HotSpotDiagnosticMXBean bean = ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class);
bean.dumpHeap(dumpFilePath, true);
return new File(dumpFilePath);
}
private File generateClassLoaderInfo() throws IOException {
@@ -606,8 +634,7 @@ public class AxisInnovatorsBox {
return;
}
String entryName = entryPath + file.getName();
ZipEntry zipEntry = new ZipEntry(entryName);
ZipEntry zipEntry = new ZipEntry(entryPath);
zos.putNextEntry(zipEntry);
try (FileInputStream fis = new FileInputStream(file)) {
@@ -692,38 +719,132 @@ public class AxisInnovatorsBox {
*/
private void setTopic() {
try {
main.registrationTopic.addTopic(new com.formdev.flatlaf.FlatDarculaLaf(),
"Darcula主题",
"Darcula主题",
LoadIcon.loadIcon(MainWindow.class, "logo.png", 64),
"system:darcula_theme");
main.registrationTopic.addTopic(UIManager.getSystemLookAndFeelClassName(),
boolean isDarkMode = SystemInfoUtil.isSystemDarkMode();
// 1. 默认系统主题
main.registrationTopic.addTopic(
UIManager.getSystemLookAndFeelClassName(),
LanguageManager.getLoadedLanguages().getText("default_theme.system.topicName"),
LanguageManager.getLoadedLanguages().getText("default_theme.default.tip"),
LoadIcon.loadIcon(MainWindow.class, "logo.png", 64),
"system:default_theme");
main.registrationTopic.setLoading("system:default_theme");
"system:default_theme",
isDarkMode
);
main.registrationTopic.addTopic("javax.swing.plaf.metal.MetalLookAndFeel",
// 2. Metal (Java默认主题) - 浅色主题
main.registrationTopic.addTopic(
"javax.swing.plaf.metal.MetalLookAndFeel",
LanguageManager.getLoadedLanguages().getText("metal_theme.system.topicName"),
LanguageManager.getLoadedLanguages().getText("metal_theme.default.tip"),
LoadIcon.loadIcon(MainWindow.class, "logo.png", 64),
"system:metal_theme");
"system:metal_theme",
false
);
main.registrationTopic.addTopic("com.sun.java.swing.plaf.motif.MotifLookAndFeel",
// 3. Motif (UNIX风格) - 通常为浅色主题
main.registrationTopic.addTopic(
"com.sun.java.swing.plaf.motif.MotifLookAndFeel",
LanguageManager.getLoadedLanguages().getText("motif_theme.system.topicName"),
LanguageManager.getLoadedLanguages().getText("motif_theme.default.tip"),
LoadIcon.loadIcon(MainWindow.class, "logo.png", 64),
"system:motif_theme");
"system:motif_theme",
false
);
main.registrationTopic.addTopic(new FlatLightLaf(),
LanguageManager.getLoadedLanguages().getText("flatLightLaf_theme.system.topicName"),
LanguageManager.getLoadedLanguages().getText("flatLightLaf_theme.default.tip"),
// 4. FlatLaf 主题注册
// 4.1 FlatLight (默认浅色)
main.registrationTopic.addTopic(
new com.formdev.flatlaf.FlatLightLaf(),
LanguageManager.getLoadedLanguages().getText("flatLight_theme.system.topicName"),
LanguageManager.getLoadedLanguages().getText("flatLight_theme.default.tip"),
LoadIcon.loadIcon(MainWindow.class, "logo.png", 64),
"system:flatLightLaf_theme");
"system:flatLight_theme",
false
);
UIManager.setLookAndFeel(new com.formdev.flatlaf.FlatDarculaLaf());
// 4.2 FlatDark (默认深色)
main.registrationTopic.addTopic(
new com.formdev.flatlaf.FlatDarkLaf(),
LanguageManager.getLoadedLanguages().getText("flatDark_theme.system.topicName"),
LanguageManager.getLoadedLanguages().getText("flatDark_theme.default.tip"),
LoadIcon.loadIcon(MainWindow.class, "logo.png", 64),
"system:flatDark_theme",
true
);
// 4.3 FlatIntelliJ (类似IDEA浅色)
main.registrationTopic.addTopic(
new com.formdev.flatlaf.FlatIntelliJLaf(),
LanguageManager.getLoadedLanguages().getText("flatIntelliJ_theme.system.topicName"),
LanguageManager.getLoadedLanguages().getText("flatIntelliJ_theme.default.tip"),
LoadIcon.loadIcon(MainWindow.class, "logo.png", 64),
"system:flatIntelliJ_theme",
false
);
// 4.4 FlatDarcula (类似IDEA深色)
main.registrationTopic.addTopic(
new com.formdev.flatlaf.FlatDarculaLaf(),
LanguageManager.getLoadedLanguages().getText("flatDarcula_theme.system.topicName"),
LanguageManager.getLoadedLanguages().getText("flatDarcula_theme.default.tip"),
LoadIcon.loadIcon(MainWindow.class, "logo.png", 64),
"system:flatDarcula_theme",
true
);
// 4.5 FlatMacLight (macOS风格浅色)
main.registrationTopic.addTopic(
new FlatMacLightLaf(),
LanguageManager.getLoadedLanguages().getText("flatMacLight_theme.system.topicName"),
LanguageManager.getLoadedLanguages().getText("flatMacLight_theme.default.tip"),
LoadIcon.loadIcon(MainWindow.class, "logo.png", 64),
"system:flatMacLight_theme",
false
);
// 4.6 FlatMacDark (macOS风格深色)
main.registrationTopic.addTopic(
new FlatMacDarkLaf(),
LanguageManager.getLoadedLanguages().getText("flatMacDark_theme.system.topicName"),
LanguageManager.getLoadedLanguages().getText("flatMacDark_theme.default.tip"),
LoadIcon.loadIcon(MainWindow.class, "logo.png", 64),
"system:flatMacDark_theme",
true
);
main.registrationTopic.addTopic(
new MaterialLookAndFeel(new JMarsDarkTheme()),
LanguageManager.getLoadedLanguages().getText("mars_dark_theme.system.topicName"),
LanguageManager.getLoadedLanguages().getText("mars_dark_theme.default.tip"),
LoadIcon.loadIcon(MainWindow.class, "logo.png", 64),
"system:mars_dark_theme",
true
);
main.registrationTopic.addTopic(
new MaterialLookAndFeel(new MaterialLiteTheme()),
LanguageManager.getLoadedLanguages().getText("material_lite_theme.system.topicName"),
LanguageManager.getLoadedLanguages().getText("material_lite_theme.default.tip"),
LoadIcon.loadIcon(MainWindow.class, "logo.png", 64),
"system:material_lite_theme",
false
);
main.registrationTopic.addTopic(
new MaterialLookAndFeel(new MaterialOceanicTheme()),
LanguageManager.getLoadedLanguages().getText("material_oceanic_theme.system.topicName"),
LanguageManager.getLoadedLanguages().getText("material_oceanic_theme.default.tip"),
LoadIcon.loadIcon(MainWindow.class, "logo.png", 64),
"system:material_oceanic_theme",
true
);
LookAndFeel defaultLaf = isDarkMode ? new FlatMacDarkLaf() : new FlatMacLightLaf();
UIManager.setLookAndFeel(defaultLaf);
main.registrationTopic.setLoading(
isDarkMode ? "system:flatMacDark_theme" : "system:flatMacLight_theme"
);
} catch (Exception e) {
logger.warn("Failed to load the system facade class", e);
}
@@ -756,7 +877,6 @@ public class AxisInnovatorsBox {
windowsJDialog.repaint();
}
/**
* 重新加载窗口
*/
@@ -769,10 +889,12 @@ public class AxisInnovatorsBox {
for (WindowsJDialog windowsJDialog : windowsJDialogList) {
windowsJDialog.getContentPane().removeAll();
windowsJDialog.initUI();
windowsJDialog.updateTheme();
windowsJDialog.revalidate();
windowsJDialog.repaint();
}
ex.initUI();
ex.updateTheme();
ex.revalidate();
RegistrationSettingsItem.overloading();
isWindow = true;
@@ -805,6 +927,20 @@ public class AxisInnovatorsBox {
}
public static void run(String[] args, boolean isDebug) {
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
if (main != null) {
main.organizingCrashReports(throwable instanceof Exception ?
(Exception) throwable : new Exception(throwable));
} else {
new AxisInnovatorsBox(args, isDebug)
.organizingCrashReports(throwable instanceof Exception ?
(Exception) throwable : new Exception(throwable));
}
});
// 设置EDT(事件调度线程)的异常处理器
System.setProperty("sun.awt.exception.handler", EDTCrashHandler.class.getName());
main = new AxisInnovatorsBox(args,isDebug);
try {
main.initLog4j2();
@@ -880,7 +1016,6 @@ public class AxisInnovatorsBox {
throw new RuntimeException(e);
}
}, "TrayThread").start();
} catch (Exception e) {
logger.error("Failed to load plugins", e);
if (main.ex != null) {
@@ -972,4 +1107,16 @@ public class AxisInnovatorsBox {
public StateManager getStateManager() {
return stateManager;
}
/**
* 专门处理EDT线程异常的处理器
*/
public static class EDTCrashHandler {
public void handle(Throwable throwable) {
if (main != null) {
main.organizingCrashReports(throwable instanceof Exception ?
(Exception) throwable : new Exception(throwable));
}
}
}
}

View File

@@ -26,7 +26,6 @@ public class Log4j2OutputStream extends OutputStream {
systemOutContent.write(b, off, len);
String message = new String(b, off, len).trim();
logger.info(message);
}
/**

View File

@@ -28,19 +28,12 @@ public class Main {
private static FileChannel lockChannel = null;
public static void main(String[] args) {
if (!acquireLock()) {
JOptionPane.showMessageDialog(
null,
"程序已在运行中,无法启动多个实例",
"错误",
JOptionPane.ERROR_MESSAGE
);
System.exit(1);
}
// 清理日志文件最大日志为10
FolderCleaner.cleanFolder(FolderCreator.getLogsFolder(), 10);
// 加载保存的语言
LanguageManager.loadSavedLanguage();
// 如果没有加载的语言,则加载默认的语言
if (LanguageManager.getLoadedLanguages() == null) {
LanguageManager.loadLanguage("system:zh_CN");
}
@@ -83,7 +76,9 @@ public class Main {
return;
}
}
if (!acquireLock()) {
return;
}
AxisInnovatorsBox.run(args, debugWindowEnabled);
}
@@ -126,10 +121,7 @@ public class Main {
}
}
// 添加JVM关闭钩子确保锁释放
static {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
releaseLock();
}));
Runtime.getRuntime().addShutdownHook(new Thread(Main::releaseLock));
}
}

View File

@@ -1,5 +1,6 @@
package com.axis.innovators.box.browser;
import com.axis.innovators.box.events.BrowserCreationCallback;
import org.cef.CefApp;
import org.cef.CefClient;
import org.cef.CefSettings;
@@ -31,6 +32,7 @@ import static org.cef.callback.CefMenuModel.MenuId.MENU_ID_USER_FIRST;
*/
public class BrowserWindow extends JFrame {
private final String windowId;
private final String htmlUrl;
private CefApp cefApp;
private CefClient client;
private CefBrowser browser;
@@ -42,6 +44,7 @@ public class BrowserWindow extends JFrame {
private CefMessageRouter msgRouter;
public static class Builder {
private BrowserCreationCallback browserCreationCallback;
private String windowId;
private String title = "JCEF Window";
private Dimension size = new Dimension(800, 600);
@@ -51,7 +54,8 @@ public class BrowserWindow extends JFrame {
private boolean resizable = true; // 默认允许调整大小
private boolean maximizable = true; // 默认允许最大化
private boolean minimizable = true; // 默认允许最小化
private String htmlUrl = "";
private boolean openLinksInExternalBrowser = true; // 默认使用外部浏览器
public Builder resizable(boolean resizable) {
this.resizable = resizable;
@@ -63,6 +67,44 @@ public class BrowserWindow extends JFrame {
return this;
}
/**
* 设置链接打开方式
*
* @param openInBrowser 是否在当前浏览器窗口中打开链接
* true - 在当前浏览器窗口中打开链接(本地跳转)
* false - 使用系统默认浏览器打开链接(外部跳转)
* @return Builder实例支持链式调用
*
* @apiNote 此方法控制两种不同的链接打开行为:
* 1. 当设置为true时
* - 所有链接将在当前CEF浏览器窗口内打开
*
* 2. 当设置为false时默认值
* - 所有链接将在系统默认浏览器中打开
* - 更安全,避免潜在的安全风险
* - 适用于简单的信息展示场景
*
* @implNote 内部实现说明:
* - 实际存储的是反向值(openLinksInExternalBrowser)
* - 这样设置是为了保持与历史版本的兼容性
* - 方法名使用"openInBrowser"更符合用户直觉
*
* @example 使用示例:
* // 在当前窗口打开链接
* new Builder().openLinksInBrowser(true).build();
*
* // 使用系统浏览器打开链接(默认)
* new Builder().openLinksInBrowser(false).build();
*
* @see #openLinksInExternalBrowser 内部存储字段
* @see CefLifeSpanHandler#onBeforePopup 弹窗处理实现
* @see CefRequestHandler#onBeforeBrowse 导航处理实现
*/
public Builder openLinksInBrowser(boolean openInBrowser) {
this.openLinksInExternalBrowser = !openInBrowser;
return this;
}
public Builder minimizable(boolean minimizable) {
this.minimizable = minimizable;
return this;
@@ -72,6 +114,15 @@ public class BrowserWindow extends JFrame {
this.windowId = windowId;
}
/**
* 设置浏览器创建回调
* @param callback 回调
*/
public Builder setBrowserCreationCallback(BrowserCreationCallback callback){
this.browserCreationCallback = callback;
return this;
}
/**
* 设置浏览器窗口标题
* @param title 标题
@@ -113,12 +164,14 @@ public class BrowserWindow extends JFrame {
* 设置HTML路径
*/
public BrowserWindow build() {
if (this.htmlPath == null || this.htmlPath.isEmpty()) {
throw new IllegalArgumentException("HTML paths cannot be empty");
}
File htmlFile = new File(this.htmlPath);
if (!htmlFile.exists()) {
throw new RuntimeException("The HTML file does not exist: " + htmlFile.getAbsolutePath());
if (htmlUrl.isEmpty()) {
if (this.htmlPath == null || this.htmlPath.isEmpty()) {
throw new IllegalArgumentException("HTML paths cannot be empty");
}
File htmlFile = new File(this.htmlPath);
if (!htmlFile.exists()) {
throw new RuntimeException("The HTML file does not exist: " + htmlFile.getAbsolutePath());
}
}
return new BrowserWindow(this);
}
@@ -131,12 +184,22 @@ public class BrowserWindow extends JFrame {
this.htmlPath = path;
return this;
}
/**
* 使用Url
* @param htmlUrl Url路径
*/
public Builder htmlUrl(String htmlUrl) {
this.htmlUrl = htmlUrl;
return this;
}
}
private BrowserWindow(Builder builder) {
this.windowId = builder.windowId;
this.htmlPath = builder.htmlPath;
this.operationHandler = builder.operationHandler;
this.htmlUrl = builder.htmlUrl;
// 设置图标(如果存在)
if (builder.icon != null) {
@@ -230,12 +293,20 @@ public class BrowserWindow extends JFrame {
@Override
public boolean onBeforePopup(CefBrowser browser, CefFrame frame,
String targetUrl, String targetFrameName) {
try {
Desktop.getDesktop().browse(new URI(targetUrl));
} catch (Exception e) {
System.out.println("Failed to open external browser: " + e.getMessage());
// 处理弹出窗口:根据配置决定打开方式
if (builder.openLinksInExternalBrowser) {
// 使用默认浏览器打开
try {
Desktop.getDesktop().browse(new URI(targetUrl));
} catch (Exception e) {
System.out.println("Failed to open external browser: " + e.getMessage());
}
return true; // 拦截弹窗
} else {
// 在当前浏览器中打开
browser.loadURL(targetUrl);
return true; // 拦截弹窗并在当前窗口打开
}
return true; // 拦截弹窗
}
});
@@ -243,12 +314,19 @@ public class BrowserWindow extends JFrame {
@Override
public boolean onBeforeBrowse(CefBrowser browser, CefFrame frame,
CefRequest request, boolean userGesture, boolean isRedirect) {
// 处理主窗口导航
if (userGesture) {
try {
Desktop.getDesktop().browse(new URI(request.getURL()));
return true; // 取消内置浏览器导航
} catch (Exception e) {
System.out.println("Failed to open external browser: " + e.getMessage());
if (builder.openLinksInExternalBrowser) {
// 使用默认浏览器打开
try {
Desktop.getDesktop().browse(new URI(request.getURL()));
return true; // 取消内置浏览器导航
} catch (Exception e) {
System.out.println("Failed to open external browser: " + e.getMessage());
}
} else {
// 允许在当前浏览器中打开
return false;
}
}
return false;
@@ -345,14 +423,46 @@ public class BrowserWindow extends JFrame {
Thread.currentThread().setName("BrowserRenderThread");
// 4. 加载HTML
String fileUrl = new File(htmlPath).toURI().toURL().toString();
System.out.println("Loading HTML from: " + fileUrl);
if (htmlUrl.isEmpty()){
String fileUrl = new File(htmlPath).toURI().toURL().toString();
System.out.println("Loading HTML from: " + fileUrl);
// 5. 创建浏览器组件(直接添加到内容面板)
browser = client.createBrowser(fileUrl, false, false);
// 5. 创建浏览器组件(直接添加到内容面板)
browser = client.createBrowser(fileUrl, false, false);
} else {
System.out.println("Loading Url from: " + htmlUrl);
browser = client.createBrowser(htmlUrl, false, false);
}
Component browserComponent = browser.getUIComponent();
browser.executeJavaScript("console.log('Java -> HTML 消息测试')",null,2);
if (builder.browserCreationCallback != null) {
boolean handled = builder.browserCreationCallback.onLayoutCustomization(
this, // 当前窗口
getContentPane(), // 内容面板
browserComponent, // 浏览器组件
builder // 构建器对象
);
// 如果回调返回true跳过默认布局
if (handled) {
// 设置窗口基本属性
setTitle(builder.title);
setSize(builder.size);
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
// 添加资源释放监听器
addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent e) {
browser.close(true);
client.dispose();
}
});
setVisible(true);
return browserComponent; // 直接返回,跳过默认布局
}
}
CefMessageRouter.CefMessageRouterConfig config = new CefMessageRouter.CefMessageRouterConfig();
config.jsQueryFunction = "javaQuery";// 定义方法

View File

@@ -1,5 +1,6 @@
package com.axis.innovators.box.browser;
import com.axis.innovators.box.events.BrowserCreationCallback;
import org.cef.CefApp;
import org.cef.CefClient;
import org.cef.CefSettings;
@@ -31,6 +32,7 @@ import static org.cef.callback.CefMenuModel.MenuId.MENU_ID_USER_FIRST;
*/
public class BrowserWindowJDialog extends JDialog {
private final String windowId;
private final String htmlUrl;
private CefApp cefApp;
private CefClient client;
private CefBrowser browser;
@@ -52,7 +54,9 @@ public class BrowserWindowJDialog extends JDialog {
private boolean resizable = true; // 默认允许调整大小
private boolean maximizable = true; // 默认允许最大化
private boolean minimizable = true; // 默认允许最小化
private String htmlUrl = "";
private BrowserCreationCallback browserCreationCallback;
private boolean openLinksInExternalBrowser = true; // 默认使用外部浏览器
public Builder resizable(boolean resizable) {
this.resizable = resizable;
@@ -81,6 +85,53 @@ public class BrowserWindowJDialog extends JDialog {
this.title = title;
return this;
}
/**
* 设置链接打开方式
*
* @param openInBrowser 是否在当前浏览器窗口中打开链接
* true - 在当前浏览器窗口中打开链接(本地跳转)
* false - 使用系统默认浏览器打开链接(外部跳转)
* @return Builder实例支持链式调用
*
* @apiNote 此方法控制两种不同的链接打开行为:
* 1. 当设置为true时
* - 所有链接将在当前CEF浏览器窗口内打开
*
* 2. 当设置为false时默认值
* - 所有链接将在系统默认浏览器中打开
* - 更安全,避免潜在的安全风险
* - 适用于简单的信息展示场景
*
* @implNote 内部实现说明:
* - 实际存储的是反向值(openLinksInExternalBrowser)
* - 这样设置是为了保持与历史版本的兼容性
* - 方法名使用"openInBrowser"更符合用户直觉
*
* @example 使用示例:
* // 在当前窗口打开链接
* new Builder().openLinksInBrowser(true).build();
*
* // 使用系统浏览器打开链接(默认)
* new Builder().openLinksInBrowser(false).build();
*
* @see #openLinksInExternalBrowser 内部存储字段
* @see CefLifeSpanHandler#onBeforePopup 弹窗处理实现
* @see CefRequestHandler#onBeforeBrowse 导航处理实现
*/
public Builder openLinksInBrowser(boolean openInBrowser) {
this.openLinksInExternalBrowser = !openInBrowser;
return this;
}
/**
* 设置浏览器创建回调
* @param callback 回调
*/
public Builder setBrowserCreationCallback(BrowserCreationCallback callback){
this.browserCreationCallback = callback;
return this;
}
/**
* 设置浏览器窗口大小
@@ -124,12 +175,14 @@ public class BrowserWindowJDialog extends JDialog {
* 设置HTML路径
*/
public BrowserWindowJDialog build() {
if (this.htmlPath == null || this.htmlPath.isEmpty()) {
throw new IllegalArgumentException("HTML paths cannot be empty");
}
File htmlFile = new File(this.htmlPath);
if (!htmlFile.exists()) {
throw new RuntimeException("The HTML file does not exist: " + htmlFile.getAbsolutePath());
if (htmlUrl.isEmpty()) {
if (this.htmlPath == null || this.htmlPath.isEmpty()) {
throw new IllegalArgumentException("HTML paths cannot be empty");
}
File htmlFile = new File(this.htmlPath);
if (!htmlFile.exists()) {
throw new RuntimeException("The HTML file does not exist: " + htmlFile.getAbsolutePath());
}
}
return new BrowserWindowJDialog(this);
}
@@ -142,13 +195,24 @@ public class BrowserWindowJDialog extends JDialog {
this.htmlPath = path;
return this;
}
/**
* 使用Url
* @param htmlUrl Url路径
*/
public Builder htmlUrl(String htmlUrl) {
this.htmlUrl = htmlUrl;
return this;
}
}
private BrowserWindowJDialog(Builder builder) {
// 根据父窗口是否存在,设置是否为模态对话框
super(builder.parentFrame, builder.title, builder.parentFrame != null);
this.windowId = builder.windowId;
this.htmlPath = builder.htmlPath;
this.htmlUrl = builder.htmlUrl;
this.operationHandler = builder.operationHandler;
// 设置图标(如果存在)
@@ -177,19 +241,13 @@ public class BrowserWindowJDialog extends JDialog {
client = cefApp.createClient();
client.addDisplayHandler(new CefDisplayHandler (){
@Override
public void onAddressChange(CefBrowser browser, CefFrame frame, String url) {
}
public void onAddressChange(CefBrowser browser, CefFrame frame, String url) {}
@Override
public void onTitleChange(CefBrowser browser, String title) {
}
public void onTitleChange(CefBrowser browser, String title) {}
@Override
public void OnFullscreenModeChange(CefBrowser browser, boolean fullscreen) {
}
public void OnFullscreenModeChange(CefBrowser browser, boolean fullscreen) {}
@Override
public boolean onTooltip(CefBrowser browser, String text) {
@@ -197,9 +255,7 @@ public class BrowserWindowJDialog extends JDialog {
}
@Override
public void onStatusMessage(CefBrowser browser, String value) {
}
public void onStatusMessage(CefBrowser browser, String value) {}
@Override
public boolean onConsoleMessage(
@@ -242,12 +298,20 @@ public class BrowserWindowJDialog extends JDialog {
@Override
public boolean onBeforePopup(CefBrowser browser, CefFrame frame,
String targetUrl, String targetFrameName) {
try {
Desktop.getDesktop().browse(new URI(targetUrl));
} catch (Exception e) {
System.out.println("Failed to open external browser: " + e.getMessage());
// 处理弹出窗口:根据配置决定打开方式
if (builder.openLinksInExternalBrowser) {
// 使用默认浏览器打开
try {
Desktop.getDesktop().browse(new URI(targetUrl));
} catch (Exception e) {
System.out.println("Failed to open external browser: " + e.getMessage());
}
return true; // 拦截弹窗
} else {
// 在当前浏览器中打开
browser.loadURL(targetUrl);
return true; // 拦截弹窗并在当前窗口打开
}
return true; // 拦截弹窗
}
});
@@ -255,12 +319,19 @@ public class BrowserWindowJDialog extends JDialog {
@Override
public boolean onBeforeBrowse(CefBrowser browser, CefFrame frame,
CefRequest request, boolean userGesture, boolean isRedirect) {
// 处理主窗口导航
if (userGesture) {
try {
Desktop.getDesktop().browse(new URI(request.getURL()));
return true; // 取消内置浏览器导航
} catch (Exception e) {
System.out.println("Failed to open external browser: " + e.getMessage());
if (builder.openLinksInExternalBrowser) {
// 使用默认浏览器打开
try {
Desktop.getDesktop().browse(new URI(request.getURL()));
return true; // 取消内置浏览器导航
} catch (Exception e) {
System.out.println("Failed to open external browser: " + e.getMessage());
}
} else {
// 允许在当前浏览器中打开
return false;
}
}
return false;
@@ -357,14 +428,48 @@ public class BrowserWindowJDialog extends JDialog {
Thread.currentThread().setName("BrowserRenderThread");
// 4. 加载HTML
String fileUrl = new File(htmlPath).toURI().toURL().toString();
System.out.println("Loading HTML from: " + fileUrl);
if (htmlUrl.isEmpty()) {
String fileUrl = new File(htmlPath).toURI().toURL().toString();
System.out.println("Loading HTML from: " + fileUrl);
// 5. 创建浏览器组件(直接添加到内容面板)
browser = client.createBrowser(fileUrl, false, false);
// 5. 创建浏览器组件(直接添加到内容面板)
browser = client.createBrowser(fileUrl, false, false);
} else {
System.out.println("Loading HTML from: " + htmlUrl);
browser = client.createBrowser(htmlUrl, false, false);
}
Component browserComponent = browser.getUIComponent();
browser.executeJavaScript("console.log('Java -> HTML 消息测试')",null,2);
if (builder.browserCreationCallback != null) {
boolean handled = builder.browserCreationCallback.onLayoutCustomization(
this, // 当前窗口
getContentPane(), // 内容面板
browserComponent, // 浏览器组件
builder // 构建器对象
);
// 如果回调返回true跳过默认布局
if (handled) {
// 设置窗口基本属性
setTitle(builder.title);
setSize(builder.size);
setLocationRelativeTo(builder.parentFrame);
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
// 添加资源释放监听器
addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent e) {
browser.close(true);
client.dispose();
}
});
setVisible(true);
return browserComponent; // 直接返回,跳过默认布局
}
}
CefMessageRouter.CefMessageRouterConfig config = new CefMessageRouter.CefMessageRouterConfig();
config.jsQueryFunction = "javaQuery";// 定义方法

View File

@@ -1,10 +1,14 @@
package com.axis.innovators.box.browser;
import com.axis.innovators.box.AxisInnovatorsBox;
import com.axis.innovators.box.register.LanguageManager;
import com.axis.innovators.box.tools.FolderCreator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.cef.CefApp;
import org.cef.CefSettings;
import org.cef.callback.CefCommandLine;
import org.cef.handler.CefAppHandlerAdapter;
import java.io.File;
import java.util.concurrent.TimeUnit;
@@ -56,22 +60,62 @@ public class CefAppManager {
initLock.lock();
try {
settings.windowless_rendering_enabled = false;
settings.javascript_flags = "--expose-gc";
settings.javascript_flags = "";
settings.cache_path = FolderCreator.getLibraryFolder() + "/jcef/cache";
settings.root_cache_path = FolderCreator.getLibraryFolder() + "/jcef/cache";
settings.persist_session_cookies = true;
settings.log_severity = CefSettings.LogSeverity.LOGSEVERITY_VERBOSE;
settings.persist_session_cookies = false;
settings.log_severity = CefSettings.LogSeverity.LOGSEVERITY_WARNING;
String subprocessPath = FolderCreator.getLibraryFolder() + "/jcef/lib/win64/jcef_helper.exe";
validateSubprocessPath(subprocessPath);
settings.browser_subprocess_path = subprocessPath;
logger.info("Default CEF settings initialized");
//settings.background_color = new Color(255, 255, 255, 0);
settings.command_line_args_disabled = false;
// 转换语言标识格式system:zh_CN -> zh-CN
CefApp.addAppHandler(new CefAppHandlerAdapter(null) {
@Override
public void onBeforeCommandLineProcessing(
String processType,
CefCommandLine commandLine
) {
LanguageManager.loadSavedLanguage();
LanguageManager.Language currentLang = LanguageManager.getLoadedLanguages();
if (currentLang != null){
String langCode = currentLang.getRegisteredName()
.replace("system:", "")
.replace("_", "-")
.toLowerCase();
settings.locale = langCode;
commandLine.appendSwitchWithValue("--lang", langCode);
commandLine.appendSwitchWithValue("--accept-language", langCode);
}
boolean isDarkTheme = isDarkTheme();
if (isDarkTheme) {
commandLine.appendSwitch("force-dark-mode");
commandLine.appendSwitchWithValue("enable-features", "WebContentsForceDark");
}
logger.info("CEF commandLine: {}", commandLine.getSwitches());
}
});
logger.info("Optimized CEF settings initialized");
} finally {
initLock.unlock();
}
}
private static boolean isDarkTheme() {
if (AxisInnovatorsBox.getMain() == null){
return false;
}
return AxisInnovatorsBox.getMain().getRegistrationTopic().isDarkMode();
}
public static CefApp getInstance() {
if (cefApp == null) {
if (initLock.tryLock()) {

View File

@@ -37,7 +37,15 @@ public class MainApplication {
private static long ctxHandle;
private static boolean isSystem = true;
public static void main(String[] args) {
AtomicReference<BrowserWindow> window = new AtomicReference<>();
WindowRegistry.getInstance().createNewWindow("main", builder ->
window.set(builder.title("Axis Innovators Box AI 工具箱")
.size(1280, 720)
.htmlUrl("https://chat.deepseek.com/")
.openLinksInBrowser(true)
.operationHandler(createOperationHandler())
.build())
);
}

View File

@@ -0,0 +1,21 @@
package com.axis.innovators.box.events;
import java.awt.*;
public interface BrowserCreationCallback {
/**
* 布局自定义回调方法
*
* @param window 当前浏览器窗口
* @param contentPane 窗口内容面板
* @param browserComponent 浏览器UI组件
* @param builder 构建器对象
* @return 返回true表示已处理布局将跳过默认布局返回false将继续执行默认布局
*/
boolean onLayoutCustomization(
Window window,
Container contentPane,
Component browserComponent,
Object builder
);
}

View File

@@ -1,138 +0,0 @@
package com.axis.innovators.box.events;
import com.axis.innovators.box.gui.MainWindow;
import java.awt.*;
/**
* 分类栏的渲染事件
* @author tzdwindows 7
*/
public class CategoryRenderingEvent {
private final MainWindow.CustomTabbedPaneUI ui;
private final Graphics graphics;
private final int tabPlacement;
private final int tabIndex;
private final int x;
private final int y;
private final int width;
private final int height;
private final boolean isSelected;
private boolean isEnd = false;
public CategoryRenderingEvent(MainWindow.CustomTabbedPaneUI ui, Graphics graphics, int tabPlacement, int tabIndex, int x, int y, int width, int height, boolean isSelected) {
this.ui = ui;
this.graphics = graphics;
this.tabPlacement = tabPlacement;
this.tabIndex = tabIndex;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.isSelected = isSelected;
}
public MainWindow.CustomTabbedPaneUI getUi() {
return ui;
}
public Graphics getGraphics() {
return graphics;
}
public int getTabPlacement() {
return tabPlacement;
}
public int getTabIndex() {
return tabIndex;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public boolean isSelected() {
return isSelected;
}
public boolean isEnd() {
return isEnd;
}
public void setEnd(boolean end) {
isEnd = end;
}
public static class paintTabBorder {
private final MainWindow.CustomTabbedPaneUI event;
private final Graphics graphics;
private final int tabPlacement;
private final int tabIndex;
private final int x;
private final int y;
private final int width;
private final int height;
private final boolean isSelected;
public paintTabBorder(MainWindow.CustomTabbedPaneUI event, Graphics graphics, int tabPlacement, int tabIndex, int x, int y, int width, int height, boolean isSelected) {
this.event = event;
this.graphics = graphics;
this.tabPlacement = tabPlacement;
this.tabIndex = tabIndex;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.isSelected = isSelected;
}
public MainWindow.CustomTabbedPaneUI getEvent() {
return event;
}
public Graphics getGraphics() {
return graphics;
}
public int getTabPlacement() {
return tabPlacement;
}
public int getTabIndex() {
return tabIndex;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public boolean isSelected() {
return isSelected;
}
}
}

View File

@@ -1,6 +1,6 @@
package com.axis.innovators.box.events;
import com.axis.innovators.box.gui.MainWindow;
import com.axis.innovators.box.window.MainWindow;
import javax.swing.*;
import java.awt.*;

View File

@@ -1,6 +1,6 @@
package com.axis.innovators.box.events;
import com.axis.innovators.box.gui.WindowsJDialog;
import com.axis.innovators.box.window.WindowsJDialog;
import javax.swing.*;

View File

@@ -1,435 +0,0 @@
package com.axis.innovators.box.gui;
import com.axis.innovators.box.verification.OnlineVerification;
import com.axis.innovators.box.verification.UserTags;
import com.axis.innovators.box.verification.VerificationService;
import com.formdev.flatlaf.FlatDarculaLaf;
import javax.swing.*;
import javax.swing.border.LineBorder;
import java.awt.*;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.atomic.AtomicReference;
/**
* 用于登录的主窗口
* @author tzdwindows 7
*/
public class LoginWindow {
private static final AtomicReference<UserTags> loginResult = new AtomicReference<>(UserTags.None);
private JDialog dialog;
private JTextField emailField;
private JPasswordField passwordField;
private JCheckBox showPasswordCheckBox;
private static final int FIELD_WIDTH = 300;
private static final int FIELD_HEIGHT = 35;
public static UserTags createAndShow() throws InterruptedException, InvocationTargetException {
AtomicReference<UserTags> result = new AtomicReference<>(UserTags.None);
SwingUtilities.invokeAndWait(() -> {
LoginWindow loginWindow = new LoginWindow();
loginWindow.dialog.setVisible(true);
result.set(loginResult.get());
if (result.get() == UserTags.None) {
System.exit(0);
}
});
return result.get();
}
private LoginWindow() {
setupLookAndFeel();
createMainDialog();
buildLoginUI();
}
private void setupLookAndFeel() {
try {
UIManager.setLookAndFeel(new FlatDarculaLaf());
// 自定义输入框样式
UIManager.put("Component.arc", 12);
UIManager.put("TextComponent.arc", 12);
UIManager.put("Button.arc", 8);
UIManager.put("ProgressBar.arc", 8);
UIManager.put("TextComponent.background", new Color(0x383838));
UIManager.put("TextField.placeholderForeground", new Color(0x808080));
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
}
private void createMainDialog() {
dialog = new JDialog((Frame) null, "AXIS 安全认证", true);
dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
dialog.setSize(380, 500);
dialog.setLocationRelativeTo(null);
dialog.setResizable(false);
dialog.setLayout(new BorderLayout());
}
private void buildLoginUI() {
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
mainPanel.setBorder(BorderFactory.createEmptyBorder(30, 30, 30, 30));
JLabel titleLabel = new JLabel("欢迎登录");
titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24));
titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
mainPanel.add(titleLabel);
mainPanel.add(Box.createRigidArea(new Dimension(0, 30)));
JPanel inputContainer = new JPanel();
inputContainer.setLayout(new BoxLayout(inputContainer, BoxLayout.Y_AXIS));
inputContainer.setOpaque(false);
inputContainer.setAlignmentX(Component.CENTER_ALIGNMENT);
inputContainer.add(createInputField("账号", buildEmailField()));
inputContainer.add(Box.createRigidArea(new Dimension(0, 10)));
inputContainer.add(createInputField("密码", buildPasswordField()));
mainPanel.add(inputContainer);
mainPanel.add(Box.createRigidArea(new Dimension(0, 30)));
JButton loginButton = createLoginButton();
loginButton.setAlignmentX(Component.CENTER_ALIGNMENT);
mainPanel.add(loginButton);
JPanel linksPanel = createUtilityLinks();
linksPanel.setAlignmentX(Component.CENTER_ALIGNMENT);
mainPanel.add(Box.createRigidArea(new Dimension(0, 30)));
mainPanel.add(linksPanel);
mainPanel.add(Box.createVerticalGlue());
dialog.add(mainPanel, BorderLayout.CENTER);
}
private JComponent buildEmailField() {
emailField = new JTextField();
customizeTextField(emailField, "请输入邮箱或手机号");
return emailField;
}
private JComponent buildPasswordField() {
JPanel passwordPanel = new JPanel(new BorderLayout());
passwordPanel.setOpaque(false);
passwordPanel.setBorder(new RoundBorder(8, new Color(0x454545)));
// 密码输入框
passwordField = new JPasswordField();
passwordField.setFont(new Font("微软雅黑", Font.PLAIN, 14));
passwordField.putClientProperty("JTextField.placeholderText", "请输入密码");
passwordField.setMaximumSize(new Dimension(FIELD_WIDTH, FIELD_HEIGHT));
passwordField.setPreferredSize(new Dimension(FIELD_WIDTH, FIELD_HEIGHT));
passwordField.setBorder(BorderFactory.createEmptyBorder(10, 15, 10, 5));
passwordPanel.add(passwordField, BorderLayout.CENTER);
// 显示密码按钮
JPanel togglePanel = new JPanel(new BorderLayout());
togglePanel.setOpaque(false);
togglePanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10));
showPasswordCheckBox = new JCheckBox();
showPasswordCheckBox.setOpaque(false);
showPasswordCheckBox.setPreferredSize(new Dimension(32, 32));
showPasswordCheckBox.setBackground(new Color(0x46494B));
showPasswordCheckBox.setIcon(UIManager.getIcon("PasswordView.icon"));
showPasswordCheckBox.setSelectedIcon(UIManager.getIcon("PasswordHide.icon"));
showPasswordCheckBox.addActionListener(e -> togglePasswordVisibility());
togglePanel.add(showPasswordCheckBox, BorderLayout.CENTER);
passwordPanel.add(togglePanel, BorderLayout.EAST);
return passwordPanel;
}
private void customizeTextField(JComponent field, String placeholder) {
field.setPreferredSize(new Dimension(FIELD_WIDTH, FIELD_HEIGHT));
field.setMaximumSize(new Dimension(FIELD_WIDTH, FIELD_HEIGHT));
field.putClientProperty("JComponent.roundRect", true);
field.putClientProperty("JTextField.placeholderText", placeholder);
field.setFont(new Font("微软雅黑", Font.PLAIN, 14));
field.setBorder(BorderFactory.createCompoundBorder(
new RoundBorder(8, new Color(0x454545)),
BorderFactory.createEmptyBorder(10, 15, 10, 15)
));
}
private JPanel createInputField(String label, JComponent field) {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.setOpaque(false);
panel.setMaximumSize(new Dimension(280, 62));
JLabel titleLabel = new JLabel(label);
titleLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13));
titleLabel.setForeground(new Color(0x9E9E9E));
titleLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
panel.add(titleLabel);
panel.add(Box.createVerticalStrut(8));
panel.add(field);
return panel;
}
private JButton createLoginButton() {
JButton button = new JButton("立即登录");
button.setFont(new Font("微软雅黑", Font.BOLD, 14));
button.setForeground(Color.WHITE);
button.setBackground(new Color(0x2B579A));
button.setPreferredSize(new Dimension(285, 40));
button.setMaximumSize(new Dimension(285, 40));
button.setAlignmentX(Component.CENTER_ALIGNMENT);
button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
button.addActionListener(e -> attemptLogin());
// 悬停效果
button.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseEntered(java.awt.event.MouseEvent evt) {
button.setBackground(new Color(0x3C6DB0));
}
public void mouseExited(java.awt.event.MouseEvent evt) {
button.setBackground(new Color(0x2B579A));
}
});
return button;
}
private static class RoundBorder extends LineBorder {
private final int radius;
public RoundBorder(int radius, Color color) {
super(color, 1);
this.radius = radius;
}
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.drawRoundRect(x, y, width-1, height-1, radius, radius);
g2.dispose();
}
}
private JPanel createUtilityLinks() {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
panel.setOpaque(false);
JButton registerBtn = createTextButton("注册账号", this::showRegister);
JButton forgotBtn = createTextButton("忘记密码", this::showForgotPassword);
panel.add(Box.createHorizontalGlue());
panel.add(registerBtn);
panel.add(Box.createHorizontalStrut(15));
panel.add(forgotBtn);
panel.add(Box.createHorizontalGlue());
return panel;
}
private JButton createTextButton(String text, Runnable action) {
JButton button = new JButton(text);
button.setForeground(new Color(0x8AB4F8));
button.setFont(new Font("微软雅黑", Font.PLAIN, 12));
button.setContentAreaFilled(false);
button.setBorderPainted(false);
button.setFocusPainted(false);
button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
button.addActionListener(e -> action.run());
return button;
}
private void togglePasswordVisibility() {
if (showPasswordCheckBox.isSelected()) {
passwordField.setEchoChar((char) 0);
} else {
passwordField.setEchoChar('•');
}
}
private void attemptLogin() {
String email = emailField.getText().trim();
String password = new String(passwordField.getPassword()).trim();
if (email.isEmpty() || password.isEmpty()) {
showError("请输入完整的登录信息");
return;
}
OnlineVerification onlineVerification = OnlineVerification.validateLogin(email, password);
loginResult.set(VerificationService.determineUserType(onlineVerification));
dialog.dispose();
}
private void showError(String message) {
JOptionPane.showMessageDialog(dialog, message, "验证错误",
JOptionPane.ERROR_MESSAGE);
}
private void showRegister() {
JDialog registerDialog = new JDialog(dialog, "注册新账号", true);
registerDialog.setSize(380, 500);
registerDialog.setLocationRelativeTo(dialog);
registerDialog.setResizable(false);
registerDialog.setLayout(new BorderLayout());
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
mainPanel.setBorder(BorderFactory.createEmptyBorder(30, 30, 30, 30));
// 标题
JLabel titleLabel = new JLabel("新用户注册");
titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24));
titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
mainPanel.add(titleLabel);
mainPanel.add(Box.createRigidArea(new Dimension(0, 30)));
// 输入容器
JPanel inputContainer = new JPanel();
inputContainer.setLayout(new BoxLayout(inputContainer, BoxLayout.Y_AXIS));
inputContainer.setOpaque(false);
// 用户名
JTextField usernameField = new JTextField();
customizeTextField(usernameField, "请输入用户名");
inputContainer.add(createInputField("用户名", usernameField));
inputContainer.add(Box.createRigidArea(new Dimension(0, 10)));
// 邮箱
JTextField emailField = new JTextField();
customizeTextField(emailField, "请输入邮箱");
inputContainer.add(createInputField("邮箱", emailField));
inputContainer.add(Box.createRigidArea(new Dimension(0, 10)));
// 密码
JPasswordField passwordField = new JPasswordField();
customizeTextField(passwordField, "请输入密码");
inputContainer.add(createInputField("密码", passwordField));
inputContainer.add(Box.createRigidArea(new Dimension(0, 10)));
// 确认密码
JPasswordField confirmField = new JPasswordField();
customizeTextField(confirmField, "请再次输入密码");
inputContainer.add(createInputField("确认密码", confirmField));
mainPanel.add(inputContainer);
mainPanel.add(Box.createRigidArea(new Dimension(0, 30)));
// 注册按钮
JButton regButton = new JButton("立即注册");
styleButton(regButton);
regButton.addActionListener(e -> {
String pwd = new String(passwordField.getPassword());
String confirm = new String(confirmField.getPassword());
if(!pwd.equals(confirm)) {
JOptionPane.showMessageDialog(registerDialog, "两次输入的密码不一致", "注册错误",
JOptionPane.ERROR_MESSAGE);
return;
}
// 调用验证服务
boolean success = VerificationService.registerUser(
usernameField.getText(),
emailField.getText(),
pwd
);
if(success) {
JOptionPane.showMessageDialog(registerDialog, "注册成功,请登录", "注册成功",
JOptionPane.INFORMATION_MESSAGE);
registerDialog.dispose();
} else {
JOptionPane.showMessageDialog(registerDialog, "注册失败,请检查信息", "注册错误",
JOptionPane.ERROR_MESSAGE);
}
});
mainPanel.add(regButton);
// 返回登录链接
JButton backBtn = createTextButton("返回登录", registerDialog::dispose);
backBtn.setAlignmentX(Component.CENTER_ALIGNMENT);
mainPanel.add(Box.createRigidArea(new Dimension(0, 15)));
mainPanel.add(backBtn);
registerDialog.add(mainPanel, BorderLayout.CENTER);
registerDialog.setVisible(true);
}
private void showForgotPassword() {
JDialog forgotDialog = new JDialog(dialog, "找回密码", true);
forgotDialog.setSize(380, 350);
forgotDialog.setLocationRelativeTo(dialog);
forgotDialog.setResizable(false);
forgotDialog.setLayout(new BorderLayout());
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
mainPanel.setBorder(BorderFactory.createEmptyBorder(30, 30, 30, 30));
JLabel titleLabel = new JLabel("找回密码");
titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24));
titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
mainPanel.add(titleLabel);
mainPanel.add(Box.createRigidArea(new Dimension(0, 30)));
// 邮箱输入
JTextField emailField = new JTextField();
customizeTextField(emailField, "请输入注册邮箱");
mainPanel.add(createInputField("注册邮箱", emailField));
mainPanel.add(Box.createRigidArea(new Dimension(0, 30)));
// 提交按钮
JButton submitBtn = new JButton("发送重置邮件");
styleButton(submitBtn);
submitBtn.addActionListener(e -> {
if(VerificationService.sendPasswordReset(emailField.getText())) {
JOptionPane.showMessageDialog(forgotDialog, "重置邮件已发送,请查收", "操作成功",
JOptionPane.INFORMATION_MESSAGE);
forgotDialog.dispose();
} else {
JOptionPane.showMessageDialog(forgotDialog, "邮箱未注册或发送失败", "操作失败",
JOptionPane.ERROR_MESSAGE);
}
});
mainPanel.add(submitBtn);
// 返回链接
JButton backBtn = createTextButton("返回登录", forgotDialog::dispose);
backBtn.setAlignmentX(Component.CENTER_ALIGNMENT);
mainPanel.add(Box.createRigidArea(new Dimension(0, 15)));
mainPanel.add(backBtn);
forgotDialog.add(mainPanel, BorderLayout.CENTER);
forgotDialog.setVisible(true);
}
// 通用按钮样式方法
private void styleButton(JButton button) {
button.setFont(new Font("微软雅黑", Font.BOLD, 14));
button.setForeground(Color.WHITE);
button.setBackground(new Color(0x2B579A));
button.setPreferredSize(new Dimension(285, 40));
button.setMaximumSize(new Dimension(285, 40));
button.setAlignmentX(Component.CENTER_ALIGNMENT);
button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
// 悬停效果
button.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseEntered(java.awt.event.MouseEvent evt) {
button.setBackground(new Color(0x3C6DB0));
}
public void mouseExited(java.awt.event.MouseEvent evt) {
button.setBackground(new Color(0x2B579A));
}
});
}
}

View File

@@ -1,818 +0,0 @@
package com.axis.innovators.box.gui;
import com.axis.innovators.box.AxisInnovatorsBox;
import com.axis.innovators.box.events.*;
import com.axis.innovators.box.register.LanguageManager;
import com.axis.innovators.box.register.RegistrationSettingsItem;
import com.formdev.flatlaf.FlatClientProperties;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.swing.Timer;
import javax.swing.*;
import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.PanelUI;
import javax.swing.plaf.basic.BasicScrollBarUI;
import javax.swing.plaf.basic.BasicTabbedPaneUI;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.util.List;
import java.util.*;
/**
* 显示窗口(显示的主窗口)
* @author tzdwindows 7
*/
public class MainWindow extends JFrame {
private static final Logger logger = LogManager.getLogger(MainWindow.class);
private final Map<JComponent, Float> cardScales = new HashMap<>();
private final Map<JComponent, Integer> cardElevations = new HashMap<>();
private final Color CARD_COLOR = Color.WHITE;
private final List<ToolCategory> categories = new ArrayList<>();
private SystemTray systemTray;
//private TrayIcon trayIcon;
public MainWindow() {
setIconImage(LoadIcon.loadIcon("logo.png", 32).getImage());
addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
for (JComponent card : cardScales.keySet()) {
cardScales.put(card, 1.0f);
card.repaint();
}
}
});
}
/**
* 添加工具分类
* @param category 工具分类
*/
public void addToolCategory(ToolCategory category){
categories.add(category);
}
public void initUI() {
setTitle(LanguageManager.getLoadedLanguages().getText("mainWindow.title"));
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(1200, 800);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
getContentPane().setBackground(new Color(0, 0, 0, 0));
JPanel mainPanel = new JPanel();
mainPanel.setOpaque(true);
mainPanel.setLayout(new BorderLayout(20, 20));
mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 30, 30, 30));
mainPanel.add(createHeader(), BorderLayout.NORTH);
mainPanel.add(createCategoryTabs(), BorderLayout.CENTER);
//mainPanel.add(createFooter(), BorderLayout.SOUTH); 底部菜单
add(mainPanel);
//createSystemTray();
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
setVisible(false);
}
});
}
private JPanel createFooter() {
JPanel footer = new JPanel();
footer.setLayout(new BoxLayout(footer, BoxLayout.X_AXIS));
footer.setBorder(BorderFactory.createEmptyBorder(15, 30, 15, 30));
JLabel version = new JLabel("轴创工具箱 v1.0");
version.setFont(new Font("微软雅黑", Font.PLAIN, 12));
version.setForeground(new Color(120, 120, 120));
footer.add(version);
footer.add(Box.createHorizontalGlue());
JLabel status = new JLabel("已加载 " + categories.size() + " 个分类, " +
categories.stream().mapToInt(c -> c.getTools().size()).sum() + " 个工具");
status.setFont(new Font("微软雅黑", Font.PLAIN, 12));
status.setForeground(new Color(120, 120, 120));
footer.add(status);
return footer;
}
// 基础菜单项创建方法(解决方法不存在问题)
private MenuItem createBaseMenuItem(String text, ActionListener action) {
MenuItem item = new MenuItem(text);
item.addActionListener(action);
return item;
}
// 圆角图标生成(修正版)
private Image createRoundedIcon(Image source, int cornerRadius) {
int size = Math.max(source.getWidth(null), source.getHeight(null));
BufferedImage output = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = output.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 创建剪切路径
RoundRectangle2D roundRect = new RoundRectangle2D.Float(0, 0, size, size, cornerRadius, cornerRadius);
g2.setClip(roundRect);
g2.drawImage(source, 0, 0, size, size, null);
g2.dispose();
return output;
}
// 添加事件监听
//private void addTrayEventListeners() {
// // 双击恢复窗口
// trayIcon.addActionListener(e -> setVisible(true));
//
// // 右键菜单触发兼容处理
// trayIcon.addMouseListener(new MouseAdapter() {
// @Override
// public void mouseReleased(MouseEvent e) {
// if (e.isPopupTrigger()) {
// trayIcon.getPopupMenu().show(e.getComponent(), e.getX(), e.getY());
// }
// }
// });
//}
// 初始化中文字体在main方法或构造函数中调用
private void initChineseFont() {
String[] fontPriority = {
"Microsoft YaHei",
"PingFang SC",
"SimSun",
Font.DIALOG
};
for (String fontName : fontPriority) {
if (isFontAvailable(fontName)) {
setGlobalFont(new Font(fontName, Font.PLAIN, 12));
break;
}
}
}
// 字体可用性检查
private boolean isFontAvailable(String fontName) {
return Arrays.asList(GraphicsEnvironment
.getLocalGraphicsEnvironment()
.getAvailableFontFamilyNames())
.contains(fontName);
}
// 全局字体设置
private void setGlobalFont(Font font) {
FontUIResource fontRes = new FontUIResource(font);
UIManager.put("MenuItem.font", fontRes);
UIManager.put("Menu.font", fontRes);
}
/**
* 对图像应用动感模糊效果。
*
* @param srcImage 需要应用动感模糊的源图像。
* 这个参数应该是一个 `BufferedImage` 类型的对象。
* @param radius 动感模糊的半径,决定模糊效果的范围。
* 半径越大,模糊范围越广,模糊效果越强。
* @param angle 动感模糊的角度,决定模糊效果的方向。
* 角度单位为度表示从正Y轴顺时针的旋转角度。
* 比如:
* - `0` 表示水平方向的模糊。
* - `90` 表示垂直方向的模糊。
* - 其他角度则表示不同方向的模糊。
* @return 返回应用了动感模糊效果的 `BufferedImage` 图像。
* 原始图像不会被修改,返回的是处理过的新图像。
*/
public BufferedImage applyMotionBlur(BufferedImage srcImage, int radius, int angle) {
double radian = Math.toRadians(angle);
float[] matrix = new float[radius * radius];
float sum = 0.0f;
int index = 0;
for (int y = -radius / 2; y <= radius / 2; y++) {
for (int x = -radius / 2; x <= radius / 2; x++) {
float weight = (float) (Math.cos(radian) * x + Math.sin(radian) * y);
if (Math.abs(weight) < 1) {
matrix[index++] = 1.0f;
sum += 1.0f;
} else {
matrix[index++] = 0.0f;
}
}
}
return getBufferedImage(srcImage, radius, matrix, sum);
}
private BufferedImage getBufferedImage(BufferedImage srcImage, int radius, float[] matrix, float sum) {
for (int i = 0; i < matrix.length; i++) {
matrix[i] /= sum;
}
Kernel kernel = new Kernel(radius, radius, matrix);
ConvolveOp convolve = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
return convolve.filter(srcImage, null);
}
/**
* 应用高斯模糊效果到给定的图像。
*
* @param srcImage 输入的原始图像,类型为 `BufferedImage`。
* @param radius 高斯模糊的半径,表示模糊的强度。半径越大,模糊效果越强。
* @return 返回模糊处理后的图像,类型为 `BufferedImage`。
*/
public BufferedImage applyGaussianBlur(BufferedImage srcImage, int radius) {
if (radius > 100) {
radius = 100;
}
float[] matrix = new float[radius * radius];
float sigma = radius / 2f;
float sum = 0.0f;
int index = 0;
for (int y = -radius / 2; y <= radius / 2; y++) {
for (int x = -radius / 2; x <= radius / 2; x++) {
float weight = (float) Math.exp(-(x * x + y * y) / (2 * sigma * sigma));
matrix[index] = weight;
index++;
sum += weight;
}
}
return getBufferedImage(srcImage, radius, matrix, sum);
}
private JComponent createCategoryTabs() {
JTabbedPane tabbedPane = new JTabbedPane();
//tabbedPane.putClientProperty(FlatClientProperties.TABBED_PANE_TAB_AREA_ALIGN, Component.LEFT_ALIGNMENT);
tabbedPane.putClientProperty(FlatClientProperties.TABBED_PANE_TAB_HEIGHT, 40);
tabbedPane.putClientProperty(FlatClientProperties.TABBED_PANE_TAB_ICON_PLACEMENT, SwingConstants.TOP);
tabbedPane.setOpaque(false);
tabbedPane.setBackground(new Color(0, 0, 0, 0));
tabbedPane.setBorder(null);
//tabbedPane.setUI(new CustomTabbedPaneUI());
for (ToolCategory category : categories) {
JPanel toolsPanel = createToolsPanel(category);
toolsPanel.setOpaque(false);
toolsPanel.setBorder(null);
JScrollPane scrollPane = new JScrollPane(toolsPanel);
scrollPane.setBorder(null);
scrollPane.setOpaque(false);
scrollPane.getViewport().setOpaque(false);
JScrollBar verticalScrollBar = scrollPane.getVerticalScrollBar();
//verticalScrollBar.setUI(new CustomScrollBarUI());
verticalScrollBar.setPreferredSize(new Dimension(10, 100));
if (category.getIcon() == null){
tabbedPane.addTab(
category.getName(),
category.getIconImage(),
scrollPane
);
}
tabbedPane.addTab(
category.getName(),
LoadIcon.loadIcon(category.getIcon(), 12),
scrollPane
);
}
return tabbedPane;
}
private JPanel createToolsPanel(ToolCategory category) {
JPanel panel = new JPanel(new GridLayout(0, 3, 20, 20));
for (ToolItem tool : category.getTools()) {
panel.add(createToolCard(tool));
}
panel.setOpaque(false);
panel.setBorder(null);
return panel;
}
private JPanel createHeader() {
JPanel header = new JPanel(new BorderLayout());
header.setOpaque(false);
header.setBorder(BorderFactory.createEmptyBorder(15, 30, 15, 30));
// 创建标题
JLabel title = new JLabel(LanguageManager.getLoadedLanguages().getText("mainWindow.title.2"));
title.setFont(new Font("微软雅黑", Font.BOLD, 28));
title.setForeground(new Color(255, 255, 255));
JButton settings = new JButton(LoadIcon.loadIcon("settings.png", 32));
settings.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_BORDERLESS);
settings.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
settings.setContentAreaFilled(false);
settings.addActionListener(e -> showSettings());
JPanel titlePanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
titlePanel.setOpaque(false);
titlePanel.add(title);
header.add(titlePanel, BorderLayout.WEST);
header.add(settings, BorderLayout.EAST);
return header;
}
@Override
public void update(Graphics g) {
GlobalEventBus.EVENT_BUS.post(new MainWindowEvents.update(this, g));
super.update(g);
}
private WindowsJDialog dialog;
public void showSettings() {
if (dialog == null || AxisInnovatorsBox.getMain().isWindowStartup(dialog)) {
dialog = new WindowsJDialog(this,
LanguageManager.getLoadedLanguages().getText("mainWindow.settings.title"), true);
}
dialog.setTitle(LanguageManager.getLoadedLanguages().getText("mainWindow.settings.title"));
dialog.setSize(600, 400);
dialog.setLocationRelativeTo(this);
JPanel content = new JPanel(new BorderLayout());
content.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
JTabbedPane tabbedPane = new JTabbedPane();
List<RegistrationSettingsItem> registrationSettingsItemList
= RegistrationSettingsItem.getRegistrationSettingsItemList();
for (RegistrationSettingsItem registrationSettingsItem : registrationSettingsItemList) {
registrationSettingsItem.registration(tabbedPane);
}
content.add(tabbedPane, BorderLayout.CENTER);
GlobalEventBus.EVENT_BUS.post(new SettingsLoadEvents(dialog, content));
dialog.add(content);
dialog.revalidate();
if (AxisInnovatorsBox.getMain().isWindowStartup(dialog)) {
AxisInnovatorsBox.getMain().popupWindow(dialog);
}
}
private JPanel createToolCard(ToolItem tool) {
JPanel card = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
// 毛玻璃效果
BufferedImage background = new BufferedImage(
getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
super.paintComponent(background.getGraphics());
BufferedImage blurred = applyGaussianBlur(background, 5);
g2d.drawImage(blurred, 0, 0, null);
// 绘制阴影
int elevation = cardElevations.getOrDefault(this, 2);
for (int i = 0; i < elevation; i++) {
g2d.setColor(new Color(0, 0, 0, 20 - i * 2));
g2d.fillRoundRect(i, i, getWidth() - i * 2, getHeight() - i * 2, 15, 15);
}
float scale = cardScales.getOrDefault(this, 1.0f);
int offset = (int) ((scale - 1) * getWidth() / 2);
g2d.translate(-offset, -offset);
g2d.scale(scale, scale);
super.paintComponent(g2d);
g2d.dispose();
}
};
card.setPreferredSize(new Dimension(200, 150));
card.setMinimumSize(new Dimension(100, 75));
card.setLayout(new BorderLayout(15, 15));
//card.setBackground(CARD_COLOR);
card.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(new Color(225, 229, 234), 1),
BorderFactory.createEmptyBorder(20, 20, 20, 20)
));
card.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
JLabel iconLabel;
if (tool.getIcon() == null){
iconLabel = new JLabel(tool.getImageIcon());
}else {
iconLabel = new JLabel(LoadIcon.loadIcon(tool.getIcon(), 64));
}
iconLabel.setHorizontalAlignment(SwingConstants.CENTER);
// 文字面板
JPanel textPanel = new JPanel();
textPanel.setLayout(new BoxLayout(textPanel, BoxLayout.Y_AXIS));
textPanel.setOpaque(false);
JLabel titleLabel = new JLabel(tool.getTitle());
titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 18));
titleLabel.setForeground(new Color(255, 255, 255));
titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
JTextArea descArea = new JTextArea(tool.getDescription());
descArea.setFont(new Font("微软雅黑", Font.PLAIN, 14));
descArea.setForeground(new Color(177, 177, 177));
descArea.setLineWrap(true);
descArea.setWrapStyleWord(true);
descArea.setEditable(false);
descArea.setOpaque(false);
descArea.setAlignmentX(Component.CENTER_ALIGNMENT);
card.setToolTipText(createToolTipHTML(tool));
textPanel.add(titleLabel);
textPanel.add(Box.createVerticalStrut(10));
textPanel.add(descArea);
card.add(iconLabel, BorderLayout.NORTH);
card.add(textPanel, BorderLayout.CENTER);
card.addMouseListener(new CardMouseAdapter(card, tool));
card.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
SwingUtilities.invokeLater(() -> {
});
}
});
card.setUI(new PanelUI() {
@Override
public void installUI(JComponent c) {
GlobalEventBus.EVENT_BUS.post(new TABUIEvents(card, c));
super.installUI(c);
}
@Override
public void update(Graphics g, JComponent c) {
GlobalEventBus.EVENT_BUS.post(new TABUIEvents.update(g, c));
super.update(g, c);
}
});
card.addMouseListener(new CardMouseAdapter(card, tool) {
@Override
public void mouseEntered(MouseEvent e) {
cardElevations.put(card, 8);
animateCardElevation(card, 8);
}
@Override
public void mouseExited(MouseEvent e) {
animateCardElevation(card, 2);
}
});
return card;
}
private String createToolTipHTML(ToolItem tool) {
return "<html><body style='width: 300px; padding: 10px;'>" +
"<h3 style='color: #2c3e50; margin: 0 0 8px 0;'>" + tool.getName() + "</h3>" +
"<p style='color: #7f8c99; margin: 0;'>" + tool.getDescription() + "</p>" +
"</body></html>";
}
private void animateCardElevation(JComponent card, int targetElevation) {
new Timer(10, new AbstractAction() {
private int currentElevation = cardElevations.getOrDefault(card, 2);
@Override
public void actionPerformed(ActionEvent e) {
if (currentElevation < targetElevation) currentElevation++;
else if (currentElevation > targetElevation) currentElevation--;
cardElevations.put(card, currentElevation);
card.repaint();
if (currentElevation == targetElevation) {
((Timer)e.getSource()).stop();
}
}
}).start();
}
public static class ToolCategory {
private final String name;
private final String icon;
private final ImageIcon iconImage;
private final String description;
private final UUID id = UUID.randomUUID();
private final List<ToolItem> tools = new ArrayList<>();
/**
* 一个大的分类项类
* @param name 分类项的显示名称
* @param icon 分类项的图标resources的路径
* @param description 分类项的描述
*/
public ToolCategory(String name, String icon, String description) {
this.name = name;
this.icon = icon;
this.description = description;
this.iconImage = null;
}
public ToolCategory(String name, ImageIcon icon, String description) {
this.name = name;
this.iconImage = icon;
this.description = description;
this.icon = null;
}
/**
* 注册工具的方法
* @param tool 工具项
*/
public void addTool(ToolItem tool) {
tools.add(tool);
}
public String getDescription() {
return description;
}
public String getIcon() {
return icon;
}
public String getName() {
return name;
}
public List<ToolItem> getTools() {
return tools;
}
public ImageIcon getIconImage() {
return iconImage;
}
public UUID getId() {
return id;
}
}
// 工具项数据类
/**
* 工具注册类
*/
public static class ToolItem {
private final ImageIcon imageIcon;
private final String title;
private final String icon;
private final String description;
private final int id;
private final Action action;
public ToolItem(String title, String icon, String description, int id, Action action){
this.title = title;
this.icon = icon;
this.description = description;
this.id = id;
this.action = action;
this.imageIcon = null;
}
public ToolItem(String title, ImageIcon icon, String description, int id, Action action) {
this.title = title;
this.imageIcon = icon;
this.description = description;
this.id = id;
this.action = action;
this.icon = null;
}
public String getTitle() {
return title;
}
public ImageIcon icon() {
return imageIcon;
}
public String getIcon() {
return icon;
}
public Action getAction() {
return action;
}
public ImageIcon getImageIcon() {
return imageIcon;
}
public int getId() {
return id;
}
public String getDescription() {
return description;
}
public String getName() {
return title;
}
}
// 分类栏面卡
public static class CustomTabbedPaneUI extends BasicTabbedPaneUI {
private static final Color SELECTED_COLOR = new Color(183, 202, 221);
private static final Color UNSELECTED_COLOR = new Color(125, 174, 237);
@Override
protected void paintTabBackground(Graphics g, int tabPlacement,
int tabIndex, int x, int y, int w, int h,
boolean isSelected) {
CategoryRenderingEvent event = new CategoryRenderingEvent(this, g, tabPlacement, tabIndex, x, y, w, h, isSelected);
GlobalEventBus.EVENT_BUS.post(event);
if (event.isEnd()){
return;
}
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (isSelected) {
g2d.setColor(SELECTED_COLOR);
} else {
g2d.setColor(UNSELECTED_COLOR);
}
g2d.fillRoundRect(x + 2, y + 2, w - 4, h - 4, 10, 10);
g2d.dispose();
}
@Override
protected void paintTabBorder(Graphics g, int tabPlacement,
int tabIndex, int x, int y, int w, int h,
boolean isSelected) {
GlobalEventBus.EVENT_BUS.post(new CategoryRenderingEvent.paintTabBorder(this, g,
tabPlacement,
tabIndex, x, y, w, h, isSelected));
}
}
private class CardMouseAdapter extends MouseAdapter {
private final JPanel card;
private final ToolItem tool;
private Timer pressTimer;
private Timer releaseTimer;
private static int delay = 0;
public CardMouseAdapter(JPanel card, ToolItem tool) {
this.card = card;
this.tool = tool;
}
@Override
public void mousePressed(MouseEvent e) {
startPressAnimation();
}
@Override
public void mouseReleased(MouseEvent e) {
if (delay == 0) {
delay++;
startReleaseAnimation(() -> tool.getAction().actionPerformed(
new ActionEvent(card, ActionEvent.ACTION_PERFORMED, "")
));
} else {
delay--;
}
}
@Override
public void mouseExited(MouseEvent e) {
if (pressTimer != null && pressTimer.isRunning()) {
startReleaseAnimation(null);
}
}
private void startPressAnimation() {
if (pressTimer != null && pressTimer.isRunning()) {
return;
}
pressTimer = new Timer(10, new AbstractAction() {
private final long startTime = System.currentTimeMillis();
@Override
public void actionPerformed(ActionEvent e) {
float progress = Math.min(1.0f,
(System.currentTimeMillis() - startTime) / 150f);
// 使用二次缓动函数
float scale = 1.0f - 0.1f * (float) Math.pow(progress, 0.5);
cardScales.put(card, scale);
card.repaint();
if (progress >= 1.0f) {
((Timer) e.getSource()).stop();
}
}
});
pressTimer.start();
}
private void startReleaseAnimation(Runnable callback) {
if (pressTimer != null) {
pressTimer.stop();
}
if (releaseTimer != null && releaseTimer.isRunning()) {
return;
}
final float startScale = cardScales.getOrDefault(card, 1.0f);
releaseTimer = new Timer(10, new AbstractAction() {
private final long startTime = System.currentTimeMillis();
@Override
public void actionPerformed(ActionEvent e) {
float progress = Math.min(1.0f,
(System.currentTimeMillis() - startTime) / 200f);
// 使用弹性缓动函数
float scale = startScale +
(1.0f - startScale) * (float) (1 - Math.pow(1 - progress, 3));
cardScales.put(card, scale);
card.repaint();
if (progress >= 1.0f) {
((Timer) e.getSource()).stop();
if (callback != null) {
callback.run();
}
}
}
});
releaseTimer.start();
}
}
public static class CustomScrollBarUI extends BasicScrollBarUI {
@Override
protected void configureScrollBarColors() {
this.thumbColor = new Color(90, 90, 120);
this.trackColor = new Color(50, 50, 70);
}
@Override
protected JButton createDecreaseButton(int orientation) {
return createInvisibleButton();
}
@Override
protected JButton createIncreaseButton(int orientation) {
return createInvisibleButton();
}
private JButton createInvisibleButton() {
JButton btn = new JButton();
btn.setPreferredSize(new Dimension(0, 0));
btn.setMinimumSize(new Dimension(0, 0));
btn.setMaximumSize(new Dimension(0, 0));
return btn;
}
@Override
protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(thumbColor);
g2.fillRoundRect(
thumbBounds.x + 2,
thumbBounds.y + 2,
thumbBounds.width - 4,
thumbBounds.height - 4,
8, 8
);
}
}
}

View File

@@ -1,109 +0,0 @@
package com.axis.innovators.box.gui;
import javax.swing.*;
import java.awt.*;
import java.util.HashMap;
import java.util.Map;
/**
* 启动窗口的任务系统
* @author tzdwindows 7
*/
public class ProgressBarManager extends WindowsJDialog {
private JFrame loadingFrame;
private JProgressBar mainProgressBar;
private JProgressBar subProgressBar;
private JLabel statusLabel;
private JLabel timeLabel;
private long startTime;
private int totalTasks;
private int completedTasks;
private Map<String, Integer> subTasks = new HashMap<>();
public ProgressBarManager(String title, int totalTasks) {
this.totalTasks = totalTasks;
this.completedTasks = 0;
this.startTime = System.currentTimeMillis();
loadingFrame = new JFrame(title);
loadingFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
loadingFrame.setSize(400, 250);
loadingFrame.setLocationRelativeTo(null);
loadingFrame.setIconImage(LoadIcon.loadIcon("logo.png", 64).getImage());
JPanel loadingPanel = new JPanel(new BorderLayout());
mainProgressBar = new JProgressBar(0, 100);
mainProgressBar.setStringPainted(true);
subProgressBar = new JProgressBar(0, 100);
subProgressBar.setStringPainted(true);
subProgressBar.setString("Subtask Progress");
statusLabel = new JLabel("Initializing...", SwingConstants.CENTER);
timeLabel = new JLabel("Time elapsed: 0s", SwingConstants.CENTER);
JLabel logoLabel = new JLabel(LoadIcon.loadIcon("logo.png", 64));
JPanel progressPanel = new JPanel(new GridLayout(2, 1));
progressPanel.add(mainProgressBar);
progressPanel.add(subProgressBar);
loadingPanel.add(logoLabel, BorderLayout.NORTH);
loadingPanel.add(progressPanel, BorderLayout.CENTER);
loadingPanel.add(statusLabel, BorderLayout.SOUTH);
loadingPanel.add(timeLabel, BorderLayout.SOUTH);
loadingFrame.add(loadingPanel);
loadingFrame.setVisible(true);
}
/**
* 更新主任务进度
* @param completedTasks 已完成的主任务数量
*/
public void updateMainProgress(int completedTasks) {
this.completedTasks = completedTasks;
int progress = (int) ((completedTasks / (double) totalTasks) * 100);
mainProgressBar.setValue(progress);
statusLabel.setText("Main Progress: " + progress + "%");
updateTimeLabel();
}
/**
* 更新子任务进度
* @param subTaskName 子任务名称
* @param subTaskCompleted 已完成的子任务数量
* @param subTaskTotal 子任务总数
*/
public void updateSubProgress(String subTaskName, int subTaskCompleted, int subTaskTotal) {
subTasks.put(subTaskName, subTaskCompleted);
int progress = (int) ((subTaskCompleted / (double) subTaskTotal) * 100);
subProgressBar.setValue(progress);
subProgressBar.setString(subTaskName + ": " + progress + "%");
updateTimeLabel();
}
/**
* 更新总任务数
*/
public void setTotalTasks(int totalTasks) {
this.totalTasks = totalTasks;
}
/**
* 关闭加载窗口
*/
public void close() {
loadingFrame.dispose();
}
/**
* 更新时间标签
*/
private void updateTimeLabel() {
long elapsedTime = (System.currentTimeMillis() - startTime) / 1000;
timeLabel.setText("Time elapsed: " + elapsedTime + "s");
}
}

View File

@@ -1,7 +1,7 @@
package com.axis.innovators.box.python;
import com.axis.innovators.box.AxisInnovatorsBox;
import com.axis.innovators.box.gui.MainWindow;
import com.axis.innovators.box.window.MainWindow;
import com.axis.innovators.box.register.LanguageManager;
import javax.swing.*;

View File

@@ -2,8 +2,8 @@ package com.axis.innovators.box.register;
import com.axis.innovators.box.AxisInnovatorsBox;
import com.axis.innovators.box.gui.LoadIcon;
import com.axis.innovators.box.gui.WindowsJDialog;
import com.axis.innovators.box.window.LoadIcon;
import com.axis.innovators.box.window.WindowsJDialog;
import com.axis.innovators.box.plugins.PluginDescriptor;
import com.axis.innovators.box.plugins.PluginLoader;
import com.axis.innovators.box.plugins.PluginPyLoader;
@@ -258,6 +258,7 @@ public class RegistrationSettingsItem extends WindowsJDialog {
language.getText("settings.4.load_theme_success.3"), JOptionPane.INFORMATION_MESSAGE);
registrationTopic.setLoading(registeredName);
themeList.repaint();
AxisInnovatorsBox.getMain().reloadAllWindow();
} catch (Exception e) {
JOptionPane.showMessageDialog(null, language.getText("settings.4.load_theme_error")
+ e.getMessage(),

View File

@@ -2,9 +2,9 @@ package com.axis.innovators.box.register;
import com.axis.innovators.box.AxisInnovatorsBox;
import com.axis.innovators.box.browser.MainApplication;
import com.axis.innovators.box.gui.FridaWindow;
import com.axis.innovators.box.gui.JarApiProfilingWindow;
import com.axis.innovators.box.gui.MainWindow;
import com.axis.innovators.box.window.FridaWindow;
import com.axis.innovators.box.window.JarApiProfilingWindow;
import com.axis.innovators.box.window.MainWindow;
import com.axis.innovators.box.plugins.PluginDescriptor;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

View File

@@ -28,6 +28,7 @@ public class RegistrationTopic {
private final List<LookAndFeel> topicsClassesLookAndFeel = new ArrayList<>();
private final List<String> topicsName = new ArrayList<>();
private final List<String> registeredNameList = new ArrayList<>();
private final List<Boolean> isDarkModeList = new ArrayList<>();
private final List<Icon> iconList = new ArrayList<>();
private final List<String> tipList = new ArrayList<>();
private final AxisInnovatorsBox axisInnovatorsBox;
@@ -52,7 +53,7 @@ public class RegistrationTopic {
* @param registeredName 主题注册名
* @throws RegistrationError 如果注册名已存在,则抛出异常
*/
public void addTopic(String topicClass, String topicName, String tip ,Icon icon, String registeredName) {
public void addTopic(String topicClass, String topicName, String tip ,Icon icon, String registeredName, boolean isDarkMode) {
if (!axisInnovatorsBox.isWindow()) {
if (registeredNameList.contains(registeredName)) {
throw new RegistrationError(registeredName + " duplicate registered names");
@@ -63,6 +64,7 @@ public class RegistrationTopic {
tipList.add(tip);
iconList.add(icon);
registeredNameList.add(registeredName);
isDarkModeList.add(isDarkMode);
} else {
logger.warn("Wrong time to add topics");
}
@@ -78,7 +80,7 @@ public class RegistrationTopic {
* @param registeredName 主题注册名
* @throws RegistrationError 如果注册名已存在,则抛出异常
*/
public void addTopic(LookAndFeel topicClass, String topicName, String tip ,Icon icon, String registeredName) {
public void addTopic(LookAndFeel topicClass, String topicName, String tip ,Icon icon, String registeredName, boolean isDarkMode) {
if (!axisInnovatorsBox.isWindow()) {
if (registeredNameList.contains(registeredName)) {
throw new RegistrationError(registeredName + " duplicate registered names");
@@ -89,6 +91,7 @@ public class RegistrationTopic {
tipList.add(tip);
iconList.add(icon);
registeredNameList.add(registeredName);
isDarkModeList.add(isDarkMode);
} else {
logger.warn("Wrong time to add topics");
}
@@ -107,6 +110,23 @@ public class RegistrationTopic {
return Objects.equals(loading, loadTopics);
}
/**
* 检查当前加载的主题是否是暗黑模式
* @return true 如果是暗黑模式false 如果是浅色模式
*/
public boolean isDarkMode() {
if (loadTopics.isEmpty()) {
return false;
}
int index = registeredNameList.indexOf(loadTopics);
if (index >= 0 && index < isDarkModeList.size()) {
return isDarkModeList.get(index);
}
return false;
}
/**
* 设置当前加载的主题。
*

View File

@@ -5,11 +5,11 @@ import java.nio.file.Paths;
public class Main {
public static void main(String[] args) throws Exception {
HighAccuracySpeechRecognition recognizer = new HighAccuracySpeechRecognition(
"C:\\Users\\Administrator\\Desktop\\声音识别模型\\vosk-model-cn-0.22",
"output"
);
recognizer.processAudio(Paths.get("G:\\鬼畜素材\\工作间\\哪吒-嗵嗵\\哪吒-嗵嗵1.wav"));
//HighAccuracySpeechRecognition recognizer = new HighAccuracySpeechRecognition(
// "C:\\Users\\Administrator\\Desktop\\声音识别模型\\vosk-model-cn-0.22",
// "output"
//);
//
//recognizer.processAudio(Paths.get("G:\\鬼畜素材\\工作间\\哪吒-嗵嗵\\哪吒-嗵嗵1.wav"));
}
}

View File

@@ -130,34 +130,42 @@ public class StateManager {
}
public int getStateAsInt(String key) {
return Integer.parseInt(configMap.get(key));
String value = configMap.get(key);
return value != null ? Integer.parseInt(value) : 0;
}
public long getStateAsLong(String key) {
return Long.parseLong(configMap.get(key));
String value = configMap.get(key);
return value != null ? Long.parseLong(value) : 0L;
}
public float getStateAsFloat(String key) {
return Float.parseFloat(configMap.get(key));
String value = configMap.get(key);
return value != null ? Float.parseFloat(value) : 0.0f;
}
public boolean getStateAsBoolean(String key) {
return Boolean.parseBoolean(configMap.get(key));
String value = configMap.get(key);
return value != null ? Boolean.parseBoolean(value) : false;
}
public double getStateAsDouble(String key) {
return Double.parseDouble(configMap.get(key));
String value = configMap.get(key);
return value != null ? Double.parseDouble(value) : 0.0;
}
public char getStateAsChar(String key) {
return configMap.get(key).charAt(0);
String value = configMap.get(key);
return value != null && !value.isEmpty() ? value.charAt(0) : '\0';
}
public byte getStateAsByte(String key) {
return Byte.parseByte(configMap.get(key));
String value = configMap.get(key);
return value != null ? Byte.parseByte(value) : 0;
}
public short getStateAsShort(String key) {
return Short.parseShort(configMap.get(key));
String value = configMap.get(key);
return value != null ? Short.parseShort(value) : 0;
}
}

View File

@@ -31,6 +31,41 @@ public class SystemInfoUtil {
return System.getProperty("os.name");
}
/**
* 判断当前系统是否处于深色模式
* @return true 表示处于深色模式false 表示处于浅色模式
*/
public static boolean isSystemDarkMode() {
try {
if (System.getProperty("os.name").toLowerCase().contains("mac")) {
Process process = Runtime.getRuntime().exec("defaults read -g AppleInterfaceStyle");
return process.waitFor() == 0; // 命令成功返回表示深色模式
}
else if (System.getProperty("os.name").toLowerCase().contains("windows")) {
String cmd = "reg query HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize "
+ "/v AppsUseLightTheme";
Process process = Runtime.getRuntime().exec(cmd);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
if (line.contains("REG_DWORD") && line.contains("0x0")) {
return true;
}
}
}
else if (System.getenv("XDG_CURRENT_DESKTOP") != null
&& System.getenv("XDG_CURRENT_DESKTOP").toLowerCase().contains("gnome")) {
Process process = Runtime.getRuntime().exec("gsettings get org.gnome.desktop.interface color-scheme");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = reader.readLine();
return line != null && line.contains("dark");
}
} catch (Exception e) {
logger.warn("Failed to detect system dark mode", e);
}
return false;
}
/**
* 获取 CPU 信息
*/

View File

@@ -1,6 +1,6 @@
package com.axis.innovators.box.util;
import com.axis.innovators.box.gui.JarApiProfilingWindow;
import com.axis.innovators.box.window.JarApiProfilingWindow;
import javax.swing.*;
import java.awt.*;

View File

@@ -39,6 +39,9 @@ public class UserLocalInformation {
OnlineVerification onlineVerification = OnlineVerification.validateLogin(
verification,
password);
if (onlineVerification == null){
return null;
}
return VerificationService.determineUserType(onlineVerification);
}
}

View File

@@ -2,32 +2,31 @@ package com.axis.innovators.box.verification;
/**
* 在线验证用户身份
* 用于报错用户的验证信息
* @author tzdwindows 7
*/
public class OnlineVerification {
public String onlineVerification;
public UserTags userTags;
public String password;
OnlineVerification(String onlineVerification, UserTags userTags){
this.onlineVerification = onlineVerification;
this.userTags = userTags;
}
/* 我是错误信息,要返回错误请修改我 */
public static String errorMessage = "用户不存在";
/**
* 验证登录
* @param identifier
* @param password
* @param identifier 账号
* @param password 密码
*/
OnlineVerification(String identifier, String password){
this.onlineVerification = identifier;
this.password = password;
}
public static OnlineVerification validateLogin(String identifier){
return new OnlineVerification(identifier, UserTags.RegularUsers);
}
/**
* 验证登录
* @param identifier 账号
* @param password 密码
* @return 验证结果,如果返回null则表示验证失败使用errorMessage获取验证失败的原因
*/
public static OnlineVerification validateLogin(String identifier, String password){
return new OnlineVerification(identifier, password);
}

View File

@@ -31,6 +31,11 @@ public enum UserTags {
EnterpriseUsers;
private OnlineVerification onlineVerification;
/**
* 设置用户组信息
* @param onlineVerification 用户验证结果信息
*/
void setUser(OnlineVerification onlineVerification) {
this.onlineVerification = onlineVerification;
}

View File

@@ -4,6 +4,12 @@ package com.axis.innovators.box.verification;
* @author tzdwindows 7
*/
public class VerificationService {
/**
* 确定用户类型
* @param identifier 用户
* @return 用户类型
*/
public static UserTags determineUserType(OnlineVerification identifier) {
UserTags userTags = UserTags.RegularUsers;
userTags.setUser(identifier);
@@ -19,6 +25,13 @@ public class VerificationService {
return true;
}
/**
* 注册用户
* @param text
* @param text1
* @param pwd
* @return
*/
public static boolean registerUser(String text, String text1, String pwd) {
return true;
}

View File

@@ -1,4 +1,4 @@
package com.axis.innovators.box.gui;
package com.axis.innovators.box.window;
import javax.swing.*;
import java.awt.*;

View File

@@ -1,4 +1,4 @@
package com.axis.innovators.box.gui;
package com.axis.innovators.box.window;
import com.axis.innovators.box.AxisInnovatorsBox;
import org.tzd.debug.ClassDebug;

View File

@@ -1,4 +1,4 @@
package com.axis.innovators.box.gui;
package com.axis.innovators.box.window;
import org.fife.ui.autocomplete.BasicCompletion;
import org.fife.ui.autocomplete.DefaultCompletionProvider;

View File

@@ -1,4 +1,4 @@
package com.axis.innovators.box.gui;
package com.axis.innovators.box.window;
import com.axis.innovators.box.decompilation.gui.JavaPseudocodeGenerator;
import com.axis.innovators.box.util.AdvancedJFileChooser;

View File

@@ -1,4 +1,4 @@
package com.axis.innovators.box.gui;
package com.axis.innovators.box.window;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

View File

@@ -1,4 +1,4 @@
package com.axis.innovators.box.gui;
package com.axis.innovators.box.window;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

View File

@@ -0,0 +1,539 @@
package com.axis.innovators.box.window;
import com.axis.innovators.box.verification.OnlineVerification;
import com.axis.innovators.box.verification.UserTags;
import com.axis.innovators.box.verification.VerificationService;
import com.formdev.flatlaf.FlatDarculaLaf;
import javax.swing.*;
import javax.swing.border.LineBorder;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.atomic.AtomicReference;
/**
* 重构后的现代化单窗口登录/注册/找回密码界面(带平滑切换动画)
* 保留原有验证逻辑接口调用OnlineVerification / VerificationService
*
* 说明:
* - 单窗口JDialog内使用滑动动画切换视图仿微软登录体验
* - 所有子界面(登录/注册/找回密码)都在同一容器中切换,不再弹新窗口。
* - 按钮与输入框固定宽度,避免被挤压变形。
*
* 注意:需要 flatlaf 依赖以呈现更现代的外观。
*/
public class LoginWindow {
private static final AtomicReference<UserTags> loginResult = new AtomicReference<>(UserTags.None);
private final JDialog dialog;
private final JLayeredPane layeredPane;
private final int DIALOG_WIDTH = 460;
private final int DIALOG_HEIGHT = 560;
// 登录面板中的控件需要在类域以便访问
private JTextField loginEmailField;
private JPasswordField loginPasswordField;
public static UserTags createAndShow() throws InterruptedException, InvocationTargetException {
AtomicReference<UserTags> result = new AtomicReference<>(UserTags.None);
SwingUtilities.invokeAndWait(() -> {
LoginWindow window = new LoginWindow();
window.dialog.setVisible(true);
result.set(loginResult.get());
if (result.get() == UserTags.None) {
System.exit(0);
}
});
return result.get();
}
public LoginWindow() {
setupLookAndFeel();
dialog = new JDialog((Frame) null, "AXIS 安全认证", true);
dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
dialog.setSize(DIALOG_WIDTH, DIALOG_HEIGHT);
dialog.setResizable(false);
dialog.setLocationRelativeTo(null);
// 根容器:深色背景并居中卡片
JPanel root = new JPanel(new GridBagLayout());
root.setBackground(new Color(0x202225));
root.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
dialog.setContentPane(root);
// 卡片容器(居中)
JPanel cardWrapper = new JPanel(null) {
@Override
public Dimension getPreferredSize() {
return new Dimension(DIALOG_WIDTH - 40, DIALOG_HEIGHT - 40);
}
};
cardWrapper.setOpaque(false);
cardWrapper.setPreferredSize(new Dimension(DIALOG_WIDTH - 40, DIALOG_HEIGHT - 40));
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
root.add(cardWrapper, gbc);
// 分层面板用于动画
layeredPane = new JLayeredPane();
layeredPane.setBounds(0, 0, DIALOG_WIDTH - 40, DIALOG_HEIGHT - 40);
cardWrapper.add(layeredPane);
// 卡片背景(圆角)
JPanel backgroundCard = new JPanel();
backgroundCard.setBackground(new Color(0x2A2E31));
backgroundCard.setBorder(new RoundBorder(16, new Color(0x3A3F42)));
backgroundCard.setBounds(0, 0, layeredPane.getWidth(), layeredPane.getHeight());
backgroundCard.setLayout(null);
layeredPane.add(backgroundCard, Integer.valueOf(0));
// 创建三个面板宽度等于容器宽度初始将登录面板放置在0位置
JPanel loginPanel = buildLoginPanel();
JPanel registerPanel = buildRegisterPanel();
JPanel forgotPanel = buildForgotPanel();
int w = layeredPane.getWidth();
int h = layeredPane.getHeight();
loginPanel.setBounds(0, 0, w, h);
registerPanel.setBounds(w, 0, w, h); // 右侧预置
forgotPanel.setBounds(w * 2, 0, w, h);
layeredPane.add(loginPanel, Integer.valueOf(1));
layeredPane.add(registerPanel, Integer.valueOf(1));
layeredPane.add(forgotPanel, Integer.valueOf(1));
dialog.pack();
// ensure layered sizes match after pack
SwingUtilities.invokeLater(() -> {
layeredPane.setBounds(0, 0, cardWrapper.getWidth(), cardWrapper.getHeight());
backgroundCard.setBounds(0, 0, layeredPane.getWidth(), layeredPane.getHeight());
int nw = layeredPane.getWidth(), nh = layeredPane.getHeight();
loginPanel.setBounds(0, 0, nw, nh);
registerPanel.setBounds(nw, 0, nw, nh);
forgotPanel.setBounds(nw * 2, 0, nw, nh);
});
}
// 切换动画direction = 1 表示向左滑动进入下一页(当前 -> 右侧),-1 表示向右滑动进入上一页
private void slideTo(int targetIndex) {
Component[] comps = layeredPane.getComponents();
// 每个面板宽度
int w = layeredPane.getWidth();
// 当前最左边的x位置找到最左的那个主要面板
// 我们采用简单方式:目标面板应该位于 x = targetIndex * w 0,1,2
int targetX = -targetIndex * w; // 我们会将所有面板整体平移,使目标显示在 x=0
// 获取当前 offset (使用第一个面板的 x 来代表整体偏移)
int startOffset = 0;
// find current offset by checking bounds of first panel (assume index 0 is login)
if (comps.length > 0) {
startOffset = comps[0].getX();
}
int start = startOffset;
int end = targetX;
int duration = 300; // ms
int fps = 60;
int delay = 1000 / fps;
int steps = Math.max(1, duration / delay);
final int[] step = {0};
Timer timer = new Timer(delay, null);
timer.addActionListener((ActionEvent e) -> {
step[0]++;
double t = (double) step[0] / steps;
// ease in-out cubic
double tt = t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
int cur = (int) Math.round(start + (end - start) * tt);
// 平移所有在 layeredPane 中(除背景)组件
for (Component c : layeredPane.getComponents()) {
if (c instanceof JPanel && c.isVisible()) {
// 计算原始索引根据名字
String name = c.getName();
// 我们之前把panel放在 x = idx * w ; 现在把它设置为 idx*w + cur
int idx = 0;
if ("login".equals(name)) idx = 0;
else if ("register".equals(name)) idx = 1;
else if ("forgot".equals(name)) idx = 2;
c.setLocation(idx * w + cur, 0);
}
}
layeredPane.repaint();
if (step[0] >= steps) {
timer.stop();
}
});
timer.setInitialDelay(0);
timer.start();
}
private JPanel buildLoginPanel() {
JPanel p = new JPanel(null);
p.setOpaque(false);
p.setName("login");
int w = DIALOG_WIDTH - 40;
int h = DIALOG_HEIGHT - 40;
// 标题区
JLabel appTitle = new JLabel("AXIS");
appTitle.setFont(new Font("微软雅黑", Font.BOLD, 28));
appTitle.setForeground(Color.WHITE);
appTitle.setBounds(28, 20, w - 56, 36);
JLabel subtitle = new JLabel("安全认证 — 请登录以继续");
subtitle.setFont(new Font("微软雅黑", Font.PLAIN, 12));
subtitle.setForeground(new Color(0xA7AEB5));
subtitle.setBounds(28, 56, w - 56, 18);
p.add(appTitle);
p.add(subtitle);
// 卡片内控件起始 y
int startY = 96;
int fieldW = Math.min(360, w - 56);
int fieldX = (w - fieldW) / 2;
// Email
JLabel emailLabel = new JLabel("账号");
emailLabel.setForeground(new Color(0x99A0A7));
emailLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13));
emailLabel.setBounds(fieldX, startY, fieldW, 18);
loginEmailField = new JTextField();
styleInput(loginEmailField);
loginEmailField.setBounds(fieldX, startY + 22, fieldW, 44);
loginEmailField.putClientProperty("JTextField.placeholderText", "邮箱或手机号");
// Password
JLabel pwdLabel = new JLabel("密码");
pwdLabel.setForeground(new Color(0x99A0A7));
pwdLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13));
pwdLabel.setBounds(fieldX, startY + 22 + 44 + 12, fieldW, 18);
loginPasswordField = new JPasswordField();
styleInput(loginPasswordField);
loginPasswordField.setBounds(fieldX, startY + 22 + 44 + 12 + 20, fieldW - 48, 44);
loginPasswordField.putClientProperty("JTextField.placeholderText", "请输入密码");
// eye toggle
JToggleButton eyeBtn = new JToggleButton("显示");
eyeBtn.setFont(new Font("微软雅黑", Font.PLAIN, 12));
eyeBtn.setFocusable(false);
eyeBtn.setBorderPainted(false);
eyeBtn.setContentAreaFilled(true);
eyeBtn.setBackground(new Color(0x39424A));
eyeBtn.setForeground(Color.WHITE);
eyeBtn.setBounds(fieldX + fieldW - 44, startY + 22 + 44 + 12 + 20, 44, 44);
eyeBtn.addActionListener(e -> {
if (eyeBtn.isSelected()) loginPasswordField.setEchoChar((char) 0);
else loginPasswordField.setEchoChar('•');
});
// 登录按钮(占满宽度)
JButton loginBtn = new JButton("立即登录");
stylePrimaryButton(loginBtn);
loginBtn.setBounds(fieldX, startY + 22 + 44 + 12 + 20 + 44 + 22, fieldW, 48);
loginBtn.addActionListener(e -> doLogin());
// 链接区域(注册 / 忘记密码) — 点击切换到对应面板
JButton toRegister = createTextLink("注册账号");
toRegister.setBounds(fieldX, startY + 22 + 44 + 12 + 20 + 44 + 22 + 60, 120, 20);
toRegister.addActionListener(e -> slideTo(1));
JButton toForgot = createTextLink("忘记密码");
toForgot.setBounds(fieldX + fieldW - 120, startY + 22 + 44 + 12 + 20 + 44 + 22 + 60, 120, 20);
toForgot.addActionListener(e -> slideTo(2));
// footer
JLabel footer = new JLabel("使用你的 AXIS 账户进行登录。");
footer.setForeground(new Color(0x8F969C));
footer.setFont(new Font("微软雅黑", Font.PLAIN, 11));
footer.setBounds(fieldX, h - 44, fieldW, 18);
p.add(emailLabel);
p.add(loginEmailField);
p.add(pwdLabel);
p.add(loginPasswordField);
p.add(eyeBtn);
p.add(loginBtn);
p.add(toRegister);
p.add(toForgot);
p.add(footer);
return p;
}
private JPanel buildRegisterPanel() {
JPanel p = new JPanel(null);
p.setOpaque(false);
p.setName("register");
int w = DIALOG_WIDTH - 40;
int h = DIALOG_HEIGHT - 40;
JLabel title = new JLabel("创建账号");
title.setFont(new Font("微软雅黑", Font.BOLD, 24));
title.setForeground(Color.WHITE);
title.setBounds(28, 20, w - 56, 36);
JLabel desc = new JLabel("快速创建你的 AXIS 帐号");
desc.setFont(new Font("微软雅黑", Font.PLAIN, 12));
desc.setForeground(new Color(0xA7AEB5));
desc.setBounds(28, 56, w - 56, 18);
p.add(title);
p.add(desc);
int startY = 96;
int fieldW = Math.min(360, w - 56);
int fieldX = (w - fieldW) / 2;
// 用户名
JLabel nameLabel = new JLabel("用户名");
nameLabel.setForeground(new Color(0x99A0A7));
nameLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13));
nameLabel.setBounds(fieldX, startY, fieldW, 18);
JTextField nameField = new JTextField();
styleInput(nameField);
nameField.setBounds(fieldX, startY + 22, fieldW, 44);
// 邮箱
JLabel emailLabel = new JLabel("邮箱");
emailLabel.setForeground(new Color(0x99A0A7));
emailLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13));
emailLabel.setBounds(fieldX, startY + 22 + 44 + 12, fieldW, 18);
JTextField emailField = new JTextField();
styleInput(emailField);
emailField.setBounds(fieldX, startY + 22 + 44 + 12 + 20, fieldW, 44);
// 密码
JLabel pwdLabel = new JLabel("密码");
pwdLabel.setForeground(new Color(0x99A0A7));
pwdLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13));
pwdLabel.setBounds(fieldX, startY + 22 + 44 + 12 + 20 + 44 + 12, fieldW, 18);
JPasswordField pwdField = new JPasswordField();
styleInput(pwdField);
pwdField.setBounds(fieldX, startY + 22 + 44 + 12 + 20 + 44 + 12 + 20, fieldW, 44);
// 确认密码
JLabel confirmLabel = new JLabel("确认密码");
confirmLabel.setForeground(new Color(0x99A0A7));
confirmLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13));
confirmLabel.setBounds(fieldX, startY + 22 + 44 + 12 + 20 + 44 + 12 + 20 + 44 + 12, fieldW, 18);
JPasswordField confirmField = new JPasswordField();
styleInput(confirmField);
confirmField.setBounds(fieldX, startY + 22 + 44 + 12 + 20 + 44 + 12 + 20 + 44 + 12 + 20, fieldW, 44);
// 注册按钮
JButton regBtn = new JButton("创建账号");
stylePrimaryButton(regBtn);
regBtn.setBounds(fieldX, startY + 22 + 44 + 12 + 20 + 44 + 12 + 20 + 44 + 12 + 20 + 44 + 18, fieldW, 48);
regBtn.addActionListener(e -> {
String name = nameField.getText().trim();
String email = emailField.getText().trim();
String pwd = new String(pwdField.getPassword());
String confirm = new String(confirmField.getPassword());
if (name.isEmpty() || email.isEmpty() || pwd.isEmpty() || confirm.isEmpty()) {
JOptionPane.showMessageDialog(dialog, "请完整填写注册信息", "注册错误", JOptionPane.ERROR_MESSAGE);
return;
}
if (!pwd.equals(confirm)) {
JOptionPane.showMessageDialog(dialog, "两次输入的密码不一致", "注册错误", JOptionPane.ERROR_MESSAGE);
return;
}
boolean success = VerificationService.registerUser(name, email, pwd);
if (success) {
JOptionPane.showMessageDialog(dialog, "注册成功,请登录", "注册成功", JOptionPane.INFORMATION_MESSAGE);
slideTo(0); // 回到登录页面
} else {
JOptionPane.showMessageDialog(dialog, "注册失败,请检查信息", "注册错误", JOptionPane.ERROR_MESSAGE);
}
});
// 返回登录链接
JButton back = createTextLink("返回登录");
back.setBounds(fieldX, regBtn.getY() + regBtn.getHeight() + 12, 120, 20);
back.addActionListener(e -> slideTo(0));
p.add(nameLabel);
p.add(nameField);
p.add(emailLabel);
p.add(emailField);
p.add(pwdLabel);
p.add(pwdField);
p.add(confirmLabel);
p.add(confirmField);
p.add(regBtn);
p.add(back);
return p;
}
private JPanel buildForgotPanel() {
JPanel p = new JPanel(null);
p.setOpaque(false);
p.setName("forgot");
int w = DIALOG_WIDTH - 40;
int h = DIALOG_HEIGHT - 40;
JLabel title = new JLabel("找回密码");
title.setFont(new Font("微软雅黑", Font.BOLD, 24));
title.setForeground(Color.WHITE);
title.setBounds(28, 20, w - 56, 36);
JLabel desc = new JLabel("通过注册邮箱重置密码");
desc.setFont(new Font("微软雅黑", Font.PLAIN, 12));
desc.setForeground(new Color(0xA7AEB5));
desc.setBounds(28, 56, w - 56, 18);
p.add(title);
p.add(desc);
int startY = 110;
int fieldW = Math.min(360, w - 56);
int fieldX = (w - fieldW) / 2;
JLabel emailLabel = new JLabel("注册邮箱");
emailLabel.setForeground(new Color(0x99A0A7));
emailLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13));
emailLabel.setBounds(fieldX, startY, fieldW, 18);
JTextField emailField = new JTextField();
styleInput(emailField);
emailField.setBounds(fieldX, startY + 22, fieldW, 44);
JButton sendBtn = new JButton("发送重置邮件");
stylePrimaryButton(sendBtn);
sendBtn.setBounds(fieldX, startY + 22 + 44 + 22, fieldW, 48);
sendBtn.addActionListener(e -> {
String email = emailField.getText().trim();
if (email.isEmpty()) {
JOptionPane.showMessageDialog(dialog, "请输入注册邮箱", "错误", JOptionPane.ERROR_MESSAGE);
return;
}
if (VerificationService.sendPasswordReset(email)) {
JOptionPane.showMessageDialog(dialog, "重置邮件已发送,请查收", "成功", JOptionPane.INFORMATION_MESSAGE);
slideTo(0);
} else {
JOptionPane.showMessageDialog(dialog, "发送失败或邮箱未注册", "失败", JOptionPane.ERROR_MESSAGE);
}
});
JButton back = createTextLink("返回登录");
back.setBounds(fieldX, sendBtn.getY() + sendBtn.getHeight() + 12, 120, 20);
back.addActionListener(e -> slideTo(0));
p.add(emailLabel);
p.add(emailField);
p.add(sendBtn);
p.add(back);
return p;
}
private void doLogin() {
String email = loginEmailField.getText().trim();
String password = new String(loginPasswordField.getPassword()).trim();
if (email.isEmpty() || password.isEmpty()) {
JOptionPane.showMessageDialog(dialog, "请输入完整的登录信息", "验证错误", JOptionPane.ERROR_MESSAGE);
return;
}
OnlineVerification onlineVerification = OnlineVerification.validateLogin(email, password);
if (onlineVerification == null) {
String err = OnlineVerification.errorMessage != null && !OnlineVerification.errorMessage.trim().isEmpty()
? OnlineVerification.errorMessage
: "验证失败,请重试";
JOptionPane.showMessageDialog(dialog, err, "验证错误", JOptionPane.ERROR_MESSAGE);
return;
}
loginResult.set(VerificationService.determineUserType(onlineVerification));
dialog.dispose();
}
// 通用输入框样式
private void styleInput(JComponent comp) {
comp.setFont(new Font("微软雅黑", Font.PLAIN, 14));
comp.setBackground(new Color(0x2F3336));
comp.setForeground(new Color(0xE8ECEF));
comp.setBorder(BorderFactory.createCompoundBorder(
new RoundBorder(8, new Color(0x3A3F42)),
BorderFactory.createEmptyBorder(10, 12, 10, 12)
));
if (comp instanceof JTextComponent) ((JTextComponent) comp).setCaretColor(new Color(0x9AA0A6));
}
// 主要操作按钮样式(主色)
private void stylePrimaryButton(AbstractButton b) {
b.setFont(new Font("微软雅黑", Font.BOLD, 14));
b.setForeground(Color.WHITE);
b.setBackground(new Color(0x2B79D0));
b.setBorderPainted(false);
b.setFocusPainted(false);
b.setOpaque(true);
b.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
private JButton createTextLink(String text) {
JButton btn = new JButton(text);
btn.setFont(new Font("微软雅黑", Font.PLAIN, 12));
btn.setForeground(new Color(0x79A6FF));
btn.setBorderPainted(false);
btn.setContentAreaFilled(false);
btn.setFocusPainted(false);
btn.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
return btn;
}
private void setupLookAndFeel() {
try {
UIManager.setLookAndFeel(new FlatDarculaLaf());
UIManager.put("Component.arc", 12);
UIManager.put("TextComponent.arc", 12);
UIManager.put("Button.arc", 10);
UIManager.put("Panel.background", new Color(0x202225));
UIManager.put("TextComponent.background", new Color(0x2F3336));
UIManager.put("TextComponent.foreground", new Color(0xE8ECEF));
} catch (UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
}
// 圆角边框
private static class RoundBorder extends LineBorder {
private final int radius;
public RoundBorder(int radius, Color color) {
super(color, 1);
this.radius = radius;
}
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(lineColor);
g2.drawRoundRect(x, y, width - 1, height - 1, radius, radius);
g2.dispose();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
package com.axis.innovators.box.gui;
package com.axis.innovators.box.window;
import org.tzd.debug.ClassDebug;
import org.tzd.debug.GetInstance;
@@ -14,9 +14,7 @@ import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableRowSorter;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.*;
import java.awt.geom.Rectangle2D;
import java.lang.instrument.Instrumentation;
import java.lang.management.ManagementFactory;
@@ -30,7 +28,7 @@ import java.text.DecimalFormat;
import java.util.List;
import java.util.Timer;
import java.util.*;
import java.util.concurrent.CancellationException;
import java.util.concurrent.*;
public class MemoryAnalysisPanel extends JPanel {
private static final DecimalFormat MB_FORMAT = new DecimalFormat("#,##0.00");
@@ -92,6 +90,14 @@ public class MemoryAnalysisPanel extends JPanel {
private final JTable specificClassInstanceTable;
private final DefaultTableModel specificClassInstanceModel;
// 自动补全相关组件
private JPopupMenu autoCompletePopup;
private JList<String> autoCompleteList;
private DefaultListModel<String> autoCompleteModel;
private ScheduledExecutorService autoCompleteExecutor;
private final Map<String, List<String>> classCache = new ConcurrentHashMap<>();
private final Set<String> loadedPackages = ConcurrentHashMap.newKeySet();
// 特定类分析面板组件
private JPanel visualizationPanel;
private JLabel ratioLabel;
@@ -99,6 +105,10 @@ public class MemoryAnalysisPanel extends JPanel {
private JTextField instanceSearchField;
private TableRowSorter<DefaultTableModel> instanceSorter;
// 可调整大小的分割面板
private JSplitPane mainSplitPane;
private JSplitPane infoVisualizationSplitPane;
private JSplitPane visualizationInstanceSplitPane;
public MemoryAnalysisPanel() {
super(new BorderLayout());
@@ -280,6 +290,231 @@ public class MemoryAnalysisPanel extends JPanel {
// 初始刷新 - 只加载内存使用和内存池数据
showLoadingDialog("正在初始化内存数据...");
refreshInitialData();
// 初始化自动补全系统
initAutoCompleteSystem();
}
private void initAutoCompleteSystem() {
// 创建自动补全组件
autoCompleteModel = new DefaultListModel<>();
autoCompleteList = new JList<>(autoCompleteModel);
autoCompleteList.setFont(DebugWindow.MONOSPACE_FONT);
autoCompleteList.setBackground(new Color(50, 50, 50));
autoCompleteList.setForeground(FOREGROUND);
autoCompleteList.setSelectionBackground(ACCENT);
autoCompleteList.setSelectionForeground(FOREGROUND);
autoCompleteList.setFixedCellHeight(25);
autoCompletePopup = new JPopupMenu();
autoCompletePopup.setBorder(BorderFactory.createLineBorder(new Color(80, 80, 80)));
autoCompletePopup.add(new JScrollPane(autoCompleteList));
// 添加选择监听器
autoCompleteList.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 1) {
selectAutoCompleteItem();
}
}
});
// 添加键盘监听器
specificClassField.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
handleAutoCompleteKeyPress(e);
}
});
// 添加文档监听器
specificClassField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
scheduleAutoCompleteUpdate();
}
@Override
public void removeUpdate(DocumentEvent e) {
scheduleAutoCompleteUpdate();
}
@Override
public void changedUpdate(DocumentEvent e) {
scheduleAutoCompleteUpdate();
}
});
// 初始化线程池
autoCompleteExecutor = Executors.newSingleThreadScheduledExecutor();
}
private void scheduleAutoCompleteUpdate() {
// 取消之前的任务
autoCompleteExecutor.shutdownNow();
autoCompleteExecutor = Executors.newSingleThreadScheduledExecutor();
// 安排新任务
autoCompleteExecutor.schedule(() -> {
SwingUtilities.invokeLater(this::updateAutoCompleteSuggestions);
}, 300, TimeUnit.MILLISECONDS);
}
private void updateAutoCompleteSuggestions() {
String text = specificClassField.getText().trim();
if (text.isEmpty()) {
autoCompletePopup.setVisible(false);
return;
}
// 获取或加载建议
List<String> suggestions = getAutoCompleteSuggestions(text);
autoCompleteModel.clear();
if (suggestions.isEmpty()) {
autoCompletePopup.setVisible(false);
return;
}
// 添加到模型
for (String suggestion : suggestions) {
autoCompleteModel.addElement(suggestion);
}
// 显示弹出菜单
if (!autoCompletePopup.isVisible()) {
showAutoCompletePopup();
}
// 选择第一个项目
autoCompleteList.setSelectedIndex(0);
}
private List<String> getAutoCompleteSuggestions(String input) {
String packagePrefix = input.contains(".") ?
input.substring(0, input.lastIndexOf('.') + 1) :
"";
// 如果包名部分发生变化重新加载该包下的类
if (!classCache.containsKey(packagePrefix) || !loadedPackages.contains(packagePrefix)) {
loadPackageClasses(packagePrefix);
}
List<String> allClasses = classCache.getOrDefault(packagePrefix, new ArrayList<>());
String searchTerm = input.toLowerCase();
// 过滤匹配的类
List<String> suggestions = new ArrayList<>();
for (String className : allClasses) {
if (className.toLowerCase().contains(searchTerm)) {
suggestions.add(className);
}
// 限制数量
if (suggestions.size() >= 100) {
break;
}
}
// 按匹配度排序
suggestions.sort((s1, s2) -> {
int pos1 = s1.toLowerCase().indexOf(searchTerm);
int pos2 = s2.toLowerCase().indexOf(searchTerm);
return Integer.compare(pos1, pos2);
});
return suggestions;
}
private void loadPackageClasses(String packageName) {
// 对于根包的特殊处理
if (packageName.isEmpty()) {
packageName = "";
}
List<String> classes = new ArrayList<>();
Class<?>[] allClasses = instrumentation.getAllLoadedClasses();
for (Class<?> clazz : allClasses) {
String className = clazz.getName();
// 只处理包匹配的类
if (packageName.isEmpty() || className.startsWith(packageName)) {
classes.add(className);
}
}
// 缓存结果
classCache.put(packageName, classes);
loadedPackages.add(packageName);
}
private void showAutoCompletePopup() {
if (specificClassField.isShowing()) {
// 计算弹出位置
Point location = specificClassField.getLocationOnScreen();
location.y += specificClassField.getHeight();
// 设置弹出大小
int width = Math.max(specificClassField.getWidth(), 400);
int height = Math.min(autoCompleteModel.size() * 25, 300);
autoCompletePopup.setPopupSize(width, height);
// 显示弹出菜单
autoCompletePopup.show(specificClassField, 0, specificClassField.getHeight());
}
}
private void handleAutoCompleteKeyPress(KeyEvent e) {
if (!autoCompletePopup.isVisible()) return;
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
moveSelection(-1);
e.consume();
break;
case KeyEvent.VK_DOWN:
moveSelection(1);
e.consume();
break;
case KeyEvent.VK_ENTER:
selectAutoCompleteItem();
e.consume();
break;
case KeyEvent.VK_ESCAPE:
autoCompletePopup.setVisible(false);
e.consume();
break;
case KeyEvent.VK_TAB:
if (autoCompleteList.getSelectedIndex() >= 0) {
selectAutoCompleteItem();
e.consume();
}
break;
}
}
private void moveSelection(int direction) {
int selected = autoCompleteList.getSelectedIndex();
int newIndex = selected + direction;
if (newIndex >= 0 && newIndex < autoCompleteModel.size()) {
autoCompleteList.setSelectedIndex(newIndex);
autoCompleteList.ensureIndexIsVisible(newIndex);
}
}
private void selectAutoCompleteItem() {
String selected = autoCompleteList.getSelectedValue();
if (selected != null) {
specificClassField.setText(selected);
autoCompletePopup.setVisible(false);
specificClassField.requestFocus();
// 将光标移动到文本末尾
specificClassField.setCaretPosition(selected.length());
}
}
private JPanel createSpecificClassAnalysisPanel() {
@@ -316,41 +551,44 @@ public class MemoryAnalysisPanel extends JPanel {
inputPanel.add(classLabel, BorderLayout.WEST);
inputPanel.add(fieldPanel, BorderLayout.CENTER);
// 主内容面板 (使用网格袋布局)
JPanel mainContentPanel = new JPanel(new GridBagLayout());
mainContentPanel.setBackground(BACKGROUND);
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1.0;
gbc.insets = new Insets(5, 5, 5, 5);
// 使用分割面板替代网格袋布局
mainSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
mainSplitPane.setDividerLocation(0.4); // 初始比例为40%
mainSplitPane.setResizeWeight(0.4);
mainSplitPane.setBorder(BorderFactory.createEmptyBorder());
mainSplitPane.setContinuousLayout(true);
mainSplitPane.setDividerSize(5);
mainSplitPane.setBackground(BACKGROUND);
// 类信息面板
// 上半部分类信息面板
JPanel infoPanel = createClassInfoPanel();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridwidth = 2;
gbc.weighty = 0.4;
mainContentPanel.add(infoPanel, gbc);
infoPanel.setMinimumSize(new Dimension(100, 100));
// 下半部分可视化+实例列表
JSplitPane bottomSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
bottomSplitPane.setDividerLocation(0.3); // 初始比例为30%
bottomSplitPane.setResizeWeight(0.3);
bottomSplitPane.setContinuousLayout(true);
bottomSplitPane.setDividerSize(5);
bottomSplitPane.setBackground(BACKGROUND);
// 可视化面板
visualizationPanel = createVisualizationPanel();
gbc.gridx = 0;
gbc.gridy = 1;
gbc.gridwidth = 1;
gbc.weighty = 0.1;
mainContentPanel.add(visualizationPanel, gbc);
visualizationPanel.setMinimumSize(new Dimension(100, 100));
// 实例列表面板
JPanel instancesPanel = createInstancesPanel();
gbc.gridx = 1;
gbc.gridy = 1;
gbc.gridwidth = 1;
gbc.weighty = 0.5;
mainContentPanel.add(instancesPanel, gbc);
instancesPanel.setMinimumSize(new Dimension(100, 100));
bottomSplitPane.setLeftComponent(visualizationPanel);
bottomSplitPane.setRightComponent(instancesPanel);
mainSplitPane.setTopComponent(infoPanel);
mainSplitPane.setBottomComponent(bottomSplitPane);
// 添加主内容面板到中心
panel.add(inputPanel, BorderLayout.NORTH);
panel.add(mainContentPanel, BorderLayout.CENTER);
panel.add(mainSplitPane, BorderLayout.CENTER);
return panel;
}

View File

@@ -1,4 +1,4 @@
package com.axis.innovators.box.gui;
package com.axis.innovators.box.window;
import com.axis.innovators.box.AxisInnovatorsBox;

View File

@@ -0,0 +1,462 @@
package com.axis.innovators.box.window;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.HashMap;
import java.util.Map;
/**
* 启动窗口的任务系统(已改造为现代流畅动画视觉效果)
* 注意保留了原有对外方法和签名updateMainProgress/updateSubProgress/setTotalTasks/close
* 作者: tzdwindows 7UI 改造版)
*/
public class ProgressBarManager extends WindowsJDialog {
private JFrame loadingFrame;
private SmoothProgressBar mainProgressBar;
private SmoothProgressBar subProgressBar;
private JLabel statusLabel;
private JLabel timeLabel;
private long startTime;
private int totalTasks;
private int completedTasks;
private Map<String, Integer> subTasks = new HashMap<>();
// 动画计时器60FPS
private Timer animationTimer;
// 视觉参数
private Color accentColor = new Color(0x00C2FF); // 科技感青蓝
private Font uiFont;
public ProgressBarManager(String title, int totalTasks) {
this.totalTasks = Math.max(1, totalTasks);
this.completedTasks = 0;
this.startTime = System.currentTimeMillis();
// 尝试设置现代中文友好字体Windows 常见)
try {
uiFont = new Font("Microsoft YaHei UI", Font.PLAIN, 13);
// 若系统无该字体则 fallback
if (!uiFont.getFamily().toLowerCase().contains("microsoft") &&
!uiFont.getFamily().toLowerCase().contains("yahei")) {
uiFont = new Font("Segoe UI", Font.PLAIN, 13);
}
} catch (Throwable t) {
uiFont = new Font(Font.SANS_SERIF, Font.PLAIN, 13);
}
loadingFrame = new JFrame(title);
loadingFrame.setUndecorated(true);
loadingFrame.setBackground(new Color(0, 0, 0, 0)); // 允许圆角透明背景
loadingFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
loadingFrame.setSize(520, 300);
loadingFrame.setLocationRelativeTo(null);
loadingFrame.setIconImage(LoadIcon.loadIcon("logo.png", 64).getImage());
// 主容器(带动画背景和圆角卡片)
AnimatedBackgroundPanel root = new AnimatedBackgroundPanel();
root.setLayout(new GridBagLayout());
root.setBorder(BorderFactory.createEmptyBorder(18, 18, 18, 18));
// 卡片面板
JPanel card = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 卡片阴影(简单外发光)
int arc = 18;
int w = getWidth();
int h = getHeight();
// 背景渐变
GradientPaint gp = new GradientPaint(0, 0, new Color(20, 22, 25, 230),
0, h, new Color(14, 16, 19, 230));
g2.setPaint(gp);
// 圆角矩形
RoundRectangle2D rr = new RoundRectangle2D.Float(6, 6, w - 12, h - 12, arc, arc);
g2.fill(rr);
// 细微边框
g2.setStroke(new BasicStroke(1f));
g2.setColor(new Color(255, 255, 255, 10));
g2.draw(rr);
g2.dispose();
super.paintComponent(g);
}
};
card.setOpaque(false);
card.setLayout(new BorderLayout(12, 12));
card.setPreferredSize(new Dimension(480, 240));
card.setBorder(BorderFactory.createEmptyBorder(14, 14, 14, 14));
// 顶部 logo + 标题
JPanel top = new JPanel(new BorderLayout());
top.setOpaque(false);
JLabel logoLabel = new JLabel(LoadIcon.loadIcon("logo.png", 48));
logoLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 12));
JLabel titleLabel = new JLabel(title);
titleLabel.setFont(uiFont.deriveFont(Font.BOLD, 18f));
titleLabel.setForeground(Color.WHITE);
top.add(logoLabel, BorderLayout.WEST);
top.add(titleLabel, BorderLayout.CENTER);
// 中间进度区
JPanel center = new JPanel(new GridBagLayout());
center.setOpaque(false);
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
c.weightx = 1;
c.fill = GridBagConstraints.HORIZONTAL;
mainProgressBar = new SmoothProgressBar(0);
mainProgressBar.setPreferredSize(new Dimension(420, 26));
mainProgressBar.setAccentColor(accentColor);
subProgressBar = new SmoothProgressBar(0);
subProgressBar.setPreferredSize(new Dimension(420, 18));
subProgressBar.setAccentColor(new Color(0x6EE7FF));
subProgressBar.setShowStripe(true);
center.add(mainProgressBar, c);
c.gridy++;
c.insets = new Insets(8, 0, 0, 0);
center.add(subProgressBar, c);
// 底部文本
JPanel bottom = new JPanel(new BorderLayout());
bottom.setOpaque(false);
statusLabel = new JLabel("Initializing...", SwingConstants.LEFT);
statusLabel.setFont(uiFont.deriveFont(Font.PLAIN, 12f));
statusLabel.setForeground(new Color(220, 230, 240));
timeLabel = new JLabel("Elapsed: 0s", SwingConstants.RIGHT);
timeLabel.setFont(uiFont.deriveFont(Font.PLAIN, 12f));
timeLabel.setForeground(new Color(180, 200, 215));
bottom.add(statusLabel, BorderLayout.WEST);
bottom.add(timeLabel, BorderLayout.EAST);
bottom.setBorder(BorderFactory.createEmptyBorder(8, 2, 2, 2));
card.add(top, BorderLayout.NORTH);
card.add(center, BorderLayout.CENTER);
card.add(bottom, BorderLayout.SOUTH);
root.add(card);
loadingFrame.setContentPane(root);
// 拖动窗口支持(在无边框下)
WindowDragger.makeDraggable(loadingFrame, card);
// 启动动画定时器
animationTimer = new Timer(1000 / 60, e -> {
boolean repaintNeeded = false;
if (mainProgressBar.animateStep()) repaintNeeded = true;
if (subProgressBar.animateStep()) repaintNeeded = true;
root.advanceAnimation();
updateTimeLabel();
if (repaintNeeded) {
root.repaint();
} else {
// 仍需刷新背景动画
root.repaint();
}
});
animationTimer.start();
loadingFrame.setVisible(true);
// 防止用户误操作关闭(保持原行为)
loadingFrame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
// DO NOTHING
}
});
}
/**
* 更新主任务进度(对外接口保持不变)
* @param completedTasks 已完成的主任务数量
*/
public void updateMainProgress(int completedTasks) {
this.completedTasks = completedTasks;
double progress = (completedTasks / (double) Math.max(1, totalTasks)) * 100.0;
if (progress < 0) progress = 0;
if (progress > 100) progress = 100;
mainProgressBar.setTarget((int) Math.round(progress));
statusLabel.setText("主任务: " + completedTasks + " / " + totalTasks + " (" + (int) progress + "%)");
}
/**
* 更新子任务进度(对外接口保持不变)
* @param subTaskName 子任务名称
* @param subTaskCompleted 已完成的子任务数量
* @param subTaskTotal 子任务总数
*/
public void updateSubProgress(String subTaskName, int subTaskCompleted, int subTaskTotal) {
if (subTaskTotal <= 0) subTaskTotal = 1;
subTasks.put(subTaskName, subTaskCompleted);
double progress = (subTaskCompleted / (double) subTaskTotal) * 100.0;
if (progress < 0) progress = 0;
if (progress > 100) progress = 100;
subProgressBar.setTarget((int) Math.round(progress));
subProgressBar.setLabel(subTaskName);
}
/**
* 更新总任务数
*/
public void setTotalTasks(int totalTasks) {
this.totalTasks = Math.max(1, totalTasks);
}
/**
* 关闭加载窗口
*/
public void close() {
if (animationTimer != null && animationTimer.isRunning()) {
animationTimer.stop();
}
loadingFrame.dispose();
}
/**
* 更新时间标签
*/
private void updateTimeLabel() {
long elapsedTime = (System.currentTimeMillis() - startTime) / 1000;
long hours = elapsedTime / 3600;
long mins = (elapsedTime % 3600) / 60;
long secs = elapsedTime % 60;
if (hours > 0) {
timeLabel.setText(String.format("Elapsed: %dh %02dm %02ds", hours, mins, secs));
} else if (mins > 0) {
timeLabel.setText(String.format("Elapsed: %dm %02ds", mins, secs));
} else {
timeLabel.setText(String.format("Elapsed: %ds", secs));
}
}
// --------------------------
// 内部类:平滑进度条(支持插值动画、条纹、标签)
// --------------------------
private static class SmoothProgressBar extends JComponent {
private int target = 0;
private double displayed = 0.0;
private int height = 20;
private Color base = new Color(255, 255, 255, 18);
private Color fill = new Color(0x00C2FF);
private String label = "";
private boolean showStripe = false;
private Color stripeColor = new Color(255, 255, 255, 30);
private double stripeOffset = 0.0;
public SmoothProgressBar(int initial) {
this.target = Math.max(0, Math.min(100, initial));
this.displayed = this.target;
setOpaque(false);
setPreferredSize(new Dimension(200, height));
}
public void setAccentColor(Color c) {
this.fill = c;
}
public void setLabel(String label) {
this.label = label;
}
public void setShowStripe(boolean v) {
this.showStripe = v;
}
public void setTarget(int t) {
t = Math.max(0, Math.min(100, t));
this.target = t;
}
/**
* 每帧推进插值,返回是否需要重绘
*/
public boolean animateStep() {
// 平滑插值(阻尼)
double diff = target - displayed;
if (Math.abs(diff) < 0.02) {
displayed = target;
} else {
displayed += diff * 0.18; // 阻尼因子(调整流畅度)
}
// 条纹动画
if (showStripe) {
stripeOffset += 1.8;
if (stripeOffset > 60) stripeOffset = 0;
}
// 是否需要重绘
return Math.abs(diff) > 0.001 || showStripe;
}
@Override
protected void paintComponent(Graphics g) {
int w = getWidth();
int h = getHeight();
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 背景轨道
RoundRectangle2D bg = new RoundRectangle2D.Float(0, 0, w, h, h, h);
g2.setColor(base);
g2.fill(bg);
// 阴影(内阴影模拟)
g2.setColor(new Color(0, 0, 0, 30));
g2.setStroke(new BasicStroke(1f));
g2.draw(bg);
// 填充(渐变)
int fillW = (int) Math.round((displayed / 100.0) * w);
if (fillW > 0) {
GradientPaint gp = new GradientPaint(0, 0, fill.brighter(), w, 0, fill.darker());
RoundRectangle2D fg = new RoundRectangle2D.Float(0, 0, fillW, h, h, h);
g2.setPaint(gp);
g2.fill(fg);
// 发光边缘
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.25f));
g2.setColor(fill);
g2.fill(new RoundRectangle2D.Float(0, -h / 3f, fillW, h + h / 3f, h, h));
g2.setComposite(AlphaComposite.SrcOver);
}
// 条纹效果
if (showStripe && fillW > 6) {
Shape clip = g2.getClip();
g2.setClip(new RoundRectangle2D.Float(0, 0, fillW, h, h, h));
int stripeW = 18;
for (int x = -stripeW * 2; x < w + stripeW * 2; x += stripeW) {
int sx = (int) (x + stripeOffset);
Polygon p = new Polygon();
p.addPoint(sx, 0);
p.addPoint(sx + stripeW, 0);
p.addPoint(sx + stripeW - 8, h);
p.addPoint(sx - 8, h);
g2.setColor(stripeColor);
g2.fill(p);
}
g2.setClip(clip);
}
// 文本显示(居中)
String text;
if (label != null && !label.isEmpty()) {
text = label + " " + Math.round(displayed) + "%";
} else {
text = Math.round(displayed) + "%";
}
g2.setFont(new Font(Font.SANS_SERIF, Font.BOLD, Math.max(11, h - 6)));
FontMetrics fm = g2.getFontMetrics();
int tx = (w - fm.stringWidth(text)) / 2;
int ty = (h + fm.getAscent() - fm.getDescent()) / 2;
g2.setColor(new Color(255, 255, 255, 210));
g2.drawString(text, tx, ty);
g2.dispose();
}
}
// --------------------------
// 内部类:带动画效果的背景面板(流动扫描线 + 颗粒/渐变)
// --------------------------
private class AnimatedBackgroundPanel extends JPanel {
private double offset = 0;
private double particlePhase = 0;
public AnimatedBackgroundPanel() {
setOpaque(false);
}
public void advanceAnimation() {
offset += 0.9;
if (offset > 2000) offset = 0;
particlePhase += 0.02;
}
@Override
protected void paintComponent(Graphics g) {
int w = getWidth();
int h = getHeight();
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 背景渐变(深色)
Paint p = new GradientPaint(0, 0, new Color(8, 10, 12), w, h, new Color(18, 20, 24));
g2.setPaint(p);
g2.fillRect(0, 0, w, h);
// 斜向扫描线(细微)
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.06f));
g2.setColor(Color.WHITE);
for (int i = -200; i < w + h; i += 40) {
int x1 = i + (int) offset;
int y1 = 0;
int x2 = i - h + (int) offset;
int y2 = h;
g2.setStroke(new BasicStroke(2f));
g2.drawLine(x1, y1, x2, y2);
}
g2.setComposite(AlphaComposite.SrcOver);
// 轻微颗粒(科技光斑)
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.08f));
for (int i = 0; i < 10; i++) {
float px = (float) ((Math.sin(particlePhase + i) + 1) / 2.0 * w);
float py = (float) ((Math.cos(particlePhase * 0.7 + i * 0.3) + 1) / 2.0 * h);
int size = 6 + (i % 3) * 4;
g2.fillOval((int) px, (int) py, size, size);
}
g2.setComposite(AlphaComposite.SrcOver);
g2.dispose();
super.paintComponent(g);
}
}
// --------------------------
// 工具:使无边框窗口可拖动
// --------------------------
private static class WindowDragger {
public static void makeDraggable(Window wnd, Component dragRegion) {
final Point[] mouseDown = {null};
dragRegion.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
mouseDown[0] = e.getPoint();
}
@Override
public void mouseReleased(MouseEvent e) {
mouseDown[0] = null;
}
});
dragRegion.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
if (mouseDown[0] != null) {
Point curr = e.getLocationOnScreen();
wnd.setLocation(curr.x - mouseDown[0].x, curr.y - mouseDown[0].y);
}
}
});
}
}
}

View File

@@ -0,0 +1,29 @@
package com.axis.innovators.box.window;
import javax.swing.*;
import java.awt.*;
/**
* @author tzdwindows 7
*/
public class ThemeColors {
// 工具方法:使颜色变暗 (factor: 0~10.2表示变暗20%)
public static Color darken(Color color, float factor) {
return new Color(
Math.max((int)(color.getRed() * (1 - factor)), 0),
Math.max((int)(color.getGreen() * (1 - factor)), 0),
Math.max((int)(color.getBlue() * (1 - factor)), 0),
color.getAlpha()
);
}
// 工具方法:使颜色变亮 (factor: 0~10.2表示变亮20%)
public static Color brighten(Color color, float factor) {
return new Color(
Math.min((int)(color.getRed() * (1 + factor)), 255),
Math.min((int)(color.getGreen() * (1 + factor)), 255),
Math.min((int)(color.getBlue() * (1 + factor)), 255),
color.getAlpha()
);
}
}

View File

@@ -1,7 +1,8 @@
package com.axis.innovators.box.gui;
package com.axis.innovators.box.window;
import com.axis.innovators.box.AxisInnovatorsBox;
import com.axis.innovators.box.register.LanguageManager;
import com.axis.innovators.box.register.RegistrationTopic;
import javax.swing.*;
import java.awt.*;
@@ -9,6 +10,7 @@ import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
/**
* 窗口
* @author tzdwindows 7
*/
public class WindowsJDialog extends JDialog {
@@ -48,4 +50,21 @@ public class WindowsJDialog extends JDialog {
AxisInnovatorsBox.getMain().clearWindow(this);
super.dispose();
}
/**
* 检测当前窗口的主题是否处于暗黑模式
* @return true 处于暗黑模式false 处于浅色模式
*/
public boolean isTopicDarkMode(){
AxisInnovatorsBox axisInnovatorsBox = AxisInnovatorsBox.getMain();
RegistrationTopic registrationTopic = axisInnovatorsBox.getRegistrationTopic();
return registrationTopic.isDarkMode();
}
/**
* 在当前窗口中更新主题
*/
public void updateTheme() {
SwingUtilities.updateComponentTreeUI(this);
}
}

View File

@@ -1,4 +1,4 @@
package com.axis.innovators.box.gui.renderer;
package com.axis.innovators.box.window.renderer;
import javax.swing.*;
import javax.swing.border.AbstractBorder;

View File

@@ -0,0 +1,4 @@
package org.tzd.explorer;
public class DesktopIconRenderer {
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -30,7 +30,7 @@
</RollingFile>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="[%t] [%d{yyyy-MM-dd HH:mm:ss}] [%-5level] %msg%n%throwable"/>
<PatternLayout pattern="[%t] [%d{yyyy-MM-dd HH:mm:ss}] [%level] [%logger-%method()] %msg%n%throwable"/>
</Console>
</Appenders>

View File

@@ -1,4 +0,0 @@
#Updated configuration
#Fri Mar 07 17:43:24 CST 2025
password=safasf
verification=aasfsaf