From 8efb62490ec153246d467a1a72c513781db887bf Mon Sep 17 00:00:00 2001 From: 2xsaiko Date: Thu, 8 Jul 2021 16:30:39 +0200 Subject: Entry Changes (#364) * Initial refactor: Allow EntryMapping to have null targetName, add EntryChange in favor of entry changing methods in GuiController * Fix resetting name not actually removing it, and renaming a class causing name collisions with itself Closes #246. * Use name proposer for setting default deobf name Closes #314 * Make network protocol use EntryChange directly * Handle writing other data correctly when the deobf name is null * b * Add some new abstraction stuff * Use pattern matching instanceof * Move classes out of newabstraction package * Make EntryChange final * Regenerate equals and hashCode * Convert EntryMapping to record * Make TristateChange final * Safety guard null accessModifier initialization--- .../src/main/java/cuchaz/enigma/gui/Gui.java | 22 ++--- .../main/java/cuchaz/enigma/gui/GuiController.java | 99 ++++++++-------------- .../cuchaz/enigma/gui/dialog/JavadocDialog.java | 22 ++--- .../enigma/gui/newabstraction/EntryValidation.java | 22 +++++ .../java/cuchaz/enigma/gui/panels/DeobfPanel.java | 2 +- .../cuchaz/enigma/gui/panels/IdentifierPanel.java | 19 ++--- .../java/cuchaz/enigma/gui/panels/ObfPanel.java | 2 +- 7 files changed, 81 insertions(+), 107 deletions(-) create mode 100644 enigma-swing/src/main/java/cuchaz/enigma/gui/newabstraction/EntryValidation.java (limited to 'enigma-swing/src/main/java') diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java index a657d171..cddedad7 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java @@ -49,11 +49,9 @@ import cuchaz.enigma.gui.renderer.InheritanceTreeCellRenderer; import cuchaz.enigma.gui.renderer.MessageListCellRenderer; import cuchaz.enigma.gui.util.*; import cuchaz.enigma.network.Message; -import cuchaz.enigma.network.packet.MarkDeobfuscatedC2SPacket; import cuchaz.enigma.network.packet.MessageC2SPacket; -import cuchaz.enigma.network.packet.RemoveMappingC2SPacket; -import cuchaz.enigma.network.packet.RenameC2SPacket; import cuchaz.enigma.source.Token; +import cuchaz.enigma.translation.mapping.EntryChange; import cuchaz.enigma.translation.mapping.EntryRemapper; import cuchaz.enigma.translation.representation.entry.ClassEntry; import cuchaz.enigma.translation.representation.entry.Entry; @@ -740,12 +738,10 @@ public class Gui implements LanguageChangeListener { Entry obfEntry = cursorReference.entry; - if (controller.project.getMapper().extendedDeobfuscate(obfEntry).isDeobfuscated()) { - if (!validateImmediateAction(vc -> this.controller.removeMapping(vc, cursorReference))) return; - this.controller.sendPacket(new RemoveMappingC2SPacket(cursorReference.getNameableEntry())); + if (this.controller.project.getMapper().getDeobfMapping(obfEntry).targetName() != null) { + validateImmediateAction(vc -> this.controller.applyChange(vc, EntryChange.modify(obfEntry).clearDeobfName())); } else { - if (!validateImmediateAction(vc -> this.controller.markAsDeobfuscated(vc, cursorReference))) return; - this.controller.sendPacket(new MarkDeobfuscatedC2SPacket(cursorReference.getNameableEntry())); + validateImmediateAction(vc -> this.controller.applyChange(vc, EntryChange.modify(obfEntry).withDefaultDeobfName(this.getController().project))); } } @@ -813,7 +809,7 @@ public class Gui implements LanguageChangeListener { this.frame.repaint(); } - public void onPanelRename(ValidationContext vc, Object prevData, Object data, DefaultMutableTreeNode node) { + public void onRenameFromClassTree(ValidationContext vc, Object prevData, Object data, DefaultMutableTreeNode node) { if (data instanceof String) { // package rename for (int i = 0; i < node.getChildCount(); i++) { @@ -821,7 +817,7 @@ public class Gui implements LanguageChangeListener { ClassEntry prevDataChild = (ClassEntry) childNode.getUserObject(); ClassEntry dataChild = new ClassEntry(data + "/" + prevDataChild.getSimpleName()); - onPanelRename(vc, prevDataChild, dataChild, node); + onRenameFromClassTree(vc, prevDataChild, dataChild, node); } node.setUserObject(data); // Ob package will never be modified, just reload deob view @@ -839,9 +835,9 @@ public class Gui implements LanguageChangeListener { .filter(e -> mapper.deobfuscate(e).equals(deobf)) .findAny().orElse(deobf); - this.controller.rename(vc, new EntryReference<>(obf, obf.getFullName()), ((ClassEntry) data).getFullName(), false); - if (!vc.canProceed()) return; - this.controller.sendPacket(new RenameC2SPacket(obf, ((ClassEntry) data).getFullName(), false)); + this.controller.applyChange(vc, EntryChange.modify(obf).withDeobfName(((ClassEntry) data).getFullName())); + } else { + throw new IllegalStateException(String.format("unhandled rename object data: '%s'", data)); } } diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java index 2b75655a..4a15b418 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.nio.file.Path; import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -39,10 +40,12 @@ import cuchaz.enigma.classprovider.ClasspathClassProvider; import cuchaz.enigma.gui.config.NetConfig; import cuchaz.enigma.gui.config.UiConfig; import cuchaz.enigma.gui.dialog.ProgressDialog; +import cuchaz.enigma.gui.newabstraction.EntryValidation; import cuchaz.enigma.gui.stats.StatsGenerator; import cuchaz.enigma.gui.stats.StatsMember; import cuchaz.enigma.gui.util.History; import cuchaz.enigma.network.*; +import cuchaz.enigma.network.packet.EntryChangeC2SPacket; import cuchaz.enigma.network.packet.LoginC2SPacket; import cuchaz.enigma.network.packet.Packet; import cuchaz.enigma.source.DecompiledClassSource; @@ -62,6 +65,7 @@ import cuchaz.enigma.translation.representation.entry.FieldEntry; import cuchaz.enigma.translation.representation.entry.MethodEntry; import cuchaz.enigma.utils.I18n; import cuchaz.enigma.utils.Utils; +import cuchaz.enigma.utils.validation.PrintValidatable; import cuchaz.enigma.utils.validation.ValidationContext; public class GuiController implements ClientPacketHandler { @@ -401,19 +405,6 @@ public class GuiController implements ClientPacketHandler { }); } - public void onModifierChanged(ValidationContext vc, Entry entry, AccessModifier modifier) { - EntryRemapper mapper = project.getMapper(); - - EntryMapping mapping = mapper.getDeobfMapping(entry); - if (mapping != null) { - mapper.mapFromObf(vc, entry, new EntryMapping(mapping.getTargetName(), modifier)); - } else { - mapper.mapFromObf(vc, entry, new EntryMapping(entry.getName(), modifier)); - } - - chp.invalidateMapped(); - } - public StructureTreeNode getClassStructure(ClassEntry entry, StructureTreeOptions options) { StructureTreeNode rootNode = new StructureTreeNode(this.project, entry, entry); rootNode.load(this.project, options); @@ -471,74 +462,54 @@ public class GuiController implements ClientPacketHandler { } @Override - public void rename(ValidationContext vc, EntryReference, Entry> reference, String newName, boolean refreshClassTree) { - rename(vc, reference, newName, refreshClassTree, false); - } - - public void rename(ValidationContext vc, EntryReference, Entry> reference, String newName, boolean refreshClassTree, boolean validateOnly) { - Entry entry = reference.getNameableEntry(); - EntryMapping previous = project.getMapper().getDeobfMapping(entry); - project.getMapper().mapFromObf(vc, entry, previous != null ? previous.withName(newName) : new EntryMapping(newName), true, validateOnly); + public boolean applyChangeFromServer(EntryChange change) { + ValidationContext vc = new ValidationContext(); + vc.setActiveElement(PrintValidatable.INSTANCE); + this.applyChange0(vc, change); gui.showStructure(gui.getActiveEditor()); - if (validateOnly || !vc.canProceed()) return; + return vc.canProceed(); + } - if (refreshClassTree && reference.entry instanceof ClassEntry && !((ClassEntry) reference.entry).isInnerClass()) - this.gui.moveClassTree(reference.entry, newName); + public void validateChange(ValidationContext vc, EntryChange change) { + if (change.getDeobfName().isSet()) { + EntryValidation.validateRename(vc, this.project, change.getTarget(), change.getDeobfName().getNewValue()); + } - chp.invalidateMapped(); + if (change.getJavadoc().isSet()) { + EntryValidation.validateJavadoc(vc, change.getJavadoc().getNewValue()); + } } - @Override - public void removeMapping(ValidationContext vc, EntryReference, Entry> reference) { - project.getMapper().removeByObf(vc, reference.getNameableEntry()); + public void applyChange(ValidationContext vc, EntryChange change) { + this.applyChange0(vc, change); gui.showStructure(gui.getActiveEditor()); - if (!vc.canProceed()) return; - - if (reference.entry instanceof ClassEntry) - this.gui.moveClassTree(reference.entry, false, true); - - chp.invalidateMapped(); + this.sendPacket(new EntryChangeC2SPacket(change)); } - @Override - public void changeDocs(ValidationContext vc, EntryReference, Entry> reference, String updatedDocs) { - changeDocs(vc, reference, updatedDocs, false); - } - - public void changeDocs(ValidationContext vc, EntryReference, Entry> reference, String updatedDocs, boolean validateOnly) { - changeDoc(vc, reference.entry, updatedDocs, validateOnly); - - if (validateOnly || !vc.canProceed()) return; + private void applyChange0(ValidationContext vc, EntryChange change) { + validateChange(vc, change); + if (!vc.canProceed()) return; - chp.invalidateJavadoc(reference.getLocationClassEntry()); - } + Entry target = change.getTarget(); + EntryMapping prev = this.project.getMapper().getDeobfMapping(target); + EntryMapping mapping = EntryUtil.applyChange(vc, this.project.getMapper(), change); - private void changeDoc(ValidationContext vc, Entry obfEntry, String newDoc, boolean validateOnly) { - EntryRemapper mapper = project.getMapper(); + boolean renamed = !change.getDeobfName().isUnchanged(); - EntryMapping deobfMapping = mapper.getDeobfMapping(obfEntry); - if (deobfMapping == null) { - deobfMapping = new EntryMapping(mapper.deobfuscate(obfEntry).getName()); + if (renamed && target instanceof ClassEntry && !((ClassEntry) target).isInnerClass()) { + this.gui.moveClassTree(target, prev.targetName() == null, mapping.targetName() == null); } - mapper.mapFromObf(vc, obfEntry, deobfMapping.withDocs(newDoc), false, validateOnly); - } + if (!Objects.equals(prev.targetName(), mapping.targetName())) { + this.chp.invalidateMapped(); + } - @Override - public void markAsDeobfuscated(ValidationContext vc, EntryReference, Entry> reference) { - EntryRemapper mapper = project.getMapper(); - Entry entry = reference.getNameableEntry(); - mapper.mapFromObf(vc, entry, new EntryMapping(mapper.deobfuscate(entry).getName())); + if (!Objects.equals(prev.javadoc(), mapping.javadoc())) { + this.chp.invalidateJavadoc(target.getTopLevelClass()); + } gui.showStructure(gui.getActiveEditor()); - - if (!vc.canProceed()) return; - - if (reference.entry instanceof ClassEntry && !((ClassEntry) reference.entry).isInnerClass()) - this.gui.moveClassTree(reference.entry, true, false); - - chp.invalidateMapped(); } public void openStats(Set includedMembers, String topLevelPackage, boolean includeSynthetic) { diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java index 2fc67476..9470e11c 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java @@ -29,23 +29,22 @@ import cuchaz.enigma.gui.config.UiConfig; import cuchaz.enigma.gui.elements.ValidatableTextArea; import cuchaz.enigma.gui.util.GuiUtil; import cuchaz.enigma.gui.util.ScaleUtil; -import cuchaz.enigma.network.packet.ChangeDocsC2SPacket; +import cuchaz.enigma.translation.mapping.EntryChange; import cuchaz.enigma.translation.representation.entry.Entry; import cuchaz.enigma.utils.I18n; -import cuchaz.enigma.utils.validation.Message; import cuchaz.enigma.utils.validation.ValidationContext; public class JavadocDialog { private final JDialog ui; private final GuiController controller; - private final EntryReference, Entry> entry; + private final Entry entry; private final ValidatableTextArea text; private final ValidationContext vc = new ValidationContext(); - private JavadocDialog(JFrame parent, GuiController controller, EntryReference, Entry> entry, String preset) { + private JavadocDialog(JFrame parent, GuiController controller, Entry entry, String preset) { this.ui = new JDialog(parent, I18n.translate("javadocs.edit")); this.controller = controller; this.entry = entry; @@ -161,28 +160,21 @@ public class JavadocDialog { public void validate() { vc.setActiveElement(text); - if (text.getText().contains("*/")) { - vc.raise(Message.ILLEGAL_DOC_COMMENT_END); - } - - controller.changeDocs(vc, entry, text.getText(), true); + controller.validateChange(vc, EntryChange.modify(entry).withJavadoc(text.getText())); } public void save() { vc.setActiveElement(text); - controller.changeDocs(vc, entry, text.getText().trim().isEmpty() ? null : text.getText()); - - if (!vc.canProceed()) return; - controller.sendPacket(new ChangeDocsC2SPacket(entry.getNameableEntry(), text.getText())); + controller.applyChange(vc, EntryChange.modify(entry).withJavadoc(text.getText())); } public static void show(JFrame parent, GuiController controller, EntryReference, Entry> entry) { EntryReference, Entry> translatedReference = controller.project.getMapper().deobfuscate(entry); String text = Strings.nullToEmpty(translatedReference.entry.getJavadocs()); - JavadocDialog dialog = new JavadocDialog(parent, controller, entry, text); - dialog.ui.doLayout(); + JavadocDialog dialog = new JavadocDialog(parent, controller, entry.getNameableEntry(), text); + //dialog.ui.doLayout(); dialog.ui.setVisible(true); dialog.text.grabFocus(); } diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/newabstraction/EntryValidation.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/newabstraction/EntryValidation.java new file mode 100644 index 00000000..898529a4 --- /dev/null +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/newabstraction/EntryValidation.java @@ -0,0 +1,22 @@ +package cuchaz.enigma.gui.newabstraction; + +import cuchaz.enigma.EnigmaProject; +import cuchaz.enigma.translation.representation.entry.Entry; +import cuchaz.enigma.utils.validation.Message; +import cuchaz.enigma.utils.validation.ValidationContext; + +public class EntryValidation { + + public static boolean validateJavadoc(ValidationContext vc, String javadoc) { + if (javadoc.contains("*/")) { + vc.raise(Message.ILLEGAL_DOC_COMMENT_END); + return false; + } + return true; + } + + public static boolean validateRename(ValidationContext vc, EnigmaProject p, Entry entry, String newName) { + return p.getMapper().getValidator().validateRename(vc, entry, newName); + } + +} diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/DeobfPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/DeobfPanel.java index 5b7882b0..cd09c1a1 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/DeobfPanel.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/DeobfPanel.java @@ -22,7 +22,7 @@ public class DeobfPanel extends JPanel { this.deobfClasses = new ClassSelector(gui, ClassSelector.DEOBF_CLASS_COMPARATOR, true); this.deobfClasses.setSelectionListener(gui.getController()::navigateTo); - this.deobfClasses.setRenameSelectionListener(gui::onPanelRename); + this.deobfClasses.setRenameSelectionListener(gui::onRenameFromClassTree); this.setLayout(new BorderLayout()); this.add(this.title, BorderLayout.NORTH); diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/IdentifierPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/IdentifierPanel.java index 3bae94c3..4ae0b7be 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/IdentifierPanel.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/IdentifierPanel.java @@ -15,7 +15,6 @@ import javax.swing.JLabel; import javax.swing.JPanel; import cuchaz.enigma.EnigmaProject; -import cuchaz.enigma.analysis.EntryReference; import cuchaz.enigma.gui.EditableType; import cuchaz.enigma.gui.Gui; import cuchaz.enigma.gui.elements.ConvertingTextField; @@ -23,8 +22,8 @@ import cuchaz.enigma.gui.events.ConvertingTextFieldListener; import cuchaz.enigma.gui.util.GridBagConstraintsBuilder; import cuchaz.enigma.gui.util.GuiUtil; import cuchaz.enigma.gui.util.ScaleUtil; -import cuchaz.enigma.network.packet.RenameC2SPacket; import cuchaz.enigma.translation.mapping.AccessModifier; +import cuchaz.enigma.translation.mapping.EntryChange; import cuchaz.enigma.translation.mapping.EntryMapping; import cuchaz.enigma.translation.representation.entry.*; import cuchaz.enigma.utils.I18n; @@ -76,7 +75,7 @@ public class IdentifierPanel { } private void onModifierChanged(AccessModifier modifier) { - gui.validateImmediateAction(vc -> this.gui.getController().onModifierChanged(vc, entry, modifier)); + gui.validateImmediateAction(vc -> this.gui.getController().applyChange(vc, EntryChange.modify(entry).withAccess(modifier))); } public void refreshReference() { @@ -176,13 +175,12 @@ public class IdentifierPanel { } private void validateRename(String newName) { - gui.getController().rename(vc, new EntryReference<>(entry, deobfEntry.getName()), newName, true, true); + gui.getController().validateChange(vc, EntryChange.modify(entry).withDeobfName(newName)); } private void doRename(String newName) { - gui.getController().rename(vc, new EntryReference<>(entry, deobfEntry.getName()), newName, true); - if (!vc.canProceed()) return; - gui.getController().sendPacket(new RenameC2SPacket(entry, newName, true)); + EntryChange> change = EntryChange.modify(entry).withDeobfName(newName); + gui.getController().applyChange(vc, change); } public void retranslateUi() { @@ -277,12 +275,7 @@ public class IdentifierPanel { JComboBox combo = new JComboBox<>(AccessModifier.values()); EntryMapping mapping = project.getMapper().getDeobfMapping(e); - - if (mapping != null) { - combo.setSelectedIndex(mapping.getAccessModifier().ordinal()); - } else { - combo.setSelectedIndex(AccessModifier.UNCHANGED.ordinal()); - } + combo.setSelectedIndex(mapping.accessModifier().ordinal()); if (this.gui.isEditable(type)) { combo.addItemListener(event -> { diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ObfPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ObfPanel.java index b384968d..7783843d 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ObfPanel.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ObfPanel.java @@ -33,7 +33,7 @@ public class ObfPanel extends JPanel { this.obfClasses = new ClassSelector(gui, obfClassComparator, false); this.obfClasses.setSelectionListener(gui.getController()::navigateTo); - this.obfClasses.setRenameSelectionListener(gui::onPanelRename); + this.obfClasses.setRenameSelectionListener(gui::onRenameFromClassTree); this.setLayout(new BorderLayout()); this.add(this.title, BorderLayout.NORTH); -- cgit v1.2.3