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