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