summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/gui/CodeReader.java
diff options
context:
space:
mode:
authorGravatar Thog2017-03-08 08:17:04 +0100
committerGravatar Thog2017-03-08 08:17:04 +0100
commit6e464ea251cab63c776ece0b2a356f1498ffa294 (patch)
tree5ed30c03f5ac4cd2d6877874f5ede576049954f7 /src/main/java/cuchaz/enigma/gui/CodeReader.java
parentDrop unix case style and implement hashCode when equals is overrided (diff)
downloadenigma-fork-6e464ea251cab63c776ece0b2a356f1498ffa294.tar.gz
enigma-fork-6e464ea251cab63c776ece0b2a356f1498ffa294.tar.xz
enigma-fork-6e464ea251cab63c776ece0b2a356f1498ffa294.zip
Follow Fabric guidelines
Diffstat (limited to 'src/main/java/cuchaz/enigma/gui/CodeReader.java')
-rw-r--r--src/main/java/cuchaz/enigma/gui/CodeReader.java362
1 files changed, 178 insertions, 184 deletions
diff --git a/src/main/java/cuchaz/enigma/gui/CodeReader.java b/src/main/java/cuchaz/enigma/gui/CodeReader.java
index 8225d8f..2e235dc 100644
--- a/src/main/java/cuchaz/enigma/gui/CodeReader.java
+++ b/src/main/java/cuchaz/enigma/gui/CodeReader.java
@@ -8,20 +8,10 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.gui; 12package cuchaz.enigma.gui;
12 13
13import com.strobel.decompiler.languages.java.ast.CompilationUnit; 14import com.strobel.decompiler.languages.java.ast.CompilationUnit;
14
15import java.awt.Rectangle;
16import java.awt.event.ActionEvent;
17import java.awt.event.ActionListener;
18
19import javax.swing.JEditorPane;
20import javax.swing.SwingUtilities;
21import javax.swing.Timer;
22import javax.swing.text.BadLocationException;
23import javax.swing.text.Highlighter.HighlightPainter;
24
25import cuchaz.enigma.Deobfuscator; 15import cuchaz.enigma.Deobfuscator;
26import cuchaz.enigma.analysis.EntryReference; 16import cuchaz.enigma.analysis.EntryReference;
27import cuchaz.enigma.analysis.SourceIndex; 17import cuchaz.enigma.analysis.SourceIndex;
@@ -31,180 +21,184 @@ import cuchaz.enigma.mapping.ClassEntry;
31import cuchaz.enigma.mapping.Entry; 21import cuchaz.enigma.mapping.Entry;
32import de.sciss.syntaxpane.DefaultSyntaxKit; 22import de.sciss.syntaxpane.DefaultSyntaxKit;
33 23
24import javax.swing.*;
25import javax.swing.text.BadLocationException;
26import javax.swing.text.Highlighter.HighlightPainter;
27import java.awt.*;
28import java.awt.event.ActionEvent;
29import java.awt.event.ActionListener;
34 30
35public class CodeReader extends JEditorPane { 31public class CodeReader extends JEditorPane {
36 32
37 private static final long serialVersionUID = 3673180950485748810L; 33 private static final long serialVersionUID = 3673180950485748810L;
38 34
39 private static final Object lock = new Object(); 35 private static final Object lock = new Object();
40 36 private SelectionHighlightPainter selectionHighlightPainter;
41 public interface SelectionListener { 37 private SourceIndex sourceIndex;
42 void onSelect(EntryReference<Entry, Entry> reference); 38 private SelectionListener selectionListener;
43 } 39 public CodeReader() {
44 40
45 private SelectionHighlightPainter selectionHighlightPainter; 41 setEditable(false);
46 private SourceIndex sourceIndex; 42 setContentType("text/java");
47 private SelectionListener selectionListener; 43
48 44 // turn off token highlighting (it's wrong most of the time anyway...)
49 public CodeReader() { 45 DefaultSyntaxKit kit = (DefaultSyntaxKit) getEditorKit();
50 46 kit.toggleComponent(this, "de.sciss.syntaxpane.components.TokenMarker");
51 setEditable(false); 47
52 setContentType("text/java"); 48 // hook events
53 49 addCaretListener(event ->
54 // turn off token highlighting (it's wrong most of the time anyway...) 50 {
55 DefaultSyntaxKit kit = (DefaultSyntaxKit) getEditorKit(); 51 if (selectionListener != null && sourceIndex != null) {
56 kit.toggleComponent(this, "de.sciss.syntaxpane.components.TokenMarker"); 52 Token token = sourceIndex.getReferenceToken(event.getDot());
57 53 if (token != null) {
58 // hook events 54 selectionListener.onSelect(sourceIndex.getDeobfReference(token));
59 addCaretListener(event -> 55 } else {
60 { 56 selectionListener.onSelect(null);
61 if (selectionListener != null && sourceIndex != null) { 57 }
62 Token token = sourceIndex.getReferenceToken(event.getDot()); 58 }
63 if (token != null) { 59 });
64 selectionListener.onSelect(sourceIndex.getDeobfReference(token)); 60
65 } else { 61 selectionHighlightPainter = new SelectionHighlightPainter();
66 selectionListener.onSelect(null); 62 }
67 } 63
68 } 64 // HACKHACK: someday we can update the main GUI to use this code reader
69 }); 65 public static void navigateToToken(final JEditorPane editor, final Token token, final HighlightPainter highlightPainter) {
70 66
71 selectionHighlightPainter = new SelectionHighlightPainter(); 67 // set the caret position to the token
72 } 68 editor.setCaretPosition(token.start);
73 69 editor.grabFocus();
74 public void setSelectionListener(SelectionListener val) { 70
75 selectionListener = val; 71 try {
76 } 72 // make sure the token is visible in the scroll window
77 73 Rectangle start = editor.modelToView(token.start);
78 public void setCode(String code) { 74 Rectangle end = editor.modelToView(token.end);
79 // sadly, the java lexer is not thread safe, so we have to serialize all these calls 75 final Rectangle show = start.union(end);
80 synchronized (lock) { 76 show.grow(start.width * 10, start.height * 6);
81 setText(code); 77 SwingUtilities.invokeLater(() -> editor.scrollRectToVisible(show));
82 } 78 } catch (BadLocationException ex) {
83 } 79 throw new Error(ex);
84 80 }
85 public SourceIndex getSourceIndex() { 81
86 return sourceIndex; 82 // highlight the token momentarily
87 } 83 final Timer timer = new Timer(200, new ActionListener() {
88 84 private int counter = 0;
89 public void decompileClass(ClassEntry classEntry, Deobfuscator deobfuscator) { 85 private Object highlight = null;
90 decompileClass(classEntry, deobfuscator, null); 86
91 } 87 @Override
92 88 public void actionPerformed(ActionEvent event) {
93 public void decompileClass(ClassEntry classEntry, Deobfuscator deobfuscator, Runnable callback) { 89 if (counter % 2 == 0) {
94 decompileClass(classEntry, deobfuscator, null, callback); 90 try {
95 } 91 highlight = editor.getHighlighter().addHighlight(token.start, token.end, highlightPainter);
96 92 } catch (BadLocationException ex) {
97 public void decompileClass(final ClassEntry classEntry, final Deobfuscator deobfuscator, final Boolean ignoreBadTokens, final Runnable callback) { 93 // don't care
98 94 }
99 if (classEntry == null) { 95 } else if (highlight != null) {
100 setCode(null); 96 editor.getHighlighter().removeHighlight(highlight);
101 return; 97 }
102 } 98
103 99 if (counter++ > 6) {
104 setCode("(decompiling...)"); 100 Timer timer = (Timer) event.getSource();
105 101 timer.stop();
106 // run decompilation in a separate thread to keep ui responsive 102 }
107 new Thread(() -> 103 }
108 { 104 });
109 105 timer.start();
110 // decompile it 106 }
111 CompilationUnit sourceTree = deobfuscator.getSourceTree(classEntry.getOutermostClassName()); 107
112 String source = deobfuscator.getSource(sourceTree); 108 public void setSelectionListener(SelectionListener val) {
113 setCode(source); 109 selectionListener = val;
114 sourceIndex = deobfuscator.getSourceIndex(sourceTree, source, ignoreBadTokens); 110 }
115 111
116 if (callback != null) { 112 public void setCode(String code) {
117 callback.run(); 113 // sadly, the java lexer is not thread safe, so we have to serialize all these calls
118 } 114 synchronized (lock) {
119 }).start(); 115 setText(code);
120 } 116 }
121 117 }
122 public void navigateToClassDeclaration(ClassEntry classEntry) { 118
123 119 public SourceIndex getSourceIndex() {
124 // navigate to the class declaration 120 return sourceIndex;
125 Token token = sourceIndex.getDeclarationToken(classEntry); 121 }
126 if (token == null) { 122
127 // couldn't find the class declaration token, might be an anonymous class 123 public void decompileClass(ClassEntry classEntry, Deobfuscator deobfuscator) {
128 // look for any declaration in that class instead 124 decompileClass(classEntry, deobfuscator, null);
129 for (Entry entry : sourceIndex.declarations()) { 125 }
130 if (entry.getClassEntry().equals(classEntry)) { 126
131 token = sourceIndex.getDeclarationToken(entry); 127 public void decompileClass(ClassEntry classEntry, Deobfuscator deobfuscator, Runnable callback) {
132 break; 128 decompileClass(classEntry, deobfuscator, null, callback);
133 } 129 }
134 } 130
135 } 131 public void decompileClass(final ClassEntry classEntry, final Deobfuscator deobfuscator, final Boolean ignoreBadTokens, final Runnable callback) {
136 132
137 if (token != null) { 133 if (classEntry == null) {
138 navigateToToken(token); 134 setCode(null);
139 } else { 135 return;
140 // couldn't find anything =( 136 }
141 System.out.println("Unable to find declaration in source for " + classEntry); 137
142 } 138 setCode("(decompiling...)");
143 } 139
144 140 // run decompilation in a separate thread to keep ui responsive
145 public void navigateToToken(final Token token) { 141 new Thread(() ->
146 navigateToToken(this, token, selectionHighlightPainter); 142 {
147 } 143
148 144 // decompile it
149 // HACKHACK: someday we can update the main GUI to use this code reader 145 CompilationUnit sourceTree = deobfuscator.getSourceTree(classEntry.getOutermostClassName());
150 public static void navigateToToken(final JEditorPane editor, final Token token, final HighlightPainter highlightPainter) { 146 String source = deobfuscator.getSource(sourceTree);
151 147 setCode(source);
152 // set the caret position to the token 148 sourceIndex = deobfuscator.getSourceIndex(sourceTree, source, ignoreBadTokens);
153 editor.setCaretPosition(token.start); 149
154 editor.grabFocus(); 150 if (callback != null) {
155 151 callback.run();
156 try { 152 }
157 // make sure the token is visible in the scroll window 153 }).start();
158 Rectangle start = editor.modelToView(token.start); 154 }
159 Rectangle end = editor.modelToView(token.end); 155
160 final Rectangle show = start.union(end); 156 public void navigateToClassDeclaration(ClassEntry classEntry) {
161 show.grow(start.width * 10, start.height * 6); 157
162 SwingUtilities.invokeLater(() -> editor.scrollRectToVisible(show)); 158 // navigate to the class declaration
163 } catch (BadLocationException ex) { 159 Token token = sourceIndex.getDeclarationToken(classEntry);
164 throw new Error(ex); 160 if (token == null) {
165 } 161 // couldn't find the class declaration token, might be an anonymous class
166 162 // look for any declaration in that class instead
167 // highlight the token momentarily 163 for (Entry entry : sourceIndex.declarations()) {
168 final Timer timer = new Timer(200, new ActionListener() { 164 if (entry.getClassEntry().equals(classEntry)) {
169 private int counter = 0; 165 token = sourceIndex.getDeclarationToken(entry);
170 private Object highlight = null; 166 break;
171 167 }
172 @Override 168 }
173 public void actionPerformed(ActionEvent event) { 169 }
174 if (counter % 2 == 0) { 170
175 try { 171 if (token != null) {
176 highlight = editor.getHighlighter().addHighlight(token.start, token.end, highlightPainter); 172 navigateToToken(token);
177 } catch (BadLocationException ex) { 173 } else {
178 // don't care 174 // couldn't find anything =(
179 } 175 System.out.println("Unable to find declaration in source for " + classEntry);
180 } else if (highlight != null) { 176 }
181 editor.getHighlighter().removeHighlight(highlight); 177 }
182 } 178
183 179 public void navigateToToken(final Token token) {
184 if (counter++ > 6) { 180 navigateToToken(this, token, selectionHighlightPainter);
185 Timer timer = (Timer) event.getSource(); 181 }
186 timer.stop(); 182
187 } 183 public void setHighlightedTokens(Iterable<Token> tokens, HighlightPainter painter) {
188 } 184 for (Token token : tokens) {
189 }); 185 setHighlightedToken(token, painter);
190 timer.start(); 186 }
191 } 187 }
192 188
193 public void setHighlightedTokens(Iterable<Token> tokens, HighlightPainter painter) { 189 public void setHighlightedToken(Token token, HighlightPainter painter) {
194 for (Token token : tokens) { 190 try {
195 setHighlightedToken(token, painter); 191 getHighlighter().addHighlight(token.start, token.end, painter);
196 } 192 } catch (BadLocationException ex) {
197 } 193 throw new IllegalArgumentException(ex);
198 194 }
199 public void setHighlightedToken(Token token, HighlightPainter painter) { 195 }
200 try { 196
201 getHighlighter().addHighlight(token.start, token.end, painter); 197 public void clearHighlights() {
202 } catch (BadLocationException ex) { 198 getHighlighter().removeAllHighlights();
203 throw new IllegalArgumentException(ex); 199 }
204 } 200
205 } 201 public interface SelectionListener {
206 202 void onSelect(EntryReference<Entry, Entry> reference);
207 public void clearHighlights() { 203 }
208 getHighlighter().removeAllHighlights();
209 }
210} 204}