├── .gitignore
├── .idea
├── .gitignore
├── encodings.xml
├── jpa-buddy.xml
├── misc.xml
├── uiDesigner.xml
└── vcs.xml
├── assets
├── demodiff.png
├── image-20230919170844682.png
├── image-20230919171001889.png
├── image-20230919171727105.png
├── image-20230926115942438.png
└── image-20230926120322733.png
├── pom.xml
├── readme-zh.md
├── readme.md
└── src
└── main
└── java
└── org
└── bridge
├── Config.java
├── Main.java
├── core
├── decompile
│ ├── Decompiler.java
│ └── JDCoreDecompiler.java
├── differ
│ └── DiffFileNodeInfo.java
├── filetree
│ ├── DeltaCommons.java
│ ├── FileTreeBuilder.java
│ ├── TreeComparator.java
│ ├── TreeDifference.java
│ ├── TreeNode.java
│ └── TreeUtils.java
└── services
│ ├── JarProcessor.java
│ ├── MakeDiffFileTree.java
│ └── TextSetter.java
└── gui
├── JarsChoosingDialog.form
├── JarsChoosingDialog.java
├── MainFrame.form
└── MainFrame.java
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 | !**/src/main/**/target/
4 | !**/src/test/**/target/
5 |
6 | ### IntelliJ IDEA ###
7 | .idea/modules.xml
8 | .idea/jarRepositories.xml
9 | .idea/compiler.xml
10 | .idea/libraries/
11 | *.iws
12 | *.iml
13 | *.ipr
14 |
15 | ### Eclipse ###
16 | .apt_generated
17 | .classpath
18 | .factorypath
19 | .project
20 | .settings
21 | .springBeans
22 | .sts4-cache
23 |
24 | ### NetBeans ###
25 | /nbproject/private/
26 | /nbbuild/
27 | /dist/
28 | /nbdist/
29 | /.nb-gradle/
30 | build/
31 | !**/src/main/**/build/
32 | !**/src/test/**/build/
33 |
34 | ### VS Code ###
35 | .vscode/
36 |
37 | ### Mac OS ###
38 | .DS_Store
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/jpa-buddy.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/.idea/uiDesigner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
7 |
8 | -
9 |
10 |
11 | -
12 |
13 |
14 | -
15 |
16 |
17 | -
18 |
19 |
20 |
21 |
22 |
23 | -
24 |
25 |
26 |
27 |
28 |
29 | -
30 |
31 |
32 |
33 |
34 |
35 | -
36 |
37 |
38 |
39 |
40 |
41 | -
42 |
43 |
44 |
45 |
46 | -
47 |
48 |
49 |
50 |
51 | -
52 |
53 |
54 |
55 |
56 | -
57 |
58 |
59 |
60 |
61 | -
62 |
63 |
64 |
65 |
66 | -
67 |
68 |
69 |
70 |
71 | -
72 |
73 |
74 | -
75 |
76 |
77 |
78 |
79 | -
80 |
81 |
82 |
83 |
84 | -
85 |
86 |
87 |
88 |
89 | -
90 |
91 |
92 |
93 |
94 | -
95 |
96 |
97 |
98 |
99 | -
100 |
101 |
102 | -
103 |
104 |
105 | -
106 |
107 |
108 | -
109 |
110 |
111 | -
112 |
113 |
114 |
115 |
116 | -
117 |
118 |
119 | -
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/assets/demodiff.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KingBridgeSS/jdifferer/7248742a33f63660e45881f8aed4c75037b03644/assets/demodiff.png
--------------------------------------------------------------------------------
/assets/image-20230919170844682.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KingBridgeSS/jdifferer/7248742a33f63660e45881f8aed4c75037b03644/assets/image-20230919170844682.png
--------------------------------------------------------------------------------
/assets/image-20230919171001889.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KingBridgeSS/jdifferer/7248742a33f63660e45881f8aed4c75037b03644/assets/image-20230919171001889.png
--------------------------------------------------------------------------------
/assets/image-20230919171727105.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KingBridgeSS/jdifferer/7248742a33f63660e45881f8aed4c75037b03644/assets/image-20230919171727105.png
--------------------------------------------------------------------------------
/assets/image-20230926115942438.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KingBridgeSS/jdifferer/7248742a33f63660e45881f8aed4c75037b03644/assets/image-20230926115942438.png
--------------------------------------------------------------------------------
/assets/image-20230926120322733.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KingBridgeSS/jdifferer/7248742a33f63660e45881f8aed4c75037b03644/assets/image-20230926120322733.png
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.bridge
8 | jdifferer
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 | org.apache.maven.plugins
14 | maven-assembly-plugin
15 | 3.3.0
16 |
17 |
18 |
19 | org.bridge.Main
20 |
21 |
22 |
23 | jar-with-dependencies
24 |
25 |
26 |
27 |
28 | package
29 |
30 | single
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | 8
39 | 8
40 | UTF-8
41 |
42 |
43 |
44 | JCenter
45 | JCenter
46 | https://jcenter.bintray.com/
47 |
48 |
49 |
50 |
51 |
52 | org.jd
53 | jd-core
54 | 1.1.3
55 |
56 |
57 |
58 | io.github.java-diff-utils
59 | java-diff-utils
60 | 4.12
61 |
62 |
63 |
64 | net.lingala.zip4j
65 | zip4j
66 | 2.11.5
67 |
68 |
69 |
70 | com.fifesoft
71 | rsyntaxtextarea
72 | 3.3.4
73 |
74 |
75 |
76 | commons-io
77 | commons-io
78 | 2.13.0
79 |
80 |
81 |
82 | com.intellij
83 | forms_rt
84 | 7.0.3
85 |
86 |
87 |
--------------------------------------------------------------------------------
/readme-zh.md:
--------------------------------------------------------------------------------
1 | # Jdifferer
2 |
3 | [English](readme.md) | [中文](readme-zh.md)
4 |
5 | Jdifferer是一个用来比较两个java jar文件的GUI应用,方便开发者和安全研究人员快速找到两个jar文件的不同。
6 |
7 | Jdifferer会自动对两个jar文件反编译,然后用友好的GUI界面显示源码层面上的不同。
8 |
9 | 反编译的API由[jd-core](https://github.com/java-decompiler/jd-core)提供。
10 |
11 | 
12 |
13 |
14 | ## Usage
15 |
16 | 点击左上角的Project -> open来选择需要比较的两个jar文件
17 |
18 | 在左边的侧边栏中提供三个子结点,分别代表两个jar文件的改动过的文件、增添的文件和删除的文件
19 |
20 | 
21 |
22 | 在update节点的窗口中,红色表示删除的内容,绿色表示增添的内容,黄色表示删除的内容。(下图仅供说明)
23 |
24 | 
25 |
26 | ## TODO
27 |
28 | - [x] filetree
29 | - [x] main gui
30 | - [x] dialog for choosing directory
31 | - [x] code highlight
32 | - [x] diff
33 | - [x] line wrap
34 | - [ ] auto expand
35 | - [x] error dialog
36 | - [ ] ctrl f
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Jdifferer
2 |
3 | [English](readme.md) | [中文](readme-zh.md)
4 |
5 | Jdifferer is a GUI application used to diff the code of two jars. It provides a convenient approach to compare the differences of jars file for developers and security researchers.
6 |
7 | Jdifferer can decompile the jar files automatically and provides a friendly GUI view to show the differences between the files in the aspect of source code.
8 |
9 | [jd-core](https://github.com/java-decompiler/jd-core) provides the decompiling APIs.
10 |
11 | 
12 |
13 |
14 | ## Usage
15 |
16 | Choose Project -> open on the top-left to choose the two jar files to diff.
17 |
18 | The sidebar on the left side provides three nodes, representing the updated, added and deleted files of the compared jar files, respectively.
19 |
20 | 
21 |
22 | When you choose one update node, red contents are deleted contents, green contents are added contents and yellow contents are updated contents. (image below is yet a demo)
23 |
24 | 
25 |
26 | ## TODO
27 |
28 | - [x] filetree
29 | - [x] main gui
30 | - [x] dialog for choosing directory
31 | - [x] code highlight
32 | - [x] diff
33 | - [x] line wrap
34 | - [ ] auto expand
35 | - [x] error dialog
36 | - [ ] ctrl f
37 |
38 |
--------------------------------------------------------------------------------
/src/main/java/org/bridge/Config.java:
--------------------------------------------------------------------------------
1 | package org.bridge;
2 |
3 | public class Config {
4 | public final static String tempDirName="Jdifferer";
5 | public final static String sourceDirName="SOURCE";
6 | public final static String revisedDirName="REVISED";
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/org/bridge/Main.java:
--------------------------------------------------------------------------------
1 | package org.bridge;
2 |
3 | import org.bridge.gui.MainFrame;
4 |
5 | public class Main {
6 | private static void printBanner() {
7 | String bannerString = "\n" +
8 | " ██╗██████╗ ██╗███████╗███████╗███████╗██████╗ ███████╗██████╗ \n" +
9 | " ██║██╔══██╗██║██╔════╝██╔════╝██╔════╝██╔══██╗██╔════╝██╔══██╗\n" +
10 | " ██║██║ ██║██║█████╗ █████╗ █████╗ ██████╔╝█████╗ ██████╔╝\n" +
11 | "██ ██║██║ ██║██║██╔══╝ ██╔══╝ ██╔══╝ ██╔══██╗██╔══╝ ██╔══██╗\n" +
12 | "╚█████╔╝██████╔╝██║██║ ██║ ███████╗██║ ██║███████╗██║ ██║\n" +
13 | " ╚════╝ ╚═════╝ ╚═╝╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝\n" +
14 | " \n" +
15 | "--- Powered By jd-core\n";
16 | System.out.println(bannerString);
17 | }
18 |
19 | public static void main(String[] args) {
20 | printBanner();
21 | new MainFrame().showGUI();
22 | }
23 | }
--------------------------------------------------------------------------------
/src/main/java/org/bridge/core/decompile/Decompiler.java:
--------------------------------------------------------------------------------
1 | package org.bridge.core.decompile;
2 |
3 | public interface Decompiler {
4 | String decompile(String fileName) throws Exception;
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/org/bridge/core/decompile/JDCoreDecompiler.java:
--------------------------------------------------------------------------------
1 | package org.bridge.core.decompile;
2 |
3 | import org.jd.core.v1.ClassFileToJavaSourceDecompiler;
4 | import org.jd.core.v1.api.loader.Loader;
5 | import org.jd.core.v1.api.loader.LoaderException;
6 | import org.jd.core.v1.api.printer.Printer;
7 |
8 | import java.io.IOException;
9 | import java.nio.file.Files;
10 | import java.nio.file.Paths;
11 |
12 | public class JDCoreDecompiler implements Decompiler {
13 | @Override
14 | public String decompile(String fileName) {
15 | FileNameLoader loader = new FileNameLoader();
16 | DefaultPrinter printer = new DefaultPrinter();
17 | ClassFileToJavaSourceDecompiler decompiler = new ClassFileToJavaSourceDecompiler();
18 | try {
19 | decompiler.decompile(loader, printer, fileName);
20 | } catch (Exception ex) {
21 | ex.printStackTrace();
22 | }
23 | return printer.toString();
24 | }
25 |
26 | private class FileNameLoader implements Loader {
27 | @Override
28 | public byte[] load(String fileName) throws LoaderException {
29 | byte[] classBytes;
30 | try {
31 | classBytes = Files.readAllBytes(Paths.get(fileName));
32 | } catch (IOException e) {
33 | throw new RuntimeException(e);
34 | }
35 | return classBytes;
36 | }
37 |
38 | @Override
39 | public boolean canLoad(String internalName) {
40 | return Files.isRegularFile(Paths.get(internalName));
41 | }
42 | }
43 |
44 | private class DefaultPrinter implements Printer {
45 | protected static final String TAB = " ";
46 | protected static final String NEWLINE = "\n";
47 |
48 | protected int indentationCount = 0;
49 | protected StringBuilder sb = new StringBuilder();
50 |
51 | @Override
52 | public String toString() {
53 | return sb.toString();
54 | }
55 |
56 | @Override
57 | public void start(int maxLineNumber, int majorVersion, int minorVersion) {
58 | }
59 |
60 | @Override
61 | public void end() {
62 | }
63 |
64 | @Override
65 | public void printText(String text) {
66 | sb.append(text);
67 | }
68 |
69 | @Override
70 | public void printNumericConstant(String constant) {
71 | sb.append(constant);
72 | }
73 |
74 | @Override
75 | public void printStringConstant(String constant, String ownerInternalName) {
76 | sb.append(constant);
77 | }
78 |
79 | @Override
80 | public void printKeyword(String keyword) {
81 | sb.append(keyword);
82 | }
83 |
84 | @Override
85 | public void printDeclaration(int type, String internalTypeName, String name, String descriptor) {
86 | sb.append(name);
87 | }
88 |
89 | @Override
90 | public void printReference(int type, String internalTypeName, String name, String descriptor, String ownerInternalName) {
91 | sb.append(name);
92 | }
93 |
94 | @Override
95 | public void indent() {
96 | this.indentationCount++;
97 | }
98 |
99 | @Override
100 | public void unindent() {
101 | this.indentationCount--;
102 | }
103 |
104 | @Override
105 | public void startLine(int lineNumber) {
106 | for (int i = 0; i < indentationCount; i++) sb.append(TAB);
107 | }
108 |
109 | @Override
110 | public void endLine() {
111 | sb.append(NEWLINE);
112 | }
113 |
114 | @Override
115 | public void extraLine(int count) {
116 | while (count-- > 0) sb.append(NEWLINE);
117 | }
118 |
119 | @Override
120 | public void startMarker(int type) {
121 | }
122 |
123 | @Override
124 | public void endMarker(int type) {
125 | }
126 | }
127 | }
--------------------------------------------------------------------------------
/src/main/java/org/bridge/core/differ/DiffFileNodeInfo.java:
--------------------------------------------------------------------------------
1 | package org.bridge.core.differ;
2 |
3 | import java.io.IOException;
4 | import java.nio.file.Files;
5 | import java.nio.file.Path;
6 | import java.nio.file.Paths;
7 | import java.util.Arrays;
8 |
9 | public class DiffFileNodeInfo {
10 | private String path;
11 | private String filePath;
12 | private String directory;
13 | public DiffFileNodeInfo(String path, String directory) {
14 | this.path = path;
15 | this.directory = directory;
16 | this.filePath = String.valueOf(Paths.get(directory, path));
17 | }
18 |
19 | public String getFilePath() {
20 | return filePath;
21 | }
22 |
23 | public Boolean fileContentsEquals(DiffFileNodeInfo info) {
24 | try {
25 | byte[] myFileContent = Files.readAllBytes(Paths.get(filePath));
26 | byte[] anotherFileContent = Files.readAllBytes(Paths.get(info.getFilePath()));
27 | return Arrays.equals(myFileContent, anotherFileContent);
28 | } catch (IOException e) {
29 | return false;
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/org/bridge/core/filetree/DeltaCommons.java:
--------------------------------------------------------------------------------
1 | package org.bridge.core.filetree;
2 |
3 | import java.util.List;
4 |
5 | public class DeltaCommons {
6 | private List differences;
7 | private TreeNode intersectionTree;
8 |
9 | public DeltaCommons(List differences, TreeNode intersectionTree) {
10 | this.differences = differences;
11 | this.intersectionTree = intersectionTree;
12 | }
13 |
14 | public List getDifferences() {
15 | return differences;
16 | }
17 |
18 | public TreeNode getIntersectionTree() {
19 | return intersectionTree;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/org/bridge/core/filetree/FileTreeBuilder.java:
--------------------------------------------------------------------------------
1 | package org.bridge.core.filetree;
2 |
3 | import java.io.File;
4 | import java.util.Arrays;
5 |
6 |
7 | public class FileTreeBuilder {
8 |
9 | public static TreeNode buildFileTree(String directoryPath) {
10 | File rootDirectory = new File(directoryPath);
11 | if (!rootDirectory.exists() || !rootDirectory.isDirectory()) {
12 | return null;
13 | }
14 |
15 | return buildFileTreeHelper(rootDirectory, "",true);
16 | }
17 |
18 | private static TreeNode buildFileTreeHelper(File directory, String path, Boolean root) {
19 | String appendPath = root ? path + "/" : path + "/" + directory.getName();
20 | TreeNode node = new TreeNode(directory.getName(), appendPath, directory.getPath(), false);
21 |
22 | File[] files = directory.listFiles();
23 | if (files != null) {
24 | for (File file : files) {
25 | if (file.isDirectory()) {
26 | TreeNode childNode = buildFileTreeHelper(file, node.getPath(),false);
27 | if (childNode != null) {
28 | node.addChild(childNode);
29 | }
30 | } else {
31 | node.addChild(new TreeNode(file.getName(), appendPath + "/" + file.getName(), file.getPath(), true));
32 | }
33 | }
34 | }
35 |
36 | return node;
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/org/bridge/core/filetree/TreeComparator.java:
--------------------------------------------------------------------------------
1 | package org.bridge.core.filetree;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 |
7 | public class TreeComparator {
8 | public static DeltaCommons compareTrees(TreeNode tree1, TreeNode tree2) {
9 | List differences = new ArrayList<>();
10 | TreeNode intersectionTree = new TreeNode("", "", null, false);
11 | compareNodes(tree1, tree2, differences, intersectionTree);
12 | return new DeltaCommons(differences, intersectionTree);
13 | }
14 |
15 | private static void compareNodes(TreeNode node1, TreeNode node2, List differences, TreeNode intersectionTree) {
16 | if (node1 == null && node2 == null) {
17 | return;
18 | }
19 | if (node1 == null || node2 == null) {// current node only in A or only in B
20 | differences.add(new TreeDifference(node1, node2));
21 | return;
22 | }
23 | for (TreeNode childA : node1.getChildren()) {
24 | boolean foundMatch = false;
25 | for (TreeNode childB : node2.getChildren()) {
26 | if (childA.getName().equals(childB.getName()) &&
27 | (childA.isFile() == childB.isFile()) // one is a file and the other is a directory
28 | ) {
29 | foundMatch = true;
30 | if ((!childA.isFile()) && (!childB.isFile())) { // both are same directories
31 | TreeNode commonNode = new TreeNode(childA.getName(), childA.getPath(), childA.getFilePath(), false);
32 | intersectionTree.addChild(commonNode);
33 | compareNodes(childA, childB, differences, commonNode);
34 | } else { // both are files
35 | TreeNode commonNode = new TreeNode(childA.getName(), childA.getPath(), childA.getFilePath(), true);
36 | intersectionTree.addChild(commonNode);
37 | }
38 | break;
39 | }
40 | }
41 | if (!foundMatch) {// childA only in A
42 | differences.add(new TreeDifference(childA, null));
43 | }
44 | }
45 | for (TreeNode childB : node2.getChildren()) {
46 | boolean foundMatch = false;
47 | for (TreeNode childA : node1.getChildren()) {
48 | if (childA.getName().equals(childB.getName()) && (childA.isFile() == childB.isFile())) {
49 | foundMatch = true;
50 | break;
51 | }
52 | }
53 | if (!foundMatch) {// childB only in B
54 | differences.add(new TreeDifference(null, childB));
55 | }
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/src/main/java/org/bridge/core/filetree/TreeDifference.java:
--------------------------------------------------------------------------------
1 | package org.bridge.core.filetree;
2 |
3 | public class TreeDifference {
4 |
5 | private TreeNode node1;
6 | private TreeNode node2;
7 |
8 | public TreeDifference(TreeNode node1, TreeNode node2) {
9 | if ((node1 == null) == (node2 == null)) {
10 | throw new IllegalArgumentException("node1 and node2 should have and only have one null value.");
11 | }
12 | this.node1 = node1;
13 | this.node2 = node2;
14 | }
15 |
16 | public TreeNode getNode1() {
17 | return node1;
18 | }
19 |
20 | public TreeNode getNode2() {
21 | return node2;
22 | }
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/src/main/java/org/bridge/core/filetree/TreeNode.java:
--------------------------------------------------------------------------------
1 | package org.bridge.core.filetree;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class TreeNode {
7 | private String name;
8 | private List children;
9 | private String path;
10 | private Boolean isFile;
11 | private String filePath;
12 |
13 | public TreeNode(String name, String path,String filePath, Boolean isFile) {
14 | this.name = name;
15 | this.children = new ArrayList<>();
16 | this.path = path;
17 | this.isFile = isFile;
18 | this.filePath=filePath;
19 | }
20 |
21 | public String getName() {
22 | return name;
23 | }
24 |
25 | public List getChildren() {
26 | return children;
27 | }
28 |
29 | public String getPath() {
30 | return path;
31 | }
32 | public Boolean isFile() {
33 | return isFile;
34 | }
35 |
36 | public String getFilePath() {
37 | return filePath;
38 | }
39 |
40 | public void addChild(TreeNode child) {
41 | children.add(child);
42 | }
43 |
44 | @Override
45 | public String toString() {
46 | return name;
47 | }
48 | }
--------------------------------------------------------------------------------
/src/main/java/org/bridge/core/filetree/TreeUtils.java:
--------------------------------------------------------------------------------
1 | package org.bridge.core.filetree;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class TreeUtils {
7 |
8 | public static void printFileTree(TreeNode node, String indent) {
9 | System.out.println(indent + node.getName());
10 | List children = node.getChildren();
11 | for (int i = 0; i < children.size(); i++) {
12 | TreeNode child = children.get(i);
13 | if (i == children.size() - 1) {
14 | printFileTree(child, indent + " ");
15 | } else {
16 | printFileTree(child, indent + "│ ");
17 | }
18 | }
19 | }
20 |
21 | public static void printDifference(List differences) {
22 | for (TreeDifference diff : differences) {
23 | TreeNode node1 = diff.getNode1();
24 | TreeNode node2 = diff.getNode2();
25 | if (node1 == null) {
26 | System.out.println("++++++++++");
27 | printFileTree(node2, "");
28 | System.out.println("****************************************************");
29 | } else {
30 | System.out.println("----------");
31 | printFileTree(node1, "");
32 | System.out.println("****************************************************");
33 | }
34 | }
35 | }
36 |
37 |
38 | private static void getFilePathHelper(TreeNode node, List pathList) {
39 | for (TreeNode child : node.getChildren()) {
40 | if (child.isFile()) {// if child is a file, stop recursing and add to list
41 | pathList.add(child.getPath());
42 | continue;
43 | }
44 | getFilePathHelper(child, pathList);
45 | }
46 | }
47 |
48 | public static List getFileNodeList(TreeNode root) {
49 | List nodeList = new ArrayList<>();
50 | if(root.isFile()){
51 | nodeList.add(root);
52 | }
53 | getFileNodeListHelper(root, nodeList);
54 | return nodeList;
55 | }
56 |
57 | private static void getFileNodeListHelper(TreeNode node, List nodeList) {
58 | for (TreeNode child : node.getChildren()) {
59 | if (child.isFile()) {
60 | nodeList.add(child);
61 | continue;
62 | }
63 | getFileNodeListHelper(child, nodeList);
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/org/bridge/core/services/JarProcessor.java:
--------------------------------------------------------------------------------
1 | package org.bridge.core.services;
2 |
3 | import net.lingala.zip4j.exception.ZipException;
4 | import org.apache.commons.io.FileUtils;
5 | import org.bridge.Config;
6 | import org.bridge.core.decompile.Decompiler;
7 | import org.bridge.core.decompile.JDCoreDecompiler;
8 |
9 | import java.io.File;
10 | import java.io.IOException;
11 | import java.nio.file.Files;
12 | import java.nio.file.Path;
13 | import java.nio.file.Paths;
14 | import java.util.Comparator;
15 | import java.util.List;
16 | import java.util.stream.Collectors;
17 | import java.util.stream.Stream;
18 |
19 | public class JarProcessor {
20 | public static void main(String[] args) {
21 | System.out.println(System.getProperty("java.io.tmpdir"));
22 | }
23 |
24 | public static String[] process(String jar1, String jar2) {
25 | try {
26 | File jdifferer = new File(System.getProperty("java.io.tmpdir"), Config.tempDirName);
27 | if (jdifferer.exists()) {
28 | FileUtils.cleanDirectory(jdifferer);
29 | } else {
30 | jdifferer.mkdir();
31 | }
32 | String sourceDir = Paths.get(jdifferer.getPath(), Config.sourceDirName).toString();
33 | String revisedDir = Paths.get(jdifferer.getPath(), Config.revisedDirName).toString();
34 | unzipAndDecompile(jar1, sourceDir, new JDCoreDecompiler());
35 | unzipAndDecompile(jar2, revisedDir, new JDCoreDecompiler());
36 | return new String[]{sourceDir, revisedDir};
37 | } catch (IOException ex) {
38 | throw new RuntimeException(ex);
39 | }
40 | }
41 |
42 | private static void unzipAndDecompile(String jarPath, String destination, Decompiler decompiler) throws IOException {
43 | unzipJarToDirectory(jarPath, destination);
44 | decompileAllClassFile(destination, decompiler);
45 | }
46 |
47 | private static void unzipJarToDirectory(String jarPath, String destination) throws ZipException {
48 | new net.lingala.zip4j.ZipFile(jarPath).extractAll(destination);
49 | }
50 |
51 | private static void decompileAllClassFile(String directory, Decompiler decompiler) throws IOException {
52 | List pathList = listFiles(Paths.get(directory));
53 | for (Path path : pathList) {
54 | File f = path.toFile();
55 | if (f.isFile() && f.getName().endsWith(".class")) {
56 | try {
57 | String source = decompiler.decompile(f.getPath());
58 | String javaPath = f.getPath().replace(".class", ".java");
59 | Files.write(Paths.get(javaPath), source.getBytes());
60 | Files.delete(Paths.get(f.getPath()));
61 | } catch (Exception e) {
62 | throw new RuntimeException(e);
63 | }
64 | }
65 | }
66 | }
67 |
68 | private static List listFiles(Path path) throws IOException {
69 |
70 | List result;
71 | try (Stream walk = Files.walk(path)) {
72 | result = walk.filter(Files::isRegularFile)
73 | .collect(Collectors.toList());
74 | }
75 | return result;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/org/bridge/core/services/MakeDiffFileTree.java:
--------------------------------------------------------------------------------
1 | package org.bridge.core.services;
2 |
3 | import org.bridge.core.differ.DiffFileNodeInfo;
4 | import org.bridge.core.filetree.*;
5 | import javax.swing.JTree;
6 | import javax.swing.tree.DefaultMutableTreeNode;
7 | import javax.swing.tree.DefaultTreeModel;
8 | import java.util.*;
9 |
10 | public class MakeDiffFileTree {
11 | public static void setDiffTree(JTree tree, String dirA, String dirB) {
12 | TreeNode fileTreeA = FileTreeBuilder.buildFileTree(dirA);
13 | TreeNode fileTreeB = FileTreeBuilder.buildFileTree(dirB);
14 | DeltaCommons dc = TreeComparator.compareTrees(fileTreeA, fileTreeB);
15 | DefaultMutableTreeNode root = new DefaultMutableTreeNode("Diff Tree");
16 | // update
17 | DefaultMutableTreeNode diffNode = new DefaultMutableTreeNode("UPDATE");
18 | List commonsNodeList = TreeUtils.getFileNodeList(dc.getIntersectionTree());
19 | List diffNodeList = new ArrayList<>();
20 | for (TreeNode node : commonsNodeList) {
21 | DiffFileNodeInfo infoA = new DiffFileNodeInfo(node.getPath(), dirA);
22 | DiffFileNodeInfo infoB = new DiffFileNodeInfo(node.getPath(), dirB);
23 | if (!infoA.fileContentsEquals(infoB)) {
24 | diffNodeList.add(node);
25 | }
26 | }
27 | diffNodeList.forEach(node -> diffNode.add(new DefaultMutableTreeNode(node)));
28 | // add and delete
29 | DefaultMutableTreeNode addNode = new DefaultMutableTreeNode("ADD");
30 | DefaultMutableTreeNode deleteNode = new DefaultMutableTreeNode("DELETE");
31 | for (TreeDifference td : dc.getDifferences()) {
32 | if (td.getNode1() == null) {
33 | List nodeList = TreeUtils.getFileNodeList(td.getNode2());
34 | nodeList.forEach(node -> addNode.add(new DefaultMutableTreeNode(node)));
35 | } else {
36 | List nodeList = TreeUtils.getFileNodeList(td.getNode1());
37 | nodeList.forEach(node -> deleteNode.add(new DefaultMutableTreeNode(node)));
38 | }
39 | }
40 | root.add(diffNode);
41 | root.add(addNode);
42 | root.add(deleteNode);
43 | tree.setModel(new DefaultTreeModel(root));
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/org/bridge/core/services/TextSetter.java:
--------------------------------------------------------------------------------
1 | package org.bridge.core.services;
2 |
3 | import com.github.difflib.DiffUtils;
4 | import com.github.difflib.patch.AbstractDelta;
5 | import com.github.difflib.patch.Patch;
6 | import org.bridge.core.filetree.TreeNode;
7 | import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
8 | import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
9 |
10 | import javax.swing.text.BadLocationException;
11 | import java.awt.*;
12 | import java.io.IOException;
13 | import java.nio.file.Files;
14 | import java.nio.file.Path;
15 | import java.nio.file.Paths;
16 | import java.util.List;
17 |
18 | public class TextSetter {
19 | public final static Color CHANGE_COLOR = new Color(251, 232, 161);
20 | public final static Color DELETE_COLOR = new Color(255, 197, 197);
21 | public final static Color INSERT_COLOR = new Color(184, 234, 184);
22 |
23 | public static void readFileToTextArea(RSyntaxTextArea pane, TreeNode node) {
24 | Path filePath = Paths.get(node.getFilePath());
25 | StringBuilder sb = new StringBuilder();
26 | sb.append(node.getPath() + "\n");
27 | try {
28 | sb.append(new String(Files.readAllBytes(filePath)));
29 | } catch (IOException ex) {
30 | throw new RuntimeException(ex);
31 | }
32 | if (filePath.toString().endsWith(".java")) {
33 | pane.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
34 | } else {
35 | pane.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_NONE);
36 | }
37 | pane.setText(sb.toString());
38 | }
39 |
40 | public static void setDiffTextArea(RSyntaxTextArea pane1, RSyntaxTextArea pane2, TreeNode node, String dirA, String dirB) {
41 | try {
42 | Path path1 = Paths.get(dirA, node.getPath());
43 | Path path2 = Paths.get(dirB, node.getPath());
44 | pane1.setText(node.getPath() + "\n" + new String(Files.readAllBytes(path1)));
45 | pane2.setText(node.getPath() + "\n" + new String(Files.readAllBytes(path2)));
46 | pane1.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
47 | pane2.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
48 |
49 | Patch patch = getPatchFromFile(path1, path2);
50 | for (AbstractDelta delta : patch.getDeltas()) {
51 | switch (delta.getType()) {
52 | case CHANGE: {
53 | applyDeltaToPane(delta, pane1, pane2, CHANGE_COLOR, CHANGE_COLOR);
54 | }
55 | case DELETE: {
56 | applyDeltaToPane(delta, pane1, pane2, DELETE_COLOR, null);
57 | }
58 | case INSERT: {
59 | applyDeltaToPane(delta, pane1, pane2, null, INSERT_COLOR);
60 | }
61 | default: {
62 | break;
63 | }
64 | }
65 | }
66 | } catch (IOException | BadLocationException ex) {
67 | throw new RuntimeException(ex);
68 | }
69 | }
70 |
71 | private static Patch getPatchFromFile(Path path1, Path path2) throws IOException {
72 | List original = Files.readAllLines(path1);
73 | List revised = Files.readAllLines(path2);
74 | Patch patch = DiffUtils.diff(original, revised);
75 | return patch;
76 | }
77 |
78 | private static void applyDeltaToPane(AbstractDelta delta, RSyntaxTextArea pane1, RSyntaxTextArea pane2, Color color1, Color color2) throws BadLocationException {
79 | int sourcePos = delta.getSource().getPosition();
80 | int sourceLen = delta.getSource().getLines().size();
81 | int targetPos = delta.getTarget().getPosition();
82 | int targetLen = delta.getTarget().getLines().size();
83 |
84 | for (int i = sourcePos; i < sourcePos + sourceLen; i++) {
85 | pane1.addLineHighlight(i + 1, color1);
86 | }
87 | for (int i = targetPos; i < targetPos + targetLen; i++) {
88 | pane2.addLineHighlight(i + 1, color2);
89 | }
90 | }
91 |
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/src/main/java/org/bridge/gui/JarsChoosingDialog.form:
--------------------------------------------------------------------------------
1 |
2 |
132 |
--------------------------------------------------------------------------------
/src/main/java/org/bridge/gui/JarsChoosingDialog.java:
--------------------------------------------------------------------------------
1 | package org.bridge.gui;
2 |
3 | import com.intellij.uiDesigner.core.GridConstraints;
4 | import com.intellij.uiDesigner.core.GridLayoutManager;
5 |
6 | import javax.swing.*;
7 | import java.awt.*;
8 | import java.awt.event.*;
9 | import java.io.File;
10 | import java.nio.file.Files;
11 | import java.util.*;
12 | import java.util.List;
13 |
14 | public class JarsChoosingDialog extends JDialog {
15 | private JPanel contentPane;
16 | private JButton buttonOK;
17 | private JButton buttonCancel;
18 | private JTextField dirTextField1;
19 | private JButton browseButton1;
20 | private JButton browseButton2;
21 | private JTextField dirTextField2;
22 | private JPanel topPanel;
23 | private List filesMessage;
24 | private Component parent;
25 | private MainFrame main;
26 |
27 | public JarsChoosingDialog(Component parent, MainFrame main) {
28 | super((Frame) parent);
29 | this.parent = parent;
30 | this.main = main;
31 | init();
32 | }
33 |
34 | private void init() {
35 | setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
36 | filesMessage = new ArrayList<>(Arrays.asList(null, null));
37 |
38 | setLocationAndSize();
39 | setContentPane(contentPane);
40 | setModal(true);
41 | getRootPane().setDefaultButton(buttonOK);
42 | addListener(browseButton1, dirTextField1, true);
43 | addListener(browseButton2, dirTextField2, false);
44 | buttonOK.addActionListener(new ActionListener() {
45 | public void actionPerformed(ActionEvent e) {
46 | onOK();
47 | }
48 | });
49 |
50 | buttonCancel.addActionListener(new ActionListener() {
51 | public void actionPerformed(ActionEvent e) {
52 | onCancel();
53 | }
54 | });
55 |
56 | // call onCancel() when cross is clicked
57 | addWindowListener(new WindowAdapter() {
58 | public void windowClosing(WindowEvent e) {
59 | onCancel();
60 | }
61 | });
62 |
63 | // call onCancel() on ESCAPE
64 | contentPane.registerKeyboardAction(new ActionListener() {
65 | public void actionPerformed(ActionEvent e) {
66 | onCancel();
67 | }
68 | }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
69 | }
70 |
71 | private void setLocationAndSize() {
72 | Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
73 | double widthRatio = 0.5;
74 | double heightRatio = 0.3;
75 | int dialogWidth = (int) (screenSize.width * widthRatio);
76 | int dialogHeight = (int) (screenSize.height * heightRatio);
77 | setSize(dialogWidth, dialogHeight);
78 | setLocationRelativeTo(parent);
79 | }
80 |
81 | private void addListener(JButton button, JTextField textField, Boolean origin) {
82 | button.addActionListener(e -> {
83 | JFileChooser chooser = new JFileChooser();
84 | chooser.setCurrentDirectory(new File("."));
85 | if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
86 | File selectedFile = chooser.getSelectedFile();
87 | textField.setText(selectedFile.getAbsolutePath());
88 | filesMessage.set(origin ? 0 : 1, selectedFile);
89 | }
90 | });
91 | }
92 |
93 | private void onOK() {
94 | if (filesMessage.get(0) == null || filesMessage.get(1) == null ||
95 | !Files.isRegularFile(filesMessage.get(0).toPath()) ||
96 | !Files.isRegularFile(filesMessage.get(1).toPath())
97 | ) {
98 | alert("File Invalid.");
99 |
100 | } else {
101 | main.loadJars(filesMessage.get(0), filesMessage.get(1));
102 | dispose();
103 | }
104 |
105 |
106 | }
107 |
108 | private void alert(String msg) {
109 | JDialog alertDialog = new JDialog(this, "alert", true);
110 | JLabel messageLabel = new JLabel(msg);
111 |
112 | JPanel panel = new JPanel();
113 | panel.add(messageLabel);
114 | alertDialog.add(panel);
115 | alertDialog.setLocationRelativeTo(this);
116 | alertDialog.pack();
117 | alertDialog.setVisible(true);
118 | }
119 |
120 | private void onCancel() {
121 | dispose();
122 | }
123 |
124 | {
125 | // GUI initializer generated by IntelliJ IDEA GUI Designer
126 | // >>> IMPORTANT!! <<<
127 | // DO NOT EDIT OR ADD ANY CODE HERE!
128 | $$$setupUI$$$();
129 | }
130 |
131 | /**
132 | * Method generated by IntelliJ IDEA GUI Designer
133 | * >>> IMPORTANT!! <<<
134 | * DO NOT edit this method OR call it in your code!
135 | *
136 | * @noinspection ALL
137 | */
138 | private void $$$setupUI$$$() {
139 | contentPane = new JPanel();
140 | contentPane.setLayout(new GridLayoutManager(2, 1, new Insets(10, 10, 10, 10), -1, -1));
141 | topPanel = new JPanel();
142 | topPanel.setLayout(new GridLayoutManager(2, 1, new Insets(0, 0, 0, 0), -1, -1));
143 | contentPane.add(topPanel, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
144 | final JPanel panel1 = new JPanel();
145 | panel1.setLayout(new GridLayoutManager(3, 1, new Insets(0, 0, 0, 0), -1, -1));
146 | topPanel.add(panel1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
147 | final JLabel label1 = new JLabel();
148 | label1.setText("Origin JAR");
149 | panel1.add(label1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
150 | dirTextField1 = new JTextField();
151 | dirTextField1.setEditable(false);
152 | panel1.add(dirTextField1, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false));
153 | browseButton1 = new JButton();
154 | browseButton1.setText("Browse...");
155 | panel1.add(browseButton1, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_EAST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
156 | final JPanel panel2 = new JPanel();
157 | panel2.setLayout(new GridLayoutManager(3, 1, new Insets(0, 0, 0, 0), -1, -1));
158 | topPanel.add(panel2, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
159 | final JLabel label2 = new JLabel();
160 | label2.setText("Origin JAR");
161 | panel2.add(label2, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
162 | dirTextField2 = new JTextField();
163 | dirTextField2.setEditable(false);
164 | panel2.add(dirTextField2, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false));
165 | browseButton2 = new JButton();
166 | browseButton2.setText("Browse...");
167 | panel2.add(browseButton2, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_EAST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
168 | final JPanel panel3 = new JPanel();
169 | panel3.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1));
170 | contentPane.add(panel3, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, 1, null, null, null, 0, false));
171 | final JPanel panel4 = new JPanel();
172 | panel4.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1));
173 | panel3.add(panel4, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
174 | buttonCancel = new JButton();
175 | buttonCancel.setText("Cancel");
176 | panel4.add(buttonCancel, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
177 | buttonOK = new JButton();
178 | buttonOK.setText("OK");
179 | panel3.add(buttonOK, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
180 | }
181 |
182 | /**
183 | * @noinspection ALL
184 | */
185 | public JComponent $$$getRootComponent$$$() {
186 | return contentPane;
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/src/main/java/org/bridge/gui/MainFrame.form:
--------------------------------------------------------------------------------
1 |
2 |
77 |
--------------------------------------------------------------------------------
/src/main/java/org/bridge/gui/MainFrame.java:
--------------------------------------------------------------------------------
1 | package org.bridge.gui;
2 |
3 | import com.intellij.uiDesigner.core.GridConstraints;
4 | import com.intellij.uiDesigner.core.GridLayoutManager;
5 | import org.bridge.core.filetree.TreeNode;
6 | import org.bridge.core.services.JarProcessor;
7 | import org.bridge.core.services.MakeDiffFileTree;
8 | import org.bridge.core.services.TextSetter;
9 | import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
10 |
11 | import javax.swing.*;
12 | import javax.swing.event.TreeSelectionEvent;
13 | import javax.swing.event.TreeSelectionListener;
14 | import javax.swing.tree.DefaultMutableTreeNode;
15 | import java.awt.*;
16 | import java.io.File;
17 |
18 | public class MainFrame {
19 | private JPanel rootPanel;
20 | private JTree fileTree;
21 | private JPanel mainPanel;
22 | private JScrollPane fileTreeScroll;
23 | private RSyntaxTextArea textArea1;
24 | private RSyntaxTextArea textArea2;
25 | private JScrollPane codeScroll1;
26 | private JScrollPane codeScroll2;
27 | private JSplitPane codeSplitPane;
28 | private JSplitPane mainSplitPane;
29 | private JFrame frame;
30 | private String dirA;
31 | private String dirB;
32 |
33 | public void showGUI() {
34 | frame = new JFrame("Jdifferer");
35 | frame.setContentPane(rootPanel);
36 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
37 | frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
38 | loadOtherGUI();
39 | setDividerLocation();
40 | frame.setVisible(true);
41 | }
42 |
43 | void loadJars(File origin, File revised) {
44 | String[] dirInfo = JarProcessor.process(origin.getAbsolutePath(), revised.getAbsolutePath());
45 | dirA = dirInfo[0];
46 | dirB = dirInfo[1];
47 | createFileTree();
48 | }
49 |
50 | private void setDividerLocation() {
51 | mainSplitPane.setResizeWeight(0.15);
52 | codeSplitPane.setResizeWeight(0.5);
53 | }
54 |
55 | private void loadOtherGUI() {
56 | insertTextArea();
57 | loadMenuBar();
58 | }
59 |
60 | private void insertTextArea() {
61 | textArea1 = new RSyntaxTextArea();
62 | textArea2 = new RSyntaxTextArea();
63 | textArea1.setEditable(false);
64 | textArea1.setHighlightCurrentLine(false);
65 | textArea2.setEditable(false);
66 | textArea2.setHighlightCurrentLine(false);
67 | textArea1.setBackground(new Color(245, 245, 245));
68 | textArea2.setBackground(new Color(245, 245, 245));
69 |
70 | codeScroll1.setViewportView(textArea1);
71 | codeScroll2.setViewportView(textArea2);
72 | }
73 |
74 | private void loadMenuBar() {
75 | JMenuBar menuBar = new JMenuBar();
76 |
77 | // Project
78 | JMenu projectMenu = new JMenu("Project");
79 | JMenuItem openItem = new JMenuItem("open");
80 | openItem.addActionListener(e -> {
81 | JDialog dialog = new JarsChoosingDialog(frame, this);
82 | dialog.setVisible(true);
83 | });
84 | JMenuItem exitItem = new JMenuItem("exit");
85 | exitItem.addActionListener(e -> {
86 | System.exit(0);
87 | });
88 | projectMenu.add(openItem);
89 | projectMenu.add(exitItem);
90 |
91 | menuBar.add(projectMenu);
92 |
93 | frame.setJMenuBar(menuBar);
94 | }
95 |
96 | private void createFileTree() {
97 | MakeDiffFileTree.setDiffTree(fileTree, dirA, dirB);
98 | fileTree.addTreeSelectionListener(new TreeSelectionListener() {
99 | @Override
100 | public void valueChanged(TreeSelectionEvent e) {
101 | DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) fileTree.getLastSelectedPathComponent();
102 | if (selectedNode != null && selectedNode.getUserObject() instanceof TreeNode) {
103 | DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) selectedNode.getParent();
104 | TreeNode treeNode = (TreeNode) selectedNode.getUserObject();
105 | if (parentNode.getUserObject().equals("ADD")) {
106 | TextSetter.readFileToTextArea(textArea2, treeNode);
107 | textArea2.select(0, 0);
108 | textArea1.setText(null);
109 | } else if (parentNode.getUserObject().equals("DELETE")) {
110 | TextSetter.readFileToTextArea(textArea1, treeNode);
111 | textArea1.select(0, 0);
112 | textArea2.setText(null);
113 | } else {
114 | TextSetter.setDiffTextArea(textArea1, textArea2, treeNode, dirA, dirB);
115 | textArea1.select(0, 0);
116 | textArea2.select(0, 0);
117 | }
118 | }
119 | }
120 | });
121 | }
122 |
123 | {
124 | // GUI initializer generated by IntelliJ IDEA GUI Designer
125 | // >>> IMPORTANT!! <<<
126 | // DO NOT EDIT OR ADD ANY CODE HERE!
127 | $$$setupUI$$$();
128 | }
129 |
130 | /**
131 | * Method generated by IntelliJ IDEA GUI Designer
132 | * >>> IMPORTANT!! <<<
133 | * DO NOT edit this method OR call it in your code!
134 | *
135 | * @noinspection ALL
136 | */
137 | private void $$$setupUI$$$() {
138 | rootPanel = new JPanel();
139 | rootPanel.setLayout(new GridLayoutManager(1, 3, new Insets(0, 0, 0, 0), -1, -1));
140 | mainPanel = new JPanel();
141 | mainPanel.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1));
142 | rootPanel.add(mainPanel, new GridConstraints(0, 0, 1, 3, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
143 | mainSplitPane = new JSplitPane();
144 | mainPanel.add(mainSplitPane, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, new Dimension(200, 200), null, 0, false));
145 | fileTreeScroll = new JScrollPane();
146 | mainSplitPane.setLeftComponent(fileTreeScroll);
147 | fileTree = new JTree();
148 | fileTree.setEnabled(true);
149 | fileTree.setRootVisible(true);
150 | fileTree.setShowsRootHandles(true);
151 | fileTreeScroll.setViewportView(fileTree);
152 | codeSplitPane = new JSplitPane();
153 | mainSplitPane.setRightComponent(codeSplitPane);
154 | codeScroll1 = new JScrollPane();
155 | codeSplitPane.setLeftComponent(codeScroll1);
156 | codeScroll2 = new JScrollPane();
157 | codeSplitPane.setRightComponent(codeScroll2);
158 | }
159 |
160 | /**
161 | * @noinspection ALL
162 | */
163 | public JComponent $$$getRootComponent$$$() {
164 | return rootPanel;
165 | }
166 | }
--------------------------------------------------------------------------------