summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/gui/MemberMatchingGui.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/MemberMatchingGui.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/MemberMatchingGui.java')
-rw-r--r--src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java815
1 files changed, 404 insertions, 411 deletions
diff --git a/src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java b/src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java
index 671f85f..4f5231f 100644
--- a/src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java
+++ b/src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java
@@ -8,25 +8,11 @@
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.google.common.collect.Lists; 14import com.google.common.collect.Lists;
14import com.google.common.collect.Maps; 15import com.google.common.collect.Maps;
15
16import java.awt.BorderLayout;
17import java.awt.Container;
18import java.awt.Dimension;
19import java.awt.FlowLayout;
20import java.awt.event.ActionListener;
21import java.awt.event.KeyAdapter;
22import java.awt.event.KeyEvent;
23import java.util.Collection;
24import java.util.List;
25import java.util.Map;
26
27import javax.swing.*;
28import javax.swing.text.Highlighter.HighlightPainter;
29
30import cuchaz.enigma.Constants; 16import cuchaz.enigma.Constants;
31import cuchaz.enigma.Deobfuscator; 17import cuchaz.enigma.Deobfuscator;
32import cuchaz.enigma.analysis.SourceIndex; 18import cuchaz.enigma.analysis.SourceIndex;
@@ -39,403 +25,410 @@ import cuchaz.enigma.mapping.ClassEntry;
39import cuchaz.enigma.mapping.Entry; 25import cuchaz.enigma.mapping.Entry;
40import de.sciss.syntaxpane.DefaultSyntaxKit; 26import de.sciss.syntaxpane.DefaultSyntaxKit;
41 27
28import javax.swing.*;
29import javax.swing.text.Highlighter.HighlightPainter;
30import java.awt.*;
31import java.awt.event.ActionListener;
32import java.awt.event.KeyAdapter;
33import java.awt.event.KeyEvent;
34import java.util.Collection;
35import java.util.List;
36import java.util.Map;
42 37
43public class MemberMatchingGui<T extends Entry> { 38public class MemberMatchingGui<T extends Entry> {
44 39
45 private enum SourceType { 40 // controls
46 Matched { 41 private JFrame frame;
47 @Override 42 private Map<SourceType, JRadioButton> sourceTypeButtons;
48 public <T extends Entry> Collection<ClassEntry> getObfSourceClasses(MemberMatches<T> matches) { 43 private ClassSelector sourceClasses;
49 return matches.getSourceClassesWithoutUnmatchedEntries(); 44 private CodeReader sourceReader;
50 } 45 private CodeReader destReader;
51 }, 46 private JButton matchButton;
52 Unmatched { 47 private JButton unmatchableButton;
53 @Override 48 private JLabel sourceLabel;
54 public <T extends Entry> Collection<ClassEntry> getObfSourceClasses(MemberMatches<T> matches) { 49 private JLabel destLabel;
55 return matches.getSourceClassesWithUnmatchedEntries(); 50 private HighlightPainter unmatchedHighlightPainter;
56 } 51 private HighlightPainter matchedHighlightPainter;
57 }; 52 private ClassMatches classMatches;
58 53 private MemberMatches<T> memberMatches;
59 public JRadioButton newRadio(ActionListener listener, ButtonGroup group) { 54 private Deobfuscator sourceDeobfuscator;
60 JRadioButton button = new JRadioButton(name(), this == getDefault()); 55 private Deobfuscator destDeobfuscator;
61 button.setActionCommand(name()); 56 private SaveListener<T> saveListener;
62 button.addActionListener(listener); 57 private SourceType sourceType;
63 group.add(button); 58 private ClassEntry obfSourceClass;
64 return button; 59 private ClassEntry obfDestClass;
65 } 60 private T obfSourceEntry;
66 61 private T obfDestEntry;
67 public abstract <T extends Entry> Collection<ClassEntry> getObfSourceClasses(MemberMatches<T> matches); 62 public MemberMatchingGui(ClassMatches classMatches, MemberMatches<T> fieldMatches, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) {
68 63
69 public static SourceType getDefault() { 64 this.classMatches = classMatches;
70 return values()[0]; 65 memberMatches = fieldMatches;
71 } 66 this.sourceDeobfuscator = sourceDeobfuscator;
72 } 67 this.destDeobfuscator = destDeobfuscator;
73 68
74 public interface SaveListener<T extends Entry> { 69 // init frame
75 void save(MemberMatches<T> matches); 70 frame = new JFrame(Constants.NAME + " - Member Matcher");
76 } 71 final Container pane = frame.getContentPane();
77 72 pane.setLayout(new BorderLayout());
78 // controls 73
79 private JFrame frame; 74 // init classes side
80 private Map<SourceType, JRadioButton> sourceTypeButtons; 75 JPanel classesPanel = new JPanel();
81 private ClassSelector sourceClasses; 76 classesPanel.setLayout(new BoxLayout(classesPanel, BoxLayout.PAGE_AXIS));
82 private CodeReader sourceReader; 77 classesPanel.setPreferredSize(new Dimension(200, 0));
83 private CodeReader destReader; 78 pane.add(classesPanel, BorderLayout.WEST);
84 private JButton matchButton; 79 classesPanel.add(new JLabel("Classes"));
85 private JButton unmatchableButton; 80
86 private JLabel sourceLabel; 81 // init source type radios
87 private JLabel destLabel; 82 JPanel sourceTypePanel = new JPanel();
88 private HighlightPainter unmatchedHighlightPainter; 83 classesPanel.add(sourceTypePanel);
89 private HighlightPainter matchedHighlightPainter; 84 sourceTypePanel.setLayout(new BoxLayout(sourceTypePanel, BoxLayout.PAGE_AXIS));
90 private ClassMatches classMatches; 85 ActionListener sourceTypeListener = event -> setSourceType(SourceType.valueOf(event.getActionCommand()));
91 private MemberMatches<T> memberMatches; 86 ButtonGroup sourceTypeButtons = new ButtonGroup();
92 private Deobfuscator sourceDeobfuscator; 87 this.sourceTypeButtons = Maps.newHashMap();
93 private Deobfuscator destDeobfuscator; 88 for (SourceType sourceType : SourceType.values()) {
94 private SaveListener<T> saveListener; 89 JRadioButton button = sourceType.newRadio(sourceTypeListener, sourceTypeButtons);
95 private SourceType sourceType; 90 this.sourceTypeButtons.put(sourceType, button);
96 private ClassEntry obfSourceClass; 91 sourceTypePanel.add(button);
97 private ClassEntry obfDestClass; 92 }
98 private T obfSourceEntry; 93
99 private T obfDestEntry; 94 sourceClasses = new ClassSelector(null, ClassSelector.DEOBF_CLASS_COMPARATOR, false);
100 95 sourceClasses.setSelectionListener(this::setSourceClass);
101 public MemberMatchingGui(ClassMatches classMatches, MemberMatches<T> fieldMatches, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) { 96 JScrollPane sourceScroller = new JScrollPane(sourceClasses);
102 97 classesPanel.add(sourceScroller);
103 this.classMatches = classMatches; 98
104 memberMatches = fieldMatches; 99 // init readers
105 this.sourceDeobfuscator = sourceDeobfuscator; 100 DefaultSyntaxKit.initKit();
106 this.destDeobfuscator = destDeobfuscator; 101 sourceReader = new CodeReader();
107 102 sourceReader.setSelectionListener(reference ->
108 // init frame 103 {
109 frame = new JFrame(Constants.NAME + " - Member Matcher"); 104 if (reference != null) {
110 final Container pane = frame.getContentPane(); 105 onSelectSource(reference.entry);
111 pane.setLayout(new BorderLayout()); 106 } else {
112 107 onSelectSource(null);
113 // init classes side 108 }
114 JPanel classesPanel = new JPanel(); 109 });
115 classesPanel.setLayout(new BoxLayout(classesPanel, BoxLayout.PAGE_AXIS)); 110 destReader = new CodeReader();
116 classesPanel.setPreferredSize(new Dimension(200, 0)); 111 destReader.setSelectionListener(reference ->
117 pane.add(classesPanel, BorderLayout.WEST); 112 {
118 classesPanel.add(new JLabel("Classes")); 113 if (reference != null) {
119 114 onSelectDest(reference.entry);
120 // init source type radios 115 } else {
121 JPanel sourceTypePanel = new JPanel(); 116 onSelectDest(null);
122 classesPanel.add(sourceTypePanel); 117 }
123 sourceTypePanel.setLayout(new BoxLayout(sourceTypePanel, BoxLayout.PAGE_AXIS)); 118 });
124 ActionListener sourceTypeListener = event -> setSourceType(SourceType.valueOf(event.getActionCommand())); 119
125 ButtonGroup sourceTypeButtons = new ButtonGroup(); 120 // add key bindings
126 this.sourceTypeButtons = Maps.newHashMap(); 121 KeyAdapter keyListener = new KeyAdapter() {
127 for (SourceType sourceType : SourceType.values()) { 122 @Override
128 JRadioButton button = sourceType.newRadio(sourceTypeListener, sourceTypeButtons); 123 public void keyPressed(KeyEvent event) {
129 this.sourceTypeButtons.put(sourceType, button); 124 if (event.getKeyCode() == KeyEvent.VK_M)
130 sourceTypePanel.add(button); 125 matchButton.doClick();
131 } 126 }
132 127 };
133 sourceClasses = new ClassSelector(null, ClassSelector.DEOBF_CLASS_COMPARATOR, false); 128 sourceReader.addKeyListener(keyListener);
134 sourceClasses.setSelectionListener(this::setSourceClass); 129 destReader.addKeyListener(keyListener);
135 JScrollPane sourceScroller = new JScrollPane(sourceClasses); 130
136 classesPanel.add(sourceScroller); 131 // init all the splits
137 132 JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, new JScrollPane(sourceReader), new JScrollPane(
138 // init readers 133 destReader));
139 DefaultSyntaxKit.initKit(); 134 splitRight.setResizeWeight(0.5); // resize 50:50
140 sourceReader = new CodeReader(); 135 JSplitPane splitLeft = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, classesPanel, splitRight);
141 sourceReader.setSelectionListener(reference -> 136 splitLeft.setResizeWeight(0); // let the right side take all the slack
142 { 137 pane.add(splitLeft, BorderLayout.CENTER);
143 if (reference != null) { 138 splitLeft.resetToPreferredSizes();
144 onSelectSource(reference.entry); 139
145 } else { 140 // init bottom panel
146 onSelectSource(null); 141 JPanel bottomPanel = new JPanel();
147 } 142 bottomPanel.setLayout(new FlowLayout());
148 }); 143 pane.add(bottomPanel, BorderLayout.SOUTH);
149 destReader = new CodeReader(); 144
150 destReader.setSelectionListener(reference -> 145 matchButton = new JButton();
151 { 146 unmatchableButton = new JButton();
152 if (reference != null) { 147
153 onSelectDest(reference.entry); 148 sourceLabel = new JLabel();
154 } else { 149 bottomPanel.add(sourceLabel);
155 onSelectDest(null); 150 bottomPanel.add(matchButton);
156 } 151 bottomPanel.add(unmatchableButton);
157 }); 152 destLabel = new JLabel();
158 153 bottomPanel.add(destLabel);
159 // add key bindings 154
160 KeyAdapter keyListener = new KeyAdapter() { 155 // show the frame
161 @Override 156 pane.doLayout();
162 public void keyPressed(KeyEvent event) { 157 frame.setSize(1024, 576);
163 if (event.getKeyCode() == KeyEvent.VK_M) 158 frame.setMinimumSize(new Dimension(640, 480));
164 matchButton.doClick(); 159 frame.setVisible(true);
165 } 160 frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
166 }; 161
167 sourceReader.addKeyListener(keyListener); 162 unmatchedHighlightPainter = new ObfuscatedHighlightPainter();
168 destReader.addKeyListener(keyListener); 163 matchedHighlightPainter = new DeobfuscatedHighlightPainter();
169 164
170 // init all the splits 165 // init state
171 JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, new JScrollPane(sourceReader), new JScrollPane( 166 saveListener = null;
172 destReader)); 167 obfSourceClass = null;
173 splitRight.setResizeWeight(0.5); // resize 50:50 168 obfDestClass = null;
174 JSplitPane splitLeft = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, classesPanel, splitRight); 169 obfSourceEntry = null;
175 splitLeft.setResizeWeight(0); // let the right side take all the slack 170 obfDestEntry = null;
176 pane.add(splitLeft, BorderLayout.CENTER); 171 setSourceType(SourceType.getDefault());
177 splitLeft.resetToPreferredSizes(); 172 updateButtons();
178 173 }
179 // init bottom panel 174
180 JPanel bottomPanel = new JPanel(); 175 protected void setSourceType(SourceType val) {
181 bottomPanel.setLayout(new FlowLayout()); 176 sourceType = val;
182 pane.add(bottomPanel, BorderLayout.SOUTH); 177 updateSourceClasses();
183 178 }
184 matchButton = new JButton(); 179
185 unmatchableButton = new JButton(); 180 public void setSaveListener(SaveListener<T> val) {
186 181 saveListener = val;
187 sourceLabel = new JLabel(); 182 }
188 bottomPanel.add(sourceLabel); 183
189 bottomPanel.add(matchButton); 184 private void updateSourceClasses() {
190 bottomPanel.add(unmatchableButton); 185
191 destLabel = new JLabel(); 186 String selectedPackage = sourceClasses.getSelectedPackage();
192 bottomPanel.add(destLabel); 187
193 188 List<ClassEntry> deobfClassEntries = Lists.newArrayList();
194 // show the frame 189 for (ClassEntry entry : sourceType.getObfSourceClasses(memberMatches)) {
195 pane.doLayout(); 190 deobfClassEntries.add(sourceDeobfuscator.deobfuscateEntry(entry));
196 frame.setSize(1024, 576); 191 }
197 frame.setMinimumSize(new Dimension(640, 480)); 192 sourceClasses.setClasses(deobfClassEntries);
198 frame.setVisible(true); 193
199 frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 194 if (selectedPackage != null) {
200 195 sourceClasses.expandPackage(selectedPackage);
201 unmatchedHighlightPainter = new ObfuscatedHighlightPainter(); 196 }
202 matchedHighlightPainter = new DeobfuscatedHighlightPainter(); 197
203 198 for (SourceType sourceType : SourceType.values()) {
204 // init state 199 sourceTypeButtons.get(sourceType).setText(String.format("%s (%d)",
205 saveListener = null; 200 sourceType.name(), sourceType.getObfSourceClasses(memberMatches).size()
206 obfSourceClass = null; 201 ));
207 obfDestClass = null; 202 }
208 obfSourceEntry = null; 203 }
209 obfDestEntry = null; 204
210 setSourceType(SourceType.getDefault()); 205 protected void setSourceClass(ClassEntry sourceClass) {
211 updateButtons(); 206
212 } 207 obfSourceClass = sourceDeobfuscator.obfuscateEntry(sourceClass);
213 208 obfDestClass = classMatches.getUniqueMatches().get(obfSourceClass);
214 protected void setSourceType(SourceType val) { 209 if (obfDestClass == null) {
215 sourceType = val; 210 throw new Error("No matching dest class for source class: " + obfSourceClass);
216 updateSourceClasses(); 211 }
217 } 212
218 213 sourceReader.decompileClass(obfSourceClass, sourceDeobfuscator, false, this::updateSourceHighlights);
219 public void setSaveListener(SaveListener<T> val) { 214 destReader.decompileClass(obfDestClass, destDeobfuscator, false, this::updateDestHighlights);
220 saveListener = val; 215 }
221 } 216
222 217 protected void updateSourceHighlights() {
223 private void updateSourceClasses() { 218 highlightEntries(sourceReader, sourceDeobfuscator, memberMatches.matches().keySet(), memberMatches.getUnmatchedSourceEntries());
224 219 }
225 String selectedPackage = sourceClasses.getSelectedPackage(); 220
226 221 protected void updateDestHighlights() {
227 List<ClassEntry> deobfClassEntries = Lists.newArrayList(); 222 highlightEntries(destReader, destDeobfuscator, memberMatches.matches().values(), memberMatches.getUnmatchedDestEntries());
228 for (ClassEntry entry : sourceType.getObfSourceClasses(memberMatches)) { 223 }
229 deobfClassEntries.add(sourceDeobfuscator.deobfuscateEntry(entry)); 224
230 } 225 private void highlightEntries(CodeReader reader, Deobfuscator deobfuscator, Collection<T> obfMatchedEntries, Collection<T> obfUnmatchedEntries) {
231 sourceClasses.setClasses(deobfClassEntries); 226 reader.clearHighlights();
232 227 // matched fields
233 if (selectedPackage != null) { 228 updateHighlighted(obfMatchedEntries, deobfuscator, reader, matchedHighlightPainter);
234 sourceClasses.expandPackage(selectedPackage); 229 // unmatched fields
235 } 230 updateHighlighted(obfUnmatchedEntries, deobfuscator, reader, unmatchedHighlightPainter);
236 231 }
237 for (SourceType sourceType : SourceType.values()) { 232
238 sourceTypeButtons.get(sourceType).setText(String.format("%s (%d)", 233 private void updateHighlighted(Collection<T> entries, Deobfuscator deobfuscator, CodeReader reader, HighlightPainter painter) {
239 sourceType.name(), sourceType.getObfSourceClasses(memberMatches).size() 234 SourceIndex index = reader.getSourceIndex();
240 )); 235 for (T obfT : entries) {
241 } 236 T deobfT = deobfuscator.deobfuscateEntry(obfT);
242 } 237 Token token = index.getDeclarationToken(deobfT);
243 238 if (token != null) {
244 protected void setSourceClass(ClassEntry sourceClass) { 239 reader.setHighlightedToken(token, painter);
245 240 }
246 obfSourceClass = sourceDeobfuscator.obfuscateEntry(sourceClass); 241 }
247 obfDestClass = classMatches.getUniqueMatches().get(obfSourceClass); 242 }
248 if (obfDestClass == null) { 243
249 throw new Error("No matching dest class for source class: " + obfSourceClass); 244 private boolean isSelectionMatched() {
250 } 245 return obfSourceEntry != null && obfDestEntry != null
251 246 && memberMatches.isMatched(obfSourceEntry, obfDestEntry);
252 sourceReader.decompileClass(obfSourceClass, sourceDeobfuscator, false, this::updateSourceHighlights); 247 }
253 destReader.decompileClass(obfDestClass, destDeobfuscator, false, this::updateDestHighlights); 248
254 } 249 protected void onSelectSource(Entry source) {
255 250
256 protected void updateSourceHighlights() { 251 // start with no selection
257 highlightEntries(sourceReader, sourceDeobfuscator, memberMatches.matches().keySet(), memberMatches.getUnmatchedSourceEntries()); 252 if (isSelectionMatched()) {
258 } 253 setDest(null);
259 254 }
260 protected void updateDestHighlights() { 255 setSource(null);
261 highlightEntries(destReader, destDeobfuscator, memberMatches.matches().values(), memberMatches.getUnmatchedDestEntries()); 256
262 } 257 // then look for a valid source selection
263 258 if (source != null) {
264 private void highlightEntries(CodeReader reader, Deobfuscator deobfuscator, Collection<T> obfMatchedEntries, Collection<T> obfUnmatchedEntries) { 259
265 reader.clearHighlights(); 260 // this looks really scary, but it's actually ok
266 // matched fields 261 // Deobfuscator.obfuscateEntry can handle all implementations of Entry
267 updateHighlighted(obfMatchedEntries, deobfuscator, reader, matchedHighlightPainter); 262 // and MemberMatches.hasSource() will only pass entries that actually match T
268 // unmatched fields 263 @SuppressWarnings("unchecked")
269 updateHighlighted(obfUnmatchedEntries, deobfuscator, reader, unmatchedHighlightPainter); 264 T sourceEntry = (T) source;
270 } 265
271 266 T obfSourceEntry = sourceDeobfuscator.obfuscateEntry(sourceEntry);
272 private void updateHighlighted(Collection<T> entries, Deobfuscator deobfuscator, CodeReader reader, HighlightPainter painter) 267 if (memberMatches.hasSource(obfSourceEntry)) {
273 { 268 setSource(obfSourceEntry);
274 SourceIndex index = reader.getSourceIndex(); 269
275 for (T obfT : entries) { 270 // look for a matched dest too
276 T deobfT = deobfuscator.deobfuscateEntry(obfT); 271 T obfDestEntry = memberMatches.matches().get(obfSourceEntry);
277 Token token = index.getDeclarationToken(deobfT); 272 if (obfDestEntry != null) {
278 if (token != null) { 273 setDest(obfDestEntry);
279 reader.setHighlightedToken(token, painter); 274 }
280 } 275 }
281 } 276 }
282 } 277
283 278 updateButtons();
284 private boolean isSelectionMatched() { 279 }
285 return obfSourceEntry != null && obfDestEntry != null 280
286 && memberMatches.isMatched(obfSourceEntry, obfDestEntry); 281 protected void onSelectDest(Entry dest) {
287 } 282
288 283 // start with no selection
289 protected void onSelectSource(Entry source) { 284 if (isSelectionMatched()) {
290 285 setSource(null);
291 // start with no selection 286 }
292 if (isSelectionMatched()) { 287 setDest(null);
293 setDest(null); 288
294 } 289 // then look for a valid dest selection
295 setSource(null); 290 if (dest != null) {
296 291
297 // then look for a valid source selection 292 // this looks really scary, but it's actually ok
298 if (source != null) { 293 // Deobfuscator.obfuscateEntry can handle all implementations of Entry
299 294 // and MemberMatches.hasSource() will only pass entries that actually match T
300 // this looks really scary, but it's actually ok 295 @SuppressWarnings("unchecked")
301 // Deobfuscator.obfuscateEntry can handle all implementations of Entry 296 T destEntry = (T) dest;
302 // and MemberMatches.hasSource() will only pass entries that actually match T 297
303 @SuppressWarnings("unchecked") 298 T obfDestEntry = destDeobfuscator.obfuscateEntry(destEntry);
304 T sourceEntry = (T) source; 299 if (memberMatches.hasDest(obfDestEntry)) {
305 300 setDest(obfDestEntry);
306 T obfSourceEntry = sourceDeobfuscator.obfuscateEntry(sourceEntry); 301
307 if (memberMatches.hasSource(obfSourceEntry)) { 302 // look for a matched source too
308 setSource(obfSourceEntry); 303 T obfSourceEntry = memberMatches.matches().inverse().get(obfDestEntry);
309 304 if (obfSourceEntry != null) {
310 // look for a matched dest too 305 setSource(obfSourceEntry);
311 T obfDestEntry = memberMatches.matches().get(obfSourceEntry); 306 }
312 if (obfDestEntry != null) { 307 }
313 setDest(obfDestEntry); 308 }
314 } 309
315 } 310 updateButtons();
316 } 311 }
317 312
318 updateButtons(); 313 private void setSource(T obfEntry) {
319 } 314 if (obfEntry == null) {
320 315 obfSourceEntry = null;
321 protected void onSelectDest(Entry dest) { 316 sourceLabel.setText("");
322 317 } else {
323 // start with no selection 318 obfSourceEntry = obfEntry;
324 if (isSelectionMatched()) { 319 sourceLabel.setText(getEntryLabel(obfEntry, sourceDeobfuscator));
325 setSource(null); 320 }
326 } 321 }
327 setDest(null); 322
328 323 private void setDest(T obfEntry) {
329 // then look for a valid dest selection 324 if (obfEntry == null) {
330 if (dest != null) { 325 obfDestEntry = null;
331 326 destLabel.setText("");
332 // this looks really scary, but it's actually ok 327 } else {
333 // Deobfuscator.obfuscateEntry can handle all implementations of Entry 328 obfDestEntry = obfEntry;
334 // and MemberMatches.hasSource() will only pass entries that actually match T 329 destLabel.setText(getEntryLabel(obfEntry, destDeobfuscator));
335 @SuppressWarnings("unchecked") 330 }
336 T destEntry = (T) dest; 331 }
337 332
338 T obfDestEntry = destDeobfuscator.obfuscateEntry(destEntry); 333 private String getEntryLabel(T obfEntry, Deobfuscator deobfuscator) {
339 if (memberMatches.hasDest(obfDestEntry)) { 334 // show obfuscated and deobfuscated names, but no types/signatures
340 setDest(obfDestEntry); 335 T deobfEntry = deobfuscator.deobfuscateEntry(obfEntry);
341 336 return String.format("%s (%s)", deobfEntry.getName(), obfEntry.getName());
342 // look for a matched source too 337 }
343 T obfSourceEntry = memberMatches.matches().inverse().get(obfDestEntry); 338
344 if (obfSourceEntry != null) { 339 private void updateButtons() {
345 setSource(obfSourceEntry); 340
346 } 341 GuiTricks.deactivateButton(matchButton);
347 } 342 GuiTricks.deactivateButton(unmatchableButton);
348 } 343
349 344 if (obfSourceEntry != null && obfDestEntry != null) {
350 updateButtons(); 345 if (memberMatches.isMatched(obfSourceEntry, obfDestEntry))
351 } 346 GuiTricks.activateButton(matchButton, "Unmatch", event -> unmatch());
352 347 else if (!memberMatches.isMatchedSourceEntry(obfSourceEntry) && !memberMatches.isMatchedDestEntry(
353 private void setSource(T obfEntry) { 348 obfDestEntry))
354 if (obfEntry == null) { 349 GuiTricks.activateButton(matchButton, "Match", event -> match());
355 obfSourceEntry = null; 350 } else if (obfSourceEntry != null)
356 sourceLabel.setText(""); 351 GuiTricks.activateButton(unmatchableButton, "Set Unmatchable", event -> unmatchable());
357 } else { 352 }
358 obfSourceEntry = obfEntry; 353
359 sourceLabel.setText(getEntryLabel(obfEntry, sourceDeobfuscator)); 354 protected void match() {
360 } 355
361 } 356 // update the field matches
362 357 memberMatches.makeMatch(obfSourceEntry, obfDestEntry, sourceDeobfuscator, destDeobfuscator);
363 private void setDest(T obfEntry) { 358 save();
364 if (obfEntry == null) { 359
365 obfDestEntry = null; 360 // update the ui
366 destLabel.setText(""); 361 onSelectSource(null);
367 } else { 362 onSelectDest(null);
368 obfDestEntry = obfEntry; 363 updateSourceHighlights();
369 destLabel.setText(getEntryLabel(obfEntry, destDeobfuscator)); 364 updateDestHighlights();
370 } 365 updateSourceClasses();
371 } 366 }
372 367
373 private String getEntryLabel(T obfEntry, Deobfuscator deobfuscator) { 368 protected void unmatch() {
374 // show obfuscated and deobfuscated names, but no types/signatures 369
375 T deobfEntry = deobfuscator.deobfuscateEntry(obfEntry); 370 // update the field matches
376 return String.format("%s (%s)", deobfEntry.getName(), obfEntry.getName()); 371 memberMatches.unmakeMatch(obfSourceEntry, obfDestEntry, sourceDeobfuscator, destDeobfuscator);
377 } 372 save();
378 373
379 private void updateButtons() { 374 // update the ui
380 375 onSelectSource(null);
381 GuiTricks.deactivateButton(matchButton); 376 onSelectDest(null);
382 GuiTricks.deactivateButton(unmatchableButton); 377 updateSourceHighlights();
383 378 updateDestHighlights();
384 if (obfSourceEntry != null && obfDestEntry != null) { 379 updateSourceClasses();
385 if (memberMatches.isMatched(obfSourceEntry, obfDestEntry)) 380 }
386 GuiTricks.activateButton(matchButton, "Unmatch", event -> unmatch()); 381
387 else if (!memberMatches.isMatchedSourceEntry(obfSourceEntry) && !memberMatches.isMatchedDestEntry( 382 protected void unmatchable() {
388 obfDestEntry)) 383
389 GuiTricks.activateButton(matchButton, "Match", event -> match()); 384 // update the field matches
390 } else if (obfSourceEntry != null) 385 memberMatches.makeSourceUnmatchable(obfSourceEntry, sourceDeobfuscator);
391 GuiTricks.activateButton(unmatchableButton, "Set Unmatchable", event -> unmatchable()); 386 save();
392 } 387
393 388 // update the ui
394 protected void match() { 389 onSelectSource(null);
395 390 onSelectDest(null);
396 // update the field matches 391 updateSourceHighlights();
397 memberMatches.makeMatch(obfSourceEntry, obfDestEntry, sourceDeobfuscator, destDeobfuscator); 392 updateDestHighlights();
398 save(); 393 updateSourceClasses();
399 394 }
400 // update the ui 395
401 onSelectSource(null); 396 private void save() {
402 onSelectDest(null); 397 if (saveListener != null) {
403 updateSourceHighlights(); 398 saveListener.save(memberMatches);
404 updateDestHighlights(); 399 }
405 updateSourceClasses(); 400 }
406 } 401
407 402 private enum SourceType {
408 protected void unmatch() { 403 Matched {
409 404 @Override
410 // update the field matches 405 public <T extends Entry> Collection<ClassEntry> getObfSourceClasses(MemberMatches<T> matches) {
411 memberMatches.unmakeMatch(obfSourceEntry, obfDestEntry, sourceDeobfuscator, destDeobfuscator); 406 return matches.getSourceClassesWithoutUnmatchedEntries();
412 save(); 407 }
413 408 },
414 // update the ui 409 Unmatched {
415 onSelectSource(null); 410 @Override
416 onSelectDest(null); 411 public <T extends Entry> Collection<ClassEntry> getObfSourceClasses(MemberMatches<T> matches) {
417 updateSourceHighlights(); 412 return matches.getSourceClassesWithUnmatchedEntries();
418 updateDestHighlights(); 413 }
419 updateSourceClasses(); 414 };
420 } 415
421 416 public static SourceType getDefault() {
422 protected void unmatchable() { 417 return values()[0];
423 418 }
424 // update the field matches 419
425 memberMatches.makeSourceUnmatchable(obfSourceEntry, sourceDeobfuscator); 420 public JRadioButton newRadio(ActionListener listener, ButtonGroup group) {
426 save(); 421 JRadioButton button = new JRadioButton(name(), this == getDefault());
427 422 button.setActionCommand(name());
428 // update the ui 423 button.addActionListener(listener);
429 onSelectSource(null); 424 group.add(button);
430 onSelectDest(null); 425 return button;
431 updateSourceHighlights(); 426 }
432 updateDestHighlights(); 427
433 updateSourceClasses(); 428 public abstract <T extends Entry> Collection<ClassEntry> getObfSourceClasses(MemberMatches<T> matches);
434 } 429 }
435 430
436 private void save() { 431 public interface SaveListener<T extends Entry> {
437 if (saveListener != null) { 432 void save(MemberMatches<T> matches);
438 saveListener.save(memberMatches); 433 }
439 }
440 }
441} 434}