From 8e93eedf31b4231a8172861402e69f4c67425387 Mon Sep 17 00:00:00 2001 From: Enaium Date: Thu, 22 Sep 2022 13:15:44 +0800 Subject: [PATCH 01/49] Update build.gradle --- build.gradle | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 294cd99..8e993a3 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ plugins { } group 'cn.enaium' -version '1.3.0' +version '1.4.0' sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8 @@ -50,7 +50,6 @@ dependencies { implementation 'org.benf:cfr:0.152' implementation 'com.github.mstrobel.procyon:procyon-decompiler:v0.6.0' implementation 'org.quiltmc:quiltflower:1.8.1' - implementation 'org.javassist:javassist:3.29.1-GA' implementation 'com.google.code.gson:gson:2.9.0' implementation 'org.tinylog:tinylog:1.3.6' implementation 'com.github.FabricMC:mapping-io:597f0722d6' @@ -70,7 +69,6 @@ shadowJar { include(dependency('org.ow2.asm:.*')) include(dependency('org.benf:cfr')) include(dependency('com.github.mstrobel.procyon:procyon-decompiler')) - include(dependency('org.javassist:javassist')) include(dependency('com.google.code.gson:gson')) include(dependency('org.tinylog:.*')) include(dependency('org.quiltmc:quiltflower')) From d0ba29a0fc038149d601ba6709fd1f1c9da7e2a6 Mon Sep 17 00:00:00 2001 From: Enaium Date: Thu, 22 Sep 2022 13:15:56 +0800 Subject: [PATCH 02/49] compile --- .../java/cn/enaium/joe/compiler/Compiler.java | 78 +++++++++++++++++++ .../joe/compiler/VirtualJavaFileObject.java | 52 +++++++++++++ .../tab/classes/ASMifierTablePanel.java | 65 +++++++++------- .../java/cn/enaium/joe/util/MessageUtil.java | 18 ++++- .../java/cn/enaium/joe/asm/VisitorTest.java | 35 ++++----- .../cn/enaium/joe/compiler/CompilerTest.java | 44 +++++++++++ 6 files changed, 240 insertions(+), 52 deletions(-) create mode 100644 src/main/java/cn/enaium/joe/compiler/Compiler.java create mode 100644 src/main/java/cn/enaium/joe/compiler/VirtualJavaFileObject.java create mode 100644 src/test/java/cn/enaium/joe/compiler/CompilerTest.java diff --git a/src/main/java/cn/enaium/joe/compiler/Compiler.java b/src/main/java/cn/enaium/joe/compiler/Compiler.java new file mode 100644 index 0000000..e7ad2e5 --- /dev/null +++ b/src/main/java/cn/enaium/joe/compiler/Compiler.java @@ -0,0 +1,78 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.compiler; + +import javax.tools.*; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author Enaium + * @since 1.4.0 + */ +public class Compiler { + private final Map javaFileObjectMap = new HashMap<>(); + + private DiagnosticListener listener; + + public void addSource(String name, String content) { + javaFileObjectMap.put(name, new VirtualJavaFileObject(name, content)); + } + + public Map getClasses() { + return javaFileObjectMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, v -> v.getValue().getBytecode())); + } + + @SuppressWarnings("unchecked") + public boolean compile() { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + VirtualFileManager fileManager = new VirtualFileManager(compiler.getStandardFileManager(null, null, StandardCharsets.UTF_8)); + try { + JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, ((DiagnosticListener) (Object) listener), null, null, javaFileObjectMap.values()); + Boolean b = task.call(); + return b != null && b; + } catch (Exception e) { + return false; + } + } + + public void setListener(DiagnosticListener listener) { + this.listener = listener; + } + + private final class VirtualFileManager extends ForwardingJavaFileManager { + public VirtualFileManager(JavaFileManager fileManager) { + super(fileManager); + } + + @Override + public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException { + if (JavaFileObject.Kind.CLASS == kind) { + VirtualJavaFileObject virtualJavaFileObject = new VirtualJavaFileObject(className, null); + System.out.println(className); + javaFileObjectMap.put(className, virtualJavaFileObject); + return virtualJavaFileObject; + } else { + return super.getJavaFileForOutput(location, className, kind, sibling); + } + } + } +} diff --git a/src/main/java/cn/enaium/joe/compiler/VirtualJavaFileObject.java b/src/main/java/cn/enaium/joe/compiler/VirtualJavaFileObject.java new file mode 100644 index 0000000..0e1e2b8 --- /dev/null +++ b/src/main/java/cn/enaium/joe/compiler/VirtualJavaFileObject.java @@ -0,0 +1,52 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.compiler; + +import javax.tools.SimpleJavaFileObject; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.URI; + +/** + * @author Enaium + * @since 1.4.0 + */ +public class VirtualJavaFileObject extends SimpleJavaFileObject { + + private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + private final String content; + + protected VirtualJavaFileObject(String className, String content) { + super(URI.create("string:///" + className.replace(".", "/") + Kind.SOURCE.extension), Kind.SOURCE); + this.content = content; + } + + public byte[] getBytecode() { + return outputStream.toByteArray(); + } + + @Override + public ByteArrayOutputStream openOutputStream() { + return outputStream; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return content; + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java index be1e5cb..f091bc8 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java @@ -16,24 +16,20 @@ package cn.enaium.joe.gui.panel.file.tabbed.tab.classes; -import cn.enaium.joe.JavaOctetEditor; +import cn.enaium.joe.compiler.Compiler; import cn.enaium.joe.gui.panel.CodeAreaPanel; import cn.enaium.joe.util.*; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.CtMethod; -import javassist.Loader; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.util.ASMifier; import org.objectweb.asm.util.TraceClassVisitor; +import org.pmw.tinylog.Logger; import javax.swing.*; +import javax.tools.Diagnostic; import java.awt.*; -import java.awt.event.ActionEvent; import java.awt.event.InputEvent; -import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.io.PrintWriter; import java.io.StringWriter; @@ -48,28 +44,39 @@ public ASMifierTablePanel(ClassNode classNode) { CodeAreaPanel codeAreaPanel = new CodeAreaPanel() {{ KeyStrokeUtil.register(getTextArea(), KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK), () -> { try { - StringWriter stringWriter = new StringWriter(); - ClassReader classReader = new ClassReader(this.getClass().getName()); - classReader.accept(new TraceClassVisitor(null, new ASMifier(), new PrintWriter(stringWriter)), 0); - ClassPool classPool = new ClassPool(); - classPool.appendSystemPath(); - classPool.importPackage("org.objectweb.asm.AnnotationVisitor"); - classPool.importPackage("org.objectweb.asm.Attribute"); - classPool.importPackage("org.objectweb.asm.ClassReader"); - classPool.importPackage("org.objectweb.asm.ClassWriter"); - classPool.importPackage("org.objectweb.asm.ConstantDynamic"); - classPool.importPackage("org.objectweb.asm.FieldVisitor"); - classPool.importPackage("org.objectweb.asm.Handle"); - classPool.importPackage("org.objectweb.asm.Label"); - classPool.importPackage("org.objectweb.asm.MethodVisitor"); - classPool.importPackage("org.objectweb.asm.Opcodes"); - classPool.importPackage("org.objectweb.asm.RecordComponentVisitor"); - classPool.importPackage("org.objectweb.asm.Type"); - classPool.importPackage("org.objectweb.asm.TypePath"); - CtClass ctClass = classPool.makeClass(ASMifier.class.getSimpleName()); - ctClass.addInterface(classPool.get("org.objectweb.asm.Opcodes")); - ctClass.addMethod(CtMethod.make("public static byte[] dump() throws Exception {" + getTextArea().getText() + "return classWriter.toByteArray();}", ctClass)); - byte[] dumps = (byte[]) new Loader(classPool).loadClass(ASMifier.class.getSimpleName()).getMethod("dump").invoke(null); + String stringBuilder = "import org.objectweb.asm.AnnotationVisitor;" + + "import org.objectweb.asm.Attribute;" + + "import org.objectweb.asm.ClassReader;" + + "import org.objectweb.asm.ClassWriter;" + + "import org.objectweb.asm.ConstantDynamic;" + + "import org.objectweb.asm.FieldVisitor;" + + "import org.objectweb.asm.Handle;" + + "import org.objectweb.asm.Label;" + + "import org.objectweb.asm.MethodVisitor;" + + "import org.objectweb.asm.Opcodes;" + + "import org.objectweb.asm.RecordComponentVisitor;" + + "import org.objectweb.asm.Type;" + + "import org.objectweb.asm.TypePath;" + + "public class" + " " + ASMifier.class.getSimpleName() + " " + "implements Opcodes" + + "{" + + "public static byte[] dump() throws Exception {" + + getTextArea().getText() + + "return classWriter.toByteArray();" + + "}" + + "}"; + Compiler compiler = new Compiler(); + compiler.addSource(ASMifier.class.getSimpleName(), stringBuilder); + compiler.compile(); + + ClassLoader loader = new ClassLoader() { + @Override + protected Class findClass(String name) { + byte[] bytes = compiler.getClasses().get(ASMifier.class.getSimpleName()); + return defineClass(name, bytes, 0, bytes.length); + } + }; + + byte[] dumps = (byte[]) loader.loadClass(ASMifier.class.getSimpleName()).getMethod("dump").invoke(null); ClassNode newClassNode = new ClassNode(); new ClassReader(dumps).accept(newClassNode, ClassReader.EXPAND_FRAMES); ReflectUtil.setAll(classNode, newClassNode); diff --git a/src/main/java/cn/enaium/joe/util/MessageUtil.java b/src/main/java/cn/enaium/joe/util/MessageUtil.java index f3947bb..1b46275 100644 --- a/src/main/java/cn/enaium/joe/util/MessageUtil.java +++ b/src/main/java/cn/enaium/joe/util/MessageUtil.java @@ -16,10 +16,17 @@ package cn.enaium.joe.util; +import cn.enaium.joe.gui.panel.BorderPanel; import cn.enaium.joe.gui.panel.confirm.ConfirmPanel; +import org.benf.cfr.reader.util.StringUtils; import org.pmw.tinylog.Logger; import javax.swing.*; +import java.awt.*; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Arrays; +import java.util.stream.Collectors; /** * @author Enaium @@ -28,8 +35,15 @@ public class MessageUtil { public static void error(Throwable e) { - Logger.error(e); - JOptionPane.showMessageDialog(null, e.toString(), LangUtil.i18n("error"), JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(null, new BorderPanel() {{ + setTop(new JLabel(e.toString())); + setCenter(new JScrollPane(new JTextArea() {{ + StringWriter out = new StringWriter(); + e.printStackTrace(new PrintWriter(out)); + setText(out.toString()); + setEditable(false); + }})); + }}, LangUtil.i18n("error"), JOptionPane.ERROR_MESSAGE); } public static void confirm(Object message, String title, Runnable yes, Runnable no) { diff --git a/src/test/java/cn/enaium/joe/asm/VisitorTest.java b/src/test/java/cn/enaium/joe/asm/VisitorTest.java index 977a771..63dedfb 100644 --- a/src/test/java/cn/enaium/joe/asm/VisitorTest.java +++ b/src/test/java/cn/enaium/joe/asm/VisitorTest.java @@ -1,41 +1,34 @@ package cn.enaium.joe.asm; -import javassist.*; +import cn.enaium.joe.compiler.Compiler; +import cn.enaium.joe.util.ASMUtil; import org.junit.jupiter.api.Test; import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.util.ASMifier; import org.objectweb.asm.util.TraceClassVisitor; import java.io.*; import java.lang.reflect.InvocationTargetException; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * @author Enaium */ class VisitorTest { @Test - public void test() throws IOException, CannotCompileException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, NotFoundException { + public void test() throws IOException { StringWriter stringWriter = new StringWriter(); ClassReader classReader = new ClassReader(this.getClass().getName()); classReader.accept(new TraceClassVisitor(null, new ASMifier(), new PrintWriter(stringWriter)), 0); - ClassPool classPool = ClassPool.getDefault(); - classPool.importPackage("org.objectweb.asm.AnnotationVisitor"); - classPool.importPackage("org.objectweb.asm.Attribute"); - classPool.importPackage("org.objectweb.asm.ClassReader"); - classPool.importPackage("org.objectweb.asm.ClassWriter"); - classPool.importPackage("org.objectweb.asm.ConstantDynamic"); - classPool.importPackage("org.objectweb.asm.FieldVisitor"); - classPool.importPackage("org.objectweb.asm.Handle"); - classPool.importPackage("org.objectweb.asm.Label"); - classPool.importPackage("org.objectweb.asm.MethodVisitor"); - classPool.importPackage("org.objectweb.asm.Opcodes"); - classPool.importPackage("org.objectweb.asm.RecordComponentVisitor"); - classPool.importPackage("org.objectweb.asm.Type"); - classPool.importPackage("org.objectweb.asm.TypePath"); - CtClass ctClass = classPool.makeClass(ASMifier.class.getSimpleName()); - ctClass.addInterface(classPool.get("org.objectweb.asm.Opcodes")); - String substring = stringWriter.toString().substring(stringWriter.toString().indexOf("{") + 1, stringWriter.toString().lastIndexOf("}")); - ctClass.addMethod(CtMethod.make(substring, ctClass)); - System.out.println(ctClass.toClass().getMethod("dump").invoke(null)); + Compiler compiler = new Compiler(); + String name = "asm." + this.getClass().getName() + "Dump"; + compiler.addSource(name, stringWriter.toString()); + assertTrue(compiler.compile()); + ClassNode classNode = ASMUtil.acceptClassNode(new ClassReader(compiler.getClasses().get(name))); + StringWriter out = new StringWriter(); + classNode.accept(new TraceClassVisitor(new PrintWriter(out))); + System.out.println(out); } } \ No newline at end of file diff --git a/src/test/java/cn/enaium/joe/compiler/CompilerTest.java b/src/test/java/cn/enaium/joe/compiler/CompilerTest.java new file mode 100644 index 0000000..db4cc09 --- /dev/null +++ b/src/test/java/cn/enaium/joe/compiler/CompilerTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.compiler; + +import cn.enaium.joe.util.ASMUtil; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.util.TraceClassVisitor; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * @author Enaium + */ +class CompilerTest { + @Test + public void compile() throws IOException { + Compiler compiler = new Compiler(); + compiler.addSource("Test", "public class Test { public static void main(String[] args) { System.out.println(0xCAFEBABE); } }"); + Assertions.assertTrue(compiler.compile()); + ClassNode classNode = ASMUtil.acceptClassNode(new ClassReader(compiler.getClasses().get("Test"))); + StringWriter out = new StringWriter(); + classNode.accept(new TraceClassVisitor(new PrintWriter(out))); + System.out.println(out); + } +} \ No newline at end of file From 1e428a5cd1119854faa3093abe2bae47f622f897 Mon Sep 17 00:00:00 2001 From: Enaium Date: Thu, 29 Sep 2022 09:41:42 +0800 Subject: [PATCH 03/49] fix language --- src/main/java/cn/enaium/joe/util/LangUtil.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/cn/enaium/joe/util/LangUtil.java b/src/main/java/cn/enaium/joe/util/LangUtil.java index 874b1d4..3efa8a4 100644 --- a/src/main/java/cn/enaium/joe/util/LangUtil.java +++ b/src/main/java/cn/enaium/joe/util/LangUtil.java @@ -38,23 +38,23 @@ public static String i18n(String key, Object... args) { } try { - String en = IOUtil.getString(LangUtil.class.getResourceAsStream("/lang/en_US.json")); + String text; URL url = LangUtil.class.getResource("/lang/" + lang + ".json"); - if (url == null) { - RuntimeException runtimeException = new RuntimeException(String.format("lang ' %s ' not Found!", lang)); - MessageUtil.error(runtimeException); - throw runtimeException; + if (url != null) { + text = IOUtil.getString(url.openStream()); + } else { + text = IOUtil.getString(LangUtil.class.getResourceAsStream("/lang/en_US.json")); } - JsonObject jsonObject = new Gson().fromJson(IOUtil.getString(url.openStream()), JsonObject.class); + JsonObject jsonObject = new Gson().fromJson(text, JsonObject.class); try { return String.format(jsonObject.get(key).getAsString(), args); } catch (NullPointerException e) { Logger.warn(String.format("Lang not found \" %s \" ", key)); try { - return String.format(new Gson().fromJson(en, JsonObject.class).get(key).getAsString(), args); + return String.format(new Gson().fromJson(text, JsonObject.class).get(key).getAsString(), args); } catch (NullPointerException ex) { MessageUtil.error(new NullPointerException(String.format("not found key ' %s ' in en_us", key))); } From d8f77711826bf3185f5d0b6887d4973b09b709fb Mon Sep 17 00:00:00 2001 From: Enaium Date: Sun, 2 Oct 2022 15:23:58 +0800 Subject: [PATCH 04/49] Update build.gradle --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 8e993a3..8bd8b60 100644 --- a/build.gradle +++ b/build.gradle @@ -39,8 +39,8 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' - implementation 'com.formdev:flatlaf:2.4' - implementation 'com.formdev:flatlaf-extras:2.4' + implementation 'com.formdev:flatlaf:2.5' + implementation 'com.formdev:flatlaf-extras:2.5' //noinspection GradlePackageUpdate implementation 'com.miglayout:miglayout-swing:5.3' implementation 'com.github.bobbylight:RSyntaxTextArea:3.2.0' From a407de114b6e41995f30f3ba20b2aec07461f30f Mon Sep 17 00:00:00 2001 From: Enaium Date: Sun, 2 Oct 2022 15:26:51 +0800 Subject: [PATCH 05/49] Update build.gradle --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8bd8b60..f8ae76e 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ plugins { } group 'cn.enaium' -version '1.4.0' +version '1.4.0-beta.1' sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8 From 5f402a74b20d0273b313067ec6a752bf7ad17516 Mon Sep 17 00:00:00 2001 From: Enaium Date: Sun, 2 Oct 2022 15:41:13 +0800 Subject: [PATCH 06/49] Update build.gradle --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f8ae76e..fb3eee0 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ plugins { } group 'cn.enaium' -version '1.4.0-beta.1' +version '1.4.0-beta.2' sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8 From 100f67004a8ea77f2c5e64d1e75c6a4af54fec88 Mon Sep 17 00:00:00 2001 From: Enaium Date: Mon, 3 Oct 2022 13:42:59 +0800 Subject: [PATCH 07/49] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 64c1e10..30101ec 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ ![GitHub all releases](https://img.shields.io/github/downloads/Enaium/JavaOctetEditor/total?style=flat-square) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/Enaium/JavaOctetEditor?style=flat-square) +![GitHub release (latest SemVer including pre-releases)](https://img.shields.io/github/v/release/Enaium/JavaOctetEditor?include_prereleases&style=flat-square) ![GitHub](https://img.shields.io/github/license/Enaium/JavaOctetEditor?style=flat-square) ![](https://user-images.githubusercontent.com/32991121/190947407-bbc6642e-2c9d-46f3-921c-6558c74272cf.png) From 81acaf57f023d827a21dd33ed1f2fbe8ada38517 Mon Sep 17 00:00:00 2001 From: Enaium Date: Mon, 3 Oct 2022 16:03:47 +0800 Subject: [PATCH 08/49] save text --- .../java/cn/enaium/joe/gui/component/FileTree.java | 7 ++----- .../cn/enaium/joe/gui/panel/CodeAreaPanel.java | 1 - .../file/tabbed/tab/resources/TextTablePanel.java | 11 +++++++++++ .../joe/gui/panel/file/tree/node/FileTreeNode.java | 14 ++++++++++---- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/main/java/cn/enaium/joe/gui/component/FileTree.java b/src/main/java/cn/enaium/joe/gui/component/FileTree.java index fc35fa0..b71b08e 100644 --- a/src/main/java/cn/enaium/joe/gui/component/FileTree.java +++ b/src/main/java/cn/enaium/joe/gui/component/FileTree.java @@ -33,14 +33,11 @@ import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.MutableTreeNode; -import javax.swing.tree.TreeNode; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.*; -import java.util.concurrent.CopyOnWriteArrayList; /** * @author Enaium @@ -170,7 +167,7 @@ public void refresh(Jar jar) { FolderTreeNode folderTreeNode = new FolderTreeNode(s); if (split.length == i + 1) { - folderTreeNode = new FileTreeNode(s, stringEntry.getValue()); + folderTreeNode = new FileTreeNode(s,stringEntry.getKey()); } if (prev == null) { @@ -229,7 +226,7 @@ public void refresh(Jar jar) { name = name.substring(name.lastIndexOf("/") + 1); } - FileTreeNode classTreeNode = new FileTreeNode(name, stringEntry.getValue()); + FileTreeNode classTreeNode = new FileTreeNode(name, stringEntry.getKey()); if (folderName.isEmpty()) { resourceRoot.add(classTreeNode); diff --git a/src/main/java/cn/enaium/joe/gui/panel/CodeAreaPanel.java b/src/main/java/cn/enaium/joe/gui/panel/CodeAreaPanel.java index 877c2fe..f07f7a6 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/CodeAreaPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/CodeAreaPanel.java @@ -46,7 +46,6 @@ public class CodeAreaPanel extends BorderPanel implements ActionListener { public CodeAreaPanel() { textArea = new RSyntaxTextArea(); textArea.setCodeFoldingEnabled(true); - textArea.setEditable(false); Theme theme; try { theme = Theme.load(getClass().getResourceAsStream("/org/fife/ui/rsyntaxtextarea/themes/monokai.xml")); diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/resources/TextTablePanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/resources/TextTablePanel.java index e82a802..41bc470 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/resources/TextTablePanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/resources/TextTablePanel.java @@ -16,15 +16,21 @@ package cn.enaium.joe.gui.panel.file.tabbed.tab.resources; +import cn.enaium.joe.JavaOctetEditor; import cn.enaium.joe.gui.panel.BorderPanel; import cn.enaium.joe.gui.panel.CodeAreaPanel; import cn.enaium.joe.gui.panel.file.tree.node.FileTreeNode; +import cn.enaium.joe.util.KeyStrokeUtil; +import cn.enaium.joe.util.LangUtil; +import cn.enaium.joe.util.MessageUtil; import org.fife.ui.rsyntaxtextarea.FileTypeUtil; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import javax.swing.*; import java.awt.*; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; @@ -48,6 +54,11 @@ public TextTablePanel(FileTreeNode fileTreeNode) { } getTextArea().setSyntaxEditingStyle(syntax); getTextArea().setText(new String(fileTreeNode.getData(), StandardCharsets.UTF_8)); + + KeyStrokeUtil.register(getTextArea(), KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK), () -> { + fileTreeNode.setData(getTextArea().getText().getBytes(StandardCharsets.UTF_8)); + MessageUtil.info(LangUtil.i18n("success")); + }); }}); } } diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tree/node/FileTreeNode.java b/src/main/java/cn/enaium/joe/gui/panel/file/tree/node/FileTreeNode.java index 1c603f3..4310eca 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tree/node/FileTreeNode.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tree/node/FileTreeNode.java @@ -16,19 +16,25 @@ package cn.enaium.joe.gui.panel.file.tree.node; +import cn.enaium.joe.JavaOctetEditor; + /** * @author Enaium */ public class FileTreeNode extends FolderTreeNode { - private final byte[] data; + private final String file; - public FileTreeNode(Object userObject, byte[] data) { + public FileTreeNode(Object userObject, String file) { super(userObject); - this.data = data; + this.file = file; } public byte[] getData() { - return data; + return JavaOctetEditor.getInstance().getJar().resources.get(file); + } + + public void setData(byte[] data) { + JavaOctetEditor.getInstance().getJar().resources.put(file, data); } } From e63e88d6fd2cb5afcbd819b1596ddf8e4b4b4623 Mon Sep 17 00:00:00 2001 From: Enaium Date: Mon, 3 Oct 2022 20:04:42 +0800 Subject: [PATCH 09/49] Update TaskManager.java --- src/main/java/cn/enaium/joe/task/TaskManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/cn/enaium/joe/task/TaskManager.java b/src/main/java/cn/enaium/joe/task/TaskManager.java index 6b64368..9b6252d 100644 --- a/src/main/java/cn/enaium/joe/task/TaskManager.java +++ b/src/main/java/cn/enaium/joe/task/TaskManager.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.Logger; @@ -35,7 +36,7 @@ */ public class TaskManager { private final ExecutorService executorService = Executors.newCachedThreadPool(); - private final List, CompletableFuture>> task = new ArrayList<>(); + private final List, CompletableFuture>> task = new CopyOnWriteArrayList<>(); public CompletableFuture submit(AbstractTask abstractTask) { for (Pair, CompletableFuture> classCompletableFuturePair : task) { From b93e569416f8416a00219fcf4bf5e0335a0d930a Mon Sep 17 00:00:00 2001 From: Enaium Date: Mon, 3 Oct 2022 20:04:56 +0800 Subject: [PATCH 10/49] message --- .../java/cn/enaium/joe/JavaOctetEditor.java | 7 +- .../java/cn/enaium/joe/dialog/Dialog.java | 5 +- .../cn/enaium/joe/dialog/OptionDialog.java | 97 +++++++++++++++++++ .../tab/classes/ASMifierTablePanel.java | 4 +- .../joe/gui/panel/file/tree/CenterPanel.java | 1 - .../java/cn/enaium/joe/util/MessageUtil.java | 44 +++------ 6 files changed, 121 insertions(+), 37 deletions(-) create mode 100644 src/main/java/cn/enaium/joe/dialog/OptionDialog.java diff --git a/src/main/java/cn/enaium/joe/JavaOctetEditor.java b/src/main/java/cn/enaium/joe/JavaOctetEditor.java index f3ba9c1..5941ea0 100644 --- a/src/main/java/cn/enaium/joe/JavaOctetEditor.java +++ b/src/main/java/cn/enaium/joe/JavaOctetEditor.java @@ -18,6 +18,7 @@ import cn.enaium.joe.config.ConfigManager; import cn.enaium.joe.event.EventManager; +import cn.enaium.joe.gui.panel.BorderPanel; import cn.enaium.joe.gui.panel.BottomPanel; import cn.enaium.joe.gui.panel.file.tree.CenterPanel; import cn.enaium.joe.gui.panel.file.tabbed.FileTabbedPanel; @@ -98,9 +99,9 @@ public void run() { add(new HelpMenu()); }}); - window.setContentPane(new JPanel(new BorderLayout()) {{ - add(new CenterPanel(), BorderLayout.CENTER); - add(bottomPanel, BorderLayout.SOUTH); + window.setContentPane(new BorderPanel() {{ + setCenter(new CenterPanel()); + setBottom(bottomPanel); }}); diff --git a/src/main/java/cn/enaium/joe/dialog/Dialog.java b/src/main/java/cn/enaium/joe/dialog/Dialog.java index 0561b83..dd9704b 100644 --- a/src/main/java/cn/enaium/joe/dialog/Dialog.java +++ b/src/main/java/cn/enaium/joe/dialog/Dialog.java @@ -20,12 +20,13 @@ import javax.swing.*; -public class Dialog extends JFrame { +public class Dialog extends JDialog { public Dialog(String title) { - super(title); + setTitle(title); setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); setSize(800, 500); setLocationRelativeTo(getOwner()); setIconImage(new FlatSVGIcon("icons/logo.svg").getImage()); + set } } \ No newline at end of file diff --git a/src/main/java/cn/enaium/joe/dialog/OptionDialog.java b/src/main/java/cn/enaium/joe/dialog/OptionDialog.java new file mode 100644 index 0000000..2e07d8e --- /dev/null +++ b/src/main/java/cn/enaium/joe/dialog/OptionDialog.java @@ -0,0 +1,97 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.dialog; + +import cn.enaium.joe.gui.panel.BorderPanel; +import cn.enaium.joe.gui.panel.confirm.ConfirmPanel; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; + +/** + * @author Enaium + * @since 1.4.0 + */ +public class OptionDialog extends Dialog { + + public OptionDialog(String title, Object message, int type, Runnable confirm, Runnable cancel) { + super(title); + setContentPane(new BorderPanel() {{ + setBorder(new EmptyBorder(10, 10, 10, 10)); + setLeft(new JLabel(getIconForType(type))); + + JPanel bottom = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + if (message != null) { + bottom.add(new JButton("Ok") {{ + addActionListener(e -> { + if (confirm != null) { + confirm.run(); + } + dispose(); + }); + }}); + + if (cancel != null) { + bottom.add(new JButton("No") {{ + addActionListener(e -> { + cancel.run(); + dispose(); + }); + }}); + } + + + if (message instanceof String) { + setCenter(new JLabel(message.toString())); + } else if (message instanceof ConfirmPanel) { + setCenter((Component) message); + } else { + setCenter((Component) message); + } + } + setBottom(bottom); + }}); + setModal(true); + pack(); + } + + public OptionDialog(String title, Object message, int type) { + this(title, message, type, null, null); + } + + private Icon getIconForType(int messageType) { + if (messageType < 0 || messageType > 3) + return null; + String propertyName = null; + switch (messageType) { + case 0: + propertyName = "OptionPane.errorIcon"; + break; + case 1: + propertyName = "OptionPane.informationIcon"; + break; + case 2: + propertyName = "OptionPane.warningIcon"; + break; + case 3: + propertyName = "OptionPane.questionIcon"; + break; + } + return (Icon) UIManager.get(propertyName); + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java index f091bc8..22f6b13 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java @@ -17,6 +17,7 @@ package cn.enaium.joe.gui.panel.file.tabbed.tab.classes; import cn.enaium.joe.compiler.Compiler; +import cn.enaium.joe.compiler.VirtualJavaFileObject; import cn.enaium.joe.gui.panel.CodeAreaPanel; import cn.enaium.joe.util.*; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; @@ -28,6 +29,7 @@ import javax.swing.*; import javax.tools.Diagnostic; +import javax.tools.DiagnosticListener; import java.awt.*; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; @@ -80,7 +82,7 @@ protected Class findClass(String name) { ClassNode newClassNode = new ClassNode(); new ClassReader(dumps).accept(newClassNode, ClassReader.EXPAND_FRAMES); ReflectUtil.setAll(classNode, newClassNode); - JOptionPane.showMessageDialog(null, LangUtil.i18n("success")); + MessageUtil.info(LangUtil.i18n("success")); } catch (Throwable e) { MessageUtil.error(e); } diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tree/CenterPanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tree/CenterPanel.java index a754811..d8b4662 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tree/CenterPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tree/CenterPanel.java @@ -43,7 +43,6 @@ public CenterPanel() { jViewport.setView(getSelectedComponent()); }); }}); - }}); } } diff --git a/src/main/java/cn/enaium/joe/util/MessageUtil.java b/src/main/java/cn/enaium/joe/util/MessageUtil.java index 1b46275..2939e2c 100644 --- a/src/main/java/cn/enaium/joe/util/MessageUtil.java +++ b/src/main/java/cn/enaium/joe/util/MessageUtil.java @@ -16,17 +16,14 @@ package cn.enaium.joe.util; -import cn.enaium.joe.gui.panel.BorderPanel; +import cn.enaium.joe.dialog.OptionDialog; import cn.enaium.joe.gui.panel.confirm.ConfirmPanel; -import org.benf.cfr.reader.util.StringUtils; import org.pmw.tinylog.Logger; import javax.swing.*; import java.awt.*; import java.io.PrintWriter; import java.io.StringWriter; -import java.util.Arrays; -import java.util.stream.Collectors; /** * @author Enaium @@ -35,36 +32,21 @@ public class MessageUtil { public static void error(Throwable e) { - JOptionPane.showMessageDialog(null, new BorderPanel() {{ - setTop(new JLabel(e.toString())); - setCenter(new JScrollPane(new JTextArea() {{ - StringWriter out = new StringWriter(); - e.printStackTrace(new PrintWriter(out)); - setText(out.toString()); - setEditable(false); - }})); - }}, LangUtil.i18n("error"), JOptionPane.ERROR_MESSAGE); + new OptionDialog(LangUtil.i18n("error"), new JScrollPane(new JTextArea() {{ + StringWriter out = new StringWriter(); + e.printStackTrace(new PrintWriter(out)); + setText(out.toString()); + setEditable(false); + }}), JOptionPane.ERROR_MESSAGE).setVisible(true); } public static void confirm(Object message, String title, Runnable yes, Runnable no) { - int i = JOptionPane.showConfirmDialog(null, message, title, JOptionPane.OK_CANCEL_OPTION); - if (i == JOptionPane.YES_OPTION) { - if (yes != null) { - yes.run(); - } - } else { - if (no != null) { - no.run(); - } - } + OptionDialog optionDialog = new OptionDialog(title, message, JOptionPane.INFORMATION_MESSAGE, yes, no); + optionDialog.setVisible(true); } public static void confirm(ConfirmPanel confirmPanel, String title) { - confirm(confirmPanel, title, () -> { - confirmPanel.getConfirm().run(); - }, () -> { - confirmPanel.getCancel().run(); - }); + confirm(confirmPanel, title, confirmPanel.getConfirm(), confirmPanel.getCancel()); } public static void confirm(ConfirmPanel confirmPanel, String title, Runnable yes) { @@ -80,12 +62,14 @@ public static void confirm(Object message, String title, Runnable yes) { public static void info(String message) { - JOptionPane.showMessageDialog(null, message, LangUtil.i18n("info"), JOptionPane.INFORMATION_MESSAGE); + OptionDialog info = new OptionDialog(LangUtil.i18n("info"), message, JOptionPane.INFORMATION_MESSAGE); + info.setVisible(true); Logger.info(message); } public static void warning(String message) { - JOptionPane.showMessageDialog(null, message, LangUtil.i18n("warning"), JOptionPane.WARNING_MESSAGE); + OptionDialog warning = new OptionDialog(LangUtil.i18n("warning"), message, JOptionPane.WARNING_MESSAGE); + warning.setVisible(true); Logger.warn(message); } } From 0faf8050107d57a3db559edb15cd68abb66e403c Mon Sep 17 00:00:00 2001 From: Enaium Date: Wed, 5 Oct 2022 15:03:21 +0800 Subject: [PATCH 11/49] Update Dialog.java --- src/main/java/cn/enaium/joe/dialog/Dialog.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/cn/enaium/joe/dialog/Dialog.java b/src/main/java/cn/enaium/joe/dialog/Dialog.java index dd9704b..9c003ad 100644 --- a/src/main/java/cn/enaium/joe/dialog/Dialog.java +++ b/src/main/java/cn/enaium/joe/dialog/Dialog.java @@ -27,6 +27,5 @@ public Dialog(String title) { setSize(800, 500); setLocationRelativeTo(getOwner()); setIconImage(new FlatSVGIcon("icons/logo.svg").getImage()); - set } } \ No newline at end of file From 957fa6b0a4717dad5449a8b666de1030980e6151 Mon Sep 17 00:00:00 2001 From: Enaium Date: Mon, 10 Oct 2022 20:46:20 +0800 Subject: [PATCH 12/49] update asm --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index fb3eee0..6738999 100644 --- a/build.gradle +++ b/build.gradle @@ -44,9 +44,9 @@ dependencies { //noinspection GradlePackageUpdate implementation 'com.miglayout:miglayout-swing:5.3' implementation 'com.github.bobbylight:RSyntaxTextArea:3.2.0' - implementation 'org.ow2.asm:asm-tree:9.3' - implementation 'org.ow2.asm:asm-util:9.3' - implementation 'org.ow2.asm:asm-commons:9.3' + implementation 'org.ow2.asm:asm-tree:9.4' + implementation 'org.ow2.asm:asm-util:9.4' + implementation 'org.ow2.asm:asm-commons:9.4' implementation 'org.benf:cfr:0.152' implementation 'com.github.mstrobel.procyon:procyon-decompiler:v0.6.0' implementation 'org.quiltmc:quiltflower:1.8.1' From 30f33d987a8d627da5f8b4af29f744a201d9b0df Mon Sep 17 00:00:00 2001 From: Enaium Date: Mon, 10 Oct 2022 21:09:44 +0800 Subject: [PATCH 13/49] fix size at high resolution --- src/main/java/cn/enaium/joe/JavaOctetEditor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/cn/enaium/joe/JavaOctetEditor.java b/src/main/java/cn/enaium/joe/JavaOctetEditor.java index 5941ea0..c7289d1 100644 --- a/src/main/java/cn/enaium/joe/JavaOctetEditor.java +++ b/src/main/java/cn/enaium/joe/JavaOctetEditor.java @@ -116,7 +116,8 @@ public void windowClosing(WindowEvent e) { }); } }); - window.setSize(1000, 600); + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + window.setSize((int) (1000 * screenSize.getWidth() / 1920), (int) (600 * screenSize.getHeight() / 1080)); window.setLocationRelativeTo(null); window.setVisible(true); } From bf4cb13673c8c6ff316bf0fd29d8e21b32ff09ae Mon Sep 17 00:00:00 2001 From: Enaium Date: Mon, 10 Oct 2022 21:48:26 +0800 Subject: [PATCH 14/49] option --- .../cn/enaium/joe/dialog/OptionDialog.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/cn/enaium/joe/dialog/OptionDialog.java b/src/main/java/cn/enaium/joe/dialog/OptionDialog.java index 2e07d8e..f0621fd 100644 --- a/src/main/java/cn/enaium/joe/dialog/OptionDialog.java +++ b/src/main/java/cn/enaium/joe/dialog/OptionDialog.java @@ -33,11 +33,9 @@ public OptionDialog(String title, Object message, int type, Runnable confirm, Ru super(title); setContentPane(new BorderPanel() {{ setBorder(new EmptyBorder(10, 10, 10, 10)); - setLeft(new JLabel(getIconForType(type))); - JPanel bottom = new JPanel(new FlowLayout(FlowLayout.RIGHT)); if (message != null) { - bottom.add(new JButton("Ok") {{ + bottom.add(new JButton(UIManager.getString("OptionPane.okButton.textAndMnemonic")) {{ addActionListener(e -> { if (confirm != null) { confirm.run(); @@ -47,7 +45,7 @@ public OptionDialog(String title, Object message, int type, Runnable confirm, Ru }}); if (cancel != null) { - bottom.add(new JButton("No") {{ + bottom.add(new JButton(UIManager.getString("OptionPane.cancelButton.textAndMnemonic")) {{ addActionListener(e -> { cancel.run(); dispose(); @@ -55,14 +53,18 @@ public OptionDialog(String title, Object message, int type, Runnable confirm, Ru }}); } - + Component content; if (message instanceof String) { - setCenter(new JLabel(message.toString())); + content = (new JLabel(message.toString())); } else if (message instanceof ConfirmPanel) { - setCenter((Component) message); + content = ((Component) message); } else { - setCenter((Component) message); + content = ((Component) message); } + setTop(new BorderPanel() {{ + setLeft(new JLabel(getIconForType(type))); + setCenter(content); + }}); } setBottom(bottom); }}); From e41e92717189617c5cf3af89ba9b4c4f5c0218d1 Mon Sep 17 00:00:00 2001 From: Enaium Date: Mon, 10 Oct 2022 21:48:37 +0800 Subject: [PATCH 15/49] fix size at high resolution --- src/main/java/cn/enaium/joe/JavaOctetEditor.java | 8 ++------ src/main/java/cn/enaium/joe/dialog/Dialog.java | 4 +++- src/main/java/cn/enaium/joe/util/Util.java | 6 ++++++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/java/cn/enaium/joe/JavaOctetEditor.java b/src/main/java/cn/enaium/joe/JavaOctetEditor.java index c7289d1..a2f821f 100644 --- a/src/main/java/cn/enaium/joe/JavaOctetEditor.java +++ b/src/main/java/cn/enaium/joe/JavaOctetEditor.java @@ -26,10 +26,7 @@ import cn.enaium.joe.gui.panel.menu.*; import cn.enaium.joe.jar.Jar; import cn.enaium.joe.task.TaskManager; -import cn.enaium.joe.util.BytecodeTokenMaker; -import cn.enaium.joe.util.LangUtil; -import cn.enaium.joe.util.MessageUtil; -import cn.enaium.joe.util.ReflectUtil; +import cn.enaium.joe.util.*; import com.formdev.flatlaf.extras.FlatSVGIcon; import org.fife.ui.rsyntaxtextarea.AbstractTokenMakerFactory; import org.fife.ui.rsyntaxtextarea.TokenMakerFactory; @@ -116,8 +113,7 @@ public void windowClosing(WindowEvent e) { }); } }); - Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); - window.setSize((int) (1000 * screenSize.getWidth() / 1920), (int) (600 * screenSize.getHeight() / 1080)); + window.setSize(Util.screenSize(1000, 600)); window.setLocationRelativeTo(null); window.setVisible(true); } diff --git a/src/main/java/cn/enaium/joe/dialog/Dialog.java b/src/main/java/cn/enaium/joe/dialog/Dialog.java index 9c003ad..d7994d8 100644 --- a/src/main/java/cn/enaium/joe/dialog/Dialog.java +++ b/src/main/java/cn/enaium/joe/dialog/Dialog.java @@ -16,15 +16,17 @@ package cn.enaium.joe.dialog; +import cn.enaium.joe.util.Util; import com.formdev.flatlaf.extras.FlatSVGIcon; import javax.swing.*; +import java.awt.*; public class Dialog extends JDialog { public Dialog(String title) { setTitle(title); setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - setSize(800, 500); + setSize(Util.screenSize(800, 500)); setLocationRelativeTo(getOwner()); setIconImage(new FlatSVGIcon("icons/logo.svg").getImage()); } diff --git a/src/main/java/cn/enaium/joe/util/Util.java b/src/main/java/cn/enaium/joe/util/Util.java index 7358e50..e35fb75 100644 --- a/src/main/java/cn/enaium/joe/util/Util.java +++ b/src/main/java/cn/enaium/joe/util/Util.java @@ -16,6 +16,7 @@ package cn.enaium.joe.util; +import java.awt.*; import java.util.Enumeration; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -46,4 +47,9 @@ public static boolean isText(byte[] bytes) { } return true; } + + public static Dimension screenSize(int width, int height) { + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + return new Dimension((int) (width * screenSize.getWidth() / 1920), (int) (height * screenSize.getHeight() / 1080)); + } } From 98a984d6f8c9c09cdfc935a0fe0c1edd6475696f Mon Sep 17 00:00:00 2001 From: Enaium Date: Mon, 10 Oct 2022 21:57:00 +0800 Subject: [PATCH 16/49] add inherit to tab --- .../cn/enaium/joe/gui/panel/InheritPanel.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/main/java/cn/enaium/joe/gui/panel/InheritPanel.java b/src/main/java/cn/enaium/joe/gui/panel/InheritPanel.java index d217bea..aaf454e 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/InheritPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/InheritPanel.java @@ -21,6 +21,7 @@ import cn.enaium.joe.gui.panel.file.tabbed.tab.classes.ClassTabPanel; import cn.enaium.joe.gui.panel.file.tree.FileTreeCellRenderer; import cn.enaium.joe.gui.panel.file.tree.node.ClassTreeNode; +import cn.enaium.joe.gui.panel.file.tree.node.PackageTreeNode; import cn.enaium.joe.jar.Jar; import cn.enaium.joe.util.ASMUtil; import cn.enaium.joe.util.JTreeUtil; @@ -33,6 +34,8 @@ import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.io.IOException; import java.util.Map; import java.util.Set; @@ -50,6 +53,23 @@ public InheritPanel() { JTree inheritance = new JTree() {{ setModel(new DefaultTreeModel(null)); setCellRenderer(new FileTreeCellRenderer()); + addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { + if (getSelectionPath() != null) { + Object lastPathComponent = getSelectionPath().getLastPathComponent(); + if (lastPathComponent instanceof PackageTreeNode) { + PackageTreeNode packageTreeNode = (PackageTreeNode) lastPathComponent; + if (packageTreeNode instanceof ClassTreeNode) { + ClassNode classNode = ((ClassTreeNode) packageTreeNode).classNode; + JavaOctetEditor.getInstance().fileTabbedPanel.addTab(classNode.name.substring(classNode.name.lastIndexOf("/") + 1), new ClassTabPanel(classNode)); + } + } + } + } + } + }); }}; JavaOctetEditor.getInstance().event.register(FileTabbedSelectEvent.class, (Consumer) event -> { if (event.getSelect() instanceof ClassTabPanel) { From 30f168cc244907ecf7f6b9c6a62e7fd43b1487d4 Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 14 Oct 2022 08:36:33 +0800 Subject: [PATCH 17/49] Update VerticalLabelUI.java --- src/main/java/cn/enaium/joe/gui/ui/VerticalLabelUI.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/cn/enaium/joe/gui/ui/VerticalLabelUI.java b/src/main/java/cn/enaium/joe/gui/ui/VerticalLabelUI.java index aa6f61d..cd5840f 100644 --- a/src/main/java/cn/enaium/joe/gui/ui/VerticalLabelUI.java +++ b/src/main/java/cn/enaium/joe/gui/ui/VerticalLabelUI.java @@ -70,10 +70,12 @@ public void paint(Graphics g, JComponent c) { Graphics2D g2 = (Graphics2D) g; AffineTransform tr = g2.getTransform(); + //don't rotate if (icon != null) { icon.paintIcon(c, g, paintIconR.x, paintIconR.y); } + //rotate if (clockwise) { g2.rotate(Math.PI / 2); g2.translate(0, -c.getWidth()); From ef2351ed61edfb6fb2495805398d5affb0d032bc Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 14 Oct 2022 08:45:23 +0800 Subject: [PATCH 18/49] fix font size in high resolution --- .../enaium/joe/gui/panel/CodeAreaPanel.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/main/java/cn/enaium/joe/gui/panel/CodeAreaPanel.java b/src/main/java/cn/enaium/joe/gui/panel/CodeAreaPanel.java index f07f7a6..2e5a097 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/CodeAreaPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/CodeAreaPanel.java @@ -21,6 +21,7 @@ import cn.enaium.joe.util.StringUtil; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.Theme; +import org.fife.ui.rtextarea.RTextArea; import org.fife.ui.rtextarea.RTextScrollPane; import org.fife.ui.rtextarea.SearchContext; import org.fife.ui.rtextarea.SearchEngine; @@ -38,13 +39,12 @@ */ public class CodeAreaPanel extends BorderPanel implements ActionListener { - private final RSyntaxTextArea textArea; - private final JTextField searchField; - private final JCheckBox regexCB; - private final JCheckBox matchCaseCB; + private final RSyntaxTextArea textArea = new RSyntaxTextArea(); + private final JTextField searchField = new JTextField(30); + private final JCheckBox regexCB = new JCheckBox("Regex"); + private final JCheckBox matchCaseCB = new JCheckBox("Match Case"); public CodeAreaPanel() { - textArea = new RSyntaxTextArea(); textArea.setCodeFoldingEnabled(true); Theme theme; try { @@ -54,8 +54,14 @@ public CodeAreaPanel() { } theme.apply(textArea); + Font defaultFont = RTextArea.getDefaultFont(); + Font font = defaultFont.deriveFont((float) UIManager.getFont("defaultFont").getSize()); + textArea.setFont(font); + textArea.setPaintMatchedBracketPair( true ); + textArea.setAnimateBracketMatching( false ); + + JToolBar toolBar = new JToolBar(); - searchField = new JTextField(30); toolBar.add(searchField); final JButton nextButton = new JButton(LangUtil.i18n("button.findNext")); nextButton.setActionCommand("FindNext"); @@ -66,13 +72,12 @@ public CodeAreaPanel() { prevButton.setActionCommand("FindPrev"); prevButton.addActionListener(this); toolBar.add(prevButton); - regexCB = new JCheckBox("Regex"); toolBar.add(regexCB); - matchCaseCB = new JCheckBox("Match Case"); toolBar.add(matchCaseCB); toolBar.setVisible(false); setTop(toolBar); setCenter(new RTextScrollPane(textArea) {{ + getGutter().setLineNumberFont(font); KeyStrokeUtil.register(textArea, KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_DOWN_MASK), () -> { if (!StringUtil.isBlank(textArea.getSelectedText())) { searchField.setText(textArea.getSelectedText()); From 60711a2f7416579eea7f266b4c8c17197ba3b78d Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 14 Oct 2022 10:22:13 +0800 Subject: [PATCH 19/49] fix module class --- .../gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java index 22f6b13..83824c9 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java @@ -57,6 +57,7 @@ public ASMifierTablePanel(ClassNode classNode) { "import org.objectweb.asm.MethodVisitor;" + "import org.objectweb.asm.Opcodes;" + "import org.objectweb.asm.RecordComponentVisitor;" + + "import org.objectweb.asm.ModuleVisitor;" + "import org.objectweb.asm.Type;" + "import org.objectweb.asm.TypePath;" + "public class" + " " + ASMifier.class.getSimpleName() + " " + "implements Opcodes" + From df8d66a588d76da8c125fe76414a3abd61eab51b Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 14 Oct 2022 11:34:47 +0800 Subject: [PATCH 20/49] Update CFRDecompiler.java --- .../joe/service/decompiler/CFRDecompiler.java | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/src/main/java/cn/enaium/joe/service/decompiler/CFRDecompiler.java b/src/main/java/cn/enaium/joe/service/decompiler/CFRDecompiler.java index 03c8269..d604494 100644 --- a/src/main/java/cn/enaium/joe/service/decompiler/CFRDecompiler.java +++ b/src/main/java/cn/enaium/joe/service/decompiler/CFRDecompiler.java @@ -19,13 +19,18 @@ import cn.enaium.joe.JavaOctetEditor; import cn.enaium.joe.config.extend.CFRConfig; import org.benf.cfr.reader.PluginRunner; +import org.benf.cfr.reader.api.CfrDriver; import org.benf.cfr.reader.api.ClassFileSource; +import org.benf.cfr.reader.api.OutputSinkFactory; import org.benf.cfr.reader.bytecode.analysis.parse.utils.Pair; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.tree.ClassNode; import java.io.IOException; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.List; /** * @author Enaium @@ -57,9 +62,42 @@ public Pair getClassFileContent(String path) throws IOException @Override public Collection addJar(String arg0) { - throw new RuntimeException(); + return Collections.emptySet(); } }; - return new PluginRunner(JavaOctetEditor.getInstance().config.getConfigMap(CFRConfig.class), cfs).getDecompilationFor(classNode.name); + + OutputSinkFactory outputSinkFactory = new OutputSinkFactory() { + String content; + + @Override + public List getSupportedSinks(SinkType sinkType, Collection available) { + return Arrays.asList(SinkClass.values()); + } + + @Override + public Sink getSink(SinkType sinkType, SinkClass sinkClass) { + + if (sinkType == SinkType.JAVA) { + return this::setContent; + } + + return t -> { + + }; + } + + private void setContent(T content) { + this.content = content.toString(); + } + + @Override + public String toString() { + return content; + } + }; + CfrDriver driver = new CfrDriver.Builder().withClassFileSource(cfs).withOptions(JavaOctetEditor.getInstance().config.getConfigMap(CFRConfig.class)).withOutputSink(outputSinkFactory).build(); + + driver.analyse(Collections.singletonList(classNode.name)); + return outputSinkFactory.toString(); } } From 7d8749609374debb431b8eafe76542b044b1760f Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 14 Oct 2022 15:04:59 +0800 Subject: [PATCH 21/49] edit utils --- .../gui/panel/confirm/ListValueEditPanel.java | 2 +- .../joe/gui/panel/confirm/ValueEditPanel.java | 2 +- .../tab/classes/ASMifierTablePanel.java | 8 +---- src/main/java/cn/enaium/joe/util/ASMUtil.java | 33 ++++++++++++++++++- .../java/cn/enaium/joe/util/MessageUtil.java | 1 + .../java/cn/enaium/joe/util/ReflectUtil.java | 17 +++++++--- src/main/java/cn/enaium/joe/util/Util.java | 7 +++- 7 files changed, 55 insertions(+), 15 deletions(-) diff --git a/src/main/java/cn/enaium/joe/gui/panel/confirm/ListValueEditPanel.java b/src/main/java/cn/enaium/joe/gui/panel/confirm/ListValueEditPanel.java index 9742da3..0fe76f0 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/confirm/ListValueEditPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/confirm/ListValueEditPanel.java @@ -46,7 +46,7 @@ public ListValueEditPanel(List objects) { setConfirm(() -> { objects.clear(); for (String s : jTextArea.getText().replaceAll("^\\s+", "").split("\n")) { - objects.add(ASMUtil.toType(type, s)); + objects.add(ASMUtil.valueOf(type, s)); } }); } diff --git a/src/main/java/cn/enaium/joe/gui/panel/confirm/ValueEditPanel.java b/src/main/java/cn/enaium/joe/gui/panel/confirm/ValueEditPanel.java index d605a05..c2e1f8d 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/confirm/ValueEditPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/confirm/ValueEditPanel.java @@ -32,7 +32,7 @@ public ValueEditPanel(ObjectWrapper objectWrapper) { JTextField jTextField = new JTextField(objectWrapper.getWrapper().toString()); add(jTextField, BorderLayout.CENTER); setConfirm(() -> { - objectWrapper.setWrapper(ASMUtil.toType(objectWrapper.getWrapper().getClass(), jTextField.getText())); + objectWrapper.setWrapper(ASMUtil.valueOf(objectWrapper.getWrapper().getClass(), jTextField.getText())); }); } } diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java index 83824c9..f7786f8 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java @@ -17,7 +17,6 @@ package cn.enaium.joe.gui.panel.file.tabbed.tab.classes; import cn.enaium.joe.compiler.Compiler; -import cn.enaium.joe.compiler.VirtualJavaFileObject; import cn.enaium.joe.gui.panel.CodeAreaPanel; import cn.enaium.joe.util.*; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; @@ -25,11 +24,8 @@ import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.util.ASMifier; import org.objectweb.asm.util.TraceClassVisitor; -import org.pmw.tinylog.Logger; import javax.swing.*; -import javax.tools.Diagnostic; -import javax.tools.DiagnosticListener; import java.awt.*; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; @@ -80,9 +76,7 @@ protected Class findClass(String name) { }; byte[] dumps = (byte[]) loader.loadClass(ASMifier.class.getSimpleName()).getMethod("dump").invoke(null); - ClassNode newClassNode = new ClassNode(); - new ClassReader(dumps).accept(newClassNode, ClassReader.EXPAND_FRAMES); - ReflectUtil.setAll(classNode, newClassNode); + ReflectUtil.copyAllMember(classNode, ASMUtil.acceptClassNode(new ClassReader(dumps))); MessageUtil.info(LangUtil.i18n("success")); } catch (Throwable e) { MessageUtil.error(e); diff --git a/src/main/java/cn/enaium/joe/util/ASMUtil.java b/src/main/java/cn/enaium/joe/util/ASMUtil.java index 8033fc1..c4839ff 100644 --- a/src/main/java/cn/enaium/joe/util/ASMUtil.java +++ b/src/main/java/cn/enaium/joe/util/ASMUtil.java @@ -30,7 +30,15 @@ * @since 1.2.0 */ public class ASMUtil { - public static Object toType(Class type, String text) { + /** + * converts a string value to a value of that type + * + * @param type value type + * @param text value text + * @param value type + * @return value of type + */ + public static Object valueOf(Class type, String text) { try { Method valueOf = type.getMethod("valueOf", String.class); return valueOf.invoke(null, text); @@ -43,6 +51,13 @@ public static Object toType(Class type, String text) { } } + + /** + * accept as class node + * + * @param classReader class reader + * @return class node + */ public static ClassNode acceptClassNode(ClassReader classReader) { ClassNode classNode = new ClassNode(); try { @@ -57,6 +72,12 @@ public static ClassNode acceptClassNode(ClassReader classReader) { return classNode; } + /** + * get all parents, include interfaces + * + * @param classNode class node + * @return all interfaces and superclasses + */ public static Set getParentClass(ClassNode classNode) { Set parent = new HashSet<>(); if (classNode.superName != null && !classNode.superName.equals(Object.class.getName().replace(".", "/"))) { @@ -65,4 +86,14 @@ public static Set getParentClass(ClassNode classNode) { parent.addAll(classNode.interfaces); return parent; } + + /** + * replace all `/` to `.` + * + * @param classNode class node + * @return reference name + */ + public static String getReferenceName(ClassNode classNode) { + return classNode.name.replace("/", "."); + } } diff --git a/src/main/java/cn/enaium/joe/util/MessageUtil.java b/src/main/java/cn/enaium/joe/util/MessageUtil.java index 2939e2c..a950d0b 100644 --- a/src/main/java/cn/enaium/joe/util/MessageUtil.java +++ b/src/main/java/cn/enaium/joe/util/MessageUtil.java @@ -32,6 +32,7 @@ public class MessageUtil { public static void error(Throwable e) { + e.printStackTrace(); new OptionDialog(LangUtil.i18n("error"), new JScrollPane(new JTextArea() {{ StringWriter out = new StringWriter(); e.printStackTrace(new PrintWriter(out)); diff --git a/src/main/java/cn/enaium/joe/util/ReflectUtil.java b/src/main/java/cn/enaium/joe/util/ReflectUtil.java index 65cde6a..f5b71a1 100644 --- a/src/main/java/cn/enaium/joe/util/ReflectUtil.java +++ b/src/main/java/cn/enaium/joe/util/ReflectUtil.java @@ -24,11 +24,20 @@ * @since 1.0.0 */ public class ReflectUtil { - public static void setAll(T old, T t) throws NoSuchFieldException, IllegalAccessException { - for (Field oldField : old.getClass().getDeclaredFields()) { + /** + * copy all class member from the old class object to the new class object + * + * @param oldObject old object + * @param newObject new object + * @param type of two classes + * @throws NoSuchFieldException e + * @throws IllegalAccessException e + */ + public static void copyAllMember(T oldObject, T newObject) throws NoSuchFieldException, IllegalAccessException { + for (Field oldField : oldObject.getClass().getDeclaredFields()) { oldField.setAccessible(true); - Field declaredField = t.getClass().getDeclaredField(oldField.getName()); - oldField.set(old, declaredField.get(t)); + Field declaredField = newObject.getClass().getDeclaredField(oldField.getName()); + oldField.set(oldObject, declaredField.get(newObject)); } } diff --git a/src/main/java/cn/enaium/joe/util/Util.java b/src/main/java/cn/enaium/joe/util/Util.java index e35fb75..41bf359 100644 --- a/src/main/java/cn/enaium/joe/util/Util.java +++ b/src/main/java/cn/enaium/joe/util/Util.java @@ -49,7 +49,12 @@ public static boolean isText(byte[] bytes) { } public static Dimension screenSize(int width, int height) { + return screenSize(new Dimension(width, height)); + } + + public static Dimension screenSize(Dimension dimension) { Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); - return new Dimension((int) (width * screenSize.getWidth() / 1920), (int) (height * screenSize.getHeight() / 1080)); + return new Dimension((int) (dimension.width * screenSize.getWidth() / 1920), (int) (dimension.height * screenSize.getHeight() / 1080)); } + } From 12def6c7ceca4c874dedd350d99193f4a505295f Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 14 Oct 2022 15:05:58 +0800 Subject: [PATCH 22/49] decompile and compile --- .../tabbed/tab/classes/DecompileTabPanel.java | 22 ++++++++++++++++--- .../tab/classes/TraceBytecodeTabPanel.java | 1 + .../joe/service/decompiler/CFRDecompiler.java | 7 ++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/DecompileTabPanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/DecompileTabPanel.java index fa97d17..f5b8239 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/DecompileTabPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/DecompileTabPanel.java @@ -17,13 +17,17 @@ package cn.enaium.joe.gui.panel.file.tabbed.tab.classes; import cn.enaium.joe.JavaOctetEditor; -import cn.enaium.joe.service.DecompileService; +import cn.enaium.joe.compiler.Compiler; import cn.enaium.joe.gui.panel.CodeAreaPanel; import cn.enaium.joe.task.DecompileTask; -import cn.enaium.joe.util.ASyncUtil; +import cn.enaium.joe.util.*; +import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; +import javax.swing.*; import java.awt.*; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; /** * @author Enaium @@ -32,7 +36,19 @@ public class DecompileTabPanel extends ClassNodeTabPanel { public DecompileTabPanel(ClassNode classNode) { super(classNode); setLayout(new BorderLayout()); - CodeAreaPanel codeAreaPanel = new CodeAreaPanel(); + CodeAreaPanel codeAreaPanel = new CodeAreaPanel() {{ + KeyStrokeUtil.register(getTextArea(), KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK), () -> { + try { + Compiler compiler = new Compiler(); + compiler.addSource(ASMUtil.getReferenceName(classNode), getTextArea().getText()); + compiler.compile(); + ReflectUtil.copyAllMember(classNode, ASMUtil.acceptClassNode(new ClassReader(compiler.getClasses().get(ASMUtil.getReferenceName(classNode))))); + MessageUtil.info(LangUtil.i18n("success")); + } catch (Throwable e) { + MessageUtil.error(e); + } + }); + }}; codeAreaPanel.getTextArea().setSyntaxEditingStyle("text/java"); JavaOctetEditor.getInstance().task.submit(new DecompileTask(classNode)).thenAccept(it -> { codeAreaPanel.getTextArea().setText(it); diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/TraceBytecodeTabPanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/TraceBytecodeTabPanel.java index c22b910..b4c62b9 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/TraceBytecodeTabPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/TraceBytecodeTabPanel.java @@ -34,6 +34,7 @@ public TraceBytecodeTabPanel(ClassNode classNode) { super(classNode); setLayout(new BorderLayout()); CodeAreaPanel codeAreaPanel = new CodeAreaPanel(); + codeAreaPanel.getTextArea().setEditable(false); codeAreaPanel.getTextArea().setSyntaxEditingStyle("text/custom"); final StringWriter stringWriter = new StringWriter(); ASyncUtil.execute(() -> { diff --git a/src/main/java/cn/enaium/joe/service/decompiler/CFRDecompiler.java b/src/main/java/cn/enaium/joe/service/decompiler/CFRDecompiler.java index d604494..b289db2 100644 --- a/src/main/java/cn/enaium/joe/service/decompiler/CFRDecompiler.java +++ b/src/main/java/cn/enaium/joe/service/decompiler/CFRDecompiler.java @@ -56,6 +56,13 @@ public Pair getClassFileContent(String path) throws IOException ClassWriter classWriter = new ClassWriter(0); classNode.accept(classWriter); return Pair.make(classWriter.toByteArray(), name); + } else { + ClassNode cn = JavaOctetEditor.getInstance().getJar().classes.get(path); + if (cn != null) { + ClassWriter classWriter = new ClassWriter(0); + cn.accept(classWriter); + return Pair.make(classWriter.toByteArray(), name); + } } return null; } From c45f8f25ce717113a143d0a51a1838e88c80d390 Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 14 Oct 2022 15:07:34 +0800 Subject: [PATCH 23/49] Update CodeAreaPanel.java --- src/main/java/cn/enaium/joe/gui/panel/CodeAreaPanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/cn/enaium/joe/gui/panel/CodeAreaPanel.java b/src/main/java/cn/enaium/joe/gui/panel/CodeAreaPanel.java index 2e5a097..3c88a2b 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/CodeAreaPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/CodeAreaPanel.java @@ -57,8 +57,8 @@ public CodeAreaPanel() { Font defaultFont = RTextArea.getDefaultFont(); Font font = defaultFont.deriveFont((float) UIManager.getFont("defaultFont").getSize()); textArea.setFont(font); - textArea.setPaintMatchedBracketPair( true ); - textArea.setAnimateBracketMatching( false ); + textArea.setPaintMatchedBracketPair(true); + textArea.setAnimateBracketMatching(false); JToolBar toolBar = new JToolBar(); From a008446fe1f179cfc8a3b9c8ed38f51175835a39 Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 14 Oct 2022 15:42:26 +0800 Subject: [PATCH 24/49] i18n --- src/main/resources/lang/en_US.json | 2 +- src/main/resources/lang/zh_CN.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/lang/en_US.json b/src/main/resources/lang/en_US.json index 3d548e9..681ce8f 100644 --- a/src/main/resources/lang/en_US.json +++ b/src/main/resources/lang/en_US.json @@ -64,7 +64,7 @@ "class.info.description": "Description:", "class.info.exceptions": "Exceptions:", "class.tab.bytecodeView": "BytecodeView", - "class.tab.decompileView": "DecompileView", + "class.tab.decompileEdit": "DecompileEdit", "class.tab.visitorEdit": "VisitorEdit", "class.tab.infoEdit": "InfoEdit", "button.search": "Search", diff --git a/src/main/resources/lang/zh_CN.json b/src/main/resources/lang/zh_CN.json index b449a95..d353894 100644 --- a/src/main/resources/lang/zh_CN.json +++ b/src/main/resources/lang/zh_CN.json @@ -64,7 +64,7 @@ "class.info.description": "描述:", "class.info.exceptions": "异常:", "class.tab.bytecodeView": "字节码查看", - "class.tab.decompileView": "反编译查看", + "class.tab.decompileEdit": "反编译编辑", "class.tab.visitorEdit": "访问者编辑", "class.tab.infoEdit": "信息编辑", "button.search": "搜索", From 8e908febf865b2643a7ff550e9d2421f2d6a80c4 Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 14 Oct 2022 15:43:28 +0800 Subject: [PATCH 25/49] tab index consistent --- .../file/tabbed/tab/classes/ClassTabPanel.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ClassTabPanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ClassTabPanel.java index 6519e52..846b861 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ClassTabPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ClassTabPanel.java @@ -16,11 +16,16 @@ package cn.enaium.joe.gui.panel.file.tabbed.tab.classes; +import cn.enaium.joe.JavaOctetEditor; +import cn.enaium.joe.event.Event; import cn.enaium.joe.util.LangUtil; import org.objectweb.asm.tree.ClassNode; import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; import java.awt.*; +import java.util.function.Consumer; /** * @author Enaium @@ -35,9 +40,19 @@ public ClassTabPanel(ClassNode classNode) { JTabbedPane jTabbedPane = new JTabbedPane(); jTabbedPane.setTabPlacement(JTabbedPane.BOTTOM); jTabbedPane.addTab(LangUtil.i18n("class.tab.bytecodeView"), new TraceBytecodeTabPanel(classNode)); - jTabbedPane.addTab(LangUtil.i18n("class.tab.decompileView"), new DecompileTabPanel(classNode)); + jTabbedPane.addTab(LangUtil.i18n("class.tab.decompileEdit"), new DecompileTabPanel(classNode)); jTabbedPane.addTab(LangUtil.i18n("class.tab.visitorEdit"), new ASMifierTablePanel(classNode)); jTabbedPane.addTab(LangUtil.i18n("class.tab.infoEdit"), new ClassInfoTabPanel(classNode)); + jTabbedPane.addChangeListener(e -> JavaOctetEditor.getInstance().event.call(new Change(jTabbedPane.getSelectedIndex()))); + JavaOctetEditor.getInstance().event.register(Change.class, (Consumer) event -> jTabbedPane.setSelectedIndex(event.index)); add(jTabbedPane); } + + private static class Change implements Event { + private final int index; + + public Change(int index) { + this.index = index; + } + } } \ No newline at end of file From 6cc4d2f7dfe6ec6842a928c17dc59978797e19f0 Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 14 Oct 2022 15:43:45 +0800 Subject: [PATCH 26/49] dialog --- .../cn/enaium/joe/dialog/ContactDialog.java | 1 + .../cn/enaium/joe/dialog/OptionDialog.java | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main/java/cn/enaium/joe/dialog/ContactDialog.java b/src/main/java/cn/enaium/joe/dialog/ContactDialog.java index e779b35..9e8fe04 100644 --- a/src/main/java/cn/enaium/joe/dialog/ContactDialog.java +++ b/src/main/java/cn/enaium/joe/dialog/ContactDialog.java @@ -51,6 +51,7 @@ public void addLink(JPanel panel, String name, Icon icon, String link) { panel.add(new JLabel(icon)); panel.add(new JLabel(name)); panel.add(new JLabel("" + link + "") {{ + setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { diff --git a/src/main/java/cn/enaium/joe/dialog/OptionDialog.java b/src/main/java/cn/enaium/joe/dialog/OptionDialog.java index f0621fd..0b4f7dd 100644 --- a/src/main/java/cn/enaium/joe/dialog/OptionDialog.java +++ b/src/main/java/cn/enaium/joe/dialog/OptionDialog.java @@ -18,6 +18,7 @@ import cn.enaium.joe.gui.panel.BorderPanel; import cn.enaium.joe.gui.panel.confirm.ConfirmPanel; +import cn.enaium.joe.util.Util; import javax.swing.*; import javax.swing.border.EmptyBorder; @@ -61,15 +62,22 @@ public OptionDialog(String title, Object message, int type, Runnable confirm, Ru } else { content = ((Component) message); } - setTop(new BorderPanel() {{ - setLeft(new JLabel(getIconForType(type))); - setCenter(content); - }}); + setLeft(new JLabel(getIconForType(type))); + setCenter(content); } setBottom(bottom); }}); setModal(true); - pack(); + Dimension size = Util.screenSize(getPreferredSize()); + if (size.width > getWidth()) { + size.width = getWidth(); + } + + if (size.height > getHeight()) { + size.height = getHeight(); + } + setMinimumSize(size); + setSize(size); } public OptionDialog(String title, Object message, int type) { From c39207ad5f5b35dd5f3645bc65c03c8cf94e2abc Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 14 Oct 2022 15:43:49 +0800 Subject: [PATCH 27/49] Update Compiler.java --- src/main/java/cn/enaium/joe/compiler/Compiler.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/cn/enaium/joe/compiler/Compiler.java b/src/main/java/cn/enaium/joe/compiler/Compiler.java index e7ad2e5..b9207bf 100644 --- a/src/main/java/cn/enaium/joe/compiler/Compiler.java +++ b/src/main/java/cn/enaium/joe/compiler/Compiler.java @@ -67,7 +67,6 @@ public VirtualFileManager(JavaFileManager fileManager) { public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException { if (JavaFileObject.Kind.CLASS == kind) { VirtualJavaFileObject virtualJavaFileObject = new VirtualJavaFileObject(className, null); - System.out.println(className); javaFileObjectMap.put(className, virtualJavaFileObject); return virtualJavaFileObject; } else { From a910897f98fba66508fb70b9582da474f50b348a Mon Sep 17 00:00:00 2001 From: Enaium Date: Sun, 16 Oct 2022 15:10:03 +0800 Subject: [PATCH 28/49] Update build.gradle --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6738999..32bae46 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ plugins { } group 'cn.enaium' -version '1.4.0-beta.2' +version '1.4.0-beta.3' sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8 From b5d77a3ae403442eeebf2016abe242a3dba930c2 Mon Sep 17 00:00:00 2001 From: Enaium Date: Sun, 16 Oct 2022 15:10:09 +0800 Subject: [PATCH 29/49] classTabIndex --- src/main/java/cn/enaium/joe/Instance.java | 6 ++++++ .../gui/panel/file/tabbed/tab/classes/ClassTabPanel.java | 9 ++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 src/main/java/cn/enaium/joe/Instance.java diff --git a/src/main/java/cn/enaium/joe/Instance.java b/src/main/java/cn/enaium/joe/Instance.java new file mode 100644 index 0000000..2859c8d --- /dev/null +++ b/src/main/java/cn/enaium/joe/Instance.java @@ -0,0 +1,6 @@ +package cn.enaium.joe; + +public enum Instance { + INSTANCE; + public int classTabIndex = 0; +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ClassTabPanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ClassTabPanel.java index 846b861..57a59f3 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ClassTabPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ClassTabPanel.java @@ -18,12 +18,11 @@ import cn.enaium.joe.JavaOctetEditor; import cn.enaium.joe.event.Event; +import cn.enaium.joe.Instance; import cn.enaium.joe.util.LangUtil; import org.objectweb.asm.tree.ClassNode; import javax.swing.*; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; import java.awt.*; import java.util.function.Consumer; @@ -43,7 +42,11 @@ public ClassTabPanel(ClassNode classNode) { jTabbedPane.addTab(LangUtil.i18n("class.tab.decompileEdit"), new DecompileTabPanel(classNode)); jTabbedPane.addTab(LangUtil.i18n("class.tab.visitorEdit"), new ASMifierTablePanel(classNode)); jTabbedPane.addTab(LangUtil.i18n("class.tab.infoEdit"), new ClassInfoTabPanel(classNode)); - jTabbedPane.addChangeListener(e -> JavaOctetEditor.getInstance().event.call(new Change(jTabbedPane.getSelectedIndex()))); + jTabbedPane.setSelectedIndex(Instance.INSTANCE.classTabIndex); + jTabbedPane.addChangeListener(e -> { + Instance.INSTANCE.classTabIndex = jTabbedPane.getSelectedIndex(); + JavaOctetEditor.getInstance().event.call(new Change(jTabbedPane.getSelectedIndex())); + }); JavaOctetEditor.getInstance().event.register(Change.class, (Consumer) event -> jTabbedPane.setSelectedIndex(event.index)); add(jTabbedPane); } From 469bd3363e4e9c54b41d19821822a7f7ddb72700 Mon Sep 17 00:00:00 2001 From: Enaium Date: Sun, 16 Oct 2022 15:10:50 +0800 Subject: [PATCH 30/49] Update ClassTabPanel.java --- .../joe/gui/panel/file/tabbed/tab/classes/ClassTabPanel.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ClassTabPanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ClassTabPanel.java index 57a59f3..1e173b8 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ClassTabPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ClassTabPanel.java @@ -43,10 +43,7 @@ public ClassTabPanel(ClassNode classNode) { jTabbedPane.addTab(LangUtil.i18n("class.tab.visitorEdit"), new ASMifierTablePanel(classNode)); jTabbedPane.addTab(LangUtil.i18n("class.tab.infoEdit"), new ClassInfoTabPanel(classNode)); jTabbedPane.setSelectedIndex(Instance.INSTANCE.classTabIndex); - jTabbedPane.addChangeListener(e -> { - Instance.INSTANCE.classTabIndex = jTabbedPane.getSelectedIndex(); - JavaOctetEditor.getInstance().event.call(new Change(jTabbedPane.getSelectedIndex())); - }); + jTabbedPane.addChangeListener(e -> JavaOctetEditor.getInstance().event.call(new Change(Instance.INSTANCE.classTabIndex = jTabbedPane.getSelectedIndex()))); JavaOctetEditor.getInstance().event.register(Change.class, (Consumer) event -> jTabbedPane.setSelectedIndex(event.index)); add(jTabbedPane); } From 542c92ce5de06201df2b531a03c1674af353ea45 Mon Sep 17 00:00:00 2001 From: Enaium Date: Sun, 16 Oct 2022 15:29:43 +0800 Subject: [PATCH 31/49] add message --- .../tabbed/tab/classes/DecompileTabPanel.java | 8 ++++++-- .../java/cn/enaium/joe/util/MessageUtil.java | 16 ++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/DecompileTabPanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/DecompileTabPanel.java index f5b8239..4eb9ced 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/DecompileTabPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/DecompileTabPanel.java @@ -42,8 +42,12 @@ public DecompileTabPanel(ClassNode classNode) { Compiler compiler = new Compiler(); compiler.addSource(ASMUtil.getReferenceName(classNode), getTextArea().getText()); compiler.compile(); - ReflectUtil.copyAllMember(classNode, ASMUtil.acceptClassNode(new ClassReader(compiler.getClasses().get(ASMUtil.getReferenceName(classNode))))); - MessageUtil.info(LangUtil.i18n("success")); + if (compiler.getClasses().get(ASMUtil.getReferenceName(classNode)).length != 0) { + ReflectUtil.copyAllMember(classNode, ASMUtil.acceptClassNode(new ClassReader(compiler.getClasses().get(ASMUtil.getReferenceName(classNode))))); + MessageUtil.info(LangUtil.i18n("success")); + } else { + MessageUtil.error(new RuntimeException("Compile failed,Please check console")); + } } catch (Throwable e) { MessageUtil.error(e); } diff --git a/src/main/java/cn/enaium/joe/util/MessageUtil.java b/src/main/java/cn/enaium/joe/util/MessageUtil.java index a950d0b..fb8d6d8 100644 --- a/src/main/java/cn/enaium/joe/util/MessageUtil.java +++ b/src/main/java/cn/enaium/joe/util/MessageUtil.java @@ -17,6 +17,7 @@ package cn.enaium.joe.util; import cn.enaium.joe.dialog.OptionDialog; +import cn.enaium.joe.gui.panel.BorderPanel; import cn.enaium.joe.gui.panel.confirm.ConfirmPanel; import org.pmw.tinylog.Logger; @@ -33,12 +34,15 @@ public class MessageUtil { public static void error(Throwable e) { e.printStackTrace(); - new OptionDialog(LangUtil.i18n("error"), new JScrollPane(new JTextArea() {{ - StringWriter out = new StringWriter(); - e.printStackTrace(new PrintWriter(out)); - setText(out.toString()); - setEditable(false); - }}), JOptionPane.ERROR_MESSAGE).setVisible(true); + new OptionDialog(LangUtil.i18n("error"), new BorderPanel() {{ + setTop(new JLabel(e.getMessage())); + setCenter(new JScrollPane(new JTextArea() {{ + StringWriter out = new StringWriter(); + e.printStackTrace(new PrintWriter(out)); + setText(out.toString()); + setEditable(false); + }})); + }}, JOptionPane.ERROR_MESSAGE).setVisible(true); } public static void confirm(Object message, String title, Runnable yes, Runnable no) { From 95f613481ab46d72a0dc1f5a552ad2413bad6137 Mon Sep 17 00:00:00 2001 From: Enaium Date: Thu, 24 Nov 2022 15:19:02 +0800 Subject: [PATCH 32/49] gson --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 32bae46..a38a97b 100644 --- a/build.gradle +++ b/build.gradle @@ -50,7 +50,7 @@ dependencies { implementation 'org.benf:cfr:0.152' implementation 'com.github.mstrobel.procyon:procyon-decompiler:v0.6.0' implementation 'org.quiltmc:quiltflower:1.8.1' - implementation 'com.google.code.gson:gson:2.9.0' + implementation 'com.google.code.gson:gson:2.10' implementation 'org.tinylog:tinylog:1.3.6' implementation 'com.github.FabricMC:mapping-io:597f0722d6' From 5a383caa2c9843c1959bb8898fec6c975beb1611 Mon Sep 17 00:00:00 2001 From: Enaium Date: Thu, 24 Nov 2022 15:19:17 +0800 Subject: [PATCH 33/49] fix integer value --- src/main/java/cn/enaium/joe/dialog/ConfigDialog.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/cn/enaium/joe/dialog/ConfigDialog.java b/src/main/java/cn/enaium/joe/dialog/ConfigDialog.java index 36b348a..00dfabb 100644 --- a/src/main/java/cn/enaium/joe/dialog/ConfigDialog.java +++ b/src/main/java/cn/enaium/joe/dialog/ConfigDialog.java @@ -25,10 +25,8 @@ import net.miginfocom.swing.MigLayout; import javax.swing.*; -import javax.swing.border.EmptyBorder; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; -import java.awt.*; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.lang.reflect.Field; @@ -85,6 +83,7 @@ public void changedUpdate(DocumentEvent e) { } else if (o instanceof IntegerValue) { IntegerValue integerValue = (IntegerValue) o; add(new JSpinner() {{ + setValue(integerValue.getValue()); addChangeListener(e -> integerValue.setValue(Integer.parseInt(getValue().toString()))); }}, "wrap"); } else if (o instanceof EnableValue) { From 1a8d6fb9fbc02f0934bb048057ff5da6bf5253ec Mon Sep 17 00:00:00 2001 From: Enaium Date: Thu, 24 Nov 2022 15:19:37 +0800 Subject: [PATCH 34/49] fix size --- src/main/java/cn/enaium/joe/dialog/OptionDialog.java | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/main/java/cn/enaium/joe/dialog/OptionDialog.java b/src/main/java/cn/enaium/joe/dialog/OptionDialog.java index 0b4f7dd..c367472 100644 --- a/src/main/java/cn/enaium/joe/dialog/OptionDialog.java +++ b/src/main/java/cn/enaium/joe/dialog/OptionDialog.java @@ -68,16 +68,8 @@ public OptionDialog(String title, Object message, int type, Runnable confirm, Ru setBottom(bottom); }}); setModal(true); - Dimension size = Util.screenSize(getPreferredSize()); - if (size.width > getWidth()) { - size.width = getWidth(); - } - - if (size.height > getHeight()) { - size.height = getHeight(); - } - setMinimumSize(size); - setSize(size); + pack(); + setMinimumSize(getSize()); } public OptionDialog(String title, Object message, int type) { From 58a2ec021192ccdd7d89ce89422bacb8fbc228c4 Mon Sep 17 00:00:00 2001 From: Enaium Date: Thu, 24 Nov 2022 15:20:05 +0800 Subject: [PATCH 35/49] add ui scale --- .../java/cn/enaium/joe/JavaOctetEditor.java | 20 +++++++++++++++---- src/main/java/cn/enaium/joe/Main.java | 3 +-- .../joe/config/extend/ApplicationConfig.java | 2 ++ 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/main/java/cn/enaium/joe/JavaOctetEditor.java b/src/main/java/cn/enaium/joe/JavaOctetEditor.java index a2f821f..a6b6682 100644 --- a/src/main/java/cn/enaium/joe/JavaOctetEditor.java +++ b/src/main/java/cn/enaium/joe/JavaOctetEditor.java @@ -17,6 +17,7 @@ package cn.enaium.joe; import cn.enaium.joe.config.ConfigManager; +import cn.enaium.joe.config.extend.ApplicationConfig; import cn.enaium.joe.event.EventManager; import cn.enaium.joe.gui.panel.BorderPanel; import cn.enaium.joe.gui.panel.BottomPanel; @@ -27,6 +28,7 @@ import cn.enaium.joe.jar.Jar; import cn.enaium.joe.task.TaskManager; import cn.enaium.joe.util.*; +import com.formdev.flatlaf.FlatDarkLaf; import com.formdev.flatlaf.extras.FlatSVGIcon; import org.fife.ui.rsyntaxtextarea.AbstractTokenMakerFactory; import org.fife.ui.rsyntaxtextarea.TokenMakerFactory; @@ -43,7 +45,7 @@ public class JavaOctetEditor { public static final String TITLE = "JavaOctetEditor"; - public JFrame window = new JFrame(TITLE); + public JFrame window; private Jar jar; @@ -61,12 +63,22 @@ public class JavaOctetEditor { public JavaOctetEditor() { - instance = this; event = new EventManager(); config = new ConfigManager(); config.load(); task = new TaskManager(); Runtime.getRuntime().addShutdownHook(new Thread(config::save)); + + Integer value = config.getByClass(ApplicationConfig.class).scale.getValue(); + + if (value > 0) { + System.setProperty("sun.java2d.uiScale", value.toString()); + } + + FlatDarkLaf.setup(); + UIManager.put("Tree.paintLines", true); + + instance = this; fileTabbedPanel = new FileTabbedPanel(); fileTree = new FileTree(); bottomPanel = new BottomPanel(); @@ -75,10 +87,10 @@ public JavaOctetEditor() { public void run() { ToolTipManager.sharedInstance().setInitialDelay(0); - + FlatDarkLaf.setup(); AbstractTokenMakerFactory abstractTokenMakerFactory = (AbstractTokenMakerFactory) TokenMakerFactory.getDefaultInstance(); abstractTokenMakerFactory.putMapping("text/custom", BytecodeTokenMaker.class.getName()); - + window = new JFrame(TITLE); window.setIconImage(new FlatSVGIcon("icons/logo.svg").getImage()); window.setJMenuBar(new JMenuBar() {{ diff --git a/src/main/java/cn/enaium/joe/Main.java b/src/main/java/cn/enaium/joe/Main.java index b08c32f..6451817 100644 --- a/src/main/java/cn/enaium/joe/Main.java +++ b/src/main/java/cn/enaium/joe/Main.java @@ -16,6 +16,7 @@ package cn.enaium.joe; +import cn.enaium.joe.config.extend.ApplicationConfig; import cn.enaium.joe.jar.Jar; import cn.enaium.joe.util.IOUtil; import cn.enaium.joe.util.MessageUtil; @@ -80,8 +81,6 @@ private static void launch() { System.setErr(new TinyLogPrintStream(System.err, STDERR)); Logger.info("DIR:{}", System.getProperty("user.dir")); - FlatDarkLaf.setup(); - UIManager.put("Tree.paintLines", true); new JavaOctetEditor().run(); } diff --git a/src/main/java/cn/enaium/joe/config/extend/ApplicationConfig.java b/src/main/java/cn/enaium/joe/config/extend/ApplicationConfig.java index 0539e4e..546a23d 100644 --- a/src/main/java/cn/enaium/joe/config/extend/ApplicationConfig.java +++ b/src/main/java/cn/enaium/joe/config/extend/ApplicationConfig.java @@ -19,6 +19,7 @@ import cn.enaium.joe.annotation.NoUI; import cn.enaium.joe.config.Config; import cn.enaium.joe.config.value.EnableValue; +import cn.enaium.joe.config.value.IntegerValue; import cn.enaium.joe.config.value.ModeValue; import cn.enaium.joe.config.value.StringSetValue; @@ -37,6 +38,7 @@ public class ApplicationConfig extends Config { public EnableValue compactMiddlePackage = new EnableValue("Compact Middle Package", true, "Only Hierarchical Mode"); @NoUI public final StringSetValue loadRecent = new StringSetValue("Load Recent", new HashSet<>(), ""); + public IntegerValue scale = new IntegerValue("Scale", 0, "UI scale,it doesn't scale if value 0"); public ApplicationConfig() { super("Application"); From a7a86e9a165432eebb4905d8ebe47f0b189890a8 Mon Sep 17 00:00:00 2001 From: Enaium Date: Thu, 24 Nov 2022 15:28:54 +0800 Subject: [PATCH 36/49] flatlaf --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index a38a97b..8a0c25e 100644 --- a/build.gradle +++ b/build.gradle @@ -39,8 +39,8 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' - implementation 'com.formdev:flatlaf:2.5' - implementation 'com.formdev:flatlaf-extras:2.5' + implementation 'com.formdev:flatlaf:2.6' + implementation 'com.formdev:flatlaf-extras:2.6' //noinspection GradlePackageUpdate implementation 'com.miglayout:miglayout-swing:5.3' implementation 'com.github.bobbylight:RSyntaxTextArea:3.2.0' From 711970706ce20e4c795017f59bd347c1e7a882b9 Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 25 Nov 2022 11:49:00 +0800 Subject: [PATCH 37/49] version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8a0c25e..f1f5ab8 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ plugins { } group 'cn.enaium' -version '1.4.0-beta.3' +version '1.4.0-beta.4' sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8 From 033ff1e8fc80ed3fb2a78730729f0476ecda13a6 Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 25 Nov 2022 11:51:25 +0800 Subject: [PATCH 38/49] key --- .../cn/enaium/joe/config/ConfigManager.java | 20 +++--- .../joe/config/extend/KeymapConfig.java | 44 +++++++++++++ .../cn/enaium/joe/config/value/KeyValue.java | 9 +++ .../cn/enaium/joe/config/value/Value.java | 4 +- .../panel/method/MethodInstructionPanel.java | 61 ++++++++++++------ .../cn/enaium/joe/util/KeyStrokeUtil.java | 62 ++++++++++++++++--- src/main/java/cn/enaium/joe/util/Util.java | 10 +++ 7 files changed, 171 insertions(+), 39 deletions(-) create mode 100644 src/main/java/cn/enaium/joe/config/extend/KeymapConfig.java create mode 100644 src/main/java/cn/enaium/joe/config/value/KeyValue.java diff --git a/src/main/java/cn/enaium/joe/config/ConfigManager.java b/src/main/java/cn/enaium/joe/config/ConfigManager.java index 33e9ae6..6cb9166 100644 --- a/src/main/java/cn/enaium/joe/config/ConfigManager.java +++ b/src/main/java/cn/enaium/joe/config/ConfigManager.java @@ -16,19 +16,16 @@ package cn.enaium.joe.config; -import cn.enaium.joe.config.extend.ApplicationConfig; -import cn.enaium.joe.config.extend.CFRConfig; -import cn.enaium.joe.config.extend.FernFlowerConfig; -import cn.enaium.joe.config.extend.ProcyonConfig; +import cn.enaium.joe.config.extend.*; import cn.enaium.joe.config.value.*; import cn.enaium.joe.util.MessageUtil; -import cn.enaium.joe.util.ReflectUtil; import com.google.gson.*; -import com.google.gson.annotations.Expose; +import javax.swing.*; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; +import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.*; @@ -45,6 +42,7 @@ public ConfigManager() { setByClass(new CFRConfig()); setByClass(new FernFlowerConfig()); setByClass(new ProcyonConfig()); + setByClass(new KeymapConfig()); } @SuppressWarnings("unchecked") @@ -83,8 +81,8 @@ public Map getConfigMap(Class config) { return map; } - private Gson gson() { - return new GsonBuilder().setPrettyPrinting().create(); + private GsonBuilder gson() { + return new GsonBuilder().setPrettyPrinting().disableHtmlEscaping(); } public void load() { @@ -95,7 +93,7 @@ public void load() { try { File file = new File(System.getProperty("."), config.getName() + ".json"); if (file.exists()) { - JsonObject jsonObject = gson().fromJson(new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8), JsonObject.class); + JsonObject jsonObject = gson().create().fromJson(new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8), JsonObject.class); for (Field configField : klass.getDeclaredFields()) { configField.setAccessible(true); @@ -135,6 +133,8 @@ public void load() { ((StringSetValue) value).setValue(strings); } else if (value instanceof StringValue) { ((StringValue) value).setValue(valueJsonElement.getAsString()); + } else if (value instanceof KeyValue) { + ((KeyValue) value).setValue(KeyStroke.getKeyStroke(valueJsonElement.getAsString())); } } } @@ -148,7 +148,7 @@ public void load() { public void save() { for (Config value : configMap.values()) { try { - Files.write(new File(System.getProperty("."), value.getName() + ".json").toPath(), gson().toJson(value).getBytes(StandardCharsets.UTF_8)); + Files.write(new File(System.getProperty("."), value.getName() + ".json").toPath(), gson().registerTypeAdapter(KeyStroke.class, (JsonSerializer) (src, typeOfSrc, context) -> new JsonPrimitive(src.toString())).create().toJson(value).getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { MessageUtil.error(e); } diff --git a/src/main/java/cn/enaium/joe/config/extend/KeymapConfig.java b/src/main/java/cn/enaium/joe/config/extend/KeymapConfig.java new file mode 100644 index 0000000..024fc5b --- /dev/null +++ b/src/main/java/cn/enaium/joe/config/extend/KeymapConfig.java @@ -0,0 +1,44 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.config.extend; + +import cn.enaium.joe.config.Config; +import cn.enaium.joe.config.value.KeyValue; + +import javax.swing.*; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +/** + * @author Enaium + * @since 1.4.0 + */ +public class KeymapConfig extends Config { + + public KeyValue edit = new KeyValue("Edit", KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "Edit method instruction"); + public KeyValue clone = new KeyValue("Clone", KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.CTRL_DOWN_MASK), "Clone method instruction"); + public KeyValue remove = new KeyValue("Remove", KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK), "Remove method instruction"); + public KeyValue copy = new KeyValue("Copy", KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK), "Copy method instruction text"); + public KeyValue insertBefore = new KeyValue("InsertBefore", KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.CTRL_DOWN_MASK | InputEvent.ALT_DOWN_MASK), "Insert method instruction before current"); + public KeyValue insertAfter = new KeyValue("InsertAfter", KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.CTRL_DOWN_MASK), "Insert method instruction after current"); + public KeyValue moveUp = new KeyValue("Move Up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK), "Move method instruction up"); + public KeyValue moveDown = new KeyValue("Move Up", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK), "Move method instruction down"); + + public KeymapConfig() { + super("Keymap"); + } +} diff --git a/src/main/java/cn/enaium/joe/config/value/KeyValue.java b/src/main/java/cn/enaium/joe/config/value/KeyValue.java new file mode 100644 index 0000000..031b8f5 --- /dev/null +++ b/src/main/java/cn/enaium/joe/config/value/KeyValue.java @@ -0,0 +1,9 @@ +package cn.enaium.joe.config.value; + +import javax.swing.*; + +public class KeyValue extends Value { + public KeyValue(String name, KeyStroke value, String description) { + super(name, value, description); + } +} diff --git a/src/main/java/cn/enaium/joe/config/value/Value.java b/src/main/java/cn/enaium/joe/config/value/Value.java index d27d490..7112d5e 100644 --- a/src/main/java/cn/enaium/joe/config/value/Value.java +++ b/src/main/java/cn/enaium/joe/config/value/Value.java @@ -21,9 +21,9 @@ * @since 0.7.0 */ public class Value { - private String name; + private final String name; private T value; - private String description; + private final String description; public Value(String name, T value, String description) { this.name = name; diff --git a/src/main/java/cn/enaium/joe/gui/panel/method/MethodInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/method/MethodInstructionPanel.java index dd25d31..883fc27 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/method/MethodInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/method/MethodInstructionPanel.java @@ -16,6 +16,8 @@ package cn.enaium.joe.gui.panel.method; +import cn.enaium.joe.JavaOctetEditor; +import cn.enaium.joe.config.extend.KeymapConfig; import cn.enaium.joe.gui.component.InstructionComboBox; import cn.enaium.joe.gui.panel.confirm.InstructionEditPanel; import cn.enaium.joe.util.*; @@ -27,6 +29,7 @@ import javax.swing.*; import java.awt.*; import java.awt.datatransfer.StringSelection; +import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; @@ -42,6 +45,7 @@ public MethodInstructionPanel(MethodNode methodNode) { super(new BorderLayout()); DefaultListModel instructionDefaultListModel = new DefaultListModel<>(); JList instructionJList = new JList<>(instructionDefaultListModel); + instructionJList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); instructionJList.setPrototypeCellValue(new InstructionWrapper(null)); instructionJList.setCellRenderer((list, value, index, isSelected, cellHasFocus) -> new JPanel(new BorderLayout()) {{ if (isSelected) { @@ -57,17 +61,21 @@ public MethodInstructionPanel(MethodNode methodNode) { } JPopupMenu jPopupMenu = new JPopupMenu(); + KeymapConfig keymapConfig = JavaOctetEditor.getInstance().config.getByClass(KeymapConfig.class); jPopupMenu.add(new JMenuItem(LangUtil.i18n("popup.instruction.edit")) {{ - addActionListener(e -> { + Runnable runnable = () -> { InstructionWrapper selectedValue = instructionJList.getSelectedValue(); if (selectedValue != null && !(selectedValue.getWrapper() instanceof LabelNode)) { MessageUtil.confirm(new InstructionEditPanel(selectedValue.getWrapper()), LangUtil.i18n("popup.instruction.edit")); } - }); + }; + KeyStrokeUtil.register(instructionJList, keymapConfig.edit.getValue(), runnable); + setAccelerator(keymapConfig.edit.getValue()); + addActionListener(Util.ofAction(runnable)); }}); jPopupMenu.add(new JMenuItem(LangUtil.i18n("popup.instruction.clone")) {{ - addActionListener(e -> { + Runnable runnable = () -> { InstructionWrapper selectedValue = instructionJList.getSelectedValue(); if (instructionJList.getSelectedIndex() != -1 || selectedValue != null) { AbstractInsnNode clone; @@ -80,11 +88,14 @@ public MethodInstructionPanel(MethodNode methodNode) { instructionDefaultListModel.add(instructionJList.getSelectedIndex() + 1, new InstructionWrapper(clone)); methodNode.instructions.insert(selectedValue.getWrapper(), clone); } - }); + }; + KeyStrokeUtil.register(instructionJList, keymapConfig.clone.getValue(), runnable); + setAccelerator(keymapConfig.clone.getValue()); + addActionListener(Util.ofAction(runnable)); }}); jPopupMenu.add(new JMenuItem(LangUtil.i18n("popup.instructions.remove")) {{ - addActionListener(e -> { + Runnable runnable = () -> { InstructionWrapper selectedValue = instructionJList.getSelectedValue(); if (instructionJList.getSelectedIndex() != -1 || selectedValue != null) { MessageUtil.confirm(LangUtil.i18n("dialog.wantRemove"), LangUtil.i18n("button.remove"), () -> { @@ -92,40 +103,50 @@ public MethodInstructionPanel(MethodNode methodNode) { methodNode.instructions.remove(selectedValue.getWrapper()); }); } - }); + }; + KeyStrokeUtil.register(instructionJList, keymapConfig.remove.getValue(), runnable); + setAccelerator(keymapConfig.remove.getValue()); + addActionListener(Util.ofAction(runnable)); }}); jPopupMenu.add(new JMenuItem(LangUtil.i18n("popup.instructions.copyText")) {{ - addActionListener(e -> { + Runnable runnable = () -> { InstructionWrapper selectedValue = instructionJList.getSelectedValue(); if (instructionJList.getSelectedIndex() != -1 || selectedValue != null) { Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(HtmlUtil.remove(selectedValue.toString())), null); } - }); + }; + KeyStrokeUtil.register(instructionJList, keymapConfig.copy.getValue(), runnable); + setAccelerator(keymapConfig.copy.getValue()); + addActionListener(Util.ofAction(runnable)); }}); jPopupMenu.add(new JMenuItem(LangUtil.i18n("popup.instructions.insertBefore")) {{ - addActionListener(e -> { - insert(methodNode, instructionJList, true); - }); + Runnable runnable = () -> insert(methodNode, instructionJList, true); + KeyStrokeUtil.register(instructionJList, keymapConfig.insertBefore.getValue(), runnable); + setAccelerator(keymapConfig.insertBefore.getValue()); + addActionListener(Util.ofAction(runnable)); }}); jPopupMenu.add(new JMenuItem(LangUtil.i18n("popup.instructions.insertAfter")) {{ - addActionListener(e -> { - insert(methodNode, instructionJList, false); - }); + Runnable runnable = () -> insert(methodNode, instructionJList, false); + KeyStrokeUtil.register(instructionJList, keymapConfig.insertAfter.getValue(), runnable); + setAccelerator(keymapConfig.insertAfter.getValue()); + addActionListener(Util.ofAction(runnable)); }}); jPopupMenu.add(new JMenuItem(LangUtil.i18n("popup.instructions.moveUp")) {{ - addActionListener(e -> { - moveInstruction(instructionJList, methodNode, true); - }); + Runnable runnable = () -> moveInstruction(instructionJList, methodNode, true); + KeyStrokeUtil.register(instructionJList, keymapConfig.moveUp.getValue(), runnable); + setAccelerator(keymapConfig.moveUp.getValue()); + addActionListener(Util.ofAction(runnable)); }}); jPopupMenu.add(new JMenuItem(LangUtil.i18n("popup.instructions.moveDown")) {{ - addActionListener(e -> { - moveInstruction(instructionJList, methodNode, false); - }); + Runnable runnable = () -> moveInstruction(instructionJList, methodNode, false); + KeyStrokeUtil.register(instructionJList, keymapConfig.moveDown.getValue(), runnable); + setAccelerator(keymapConfig.moveDown.getValue()); + addActionListener(Util.ofAction(runnable)); }}); JMenuUtil.addPopupMenu(instructionJList, () -> jPopupMenu, () -> instructionJList.getSelectedValue() != null); diff --git a/src/main/java/cn/enaium/joe/util/KeyStrokeUtil.java b/src/main/java/cn/enaium/joe/util/KeyStrokeUtil.java index d9a15e5..9631d8d 100644 --- a/src/main/java/cn/enaium/joe/util/KeyStrokeUtil.java +++ b/src/main/java/cn/enaium/joe/util/KeyStrokeUtil.java @@ -20,6 +20,7 @@ import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; +import java.lang.reflect.Field; import java.util.concurrent.atomic.AtomicInteger; /** @@ -30,16 +31,63 @@ public class KeyStrokeUtil { private static final AtomicInteger ATOMIC_INTEGER = new AtomicInteger(0); - public static void register(JComponent component, KeyStroke keyStroke, Runnable action) { + public static void register(JComponent component, KeyStroke keyStroke, Runnable runnable) { String key = String.valueOf(ATOMIC_INTEGER.incrementAndGet()); InputMap inputMap = component.getInputMap(JComponent.WHEN_FOCUSED); inputMap.put(keyStroke, key); ActionMap actionMap = component.getActionMap(); - actionMap.put(key, new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - action.run(); - } - }); + actionMap.put(key, Util.ofAction(runnable)); } +// +// public static int getKey(String name) { +// for (Field field : KeyEvent.class.getFields()) { +// if (field.getName().equals(name)) { +// try { +// return field.getInt(null); +// } catch (IllegalAccessException e) { +// MessageUtil.error(e); +// } +// } +// } +// throw new RuntimeException(String.format("%s not found", name)); +// } +// +// public static String getKeyName(int key) { +// for (Field field : KeyEvent.class.getFields()) { +// try { +// if (field.getInt(null) == key) { +// return field.getName(); +// } +// } catch (IllegalAccessException e) { +// MessageUtil.error(e); +// } +// } +// throw new RuntimeException(String.format("%s not found", key)); +// } +// +// public static int getInput(String name) { +// for (Field field : InputEvent.class.getFields()) { +// if (field.getName().equals(name)) { +// try { +// return field.getInt(null); +// } catch (IllegalAccessException e) { +// MessageUtil.error(e); +// } +// } +// } +// throw new RuntimeException(String.format("%s not found", name)); +// } +// +// public static String getInputName(int key) { +// for (Field field : InputEvent.class.getFields()) { +// try { +// if (field.getInt(null) == key) { +// return field.getName(); +// } +// } catch (IllegalAccessException e) { +// MessageUtil.error(e); +// } +// } +// throw new RuntimeException(String.format("%s not found", key)); +// } } diff --git a/src/main/java/cn/enaium/joe/util/Util.java b/src/main/java/cn/enaium/joe/util/Util.java index 41bf359..eb85583 100644 --- a/src/main/java/cn/enaium/joe/util/Util.java +++ b/src/main/java/cn/enaium/joe/util/Util.java @@ -16,7 +16,9 @@ package cn.enaium.joe.util; +import javax.swing.*; import java.awt.*; +import java.awt.event.ActionEvent; import java.util.Enumeration; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -57,4 +59,12 @@ public static Dimension screenSize(Dimension dimension) { return new Dimension((int) (dimension.width * screenSize.getWidth() / 1920), (int) (dimension.height * screenSize.getHeight() / 1080)); } + public static AbstractAction ofAction(Runnable runnable) { + return new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + runnable.run(); + } + }; + } } From 429b76473101a1d6bca95416a83af31795baa134 Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 25 Nov 2022 14:38:35 +0800 Subject: [PATCH 39/49] key config --- .../java/cn/enaium/joe/dialog/ConfigDialog.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/java/cn/enaium/joe/dialog/ConfigDialog.java b/src/main/java/cn/enaium/joe/dialog/ConfigDialog.java index 00dfabb..9494588 100644 --- a/src/main/java/cn/enaium/joe/dialog/ConfigDialog.java +++ b/src/main/java/cn/enaium/joe/dialog/ConfigDialog.java @@ -27,6 +27,9 @@ import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; +import java.awt.*; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.lang.reflect.Field; @@ -109,6 +112,20 @@ public void changedUpdate(DocumentEvent e) { }); } }}, "wrap"); + } else if (o instanceof KeyValue) { + KeyValue keyValue = (KeyValue) o; + add(new JButton(keyValue.getValue().toString()) {{ + addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyChar() != 65535) { + KeyStroke newKey = KeyStroke.getKeyStroke(e.getKeyCode(), e.getModifiers()); + keyValue.setValue(newKey); + setText(newKey.toString()); + } + } + }); + }}, "wrap"); } } } catch (IllegalAccessException e) { From 4f8eb36a21232e7e7efd7702c2679ce1e9a27108 Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 25 Nov 2022 14:43:21 +0800 Subject: [PATCH 40/49] layout --- .../instruction/AbstractInstructionPanel.java | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/main/java/cn/enaium/joe/gui/panel/instruction/AbstractInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/instruction/AbstractInstructionPanel.java index fd1805d..124e7d5 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/instruction/AbstractInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/instruction/AbstractInstructionPanel.java @@ -18,6 +18,7 @@ import cn.enaium.joe.util.LangUtil; import cn.enaium.joe.util.OpcodeUtil; +import net.miginfocom.swing.MigLayout; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.InsnList; @@ -34,34 +35,21 @@ */ public abstract class AbstractInstructionPanel extends JPanel { private final JComboBox opcode = new JComboBox<>(new DefaultComboBoxModel<>()); - - private final JPanel names = new JPanel(new GridLayout(0, 1)); - private final JPanel components = new JPanel(new GridLayout(0, 1)); - private Callable confirm = () -> false; public AbstractInstructionPanel(AbstractInsnNode instruction) { - setLayout(new BorderLayout()); + setLayout(new MigLayout("fillx", "[fill][fill]")); if (instruction.getOpcode() != -1) { DefaultComboBoxModel model = (DefaultComboBoxModel) opcode.getModel(); getOpcodes().forEach(model::addElement); model.setSelectedItem(OpcodeUtil.OPCODE.get(instruction.getOpcode())); addComponent(new JLabel(LangUtil.i18n("instruction.opcode")), opcode); } - - add(names, BorderLayout.WEST); - add(components, BorderLayout.CENTER); } public void addComponent(JComponent name, JComponent component) { - names.add(new JPanel(new BorderLayout()) {{ - setBorder(new EmptyBorder(10, 10, 10, 10)); - add(name, BorderLayout.CENTER); - }}); - components.add(new JPanel(new BorderLayout()) {{ - setBorder(new EmptyBorder(10, 10, 10, 10)); - add(component, BorderLayout.CENTER); - }}); + add(name); + add(component, "wrap"); } public void setConfirm(Callable callable) { From ea66ba9bdb1d6b743e5f34a4c8a9e052aa8f0ab1 Mon Sep 17 00:00:00 2001 From: Enaium Date: Fri, 25 Nov 2022 14:50:48 +0800 Subject: [PATCH 41/49] key --- .../joe/config/extend/KeymapConfig.java | 1 + .../tab/classes/ASMifierTablePanel.java | 4 +- .../tabbed/tab/classes/DecompileTabPanel.java | 3 +- .../tabbed/tab/resources/TextTablePanel.java | 3 +- .../cn/enaium/joe/util/KeyStrokeUtil.java | 52 ------------------- 5 files changed, 8 insertions(+), 55 deletions(-) diff --git a/src/main/java/cn/enaium/joe/config/extend/KeymapConfig.java b/src/main/java/cn/enaium/joe/config/extend/KeymapConfig.java index 024fc5b..f3262ac 100644 --- a/src/main/java/cn/enaium/joe/config/extend/KeymapConfig.java +++ b/src/main/java/cn/enaium/joe/config/extend/KeymapConfig.java @@ -37,6 +37,7 @@ public class KeymapConfig extends Config { public KeyValue insertAfter = new KeyValue("InsertAfter", KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.CTRL_DOWN_MASK), "Insert method instruction after current"); public KeyValue moveUp = new KeyValue("Move Up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK), "Move method instruction up"); public KeyValue moveDown = new KeyValue("Move Up", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK), "Move method instruction down"); + public KeyValue save = new KeyValue("Save", KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK), "Save something"); public KeymapConfig() { super("Keymap"); diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java index f7786f8..5c566c8 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/ASMifierTablePanel.java @@ -16,7 +16,9 @@ package cn.enaium.joe.gui.panel.file.tabbed.tab.classes; +import cn.enaium.joe.JavaOctetEditor; import cn.enaium.joe.compiler.Compiler; +import cn.enaium.joe.config.extend.KeymapConfig; import cn.enaium.joe.gui.panel.CodeAreaPanel; import cn.enaium.joe.util.*; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; @@ -40,7 +42,7 @@ public ASMifierTablePanel(ClassNode classNode) { super(classNode); setLayout(new BorderLayout()); CodeAreaPanel codeAreaPanel = new CodeAreaPanel() {{ - KeyStrokeUtil.register(getTextArea(), KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK), () -> { + KeyStrokeUtil.register(getTextArea(), JavaOctetEditor.getInstance().config.getByClass(KeymapConfig.class).save.getValue(), () -> { try { String stringBuilder = "import org.objectweb.asm.AnnotationVisitor;" + "import org.objectweb.asm.Attribute;" + diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/DecompileTabPanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/DecompileTabPanel.java index 4eb9ced..c4d3037 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/DecompileTabPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/classes/DecompileTabPanel.java @@ -18,6 +18,7 @@ import cn.enaium.joe.JavaOctetEditor; import cn.enaium.joe.compiler.Compiler; +import cn.enaium.joe.config.extend.KeymapConfig; import cn.enaium.joe.gui.panel.CodeAreaPanel; import cn.enaium.joe.task.DecompileTask; import cn.enaium.joe.util.*; @@ -37,7 +38,7 @@ public DecompileTabPanel(ClassNode classNode) { super(classNode); setLayout(new BorderLayout()); CodeAreaPanel codeAreaPanel = new CodeAreaPanel() {{ - KeyStrokeUtil.register(getTextArea(), KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK), () -> { + KeyStrokeUtil.register(getTextArea(), JavaOctetEditor.getInstance().config.getByClass(KeymapConfig.class).save.getValue(), () -> { try { Compiler compiler = new Compiler(); compiler.addSource(ASMUtil.getReferenceName(classNode), getTextArea().getText()); diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/resources/TextTablePanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/resources/TextTablePanel.java index 41bc470..5abfa01 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/resources/TextTablePanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/resources/TextTablePanel.java @@ -17,6 +17,7 @@ package cn.enaium.joe.gui.panel.file.tabbed.tab.resources; import cn.enaium.joe.JavaOctetEditor; +import cn.enaium.joe.config.extend.KeymapConfig; import cn.enaium.joe.gui.panel.BorderPanel; import cn.enaium.joe.gui.panel.CodeAreaPanel; import cn.enaium.joe.gui.panel.file.tree.node.FileTreeNode; @@ -55,7 +56,7 @@ public TextTablePanel(FileTreeNode fileTreeNode) { getTextArea().setSyntaxEditingStyle(syntax); getTextArea().setText(new String(fileTreeNode.getData(), StandardCharsets.UTF_8)); - KeyStrokeUtil.register(getTextArea(), KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK), () -> { + KeyStrokeUtil.register(getTextArea(), JavaOctetEditor.getInstance().config.getByClass(KeymapConfig.class).save.getValue(), () -> { fileTreeNode.setData(getTextArea().getText().getBytes(StandardCharsets.UTF_8)); MessageUtil.info(LangUtil.i18n("success")); }); diff --git a/src/main/java/cn/enaium/joe/util/KeyStrokeUtil.java b/src/main/java/cn/enaium/joe/util/KeyStrokeUtil.java index 9631d8d..baf7665 100644 --- a/src/main/java/cn/enaium/joe/util/KeyStrokeUtil.java +++ b/src/main/java/cn/enaium/joe/util/KeyStrokeUtil.java @@ -38,56 +38,4 @@ public static void register(JComponent component, KeyStroke keyStroke, Runnable ActionMap actionMap = component.getActionMap(); actionMap.put(key, Util.ofAction(runnable)); } -// -// public static int getKey(String name) { -// for (Field field : KeyEvent.class.getFields()) { -// if (field.getName().equals(name)) { -// try { -// return field.getInt(null); -// } catch (IllegalAccessException e) { -// MessageUtil.error(e); -// } -// } -// } -// throw new RuntimeException(String.format("%s not found", name)); -// } -// -// public static String getKeyName(int key) { -// for (Field field : KeyEvent.class.getFields()) { -// try { -// if (field.getInt(null) == key) { -// return field.getName(); -// } -// } catch (IllegalAccessException e) { -// MessageUtil.error(e); -// } -// } -// throw new RuntimeException(String.format("%s not found", key)); -// } -// -// public static int getInput(String name) { -// for (Field field : InputEvent.class.getFields()) { -// if (field.getName().equals(name)) { -// try { -// return field.getInt(null); -// } catch (IllegalAccessException e) { -// MessageUtil.error(e); -// } -// } -// } -// throw new RuntimeException(String.format("%s not found", name)); -// } -// -// public static String getInputName(int key) { -// for (Field field : InputEvent.class.getFields()) { -// try { -// if (field.getInt(null) == key) { -// return field.getName(); -// } -// } catch (IllegalAccessException e) { -// MessageUtil.error(e); -// } -// } -// throw new RuntimeException(String.format("%s not found", key)); -// } } From 7e95e35e55def9063271a84fabf161027babf4f2 Mon Sep 17 00:00:00 2001 From: Enaium Date: Sat, 26 Nov 2022 09:17:25 +0800 Subject: [PATCH 42/49] key --- .../panel/method/MethodInstructionPanel.java | 133 +++++++----------- src/main/resources/lang/en_US.json | 4 +- src/main/resources/lang/zh_CN.json | 4 +- 3 files changed, 52 insertions(+), 89 deletions(-) diff --git a/src/main/java/cn/enaium/joe/gui/panel/method/MethodInstructionPanel.java b/src/main/java/cn/enaium/joe/gui/panel/method/MethodInstructionPanel.java index 883fc27..1e27b65 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/method/MethodInstructionPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/method/MethodInstructionPanel.java @@ -20,6 +20,7 @@ import cn.enaium.joe.config.extend.KeymapConfig; import cn.enaium.joe.gui.component.InstructionComboBox; import cn.enaium.joe.gui.panel.confirm.InstructionEditPanel; +import cn.enaium.joe.util.Util; import cn.enaium.joe.util.*; import cn.enaium.joe.wrapper.InstructionWrapper; import org.objectweb.asm.Handle; @@ -29,11 +30,6 @@ import javax.swing.*; import java.awt.*; import java.awt.datatransfer.StringSelection; -import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.ArrayList; import java.util.HashMap; /** @@ -62,97 +58,64 @@ public MethodInstructionPanel(MethodNode methodNode) { JPopupMenu jPopupMenu = new JPopupMenu(); KeymapConfig keymapConfig = JavaOctetEditor.getInstance().config.getByClass(KeymapConfig.class); - jPopupMenu.add(new JMenuItem(LangUtil.i18n("popup.instruction.edit")) {{ - Runnable runnable = () -> { - InstructionWrapper selectedValue = instructionJList.getSelectedValue(); - if (selectedValue != null && !(selectedValue.getWrapper() instanceof LabelNode)) { - MessageUtil.confirm(new InstructionEditPanel(selectedValue.getWrapper()), LangUtil.i18n("popup.instruction.edit")); - } - }; - KeyStrokeUtil.register(instructionJList, keymapConfig.edit.getValue(), runnable); - setAccelerator(keymapConfig.edit.getValue()); - addActionListener(Util.ofAction(runnable)); - }}); - jPopupMenu.add(new JMenuItem(LangUtil.i18n("popup.instruction.clone")) {{ - Runnable runnable = () -> { - InstructionWrapper selectedValue = instructionJList.getSelectedValue(); - if (instructionJList.getSelectedIndex() != -1 || selectedValue != null) { - AbstractInsnNode clone; - if (selectedValue.getWrapper() instanceof LabelNode) { - clone = new LabelNode(); - } else { - clone = selectedValue.getWrapper().clone(new HashMap<>()); - } - - instructionDefaultListModel.add(instructionJList.getSelectedIndex() + 1, new InstructionWrapper(clone)); - methodNode.instructions.insert(selectedValue.getWrapper(), clone); - } - }; - KeyStrokeUtil.register(instructionJList, keymapConfig.clone.getValue(), runnable); - setAccelerator(keymapConfig.clone.getValue()); - addActionListener(Util.ofAction(runnable)); - }}); + addItem(instructionJList, jPopupMenu, LangUtil.i18n("popup.instructions.edit"), () -> { + InstructionWrapper selectedValue = instructionJList.getSelectedValue(); + if (selectedValue != null && !(selectedValue.getWrapper() instanceof LabelNode)) { + MessageUtil.confirm(new InstructionEditPanel(selectedValue.getWrapper()), LangUtil.i18n("popup.instructions.edit")); + } + }, keymapConfig.edit.getValue()); - jPopupMenu.add(new JMenuItem(LangUtil.i18n("popup.instructions.remove")) {{ - Runnable runnable = () -> { - InstructionWrapper selectedValue = instructionJList.getSelectedValue(); - if (instructionJList.getSelectedIndex() != -1 || selectedValue != null) { - MessageUtil.confirm(LangUtil.i18n("dialog.wantRemove"), LangUtil.i18n("button.remove"), () -> { - instructionDefaultListModel.remove(instructionJList.getSelectedIndex()); - methodNode.instructions.remove(selectedValue.getWrapper()); - }); - } - }; - KeyStrokeUtil.register(instructionJList, keymapConfig.remove.getValue(), runnable); - setAccelerator(keymapConfig.remove.getValue()); - addActionListener(Util.ofAction(runnable)); - }}); - jPopupMenu.add(new JMenuItem(LangUtil.i18n("popup.instructions.copyText")) {{ - Runnable runnable = () -> { - InstructionWrapper selectedValue = instructionJList.getSelectedValue(); - if (instructionJList.getSelectedIndex() != -1 || selectedValue != null) { - Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(HtmlUtil.remove(selectedValue.toString())), null); + addItem(instructionJList, jPopupMenu, LangUtil.i18n("popup.instructions.clone"), () -> { + InstructionWrapper selectedValue = instructionJList.getSelectedValue(); + if (instructionJList.getSelectedIndex() != -1 || selectedValue != null) { + AbstractInsnNode clone; + if (selectedValue.getWrapper() instanceof LabelNode) { + clone = new LabelNode(); + } else { + clone = selectedValue.getWrapper().clone(new HashMap<>()); } - }; - KeyStrokeUtil.register(instructionJList, keymapConfig.copy.getValue(), runnable); - setAccelerator(keymapConfig.copy.getValue()); - addActionListener(Util.ofAction(runnable)); - }}); - jPopupMenu.add(new JMenuItem(LangUtil.i18n("popup.instructions.insertBefore")) {{ - Runnable runnable = () -> insert(methodNode, instructionJList, true); - KeyStrokeUtil.register(instructionJList, keymapConfig.insertBefore.getValue(), runnable); - setAccelerator(keymapConfig.insertBefore.getValue()); - addActionListener(Util.ofAction(runnable)); - }}); - - jPopupMenu.add(new JMenuItem(LangUtil.i18n("popup.instructions.insertAfter")) {{ - Runnable runnable = () -> insert(methodNode, instructionJList, false); - KeyStrokeUtil.register(instructionJList, keymapConfig.insertAfter.getValue(), runnable); - setAccelerator(keymapConfig.insertAfter.getValue()); - addActionListener(Util.ofAction(runnable)); - }}); + instructionDefaultListModel.add(instructionJList.getSelectedIndex() + 1, new InstructionWrapper(clone)); + methodNode.instructions.insert(selectedValue.getWrapper(), clone); + } + }, keymapConfig.clone.getValue()); + + addItem(instructionJList, jPopupMenu, LangUtil.i18n("popup.instructions.remove"), () -> { + InstructionWrapper selectedValue = instructionJList.getSelectedValue(); + if (instructionJList.getSelectedIndex() != -1 || selectedValue != null) { + MessageUtil.confirm(LangUtil.i18n("dialog.wantRemove"), LangUtil.i18n("button.remove"), () -> { + instructionDefaultListModel.remove(instructionJList.getSelectedIndex()); + methodNode.instructions.remove(selectedValue.getWrapper()); + }); + } + }, keymapConfig.remove.getValue()); - jPopupMenu.add(new JMenuItem(LangUtil.i18n("popup.instructions.moveUp")) {{ - Runnable runnable = () -> moveInstruction(instructionJList, methodNode, true); - KeyStrokeUtil.register(instructionJList, keymapConfig.moveUp.getValue(), runnable); - setAccelerator(keymapConfig.moveUp.getValue()); - addActionListener(Util.ofAction(runnable)); - }}); + addItem(instructionJList, jPopupMenu, LangUtil.i18n("popup.instructions.copyText"), () -> { + InstructionWrapper selectedValue = instructionJList.getSelectedValue(); + if (instructionJList.getSelectedIndex() != -1 || selectedValue != null) { + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(HtmlUtil.remove(selectedValue.toString())), null); + } + }, keymapConfig.copy.getValue()); - jPopupMenu.add(new JMenuItem(LangUtil.i18n("popup.instructions.moveDown")) {{ - Runnable runnable = () -> moveInstruction(instructionJList, methodNode, false); - KeyStrokeUtil.register(instructionJList, keymapConfig.moveDown.getValue(), runnable); - setAccelerator(keymapConfig.moveDown.getValue()); - addActionListener(Util.ofAction(runnable)); - }}); + addItem(instructionJList, jPopupMenu, LangUtil.i18n("popup.instructions.insertBefore"), () -> insert(methodNode, instructionJList, true), keymapConfig.insertBefore.getValue()); + addItem(instructionJList, jPopupMenu, LangUtil.i18n("popup.instructions.insertAfter"), () -> insert(methodNode, instructionJList, false), keymapConfig.insertAfter.getValue()); + addItem(instructionJList, jPopupMenu, LangUtil.i18n("popup.instructions.moveUp"), () -> moveInstruction(instructionJList, methodNode, true), keymapConfig.insertAfter.getValue()); + addItem(instructionJList, jPopupMenu, LangUtil.i18n("popup.instructions.moveDown"), () -> moveInstruction(instructionJList, methodNode, false), keymapConfig.insertAfter.getValue()); JMenuUtil.addPopupMenu(instructionJList, () -> jPopupMenu, () -> instructionJList.getSelectedValue() != null); add(new JScrollPane(instructionJList), BorderLayout.CENTER); } + private void addItem(JList instructionJList, JPopupMenu jPopupMenu, String text, Runnable runnable, KeyStroke key) { + jPopupMenu.add(new JMenuItem(text) {{ + KeyStrokeUtil.register(instructionJList, key, runnable); + setAccelerator(key); + addActionListener(Util.ofAction(runnable)); + }}); + } + private static void moveInstruction(JList instructionJList, MethodNode methodNode, boolean up) { DefaultListModel instructionDefaultListModel = ((DefaultListModel) instructionJList.getModel()); InstructionWrapper selectedValue = instructionJList.getSelectedValue(); @@ -238,7 +201,7 @@ private static void insert(MethodNode methodNode, JList inst throw new RuntimeException(); } - MessageUtil.confirm(new InstructionEditPanel(abstractInsnNode), LangUtil.i18n("popup.instruction.edit"), () -> { + MessageUtil.confirm(new InstructionEditPanel(abstractInsnNode), LangUtil.i18n("popup.instructions.edit"), () -> { if (before) { methodNode.instructions.insertBefore(instructionJList.getSelectedValue().getWrapper(), abstractInsnNode); } else { diff --git a/src/main/resources/lang/en_US.json b/src/main/resources/lang/en_US.json index 681ce8f..b9fde23 100644 --- a/src/main/resources/lang/en_US.json +++ b/src/main/resources/lang/en_US.json @@ -36,8 +36,8 @@ "menu.help.contact": "Contact", "popup.attach.properties": "Properties", "popup.attach.external": "External", - "popup.instruction.edit": "Edit", - "popup.instruction.clone": "Clone", + "popup.instructions.edit": "Edit", + "popup.instructions.clone": "Clone", "popup.instructions.remove": "Remove", "popup.instructions.copyText": "Copy Text", "popup.instructions.insertBefore": "Insert Before", diff --git a/src/main/resources/lang/zh_CN.json b/src/main/resources/lang/zh_CN.json index d353894..be01105 100644 --- a/src/main/resources/lang/zh_CN.json +++ b/src/main/resources/lang/zh_CN.json @@ -36,8 +36,8 @@ "menu.help.contact": "联系", "popup.attach.external": "外部", "popup.attach.properties": "属性", - "popup.instruction.edit": "编辑", - "popup.instruction.clone": "克隆", + "popup.instructions.edit": "编辑", + "popup.instructions.clone": "克隆", "popup.instructions.remove": "移除", "popup.instructions.copyText": "复制文本", "popup.instructions.insertBefore": "前插入", From 9fcc6994d2e862937b8f9c9cc530c1d79ebf7ba0 Mon Sep 17 00:00:00 2001 From: Hileb <107909747+Ecdcaeb@users.noreply.github.com> Date: Sun, 24 Nov 2024 10:41:36 +0800 Subject: [PATCH 43/49] postMerge --- src/main/java/cn/enaium/joe/config/ConfigManager.java | 7 ++++--- .../cn/enaium/joe/service/decompiler/CFRDecompiler.java | 7 ++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/cn/enaium/joe/config/ConfigManager.java b/src/main/java/cn/enaium/joe/config/ConfigManager.java index f145879..2abe9e1 100644 --- a/src/main/java/cn/enaium/joe/config/ConfigManager.java +++ b/src/main/java/cn/enaium/joe/config/ConfigManager.java @@ -92,8 +92,9 @@ public Map> getConfigMap(Class config) { return map; } - private GsonBuilder gson() { - return new GsonBuilder().setPrettyPrinting().disableHtmlEscaping(); + private static final Gson GSON new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); + private Gson gson() { + return GSON; } public void load() { @@ -104,7 +105,7 @@ public void load() { try { File file = new File(System.getProperty("."), config.getName() + ".json"); if (file.exists()) { - JsonObject jsonObject = gson().create().fromJson(Files.readString(file.toPath()), JsonObject.class); + JsonObject jsonObject = gson().fromJson(Files.readString(file.toPath()), JsonObject.class); for (Field configField : klass.getDeclaredFields()) { configField.setAccessible(true); if (!jsonObject.has(configField.getName())) { diff --git a/src/main/java/cn/enaium/joe/service/decompiler/CFRDecompiler.java b/src/main/java/cn/enaium/joe/service/decompiler/CFRDecompiler.java index 1e726cf..6894bf1 100644 --- a/src/main/java/cn/enaium/joe/service/decompiler/CFRDecompiler.java +++ b/src/main/java/cn/enaium/joe/service/decompiler/CFRDecompiler.java @@ -55,11 +55,8 @@ public Pair getClassFileContent(String path) { if (name.equals(classNode.getInternalName())) { return Pair.make(classNode.getClassBytes(), name); } else { - ClassNode cn = JavaOctetEditor.getInstance().getJar().classes.get(path); - if (cn != null) { - ClassWriter classWriter = new ClassWriter(0); - cn.accept(classWriter); - return Pair.make(classWriter.toByteArray(), name); + if (JavaOctetEditor.getInstance().getJar().classes.get(path) != null) { + return Pair.make(ClassNode.of(JavaOctetEditor.getInstance().getJar().classes.get(path)).getClassBytes(), name); } } return null; From a66c1f026fc98c9e44599f7e6e541e04523f31b8 Mon Sep 17 00:00:00 2001 From: Hileb <107909747+Ecdcaeb@users.noreply.github.com> Date: Sun, 24 Nov 2024 10:45:09 +0800 Subject: [PATCH 44/49] = --- src/main/java/cn/enaium/joe/config/ConfigManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/cn/enaium/joe/config/ConfigManager.java b/src/main/java/cn/enaium/joe/config/ConfigManager.java index 2abe9e1..07de3ef 100644 --- a/src/main/java/cn/enaium/joe/config/ConfigManager.java +++ b/src/main/java/cn/enaium/joe/config/ConfigManager.java @@ -92,7 +92,7 @@ public Map> getConfigMap(Class config) { return map; } - private static final Gson GSON new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); private Gson gson() { return GSON; } From aa5a6d2c0d3b14785d6ccbb8eb2723de74bb7edb Mon Sep 17 00:00:00 2001 From: Hileb <107909747+Ecdcaeb@users.noreply.github.com> Date: Sun, 24 Nov 2024 10:49:14 +0800 Subject: [PATCH 45/49] KeyStroke value --- src/main/java/cn/enaium/joe/config/value/KeyValue.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/cn/enaium/joe/config/value/KeyValue.java b/src/main/java/cn/enaium/joe/config/value/KeyValue.java index 031b8f5..697790f 100644 --- a/src/main/java/cn/enaium/joe/config/value/KeyValue.java +++ b/src/main/java/cn/enaium/joe/config/value/KeyValue.java @@ -1,9 +1,9 @@ package cn.enaium.joe.config.value; -import javax.swing.*; +import javax.swing.KeyStroke; public class KeyValue extends Value { public KeyValue(String name, KeyStroke value, String description) { - super(name, value, description); + super(KeyStroke.class, name, value, description); } } From 7f8bb833fe7ec2f863b12fd56f9b7df3b8c6db81 Mon Sep 17 00:00:00 2001 From: Hileb <107909747+Ecdcaeb@users.noreply.github.com> Date: Sun, 24 Nov 2024 10:57:53 +0800 Subject: [PATCH 46/49] svg decoder --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 138d23f..0985c89 100644 --- a/build.gradle +++ b/build.gradle @@ -41,6 +41,7 @@ dependencies { implementation 'com.formdev:flatlaf:3.5.2' implementation 'com.formdev:flatlaf-extras:3.5.2' + implementation 'com.github.weisj:jsvg:1.6.1' //noinspection GradlePackageUpdate implementation 'com.miglayout:miglayout-swing:11.4.2' implementation 'com.github.bobbylight:RSyntaxTextArea:3.5.2' From 9f1e35b0a22d2b6b38b37ee2c6d421b802ae4aca Mon Sep 17 00:00:00 2001 From: Hileb <107909747+Ecdcaeb@users.noreply.github.com> Date: Sun, 24 Nov 2024 11:10:15 +0800 Subject: [PATCH 47/49] fixup --- src/main/java/cn/enaium/joe/JavaOctetEditor.java | 3 ++- src/main/java/cn/enaium/joe/config/ConfigManager.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/cn/enaium/joe/JavaOctetEditor.java b/src/main/java/cn/enaium/joe/JavaOctetEditor.java index a6b6682..f6fab23 100644 --- a/src/main/java/cn/enaium/joe/JavaOctetEditor.java +++ b/src/main/java/cn/enaium/joe/JavaOctetEditor.java @@ -63,6 +63,8 @@ public class JavaOctetEditor { public JavaOctetEditor() { + instance = this; + event = new EventManager(); config = new ConfigManager(); config.load(); @@ -78,7 +80,6 @@ public JavaOctetEditor() { FlatDarkLaf.setup(); UIManager.put("Tree.paintLines", true); - instance = this; fileTabbedPanel = new FileTabbedPanel(); fileTree = new FileTree(); bottomPanel = new BottomPanel(); diff --git a/src/main/java/cn/enaium/joe/config/ConfigManager.java b/src/main/java/cn/enaium/joe/config/ConfigManager.java index 07de3ef..4c07b33 100644 --- a/src/main/java/cn/enaium/joe/config/ConfigManager.java +++ b/src/main/java/cn/enaium/joe/config/ConfigManager.java @@ -112,7 +112,7 @@ public void load() { continue; } - if (!jsonObject.has(configField.getName())) { + if (!jsonObject.get(configField.getName()).isJsonObject()) { continue; } From 12441dae0dc9a771a092072bb56a7a7f87fc38c9 Mon Sep 17 00:00:00 2001 From: Hileb <107909747+Ecdcaeb@users.noreply.github.com> Date: Sun, 24 Nov 2024 11:16:06 +0800 Subject: [PATCH 48/49] impl --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 0985c89..41b0835 100644 --- a/build.gradle +++ b/build.gradle @@ -66,6 +66,7 @@ shadowJar { dependencies { include(dependency('com.formdev:.*')) include(dependency('com.miglayout:.*')) + include(dependency('com.github.weisj:.*')) include(dependency('com.github.bobbylight:RSyntaxTextArea')) include(dependency('org.ow2.asm:.*')) include(dependency('org.benf:cfr')) From 1984651b922959c03ea5a437f81facba4f4a3a7c Mon Sep 17 00:00:00 2001 From: Hileb <107909747+Ecdcaeb@users.noreply.github.com> Date: Sun, 24 Nov 2024 11:32:41 +0800 Subject: [PATCH 49/49] resetup config --- .../cn/enaium/joe/config/ConfigManager.java | 23 +------------------ .../enaium/joe/config/value/EnableValue.java | 7 ++++++ .../enaium/joe/config/value/IntegerValue.java | 7 ++++++ .../cn/enaium/joe/config/value/KeyValue.java | 13 +++++++++++ .../cn/enaium/joe/config/value/ModeValue.java | 10 ++++++++ .../joe/config/value/StringSetValue.java | 11 +++++++++ .../enaium/joe/config/value/StringValue.java | 7 ++++++ .../cn/enaium/joe/config/value/Value.java | 6 ++++- 8 files changed, 61 insertions(+), 23 deletions(-) diff --git a/src/main/java/cn/enaium/joe/config/ConfigManager.java b/src/main/java/cn/enaium/joe/config/ConfigManager.java index 4c07b33..47a6d10 100644 --- a/src/main/java/cn/enaium/joe/config/ConfigManager.java +++ b/src/main/java/cn/enaium/joe/config/ConfigManager.java @@ -125,28 +125,7 @@ public void load() { Object valueObject = configField.get(config); if (valueObject instanceof Value) { Value value = (Value) valueObject; - if (value instanceof EnableValue) { - ((EnableValue) value).setValue(valueJsonElement.getAsBoolean()); - } else if (value instanceof IntegerValue) { - ((IntegerValue) value).setValue(valueJsonElement.getAsInt()); - } else if (value instanceof ModeValue) { - ModeValue modeValue = (ModeValue) value; - if (modeValue.getMode().contains(valueJsonElement.getAsString())) { - modeValue.setValue(valueJsonElement.getAsString()); - } else { - modeValue.setValue(modeValue.getMode().get(0)); - } - } else if (value instanceof StringSetValue) { - Set strings = new HashSet<>(); - for (JsonElement jsonElement : valueJsonElement.getAsJsonArray()) { - strings.add(jsonElement.getAsString()); - } - ((StringSetValue) value).setValue(strings); - } else if (value instanceof StringValue) { - ((StringValue) value).setValue(valueJsonElement.getAsString()); - } else if (value instanceof KeyValue) { - ((KeyValue) value).setValue(KeyStroke.getKeyStroke(valueJsonElement.getAsString())); - } + value.decode(valueJsonElement); } } } diff --git a/src/main/java/cn/enaium/joe/config/value/EnableValue.java b/src/main/java/cn/enaium/joe/config/value/EnableValue.java index 8507e19..07d4817 100644 --- a/src/main/java/cn/enaium/joe/config/value/EnableValue.java +++ b/src/main/java/cn/enaium/joe/config/value/EnableValue.java @@ -16,6 +16,8 @@ package cn.enaium.joe.config.value; +import com.google.gson.JsonElement; + /** * @author Enaium * @since 0.7.0 @@ -24,4 +26,9 @@ public class EnableValue extends Value { public EnableValue(String name, Boolean value, String description) { super(Boolean.class, name, value, description); } + + @Override + public void decode(JsonElement jsonElement) { + this.setValue(jsonElement.getAsBoolean()); + } } diff --git a/src/main/java/cn/enaium/joe/config/value/IntegerValue.java b/src/main/java/cn/enaium/joe/config/value/IntegerValue.java index c76c6d5..958657a 100644 --- a/src/main/java/cn/enaium/joe/config/value/IntegerValue.java +++ b/src/main/java/cn/enaium/joe/config/value/IntegerValue.java @@ -16,6 +16,8 @@ package cn.enaium.joe.config.value; +import com.google.gson.JsonElement; + /** * @author Enaium * @since 0.7.0 @@ -24,4 +26,9 @@ public class IntegerValue extends Value { public IntegerValue(String name, Integer value, String description) { super(Integer.class, name, value, description); } + + @Override + public void decode(JsonElement jsonElement) { + this.setValue(jsonElement.getAsInt()); + } } diff --git a/src/main/java/cn/enaium/joe/config/value/KeyValue.java b/src/main/java/cn/enaium/joe/config/value/KeyValue.java index 697790f..c1492da 100644 --- a/src/main/java/cn/enaium/joe/config/value/KeyValue.java +++ b/src/main/java/cn/enaium/joe/config/value/KeyValue.java @@ -1,9 +1,22 @@ package cn.enaium.joe.config.value; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + import javax.swing.KeyStroke; public class KeyValue extends Value { public KeyValue(String name, KeyStroke value, String description) { super(KeyStroke.class, name, value, description); } + + @Override + public void decode(JsonElement jsonElement) { + if (jsonElement.isJsonObject()){ + JsonObject jsonObject = jsonElement.getAsJsonObject(); + this.setValue(KeyStroke.getKeyStroke(jsonObject.get("keyCode").getAsInt(), jsonObject.get("modifiers").getAsInt(), jsonObject.get("onKeyRelease").getAsBoolean())); + } else { + this.setValue(KeyStroke.getKeyStroke(jsonElement.getAsString())); + } + } } diff --git a/src/main/java/cn/enaium/joe/config/value/ModeValue.java b/src/main/java/cn/enaium/joe/config/value/ModeValue.java index ce099e1..a1a2b91 100644 --- a/src/main/java/cn/enaium/joe/config/value/ModeValue.java +++ b/src/main/java/cn/enaium/joe/config/value/ModeValue.java @@ -16,6 +16,7 @@ package cn.enaium.joe.config.value; +import com.google.gson.JsonElement; import com.google.gson.annotations.Expose; import java.util.List; @@ -41,4 +42,13 @@ public List getMode() { public void setMode(List mode) { this.mode = mode; } + + @Override + public void decode(JsonElement jsonElement) { + if (this.getMode().contains(jsonElement.getAsString())) { + this.setValue(jsonElement.getAsString()); + } else { + this.setValue(this.getMode().getFirst()); + } + } } diff --git a/src/main/java/cn/enaium/joe/config/value/StringSetValue.java b/src/main/java/cn/enaium/joe/config/value/StringSetValue.java index 48519a7..83114d7 100644 --- a/src/main/java/cn/enaium/joe/config/value/StringSetValue.java +++ b/src/main/java/cn/enaium/joe/config/value/StringSetValue.java @@ -16,9 +16,11 @@ package cn.enaium.joe.config.value; +import com.google.gson.JsonElement; import com.google.gson.reflect.TypeToken; import java.lang.reflect.Type; +import java.util.HashSet; import java.util.Set; /** @@ -30,4 +32,13 @@ public class StringSetValue extends Value>{ public StringSetValue(String name, Set value, String description) { super(TYPE, name, value, description); } + + @Override + public void decode(JsonElement jsonElement) { + Set strings = new HashSet<>(); + for (JsonElement element : jsonElement.getAsJsonArray()) { + strings.add(element.getAsString()); + } + this.setValue(strings); + } } diff --git a/src/main/java/cn/enaium/joe/config/value/StringValue.java b/src/main/java/cn/enaium/joe/config/value/StringValue.java index 3902e04..52268cf 100644 --- a/src/main/java/cn/enaium/joe/config/value/StringValue.java +++ b/src/main/java/cn/enaium/joe/config/value/StringValue.java @@ -16,6 +16,8 @@ package cn.enaium.joe.config.value; +import com.google.gson.JsonElement; + /** * @author Enaium * @since 0.7.0 @@ -24,4 +26,9 @@ public class StringValue extends Value { public StringValue(String name, String value, String description) { super(String.class, name, value, description); } + + @Override + public void decode(JsonElement jsonElement) { + this.setValue(jsonElement.getAsString()); + } } diff --git a/src/main/java/cn/enaium/joe/config/value/Value.java b/src/main/java/cn/enaium/joe/config/value/Value.java index f281580..21e0a1a 100644 --- a/src/main/java/cn/enaium/joe/config/value/Value.java +++ b/src/main/java/cn/enaium/joe/config/value/Value.java @@ -16,6 +16,8 @@ package cn.enaium.joe.config.value; +import com.google.gson.JsonElement; + import java.lang.reflect.Type; import java.util.HashSet; import java.util.Set; @@ -24,7 +26,7 @@ * @author Enaium * @since 0.7.0 */ -public class Value { +public abstract class Value { private transient final Type type; private final String name; private T value; @@ -62,6 +64,8 @@ public void setValue(T value) { } } + public abstract void decode(JsonElement jsonElement); + public void addListener(ConfigValueListener listener) { this.listeners.add(listener); }