summaryrefslogtreecommitdiff
path: root/enigma-swing
diff options
context:
space:
mode:
authorGravatar modmuss502022-09-14 13:12:55 +0100
committerGravatar GitHub2022-09-14 13:12:55 +0100
commit9c736848fb7aa82d295b3aa2946e6cd132ee998f (patch)
treeb982613cfa7201b2db25cb64a5950f9a2c34a5b3 /enigma-swing
parentNested packages in Swing UI (#458) (diff)
downloadenigma-9c736848fb7aa82d295b3aa2946e6cd132ee998f.tar.gz
enigma-9c736848fb7aa82d295b3aa2946e6cd132ee998f.tar.xz
enigma-9c736848fb7aa82d295b3aa2946e6cd132ee998f.zip
Add checkstyle (#460)
Diffstat (limited to 'enigma-swing')
-rw-r--r--enigma-swing/build.gradle30
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/BrowserCaret.java20
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/ClassSelector.java69
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/EditableType.java9
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/EnigmaQuickFindDialog.java26
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/EnigmaSyntaxKit.java55
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/ExceptionIgnorer.java24
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java127
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java149
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/Main.java106
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java37
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/QuickFindAction.java9
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/ReadableToken.java19
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/TokenListCellRenderer.java30
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/config/LookAndFeel.java11
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/config/NetConfig.java2
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/config/OldConfigImporter.java4
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/config/Themes.java9
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/config/UiConfig.java15
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/config/legacy/Config.java20
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AboutDialog.java31
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AbstractDialog.java12
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ChangeDialog.java2
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ConnectToServerDialog.java27
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CrashDialog.java50
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CreateServerDialog.java24
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/FontDialog.java30
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java74
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ProgressDialog.java33
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java92
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/StatsDialog.java23
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/elements/AbstractInheritanceTree.java9
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/elements/CallsTree.java16
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/elements/CollapsibleTabbedPane.java11
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ConvertingTextField.java43
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/elements/DeobfPanelPopupMenu.java101
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorPopupMenu.java66
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabPopupMenu.java1
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabbedPane.java11
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/elements/JMultiLineToolTip.java19
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java99
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/elements/StatusBar.java2
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatablePasswordField.java2
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableTextArea.java2
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableTextField.java2
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableUi.java43
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/events/ConvertingTextFieldListener.java2
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/events/EditorActionListener.java2
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/events/ThemeChangeListener.java2
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/highlight/BoxHighlightPainter.java19
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/highlight/SelectionHighlightPainter.java26
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/newabstraction/EntryValidation.java3
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java34
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java27
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ClosableTabTitlePane.java28
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/panels/DeobfPanel.java3
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/panels/EditorPanel.java223
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/panels/IdentifierPanel.java48
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ObfPanel.java4
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/panels/StructurePanel.java291
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/CallsTreeCellRenderer.java78
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/ImplementationsTreeCellRenderer.java39
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/InheritanceTreeCellRenderer.java19
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/MessageListCellRenderer.java4
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/StructureOptionListCellRenderer.java25
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/search/SearchEntry.java2
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/search/SearchUtil.java71
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java212
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsMember.java8
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsResult.java6
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/util/AbstractListCellRenderer.java17
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/util/GridBagConstraintsBuilder.java2
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/util/GuiUtil.java334
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/util/History.java4
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/util/LanguageChangeListener.java2
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/util/LanguageUtil.java2
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/util/ScaleChangeListener.java2
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/util/ScaleUtil.java5
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/util/SingleTreeSelectionModel.java7
79 files changed, 1757 insertions, 1390 deletions
diff --git a/enigma-swing/build.gradle b/enigma-swing/build.gradle
index d783e950..a4a13d88 100644
--- a/enigma-swing/build.gradle
+++ b/enigma-swing/build.gradle
@@ -1,18 +1,18 @@
1plugins { 1plugins {
2 id 'application' 2 id 'application'
3 id 'com.github.johnrengelman.shadow' version '7.0.0' 3 id 'com.github.johnrengelman.shadow' version '7.0.0'
4} 4}
5 5
6dependencies { 6dependencies {
7 implementation project(':enigma') 7 implementation project(':enigma')
8 implementation project(':enigma-server') 8 implementation project(':enigma-server')
9 9
10 implementation 'net.sf.jopt-simple:jopt-simple:6.0-alpha-3' 10 implementation 'net.sf.jopt-simple:jopt-simple:6.0-alpha-3'
11 implementation 'com.formdev:flatlaf:1.6.1' 11 implementation 'com.formdev:flatlaf:1.6.1'
12 implementation 'com.formdev:flatlaf-extras:1.6.1' // for SVG icons 12 implementation 'com.formdev:flatlaf-extras:1.6.1' // for SVG icons
13 implementation 'de.sciss:syntaxpane:1.2.0' 13 implementation 'de.sciss:syntaxpane:1.2.0'
14 implementation 'com.github.lukeu:swing-dpi:0.9' 14 implementation 'com.github.lukeu:swing-dpi:0.9'
15 implementation 'org.drjekyll:fontchooser:2.5.2' 15 implementation 'org.drjekyll:fontchooser:2.5.2'
16} 16}
17 17
18mainClassName = 'cuchaz.enigma.gui.Main' 18mainClassName = 'cuchaz.enigma.gui.Main'
@@ -20,9 +20,9 @@ mainClassName = 'cuchaz.enigma.gui.Main'
20jar.manifest.attributes 'Main-Class': mainClassName 20jar.manifest.attributes 'Main-Class': mainClassName
21 21
22publishing { 22publishing {
23 publications { 23 publications {
24 shadow(MavenPublication) { publication -> 24 shadow(MavenPublication) { publication ->
25 publication.from components.java 25 publication.from components.java
26 } 26 }
27 } 27 }
28} 28}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/BrowserCaret.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/BrowserCaret.java
index af105dbd..a213a592 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/BrowserCaret.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/BrowserCaret.java
@@ -1,20 +1,19 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 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 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.gui; 12package cuchaz.enigma.gui;
13 13
14import javax.swing.text.DefaultCaret; 14import javax.swing.text.DefaultCaret;
15 15
16public class BrowserCaret extends DefaultCaret { 16public class BrowserCaret extends DefaultCaret {
17
18 @Override 17 @Override
19 public boolean isSelectionVisible() { 18 public boolean isSelectionVisible() {
20 return true; 19 return true;
@@ -24,5 +23,4 @@ public class BrowserCaret extends DefaultCaret {
24 public boolean isVisible() { 23 public boolean isVisible() {
25 return true; 24 return true;
26 } 25 }
27
28} 26}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/ClassSelector.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/ClassSelector.java
index b7d3c4ef..4b9fa595 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/ClassSelector.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/ClassSelector.java
@@ -1,35 +1,43 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 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 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.gui; 12package cuchaz.enigma.gui;
13 13
14import cuchaz.enigma.gui.node.ClassSelectorClassNode; 14import java.awt.Component;
15import cuchaz.enigma.gui.util.GuiUtil;
16import cuchaz.enigma.translation.representation.entry.ClassEntry;
17import cuchaz.enigma.utils.validation.ValidationContext;
18
19import javax.swing.*;
20import javax.swing.event.CellEditorListener;
21import javax.swing.event.ChangeEvent;
22import javax.swing.tree.*;
23import java.awt.*;
24import java.awt.event.KeyAdapter; 15import java.awt.event.KeyAdapter;
25import java.awt.event.KeyEvent; 16import java.awt.event.KeyEvent;
26import java.awt.event.MouseAdapter; 17import java.awt.event.MouseAdapter;
27import java.awt.event.MouseEvent; 18import java.awt.event.MouseEvent;
19import java.util.ArrayList;
20import java.util.Collection;
21import java.util.Comparator;
22import java.util.EventObject;
28import java.util.List; 23import java.util.List;
29import java.util.*;
30 24
31public class ClassSelector extends JTree { 25import javax.swing.JTree;
26import javax.swing.event.CellEditorListener;
27import javax.swing.event.ChangeEvent;
28import javax.swing.tree.DefaultMutableTreeNode;
29import javax.swing.tree.DefaultTreeCellEditor;
30import javax.swing.tree.DefaultTreeCellRenderer;
31import javax.swing.tree.DefaultTreeModel;
32import javax.swing.tree.TreeNode;
33import javax.swing.tree.TreePath;
34
35import cuchaz.enigma.gui.node.ClassSelectorClassNode;
36import cuchaz.enigma.gui.util.GuiUtil;
37import cuchaz.enigma.translation.representation.entry.ClassEntry;
38import cuchaz.enigma.utils.validation.ValidationContext;
32 39
40public class ClassSelector extends JTree {
33 public static final Comparator<ClassEntry> DEOBF_CLASS_COMPARATOR = Comparator.comparing(ClassEntry::getFullName); 41 public static final Comparator<ClassEntry> DEOBF_CLASS_COMPARATOR = Comparator.comparing(ClassEntry::getFullName);
34 42
35 private final Comparator<ClassEntry> comparator; 43 private final Comparator<ClassEntry> comparator;
@@ -56,6 +64,7 @@ public class ClassSelector extends JTree {
56 if (selectionListener != null && event.getClickCount() == 2) { 64 if (selectionListener != null && event.getClickCount() == 2) {
57 // get the selected node 65 // get the selected node
58 TreePath path = getSelectionPath(); 66 TreePath path = getSelectionPath();
67
59 if (path != null && path.getLastPathComponent() instanceof ClassSelectorClassNode node) { 68 if (path != null && path.getLastPathComponent() instanceof ClassSelectorClassNode node) {
60 selectionListener.onSelectClass(node.getObfEntry()); 69 selectionListener.onSelectClass(node.getObfEntry());
61 } 70 }
@@ -121,23 +130,31 @@ public class ClassSelector extends JTree {
121 TreePath path = getSelectionPath(); 130 TreePath path = getSelectionPath();
122 131
123 Object realPath = path.getLastPathComponent(); 132 Object realPath = path.getLastPathComponent();
133
124 if (realPath instanceof DefaultMutableTreeNode node && data != null) { 134 if (realPath instanceof DefaultMutableTreeNode node && data != null) {
125 TreeNode parentNode = node.getParent(); 135 TreeNode parentNode = node.getParent();
126 if (parentNode == null) 136
137 if (parentNode == null) {
127 return; 138 return;
139 }
140
128 boolean allowEdit = true; 141 boolean allowEdit = true;
142
129 for (int i = 0; i < parentNode.getChildCount(); i++) { 143 for (int i = 0; i < parentNode.getChildCount(); i++) {
130 TreeNode childNode = parentNode.getChildAt(i); 144 TreeNode childNode = parentNode.getChildAt(i);
145
131 if (childNode != null && childNode.toString().equals(data) && childNode != node) { 146 if (childNode != null && childNode.toString().equals(data) && childNode != node) {
132 allowEdit = false; 147 allowEdit = false;
133 break; 148 break;
134 } 149 }
135 } 150 }
151
136 if (allowEdit && renameSelectionListener != null) { 152 if (allowEdit && renameSelectionListener != null) {
137 Object prevData = node.getUserObject(); 153 Object prevData = node.getUserObject();
138 Object objectData = node.getUserObject() instanceof ClassEntry ? new ClassEntry(((ClassEntry) prevData).getPackageName() + "/" + data) : data; 154 Object objectData = node.getUserObject() instanceof ClassEntry ? new ClassEntry(((ClassEntry) prevData).getPackageName() + "/" + data) : data;
139 gui.validateImmediateAction(vc -> { 155 gui.validateImmediateAction(vc -> {
140 renameSelectionListener.onSelectionRename(vc, node.getUserObject(), objectData, node); 156 renameSelectionListener.onSelectionRename(vc, node.getUserObject(), objectData, node);
157
141 if (vc.canProceed()) { 158 if (vc.canProceed()) {
142 node.setUserObject(objectData); // Make sure that it's modified 159 node.setUserObject(objectData); // Make sure that it's modified
143 } else { 160 } else {
@@ -206,15 +223,19 @@ public class ClassSelector extends JTree {
206 public List<StateEntry> getExpansionState() { 223 public List<StateEntry> getExpansionState() {
207 List<StateEntry> state = new ArrayList<>(); 224 List<StateEntry> state = new ArrayList<>();
208 int rowCount = getRowCount(); 225 int rowCount = getRowCount();
226
209 for (int i = 0; i < rowCount; i++) { 227 for (int i = 0; i < rowCount; i++) {
210 TreePath path = getPathForRow(i); 228 TreePath path = getPathForRow(i);
229
211 if (isPathSelected(path)) { 230 if (isPathSelected(path)) {
212 state.add(new StateEntry(State.SELECTED, path)); 231 state.add(new StateEntry(State.SELECTED, path));
213 } 232 }
233
214 if (isExpanded(path)) { 234 if (isExpanded(path)) {
215 state.add(new StateEntry(State.EXPANDED, path)); 235 state.add(new StateEntry(State.EXPANDED, path));
216 } 236 }
217 } 237 }
238
218 return state; 239 return state;
219 } 240 }
220 241
@@ -223,8 +244,8 @@ public class ClassSelector extends JTree {
223 244
224 for (StateEntry entry : expansionState) { 245 for (StateEntry entry : expansionState) {
225 switch (entry.state) { 246 switch (entry.state) {
226 case SELECTED -> addSelectionPath(entry.path); 247 case SELECTED -> addSelectionPath(entry.path);
227 case EXPANDED -> expandPath(entry.path); 248 case EXPANDED -> expandPath(entry.path);
228 } 249 }
229 } 250 }
230 } 251 }
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/EditableType.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/EditableType.java
index 1e8d6cf0..6028609f 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/EditableType.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/EditableType.java
@@ -2,7 +2,11 @@ package cuchaz.enigma.gui;
2 2
3import javax.annotation.Nullable; 3import javax.annotation.Nullable;
4 4
5import cuchaz.enigma.translation.representation.entry.*; 5import cuchaz.enigma.translation.representation.entry.ClassEntry;
6import cuchaz.enigma.translation.representation.entry.Entry;
7import cuchaz.enigma.translation.representation.entry.FieldEntry;
8import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
9import cuchaz.enigma.translation.representation.entry.MethodEntry;
6 10
7public enum EditableType { 11public enum EditableType {
8 CLASS, 12 CLASS,
@@ -10,8 +14,7 @@ public enum EditableType {
10 FIELD, 14 FIELD,
11 PARAMETER, 15 PARAMETER,
12 LOCAL_VARIABLE, 16 LOCAL_VARIABLE,
13 JAVADOC, 17 JAVADOC;
14 ;
15 18
16 @Nullable 19 @Nullable
17 public static EditableType fromEntry(Entry<?> entry) { 20 public static EditableType fromEntry(Entry<?> entry) {
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/EnigmaQuickFindDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/EnigmaQuickFindDialog.java
index c912be3a..0af8f9c1 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/EnigmaQuickFindDialog.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/EnigmaQuickFindDialog.java
@@ -1,16 +1,22 @@
1package cuchaz.enigma.gui; 1package cuchaz.enigma.gui;
2 2
3import de.sciss.syntaxpane.actions.DocumentSearchData; 3import java.awt.Component;
4import de.sciss.syntaxpane.actions.gui.QuickFindDialog; 4import java.awt.Container;
5 5import java.awt.Point;
6import javax.swing.*;
7import javax.swing.text.JTextComponent;
8import java.awt.*;
9import java.awt.event.KeyAdapter; 6import java.awt.event.KeyAdapter;
10import java.awt.event.KeyEvent; 7import java.awt.event.KeyEvent;
11import java.util.stream.IntStream; 8import java.util.stream.IntStream;
12import java.util.stream.Stream; 9import java.util.stream.Stream;
13 10
11import javax.swing.JButton;
12import javax.swing.JTextField;
13import javax.swing.JToolBar;
14import javax.swing.SwingUtilities;
15import javax.swing.text.JTextComponent;
16
17import de.sciss.syntaxpane.actions.DocumentSearchData;
18import de.sciss.syntaxpane.actions.gui.QuickFindDialog;
19
14public class EnigmaQuickFindDialog extends QuickFindDialog { 20public class EnigmaQuickFindDialog extends QuickFindDialog {
15 public EnigmaQuickFindDialog(JTextComponent target) { 21 public EnigmaQuickFindDialog(JTextComponent target) {
16 super(target, DocumentSearchData.getFromEditor(target)); 22 super(target, DocumentSearchData.getFromEditor(target));
@@ -22,6 +28,7 @@ public class EnigmaQuickFindDialog extends QuickFindDialog {
22 @Override 28 @Override
23 public void keyPressed(KeyEvent e) { 29 public void keyPressed(KeyEvent e) {
24 super.keyPressed(e); 30 super.keyPressed(e);
31
25 if (e.getKeyCode() == KeyEvent.VK_ENTER) { 32 if (e.getKeyCode() == KeyEvent.VK_ENTER) {
26 JToolBar toolBar = getToolBar(); 33 JToolBar toolBar = getToolBar();
27 boolean next = !e.isShiftDown(); 34 boolean next = !e.isShiftDown();
@@ -78,13 +85,10 @@ public class EnigmaQuickFindDialog extends QuickFindDialog {
78 } 85 }
79 86
80 private static Stream<Component> components(Container container) { 87 private static Stream<Component> components(Container container) {
81 return IntStream.range(0, container.getComponentCount()) 88 return IntStream.range(0, container.getComponentCount()).mapToObj(container::getComponent);
82 .mapToObj(container::getComponent);
83 } 89 }
84 90
85 private static <T extends Component> Stream<T> components(Container container, Class<T> type) { 91 private static <T extends Component> Stream<T> components(Container container, Class<T> type) {
86 return components(container) 92 return components(container).filter(type::isInstance).map(type::cast);
87 .filter(type::isInstance)
88 .map(type::cast);
89 } 93 }
90} 94}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/EnigmaSyntaxKit.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/EnigmaSyntaxKit.java
index 43745dd9..b81782eb 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/EnigmaSyntaxKit.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/EnigmaSyntaxKit.java
@@ -10,7 +10,6 @@ import de.sciss.syntaxpane.util.Configuration;
10import cuchaz.enigma.gui.config.UiConfig; 10import cuchaz.enigma.gui.config.UiConfig;
11 11
12public class EnigmaSyntaxKit extends JavaSyntaxKit { 12public class EnigmaSyntaxKit extends JavaSyntaxKit {
13
14 private static Configuration configuration = null; 13 private static Configuration configuration = null;
15 14
16 @Override 15 @Override
@@ -18,23 +17,20 @@ public class EnigmaSyntaxKit extends JavaSyntaxKit {
18 if (configuration == null) { 17 if (configuration == null) {
19 initConfig(DefaultSyntaxKit.getConfig(JavaSyntaxKit.class)); 18 initConfig(DefaultSyntaxKit.getConfig(JavaSyntaxKit.class));
20 } 19 }
20
21 return configuration; 21 return configuration;
22 } 22 }
23 23
24 public void initConfig(Configuration baseConfig) { 24 public void initConfig(Configuration baseConfig) {
25 configuration = flattenConfiguration(baseConfig, EnigmaSyntaxKit.class); 25 configuration = flattenConfiguration(baseConfig, EnigmaSyntaxKit.class);
26 26
27 // Remove all actions except a select few because they disregard the 27 // Remove all actions except a select few because they disregard the
28 // editable state of the editor, or at least are useless anyway because 28 // editable state of the editor, or at least are useless anyway because
29 // they would try editing the file. 29 // they would try editing the file.
30 // Also includes the Action.insert-date action which is written in 30 // Also includes the Action.insert-date action which is written in
31 // Javascript and causes the editor to freeze on first load for a short 31 // Javascript and causes the editor to freeze on first load for a short
32 // time. 32 // time.
33 configuration.keySet().removeIf(s -> s.startsWith("Action.") && 33 configuration.keySet().removeIf(s -> s.startsWith("Action.") && !(s.startsWith("Action.find") || s.startsWith("Action.goto-line") || s.startsWith("Action.jump-to-pair") || s.startsWith("Action.quick-find")));
34 !(s.startsWith("Action.find") ||
35 s.startsWith("Action.goto-line") ||
36 s.startsWith("Action.jump-to-pair") ||
37 s.startsWith("Action.quick-find")));
38 34
39 // See de.sciss.syntaxpane.TokenType 35 // See de.sciss.syntaxpane.TokenType
40 configuration.put("Style.KEYWORD", String.format("%d, 0", UiConfig.getHighlightColor().getRGB())); 36 configuration.put("Style.KEYWORD", String.format("%d, 0", UiConfig.getHighlightColor().getRGB()));
@@ -59,27 +55,28 @@ public class EnigmaSyntaxKit extends JavaSyntaxKit {
59 55
60 Font editorFont = UiConfig.activeUseCustomFonts() ? UiConfig.getEditorFont() : UiConfig.getFallbackEditorFont(); 56 Font editorFont = UiConfig.activeUseCustomFonts() ? UiConfig.getEditorFont() : UiConfig.getFallbackEditorFont();
61 configuration.put("DefaultFont", UiConfig.encodeFont(editorFont)); 57 configuration.put("DefaultFont", UiConfig.encodeFont(editorFont));
62 } 58 }
59
60 /**
61 * Creates a new configuration from the passed configuration so that it has
62 * no parents and all its values are on the same level. This is needed since
63 * there is no way to remove map entries from parent configurations.
64 *
65 * @param source the configuration to flatten
66 * @param configClass the class for the new configuration
67 * @return a new configuration
68 */
69 private static Configuration flattenConfiguration(Configuration source, Class<?> configClass) {
70 Configuration config = new Configuration(configClass, null);
63 71
64 /** 72 for (String p : source.stringPropertyNames()) {
65 * Creates a new configuration from the passed configuration so that it has 73 config.put(p, source.getString(p));
66 * no parents and all its values are on the same level. This is needed since 74 }
67 * there is no way to remove map entries from parent configurations. 75
68 * 76 return config;
69 * @param source the configuration to flatten
70 * @param configClass the class for the new configuration
71 * @return a new configuration
72 */
73 private static Configuration flattenConfiguration(Configuration source, Class<?> configClass) {
74 Configuration config = new Configuration(configClass, null);
75 for (String p : source.stringPropertyNames()) {
76 config.put(p, source.getString(p));
77 }
78 return config;
79 } 77 }
80 78
81 public static void invalidate() { 79 public static void invalidate() {
82 configuration = null; 80 configuration = null;
83 } 81 }
84
85} 82}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/ExceptionIgnorer.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/ExceptionIgnorer.java
index 6246192c..76d18598 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/ExceptionIgnorer.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/ExceptionIgnorer.java
@@ -1,28 +1,27 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 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 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.gui; 12package cuchaz.enigma.gui;
13 13
14public class ExceptionIgnorer { 14public class ExceptionIgnorer {
15
16 public static boolean shouldIgnore(Throwable t) { 15 public static boolean shouldIgnore(Throwable t) {
17
18 // is this that pesky concurrent access bug in the highlight painter system? 16 // is this that pesky concurrent access bug in the highlight painter system?
19 // (ancient ui code is ancient) 17 // (ancient ui code is ancient)
20 if (t instanceof ArrayIndexOutOfBoundsException) { 18 if (t instanceof ArrayIndexOutOfBoundsException) {
21 StackTraceElement[] stackTrace = t.getStackTrace(); 19 StackTraceElement[] stackTrace = t.getStackTrace();
22 if (stackTrace.length > 1) {
23 20
21 if (stackTrace.length > 1) {
24 // does this stack frame match javax.swing.text.DefaultHighlighter.paint*() ? 22 // does this stack frame match javax.swing.text.DefaultHighlighter.paint*() ?
25 StackTraceElement frame = stackTrace[1]; 23 StackTraceElement frame = stackTrace[1];
24
26 if (frame.getClassName().equals("javax.swing.text.DefaultHighlighter") && frame.getMethodName().startsWith("paint")) { 25 if (frame.getClassName().equals("javax.swing.text.DefaultHighlighter") && frame.getMethodName().startsWith("paint")) {
27 return true; 26 return true;
28 } 27 }
@@ -31,5 +30,4 @@ public class ExceptionIgnorer {
31 30
32 return false; 31 return false;
33 } 32 }
34
35} 33}
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 5a1e3d8b..b3117ce2 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 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 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.gui; 12package cuchaz.enigma.gui;
13 13
@@ -17,7 +17,6 @@ import java.awt.Point;
17import java.awt.event.ActionEvent; 17import java.awt.event.ActionEvent;
18import java.nio.file.Path; 18import java.nio.file.Path;
19import java.util.Collection; 19import java.util.Collection;
20import java.util.Collections;
21import java.util.List; 20import java.util.List;
22import java.util.Set; 21import java.util.Set;
23import java.util.concurrent.CompletableFuture; 22import java.util.concurrent.CompletableFuture;
@@ -25,12 +24,23 @@ import java.util.function.Consumer;
25import java.util.function.Function; 24import java.util.function.Function;
26 25
27import javax.annotation.Nullable; 26import javax.annotation.Nullable;
28import javax.swing.*; 27import javax.swing.AbstractAction;
28import javax.swing.DefaultListModel;
29import javax.swing.JButton;
30import javax.swing.JFileChooser;
31import javax.swing.JFrame;
32import javax.swing.JLabel;
33import javax.swing.JList;
34import javax.swing.JOptionPane;
35import javax.swing.JPanel;
36import javax.swing.JScrollBar;
37import javax.swing.JScrollPane;
38import javax.swing.JSplitPane;
39import javax.swing.JTabbedPane;
40import javax.swing.JTextField;
41import javax.swing.SwingUtilities;
42import javax.swing.WindowConstants;
29import javax.swing.tree.DefaultMutableTreeNode; 43import javax.swing.tree.DefaultMutableTreeNode;
30import javax.swing.tree.TreeNode;
31import javax.swing.tree.TreePath;
32
33import com.google.common.collect.Lists;
34 44
35import cuchaz.enigma.Enigma; 45import cuchaz.enigma.Enigma;
36import cuchaz.enigma.EnigmaProfile; 46import cuchaz.enigma.EnigmaProfile;
@@ -39,8 +49,19 @@ import cuchaz.enigma.gui.config.Themes;
39import cuchaz.enigma.gui.config.UiConfig; 49import cuchaz.enigma.gui.config.UiConfig;
40import cuchaz.enigma.gui.dialog.JavadocDialog; 50import cuchaz.enigma.gui.dialog.JavadocDialog;
41import cuchaz.enigma.gui.dialog.SearchDialog; 51import cuchaz.enigma.gui.dialog.SearchDialog;
42import cuchaz.enigma.gui.elements.*; 52import cuchaz.enigma.gui.elements.CallsTree;
43import cuchaz.enigma.gui.panels.*; 53import cuchaz.enigma.gui.elements.CollapsibleTabbedPane;
54import cuchaz.enigma.gui.elements.EditorTabbedPane;
55import cuchaz.enigma.gui.elements.ImplementationsTree;
56import cuchaz.enigma.gui.elements.InheritanceTree;
57import cuchaz.enigma.gui.elements.MainWindow;
58import cuchaz.enigma.gui.elements.MenuBar;
59import cuchaz.enigma.gui.elements.ValidatableUi;
60import cuchaz.enigma.gui.panels.DeobfPanel;
61import cuchaz.enigma.gui.panels.EditorPanel;
62import cuchaz.enigma.gui.panels.IdentifierPanel;
63import cuchaz.enigma.gui.panels.ObfPanel;
64import cuchaz.enigma.gui.panels.StructurePanel;
44import cuchaz.enigma.gui.renderer.MessageListCellRenderer; 65import cuchaz.enigma.gui.renderer.MessageListCellRenderer;
45import cuchaz.enigma.gui.util.GuiUtil; 66import cuchaz.enigma.gui.util.GuiUtil;
46import cuchaz.enigma.gui.util.LanguageUtil; 67import cuchaz.enigma.gui.util.LanguageUtil;
@@ -57,7 +78,6 @@ import cuchaz.enigma.utils.validation.ParameterizedMessage;
57import cuchaz.enigma.utils.validation.ValidationContext; 78import cuchaz.enigma.utils.validation.ValidationContext;
58 79
59public class Gui { 80public class Gui {
60
61 private final MainWindow mainWindow = new MainWindow(Enigma.NAME); 81 private final MainWindow mainWindow = new MainWindow(Enigma.NAME);
62 private final GuiController controller; 82 private final GuiController controller;
63 83
@@ -179,6 +199,7 @@ public class Gui {
179 199
180 // restore state 200 // restore state
181 int[] layout = UiConfig.getLayout(); 201 int[] layout = UiConfig.getLayout();
202
182 if (layout.length >= 4) { 203 if (layout.length >= 4) {
183 this.splitClasses.setDividerLocation(layout[0]); 204 this.splitClasses.setDividerLocation(layout[0]);
184 this.splitCenter.setDividerLocation(layout[1]); 205 this.splitCenter.setDividerLocation(layout[1]);
@@ -200,6 +221,7 @@ public class Gui {
200 frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); 221 frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
201 222
202 Point windowPos = UiConfig.getWindowPos("Main Window", null); 223 Point windowPos = UiConfig.getWindowPos("Main Window", null);
224
203 if (windowPos != null) { 225 if (windowPos != null) {
204 frame.setLocation(windowPos); 226 frame.setLocation(windowPos);
205 } else { 227 } else {
@@ -327,18 +349,26 @@ public class Gui {
327 349
328 public void startDocChange(EditorPanel editor) { 350 public void startDocChange(EditorPanel editor) {
329 EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference(); 351 EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference();
330 if (cursorReference == null || !this.isEditable(EditableType.JAVADOC)) return; 352
353 if (cursorReference == null || !this.isEditable(EditableType.JAVADOC)) {
354 return;
355 }
356
331 JavadocDialog.show(mainWindow.frame(), getController(), cursorReference); 357 JavadocDialog.show(mainWindow.frame(), getController(), cursorReference);
332 } 358 }
333 359
334 public void startRename(EditorPanel editor, String text) { 360 public void startRename(EditorPanel editor, String text) {
335 if (editor != this.editorTabbedPane.getActiveEditor()) return; 361 if (editor != this.editorTabbedPane.getActiveEditor()) {
362 return;
363 }
336 364
337 infoPanel.startRenaming(text); 365 infoPanel.startRenaming(text);
338 } 366 }
339 367
340 public void startRename(EditorPanel editor) { 368 public void startRename(EditorPanel editor) {
341 if (editor != this.editorTabbedPane.getActiveEditor()) return; 369 if (editor != this.editorTabbedPane.getActiveEditor()) {
370 return;
371 }
342 372
343 infoPanel.startRenaming(); 373 infoPanel.startRenaming();
344 } 374 }
@@ -349,7 +379,10 @@ public class Gui {
349 379
350 public void showInheritance(EditorPanel editor) { 380 public void showInheritance(EditorPanel editor) {
351 EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference(); 381 EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference();
352 if (cursorReference == null) return; 382
383 if (cursorReference == null) {
384 return;
385 }
353 386
354 this.inheritanceTree.display(cursorReference.entry); 387 this.inheritanceTree.display(cursorReference.entry);
355 tabs.setSelectedIndex(1); 388 tabs.setSelectedIndex(1);
@@ -357,7 +390,10 @@ public class Gui {
357 390
358 public void showImplementations(EditorPanel editor) { 391 public void showImplementations(EditorPanel editor) {
359 EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference(); 392 EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference();
360 if (cursorReference == null) return; 393
394 if (cursorReference == null) {
395 return;
396 }
361 397
362 this.implementationsTree.display(cursorReference.entry); 398 this.implementationsTree.display(cursorReference.entry);
363 tabs.setSelectedIndex(2); 399 tabs.setSelectedIndex(2);
@@ -365,7 +401,10 @@ public class Gui {
365 401
366 public void showCalls(EditorPanel editor, boolean recurse) { 402 public void showCalls(EditorPanel editor, boolean recurse) {
367 EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference(); 403 EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference();
368 if (cursorReference == null) return; 404
405 if (cursorReference == null) {
406 return;
407 }
369 408
370 this.callsTree.showCalls(cursorReference.entry, recurse); 409 this.callsTree.showCalls(cursorReference.entry, recurse);
371 tabs.setSelectedIndex(3); 410 tabs.setSelectedIndex(3);
@@ -373,7 +412,10 @@ public class Gui {
373 412
374 public void toggleMapping(EditorPanel editor) { 413 public void toggleMapping(EditorPanel editor) {
375 EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference(); 414 EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference();
376 if (cursorReference == null) return; 415
416 if (cursorReference == null) {
417 return;
418 }
377 419
378 Entry<?> obfEntry = cursorReference.entry; 420 Entry<?> obfEntry = cursorReference.entry;
379 toggleMappingFromEntry(obfEntry); 421 toggleMappingFromEntry(obfEntry);
@@ -388,14 +430,15 @@ public class Gui {
388 } 430 }
389 431
390 public void showDiscardDiag(Function<Integer, Void> callback, String... options) { 432 public void showDiscardDiag(Function<Integer, Void> callback, String... options) {
391 int response = JOptionPane.showOptionDialog(this.mainWindow.frame(), I18n.translate("prompt.close.summary"), I18n.translate("prompt.close.title"), JOptionPane.YES_NO_CANCEL_OPTION, 433 int response = JOptionPane.showOptionDialog(this.mainWindow.frame(), I18n.translate("prompt.close.summary"), I18n.translate("prompt.close.title"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[2]);
392 JOptionPane.QUESTION_MESSAGE, null, options, options[2]);
393 callback.apply(response); 434 callback.apply(response);
394 } 435 }
395 436
396 public CompletableFuture<Void> saveMapping() { 437 public CompletableFuture<Void> saveMapping() {
397 if (this.enigmaMappingsFileChooser.getSelectedFile() != null || this.enigmaMappingsFileChooser.showSaveDialog(this.mainWindow.frame()) == JFileChooser.APPROVE_OPTION) 438 if (this.enigmaMappingsFileChooser.getSelectedFile() != null || this.enigmaMappingsFileChooser.showSaveDialog(this.mainWindow.frame()) == JFileChooser.APPROVE_OPTION) {
398 return this.controller.saveMappings(this.enigmaMappingsFileChooser.getSelectedFile().toPath()); 439 return this.controller.saveMappings(this.enigmaMappingsFileChooser.getSelectedFile().toPath());
440 }
441
399 return CompletableFuture.completedFuture(null); 442 return CompletableFuture.completedFuture(null);
400 } 443 }
401 444
@@ -421,16 +464,13 @@ public class Gui {
421 private void exit() { 464 private void exit() {
422 UiConfig.setWindowPos("Main Window", this.mainWindow.frame().getLocationOnScreen()); 465 UiConfig.setWindowPos("Main Window", this.mainWindow.frame().getLocationOnScreen());
423 UiConfig.setWindowSize("Main Window", this.mainWindow.frame().getSize()); 466 UiConfig.setWindowSize("Main Window", this.mainWindow.frame().getSize());
424 UiConfig.setLayout( 467 UiConfig.setLayout(this.splitClasses.getDividerLocation(), this.splitCenter.getDividerLocation(), this.splitRight.getDividerLocation(), this.logSplit.getDividerLocation());
425 this.splitClasses.getDividerLocation(),
426 this.splitCenter.getDividerLocation(),
427 this.splitRight.getDividerLocation(),
428 this.logSplit.getDividerLocation());
429 UiConfig.save(); 468 UiConfig.save();
430 469
431 if (searchDialog != null) { 470 if (searchDialog != null) {
432 searchDialog.dispose(); 471 searchDialog.dispose();
433 } 472 }
473
434 this.mainWindow.frame().dispose(); 474 this.mainWindow.frame().dispose();
435 System.exit(0); 475 System.exit(0);
436 } 476 }
@@ -452,6 +492,7 @@ public class Gui {
452 492
453 onRenameFromClassTree(vc, prevDataChild, dataChild, node); 493 onRenameFromClassTree(vc, prevDataChild, dataChild, node);
454 } 494 }
495
455 node.setUserObject(data); 496 node.setUserObject(data);
456 // Ob package will never be modified, just reload deob view 497 // Ob package will never be modified, just reload deob view
457 this.deobfPanel.deobfClasses.reload(); 498 this.deobfPanel.deobfClasses.reload();
@@ -462,11 +503,7 @@ public class Gui {
462 // fast enough for now 503 // fast enough for now
463 EntryRemapper mapper = this.controller.project.getMapper(); 504 EntryRemapper mapper = this.controller.project.getMapper();
464 ClassEntry deobf = (ClassEntry) prevData; 505 ClassEntry deobf = (ClassEntry) prevData;
465 ClassEntry obf = mapper.getObfToDeobf().getAllEntries() 506 ClassEntry obf = mapper.getObfToDeobf().getAllEntries().filter(e -> e instanceof ClassEntry).map(e -> (ClassEntry) e).filter(e -> mapper.deobfuscate(e).equals(deobf)).findAny().orElse(deobf);
466 .filter(e -> e instanceof ClassEntry)
467 .map(e -> (ClassEntry) e)
468 .filter(e -> mapper.deobfuscate(e).equals(deobf))
469 .findAny().orElse(deobf);
470 507
471 this.controller.applyChange(vc, EntryChange.modify(obf).withDeobfName(((ClassEntry) data).getFullName())); 508 this.controller.applyChange(vc, EntryChange.modify(obf).withDeobfName(((ClassEntry) data).getFullName()));
472 } else { 509 } else {
@@ -493,16 +530,12 @@ public class Gui {
493 this.obfPanel.obfClasses.removeEntry(classEntry); 530 this.obfPanel.obfClasses.removeEntry(classEntry);
494 this.deobfPanel.deobfClasses.reload(); 531 this.deobfPanel.deobfClasses.reload();
495 this.obfPanel.obfClasses.reload(); 532 this.obfPanel.obfClasses.reload();
496 } 533 } else if (!isOldOb) { // Deob -> ob
497 // Deob -> ob
498 else if (!isOldOb) {
499 this.obfPanel.obfClasses.moveClassIn(classEntry); 534 this.obfPanel.obfClasses.moveClassIn(classEntry);
500 this.deobfPanel.deobfClasses.removeEntry(classEntry); 535 this.deobfPanel.deobfClasses.removeEntry(classEntry);
501 this.deobfPanel.deobfClasses.reload(); 536 this.deobfPanel.deobfClasses.reload();
502 this.obfPanel.obfClasses.reload(); 537 this.obfPanel.obfClasses.reload();
503 } 538 } else if (isOldOb) { // Local move
504 // Local move
505 else if (isOldOb) {
506 this.obfPanel.obfClasses.moveClassIn(classEntry); 539 this.obfPanel.obfClasses.moveClassIn(classEntry);
507 this.obfPanel.obfClasses.reload(); 540 this.obfPanel.obfClasses.reload();
508 } else { 541 } else {
@@ -526,6 +559,7 @@ public class Gui {
526 if (searchDialog == null) { 559 if (searchDialog == null) {
527 searchDialog = new SearchDialog(this); 560 searchDialog = new SearchDialog(this);
528 } 561 }
562
529 return searchDialog; 563 return searchDialog;
530 } 564 }
531 565
@@ -549,9 +583,11 @@ public class Gui {
549 583
550 private void sendMessage() { 584 private void sendMessage() {
551 String text = chatBox.getText().trim(); 585 String text = chatBox.getText().trim();
586
552 if (!text.isEmpty()) { 587 if (!text.isEmpty()) {
553 getController().sendPacket(new MessageC2SPacket(text)); 588 getController().sendPacket(new MessageC2SPacket(text));
554 } 589 }
590
555 chatBox.setText(""); 591 chatBox.setText("");
556 } 592 }
557 593
@@ -617,16 +653,17 @@ public class Gui {
617 public boolean validateImmediateAction(Consumer<ValidationContext> op) { 653 public boolean validateImmediateAction(Consumer<ValidationContext> op) {
618 ValidationContext vc = new ValidationContext(); 654 ValidationContext vc = new ValidationContext();
619 op.accept(vc); 655 op.accept(vc);
656
620 if (!vc.canProceed()) { 657 if (!vc.canProceed()) {
621 List<ParameterizedMessage> messages = vc.getMessages(); 658 List<ParameterizedMessage> messages = vc.getMessages();
622 String text = ValidatableUi.formatMessages(messages); 659 String text = ValidatableUi.formatMessages(messages);
623 JOptionPane.showMessageDialog(this.getFrame(), text, String.format("%d message(s)", messages.size()), JOptionPane.ERROR_MESSAGE); 660 JOptionPane.showMessageDialog(this.getFrame(), text, String.format("%d message(s)", messages.size()), JOptionPane.ERROR_MESSAGE);
624 } 661 }
662
625 return vc.canProceed(); 663 return vc.canProceed();
626 } 664 }
627 665
628 public boolean isEditable(EditableType t) { 666 public boolean isEditable(EditableType t) {
629 return this.editableTypes.contains(t); 667 return this.editableTypes.contains(t);
630 } 668 }
631
632} 669}
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 47a854f9..0eb9a167 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 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 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.gui; 12package cuchaz.enigma.gui;
13 13
@@ -32,7 +32,17 @@ import com.google.common.collect.Lists;
32import cuchaz.enigma.Enigma; 32import cuchaz.enigma.Enigma;
33import cuchaz.enigma.EnigmaProfile; 33import cuchaz.enigma.EnigmaProfile;
34import cuchaz.enigma.EnigmaProject; 34import cuchaz.enigma.EnigmaProject;
35import cuchaz.enigma.analysis.*; 35import cuchaz.enigma.analysis.ClassImplementationsTreeNode;
36import cuchaz.enigma.analysis.ClassInheritanceTreeNode;
37import cuchaz.enigma.analysis.ClassReferenceTreeNode;
38import cuchaz.enigma.analysis.EntryReference;
39import cuchaz.enigma.analysis.FieldReferenceTreeNode;
40import cuchaz.enigma.analysis.IndexTreeBuilder;
41import cuchaz.enigma.analysis.MethodImplementationsTreeNode;
42import cuchaz.enigma.analysis.MethodInheritanceTreeNode;
43import cuchaz.enigma.analysis.MethodReferenceTreeNode;
44import cuchaz.enigma.analysis.StructureTreeNode;
45import cuchaz.enigma.analysis.StructureTreeOptions;
36import cuchaz.enigma.api.service.ObfuscationTestService; 46import cuchaz.enigma.api.service.ObfuscationTestService;
37import cuchaz.enigma.classhandle.ClassHandle; 47import cuchaz.enigma.classhandle.ClassHandle;
38import cuchaz.enigma.classhandle.ClassHandleProvider; 48import cuchaz.enigma.classhandle.ClassHandleProvider;
@@ -44,7 +54,12 @@ import cuchaz.enigma.gui.newabstraction.EntryValidation;
44import cuchaz.enigma.gui.stats.StatsGenerator; 54import cuchaz.enigma.gui.stats.StatsGenerator;
45import cuchaz.enigma.gui.stats.StatsMember; 55import cuchaz.enigma.gui.stats.StatsMember;
46import cuchaz.enigma.gui.util.History; 56import cuchaz.enigma.gui.util.History;
47import cuchaz.enigma.network.*; 57import cuchaz.enigma.network.ClientPacketHandler;
58import cuchaz.enigma.network.EnigmaClient;
59import cuchaz.enigma.network.EnigmaServer;
60import cuchaz.enigma.network.IntegratedEnigmaServer;
61import cuchaz.enigma.network.Message;
62import cuchaz.enigma.network.ServerPacketHandler;
48import cuchaz.enigma.network.packet.EntryChangeC2SPacket; 63import cuchaz.enigma.network.packet.EntryChangeC2SPacket;
49import cuchaz.enigma.network.packet.LoginC2SPacket; 64import cuchaz.enigma.network.packet.LoginC2SPacket;
50import cuchaz.enigma.network.packet.Packet; 65import cuchaz.enigma.network.packet.Packet;
@@ -54,7 +69,12 @@ import cuchaz.enigma.source.SourceIndex;
54import cuchaz.enigma.source.Token; 69import cuchaz.enigma.source.Token;
55import cuchaz.enigma.translation.TranslateResult; 70import cuchaz.enigma.translation.TranslateResult;
56import cuchaz.enigma.translation.Translator; 71import cuchaz.enigma.translation.Translator;
57import cuchaz.enigma.translation.mapping.*; 72import cuchaz.enigma.translation.mapping.EntryChange;
73import cuchaz.enigma.translation.mapping.EntryMapping;
74import cuchaz.enigma.translation.mapping.EntryRemapper;
75import cuchaz.enigma.translation.mapping.EntryUtil;
76import cuchaz.enigma.translation.mapping.MappingDelta;
77import cuchaz.enigma.translation.mapping.ResolutionStrategy;
58import cuchaz.enigma.translation.mapping.serde.MappingFormat; 78import cuchaz.enigma.translation.mapping.serde.MappingFormat;
59import cuchaz.enigma.translation.mapping.serde.MappingParseException; 79import cuchaz.enigma.translation.mapping.serde.MappingParseException;
60import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; 80import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters;
@@ -90,9 +110,7 @@ public class GuiController implements ClientPacketHandler {
90 110
91 public GuiController(Gui gui, EnigmaProfile profile) { 111 public GuiController(Gui gui, EnigmaProfile profile) {
92 this.gui = gui; 112 this.gui = gui;
93 this.enigma = Enigma.builder() 113 this.enigma = Enigma.builder().setProfile(profile).build();
94 .setProfile(profile)
95 .build();
96 } 114 }
97 115
98 public boolean isDirty() { 116 public boolean isDirty() {
@@ -121,7 +139,9 @@ public class GuiController implements ClientPacketHandler {
121 } 139 }
122 140
123 public CompletableFuture<Void> openMappings(MappingFormat format, Path path) { 141 public CompletableFuture<Void> openMappings(MappingFormat format, Path path) {
124 if (project == null) return CompletableFuture.completedFuture(null); 142 if (project == null) {
143 return CompletableFuture.completedFuture(null);
144 }
125 145
126 gui.setMappingsFile(path); 146 gui.setMappingsFile(path);
127 147
@@ -145,7 +165,9 @@ public class GuiController implements ClientPacketHandler {
145 165
146 @Override 166 @Override
147 public void openMappings(EntryTree<EntryMapping> mappings) { 167 public void openMappings(EntryTree<EntryMapping> mappings) {
148 if (project == null) return; 168 if (project == null) {
169 return;
170 }
149 171
150 project.setMappings(mappings); 172 project.setMappings(mappings);
151 refreshClasses(); 173 refreshClasses();
@@ -168,7 +190,9 @@ public class GuiController implements ClientPacketHandler {
168 * @return the future of saving 190 * @return the future of saving
169 */ 191 */
170 public CompletableFuture<Void> saveMappings(Path path, MappingFormat format) { 192 public CompletableFuture<Void> saveMappings(Path path, MappingFormat format) {
171 if (project == null) return CompletableFuture.completedFuture(null); 193 if (project == null) {
194 return CompletableFuture.completedFuture(null);
195 }
172 196
173 return ProgressDialog.runOffThread(this.gui.getFrame(), progress -> { 197 return ProgressDialog.runOffThread(this.gui.getFrame(), progress -> {
174 EntryRemapper mapper = project.getMapper(); 198 EntryRemapper mapper = project.getMapper();
@@ -189,7 +213,9 @@ public class GuiController implements ClientPacketHandler {
189 } 213 }
190 214
191 public void closeMappings() { 215 public void closeMappings() {
192 if (project == null) return; 216 if (project == null) {
217 return;
218 }
193 219
194 project.setMappings(null); 220 project.setMappings(null);
195 221
@@ -202,9 +228,11 @@ public class GuiController implements ClientPacketHandler {
202 Path jarPath = this.project.getJarPath(); 228 Path jarPath = this.project.getJarPath();
203 MappingFormat loadedMappingFormat = this.loadedMappingFormat; 229 MappingFormat loadedMappingFormat = this.loadedMappingFormat;
204 Path loadedMappingPath = this.loadedMappingPath; 230 Path loadedMappingPath = this.loadedMappingPath;
231
205 if (jarPath != null) { 232 if (jarPath != null) {
206 this.closeJar(); 233 this.closeJar();
207 CompletableFuture<Void> f = this.openJar(jarPath); 234 CompletableFuture<Void> f = this.openJar(jarPath);
235
208 if (loadedMappingFormat != null && loadedMappingPath != null) { 236 if (loadedMappingFormat != null && loadedMappingPath != null) {
209 f.whenComplete((v, t) -> this.openMappings(loadedMappingFormat, loadedMappingPath)); 237 f.whenComplete((v, t) -> this.openMappings(loadedMappingFormat, loadedMappingPath));
210 } 238 }
@@ -214,6 +242,7 @@ public class GuiController implements ClientPacketHandler {
214 public void reloadMappings() { 242 public void reloadMappings() {
215 MappingFormat loadedMappingFormat = this.loadedMappingFormat; 243 MappingFormat loadedMappingFormat = this.loadedMappingFormat;
216 Path loadedMappingPath = this.loadedMappingPath; 244 Path loadedMappingPath = this.loadedMappingPath;
245
217 if (loadedMappingFormat != null && loadedMappingPath != null) { 246 if (loadedMappingFormat != null && loadedMappingPath != null) {
218 this.closeMappings(); 247 this.closeMappings();
219 this.openMappings(loadedMappingFormat, loadedMappingPath); 248 this.openMappings(loadedMappingFormat, loadedMappingPath);
@@ -221,29 +250,34 @@ public class GuiController implements ClientPacketHandler {
221 } 250 }
222 251
223 public CompletableFuture<Void> dropMappings() { 252 public CompletableFuture<Void> dropMappings() {
224 if (project == null) return CompletableFuture.completedFuture(null); 253 if (project == null) {
254 return CompletableFuture.completedFuture(null);
255 }
225 256
226 return ProgressDialog.runOffThread(this.gui.getFrame(), progress -> project.dropMappings(progress)); 257 return ProgressDialog.runOffThread(this.gui.getFrame(), progress -> project.dropMappings(progress));
227 } 258 }
228 259
229 public CompletableFuture<Void> exportSource(final Path path) { 260 public CompletableFuture<Void> exportSource(final Path path) {
230 if (project == null) return CompletableFuture.completedFuture(null); 261 if (project == null) {
262 return CompletableFuture.completedFuture(null);
263 }
231 264
232 return ProgressDialog.runOffThread(this.gui.getFrame(), progress -> { 265 return ProgressDialog.runOffThread(this.gui.getFrame(), progress -> {
233 EnigmaProject.JarExport jar = project.exportRemappedJar(progress); 266 EnigmaProject.JarExport jar = project.exportRemappedJar(progress);
234 jar.decompileStream(progress, chp.getDecompilerService(), EnigmaProject.DecompileErrorStrategy.TRACE_AS_SOURCE) 267 jar.decompileStream(progress, chp.getDecompilerService(), EnigmaProject.DecompileErrorStrategy.TRACE_AS_SOURCE).forEach(source -> {
235 .forEach(source -> { 268 try {
236 try { 269 source.writeTo(source.resolvePath(path));
237 source.writeTo(source.resolvePath(path)); 270 } catch (IOException e) {
238 } catch (IOException e) { 271 e.printStackTrace();
239 e.printStackTrace(); 272 }
240 } 273 });
241 });
242 }); 274 });
243 } 275 }
244 276
245 public CompletableFuture<Void> exportJar(final Path path) { 277 public CompletableFuture<Void> exportJar(final Path path) {
246 if (project == null) return CompletableFuture.completedFuture(null); 278 if (project == null) {
279 return CompletableFuture.completedFuture(null);
280 }
247 281
248 return ProgressDialog.runOffThread(this.gui.getFrame(), progress -> { 282 return ProgressDialog.runOffThread(this.gui.getFrame(), progress -> {
249 EnigmaProject.JarExport jar = project.exportRemappedJar(progress); 283 EnigmaProject.JarExport jar = project.exportRemappedJar(progress);
@@ -269,20 +303,14 @@ public class GuiController implements ClientPacketHandler {
269 } 303 }
270 304
271 try { 305 try {
272 return tokenHandle.getSource().get() 306 return tokenHandle.getSource().get().map(DecompiledClassSource::getIndex).map(index -> new ReadableToken(index.getLineNumber(token.start), index.getColumnNumber(token.start), index.getColumnNumber(token.end))).unwrapOr(null);
273 .map(DecompiledClassSource::getIndex)
274 .map(index -> new ReadableToken(
275 index.getLineNumber(token.start),
276 index.getColumnNumber(token.start),
277 index.getColumnNumber(token.end)))
278 .unwrapOr(null);
279 } catch (InterruptedException | ExecutionException e) { 307 } catch (InterruptedException | ExecutionException e) {
280 throw new RuntimeException(e); 308 throw new RuntimeException(e);
281 } 309 }
282 } 310 }
283 311
284 /** 312 /**
285 * Navigates to the declaration with respect to navigation history 313 * Navigates to the declaration with respect to navigation history.
286 * 314 *
287 * @param entry the entry whose declaration will be navigated to 315 * @param entry the entry whose declaration will be navigated to
288 */ 316 */
@@ -290,11 +318,12 @@ public class GuiController implements ClientPacketHandler {
290 if (entry == null) { 318 if (entry == null) {
291 throw new IllegalArgumentException("Entry cannot be null!"); 319 throw new IllegalArgumentException("Entry cannot be null!");
292 } 320 }
321
293 openReference(EntryReference.declaration(entry, entry.getName())); 322 openReference(EntryReference.declaration(entry, entry.getName()));
294 } 323 }
295 324
296 /** 325 /**
297 * Navigates to the reference with respect to navigation history 326 * Navigates to the reference with respect to navigation history.
298 * 327 *
299 * @param reference the reference 328 * @param reference the reference
300 */ 329 */
@@ -302,6 +331,7 @@ public class GuiController implements ClientPacketHandler {
302 if (reference == null) { 331 if (reference == null) {
303 throw new IllegalArgumentException("Reference cannot be null!"); 332 throw new IllegalArgumentException("Reference cannot be null!");
304 } 333 }
334
305 if (this.referenceHistory == null) { 335 if (this.referenceHistory == null) {
306 this.referenceHistory = new History<>(reference); 336 this.referenceHistory = new History<>(reference);
307 } else { 337 } else {
@@ -317,11 +347,7 @@ public class GuiController implements ClientPacketHandler {
317 EntryRemapper mapper = this.project.getMapper(); 347 EntryRemapper mapper = this.project.getMapper();
318 348
319 SourceIndex index = source.getIndex(); 349 SourceIndex index = source.getIndex();
320 return mapper.getObfResolver().resolveReference(reference, ResolutionStrategy.RESOLVE_CLOSEST) 350 return mapper.getObfResolver().resolveReference(reference, ResolutionStrategy.RESOLVE_CLOSEST).stream().flatMap(r -> index.getReferenceTokens(r).stream()).sorted().toList();
321 .stream()
322 .flatMap(r -> index.getReferenceTokens(r).stream())
323 .sorted()
324 .toList();
325 } 351 }
326 352
327 public void openPreviousReference() { 353 public void openPreviousReference() {
@@ -349,6 +375,7 @@ public class GuiController implements ClientPacketHandler {
349 // entry is not in the jar. Ignore it 375 // entry is not in the jar. Ignore it
350 return; 376 return;
351 } 377 }
378
352 openDeclaration(entry); 379 openDeclaration(entry);
353 } 380 }
354 381
@@ -356,12 +383,15 @@ public class GuiController implements ClientPacketHandler {
356 if (!project.isRenamable(reference.getLocationClassEntry())) { 383 if (!project.isRenamable(reference.getLocationClassEntry())) {
357 return; 384 return;
358 } 385 }
386
359 openReference(reference); 387 openReference(reference);
360 } 388 }
361 389
362 public void refreshClasses() { 390 public void refreshClasses() {
363 if (project == null) return; 391 if (project == null) {
364 392 return;
393 }
394
365 List<ClassEntry> obfClasses = Lists.newArrayList(); 395 List<ClassEntry> obfClasses = Lists.newArrayList();
366 List<ClassEntry> deobfClasses = Lists.newArrayList(); 396 List<ClassEntry> deobfClasses = Lists.newArrayList();
367 this.addSeparatedClasses(obfClasses, deobfClasses); 397 this.addSeparatedClasses(obfClasses, deobfClasses);
@@ -373,8 +403,7 @@ public class GuiController implements ClientPacketHandler {
373 EntryRemapper mapper = project.getMapper(); 403 EntryRemapper mapper = project.getMapper();
374 404
375 Collection<ClassEntry> classes = project.getJarIndex().getEntryIndex().getClasses(); 405 Collection<ClassEntry> classes = project.getJarIndex().getEntryIndex().getClasses();
376 Stream<ClassEntry> visibleClasses = classes.stream() 406 Stream<ClassEntry> visibleClasses = classes.stream().filter(entry -> !entry.isInnerClass());
377 .filter(entry -> !entry.isInnerClass());
378 407
379 visibleClasses.forEach(entry -> { 408 visibleClasses.forEach(entry -> {
380 if (gui.isSingleClassTree()) { 409 if (gui.isSingleClassTree()) {
@@ -428,12 +457,15 @@ public class GuiController implements ClientPacketHandler {
428 public MethodImplementationsTreeNode getMethodImplementations(MethodEntry entry) { 457 public MethodImplementationsTreeNode getMethodImplementations(MethodEntry entry) {
429 Translator translator = project.getMapper().getDeobfuscator(); 458 Translator translator = project.getMapper().getDeobfuscator();
430 List<MethodImplementationsTreeNode> rootNodes = indexTreeBuilder.buildMethodImplementations(translator, entry); 459 List<MethodImplementationsTreeNode> rootNodes = indexTreeBuilder.buildMethodImplementations(translator, entry);
460
431 if (rootNodes.isEmpty()) { 461 if (rootNodes.isEmpty()) {
432 return null; 462 return null;
433 } 463 }
464
434 if (rootNodes.size() > 1) { 465 if (rootNodes.size() > 1) {
435 System.err.println("WARNING: Method " + entry + " implements multiple interfaces. Only showing first one."); 466 System.err.println("WARNING: Method " + entry + " implements multiple interfaces. Only showing first one.");
436 } 467 }
468
437 return MethodImplementationsTreeNode.findNode(rootNodes.get(0), entry); 469 return MethodImplementationsTreeNode.findNode(rootNodes.get(0), entry);
438 } 470 }
439 471
@@ -481,13 +513,20 @@ public class GuiController implements ClientPacketHandler {
481 public void applyChange(ValidationContext vc, EntryChange<?> change) { 513 public void applyChange(ValidationContext vc, EntryChange<?> change) {
482 this.applyChange0(vc, change); 514 this.applyChange0(vc, change);
483 gui.showStructure(gui.getActiveEditor()); 515 gui.showStructure(gui.getActiveEditor());
484 if (!vc.canProceed()) return; 516
517 if (!vc.canProceed()) {
518 return;
519 }
520
485 this.sendPacket(new EntryChangeC2SPacket(change)); 521 this.sendPacket(new EntryChangeC2SPacket(change));
486 } 522 }
487 523
488 private void applyChange0(ValidationContext vc, EntryChange<?> change) { 524 private void applyChange0(ValidationContext vc, EntryChange<?> change) {
489 validateChange(vc, change); 525 validateChange(vc, change);
490 if (!vc.canProceed()) return; 526
527 if (!vc.canProceed()) {
528 return;
529 }
491 530
492 Entry<?> target = change.getTarget(); 531 Entry<?> target = change.getTarget();
493 EntryMapping prev = this.project.getMapper().getDeobfMapping(target); 532 EntryMapping prev = this.project.getMapper().getDeobfMapping(target);
@@ -506,6 +545,7 @@ public class GuiController implements ClientPacketHandler {
506 if (!Objects.equals(prev.javadoc(), mapping.javadoc())) { 545 if (!Objects.equals(prev.javadoc(), mapping.javadoc())) {
507 this.chp.invalidateJavadoc(target.getTopLevelClass()); 546 this.chp.invalidateJavadoc(target.getTopLevelClass());
508 } 547 }
548
509 gui.showStructure(gui.getActiveEditor()); 549 gui.showStructure(gui.getActiveEditor());
510 } 550 }
511 551
@@ -517,10 +557,7 @@ public class GuiController implements ClientPacketHandler {
517 File statsFile = File.createTempFile("stats", ".html"); 557 File statsFile = File.createTempFile("stats", ".html");
518 558
519 try (FileWriter w = new FileWriter(statsFile)) { 559 try (FileWriter w = new FileWriter(statsFile)) {
520 w.write( 560 w.write(Utils.readResourceToString("/stats.html").replace("/*data*/", data));
521 Utils.readResourceToString("/stats.html")
522 .replace("/*data*/", data)
523 );
524 } 561 }
525 562
526 Desktop.getDesktop().open(statsFile); 563 Desktop.getDesktop().open(statsFile);
@@ -573,15 +610,18 @@ public class GuiController implements ClientPacketHandler {
573 if (client != null) { 610 if (client != null) {
574 client.disconnect(); 611 client.disconnect();
575 } 612 }
613
576 if (server != null) { 614 if (server != null) {
577 server.stop(); 615 server.stop();
578 } 616 }
617
579 client = null; 618 client = null;
580 server = null; 619 server = null;
581 SwingUtilities.invokeLater(() -> { 620 SwingUtilities.invokeLater(() -> {
582 if (reason != null) { 621 if (reason != null) {
583 JOptionPane.showMessageDialog(gui.getFrame(), I18n.translate(reason), I18n.translate("disconnect.disconnected"), JOptionPane.INFORMATION_MESSAGE); 622 JOptionPane.showMessageDialog(gui.getFrame(), I18n.translate(reason), I18n.translate("disconnect.disconnected"), JOptionPane.INFORMATION_MESSAGE);
584 } 623 }
624
585 gui.setConnectionState(ConnectionState.NOT_CONNECTED); 625 gui.setConnectionState(ConnectionState.NOT_CONNECTED);
586 }); 626 });
587 } 627 }
@@ -602,5 +642,4 @@ public class GuiController implements ClientPacketHandler {
602 public void updateUserList(List<String> users) { 642 public void updateUserList(List<String> users) {
603 gui.setUserList(users); 643 gui.setUserList(users);
604 } 644 }
605
606} 645}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/Main.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/Main.java
index 1172a393..56f43859 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/Main.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/Main.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 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 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.gui; 12package cuchaz.enigma.gui;
13 13
@@ -20,7 +20,11 @@ import java.util.List;
20import java.util.Set; 20import java.util.Set;
21 21
22import com.google.common.io.MoreFiles; 22import com.google.common.io.MoreFiles;
23import joptsimple.*; 23import joptsimple.OptionException;
24import joptsimple.OptionParser;
25import joptsimple.OptionSet;
26import joptsimple.OptionSpec;
27import joptsimple.ValueConverter;
24 28
25import cuchaz.enigma.EnigmaProfile; 29import cuchaz.enigma.EnigmaProfile;
26import cuchaz.enigma.gui.config.Themes; 30import cuchaz.enigma.gui.config.Themes;
@@ -30,21 +34,14 @@ import cuchaz.enigma.translation.mapping.serde.MappingFormat;
30import cuchaz.enigma.utils.I18n; 34import cuchaz.enigma.utils.I18n;
31 35
32public class Main { 36public class Main {
33
34 public static void main(String[] args) throws IOException { 37 public static void main(String[] args) throws IOException {
35 OptionParser parser = new OptionParser(); 38 OptionParser parser = new OptionParser();
36 39
37 OptionSpec<Path> jar = parser.accepts("jar", "Jar file to open at startup") 40 OptionSpec<Path> jar = parser.accepts("jar", "Jar file to open at startup").withRequiredArg().withValuesConvertedBy(PathConverter.INSTANCE);
38 .withRequiredArg()
39 .withValuesConvertedBy(PathConverter.INSTANCE);
40 41
41 OptionSpec<Path> mappings = parser.accepts("mappings", "Mappings file to open at startup") 42 OptionSpec<Path> mappings = parser.accepts("mappings", "Mappings file to open at startup").withRequiredArg().withValuesConvertedBy(PathConverter.INSTANCE);
42 .withRequiredArg()
43 .withValuesConvertedBy(PathConverter.INSTANCE);
44 43
45 OptionSpec<Path> profile = parser.accepts("profile", "Profile json to apply at startup") 44 OptionSpec<Path> profile = parser.accepts("profile", "Profile json to apply at startup").withRequiredArg().withValuesConvertedBy(PathConverter.INSTANCE);
46 .withRequiredArg()
47 .withValuesConvertedBy(PathConverter.INSTANCE);
48 45
49 parser.acceptsAll(List.of("edit-all", "e"), "Enable editing everything"); 46 parser.acceptsAll(List.of("edit-all", "e"), "Enable editing everything");
50 parser.acceptsAll(List.of("no-edit-all", "E"), "Disable editing everything"); 47 parser.acceptsAll(List.of("no-edit-all", "E"), "Disable editing everything");
@@ -78,26 +75,26 @@ public class Main {
78 for (OptionSpec<?> spec : options.specs()) { 75 for (OptionSpec<?> spec : options.specs()) {
79 for (String s : spec.options()) { 76 for (String s : spec.options()) {
80 switch (s) { 77 switch (s) {
81 case "edit-all" -> editables.addAll(List.of(EditableType.values())); 78 case "edit-all" -> editables.addAll(List.of(EditableType.values()));
82 case "no-edit-all" -> editables.clear(); 79 case "no-edit-all" -> editables.clear();
83 case "edit-classes" -> editables.add(EditableType.CLASS); 80 case "edit-classes" -> editables.add(EditableType.CLASS);
84 case "no-edit-classes" -> editables.remove(EditableType.CLASS); 81 case "no-edit-classes" -> editables.remove(EditableType.CLASS);
85 case "edit-methods" -> editables.add(EditableType.METHOD); 82 case "edit-methods" -> editables.add(EditableType.METHOD);
86 case "no-edit-methods" -> editables.remove(EditableType.METHOD); 83 case "no-edit-methods" -> editables.remove(EditableType.METHOD);
87 case "edit-fields" -> editables.add(EditableType.FIELD); 84 case "edit-fields" -> editables.add(EditableType.FIELD);
88 case "no-edit-fields" -> editables.remove(EditableType.FIELD); 85 case "no-edit-fields" -> editables.remove(EditableType.FIELD);
89 case "edit-parameters" -> editables.add(EditableType.PARAMETER); 86 case "edit-parameters" -> editables.add(EditableType.PARAMETER);
90 case "no-edit-parameters" -> editables.remove(EditableType.PARAMETER); 87 case "no-edit-parameters" -> editables.remove(EditableType.PARAMETER);
91 case "edit-locals" -> { 88 case "edit-locals" -> {
92 editables.add(EditableType.LOCAL_VARIABLE); 89 editables.add(EditableType.LOCAL_VARIABLE);
93 System.err.println("warning: --edit-locals has no effect as local variables are currently not editable"); 90 System.err.println("warning: --edit-locals has no effect as local variables are currently not editable");
94 } 91 }
95 case "no-edit-locals" -> { 92 case "no-edit-locals" -> {
96 editables.remove(EditableType.LOCAL_VARIABLE); 93 editables.remove(EditableType.LOCAL_VARIABLE);
97 System.err.println("warning: --no-edit-locals has no effect as local variables are currently not editable"); 94 System.err.println("warning: --no-edit-locals has no effect as local variables are currently not editable");
98 } 95 }
99 case "edit-javadocs" -> editables.add(EditableType.JAVADOC); 96 case "edit-javadocs" -> editables.add(EditableType.JAVADOC);
100 case "no-edit-javadocs" -> editables.remove(EditableType.JAVADOC); 97 case "no-edit-javadocs" -> editables.remove(EditableType.JAVADOC);
101 } 98 }
102 } 99 }
103 } 100 }
@@ -110,7 +107,7 @@ public class Main {
110 107
111 Gui gui = new Gui(parsedProfile, editables); 108 Gui gui = new Gui(parsedProfile, editables);
112 GuiController controller = gui.getController(); 109 GuiController controller = gui.getController();
113 110
114 if (options.has("single-class-tree")) { 111 if (options.has("single-class-tree")) {
115 gui.setSingleClassTree(true); 112 gui.setSingleClassTree(true);
116 } 113 }
@@ -120,6 +117,7 @@ public class Main {
120 CrashDialog.init(gui.getFrame()); 117 CrashDialog.init(gui.getFrame());
121 Thread.setDefaultUncaughtExceptionHandler((thread, t) -> { 118 Thread.setDefaultUncaughtExceptionHandler((thread, t) -> {
122 t.printStackTrace(System.err); 119 t.printStackTrace(System.err);
120
123 if (!ExceptionIgnorer.shouldIgnore(t)) { 121 if (!ExceptionIgnorer.shouldIgnore(t)) {
124 CrashDialog.show(t); 122 CrashDialog.show(t);
125 } 123 }
@@ -128,19 +126,19 @@ public class Main {
128 126
129 if (options.has(jar)) { 127 if (options.has(jar)) {
130 Path jarPath = options.valueOf(jar); 128 Path jarPath = options.valueOf(jar);
131 controller.openJar(jarPath) 129 controller.openJar(jarPath).whenComplete((v, t) -> {
132 .whenComplete((v, t) -> { 130 if (options.has(mappings)) {
133 if (options.has(mappings)) { 131 Path mappingsPath = options.valueOf(mappings);
134 Path mappingsPath = options.valueOf(mappings); 132
135 if (Files.isDirectory(mappingsPath)) { 133 if (Files.isDirectory(mappingsPath)) {
136 controller.openMappings(MappingFormat.ENIGMA_DIRECTORY, mappingsPath); 134 controller.openMappings(MappingFormat.ENIGMA_DIRECTORY, mappingsPath);
137 } else if ("zip".equalsIgnoreCase(MoreFiles.getFileExtension(mappingsPath))) { 135 } else if ("zip".equalsIgnoreCase(MoreFiles.getFileExtension(mappingsPath))) {
138 controller.openMappings(MappingFormat.ENIGMA_ZIP, mappingsPath); 136 controller.openMappings(MappingFormat.ENIGMA_ZIP, mappingsPath);
139 } else { 137 } else {
140 controller.openMappings(MappingFormat.ENIGMA_FILE, mappingsPath); 138 controller.openMappings(MappingFormat.ENIGMA_FILE, mappingsPath);
141 } 139 }
142 } 140 }
143 }); 141 });
144 } 142 }
145 } catch (OptionException e) { 143 } catch (OptionException e) {
146 System.out.println("Invalid arguments: " + e.getMessage()); 144 System.out.println("Invalid arguments: " + e.getMessage());
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java
index 309f9106..c4541fc6 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java
@@ -1,21 +1,22 @@
1package cuchaz.enigma.gui; 1package cuchaz.enigma.gui;
2 2
3import cuchaz.enigma.gui.node.ClassSelectorClassNode; 3import java.util.Collection;
4import cuchaz.enigma.gui.node.ClassSelectorPackageNode; 4import java.util.Comparator;
5import cuchaz.enigma.translation.mapping.EntryRemapper; 5import java.util.Enumeration;
6import cuchaz.enigma.translation.representation.entry.ClassEntry; 6import java.util.HashMap;
7import java.util.Map;
7 8
8import javax.swing.tree.DefaultMutableTreeNode; 9import javax.swing.tree.DefaultMutableTreeNode;
9import javax.swing.tree.MutableTreeNode; 10import javax.swing.tree.MutableTreeNode;
10import javax.swing.tree.TreeNode; 11import javax.swing.tree.TreeNode;
11import javax.swing.tree.TreePath; 12import javax.swing.tree.TreePath;
12import java.util.Collection;
13import java.util.Comparator;
14import java.util.HashMap;
15import java.util.Map;
16 13
17public class NestedPackages { 14import cuchaz.enigma.gui.node.ClassSelectorClassNode;
15import cuchaz.enigma.gui.node.ClassSelectorPackageNode;
16import cuchaz.enigma.translation.mapping.EntryRemapper;
17import cuchaz.enigma.translation.representation.entry.ClassEntry;
18 18
19public class NestedPackages {
19 private final DefaultMutableTreeNode root = new DefaultMutableTreeNode(); 20 private final DefaultMutableTreeNode root = new DefaultMutableTreeNode();
20 private final Map<String, DefaultMutableTreeNode> packageToNode = new HashMap<>(); 21 private final Map<String, DefaultMutableTreeNode> packageToNode = new HashMap<>();
21 private final Map<ClassEntry, ClassSelectorClassNode> classToNode = new HashMap<>(); 22 private final Map<ClassEntry, ClassSelectorClassNode> classToNode = new HashMap<>();
@@ -42,20 +43,20 @@ public class NestedPackages {
42 return 0; 43 return 0;
43 }; 44 };
44 45
45 for (var entry : entries) { 46 for (ClassEntry entry : entries) {
46 addEntry(entry); 47 addEntry(entry);
47 } 48 }
48 } 49 }
49 50
50 public void addEntry(ClassEntry entry) { 51 public void addEntry(ClassEntry entry) {
51 var translated = remapper.deobfuscate(entry); 52 ClassEntry translated = remapper.deobfuscate(entry);
52 var me = new ClassSelectorClassNode(entry, translated); 53 var me = new ClassSelectorClassNode(entry, translated);
53 classToNode.put(entry, me); 54 classToNode.put(entry, me);
54 insert(getPackage(translated.getPackageName()), me); 55 insert(getPackage(translated.getPackageName()), me);
55 } 56 }
56 57
57 public DefaultMutableTreeNode getPackage(String packageName) { 58 public DefaultMutableTreeNode getPackage(String packageName) {
58 var node = packageToNode.get(packageName); 59 DefaultMutableTreeNode node = packageToNode.get(packageName);
59 60
60 if (packageName == null) { 61 if (packageName == null) {
61 return root; 62 return root;
@@ -75,7 +76,7 @@ public class NestedPackages {
75 } 76 }
76 77
77 public TreePath getPackagePath(String packageName) { 78 public TreePath getPackagePath(String packageName) {
78 var node = packageToNode.getOrDefault(packageName, root); 79 DefaultMutableTreeNode node = packageToNode.getOrDefault(packageName, root);
79 return new TreePath(node.getPath()); 80 return new TreePath(node.getPath());
80 } 81 }
81 82
@@ -84,15 +85,15 @@ public class NestedPackages {
84 } 85 }
85 86
86 public void removeClassNode(ClassEntry entry) { 87 public void removeClassNode(ClassEntry entry) {
87 var node = classToNode.remove(entry); 88 ClassSelectorClassNode node = classToNode.remove(entry);
88 89
89 if (node != null) { 90 if (node != null) {
90 node.removeFromParent(); 91 node.removeFromParent();
91 // remove dangling packages 92 // remove dangling packages
92 var packageNode = packageToNode.get(entry.getPackageName()); 93 DefaultMutableTreeNode packageNode = packageToNode.get(entry.getPackageName());
93 94
94 while (packageNode != null && packageNode.getChildCount() == 0) { 95 while (packageNode != null && packageNode.getChildCount() == 0) {
95 var theNode = packageNode; 96 DefaultMutableTreeNode theNode = packageNode;
96 packageNode = (DefaultMutableTreeNode) packageNode.getParent(); 97 packageNode = (DefaultMutableTreeNode) packageNode.getParent();
97 theNode.removeFromParent(); 98 theNode.removeFromParent();
98 99
@@ -108,8 +109,8 @@ public class NestedPackages {
108 } 109 }
109 110
110 private void insert(DefaultMutableTreeNode parent, MutableTreeNode child) { 111 private void insert(DefaultMutableTreeNode parent, MutableTreeNode child) {
111 var index = 0; 112 int index = 0;
112 var children = parent.children(); 113 Enumeration<TreeNode> children = parent.children();
113 114
114 while (children.hasMoreElements()) { 115 while (children.hasMoreElements()) {
115 if (comparator.compare(children.nextElement(), child) < 0) { 116 if (comparator.compare(children.nextElement(), child) < 0) {
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/QuickFindAction.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/QuickFindAction.java
index b7fa2eba..ff80e17f 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/QuickFindAction.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/QuickFindAction.java
@@ -1,10 +1,11 @@
1package cuchaz.enigma.gui; 1package cuchaz.enigma.gui;
2 2
3import de.sciss.syntaxpane.SyntaxDocument; 3import java.awt.event.ActionEvent;
4import de.sciss.syntaxpane.actions.DefaultSyntaxAction;
5 4
6import javax.swing.text.JTextComponent; 5import javax.swing.text.JTextComponent;
7import java.awt.event.ActionEvent; 6
7import de.sciss.syntaxpane.SyntaxDocument;
8import de.sciss.syntaxpane.actions.DefaultSyntaxAction;
8 9
9public final class QuickFindAction extends DefaultSyntaxAction { 10public final class QuickFindAction extends DefaultSyntaxAction {
10 public QuickFindAction() { 11 public QuickFindAction() {
@@ -26,6 +27,7 @@ public final class QuickFindAction extends DefaultSyntaxAction {
26 27
27 public static Data get(JTextComponent target) { 28 public static Data get(JTextComponent target) {
28 Object o = target.getDocument().getProperty(KEY); 29 Object o = target.getDocument().getProperty(KEY);
30
29 if (o instanceof Data) { 31 if (o instanceof Data) {
30 return (Data) o; 32 return (Data) o;
31 } 33 }
@@ -39,6 +41,7 @@ public final class QuickFindAction extends DefaultSyntaxAction {
39 if (findDialog == null) { 41 if (findDialog == null) {
40 findDialog = new EnigmaQuickFindDialog(target); 42 findDialog = new EnigmaQuickFindDialog(target);
41 } 43 }
44
42 findDialog.showFor(target); 45 findDialog.showFor(target);
43 } 46 }
44 } 47 }
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/ReadableToken.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/ReadableToken.java
index 3e4b30cd..eac11ed4 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/ReadableToken.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/ReadableToken.java
@@ -1,18 +1,17 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 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 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.gui; 12package cuchaz.enigma.gui;
13 13
14public class ReadableToken { 14public class ReadableToken {
15
16 public int line; 15 public int line;
17 public int startColumn; 16 public int startColumn;
18 public int endColumn; 17 public int endColumn;
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/TokenListCellRenderer.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/TokenListCellRenderer.java
index 4ef04428..000793e6 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/TokenListCellRenderer.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/TokenListCellRenderer.java
@@ -1,23 +1,26 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 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 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.gui; 12package cuchaz.enigma.gui;
13 13
14import cuchaz.enigma.source.Token; 14import java.awt.Component;
15 15
16import javax.swing.*; 16import javax.swing.DefaultListCellRenderer;
17import java.awt.*; 17import javax.swing.JLabel;
18import javax.swing.JList;
19import javax.swing.ListCellRenderer;
18 20
19public class TokenListCellRenderer implements ListCellRenderer<Token> { 21import cuchaz.enigma.source.Token;
20 22
23public class TokenListCellRenderer implements ListCellRenderer<Token> {
21 private GuiController controller; 24 private GuiController controller;
22 private DefaultListCellRenderer defaultRenderer; 25 private DefaultListCellRenderer defaultRenderer;
23 26
@@ -32,5 +35,4 @@ public class TokenListCellRenderer implements ListCellRenderer<Token> {
32 label.setText(this.controller.getReadableToken(token).toString()); 35 label.setText(this.controller.getReadableToken(token).toString());
33 return label; 36 return label;
34 } 37 }
35
36} 38}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/LookAndFeel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/LookAndFeel.java
index cec3fa1e..2088aac2 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/LookAndFeel.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/LookAndFeel.java
@@ -40,11 +40,11 @@ public enum LookAndFeel {
40 40
41 try { 41 try {
42 switch (this) { 42 switch (this) {
43 case NONE -> UIManager.setLookAndFeel(NONE_LAF); 43 case NONE -> UIManager.setLookAndFeel(NONE_LAF);
44 case DEFAULT -> UIManager.setLookAndFeel(new FlatLightLaf()); 44 case DEFAULT -> UIManager.setLookAndFeel(new FlatLightLaf());
45 case METAL -> UIManager.setLookAndFeel(new MetalLookAndFeel()); 45 case METAL -> UIManager.setLookAndFeel(new MetalLookAndFeel());
46 case DARCULA -> UIManager.setLookAndFeel(new FlatDarkLaf()); 46 case DARCULA -> UIManager.setLookAndFeel(new FlatDarkLaf());
47 case SYSTEM -> UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 47 case SYSTEM -> UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
48 } 48 }
49 } catch (Exception e) { 49 } catch (Exception e) {
50 throw new Error("Failed to set global look and feel", e); 50 throw new Error("Failed to set global look and feel", e);
@@ -66,5 +66,4 @@ public enum LookAndFeel {
66 int b = (int) (0.3 * c.getRed() + 0.59 * c.getGreen() + 0.11 * c.getBlue()); 66 int b = (int) (0.3 * c.getRed() + 0.59 * c.getGreen() + 0.11 * c.getBlue());
67 return b < 85; 67 return b < 85;
68 } 68 }
69
70} 69}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/NetConfig.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/NetConfig.java
index 4439cb8a..eaf20e7f 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/NetConfig.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/NetConfig.java
@@ -4,7 +4,6 @@ import cuchaz.enigma.config.ConfigContainer;
4import cuchaz.enigma.network.EnigmaServer; 4import cuchaz.enigma.network.EnigmaServer;
5 5
6public final class NetConfig { 6public final class NetConfig {
7
8 private NetConfig() { 7 private NetConfig() {
9 } 8 }
10 9
@@ -53,5 +52,4 @@ public final class NetConfig {
53 public static void setServerPort(int port) { 52 public static void setServerPort(int port) {
54 cfg.data().section("Server").setInt("Port", port); 53 cfg.data().section("Server").setInt("Port", port);
55 } 54 }
56
57} 55}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/OldConfigImporter.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/OldConfigImporter.java
index 660d2313..2e84991b 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/OldConfigImporter.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/OldConfigImporter.java
@@ -5,7 +5,6 @@ import java.awt.Font;
5import cuchaz.enigma.gui.config.legacy.Config; 5import cuchaz.enigma.gui.config.legacy.Config;
6 6
7public final class OldConfigImporter { 7public final class OldConfigImporter {
8
9 private OldConfigImporter() { 8 private OldConfigImporter() {
10 } 9 }
11 10
@@ -13,14 +12,15 @@ public final class OldConfigImporter {
13 public static void doImport() { 12 public static void doImport() {
14 if (Config.CONFIG_FILE.exists()) { 13 if (Config.CONFIG_FILE.exists()) {
15 Config config = new Config(); 14 Config config = new Config();
15
16 if (config.editorFont != null) { 16 if (config.editorFont != null) {
17 UiConfig.setEditorFont(Font.decode(config.editorFont)); 17 UiConfig.setEditorFont(Font.decode(config.editorFont));
18 } 18 }
19
19 UiConfig.setLanguage(config.language); 20 UiConfig.setLanguage(config.language);
20 UiConfig.setLookAndFeel(config.lookAndFeel); 21 UiConfig.setLookAndFeel(config.lookAndFeel);
21 UiConfig.setScaleFactor(config.scaleFactor); 22 UiConfig.setScaleFactor(config.scaleFactor);
22 UiConfig.setDecompiler(config.decompiler); 23 UiConfig.setDecompiler(config.decompiler);
23 } 24 }
24 } 25 }
25
26} 26}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/Themes.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/Themes.java
index 839a5cbc..e2db9682 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/Themes.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/Themes.java
@@ -16,7 +16,6 @@ import cuchaz.enigma.gui.util.ScaleUtil;
16import cuchaz.enigma.source.RenamableTokenType; 16import cuchaz.enigma.source.RenamableTokenType;
17 17
18public class Themes { 18public class Themes {
19
20 private static final Set<ThemeChangeListener> listeners = new HashSet<>(); 19 private static final Set<ThemeChangeListener> listeners = new HashSet<>();
21 20
22 // Calling this after the UI is initialized (e.g. when the user changes 21 // Calling this after the UI is initialized (e.g. when the user changes
@@ -87,11 +86,8 @@ public class Themes {
87 } 86 }
88 87
89 public static ImmutableMap<RenamableTokenType, BoxHighlightPainter> getBoxHighlightPainters() { 88 public static ImmutableMap<RenamableTokenType, BoxHighlightPainter> getBoxHighlightPainters() {
90 return ImmutableMap.of( 89 return ImmutableMap.of(RenamableTokenType.OBFUSCATED, BoxHighlightPainter.create(UiConfig.getObfuscatedColor(), UiConfig.getObfuscatedOutlineColor()), RenamableTokenType.PROPOSED, BoxHighlightPainter.create(UiConfig.getProposedColor(), UiConfig.getProposedOutlineColor()),
91 RenamableTokenType.OBFUSCATED, BoxHighlightPainter.create(UiConfig.getObfuscatedColor(), UiConfig.getObfuscatedOutlineColor()), 90 RenamableTokenType.DEOBFUSCATED, BoxHighlightPainter.create(UiConfig.getDeobfuscatedColor(), UiConfig.getDeobfuscatedOutlineColor()));
92 RenamableTokenType.PROPOSED, BoxHighlightPainter.create(UiConfig.getProposedColor(), UiConfig.getProposedOutlineColor()),
93 RenamableTokenType.DEOBFUSCATED, BoxHighlightPainter.create(UiConfig.getDeobfuscatedColor(), UiConfig.getDeobfuscatedOutlineColor())
94 );
95 } 91 }
96 92
97 public static void addListener(ThemeChangeListener listener) { 93 public static void addListener(ThemeChangeListener listener) {
@@ -101,5 +97,4 @@ public class Themes {
101 public static void removeListener(ThemeChangeListener listener) { 97 public static void removeListener(ThemeChangeListener listener) {
102 listeners.remove(listener); 98 listeners.remove(listener);
103 } 99 }
104
105} 100}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/UiConfig.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/UiConfig.java
index 8a10acec..cdf27cac 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/UiConfig.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/UiConfig.java
@@ -1,6 +1,10 @@
1package cuchaz.enigma.gui.config; 1package cuchaz.enigma.gui.config;
2 2
3import java.awt.*; 3import java.awt.Color;
4import java.awt.Dimension;
5import java.awt.Font;
6import java.awt.Point;
7import java.awt.Toolkit;
4import java.util.Optional; 8import java.util.Optional;
5import java.util.OptionalInt; 9import java.util.OptionalInt;
6 10
@@ -10,7 +14,6 @@ import cuchaz.enigma.gui.util.ScaleUtil;
10import cuchaz.enigma.utils.I18n; 14import cuchaz.enigma.utils.I18n;
11 15
12public final class UiConfig { 16public final class UiConfig {
13
14 private UiConfig() { 17 private UiConfig() {
15 } 18 }
16 19
@@ -82,11 +85,11 @@ public final class UiConfig {
82 * @return an integer array composed of these 4 dimensions 85 * @return an integer array composed of these 4 dimensions
83 */ 86 */
84 public static int[] getLayout() { 87 public static int[] getLayout() {
85 return swing.data().section("Main Window").getIntArray("Layout").orElseGet(() -> new int[] { -1, -1, -1, -1 }); 88 return swing.data().section("Main Window").getIntArray("Layout").orElseGet(() -> new int[]{-1, -1, -1, -1});
86 } 89 }
87 90
88 public static void setLayout(int leftV, int left, int right, int rightH) { 91 public static void setLayout(int leftV, int left, int right, int rightH) {
89 swing.data().section("Main Window").setIntArray("Layout", new int[] { leftV, left, right, rightH }); 92 swing.data().section("Main Window").setIntArray("Layout", new int[]{leftV, left, right, rightH});
90 } 93 }
91 94
92 public static LookAndFeel getLookAndFeel() { 95 public static LookAndFeel getLookAndFeel() {
@@ -287,6 +290,7 @@ public final class UiConfig {
287 ConfigSection section = swing.data().section(window); 290 ConfigSection section = swing.data().section(window);
288 OptionalInt width = section.getInt(String.format("Width %s", screenSize.width)); 291 OptionalInt width = section.getInt(String.format("Width %s", screenSize.width));
289 OptionalInt height = section.getInt(String.format("Height %s", screenSize.height)); 292 OptionalInt height = section.getInt(String.format("Height %s", screenSize.height));
293
290 if (width.isPresent() && height.isPresent()) { 294 if (width.isPresent() && height.isPresent()) {
291 return new Dimension(width.getAsInt(), height.getAsInt()); 295 return new Dimension(width.getAsInt(), height.getAsInt());
292 } else { 296 } else {
@@ -306,6 +310,7 @@ public final class UiConfig {
306 ConfigSection section = swing.data().section(window); 310 ConfigSection section = swing.data().section(window);
307 OptionalInt x = section.getInt(String.format("X %s", screenSize.width)); 311 OptionalInt x = section.getInt(String.format("X %s", screenSize.width));
308 OptionalInt y = section.getInt(String.format("Y %s", screenSize.height)); 312 OptionalInt y = section.getInt(String.format("Y %s", screenSize.height));
313
309 if (x.isPresent() && y.isPresent()) { 314 if (x.isPresent() && y.isPresent()) {
310 int ix = x.getAsInt(); 315 int ix = x.getAsInt();
311 int iy = y.getAsInt(); 316 int iy = y.getAsInt();
@@ -354,6 +359,7 @@ public final class UiConfig {
354 359
355 public static void setLookAndFeelDefaults(LookAndFeel laf, boolean isDark) { 360 public static void setLookAndFeelDefaults(LookAndFeel laf, boolean isDark) {
356 ConfigSection s = swing.data().section("Themes").section(laf.name()).section("Colors"); 361 ConfigSection s = swing.data().section("Themes").section(laf.name()).section("Colors");
362
357 if (!isDark) { 363 if (!isDark) {
358 // Defaults found here: https://github.com/Sciss/SyntaxPane/blob/122da367ff7a5d31627a70c62a48a9f0f4f85a0a/src/main/resources/de/sciss/syntaxpane/defaultsyntaxkit/config.properties#L139 364 // Defaults found here: https://github.com/Sciss/SyntaxPane/blob/122da367ff7a5d31627a70c62a48a9f0f4f85a0a/src/main/resources/de/sciss/syntaxpane/defaultsyntaxkit/config.properties#L139
359 s.setIfAbsentRgbColor("Line Numbers Foreground", 0x333300); 365 s.setIfAbsentRgbColor("Line Numbers Foreground", 0x333300);
@@ -412,5 +418,4 @@ public final class UiConfig {
412 s.setIfAbsentRgbColor("Text", 0xF8F8F2); 418 s.setIfAbsentRgbColor("Text", 0xF8F8F2);
413 } 419 }
414 } 420 }
415
416} 421}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/legacy/Config.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/legacy/Config.java
index 1265750f..0e8f7da2 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/legacy/Config.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/legacy/Config.java
@@ -6,7 +6,15 @@ import java.lang.reflect.Type;
6import java.nio.charset.Charset; 6import java.nio.charset.Charset;
7 7
8import com.google.common.io.Files; 8import com.google.common.io.Files;
9import com.google.gson.*; 9import com.google.gson.Gson;
10import com.google.gson.GsonBuilder;
11import com.google.gson.InstanceCreator;
12import com.google.gson.JsonDeserializationContext;
13import com.google.gson.JsonDeserializer;
14import com.google.gson.JsonElement;
15import com.google.gson.JsonPrimitive;
16import com.google.gson.JsonSerializationContext;
17import com.google.gson.JsonSerializer;
10 18
11import cuchaz.enigma.gui.config.Decompiler; 19import cuchaz.enigma.gui.config.Decompiler;
12import cuchaz.enigma.utils.I18n; 20import cuchaz.enigma.utils.I18n;
@@ -28,7 +36,7 @@ public class Config {
28 } 36 }
29 37
30 Color baseColor = new Color(rgb); 38 Color baseColor = new Color(rgb);
31 return new Color(baseColor.getRed(), baseColor.getGreen(), baseColor.getBlue(), (int)(255 * alpha)); 39 return new Color(baseColor.getRed(), baseColor.getGreen(), baseColor.getBlue(), (int) (255 * alpha));
32 } 40 }
33 } 41 }
34 42
@@ -73,12 +81,7 @@ public class Config {
73 public Decompiler decompiler = Decompiler.CFR; 81 public Decompiler decompiler = Decompiler.CFR;
74 82
75 public Config() { 83 public Config() {
76 gson = new GsonBuilder() 84 gson = new GsonBuilder().registerTypeAdapter(Integer.class, new IntSerializer()).registerTypeAdapter(Integer.class, new IntDeserializer()).registerTypeAdapter(Config.class, (InstanceCreator<Config>) type -> this).setPrettyPrinting().create();
77 .registerTypeAdapter(Integer.class, new IntSerializer())
78 .registerTypeAdapter(Integer.class, new IntDeserializer())
79 .registerTypeAdapter(Config.class, (InstanceCreator<Config>) type -> this)
80 .setPrettyPrinting()
81 .create();
82 this.loadConfig(); 85 this.loadConfig();
83 } 86 }
84 87
@@ -105,5 +108,4 @@ public class Config {
105 return (int) Long.parseLong(json.getAsString().replace("#", ""), 16); 108 return (int) Long.parseLong(json.getAsString().replace("#", ""), 16);
106 } 109 }
107 } 110 }
108
109} 111}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AboutDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AboutDialog.java
index f8922e64..c2211209 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AboutDialog.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AboutDialog.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 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 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.gui.dialog; 12package cuchaz.enigma.gui.dialog;
13 13
@@ -15,7 +15,11 @@ import java.awt.Container;
15import java.awt.GridBagConstraints; 15import java.awt.GridBagConstraints;
16import java.awt.GridBagLayout; 16import java.awt.GridBagLayout;
17 17
18import javax.swing.*; 18import javax.swing.JButton;
19import javax.swing.JDialog;
20import javax.swing.JFrame;
21import javax.swing.JLabel;
22import javax.swing.WindowConstants;
19 23
20import cuchaz.enigma.Enigma; 24import cuchaz.enigma.Enigma;
21import cuchaz.enigma.gui.util.GridBagConstraintsBuilder; 25import cuchaz.enigma.gui.util.GridBagConstraintsBuilder;
@@ -23,16 +27,12 @@ import cuchaz.enigma.gui.util.GuiUtil;
23import cuchaz.enigma.utils.I18n; 27import cuchaz.enigma.utils.I18n;
24 28
25public class AboutDialog { 29public class AboutDialog {
26
27 public static void show(JFrame parent) { 30 public static void show(JFrame parent) {
28 JDialog frame = new JDialog(parent, String.format(I18n.translate("menu.help.about.title"), Enigma.NAME), true); 31 JDialog frame = new JDialog(parent, String.format(I18n.translate("menu.help.about.title"), Enigma.NAME), true);
29 Container pane = frame.getContentPane(); 32 Container pane = frame.getContentPane();
30 pane.setLayout(new GridBagLayout()); 33 pane.setLayout(new GridBagLayout());
31 34
32 GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create() 35 GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(2).weight(1.0, 0.0).anchor(GridBagConstraints.WEST);
33 .insets(2)
34 .weight(1.0, 0.0)
35 .anchor(GridBagConstraints.WEST);
36 36
37 JLabel title = new JLabel(Enigma.NAME); 37 JLabel title = new JLabel(Enigma.NAME);
38 title.setFont(title.getFont().deriveFont(title.getFont().getSize2D() * 1.5f)); 38 title.setFont(title.getFont().deriveFont(title.getFont().getSize2D() * 1.5f));
@@ -52,5 +52,4 @@ public class AboutDialog {
52 frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 52 frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
53 frame.setVisible(true); 53 frame.setVisible(true);
54 } 54 }
55
56} 55}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AbstractDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AbstractDialog.java
index c9ca8090..76232c44 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AbstractDialog.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AbstractDialog.java
@@ -1,6 +1,12 @@
1package cuchaz.enigma.gui.dialog; 1package cuchaz.enigma.gui.dialog;
2 2
3import java.awt.*; 3import java.awt.BorderLayout;
4import java.awt.Component;
5import java.awt.Container;
6import java.awt.FlowLayout;
7import java.awt.Frame;
8import java.awt.GridBagConstraints;
9import java.awt.GridBagLayout;
4import java.util.List; 10import java.util.List;
5 11
6import javax.swing.JButton; 12import javax.swing.JButton;
@@ -15,7 +21,6 @@ import cuchaz.enigma.utils.Pair;
15import cuchaz.enigma.utils.validation.ValidationContext; 21import cuchaz.enigma.utils.validation.ValidationContext;
16 22
17public abstract class AbstractDialog extends JDialog { 23public abstract class AbstractDialog extends JDialog {
18
19 protected final ValidationContext vc = new ValidationContext(); 24 protected final ValidationContext vc = new ValidationContext();
20 25
21 private boolean actionConfirm = false; 26 private boolean actionConfirm = false;
@@ -38,6 +43,7 @@ public abstract class AbstractDialog extends JDialog {
38 inputContainer.add(label, cb.pos(0, i).weightX(0.0).anchor(GridBagConstraints.LINE_END).fill(GridBagConstraints.NONE).build()); 43 inputContainer.add(label, cb.pos(0, i).weightX(0.0).anchor(GridBagConstraints.LINE_END).fill(GridBagConstraints.NONE).build());
39 inputContainer.add(component, cb.pos(1, i).weightX(1.0).anchor(GridBagConstraints.LINE_END).fill(GridBagConstraints.HORIZONTAL).build()); 44 inputContainer.add(component, cb.pos(1, i).weightX(1.0).anchor(GridBagConstraints.LINE_END).fill(GridBagConstraints.HORIZONTAL).build());
40 } 45 }
46
41 contentPane.add(inputContainer, BorderLayout.CENTER); 47 contentPane.add(inputContainer, BorderLayout.CENTER);
42 Container buttonContainer = new JPanel(new FlowLayout(FlowLayout.RIGHT, ScaleUtil.scale(4), ScaleUtil.scale(4))); 48 Container buttonContainer = new JPanel(new FlowLayout(FlowLayout.RIGHT, ScaleUtil.scale(4), ScaleUtil.scale(4)));
43 JButton connectButton = new JButton(I18n.translate(confirmAction)); 49 JButton connectButton = new JButton(I18n.translate(confirmAction));
@@ -57,6 +63,7 @@ public abstract class AbstractDialog extends JDialog {
57 protected void confirm() { 63 protected void confirm() {
58 vc.reset(); 64 vc.reset();
59 validateInputs(); 65 validateInputs();
66
60 if (vc.canProceed()) { 67 if (vc.canProceed()) {
61 actionConfirm = true; 68 actionConfirm = true;
62 setVisible(false); 69 setVisible(false);
@@ -74,5 +81,4 @@ public abstract class AbstractDialog extends JDialog {
74 81
75 public void validateInputs() { 82 public void validateInputs() {
76 } 83 }
77
78} 84}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ChangeDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ChangeDialog.java
index df65473c..51948b56 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ChangeDialog.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ChangeDialog.java
@@ -14,7 +14,6 @@ import javax.swing.JPanel;
14import cuchaz.enigma.utils.I18n; 14import cuchaz.enigma.utils.I18n;
15 15
16public class ChangeDialog { 16public class ChangeDialog {
17
18 public static void show(Window parent) { 17 public static void show(Window parent) {
19 // init frame 18 // init frame
20 JDialog frame = new JDialog(parent, I18n.translate("menu.view.change.title"), Dialog.DEFAULT_MODALITY_TYPE); 19 JDialog frame = new JDialog(parent, I18n.translate("menu.view.change.title"), Dialog.DEFAULT_MODALITY_TYPE);
@@ -48,5 +47,4 @@ public class ChangeDialog {
48 frame.setLocationRelativeTo(parent); 47 frame.setLocationRelativeTo(parent);
49 frame.setVisible(true); 48 frame.setVisible(true);
50 } 49 }
51
52} 50}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ConnectToServerDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ConnectToServerDialog.java
index 2486dfe1..1c2bd4c1 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ConnectToServerDialog.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ConnectToServerDialog.java
@@ -20,7 +20,6 @@ import cuchaz.enigma.utils.validation.Message;
20import cuchaz.enigma.utils.validation.StandardValidation; 20import cuchaz.enigma.utils.validation.StandardValidation;
21 21
22public class ConnectToServerDialog extends AbstractDialog { 22public class ConnectToServerDialog extends AbstractDialog {
23
24 private JTextField usernameField; 23 private JTextField usernameField;
25 private ValidatableTextField ipField; 24 private ValidatableTextField ipField;
26 private JPasswordField passwordField; 25 private JPasswordField passwordField;
@@ -45,16 +44,13 @@ public class ConnectToServerDialog extends AbstractDialog {
45 ipField.addActionListener(event -> confirm()); 44 ipField.addActionListener(event -> confirm());
46 passwordField.addActionListener(event -> confirm()); 45 passwordField.addActionListener(event -> confirm());
47 46
48 return Arrays.asList( 47 return Arrays.asList(new Pair<>("prompt.connect.username", usernameField), new Pair<>("prompt.connect.address", ipField), new Pair<>("prompt.password", passwordField));
49 new Pair<>("prompt.connect.username", usernameField),
50 new Pair<>("prompt.connect.address", ipField),
51 new Pair<>("prompt.password", passwordField)
52 );
53 } 48 }
54 49
55 @Override 50 @Override
56 public void validateInputs() { 51 public void validateInputs() {
57 vc.setActiveElement(ipField); 52 vc.setActiveElement(ipField);
53
58 if (StandardValidation.notBlank(vc, ipField.getText())) { 54 if (StandardValidation.notBlank(vc, ipField.getText())) {
59 if (ServerAddress.from(ipField.getText(), EnigmaServer.DEFAULT_PORT) == null) { 55 if (ServerAddress.from(ipField.getText(), EnigmaServer.DEFAULT_PORT) == null) {
60 vc.raise(Message.INVALID_IP); 56 vc.raise(Message.INVALID_IP);
@@ -63,16 +59,18 @@ public class ConnectToServerDialog extends AbstractDialog {
63 } 59 }
64 60
65 public Result getResult() { 61 public Result getResult() {
66 if (!isActionConfirm()) return null; 62 if (!isActionConfirm()) {
63 return null;
64 }
65
67 vc.reset(); 66 vc.reset();
68 validateInputs(); 67 validateInputs();
69 if (!vc.canProceed()) return null; 68
70 return new Result( 69 if (!vc.canProceed()) {
71 usernameField.getText(), 70 return null;
72 ipField.getText(), 71 }
73 Objects.requireNonNull(ServerAddress.from(ipField.getText(), EnigmaServer.DEFAULT_PORT)), 72
74 passwordField.getPassword() 73 return new Result(usernameField.getText(), ipField.getText(), Objects.requireNonNull(ServerAddress.from(ipField.getText(), EnigmaServer.DEFAULT_PORT)), passwordField.getPassword());
75 );
76 } 74 }
77 75
78 public static Result show(Frame parent) { 76 public static Result show(Frame parent) {
@@ -114,5 +112,4 @@ public class ConnectToServerDialog extends AbstractDialog {
114 return password; 112 return password;
115 } 113 }
116 } 114 }
117
118} 115}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CrashDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CrashDialog.java
index c2a93fa5..a84e9775 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CrashDialog.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CrashDialog.java
@@ -1,31 +1,42 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 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 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.gui.dialog; 12package cuchaz.enigma.gui.dialog;
13 13
14import java.awt.BorderLayout;
15import java.awt.Container;
16import java.io.File;
17import java.io.FileWriter;
18import java.io.IOException;
19import java.io.PrintWriter;
20import java.io.StringWriter;
21
22import javax.swing.BorderFactory;
23import javax.swing.Box;
24import javax.swing.BoxLayout;
25import javax.swing.JButton;
26import javax.swing.JFileChooser;
27import javax.swing.JFrame;
28import javax.swing.JLabel;
29import javax.swing.JPanel;
30import javax.swing.JScrollPane;
31import javax.swing.JTextArea;
32import javax.swing.WindowConstants;
33
14import cuchaz.enigma.Enigma; 34import cuchaz.enigma.Enigma;
15import cuchaz.enigma.gui.util.GuiUtil; 35import cuchaz.enigma.gui.util.GuiUtil;
16import cuchaz.enigma.utils.I18n;
17import cuchaz.enigma.gui.util.ScaleUtil; 36import cuchaz.enigma.gui.util.ScaleUtil;
18 37import cuchaz.enigma.utils.I18n;
19import javax.swing.*;
20import java.awt.*;
21import java.io.PrintWriter;
22import java.io.StringWriter;
23import java.io.FileWriter;
24import java.io.File;
25import java.io.IOException;
26 38
27public class CrashDialog { 39public class CrashDialog {
28
29 private static CrashDialog instance = null; 40 private static CrashDialog instance = null;
30 41
31 private JFrame frame; 42 private JFrame frame;
@@ -53,6 +64,7 @@ public class CrashDialog {
53 exportButton.addActionListener(event -> { 64 exportButton.addActionListener(event -> {
54 JFileChooser chooser = new JFileChooser(); 65 JFileChooser chooser = new JFileChooser();
55 chooser.setSelectedFile(new File("enigma_crash.log")); 66 chooser.setSelectedFile(new File("enigma_crash.log"));
67
56 if (chooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) { 68 if (chooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) {
57 try { 69 try {
58 File file = chooser.getSelectedFile(); 70 File file = chooser.getSelectedFile();
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CreateServerDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CreateServerDialog.java
index 07daf6dc..35999e28 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CreateServerDialog.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CreateServerDialog.java
@@ -16,7 +16,6 @@ import cuchaz.enigma.utils.validation.Message;
16import cuchaz.enigma.utils.validation.StandardValidation; 16import cuchaz.enigma.utils.validation.StandardValidation;
17 17
18public class CreateServerDialog extends AbstractDialog { 18public class CreateServerDialog extends AbstractDialog {
19
20 private ValidatableTextField portField; 19 private ValidatableTextField portField;
21 private ValidatablePasswordField passwordField; 20 private ValidatablePasswordField passwordField;
22 21
@@ -38,10 +37,7 @@ public class CreateServerDialog extends AbstractDialog {
38 portField.addActionListener(event -> confirm()); 37 portField.addActionListener(event -> confirm());
39 passwordField.addActionListener(event -> confirm()); 38 passwordField.addActionListener(event -> confirm());
40 39
41 return Arrays.asList( 40 return Arrays.asList(new Pair<>("prompt.create_server.port", portField), new Pair<>("prompt.password", passwordField));
42 new Pair<>("prompt.create_server.port", portField),
43 new Pair<>("prompt.password", passwordField)
44 );
45 } 41 }
46 42
47 @Override 43 @Override
@@ -49,20 +45,25 @@ public class CreateServerDialog extends AbstractDialog {
49 vc.setActiveElement(portField); 45 vc.setActiveElement(portField);
50 StandardValidation.isIntInRange(vc, portField.getText(), 0, 65535); 46 StandardValidation.isIntInRange(vc, portField.getText(), 0, 65535);
51 vc.setActiveElement(passwordField); 47 vc.setActiveElement(passwordField);
48
52 if (passwordField.getPassword().length > EnigmaServer.MAX_PASSWORD_LENGTH) { 49 if (passwordField.getPassword().length > EnigmaServer.MAX_PASSWORD_LENGTH) {
53 vc.raise(Message.FIELD_LENGTH_OUT_OF_RANGE, EnigmaServer.MAX_PASSWORD_LENGTH); 50 vc.raise(Message.FIELD_LENGTH_OUT_OF_RANGE, EnigmaServer.MAX_PASSWORD_LENGTH);
54 } 51 }
55 } 52 }
56 53
57 public Result getResult() { 54 public Result getResult() {
58 if (!isActionConfirm()) return null; 55 if (!isActionConfirm()) {
56 return null;
57 }
58
59 vc.reset(); 59 vc.reset();
60 validateInputs(); 60 validateInputs();
61 if (!vc.canProceed()) return null; 61
62 return new Result( 62 if (!vc.canProceed()) {
63 Integer.parseInt(portField.getText()), 63 return null;
64 passwordField.getPassword() 64 }
65 ); 65
66 return new Result(Integer.parseInt(portField.getText()), passwordField.getPassword());
66 } 67 }
67 68
68 public static Result show(Frame parent) { 69 public static Result show(Frame parent) {
@@ -92,5 +93,4 @@ public class CreateServerDialog extends AbstractDialog {
92 return password; 93 return password;
93 } 94 }
94 } 95 }
95
96} 96}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/FontDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/FontDialog.java
index 4e02a666..f0bae17b 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/FontDialog.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/FontDialog.java
@@ -1,6 +1,11 @@
1package cuchaz.enigma.gui.dialog; 1package cuchaz.enigma.gui.dialog;
2 2
3import java.awt.*; 3import java.awt.Component;
4import java.awt.Container;
5import java.awt.Font;
6import java.awt.Frame;
7import java.awt.GridBagConstraints;
8import java.awt.GridBagLayout;
4import java.util.List; 9import java.util.List;
5 10
6import javax.swing.JButton; 11import javax.swing.JButton;
@@ -16,20 +21,9 @@ import cuchaz.enigma.gui.util.ScaleUtil;
16import cuchaz.enigma.utils.I18n; 21import cuchaz.enigma.utils.I18n;
17 22
18public class FontDialog extends JDialog { 23public class FontDialog extends JDialog {
24 private static final List<String> CATEGORIES = List.of("Default", "Default 2", "Small", "Editor");
19 25
20 private static final List<String> CATEGORIES = List.of( 26 private static final List<String> CATEGORY_TEXTS = List.of("fonts.cat.default", "fonts.cat.default2", "fonts.cat.small", "fonts.cat.editor");
21 "Default",
22 "Default 2",
23 "Small",
24 "Editor"
25 );
26
27 private static final List<String> CATEGORY_TEXTS = List.of(
28 "fonts.cat.default",
29 "fonts.cat.default2",
30 "fonts.cat.small",
31 "fonts.cat.editor"
32 );
33 27
34 private final JList<String> entries = new JList<>(CATEGORY_TEXTS.stream().map(I18n::translate).toArray(String[]::new)); 28 private final JList<String> entries = new JList<>(CATEGORY_TEXTS.stream().map(I18n::translate).toArray(String[]::new));
35 private final FontChooser chooser = new FontChooser(Font.decode(Font.DIALOG)); 29 private final FontChooser chooser = new FontChooser(Font.decode(Font.DIALOG));
@@ -55,8 +49,7 @@ public class FontDialog extends JDialog {
55 Container contentPane = this.getContentPane(); 49 Container contentPane = this.getContentPane();
56 contentPane.setLayout(new GridBagLayout()); 50 contentPane.setLayout(new GridBagLayout());
57 51
58 GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create() 52 GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(2);
59 .insets(2);
60 53
61 contentPane.add(this.entries, cb.pos(0, 0).weight(0.0, 1.0).fill(GridBagConstraints.BOTH).build()); 54 contentPane.add(this.entries, cb.pos(0, 0).weight(0.0, 1.0).fill(GridBagConstraints.BOTH).build());
62 contentPane.add(this.chooser, cb.pos(1, 0).weight(1.0, 1.0).fill(GridBagConstraints.BOTH).size(2, 1).build()); 55 contentPane.add(this.chooser, cb.pos(1, 0).weight(1.0, 1.0).fill(GridBagConstraints.BOTH).size(2, 1).build());
@@ -77,6 +70,7 @@ public class FontDialog extends JDialog {
77 private void categoryChanged() { 70 private void categoryChanged() {
78 this.updateUiState(); 71 this.updateUiState();
79 int selectedIndex = this.entries.getSelectedIndex(); 72 int selectedIndex = this.entries.getSelectedIndex();
73
80 if (selectedIndex != -1) { 74 if (selectedIndex != -1) {
81 this.chooser.setSelectedFont(this.fonts[selectedIndex]); 75 this.chooser.setSelectedFont(this.fonts[selectedIndex]);
82 } 76 }
@@ -84,6 +78,7 @@ public class FontDialog extends JDialog {
84 78
85 private void selectedFontChanged() { 79 private void selectedFontChanged() {
86 int selectedIndex = this.entries.getSelectedIndex(); 80 int selectedIndex = this.entries.getSelectedIndex();
81
87 if (selectedIndex != -1) { 82 if (selectedIndex != -1) {
88 this.fonts[selectedIndex] = this.chooser.getSelectedFont(); 83 this.fonts[selectedIndex] = this.chooser.getSelectedFont();
89 } 84 }
@@ -98,6 +93,7 @@ public class FontDialog extends JDialog {
98 for (int i = 0; i < CATEGORIES.size(); i++) { 93 for (int i = 0; i < CATEGORIES.size(); i++) {
99 UiConfig.setFont(CATEGORIES.get(i), this.fonts[i]); 94 UiConfig.setFont(CATEGORIES.get(i), this.fonts[i]);
100 } 95 }
96
101 UiConfig.setUseCustomFonts(this.customCheckBox.isSelected()); 97 UiConfig.setUseCustomFonts(this.customCheckBox.isSelected());
102 UiConfig.save(); 98 UiConfig.save();
103 ChangeDialog.show(this); 99 ChangeDialog.show(this);
@@ -118,8 +114,8 @@ public class FontDialog extends JDialog {
118 for (Component component : ((Container) self).getComponents()) { 114 for (Component component : ((Container) self).getComponents()) {
119 recursiveSetEnabled(component, enabled); 115 recursiveSetEnabled(component, enabled);
120 } 116 }
117
121 self.setEnabled(enabled); 118 self.setEnabled(enabled);
122 } 119 }
123 } 120 }
124
125} 121}
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 9470e11c..d6e544d0 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
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 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 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.gui.dialog; 12package cuchaz.enigma.gui.dialog;
13 13
@@ -18,7 +18,15 @@ import java.awt.FlowLayout;
18import java.awt.event.KeyAdapter; 18import java.awt.event.KeyAdapter;
19import java.awt.event.KeyEvent; 19import java.awt.event.KeyEvent;
20 20
21import javax.swing.*; 21import javax.swing.JButton;
22import javax.swing.JComboBox;
23import javax.swing.JDialog;
24import javax.swing.JFrame;
25import javax.swing.JLabel;
26import javax.swing.JMenuBar;
27import javax.swing.JPanel;
28import javax.swing.JScrollPane;
29import javax.swing.WindowConstants;
22import javax.swing.text.html.HTML; 30import javax.swing.text.html.HTML;
23 31
24import com.google.common.base.Strings; 32import com.google.common.base.Strings;
@@ -35,7 +43,6 @@ import cuchaz.enigma.utils.I18n;
35import cuchaz.enigma.utils.validation.ValidationContext; 43import cuchaz.enigma.utils.validation.ValidationContext;
36 44
37public class JavadocDialog { 45public class JavadocDialog {
38
39 private final JDialog ui; 46 private final JDialog ui;
40 private final GuiController controller; 47 private final GuiController controller;
41 private final Entry<?> entry; 48 private final Entry<?> entry;
@@ -62,19 +69,21 @@ public class JavadocDialog {
62 @Override 69 @Override
63 public void keyPressed(KeyEvent event) { 70 public void keyPressed(KeyEvent event) {
64 switch (event.getKeyCode()) { 71 switch (event.getKeyCode()) {
65 case KeyEvent.VK_ENTER: 72 case KeyEvent.VK_ENTER:
66 if (event.isControlDown()) { 73 if (event.isControlDown()) {
67 doSave(); 74 doSave();
68 if (vc.canProceed()) { 75
69 close(); 76 if (vc.canProceed()) {
70 } 77 close();
71 } 78 }
72 break; 79 }
73 case KeyEvent.VK_ESCAPE: 80
74 close(); 81 break;
75 break; 82 case KeyEvent.VK_ESCAPE:
76 default: 83 close();
77 break; 84 break;
85 default:
86 break;
78 } 87 }
79 } 88 }
80 }); 89 });
@@ -108,6 +117,7 @@ public class JavadocDialog {
108 } else { 117 } else {
109 tagText = tag.getText() + " " + text.getSelectedText(); 118 tagText = tag.getText() + " " + text.getSelectedText();
110 } 119 }
120
111 text.replaceSelection(tagText); 121 text.replaceSelection(tagText);
112 } else { 122 } else {
113 text.insert(tagText, text.getCaretPosition()); 123 text.insert(tagText, text.getCaretPosition());
@@ -116,6 +126,7 @@ public class JavadocDialog {
116 if (tag.isInline()) { 126 if (tag.isInline()) {
117 text.setCaretPosition(text.getCaretPosition() - 1); 127 text.setCaretPosition(text.getCaretPosition() - 1);
118 } 128 }
129
119 text.grabFocus(); 130 text.grabFocus();
120 }); 131 });
121 tagsMenu.add(tagButton); 132 tagsMenu.add(tagButton);
@@ -124,9 +135,11 @@ public class JavadocDialog {
124 // add html tags 135 // add html tags
125 JComboBox<String> htmlList = new JComboBox<String>(); 136 JComboBox<String> htmlList = new JComboBox<String>();
126 htmlList.setPreferredSize(new Dimension()); 137 htmlList.setPreferredSize(new Dimension());
138
127 for (HTML.Tag htmlTag : HTML.getAllTags()) { 139 for (HTML.Tag htmlTag : HTML.getAllTags()) {
128 htmlList.addItem(htmlTag.toString()); 140 htmlList.addItem(htmlTag.toString());
129 } 141 }
142
130 htmlList.addActionListener(action -> { 143 htmlList.addActionListener(action -> {
131 String tagText = "<" + htmlList.getSelectedItem().toString() + ">"; 144 String tagText = "<" + htmlList.getSelectedItem().toString() + ">";
132 text.insert(tagText, text.getCaretPosition()); 145 text.insert(tagText, text.getCaretPosition());
@@ -146,9 +159,17 @@ public class JavadocDialog {
146 public void doSave() { 159 public void doSave() {
147 vc.reset(); 160 vc.reset();
148 validate(); 161 validate();
149 if (!vc.canProceed()) return; 162
163 if (!vc.canProceed()) {
164 return;
165 }
166
150 save(); 167 save();
151 if (!vc.canProceed()) return; 168
169 if (!vc.canProceed()) {
170 return;
171 }
172
152 close(); 173 close();
153 } 174 }
154 175
@@ -189,7 +210,7 @@ public class JavadocDialog {
189 210
190 private boolean inline; 211 private boolean inline;
191 212
192 private JavadocTag(boolean inline) { 213 JavadocTag(boolean inline) {
193 this.inline = inline; 214 this.inline = inline;
194 } 215 }
195 216
@@ -201,5 +222,4 @@ public class JavadocDialog {
201 return this.inline; 222 return this.inline;
202 } 223 }
203 } 224 }
204
205} 225}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ProgressDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ProgressDialog.java
index d76ddea9..3beae21c 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ProgressDialog.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ProgressDialog.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 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 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.gui.dialog; 12package cuchaz.enigma.gui.dialog;
13 13
@@ -17,7 +17,12 @@ import java.awt.GridBagConstraints;
17import java.awt.GridBagLayout; 17import java.awt.GridBagLayout;
18import java.util.concurrent.CompletableFuture; 18import java.util.concurrent.CompletableFuture;
19 19
20import javax.swing.*; 20import javax.swing.JDialog;
21import javax.swing.JFrame;
22import javax.swing.JLabel;
23import javax.swing.JProgressBar;
24import javax.swing.SwingUtilities;
25import javax.swing.WindowConstants;
21 26
22import cuchaz.enigma.Enigma; 27import cuchaz.enigma.Enigma;
23import cuchaz.enigma.ProgressListener; 28import cuchaz.enigma.ProgressListener;
@@ -27,7 +32,6 @@ import cuchaz.enigma.gui.util.ScaleUtil;
27import cuchaz.enigma.utils.I18n; 32import cuchaz.enigma.utils.I18n;
28 33
29public class ProgressDialog implements ProgressListener, AutoCloseable { 34public class ProgressDialog implements ProgressListener, AutoCloseable {
30
31 private final JDialog dialog; 35 private final JDialog dialog;
32 private final JLabel labelTitle = new JLabel(); 36 private final JLabel labelTitle = new JLabel();
33 private final JLabel labelText = GuiUtil.unboldLabel(new JLabel()); 37 private final JLabel labelText = GuiUtil.unboldLabel(new JLabel());
@@ -39,11 +43,7 @@ public class ProgressDialog implements ProgressListener, AutoCloseable {
39 Container pane = this.dialog.getContentPane(); 43 Container pane = this.dialog.getContentPane();
40 pane.setLayout(new GridBagLayout()); 44 pane.setLayout(new GridBagLayout());
41 45
42 GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create() 46 GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(2).anchor(GridBagConstraints.WEST).fill(GridBagConstraints.BOTH).weight(1.0, 0.0);
43 .insets(2)
44 .anchor(GridBagConstraints.WEST)
45 .fill(GridBagConstraints.BOTH)
46 .weight(1.0, 0.0);
47 47
48 pane.add(this.labelTitle, cb.pos(0, 0).build()); 48 pane.add(this.labelTitle, cb.pos(0, 0).build());
49 pane.add(this.labelText, cb.pos(0, 1).build()); 49 pane.add(this.labelText, cb.pos(0, 1).build());
@@ -121,6 +121,7 @@ public class ProgressDialog implements ProgressListener, AutoCloseable {
121 public void step(int numDone, String message) { 121 public void step(int numDone, String message) {
122 SwingUtilities.invokeLater(() -> { 122 SwingUtilities.invokeLater(() -> {
123 this.labelText.setText(message); 123 this.labelText.setText(message);
124
124 if (numDone != -1) { 125 if (numDone != -1) {
125 this.progress.setValue(numDone); 126 this.progress.setValue(numDone);
126 this.progress.setIndeterminate(false); 127 this.progress.setIndeterminate(false);
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java
index e65b661b..7814dd81 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 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 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.gui.dialog; 12package cuchaz.enigma.gui.dialog;
13 13
@@ -15,17 +15,36 @@ import java.awt.BorderLayout;
15import java.awt.Color; 15import java.awt.Color;
16import java.awt.FlowLayout; 16import java.awt.FlowLayout;
17import java.awt.Font; 17import java.awt.Font;
18import java.awt.event.*; 18import java.awt.event.ComponentAdapter;
19import java.util.*; 19import java.awt.event.ComponentEvent;
20import java.awt.event.KeyAdapter;
21import java.awt.event.KeyEvent;
22import java.awt.event.MouseAdapter;
23import java.awt.event.MouseEvent;
24import java.util.Arrays;
25import java.util.Collections;
26import java.util.List;
27import java.util.Queue;
20import java.util.concurrent.ConcurrentLinkedQueue; 28import java.util.concurrent.ConcurrentLinkedQueue;
21 29
22import javax.swing.*; 30import javax.swing.DefaultListModel;
31import javax.swing.JButton;
32import javax.swing.JDialog;
33import javax.swing.JLabel;
34import javax.swing.JList;
35import javax.swing.JPanel;
36import javax.swing.JScrollPane;
37import javax.swing.JTextField;
38import javax.swing.ListSelectionModel;
39import javax.swing.SwingUtilities;
23import javax.swing.event.DocumentEvent; 40import javax.swing.event.DocumentEvent;
24import javax.swing.event.DocumentListener; 41import javax.swing.event.DocumentListener;
25 42
26import cuchaz.enigma.analysis.index.EntryIndex; 43import cuchaz.enigma.analysis.index.EntryIndex;
27import cuchaz.enigma.gui.Gui; 44import cuchaz.enigma.gui.Gui;
28import cuchaz.enigma.gui.GuiController; 45import cuchaz.enigma.gui.GuiController;
46import cuchaz.enigma.gui.search.SearchEntry;
47import cuchaz.enigma.gui.search.SearchUtil;
29import cuchaz.enigma.gui.util.AbstractListCellRenderer; 48import cuchaz.enigma.gui.util.AbstractListCellRenderer;
30import cuchaz.enigma.gui.util.GuiUtil; 49import cuchaz.enigma.gui.util.GuiUtil;
31import cuchaz.enigma.gui.util.ScaleUtil; 50import cuchaz.enigma.gui.util.ScaleUtil;
@@ -34,11 +53,8 @@ import cuchaz.enigma.translation.representation.entry.FieldEntry;
34import cuchaz.enigma.translation.representation.entry.MethodEntry; 53import cuchaz.enigma.translation.representation.entry.MethodEntry;
35import cuchaz.enigma.translation.representation.entry.ParentedEntry; 54import cuchaz.enigma.translation.representation.entry.ParentedEntry;
36import cuchaz.enigma.utils.I18n; 55import cuchaz.enigma.utils.I18n;
37import cuchaz.enigma.gui.search.SearchEntry;
38import cuchaz.enigma.gui.search.SearchUtil;
39 56
40public class SearchDialog { 57public class SearchDialog {
41
42 private final JTextField searchField; 58 private final JTextField searchField;
43 private DefaultListModel<SearchEntryImpl> classListModel; 59 private DefaultListModel<SearchEntryImpl> classListModel;
44 private final JList<SearchEntryImpl> classList; 60 private final JList<SearchEntryImpl> classList;
@@ -60,7 +76,6 @@ public class SearchDialog {
60 76
61 searchField = new JTextField(); 77 searchField = new JTextField();
62 searchField.getDocument().addDocumentListener(new DocumentListener() { 78 searchField.getDocument().addDocumentListener(new DocumentListener() {
63
64 @Override 79 @Override
65 public void insertUpdate(DocumentEvent e) { 80 public void insertUpdate(DocumentEvent e) {
66 updateList(); 81 updateList();
@@ -75,7 +90,6 @@ public class SearchDialog {
75 public void changedUpdate(DocumentEvent e) { 90 public void changedUpdate(DocumentEvent e) {
76 updateList(); 91 updateList();
77 } 92 }
78
79 }); 93 });
80 searchField.addKeyListener(new KeyAdapter() { 94 searchField.addKeyListener(new KeyAdapter() {
81 @Override 95 @Override
@@ -143,23 +157,9 @@ public class SearchDialog {
143 final EntryIndex entryIndex = parent.getController().project.getJarIndex().getEntryIndex(); 157 final EntryIndex entryIndex = parent.getController().project.getJarIndex().getEntryIndex();
144 158
145 switch (type) { 159 switch (type) {
146 case CLASS -> entryIndex.getClasses().parallelStream() 160 case CLASS -> entryIndex.getClasses().parallelStream().filter(e -> !e.isInnerClass()).map(e -> SearchEntryImpl.from(e, parent.getController())).map(SearchUtil.Entry::from).sequential().forEach(su::add);
147 .filter(e -> !e.isInnerClass()) 161 case METHOD -> entryIndex.getMethods().parallelStream().filter(e -> !e.isConstructor() && !entryIndex.getMethodAccess(e).isSynthetic()).map(e -> SearchEntryImpl.from(e, parent.getController())).map(SearchUtil.Entry::from).sequential().forEach(su::add);
148 .map(e -> SearchEntryImpl.from(e, parent.getController())) 162 case FIELD -> entryIndex.getFields().parallelStream().map(e -> SearchEntryImpl.from(e, parent.getController())).map(SearchUtil.Entry::from).sequential().forEach(su::add);
149 .map(SearchUtil.Entry::from)
150 .sequential()
151 .forEach(su::add);
152 case METHOD -> entryIndex.getMethods().parallelStream()
153 .filter(e -> !e.isConstructor() && !entryIndex.getMethodAccess(e).isSynthetic())
154 .map(e -> SearchEntryImpl.from(e, parent.getController()))
155 .map(SearchUtil.Entry::from)
156 .sequential()
157 .forEach(su::add);
158 case FIELD -> entryIndex.getFields().parallelStream()
159 .map(e -> SearchEntryImpl.from(e, parent.getController()))
160 .map(SearchUtil.Entry::from)
161 .sequential()
162 .forEach(su::add);
163 } 163 }
164 164
165 updateList(); 165 updateList();
@@ -172,6 +172,7 @@ public class SearchDialog {
172 172
173 private void openSelected() { 173 private void openSelected() {
174 SearchEntryImpl selectedValue = classList.getSelectedValue(); 174 SearchEntryImpl selectedValue = classList.getSelectedValue();
175
175 if (selectedValue != null) { 176 if (selectedValue != null) {
176 openEntry(selectedValue); 177 openEntry(selectedValue);
177 } 178 }
@@ -181,6 +182,7 @@ public class SearchDialog {
181 close(); 182 close();
182 su.hit(e); 183 su.hit(e);
183 parent.getController().navigateTo(e.obf); 184 parent.getController().navigateTo(e.obf);
185
184 if (e.obf instanceof ClassEntry) { 186 if (e.obf instanceof ClassEntry) {
185 if (e.deobf != null) { 187 if (e.deobf != null) {
186 parent.getDeobfPanel().deobfClasses.setSelectionClass((ClassEntry) e.deobf); 188 parent.getDeobfPanel().deobfClasses.setSelectionClass((ClassEntry) e.deobf);
@@ -202,7 +204,9 @@ public class SearchDialog {
202 204
203 // Updates the list of class names 205 // Updates the list of class names
204 private void updateList() { 206 private void updateList() {
205 if (currentSearch != null) currentSearch.stop(); 207 if (currentSearch != null) {
208 currentSearch.stop();
209 }
206 210
207 DefaultListModel<SearchEntryImpl> classListModel = new DefaultListModel<>(); 211 DefaultListModel<SearchEntryImpl> classListModel = new DefaultListModel<>();
208 this.classListModel = classListModel; 212 this.classListModel = classListModel;
@@ -210,7 +214,9 @@ public class SearchDialog {
210 214
211 // handle these search result like minecraft scheduled tasks to prevent 215 // handle these search result like minecraft scheduled tasks to prevent
212 // flooding swing buttons inputs etc with tons of (possibly outdated) invocations 216 // flooding swing buttons inputs etc with tons of (possibly outdated) invocations
213 record Order(int idx, SearchEntryImpl e) {} 217 record Order(int idx, SearchEntryImpl e) {
218 }
219
214 Queue<Order> queue = new ConcurrentLinkedQueue<>(); 220 Queue<Order> queue = new ConcurrentLinkedQueue<>();
215 Runnable updater = new Runnable() { 221 Runnable updater = new Runnable() {
216 @Override 222 @Override
@@ -221,8 +227,9 @@ public class SearchDialog {
221 227
222 // too large count may increase delay for key and input handling, etc. 228 // too large count may increase delay for key and input handling, etc.
223 int count = 100; 229 int count = 100;
230
224 while (count > 0 && !queue.isEmpty()) { 231 while (count > 0 && !queue.isEmpty()) {
225 var o = queue.remove(); 232 Order o = queue.remove();
226 classListModel.insertElementAt(o.e, o.idx); 233 classListModel.insertElementAt(o.e, o.idx);
227 count--; 234 count--;
228 } 235 }
@@ -240,7 +247,6 @@ public class SearchDialog {
240 } 247 }
241 248
242 private static final class SearchEntryImpl implements SearchEntry { 249 private static final class SearchEntryImpl implements SearchEntry {
243
244 public final ParentedEntry<?> obf; 250 public final ParentedEntry<?> obf;
245 public final ParentedEntry<?> deobf; 251 public final ParentedEntry<?> deobf;
246 252
@@ -270,10 +276,13 @@ public class SearchDialog {
270 276
271 public static SearchEntryImpl from(ParentedEntry<?> e, GuiController controller) { 277 public static SearchEntryImpl from(ParentedEntry<?> e, GuiController controller) {
272 ParentedEntry<?> deobf = controller.project.getMapper().deobfuscate(e); 278 ParentedEntry<?> deobf = controller.project.getMapper().deobfuscate(e);
273 if (deobf.equals(e)) deobf = null; 279
280 if (deobf.equals(e)) {
281 deobf = null;
282 }
283
274 return new SearchEntryImpl(e, deobf); 284 return new SearchEntryImpl(e, deobf);
275 } 285 }
276
277 } 286 }
278 287
279 private static final class ListCellRendererImpl extends AbstractListCellRenderer<SearchEntryImpl> { 288 private static final class ListCellRendererImpl extends AbstractListCellRenderer<SearchEntryImpl> {
@@ -281,7 +290,7 @@ public class SearchDialog {
281 private final JLabel mainName; 290 private final JLabel mainName;
282 private final JLabel secondaryName; 291 private final JLabel secondaryName;
283 292
284 public ListCellRendererImpl(Gui gui) { 293 ListCellRendererImpl(Gui gui) {
285 this.setLayout(new BorderLayout()); 294 this.setLayout(new BorderLayout());
286 this.gui = gui; 295 this.gui = gui;
287 296
@@ -316,7 +325,6 @@ public class SearchDialog {
316 mainName.setIcon(GuiUtil.FIELD_ICON); 325 mainName.setIcon(GuiUtil.FIELD_ICON);
317 } 326 }
318 } 327 }
319
320 } 328 }
321 329
322 public enum Type { 330 public enum Type {
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/StatsDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/StatsDialog.java
index 0398093b..1ab66ef2 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/StatsDialog.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/StatsDialog.java
@@ -4,10 +4,19 @@ import java.awt.Container;
4import java.awt.Dimension; 4import java.awt.Dimension;
5import java.awt.GridBagConstraints; 5import java.awt.GridBagConstraints;
6import java.awt.GridBagLayout; 6import java.awt.GridBagLayout;
7import java.util.*; 7import java.util.Collections;
8import java.util.HashMap;
9import java.util.Locale;
10import java.util.Map;
11import java.util.Set;
8import java.util.stream.Collectors; 12import java.util.stream.Collectors;
9 13
10import javax.swing.*; 14import javax.swing.JButton;
15import javax.swing.JCheckBox;
16import javax.swing.JDialog;
17import javax.swing.JLabel;
18import javax.swing.JTextField;
19import javax.swing.SwingUtilities;
11 20
12import cuchaz.enigma.gui.Gui; 21import cuchaz.enigma.gui.Gui;
13import cuchaz.enigma.gui.config.UiConfig; 22import cuchaz.enigma.gui.config.UiConfig;
@@ -19,14 +28,15 @@ import cuchaz.enigma.gui.util.ScaleUtil;
19import cuchaz.enigma.utils.I18n; 28import cuchaz.enigma.utils.I18n;
20 29
21public class StatsDialog { 30public class StatsDialog {
22
23 public static void show(Gui gui) { 31 public static void show(Gui gui) {
24 ProgressDialog.runOffThread(gui.getFrame(), listener -> { 32 ProgressDialog.runOffThread(gui.getFrame(), listener -> {
25 final StatsGenerator statsGenerator = new StatsGenerator(gui.getController().project); 33 final StatsGenerator statsGenerator = new StatsGenerator(gui.getController().project);
26 final Map<StatsMember, StatsResult> results = new HashMap<>(); 34 final Map<StatsMember, StatsResult> results = new HashMap<>();
35
27 for (StatsMember member : StatsMember.values()) { 36 for (StatsMember member : StatsMember.values()) {
28 results.put(member, statsGenerator.generate(listener, Collections.singleton(member), "", false)); 37 results.put(member, statsGenerator.generate(listener, Collections.singleton(member), "", false));
29 } 38 }
39
30 SwingUtilities.invokeLater(() -> show(gui, results)); 40 SwingUtilities.invokeLater(() -> show(gui, results));
31 }); 41 });
32 } 42 }
@@ -111,12 +121,7 @@ public class StatsDialog {
111 121
112 private static void generateStats(Gui gui, Map<StatsMember, JCheckBox> checkboxes, String topLevelPackage, boolean includeSynthetic) { 122 private static void generateStats(Gui gui, Map<StatsMember, JCheckBox> checkboxes, String topLevelPackage, boolean includeSynthetic) {
113 // get members from selected checkboxes 123 // get members from selected checkboxes
114 Set<StatsMember> includedMembers = checkboxes 124 Set<StatsMember> includedMembers = checkboxes.entrySet().stream().filter(entry -> entry.getValue().isSelected()).map(Map.Entry::getKey).collect(Collectors.toSet());
115 .entrySet()
116 .stream()
117 .filter(entry -> entry.getValue().isSelected())
118 .map(Map.Entry::getKey)
119 .collect(Collectors.toSet());
120 125
121 // checks if a project is open 126 // checks if a project is open
122 if (gui.getController().project != null) { 127 if (gui.getController().project != null) {
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/AbstractInheritanceTree.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/AbstractInheritanceTree.java
index 39aa212f..3f1625de 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/AbstractInheritanceTree.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/AbstractInheritanceTree.java
@@ -7,7 +7,11 @@ import javax.annotation.Nullable;
7import javax.swing.JPanel; 7import javax.swing.JPanel;
8import javax.swing.JScrollPane; 8import javax.swing.JScrollPane;
9import javax.swing.JTree; 9import javax.swing.JTree;
10import javax.swing.tree.*; 10import javax.swing.tree.DefaultMutableTreeNode;
11import javax.swing.tree.DefaultTreeModel;
12import javax.swing.tree.TreeCellRenderer;
13import javax.swing.tree.TreeNode;
14import javax.swing.tree.TreePath;
11 15
12import cuchaz.enigma.analysis.ClassInheritanceTreeNode; 16import cuchaz.enigma.analysis.ClassInheritanceTreeNode;
13import cuchaz.enigma.analysis.MethodInheritanceTreeNode; 17import cuchaz.enigma.analysis.MethodInheritanceTreeNode;
@@ -40,11 +44,13 @@ public abstract class AbstractInheritanceTree {
40 if (event.getClickCount() >= 2 && event.getButton() == MouseEvent.BUTTON1) { 44 if (event.getClickCount() >= 2 && event.getButton() == MouseEvent.BUTTON1) {
41 // get the selected node 45 // get the selected node
42 TreePath path = tree.getSelectionPath(); 46 TreePath path = tree.getSelectionPath();
47
43 if (path == null) { 48 if (path == null) {
44 return; 49 return;
45 } 50 }
46 51
47 Object node = path.getLastPathComponent(); 52 Object node = path.getLastPathComponent();
53
48 if (node instanceof ClassInheritanceTreeNode classNode) { 54 if (node instanceof ClassInheritanceTreeNode classNode) {
49 gui.getController().navigateTo(new ClassEntry(classNode.getObfClassName())); 55 gui.getController().navigateTo(new ClassEntry(classNode.getObfClassName()));
50 } else if (node instanceof MethodInheritanceTreeNode methodNode) { 56 } else if (node instanceof MethodInheritanceTreeNode methodNode) {
@@ -72,7 +78,6 @@ public abstract class AbstractInheritanceTree {
72 } 78 }
73 79
74 public void retranslateUi() { 80 public void retranslateUi() {
75
76 } 81 }
77 82
78 @Nullable 83 @Nullable
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/CallsTree.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/CallsTree.java
index c92534f0..56711880 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/CallsTree.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/CallsTree.java
@@ -5,7 +5,12 @@ import java.awt.event.MouseEvent;
5import java.util.Collection; 5import java.util.Collection;
6import java.util.Vector; 6import java.util.Vector;
7 7
8import javax.swing.*; 8import javax.swing.JList;
9import javax.swing.JPanel;
10import javax.swing.JScrollPane;
11import javax.swing.JSplitPane;
12import javax.swing.JTree;
13import javax.swing.ListSelectionModel;
9import javax.swing.tree.DefaultTreeModel; 14import javax.swing.tree.DefaultTreeModel;
10import javax.swing.tree.TreeNode; 15import javax.swing.tree.TreeNode;
11import javax.swing.tree.TreePath; 16import javax.swing.tree.TreePath;
@@ -47,12 +52,7 @@ public class CallsTree {
47 this.tokens.setPreferredSize(ScaleUtil.getDimension(0, 200)); 52 this.tokens.setPreferredSize(ScaleUtil.getDimension(0, 200));
48 this.tokens.setMinimumSize(ScaleUtil.getDimension(0, 200)); 53 this.tokens.setMinimumSize(ScaleUtil.getDimension(0, 200));
49 54
50 JSplitPane contentPane = new JSplitPane( 55 JSplitPane contentPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, new JScrollPane(this.callsTree), new JScrollPane(this.tokens));
51 JSplitPane.VERTICAL_SPLIT,
52 true,
53 new JScrollPane(this.callsTree),
54 new JScrollPane(this.tokens)
55 );
56 56
57 contentPane.setResizeWeight(1); // let the top side take all the slack 57 contentPane.setResizeWeight(1); // let the top side take all the slack
58 contentPane.resetToPreferredSizes(); 58 contentPane.resetToPreferredSizes();
@@ -109,6 +109,7 @@ public class CallsTree {
109 private void onTokenClicked(MouseEvent event) { 109 private void onTokenClicked(MouseEvent event) {
110 if (event.getClickCount() == 2) { 110 if (event.getClickCount() == 2) {
111 Token selected = this.tokens.getSelectedValue(); 111 Token selected = this.tokens.getSelectedValue();
112
112 if (selected != null) { 113 if (selected != null) {
113 this.gui.openClass(this.gui.getController().getTokenHandle().getRef()).navigateToToken(selected); 114 this.gui.openClass(this.gui.getController().getTokenHandle().getRef()).navigateToToken(selected);
114 } 115 }
@@ -116,7 +117,6 @@ public class CallsTree {
116 } 117 }
117 118
118 public void retranslateUi() { 119 public void retranslateUi() {
119
120 } 120 }
121 121
122 public JPanel getPanel() { 122 public JPanel getPanel() {
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/CollapsibleTabbedPane.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/CollapsibleTabbedPane.java
index fb497b11..e05ab458 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/CollapsibleTabbedPane.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/CollapsibleTabbedPane.java
@@ -5,7 +5,6 @@ import java.awt.event.MouseEvent;
5import javax.swing.JTabbedPane; 5import javax.swing.JTabbedPane;
6 6
7public class CollapsibleTabbedPane extends JTabbedPane { 7public class CollapsibleTabbedPane extends JTabbedPane {
8
9 public CollapsibleTabbedPane() { 8 public CollapsibleTabbedPane() {
10 } 9 }
11 10
@@ -20,9 +19,14 @@ public class CollapsibleTabbedPane extends JTabbedPane {
20 @Override 19 @Override
21 protected void processMouseEvent(MouseEvent e) { 20 protected void processMouseEvent(MouseEvent e) {
22 int id = e.getID(); 21 int id = e.getID();
22
23 if (id == MouseEvent.MOUSE_PRESSED) { 23 if (id == MouseEvent.MOUSE_PRESSED) {
24 if (!isEnabled()) return; 24 if (!isEnabled()) {
25 return;
26 }
27
25 int tabIndex = getUI().tabForCoordinate(this, e.getX(), e.getY()); 28 int tabIndex = getUI().tabForCoordinate(this, e.getX(), e.getY());
29
26 if (tabIndex >= 0 && isEnabledAt(tabIndex)) { 30 if (tabIndex >= 0 && isEnabledAt(tabIndex)) {
27 if (tabIndex == getSelectedIndex()) { 31 if (tabIndex == getSelectedIndex()) {
28 if (isFocusOwner() && isRequestFocusEnabled()) { 32 if (isFocusOwner() && isRequestFocusEnabled()) {
@@ -30,11 +34,12 @@ public class CollapsibleTabbedPane extends JTabbedPane {
30 } else { 34 } else {
31 setSelectedIndex(-1); 35 setSelectedIndex(-1);
32 } 36 }
37
33 return; 38 return;
34 } 39 }
35 } 40 }
36 } 41 }
42
37 super.processMouseEvent(e); 43 super.processMouseEvent(e);
38 } 44 }
39
40} 45}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ConvertingTextField.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ConvertingTextField.java
index 9a6ea098..301ae7f1 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ConvertingTextField.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ConvertingTextField.java
@@ -1,7 +1,12 @@
1package cuchaz.enigma.gui.elements; 1package cuchaz.enigma.gui.elements;
2 2
3import java.awt.GridLayout; 3import java.awt.GridLayout;
4import java.awt.event.*; 4import java.awt.event.FocusAdapter;
5import java.awt.event.FocusEvent;
6import java.awt.event.KeyAdapter;
7import java.awt.event.KeyEvent;
8import java.awt.event.MouseAdapter;
9import java.awt.event.MouseEvent;
5import java.util.HashSet; 10import java.util.HashSet;
6import java.util.Set; 11import java.util.Set;
7 12
@@ -21,7 +26,6 @@ import cuchaz.enigma.utils.validation.Validatable;
21 * A label that converts into an editable text field when you click it. 26 * A label that converts into an editable text field when you click it.
22 */ 27 */
23public class ConvertingTextField implements Validatable { 28public class ConvertingTextField implements Validatable {
24
25 private final JPanel ui; 29 private final JPanel ui;
26 private final ValidatableTextField textField; 30 private final ValidatableTextField textField;
27 private final JLabel label; 31 private final JLabel label;
@@ -69,7 +73,9 @@ public class ConvertingTextField implements Validatable {
69 } 73 }
70 74
71 public void startEditing() { 75 public void startEditing() {
72 if (this.editing || !this.editable) return; 76 if (this.editing || !this.editable) {
77 return;
78 }
73 79
74 this.ui.removeAll(); 80 this.ui.removeAll();
75 this.ui.add(this.textField); 81 this.ui.add(this.textField);
@@ -82,9 +88,13 @@ public class ConvertingTextField implements Validatable {
82 } 88 }
83 89
84 public void stopEditing(boolean abort) { 90 public void stopEditing(boolean abort) {
85 if (!editing) return; 91 if (!editing) {
92 return;
93 }
86 94
87 if (!listeners.stream().allMatch(l -> l.tryStopEditing(this, abort))) return; 95 if (!listeners.stream().allMatch(l -> l.tryStopEditing(this, abort))) {
96 return;
97 }
88 98
89 if (abort) { 99 if (abort) {
90 this.textField.setText(this.label.getText()); 100 this.textField.setText(this.label.getText());
@@ -107,7 +117,9 @@ public class ConvertingTextField implements Validatable {
107 } 117 }
108 118
109 public void setEditText(String text) { 119 public void setEditText(String text) {
110 if (!editing) return; 120 if (!editing) {
121 return;
122 }
111 123
112 this.textField.setText(text); 124 this.textField.setText(text);
113 } 125 }
@@ -122,22 +134,29 @@ public class ConvertingTextField implements Validatable {
122 } 134 }
123 135
124 public void selectAll() { 136 public void selectAll() {
125 if (!editing) return; 137 if (!editing) {
138 return;
139 }
126 140
127 this.textField.selectAll(); 141 this.textField.selectAll();
128 } 142 }
129 143
130 public void selectSubstring(int startIndex) { 144 public void selectSubstring(int startIndex) {
131 if (!editing) return; 145 if (!editing) {
146 return;
147 }
132 148
133 Document doc = this.textField.getDocument(); 149 Document doc = this.textField.getDocument();
150
134 if (doc != null) { 151 if (doc != null) {
135 this.selectSubstring(startIndex, doc.getLength()); 152 this.selectSubstring(startIndex, doc.getLength());
136 } 153 }
137 } 154 }
138 155
139 public void selectSubstring(int startIndex, int endIndex) { 156 public void selectSubstring(int startIndex, int endIndex) {
140 if (!editing) return; 157 if (!editing) {
158 return;
159 }
141 160
142 this.textField.select(startIndex, endIndex); 161 this.textField.select(startIndex, endIndex);
143 } 162 }
@@ -155,7 +174,10 @@ public class ConvertingTextField implements Validatable {
155 } 174 }
156 175
157 public boolean hasChanges() { 176 public boolean hasChanges() {
158 if (!editing) return false; 177 if (!editing) {
178 return false;
179 }
180
159 return !this.textField.getText().equals(this.label.getText()); 181 return !this.textField.getText().equals(this.label.getText());
160 } 182 }
161 183
@@ -180,5 +202,4 @@ public class ConvertingTextField implements Validatable {
180 public JPanel getUi() { 202 public JPanel getUi() {
181 return ui; 203 return ui;
182 } 204 }
183
184} 205}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/DeobfPanelPopupMenu.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/DeobfPanelPopupMenu.java
index 0b44881f..bcc6dc6f 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/DeobfPanelPopupMenu.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/DeobfPanelPopupMenu.java
@@ -9,55 +9,54 @@ import cuchaz.enigma.gui.panels.DeobfPanel;
9import cuchaz.enigma.utils.I18n; 9import cuchaz.enigma.utils.I18n;
10 10
11public class DeobfPanelPopupMenu { 11public class DeobfPanelPopupMenu {
12 12 private final JPopupMenu ui;
13 private final JPopupMenu ui; 13 private final JMenuItem renamePackage = new JMenuItem();
14 private final JMenuItem renamePackage = new JMenuItem(); 14 private final JMenuItem renameClass = new JMenuItem();
15 private final JMenuItem renameClass = new JMenuItem(); 15 private final JMenuItem expandAll = new JMenuItem();
16 private final JMenuItem expandAll = new JMenuItem(); 16 private final JMenuItem collapseAll = new JMenuItem();
17 private final JMenuItem collapseAll = new JMenuItem(); 17
18 18 public DeobfPanelPopupMenu(DeobfPanel panel) {
19 public DeobfPanelPopupMenu(DeobfPanel panel) { 19 this.ui = new JPopupMenu();
20 this.ui = new JPopupMenu(); 20
21 21 this.ui.add(this.renamePackage);
22 this.ui.add(this.renamePackage); 22 this.ui.add(this.renameClass);
23 this.ui.add(this.renameClass); 23 this.ui.addSeparator();
24 this.ui.addSeparator(); 24 this.ui.add(this.expandAll);
25 this.ui.add(this.expandAll); 25 this.ui.add(this.collapseAll);
26 this.ui.add(this.collapseAll); 26
27 27 ClassSelector deobfClasses = panel.deobfClasses;
28 ClassSelector deobfClasses = panel.deobfClasses; 28
29 29 this.renamePackage.addActionListener(a -> {
30 this.renamePackage.addActionListener(a -> { 30 TreePath path;
31 TreePath path; 31
32 32 if (deobfClasses.getSelectedClass() != null) {
33 if (deobfClasses.getSelectedClass() != null) { 33 // Rename parent package if selected path is a class
34 // Rename parent package if selected path is a class 34 path = deobfClasses.getSelectionPath().getParentPath();
35 path = deobfClasses.getSelectionPath().getParentPath(); 35 } else {
36 } else { 36 // Rename selected path if it's already a package
37 // Rename selected path if it's already a package 37 path = deobfClasses.getSelectionPath();
38 path = deobfClasses.getSelectionPath(); 38 }
39 } 39
40 40 deobfClasses.getUI().startEditingAtPath(deobfClasses, path);
41 deobfClasses.getUI().startEditingAtPath(deobfClasses, path); 41 });
42 }); 42 this.renameClass.addActionListener(a -> deobfClasses.getUI().startEditingAtPath(deobfClasses, deobfClasses.getSelectionPath()));
43 this.renameClass.addActionListener(a -> deobfClasses.getUI().startEditingAtPath(deobfClasses, deobfClasses.getSelectionPath())); 43 this.expandAll.addActionListener(a -> deobfClasses.expandAll());
44 this.expandAll.addActionListener(a -> deobfClasses.expandAll()); 44 this.collapseAll.addActionListener(a -> deobfClasses.collapseAll());
45 this.collapseAll.addActionListener(a -> deobfClasses.collapseAll()); 45
46 46 this.retranslateUi();
47 this.retranslateUi(); 47 }
48 } 48
49 49 public void show(ClassSelector deobfClasses, int x, int y) {
50 public void show(ClassSelector deobfClasses, int x, int y) { 50 // Only enable rename class if selected path is a class
51 // Only enable rename class if selected path is a class 51 this.renameClass.setEnabled(deobfClasses.getSelectedClass() != null);
52 this.renameClass.setEnabled(deobfClasses.getSelectedClass() != null); 52
53 53 this.ui.show(deobfClasses, x, y);
54 this.ui.show(deobfClasses, x, y); 54 }
55 } 55
56 56 public void retranslateUi() {
57 public void retranslateUi() { 57 this.renamePackage.setText(I18n.translate("popup_menu.deobf_panel.rename_package"));
58 this.renamePackage.setText(I18n.translate("popup_menu.deobf_panel.rename_package")); 58 this.renameClass.setText(I18n.translate("popup_menu.deobf_panel.rename_class"));
59 this.renameClass.setText(I18n.translate("popup_menu.deobf_panel.rename_class")); 59 this.expandAll.setText(I18n.translate("popup_menu.deobf_panel.expand_all"));
60 this.expandAll.setText(I18n.translate("popup_menu.deobf_panel.expand_all")); 60 this.collapseAll.setText(I18n.translate("popup_menu.deobf_panel.collapse_all"));
61 this.collapseAll.setText(I18n.translate("popup_menu.deobf_panel.collapse_all")); 61 }
62 }
63} 62}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorPopupMenu.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorPopupMenu.java
index 2ce6ed93..d128bf5c 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorPopupMenu.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorPopupMenu.java
@@ -19,7 +19,6 @@ import cuchaz.enigma.translation.representation.entry.MethodEntry;
19import cuchaz.enigma.utils.I18n; 19import cuchaz.enigma.utils.I18n;
20 20
21public class EditorPopupMenu { 21public class EditorPopupMenu {
22
23 private final JPopupMenu ui = new JPopupMenu(); 22 private final JPopupMenu ui = new JPopupMenu();
24 23
25 private final JMenuItem renameItem = new JMenuItem(); 24 private final JMenuItem renameItem = new JMenuItem();
@@ -105,39 +104,41 @@ public class EditorPopupMenu {
105 public boolean handleKeyEvent(KeyEvent event) { 104 public boolean handleKeyEvent(KeyEvent event) {
106 if (event.isControlDown()) { 105 if (event.isControlDown()) {
107 switch (event.getKeyCode()) { 106 switch (event.getKeyCode()) {
108 case KeyEvent.VK_I: 107 case KeyEvent.VK_I:
109 this.showInheritanceItem.doClick(); 108 this.showInheritanceItem.doClick();
110 return true; 109 return true;
111 case KeyEvent.VK_M: 110 case KeyEvent.VK_M:
112 this.showImplementationsItem.doClick(); 111 this.showImplementationsItem.doClick();
113 return true; 112 return true;
114 case KeyEvent.VK_N: 113 case KeyEvent.VK_N:
115 this.openEntryItem.doClick(); 114 this.openEntryItem.doClick();
116 return true; 115 return true;
117 case KeyEvent.VK_P: 116 case KeyEvent.VK_P:
118 this.openPreviousItem.doClick(); 117 this.openPreviousItem.doClick();
119 return true; 118 return true;
120 case KeyEvent.VK_E: 119 case KeyEvent.VK_E:
121 this.openNextItem.doClick(); 120 this.openNextItem.doClick();
122 return true; 121 return true;
123 case KeyEvent.VK_C: 122 case KeyEvent.VK_C:
124 if (event.isShiftDown()) { 123 if (event.isShiftDown()) {
125 this.showCallsSpecificItem.doClick(); 124 this.showCallsSpecificItem.doClick();
126 } else { 125 } else {
127 this.showCallsItem.doClick(); 126 this.showCallsItem.doClick();
128 } 127 }
129 return true; 128
130 case KeyEvent.VK_O: 129 return true;
131 this.toggleMappingItem.doClick(); 130 case KeyEvent.VK_O:
132 return true; 131 this.toggleMappingItem.doClick();
133 case KeyEvent.VK_R: 132 return true;
134 this.renameItem.doClick(); 133 case KeyEvent.VK_R:
135 return true; 134 this.renameItem.doClick();
136 case KeyEvent.VK_D: 135 return true;
137 this.editJavadocItem.doClick(); 136 case KeyEvent.VK_D:
138 return true; 137 this.editJavadocItem.doClick();
138 return true;
139 } 139 }
140 } 140 }
141
141 return false; 142 return false;
142 } 143 }
143 144
@@ -191,5 +192,4 @@ public class EditorPopupMenu {
191 public JPopupMenu getUi() { 192 public JPopupMenu getUi() {
192 return ui; 193 return ui;
193 } 194 }
194
195} 195}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabPopupMenu.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabPopupMenu.java
index 0b4926eb..93854818 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabPopupMenu.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabPopupMenu.java
@@ -11,7 +11,6 @@ import cuchaz.enigma.gui.panels.EditorPanel;
11import cuchaz.enigma.utils.I18n; 11import cuchaz.enigma.utils.I18n;
12 12
13public class EditorTabPopupMenu { 13public class EditorTabPopupMenu {
14
15 private final JPopupMenu ui; 14 private final JPopupMenu ui;
16 private final JMenuItem close; 15 private final JMenuItem close;
17 private final JMenuItem closeAll; 16 private final JMenuItem closeAll;
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabbedPane.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabbedPane.java
index ff0bba3f..7a6290ea 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabbedPane.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabbedPane.java
@@ -39,7 +39,11 @@ public class EditorTabbedPane {
39 public EditorPanel openClass(ClassEntry entry) { 39 public EditorPanel openClass(ClassEntry entry) {
40 EditorPanel editorPanel = this.editors.computeIfAbsent(entry, e -> { 40 EditorPanel editorPanel = this.editors.computeIfAbsent(entry, e -> {
41 ClassHandle ch = this.gui.getController().getClassHandleProvider().openClass(entry); 41 ClassHandle ch = this.gui.getController().getClassHandleProvider().openClass(entry);
42 if (ch == null) return null; 42
43 if (ch == null) {
44 return null;
45 }
46
43 EditorPanel ed = new EditorPanel(this.gui); 47 EditorPanel ed = new EditorPanel(this.gui);
44 ed.setup(); 48 ed.setup();
45 ed.setClassHandle(ch); 49 ed.setClassHandle(ch);
@@ -125,7 +129,10 @@ public class EditorTabbedPane {
125 int index = this.openFiles.indexOfComponent(ed.getUi()); 129 int index = this.openFiles.indexOfComponent(ed.getUi());
126 130
127 for (int i = this.openFiles.getTabCount() - 1; i >= 0; i--) { 131 for (int i = this.openFiles.getTabCount() - 1; i >= 0; i--) {
128 if (i == index) continue; 132 if (i == index) {
133 continue;
134 }
135
129 closeEditor(EditorPanel.byUi(this.openFiles.getComponentAt(i))); 136 closeEditor(EditorPanel.byUi(this.openFiles.getComponentAt(i)));
130 } 137 }
131 } 138 }
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/JMultiLineToolTip.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/JMultiLineToolTip.java
index 533d1b30..9e632d9d 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/JMultiLineToolTip.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/JMultiLineToolTip.java
@@ -12,13 +12,12 @@ import javax.swing.plaf.ComponentUI;
12import javax.swing.plaf.basic.BasicToolTipUI; 12import javax.swing.plaf.basic.BasicToolTipUI;
13 13
14/** 14/**
15 * Implements a multi line tooltip for GUI components 15 * Implements a multi line tooltip for GUI components.
16 * Copied from http://www.codeguru.com/java/articles/122.shtml 16 * Copied from http://www.codeguru.com/java/articles/122.shtml
17 * 17 *
18 * @author Zafir Anjum 18 * @author Zafir Anjum
19 */ 19 */
20public class JMultiLineToolTip extends JToolTip { 20public class JMultiLineToolTip extends JToolTip {
21
22 private static final long serialVersionUID = 7813662474312183098L; 21 private static final long serialVersionUID = 7813662474312183098L;
23 22
24 public JMultiLineToolTip() { 23 public JMultiLineToolTip() {
@@ -52,10 +51,9 @@ public class JMultiLineToolTip extends JToolTip {
52} 51}
53 52
54/** 53/**
55 * UI for multi line tool tip 54 * UI for multi line tool tip.
56 */ 55 */
57class MultiLineToolTipUI extends BasicToolTipUI { 56class MultiLineToolTipUI extends BasicToolTipUI {
58
59 static MultiLineToolTipUI sharedInstance = new MultiLineToolTipUI(); 57 static MultiLineToolTipUI sharedInstance = new MultiLineToolTipUI();
60 Font smallFont; 58 Font smallFont;
61 static JToolTip tip; 59 static JToolTip tip;
@@ -67,7 +65,7 @@ class MultiLineToolTipUI extends BasicToolTipUI {
67 return sharedInstance; 65 return sharedInstance;
68 } 66 }
69 67
70 public MultiLineToolTipUI() { 68 MultiLineToolTipUI() {
71 super(); 69 super();
72 } 70 }
73 71
@@ -93,7 +91,11 @@ class MultiLineToolTipUI extends BasicToolTipUI {
93 91
94 public Dimension getPreferredSize(JComponent c) { 92 public Dimension getPreferredSize(JComponent c) {
95 String tipText = ((JToolTip) c).getTipText(); 93 String tipText = ((JToolTip) c).getTipText();
96 if (tipText == null) return new Dimension(0, 0); 94
95 if (tipText == null) {
96 return new Dimension(0, 0);
97 }
98
97 textArea = new JTextArea(tipText); 99 textArea = new JTextArea(tipText);
98 rendererPane.removeAll(); 100 rendererPane.removeAll();
99 rendererPane.add(textArea); 101 rendererPane.add(textArea);
@@ -112,8 +114,9 @@ class MultiLineToolTipUI extends BasicToolTipUI {
112 d.width = width; 114 d.width = width;
113 d.height++; 115 d.height++;
114 textArea.setSize(d); 116 textArea.setSize(d);
115 } else 117 } else {
116 textArea.setLineWrap(false); 118 textArea.setLineWrap(false);
119 }
117 120
118 Dimension dim = textArea.getPreferredSize(); 121 Dimension dim = textArea.getPreferredSize();
119 122
@@ -129,4 +132,4 @@ class MultiLineToolTipUI extends BasicToolTipUI {
129 public Dimension getMaximumSize(JComponent c) { 132 public Dimension getMaximumSize(JComponent c) {
130 return getPreferredSize(c); 133 return getPreferredSize(c);
131 } 134 }
132} \ No newline at end of file 135}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java
index eeb52ccf..24a69b65 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java
@@ -12,7 +12,14 @@ import java.util.Map;
12import java.util.stream.Collectors; 12import java.util.stream.Collectors;
13import java.util.stream.IntStream; 13import java.util.stream.IntStream;
14 14
15import javax.swing.*; 15import javax.swing.ButtonGroup;
16import javax.swing.JFileChooser;
17import javax.swing.JMenu;
18import javax.swing.JMenuBar;
19import javax.swing.JMenuItem;
20import javax.swing.JOptionPane;
21import javax.swing.JRadioButtonMenuItem;
22import javax.swing.KeyStroke;
16 23
17import cuchaz.enigma.gui.ConnectionState; 24import cuchaz.enigma.gui.ConnectionState;
18import cuchaz.enigma.gui.Gui; 25import cuchaz.enigma.gui.Gui;
@@ -20,7 +27,13 @@ import cuchaz.enigma.gui.config.Decompiler;
20import cuchaz.enigma.gui.config.LookAndFeel; 27import cuchaz.enigma.gui.config.LookAndFeel;
21import cuchaz.enigma.gui.config.NetConfig; 28import cuchaz.enigma.gui.config.NetConfig;
22import cuchaz.enigma.gui.config.UiConfig; 29import cuchaz.enigma.gui.config.UiConfig;
23import cuchaz.enigma.gui.dialog.*; 30import cuchaz.enigma.gui.dialog.AboutDialog;
31import cuchaz.enigma.gui.dialog.ChangeDialog;
32import cuchaz.enigma.gui.dialog.ConnectToServerDialog;
33import cuchaz.enigma.gui.dialog.CreateServerDialog;
34import cuchaz.enigma.gui.dialog.FontDialog;
35import cuchaz.enigma.gui.dialog.SearchDialog;
36import cuchaz.enigma.gui.dialog.StatsDialog;
24import cuchaz.enigma.gui.util.GuiUtil; 37import cuchaz.enigma.gui.util.GuiUtil;
25import cuchaz.enigma.gui.util.LanguageUtil; 38import cuchaz.enigma.gui.util.LanguageUtil;
26import cuchaz.enigma.gui.util.ScaleUtil; 39import cuchaz.enigma.gui.util.ScaleUtil;
@@ -29,7 +42,6 @@ import cuchaz.enigma.utils.I18n;
29import cuchaz.enigma.utils.Pair; 42import cuchaz.enigma.utils.Pair;
30 43
31public class MenuBar { 44public class MenuBar {
32
33 private final JMenu fileMenu = new JMenu(); 45 private final JMenu fileMenu = new JMenu();
34 private final JMenuItem jarOpenItem = new JMenuItem(); 46 private final JMenuItem jarOpenItem = new JMenuItem();
35 private final JMenuItem jarCloseItem = new JMenuItem(); 47 private final JMenuItem jarCloseItem = new JMenuItem();
@@ -221,13 +233,16 @@ public class MenuBar {
221 } 233 }
222 234
223 File file = d.getSelectedFile(); 235 File file = d.getSelectedFile();
236
224 // checks if the file name is not empty 237 // checks if the file name is not empty
225 if (file != null) { 238 if (file != null) {
226 Path path = file.toPath(); 239 Path path = file.toPath();
240
227 // checks if the file name corresponds to an existing file 241 // checks if the file name corresponds to an existing file
228 if (Files.exists(path)) { 242 if (Files.exists(path)) {
229 this.gui.getController().openJar(path); 243 this.gui.getController().openJar(path);
230 } 244 }
245
231 UiConfig.setLastSelectedDir(d.getCurrentDirectory().getAbsolutePath()); 246 UiConfig.setLastSelectedDir(d.getCurrentDirectory().getAbsolutePath());
232 } 247 }
233 } 248 }
@@ -241,8 +256,10 @@ public class MenuBar {
241 this.gui.showDiscardDiag((response -> { 256 this.gui.showDiscardDiag((response -> {
242 if (response == JOptionPane.YES_OPTION) { 257 if (response == JOptionPane.YES_OPTION) {
243 this.gui.saveMapping().thenRun(then); 258 this.gui.saveMapping().thenRun(then);
244 } else if (response == JOptionPane.NO_OPTION) 259 } else if (response == JOptionPane.NO_OPTION) {
245 then.run(); 260 then.run();
261 }
262
246 return null; 263 return null;
247 }), I18n.translate("prompt.close.save"), I18n.translate("prompt.close.discard"), I18n.translate("prompt.cancel")); 264 }), I18n.translate("prompt.close.save"), I18n.translate("prompt.close.discard"), I18n.translate("prompt.cancel"));
248 } else { 265 } else {
@@ -264,6 +281,7 @@ public class MenuBar {
264 281
265 private void onExportSourceClicked() { 282 private void onExportSourceClicked() {
266 this.gui.exportSourceFileChooser.setCurrentDirectory(new File(UiConfig.getLastSelectedDir())); 283 this.gui.exportSourceFileChooser.setCurrentDirectory(new File(UiConfig.getLastSelectedDir()));
284
267 if (this.gui.exportSourceFileChooser.showSaveDialog(this.gui.getFrame()) == JFileChooser.APPROVE_OPTION) { 285 if (this.gui.exportSourceFileChooser.showSaveDialog(this.gui.getFrame()) == JFileChooser.APPROVE_OPTION) {
268 UiConfig.setLastSelectedDir(this.gui.exportSourceFileChooser.getCurrentDirectory().toString()); 286 UiConfig.setLastSelectedDir(this.gui.exportSourceFileChooser.getCurrentDirectory().toString());
269 this.gui.getController().exportSource(this.gui.exportSourceFileChooser.getSelectedFile().toPath()); 287 this.gui.getController().exportSource(this.gui.exportSourceFileChooser.getSelectedFile().toPath());
@@ -287,29 +305,35 @@ public class MenuBar {
287 } 305 }
288 306
289 private void onCustomScaleClicked() { 307 private void onCustomScaleClicked() {
290 String answer = (String) JOptionPane.showInputDialog(this.gui.getFrame(), I18n.translate("menu.view.scale.custom.title"), I18n.translate("menu.view.scale.custom.title"), 308 String answer = (String) JOptionPane.showInputDialog(this.gui.getFrame(), I18n.translate("menu.view.scale.custom.title"), I18n.translate("menu.view.scale.custom.title"), JOptionPane.QUESTION_MESSAGE, null, null, Float.toString(UiConfig.getScaleFactor() * 100));
291 JOptionPane.QUESTION_MESSAGE, null, null, Float.toString(UiConfig.getScaleFactor() * 100)); 309
292 if (answer == null) return; 310 if (answer == null) {
311 return;
312 }
313
293 float newScale = 1.0f; 314 float newScale = 1.0f;
315
294 try { 316 try {
295 newScale = Float.parseFloat(answer) / 100f; 317 newScale = Float.parseFloat(answer) / 100f;
296 } catch (NumberFormatException ignored) { 318 } catch (NumberFormatException ignored) {
319 // ignored
297 } 320 }
321
298 ScaleUtil.setScaleFactor(newScale); 322 ScaleUtil.setScaleFactor(newScale);
299 ChangeDialog.show(this.gui.getFrame()); 323 ChangeDialog.show(this.gui.getFrame());
300 } 324 }
301 325
302 private void onFontClicked(Gui gui) { 326 private void onFontClicked(Gui gui) {
303// FontDialog fd = new FontDialog(gui.getFrame(), "Choose Font", true); 327 // FontDialog fd = new FontDialog(gui.getFrame(), "Choose Font", true);
304// fd.setLocationRelativeTo(gui.getFrame()); 328 // fd.setLocationRelativeTo(gui.getFrame());
305// fd.setSelectedFont(UiConfig.getEditorFont()); 329 // fd.setSelectedFont(UiConfig.getEditorFont());
306// fd.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 330 // fd.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
307// fd.setVisible(true); 331 // fd.setVisible(true);
308// 332 //
309// if (!fd.isCancelSelected()) { 333 // if (!fd.isCancelSelected()) {
310// UiConfig.setEditorFont(fd.getSelectedFont()); 334 // UiConfig.setEditorFont(fd.getSelectedFont());
311// UiConfig.save(); 335 // UiConfig.save();
312// } 336 // }
313 FontDialog.display(gui.getFrame()); 337 FontDialog.display(gui.getFrame());
314 } 338 }
315 339
@@ -324,11 +348,15 @@ public class MenuBar {
324 this.gui.getController().disconnectIfConnected(null); 348 this.gui.getController().disconnectIfConnected(null);
325 return; 349 return;
326 } 350 }
351
327 ConnectToServerDialog.Result result = ConnectToServerDialog.show(this.gui.getFrame()); 352 ConnectToServerDialog.Result result = ConnectToServerDialog.show(this.gui.getFrame());
353
328 if (result == null) { 354 if (result == null) {
329 return; 355 return;
330 } 356 }
357
331 this.gui.getController().disconnectIfConnected(null); 358 this.gui.getController().disconnectIfConnected(null);
359
332 try { 360 try {
333 this.gui.getController().createClient(result.getUsername(), result.getAddress().address, result.getAddress().port, result.getPassword()); 361 this.gui.getController().createClient(result.getUsername(), result.getAddress().address, result.getAddress().port, result.getPassword());
334 NetConfig.setUsername(result.getUsername()); 362 NetConfig.setUsername(result.getUsername());
@@ -339,6 +367,7 @@ public class MenuBar {
339 JOptionPane.showMessageDialog(this.gui.getFrame(), e.toString(), I18n.translate("menu.collab.connect.error"), JOptionPane.ERROR_MESSAGE); 367 JOptionPane.showMessageDialog(this.gui.getFrame(), e.toString(), I18n.translate("menu.collab.connect.error"), JOptionPane.ERROR_MESSAGE);
340 this.gui.getController().disconnectIfConnected(null); 368 this.gui.getController().disconnectIfConnected(null);
341 } 369 }
370
342 Arrays.fill(result.getPassword(), (char) 0); 371 Arrays.fill(result.getPassword(), (char) 0);
343 } 372 }
344 373
@@ -347,11 +376,15 @@ public class MenuBar {
347 this.gui.getController().disconnectIfConnected(null); 376 this.gui.getController().disconnectIfConnected(null);
348 return; 377 return;
349 } 378 }
379
350 CreateServerDialog.Result result = CreateServerDialog.show(this.gui.getFrame()); 380 CreateServerDialog.Result result = CreateServerDialog.show(this.gui.getFrame());
381
351 if (result == null) { 382 if (result == null) {
352 return; 383 return;
353 } 384 }
385
354 this.gui.getController().disconnectIfConnected(null); 386 this.gui.getController().disconnectIfConnected(null);
387
355 try { 388 try {
356 this.gui.getController().createServer(result.getPort(), result.getPassword()); 389 this.gui.getController().createServer(result.getPort(), result.getPassword());
357 NetConfig.setServerPort(result.getPort()); 390 NetConfig.setServerPort(result.getPort());
@@ -373,6 +406,7 @@ public class MenuBar {
373 JMenuItem item = new JMenuItem(I18n.translate("mapping_format." + format.name().toLowerCase(Locale.ROOT))); 406 JMenuItem item = new JMenuItem(I18n.translate("mapping_format." + format.name().toLowerCase(Locale.ROOT)));
374 item.addActionListener(event -> { 407 item.addActionListener(event -> {
375 gui.enigmaMappingsFileChooser.setCurrentDirectory(new File(UiConfig.getLastSelectedDir())); 408 gui.enigmaMappingsFileChooser.setCurrentDirectory(new File(UiConfig.getLastSelectedDir()));
409
376 if (gui.enigmaMappingsFileChooser.showOpenDialog(gui.getFrame()) == JFileChooser.APPROVE_OPTION) { 410 if (gui.enigmaMappingsFileChooser.showOpenDialog(gui.getFrame()) == JFileChooser.APPROVE_OPTION) {
377 File selectedFile = gui.enigmaMappingsFileChooser.getSelectedFile(); 411 File selectedFile = gui.enigmaMappingsFileChooser.getSelectedFile();
378 gui.getController().openMappings(format, selectedFile.toPath()); 412 gui.getController().openMappings(format, selectedFile.toPath());
@@ -411,9 +445,11 @@ public class MenuBar {
411 for (Decompiler decompiler : Decompiler.values()) { 445 for (Decompiler decompiler : Decompiler.values()) {
412 JRadioButtonMenuItem decompilerButton = new JRadioButtonMenuItem(decompiler.name); 446 JRadioButtonMenuItem decompilerButton = new JRadioButtonMenuItem(decompiler.name);
413 decompilerGroup.add(decompilerButton); 447 decompilerGroup.add(decompilerButton);
448
414 if (decompiler.equals(UiConfig.getDecompiler())) { 449 if (decompiler.equals(UiConfig.getDecompiler())) {
415 decompilerButton.setSelected(true); 450 decompilerButton.setSelected(true);
416 } 451 }
452
417 decompilerButton.addActionListener(event -> { 453 decompilerButton.addActionListener(event -> {
418 gui.getController().setDecompiler(decompiler.service); 454 gui.getController().setDecompiler(decompiler.service);
419 455
@@ -426,12 +462,15 @@ public class MenuBar {
426 462
427 private static void prepareThemesMenu(JMenu themesMenu, Gui gui) { 463 private static void prepareThemesMenu(JMenu themesMenu, Gui gui) {
428 ButtonGroup themeGroup = new ButtonGroup(); 464 ButtonGroup themeGroup = new ButtonGroup();
465
429 for (LookAndFeel lookAndFeel : LookAndFeel.values()) { 466 for (LookAndFeel lookAndFeel : LookAndFeel.values()) {
430 JRadioButtonMenuItem themeButton = new JRadioButtonMenuItem(I18n.translate("menu.view.themes." + lookAndFeel.name().toLowerCase(Locale.ROOT))); 467 JRadioButtonMenuItem themeButton = new JRadioButtonMenuItem(I18n.translate("menu.view.themes." + lookAndFeel.name().toLowerCase(Locale.ROOT)));
431 themeGroup.add(themeButton); 468 themeGroup.add(themeButton);
469
432 if (lookAndFeel.equals(UiConfig.getLookAndFeel())) { 470 if (lookAndFeel.equals(UiConfig.getLookAndFeel())) {
433 themeButton.setSelected(true); 471 themeButton.setSelected(true);
434 } 472 }
473
435 themeButton.addActionListener(_e -> { 474 themeButton.addActionListener(_e -> {
436 UiConfig.setLookAndFeel(lookAndFeel); 475 UiConfig.setLookAndFeel(lookAndFeel);
437 UiConfig.save(); 476 UiConfig.save();
@@ -443,12 +482,15 @@ public class MenuBar {
443 482
444 private static void prepareLanguagesMenu(JMenu languagesMenu) { 483 private static void prepareLanguagesMenu(JMenu languagesMenu) {
445 ButtonGroup languageGroup = new ButtonGroup(); 484 ButtonGroup languageGroup = new ButtonGroup();
485
446 for (String lang : I18n.getAvailableLanguages()) { 486 for (String lang : I18n.getAvailableLanguages()) {
447 JRadioButtonMenuItem languageButton = new JRadioButtonMenuItem(I18n.getLanguageName(lang)); 487 JRadioButtonMenuItem languageButton = new JRadioButtonMenuItem(I18n.getLanguageName(lang));
448 languageGroup.add(languageButton); 488 languageGroup.add(languageButton);
489
449 if (lang.equals(UiConfig.getLanguage())) { 490 if (lang.equals(UiConfig.getLanguage())) {
450 languageButton.setSelected(true); 491 languageButton.setSelected(true);
451 } 492 }
493
452 languageButton.addActionListener(event -> { 494 languageButton.addActionListener(event -> {
453 UiConfig.setLanguage(lang); 495 UiConfig.setLanguage(lang);
454 I18n.setLanguage(lang); 496 I18n.setLanguage(lang);
@@ -461,25 +503,25 @@ public class MenuBar {
461 503
462 private static void prepareScaleMenu(JMenu scaleMenu, Gui gui) { 504 private static void prepareScaleMenu(JMenu scaleMenu, Gui gui) {
463 ButtonGroup scaleGroup = new ButtonGroup(); 505 ButtonGroup scaleGroup = new ButtonGroup();
464 Map<Float, JRadioButtonMenuItem> scaleButtons = IntStream.of(100, 125, 150, 175, 200) 506 Map<Float, JRadioButtonMenuItem> scaleButtons = IntStream.of(100, 125, 150, 175, 200).mapToObj(scaleFactor -> {
465 .mapToObj(scaleFactor -> { 507 float realScaleFactor = scaleFactor / 100f;
466 float realScaleFactor = scaleFactor / 100f; 508 JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(String.format("%d%%", scaleFactor));
467 JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(String.format("%d%%", scaleFactor)); 509 menuItem.addActionListener(event -> ScaleUtil.setScaleFactor(realScaleFactor));
468 menuItem.addActionListener(event -> ScaleUtil.setScaleFactor(realScaleFactor)); 510 menuItem.addActionListener(event -> ChangeDialog.show(gui.getFrame()));
469 menuItem.addActionListener(event -> ChangeDialog.show(gui.getFrame())); 511 scaleGroup.add(menuItem);
470 scaleGroup.add(menuItem); 512 scaleMenu.add(menuItem);
471 scaleMenu.add(menuItem); 513 return new Pair<>(realScaleFactor, menuItem);
472 return new Pair<>(realScaleFactor, menuItem); 514 }).collect(Collectors.toMap(x -> x.a, x -> x.b));
473 })
474 .collect(Collectors.toMap(x -> x.a, x -> x.b));
475 515
476 JRadioButtonMenuItem currentScaleButton = scaleButtons.get(UiConfig.getScaleFactor()); 516 JRadioButtonMenuItem currentScaleButton = scaleButtons.get(UiConfig.getScaleFactor());
517
477 if (currentScaleButton != null) { 518 if (currentScaleButton != null) {
478 currentScaleButton.setSelected(true); 519 currentScaleButton.setSelected(true);
479 } 520 }
480 521
481 ScaleUtil.addListener((newScale, _oldScale) -> { 522 ScaleUtil.addListener((newScale, _oldScale) -> {
482 JRadioButtonMenuItem mi = scaleButtons.get(newScale); 523 JRadioButtonMenuItem mi = scaleButtons.get(newScale);
524
483 if (mi != null) { 525 if (mi != null) {
484 mi.setSelected(true); 526 mi.setSelected(true);
485 } else { 527 } else {
@@ -487,5 +529,4 @@ public class MenuBar {
487 } 529 }
488 }); 530 });
489 } 531 }
490
491} 532}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/StatusBar.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/StatusBar.java
index 0c667c00..48404a1c 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/StatusBar.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/StatusBar.java
@@ -54,7 +54,7 @@ public class StatusBar {
54 * 54 *
55 * @param message the message to display 55 * @param message the message to display
56 * @param timeout the timeout in milliseconds to wait until clearing the 56 * @param timeout the timeout in milliseconds to wait until clearing the
57 * message; if 0, the message is not automatically cleared 57 * message; if 0, the message is not automatically cleared
58 */ 58 */
59 public void showMessage(String message, int timeout) { 59 public void showMessage(String message, int timeout) {
60 this.timer.stop(); 60 this.timer.stop();
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatablePasswordField.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatablePasswordField.java
index 02e1bc39..4329cae0 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatablePasswordField.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatablePasswordField.java
@@ -14,7 +14,6 @@ import cuchaz.enigma.utils.validation.ParameterizedMessage;
14import cuchaz.enigma.utils.validation.Validatable; 14import cuchaz.enigma.utils.validation.Validatable;
15 15
16public class ValidatablePasswordField extends JPasswordField implements Validatable { 16public class ValidatablePasswordField extends JPasswordField implements Validatable {
17
18 private List<ParameterizedMessage> messages = new ArrayList<>(); 17 private List<ParameterizedMessage> messages = new ArrayList<>();
19 private String tooltipText = null; 18 private String tooltipText = null;
20 19
@@ -92,5 +91,4 @@ public class ValidatablePasswordField extends JPasswordField implements Validata
92 super.paint(g); 91 super.paint(g);
93 ValidatableUi.drawMarker(this, g, messages); 92 ValidatableUi.drawMarker(this, g, messages);
94 } 93 }
95
96} 94}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableTextArea.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableTextArea.java
index 7d1f8665..2d5e2295 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableTextArea.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableTextArea.java
@@ -14,7 +14,6 @@ import cuchaz.enigma.utils.validation.ParameterizedMessage;
14import cuchaz.enigma.utils.validation.Validatable; 14import cuchaz.enigma.utils.validation.Validatable;
15 15
16public class ValidatableTextArea extends JTextArea implements Validatable { 16public class ValidatableTextArea extends JTextArea implements Validatable {
17
18 private List<ParameterizedMessage> messages = new ArrayList<>(); 17 private List<ParameterizedMessage> messages = new ArrayList<>();
19 private String tooltipText = null; 18 private String tooltipText = null;
20 19
@@ -96,5 +95,4 @@ public class ValidatableTextArea extends JTextArea implements Validatable {
96 super.paint(g); 95 super.paint(g);
97 ValidatableUi.drawMarker(this, g, messages); 96 ValidatableUi.drawMarker(this, g, messages);
98 } 97 }
99
100} 98}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableTextField.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableTextField.java
index c114dc17..be658d59 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableTextField.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableTextField.java
@@ -14,7 +14,6 @@ import cuchaz.enigma.utils.validation.ParameterizedMessage;
14import cuchaz.enigma.utils.validation.Validatable; 14import cuchaz.enigma.utils.validation.Validatable;
15 15
16public class ValidatableTextField extends JTextField implements Validatable { 16public class ValidatableTextField extends JTextField implements Validatable {
17
18 private List<ParameterizedMessage> messages = new ArrayList<>(); 17 private List<ParameterizedMessage> messages = new ArrayList<>();
19 private String tooltipText = null; 18 private String tooltipText = null;
20 19
@@ -92,5 +91,4 @@ public class ValidatableTextField extends JTextField implements Validatable {
92 super.paint(g); 91 super.paint(g);
93 ValidatableUi.drawMarker(this, g, messages); 92 ValidatableUi.drawMarker(this, g, messages);
94 } 93 }
95
96} 94}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableUi.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableUi.java
index 5df63486..b8b8431b 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableUi.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableUi.java
@@ -13,26 +13,29 @@ import cuchaz.enigma.gui.util.ScaleUtil;
13import cuchaz.enigma.utils.validation.ParameterizedMessage; 13import cuchaz.enigma.utils.validation.ParameterizedMessage;
14 14
15public final class ValidatableUi { 15public final class ValidatableUi {
16
17 private ValidatableUi() { 16 private ValidatableUi() {
18 } 17 }
19 18
20 public static String getTooltipText(String tooltipText, List<ParameterizedMessage> messages) { 19 public static String getTooltipText(String tooltipText, List<ParameterizedMessage> messages) {
21 List<String> strings = new ArrayList<>(); 20 List<String> strings = new ArrayList<>();
21
22 if (tooltipText != null) { 22 if (tooltipText != null) {
23 strings.add(tooltipText); 23 strings.add(tooltipText);
24 } 24 }
25
25 if (!messages.isEmpty()) { 26 if (!messages.isEmpty()) {
26 strings.add("Error(s): "); 27 strings.add("Error(s): ");
27 28
28 messages.forEach(msg -> { 29 messages.forEach(msg -> {
29 strings.add(String.format(" - %s", msg.getText())); 30 strings.add(String.format(" - %s", msg.getText()));
30 String longDesc = msg.getLongText(); 31 String longDesc = msg.getLongText();
32
31 if (!longDesc.isEmpty()) { 33 if (!longDesc.isEmpty()) {
32 Arrays.stream(longDesc.split("\n")).map(s -> String.format(" %s", s)).forEach(strings::add); 34 Arrays.stream(longDesc.split("\n")).map(s -> String.format(" %s", s)).forEach(strings::add);
33 } 35 }
34 }); 36 });
35 } 37 }
38
36 if (strings.isEmpty()) { 39 if (strings.isEmpty()) {
37 return null; 40 return null;
38 } else { 41 } else {
@@ -49,11 +52,13 @@ public final class ValidatableUi {
49 messages.forEach(msg -> { 52 messages.forEach(msg -> {
50 strings.add(String.format(" - %s", msg.getText())); 53 strings.add(String.format(" - %s", msg.getText()));
51 String longDesc = msg.getLongText(); 54 String longDesc = msg.getLongText();
55
52 if (!longDesc.isEmpty()) { 56 if (!longDesc.isEmpty()) {
53 Arrays.stream(longDesc.split("\n")).map(s -> String.format(" %s", s)).forEach(strings::add); 57 Arrays.stream(longDesc.split("\n")).map(s -> String.format(" %s", s)).forEach(strings::add);
54 } 58 }
55 }); 59 });
56 } 60 }
61
57 if (strings.isEmpty()) { 62 if (strings.isEmpty()) {
58 return null; 63 return null;
59 } else { 64 } else {
@@ -63,6 +68,7 @@ public final class ValidatableUi {
63 68
64 public static void drawMarker(Component self, Graphics g, List<ParameterizedMessage> messages) { 69 public static void drawMarker(Component self, Graphics g, List<ParameterizedMessage> messages) {
65 Color color = ValidatableUi.getMarkerColor(messages); 70 Color color = ValidatableUi.getMarkerColor(messages);
71
66 if (color != null) { 72 if (color != null) {
67 g.setColor(color); 73 g.setColor(color);
68 int x1 = self.getWidth() - ScaleUtil.scale(8) - 1; 74 int x1 = self.getWidth() - ScaleUtil.scale(8) - 1;
@@ -75,33 +81,32 @@ public final class ValidatableUi {
75 81
76 @Nullable 82 @Nullable
77 public static Color getMarkerColor(List<ParameterizedMessage> messages) { 83 public static Color getMarkerColor(List<ParameterizedMessage> messages) {
78 int level = messages.stream() 84 int level = messages.stream().mapToInt(ValidatableUi::getMessageLevel).max().orElse(0);
79 .mapToInt(ValidatableUi::getMessageLevel)
80 .max().orElse(0);
81 85
82 switch (level) { 86 switch (level) {
83 case 0: 87 case 0:
84 return null; 88 return null;
85 case 1: 89 case 1:
86 return Color.BLUE; 90 return Color.BLUE;
87 case 2: 91 case 2:
88 return Color.ORANGE; 92 return Color.ORANGE;
89 case 3: 93 case 3:
90 return Color.RED; 94 return Color.RED;
91 } 95 }
96
92 throw new IllegalStateException("unreachable"); 97 throw new IllegalStateException("unreachable");
93 } 98 }
94 99
95 private static int getMessageLevel(ParameterizedMessage message) { 100 private static int getMessageLevel(ParameterizedMessage message) {
96 switch (message.message.type) { 101 switch (message.message.type) {
97 case INFO: 102 case INFO:
98 return 1; 103 return 1;
99 case WARNING: 104 case WARNING:
100 return 2; 105 return 2;
101 case ERROR: 106 case ERROR:
102 return 3; 107 return 3;
103 } 108 }
109
104 throw new IllegalStateException("unreachable"); 110 throw new IllegalStateException("unreachable");
105 } 111 }
106
107} 112}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/events/ConvertingTextFieldListener.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/events/ConvertingTextFieldListener.java
index 6e17fec1..d9ec95c2 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/events/ConvertingTextFieldListener.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/events/ConvertingTextFieldListener.java
@@ -3,7 +3,6 @@ package cuchaz.enigma.gui.events;
3import cuchaz.enigma.gui.elements.ConvertingTextField; 3import cuchaz.enigma.gui.elements.ConvertingTextField;
4 4
5public interface ConvertingTextFieldListener { 5public interface ConvertingTextFieldListener {
6
7 default void onStartEditing(ConvertingTextField field) { 6 default void onStartEditing(ConvertingTextField field) {
8 } 7 }
9 8
@@ -13,5 +12,4 @@ public interface ConvertingTextFieldListener {
13 12
14 default void onStopEditing(ConvertingTextField field, boolean abort) { 13 default void onStopEditing(ConvertingTextField field, boolean abort) {
15 } 14 }
16
17} 15}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/events/EditorActionListener.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/events/EditorActionListener.java
index 48c9ec4b..1651abf0 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/events/EditorActionListener.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/events/EditorActionListener.java
@@ -7,7 +7,6 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry;
7import cuchaz.enigma.translation.representation.entry.Entry; 7import cuchaz.enigma.translation.representation.entry.Entry;
8 8
9public interface EditorActionListener { 9public interface EditorActionListener {
10
11 default void onCursorReferenceChanged(EditorPanel editor, EntryReference<Entry<?>, Entry<?>> ref) { 10 default void onCursorReferenceChanged(EditorPanel editor, EntryReference<Entry<?>, Entry<?>> ref) {
12 } 11 }
13 12
@@ -16,5 +15,4 @@ public interface EditorActionListener {
16 15
17 default void onTitleChanged(EditorPanel editor, String title) { 16 default void onTitleChanged(EditorPanel editor, String title) {
18 } 17 }
19
20} 18}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/events/ThemeChangeListener.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/events/ThemeChangeListener.java
index 10d7ce1c..e2054b29 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/events/ThemeChangeListener.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/events/ThemeChangeListener.java
@@ -7,7 +7,5 @@ import cuchaz.enigma.gui.highlight.BoxHighlightPainter;
7import cuchaz.enigma.source.RenamableTokenType; 7import cuchaz.enigma.source.RenamableTokenType;
8 8
9public interface ThemeChangeListener { 9public interface ThemeChangeListener {
10
11 void onThemeChanged(LookAndFeel lookAndFeel, Map<RenamableTokenType, BoxHighlightPainter> boxHighlightPainters); 10 void onThemeChanged(LookAndFeel lookAndFeel, Map<RenamableTokenType, BoxHighlightPainter> boxHighlightPainters);
12
13} 11}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/highlight/BoxHighlightPainter.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/highlight/BoxHighlightPainter.java
index 2d8d76a7..a97b3779 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/highlight/BoxHighlightPainter.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/highlight/BoxHighlightPainter.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 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 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.gui.highlight; 12package cuchaz.enigma.gui.highlight;
13 13
@@ -67,5 +67,4 @@ public class BoxHighlightPainter implements Highlighter.HighlightPainter {
67 g.setColor(this.borderColor); 67 g.setColor(this.borderColor);
68 g.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4); 68 g.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4);
69 } 69 }
70
71} 70}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/highlight/SelectionHighlightPainter.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/highlight/SelectionHighlightPainter.java
index 22d64201..a807802d 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/highlight/SelectionHighlightPainter.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/highlight/SelectionHighlightPainter.java
@@ -1,17 +1,21 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 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 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.gui.highlight; 12package cuchaz.enigma.gui.highlight;
13 13
14import java.awt.*; 14import java.awt.BasicStroke;
15import java.awt.Graphics;
16import java.awt.Graphics2D;
17import java.awt.Rectangle;
18import java.awt.Shape;
15 19
16import javax.swing.text.Highlighter; 20import javax.swing.text.Highlighter;
17import javax.swing.text.JTextComponent; 21import javax.swing.text.JTextComponent;
@@ -19,7 +23,6 @@ import javax.swing.text.JTextComponent;
19import cuchaz.enigma.gui.config.UiConfig; 23import cuchaz.enigma.gui.config.UiConfig;
20 24
21public class SelectionHighlightPainter implements Highlighter.HighlightPainter { 25public class SelectionHighlightPainter implements Highlighter.HighlightPainter {
22
23 public static final SelectionHighlightPainter INSTANCE = new SelectionHighlightPainter(); 26 public static final SelectionHighlightPainter INSTANCE = new SelectionHighlightPainter();
24 27
25 @Override 28 @Override
@@ -31,5 +34,4 @@ public class SelectionHighlightPainter implements Highlighter.HighlightPainter {
31 g2d.setStroke(new BasicStroke(2.0f)); 34 g2d.setStroke(new BasicStroke(2.0f));
32 g2d.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4); 35 g2d.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4);
33 } 36 }
34
35} 37}
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
index 898529a4..1dcdeabf 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/newabstraction/EntryValidation.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/newabstraction/EntryValidation.java
@@ -6,17 +6,16 @@ import cuchaz.enigma.utils.validation.Message;
6import cuchaz.enigma.utils.validation.ValidationContext; 6import cuchaz.enigma.utils.validation.ValidationContext;
7 7
8public class EntryValidation { 8public class EntryValidation {
9
10 public static boolean validateJavadoc(ValidationContext vc, String javadoc) { 9 public static boolean validateJavadoc(ValidationContext vc, String javadoc) {
11 if (javadoc.contains("*/")) { 10 if (javadoc.contains("*/")) {
12 vc.raise(Message.ILLEGAL_DOC_COMMENT_END); 11 vc.raise(Message.ILLEGAL_DOC_COMMENT_END);
13 return false; 12 return false;
14 } 13 }
14
15 return true; 15 return true;
16 } 16 }
17 17
18 public static boolean validateRename(ValidationContext vc, EnigmaProject p, Entry<?> entry, String newName) { 18 public static boolean validateRename(ValidationContext vc, EnigmaProject p, Entry<?> entry, String newName) {
19 return p.getMapper().getValidator().validateRename(vc, entry, newName); 19 return p.getMapper().getValidator().validateRename(vc, entry, newName);
20 } 20 }
21
22} 21}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java
index 922f8f24..f931a93f 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java
@@ -1,22 +1,21 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 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 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.gui.node; 12package cuchaz.enigma.gui.node;
13 13
14import cuchaz.enigma.translation.representation.entry.ClassEntry;
15
16import javax.swing.tree.DefaultMutableTreeNode; 14import javax.swing.tree.DefaultMutableTreeNode;
17 15
18public class ClassSelectorClassNode extends DefaultMutableTreeNode { 16import cuchaz.enigma.translation.representation.entry.ClassEntry;
19 17
18public class ClassSelectorClassNode extends DefaultMutableTreeNode {
20 private final ClassEntry obfEntry; 19 private final ClassEntry obfEntry;
21 private ClassEntry classEntry; 20 private ClassEntry classEntry;
22 21
@@ -57,12 +56,17 @@ public class ClassSelectorClassNode extends DefaultMutableTreeNode {
57 @Override 56 @Override
58 public void setUserObject(Object userObject) { 57 public void setUserObject(Object userObject) {
59 String packageName = ""; 58 String packageName = "";
60 if (classEntry.getPackageName() != null) 59
60 if (classEntry.getPackageName() != null) {
61 packageName = classEntry.getPackageName() + "/"; 61 packageName = classEntry.getPackageName() + "/";
62 if (userObject instanceof String) 62 }
63
64 if (userObject instanceof String) {
63 this.classEntry = new ClassEntry(packageName + userObject); 65 this.classEntry = new ClassEntry(packageName + userObject);
64 else if (userObject instanceof ClassEntry) 66 } else if (userObject instanceof ClassEntry) {
65 this.classEntry = (ClassEntry) userObject; 67 this.classEntry = (ClassEntry) userObject;
68 }
69
66 super.setUserObject(classEntry); 70 super.setUserObject(classEntry);
67 } 71 }
68 72
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java
index c1c7d387..dfcbd8c1 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java
@@ -1,22 +1,21 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 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 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.gui.node; 12package cuchaz.enigma.gui.node;
13 13
14import cuchaz.enigma.translation.representation.entry.ClassEntry;
15
16import javax.swing.tree.DefaultMutableTreeNode; 14import javax.swing.tree.DefaultMutableTreeNode;
17 15
18public class ClassSelectorPackageNode extends DefaultMutableTreeNode { 16import cuchaz.enigma.translation.representation.entry.ClassEntry;
19 17
18public class ClassSelectorPackageNode extends DefaultMutableTreeNode {
20 private String packageName; 19 private String packageName;
21 20
22 public ClassSelectorPackageNode(String packageName) { 21 public ClassSelectorPackageNode(String packageName) {
@@ -34,8 +33,10 @@ public class ClassSelectorPackageNode extends DefaultMutableTreeNode {
34 33
35 @Override 34 @Override
36 public void setUserObject(Object userObject) { 35 public void setUserObject(Object userObject) {
37 if (userObject instanceof String) 36 if (userObject instanceof String) {
38 this.packageName = (String) userObject; 37 this.packageName = (String) userObject;
38 }
39
39 super.setUserObject(userObject); 40 super.setUserObject(userObject);
40 } 41 }
41 42
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ClosableTabTitlePane.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ClosableTabTitlePane.java
index fe5c8578..dca714dd 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ClosableTabTitlePane.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ClosableTabTitlePane.java
@@ -9,12 +9,17 @@ import java.awt.event.MouseEvent;
9 9
10import javax.accessibility.AccessibleContext; 10import javax.accessibility.AccessibleContext;
11import javax.annotation.Nullable; 11import javax.annotation.Nullable;
12import javax.swing.*; 12import javax.swing.JButton;
13import javax.swing.JComponent;
14import javax.swing.JLabel;
15import javax.swing.JPanel;
16import javax.swing.JTabbedPane;
17import javax.swing.SwingUtilities;
18import javax.swing.UIManager;
13import javax.swing.border.EmptyBorder; 19import javax.swing.border.EmptyBorder;
14import javax.swing.event.ChangeListener; 20import javax.swing.event.ChangeListener;
15 21
16public class ClosableTabTitlePane { 22public class ClosableTabTitlePane {
17
18 private final JPanel ui; 23 private final JPanel ui;
19 private final JButton closeButton; 24 private final JButton closeButton;
20 private final JLabel label; 25 private final JLabel label;
@@ -66,19 +71,7 @@ public class ClosableTabTitlePane {
66 if (parent != null) { 71 if (parent != null) {
67 Point pt = new Point(e.getXOnScreen(), e.getYOnScreen()); 72 Point pt = new Point(e.getXOnScreen(), e.getYOnScreen());
68 SwingUtilities.convertPointFromScreen(pt, parent); 73 SwingUtilities.convertPointFromScreen(pt, parent);
69 MouseEvent e1 = new MouseEvent( 74 MouseEvent e1 = new MouseEvent(parent, e.getID(), e.getWhen(), e.getModifiersEx(), (int) pt.getX(), (int) pt.getY(), e.getXOnScreen(), e.getYOnScreen(), e.getClickCount(), e.isPopupTrigger(), e.getButton());
70 parent,
71 e.getID(),
72 e.getWhen(),
73 e.getModifiersEx(),
74 (int) pt.getX(),
75 (int) pt.getY(),
76 e.getXOnScreen(),
77 e.getYOnScreen(),
78 e.getClickCount(),
79 e.isPopupTrigger(),
80 e.getButton()
81 );
82 parent.dispatchEvent(e1); 75 parent.dispatchEvent(e1);
83 } 76 }
84 } 77 }
@@ -91,11 +84,13 @@ public class ClosableTabTitlePane {
91 if (this.parent != null) { 84 if (this.parent != null) {
92 pane.removeChangeListener(cachedChangeListener); 85 pane.removeChangeListener(cachedChangeListener);
93 } 86 }
87
94 if (pane != null) { 88 if (pane != null) {
95 updateState(pane); 89 updateState(pane);
96 cachedChangeListener = e -> updateState(pane); 90 cachedChangeListener = e -> updateState(pane);
97 pane.addChangeListener(cachedChangeListener); 91 pane.addChangeListener(cachedChangeListener);
98 } 92 }
93
99 this.parent = pane; 94 this.parent = pane;
100 } 95 }
101 96
@@ -123,11 +118,12 @@ public class ClosableTabTitlePane {
123 public static ClosableTabTitlePane byUi(Component c) { 118 public static ClosableTabTitlePane byUi(Component c) {
124 if (c instanceof JComponent) { 119 if (c instanceof JComponent) {
125 Object prop = ((JComponent) c).getClientProperty(ClosableTabTitlePane.class); 120 Object prop = ((JComponent) c).getClientProperty(ClosableTabTitlePane.class);
121
126 if (prop instanceof ClosableTabTitlePane) { 122 if (prop instanceof ClosableTabTitlePane) {
127 return (ClosableTabTitlePane) prop; 123 return (ClosableTabTitlePane) prop;
128 } 124 }
129 } 125 }
126
130 return null; 127 return null;
131 } 128 }
132
133} 129}
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 10fc5e1a..5d1d0f2b 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
@@ -15,7 +15,6 @@ import cuchaz.enigma.gui.util.GuiUtil;
15import cuchaz.enigma.utils.I18n; 15import cuchaz.enigma.utils.I18n;
16 16
17public class DeobfPanel extends JPanel { 17public class DeobfPanel extends JPanel {
18
19 public final ClassSelector deobfClasses; 18 public final ClassSelector deobfClasses;
20 private final JLabel title = new JLabel(); 19 private final JLabel title = new JLabel();
21 20
@@ -44,6 +43,7 @@ public class DeobfPanel extends JPanel {
44 if (SwingUtilities.isRightMouseButton(e)) { 43 if (SwingUtilities.isRightMouseButton(e)) {
45 deobfClasses.setSelectionRow(deobfClasses.getClosestRowForLocation(e.getX(), e.getY())); 44 deobfClasses.setSelectionRow(deobfClasses.getClosestRowForLocation(e.getX(), e.getY()));
46 int i = deobfClasses.getRowForPath(deobfClasses.getSelectionPath()); 45 int i = deobfClasses.getRowForPath(deobfClasses.getSelectionPath());
46
47 if (i != -1) { 47 if (i != -1) {
48 deobfPanelPopupMenu.show(deobfClasses, e.getX(), e.getY()); 48 deobfPanelPopupMenu.show(deobfClasses, e.getX(), e.getY());
49 } 49 }
@@ -54,5 +54,4 @@ public class DeobfPanel extends JPanel {
54 this.title.setText(I18n.translate(gui.isSingleClassTree() ? "info_panel.classes" : "info_panel.classes.deobfuscated")); 54 this.title.setText(I18n.translate(gui.isSingleClassTree() ? "info_panel.classes" : "info_panel.classes.deobfuscated"));
55 this.deobfPanelPopupMenu.retranslateUi(); 55 this.deobfPanelPopupMenu.retranslateUi();
56 } 56 }
57
58} 57}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/EditorPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/EditorPanel.java
index f4b190bc..cb74ceca 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/EditorPanel.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/EditorPanel.java
@@ -1,14 +1,35 @@
1package cuchaz.enigma.gui.panels; 1package cuchaz.enigma.gui.panels;
2 2
3import java.awt.*; 3import java.awt.Color;
4import java.awt.event.*; 4import java.awt.Component;
5import java.awt.Font;
6import java.awt.GridBagConstraints;
7import java.awt.GridBagLayout;
8import java.awt.GridLayout;
9import java.awt.Rectangle;
10import java.awt.event.ActionEvent;
11import java.awt.event.ActionListener;
12import java.awt.event.KeyAdapter;
13import java.awt.event.KeyEvent;
14import java.awt.event.MouseAdapter;
15import java.awt.event.MouseEvent;
5import java.util.ArrayList; 16import java.util.ArrayList;
6import java.util.Collection; 17import java.util.Collection;
7import java.util.List; 18import java.util.List;
8import java.util.Map; 19import java.util.Map;
9 20
10import javax.annotation.Nullable; 21import javax.annotation.Nullable;
11import javax.swing.*; 22import javax.swing.JButton;
23import javax.swing.JComponent;
24import javax.swing.JEditorPane;
25import javax.swing.JLabel;
26import javax.swing.JPanel;
27import javax.swing.JProgressBar;
28import javax.swing.JScrollPane;
29import javax.swing.JSeparator;
30import javax.swing.JTextArea;
31import javax.swing.SwingUtilities;
32import javax.swing.Timer;
12import javax.swing.text.BadLocationException; 33import javax.swing.text.BadLocationException;
13import javax.swing.text.Document; 34import javax.swing.text.Document;
14import javax.swing.text.Highlighter.HighlightPainter; 35import javax.swing.text.Highlighter.HighlightPainter;
@@ -46,7 +67,6 @@ import cuchaz.enigma.utils.I18n;
46import cuchaz.enigma.utils.Result; 67import cuchaz.enigma.utils.Result;
47 68
48public class EditorPanel { 69public class EditorPanel {
49
50 private final JPanel ui = new JPanel(); 70 private final JPanel ui = new JPanel();
51 private final JEditorPane editor = new JEditorPane(); 71 private final JEditorPane editor = new JEditorPane();
52 private final JScrollPane editorScrollPane = new JScrollPane(this.editor); 72 private final JScrollPane editorScrollPane = new JScrollPane(this.editor);
@@ -123,18 +143,19 @@ public class EditorPanel {
123 @Override 143 @Override
124 public void mouseReleased(MouseEvent e) { 144 public void mouseReleased(MouseEvent e) {
125 switch (e.getButton()) { 145 switch (e.getButton()) {
126 case MouseEvent.BUTTON3: // Right click 146 case MouseEvent.BUTTON3: // Right click
127 EditorPanel.this.editor.setCaretPosition(EditorPanel.this.editor.viewToModel(e.getPoint())); 147 EditorPanel.this.editor.setCaretPosition(EditorPanel.this.editor.viewToModel(e.getPoint()));
128 break; 148 break;
129 149
130 case 4: // Back navigation 150 case 4: // Back navigation
131 gui.getController().openPreviousReference(); 151 gui.getController().openPreviousReference();
132 break; 152 break;
133 153
134 case 5: // Forward navigation 154 case 5: // Forward navigation
135 gui.getController().openNextReference(); 155 gui.getController().openNextReference();
136 break; 156 break;
137 } 157 }
158
138 EditorPanel.this.mouseIsPressed = false; 159 EditorPanel.this.mouseIsPressed = false;
139 } 160 }
140 }); 161 });
@@ -143,31 +164,36 @@ public class EditorPanel {
143 public void keyPressed(KeyEvent event) { 164 public void keyPressed(KeyEvent event) {
144 if (event.isControlDown()) { 165 if (event.isControlDown()) {
145 EditorPanel.this.shouldNavigateOnClick = false; 166 EditorPanel.this.shouldNavigateOnClick = false;
146 if (EditorPanel.this.popupMenu.handleKeyEvent(event)) return; 167
168 if (EditorPanel.this.popupMenu.handleKeyEvent(event)) {
169 return;
170 }
171
147 switch (event.getKeyCode()) { 172 switch (event.getKeyCode()) {
148 case KeyEvent.VK_F5: 173 case KeyEvent.VK_F5:
149 if (EditorPanel.this.classHandle != null) { 174 if (EditorPanel.this.classHandle != null) {
150 EditorPanel.this.classHandle.invalidate(); 175 EditorPanel.this.classHandle.invalidate();
151 } 176 }
152 break; 177
153 178 break;
154 case KeyEvent.VK_F: 179
155 // prevent navigating on click when quick find activated 180 case KeyEvent.VK_F:
156 break; 181 // prevent navigating on click when quick find activated
157 182 break;
158 case KeyEvent.VK_ADD: 183
159 case KeyEvent.VK_EQUALS: 184 case KeyEvent.VK_ADD:
160 case KeyEvent.VK_PLUS: 185 case KeyEvent.VK_EQUALS:
161 offsetEditorZoom(2); 186 case KeyEvent.VK_PLUS:
162 break; 187 offsetEditorZoom(2);
163 case KeyEvent.VK_SUBTRACT: 188 break;
164 case KeyEvent.VK_MINUS: 189 case KeyEvent.VK_SUBTRACT:
165 offsetEditorZoom(-2); 190 case KeyEvent.VK_MINUS:
166 break; 191 offsetEditorZoom(-2);
167 192 break;
168 default: 193
169 EditorPanel.this.shouldNavigateOnClick = true; // CTRL 194 default:
170 break; 195 EditorPanel.this.shouldNavigateOnClick = true; // CTRL
196 break;
171 } 197 }
172 } 198 }
173 } 199 }
@@ -175,8 +201,14 @@ public class EditorPanel {
175 @Override 201 @Override
176 public void keyTyped(KeyEvent event) { 202 public void keyTyped(KeyEvent event) {
177 EntryReference<Entry<?>, Entry<?>> ref = EditorPanel.this.getCursorReference(); 203 EntryReference<Entry<?>, Entry<?>> ref = EditorPanel.this.getCursorReference();
178 if (ref == null) return; 204
179 if (!EditorPanel.this.controller.project.isRenamable(ref)) return; 205 if (ref == null) {
206 return;
207 }
208
209 if (!EditorPanel.this.controller.project.isRenamable(ref)) {
210 return;
211 }
180 212
181 if (!event.isControlDown() && !event.isAltDown() && Character.isJavaIdentifierPart(event.getKeyChar())) { 213 if (!event.isControlDown() && !event.isAltDown() && Character.isJavaIdentifierPart(event.getKeyChar())) {
182 EnigmaProject project = gui.getController().project; 214 EnigmaProject project = gui.getController().project;
@@ -184,8 +216,10 @@ public class EditorPanel {
184 Entry<?> entry = reference.getNameableEntry(); 216 Entry<?> entry = reference.getNameableEntry();
185 217
186 String name = String.valueOf(event.getKeyChar()); 218 String name = String.valueOf(event.getKeyChar());
219
187 if (entry instanceof ClassEntry && ((ClassEntry) entry).getParent() == null) { 220 if (entry instanceof ClassEntry && ((ClassEntry) entry).getParent() == null) {
188 String packageName = ((ClassEntry) entry).getPackageName(); 221 String packageName = ((ClassEntry) entry).getPackageName();
222
189 if (packageName != null) { 223 if (packageName != null) {
190 name = packageName + "/" + name; 224 name = packageName + "/" + name;
191 } 225 }
@@ -207,12 +241,14 @@ public class EditorPanel {
207 if ((this.editorLaf == null || this.editorLaf != laf)) { 241 if ((this.editorLaf == null || this.editorLaf != laf)) {
208 this.editor.updateUI(); 242 this.editor.updateUI();
209 this.editor.setBackground(UiConfig.getEditorBackgroundColor()); 243 this.editor.setBackground(UiConfig.getEditorBackgroundColor());
244
210 if (this.editorLaf != null) { 245 if (this.editorLaf != null) {
211 this.classHandle.invalidateMapped(); 246 this.classHandle.invalidateMapped();
212 } 247 }
213 248
214 this.editorLaf = laf; 249 this.editorLaf = laf;
215 } 250 }
251
216 this.boxHighlightPainters = boxHighlightPainters; 252 this.boxHighlightPainters = boxHighlightPainters;
217 }; 253 };
218 254
@@ -223,19 +259,23 @@ public class EditorPanel {
223 public static EditorPanel byUi(Component ui) { 259 public static EditorPanel byUi(Component ui) {
224 if (ui instanceof JComponent) { 260 if (ui instanceof JComponent) {
225 Object prop = ((JComponent) ui).getClientProperty(EditorPanel.class); 261 Object prop = ((JComponent) ui).getClientProperty(EditorPanel.class);
262
226 if (prop instanceof EditorPanel) { 263 if (prop instanceof EditorPanel) {
227 return (EditorPanel) prop; 264 return (EditorPanel) prop;
228 } 265 }
229 } 266 }
267
230 return null; 268 return null;
231 } 269 }
232 270
233 public void setClassHandle(ClassHandle handle) { 271 public void setClassHandle(ClassHandle handle) {
234 ClassEntry old = null; 272 ClassEntry old = null;
273
235 if (this.classHandle != null) { 274 if (this.classHandle != null) {
236 old = this.classHandle.getRef(); 275 old = this.classHandle.getRef();
237 this.classHandle.close(); 276 this.classHandle.close();
238 } 277 }
278
239 setClassHandle0(old, handle); 279 setClassHandle0(old, handle);
240 } 280 }
241 281
@@ -299,53 +339,61 @@ public class EditorPanel {
299 } else { 339 } else {
300 this.displayError(res.unwrapErr()); 340 this.displayError(res.unwrapErr());
301 } 341 }
342
302 this.nextReference = null; 343 this.nextReference = null;
303 }); 344 });
304 } 345 }
305 346
306 public void displayError(ClassHandleError t) { 347 public void displayError(ClassHandleError t) {
307 this.setDisplayMode(DisplayMode.ERRORED); 348 this.setDisplayMode(DisplayMode.ERRORED);
349
308 String str = switch (t.type) { 350 String str = switch (t.type) {
309 case DECOMPILE -> "editor.decompile_error"; 351 case DECOMPILE -> "editor.decompile_error";
310 case REMAP -> "editor.remap_error"; 352 case REMAP -> "editor.remap_error";
311 }; 353 };
354
312 this.errorLabel.setText(I18n.translate(str)); 355 this.errorLabel.setText(I18n.translate(str));
313 this.errorTextArea.setText(t.getStackTrace()); 356 this.errorTextArea.setText(t.getStackTrace());
314 this.errorTextArea.setCaretPosition(0); 357 this.errorTextArea.setCaretPosition(0);
315 } 358 }
316 359
317 public void setDisplayMode(DisplayMode mode) { 360 public void setDisplayMode(DisplayMode mode) {
318 if (this.mode == mode) return; 361 if (this.mode == mode) {
362 return;
363 }
364
319 this.ui.removeAll(); 365 this.ui.removeAll();
366
320 switch (mode) { 367 switch (mode) {
321 case INACTIVE: 368 case INACTIVE:
322 break; 369 break;
323 case IN_PROGRESS: { 370 case IN_PROGRESS: {
324 // make progress bar start from the left every time 371 // make progress bar start from the left every time
325 this.decompilingProgressBar.setIndeterminate(false); 372 this.decompilingProgressBar.setIndeterminate(false);
326 this.decompilingProgressBar.setIndeterminate(true); 373 this.decompilingProgressBar.setIndeterminate(true);
327 374
328 this.ui.setLayout(new GridBagLayout()); 375 this.ui.setLayout(new GridBagLayout());
329 GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(2); 376 GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(2);
330 this.ui.add(this.decompilingLabel, cb.pos(0, 0).anchor(GridBagConstraints.SOUTH).build()); 377 this.ui.add(this.decompilingLabel, cb.pos(0, 0).anchor(GridBagConstraints.SOUTH).build());
331 this.ui.add(this.decompilingProgressBar, cb.pos(0, 1).anchor(GridBagConstraints.NORTH).build()); 378 this.ui.add(this.decompilingProgressBar, cb.pos(0, 1).anchor(GridBagConstraints.NORTH).build());
332 break; 379 break;
333 } 380 }
334 case SUCCESS: { 381 case SUCCESS: {
335 this.ui.setLayout(new GridLayout(1, 1, 0, 0)); 382 this.ui.setLayout(new GridLayout(1, 1, 0, 0));
336 this.ui.add(this.editorScrollPane); 383 this.ui.add(this.editorScrollPane);
337 break; 384 break;
338 } 385 }
339 case ERRORED: { 386 case ERRORED: {
340 this.ui.setLayout(new GridBagLayout()); 387 this.ui.setLayout(new GridBagLayout());
341 GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(2).weight(1.0, 0.0).anchor(GridBagConstraints.WEST); 388 GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(2).weight(1.0, 0.0).anchor(GridBagConstraints.WEST);
342 this.ui.add(this.errorLabel, cb.pos(0, 0).build()); 389 this.ui.add(this.errorLabel, cb.pos(0, 0).build());
343 this.ui.add(new JSeparator(JSeparator.HORIZONTAL), cb.pos(0, 1).fill(GridBagConstraints.HORIZONTAL).build()); 390 this.ui.add(new JSeparator(JSeparator.HORIZONTAL), cb.pos(0, 1).fill(GridBagConstraints.HORIZONTAL).build());
344 this.ui.add(this.errorScrollPane, cb.pos(0, 2).weight(1.0, 1.0).fill(GridBagConstraints.BOTH).build()); 391 this.ui.add(this.errorScrollPane, cb.pos(0, 2).weight(1.0, 1.0).fill(GridBagConstraints.BOTH).build());
345 this.ui.add(this.retryButton, cb.pos(0, 3).weight(0.0, 0.0).anchor(GridBagConstraints.EAST).build()); 392 this.ui.add(this.retryButton, cb.pos(0, 3).weight(0.0, 0.0).anchor(GridBagConstraints.EAST).build());
346 break; 393 break;
347 } 394 }
348 } 395 }
396
349 this.ui.validate(); 397 this.ui.validate();
350 this.ui.repaint(); 398 this.ui.repaint();
351 this.mode = mode; 399 this.mode = mode;
@@ -353,6 +401,7 @@ public class EditorPanel {
353 401
354 public void offsetEditorZoom(int zoomAmount) { 402 public void offsetEditorZoom(int zoomAmount) {
355 int newResult = this.fontSize + zoomAmount; 403 int newResult = this.fontSize + zoomAmount;
404
356 if (newResult > 8 && newResult < 72) { 405 if (newResult > 8 && newResult < 72) {
357 this.fontSize = newResult; 406 this.fontSize = newResult;
358 this.editor.setFont(ScaleUtil.getFont(this.editor.getFont().getFontName(), Font.PLAIN, this.fontSize)); 407 this.editor.setFont(ScaleUtil.getFont(this.editor.getFont().getFontName(), Font.PLAIN, this.fontSize));
@@ -365,8 +414,13 @@ public class EditorPanel {
365 } 414 }
366 415
367 public void onCaretMove(int pos, boolean fromClick) { 416 public void onCaretMove(int pos, boolean fromClick) {
368 if (this.settingSource) return; 417 if (this.settingSource) {
369 if (this.controller.project == null) return; 418 return;
419 }
420
421 if (this.controller.project == null) {
422 return;
423 }
370 424
371 EntryRemapper mapper = this.controller.project.getMapper(); 425 EntryRemapper mapper = this.controller.project.getMapper();
372 Token token = getToken(pos); 426 Token token = getToken(pos);
@@ -378,10 +432,12 @@ public class EditorPanel {
378 if (referenceEntry != null && this.shouldNavigateOnClick && fromClick) { 432 if (referenceEntry != null && this.shouldNavigateOnClick && fromClick) {
379 this.shouldNavigateOnClick = false; 433 this.shouldNavigateOnClick = false;
380 Entry<?> navigationEntry = referenceEntry; 434 Entry<?> navigationEntry = referenceEntry;
435
381 if (this.cursorReference.context == null) { 436 if (this.cursorReference.context == null) {
382 EntryResolver resolver = mapper.getObfResolver(); 437 EntryResolver resolver = mapper.getObfResolver();
383 navigationEntry = resolver.resolveFirstEntry(referenceEntry, ResolutionStrategy.RESOLVE_ROOT); 438 navigationEntry = resolver.resolveFirstEntry(referenceEntry, ResolutionStrategy.RESOLVE_ROOT);
384 } 439 }
440
385 this.controller.navigateTo(navigationEntry); 441 this.controller.navigateTo(navigationEntry);
386 } 442 }
387 } 443 }
@@ -398,6 +454,7 @@ public class EditorPanel {
398 if (this.source == null) { 454 if (this.source == null) {
399 return null; 455 return null;
400 } 456 }
457
401 return this.source.getIndex().getReferenceToken(pos); 458 return this.source.getIndex().getReferenceToken(pos);
402 } 459 }
403 460
@@ -406,16 +463,22 @@ public class EditorPanel {
406 if (this.source == null) { 463 if (this.source == null) {
407 return null; 464 return null;
408 } 465 }
466
409 return this.source.getIndex().getReference(token); 467 return this.source.getIndex().getReference(token);
410 } 468 }
411 469
412 public void setSource(DecompiledClassSource source) { 470 public void setSource(DecompiledClassSource source) {
413 this.setDisplayMode(DisplayMode.SUCCESS); 471 this.setDisplayMode(DisplayMode.SUCCESS);
414 if (source == null) return; 472
473 if (source == null) {
474 return;
475 }
476
415 try { 477 try {
416 this.settingSource = true; 478 this.settingSource = true;
417 479
418 int newCaretPos = 0; 480 int newCaretPos = 0;
481
419 if (this.source != null && this.source.getEntry().equals(source.getEntry())) { 482 if (this.source != null && this.source.getEntry().equals(source.getEntry())) {
420 int caretPos = this.editor.getCaretPosition(); 483 int caretPos = this.editor.getCaretPosition();
421 484
@@ -441,9 +504,11 @@ public class EditorPanel {
441 this.source = source; 504 this.source = source;
442 this.editor.getHighlighter().removeAllHighlights(); 505 this.editor.getHighlighter().removeAllHighlights();
443 this.editor.setText(source.toString()); 506 this.editor.setText(source.toString());
507
444 if (this.source != null) { 508 if (this.source != null) {
445 this.editor.setCaretPosition(newCaretPos); 509 this.editor.setCaretPosition(newCaretPos);
446 } 510 }
511
447 setHighlightedTokens(source.getHighlightedTokens()); 512 setHighlightedTokens(source.getHighlightedTokens());
448 setCursorReference(getReference(getToken(this.editor.getCaretPosition()))); 513 setCursorReference(getReference(getToken(this.editor.getCaretPosition())));
449 } finally { 514 } finally {
@@ -515,10 +580,16 @@ public class EditorPanel {
515 * @param reference 580 * @param reference
516 */ 581 */
517 private void showReference0(EntryReference<Entry<?>, Entry<?>> reference) { 582 private void showReference0(EntryReference<Entry<?>, Entry<?>> reference) {
518 if (this.source == null) return; 583 if (this.source == null) {
519 if (reference == null) return; 584 return;
585 }
586
587 if (reference == null) {
588 return;
589 }
520 590
521 List<Token> tokens = this.controller.getTokensForReference(this.source, reference); 591 List<Token> tokens = this.controller.getTokensForReference(this.source, reference);
592
522 if (tokens.isEmpty()) { 593 if (tokens.isEmpty()) {
523 // DEBUG 594 // DEBUG
524 System.err.println(String.format("WARNING: no tokens found for %s in %s", reference, this.classHandle.getRef())); 595 System.err.println(String.format("WARNING: no tokens found for %s in %s", reference, this.classHandle.getRef()));
@@ -531,6 +602,7 @@ public class EditorPanel {
531 if (token == null) { 602 if (token == null) {
532 throw new IllegalArgumentException("Token cannot be null!"); 603 throw new IllegalArgumentException("Token cannot be null!");
533 } 604 }
605
534 navigateToToken(token, SelectionHighlightPainter.INSTANCE); 606 navigateToToken(token, SelectionHighlightPainter.INSTANCE);
535 } 607 }
536 608
@@ -546,9 +618,11 @@ public class EditorPanel {
546 // make sure the token is visible in the scroll window 618 // make sure the token is visible in the scroll window
547 Rectangle start = this.editor.modelToView(token.start); 619 Rectangle start = this.editor.modelToView(token.start);
548 Rectangle end = this.editor.modelToView(token.end); 620 Rectangle end = this.editor.modelToView(token.end);
621
549 if (start == null || end == null) { 622 if (start == null || end == null) {
550 return; 623 return;
551 } 624 }
625
552 Rectangle show = start.union(end); 626 Rectangle show = start.union(end);
553 show.grow(start.width * 10, start.height * 6); 627 show.grow(start.width * 10, start.height * 6);
554 SwingUtilities.invokeLater(() -> this.editor.scrollRectToVisible(show)); 628 SwingUtilities.invokeLater(() -> this.editor.scrollRectToVisible(show));
@@ -625,5 +699,4 @@ public class EditorPanel {
625 SUCCESS, 699 SUCCESS,
626 ERRORED, 700 ERRORED,
627 } 701 }
628
629} 702}
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 e71894db..7b75f1a8 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
@@ -25,12 +25,15 @@ import cuchaz.enigma.gui.util.ScaleUtil;
25import cuchaz.enigma.translation.mapping.AccessModifier; 25import cuchaz.enigma.translation.mapping.AccessModifier;
26import cuchaz.enigma.translation.mapping.EntryChange; 26import cuchaz.enigma.translation.mapping.EntryChange;
27import cuchaz.enigma.translation.mapping.EntryMapping; 27import cuchaz.enigma.translation.mapping.EntryMapping;
28import cuchaz.enigma.translation.representation.entry.*; 28import cuchaz.enigma.translation.representation.entry.ClassEntry;
29import cuchaz.enigma.translation.representation.entry.Entry;
30import cuchaz.enigma.translation.representation.entry.FieldEntry;
31import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
32import cuchaz.enigma.translation.representation.entry.MethodEntry;
29import cuchaz.enigma.utils.I18n; 33import cuchaz.enigma.utils.I18n;
30import cuchaz.enigma.utils.validation.ValidationContext; 34import cuchaz.enigma.utils.validation.ValidationContext;
31 35
32public class IdentifierPanel { 36public class IdentifierPanel {
33
34 private final Gui gui; 37 private final Gui gui;
35 38
36 private final JPanel ui = new JPanel(); 39 private final JPanel ui = new JPanel();
@@ -57,7 +60,9 @@ public class IdentifierPanel {
57 } 60 }
58 61
59 public boolean startRenaming() { 62 public boolean startRenaming() {
60 if (this.nameField == null) return false; 63 if (this.nameField == null) {
64 return false;
65 }
61 66
62 this.nameField.startEditing(); 67 this.nameField.startEditing();
63 68
@@ -65,7 +70,9 @@ public class IdentifierPanel {
65 } 70 }
66 71
67 public boolean startRenaming(String text) { 72 public boolean startRenaming(String text) {
68 if (this.nameField == null) return false; 73 if (this.nameField == null) {
74 return false;
75 }
69 76
70 this.nameField.startEditing(); 77 this.nameField.startEditing();
71 this.nameField.setEditText(text); 78 this.nameField.setEditText(text);
@@ -84,6 +91,7 @@ public class IdentifierPanel {
84 91
85 TableHelper th = new TableHelper(this.ui, this.entry, this.gui); 92 TableHelper th = new TableHelper(this.ui, this.entry, this.gui);
86 th.begin(); 93 th.begin();
94
87 if (this.entry == null) { 95 if (this.entry == null) {
88 this.ui.setEnabled(false); 96 this.ui.setEnabled(false);
89 } else { 97 } else {
@@ -102,8 +110,10 @@ public class IdentifierPanel {
102 th.addModifierRow(I18n.translate("info_panel.identifier.modifier"), EditableType.FIELD, this::onModifierChanged); 110 th.addModifierRow(I18n.translate("info_panel.identifier.modifier"), EditableType.FIELD, this::onModifierChanged);
103 } else if (deobfEntry instanceof MethodEntry) { 111 } else if (deobfEntry instanceof MethodEntry) {
104 MethodEntry me = (MethodEntry) deobfEntry; 112 MethodEntry me = (MethodEntry) deobfEntry;
113
105 if (me.isConstructor()) { 114 if (me.isConstructor()) {
106 ClassEntry ce = me.getParent(); 115 ClassEntry ce = me.getParent();
116
107 if (ce != null) { 117 if (ce != null) {
108 String name = ce.isInnerClass() ? ce.getName() : ce.getFullName(); 118 String name = ce.isInnerClass() ? ce.getName() : ce.getFullName();
109 this.nameField = th.addRenameTextField(EditableType.CLASS, name); 119 this.nameField = th.addRenameTextField(EditableType.CLASS, name);
@@ -112,6 +122,7 @@ public class IdentifierPanel {
112 this.nameField = th.addRenameTextField(EditableType.METHOD, me.getName()); 122 this.nameField = th.addRenameTextField(EditableType.METHOD, me.getName());
113 th.addStringRow(I18n.translate("info_panel.identifier.class"), me.getParent().getFullName()); 123 th.addStringRow(I18n.translate("info_panel.identifier.class"), me.getParent().getFullName());
114 } 124 }
125
115 th.addCopiableStringRow(I18n.translate("info_panel.identifier.method_descriptor"), me.getDesc().toString()); 126 th.addCopiableStringRow(I18n.translate("info_panel.identifier.method_descriptor"), me.getDesc().toString());
116 th.addModifierRow(I18n.translate("info_panel.identifier.modifier"), EditableType.METHOD, this::onModifierChanged); 127 th.addModifierRow(I18n.translate("info_panel.identifier.modifier"), EditableType.METHOD, this::onModifierChanged);
117 } else if (deobfEntry instanceof LocalVariableEntry) { 128 } else if (deobfEntry instanceof LocalVariableEntry) {
@@ -132,6 +143,7 @@ public class IdentifierPanel {
132 throw new IllegalStateException("unreachable"); 143 throw new IllegalStateException("unreachable");
133 } 144 }
134 } 145 }
146
135 th.end(); 147 th.end();
136 148
137 if (this.nameField != null) { 149 if (this.nameField != null) {
@@ -139,6 +151,7 @@ public class IdentifierPanel {
139 @Override 151 @Override
140 public void onStartEditing(ConvertingTextField field) { 152 public void onStartEditing(ConvertingTextField field) {
141 int i = field.getText().lastIndexOf('/'); 153 int i = field.getText().lastIndexOf('/');
154
142 if (i != -1) { 155 if (i != -1) {
143 field.selectSubstring(i + 1); 156 field.selectSubstring(i + 1);
144 } 157 }
@@ -146,7 +159,10 @@ public class IdentifierPanel {
146 159
147 @Override 160 @Override
148 public boolean tryStopEditing(ConvertingTextField field, boolean abort) { 161 public boolean tryStopEditing(ConvertingTextField field, boolean abort) {
149 if (abort) return true; 162 if (abort) {
163 return true;
164 }
165
150 vc.reset(); 166 vc.reset();
151 vc.setActiveElement(field); 167 vc.setActiveElement(field);
152 validateRename(field.getText()); 168 validateRename(field.getText());
@@ -162,6 +178,7 @@ public class IdentifierPanel {
162 } 178 }
163 179
164 EditorPanel e = gui.getActiveEditor(); 180 EditorPanel e = gui.getActiveEditor();
181
165 if (e != null) { 182 if (e != null) {
166 e.getEditor().requestFocusInWindow(); 183 e.getEditor().requestFocusInWindow();
167 } 184 }
@@ -192,13 +209,12 @@ public class IdentifierPanel {
192 } 209 }
193 210
194 private static final class TableHelper { 211 private static final class TableHelper {
195
196 private final Container c; 212 private final Container c;
197 private final Entry<?> e; 213 private final Entry<?> e;
198 private final Gui gui; 214 private final Gui gui;
199 private int row; 215 private int row;
200 216
201 public TableHelper(Container c, Entry<?> e, Gui gui) { 217 TableHelper(Container c, Entry<?> e, Gui gui) {
202 this.c = c; 218 this.c = c;
203 this.e = e; 219 this.e = e;
204 this.gui = gui; 220 this.gui = gui;
@@ -210,9 +226,7 @@ public class IdentifierPanel {
210 } 226 }
211 227
212 public void addRow(Component c1, Component c2) { 228 public void addRow(Component c1, Component c2) {
213 GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create() 229 GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(2).anchor(GridBagConstraints.WEST);
214 .insets(2)
215 .anchor(GridBagConstraints.WEST);
216 c.add(c1, cb.pos(0, this.row).build()); 230 c.add(c1, cb.pos(0, this.row).build());
217 c.add(c2, cb.pos(1, this.row).weightX(1.0).fill(GridBagConstraints.HORIZONTAL).build()); 231 c.add(c2, cb.pos(1, this.row).weightX(1.0).fill(GridBagConstraints.HORIZONTAL).build());
218 232
@@ -239,12 +253,12 @@ public class IdentifierPanel {
239 } 253 }
240 254
241 public ConvertingTextField addRenameTextField(EditableType type, String c2) { 255 public ConvertingTextField addRenameTextField(EditableType type, String c2) {
242 String description = switch(type) { 256 String description = switch (type) {
243 case CLASS -> I18n.translate("info_panel.identifier.class"); 257 case CLASS -> I18n.translate("info_panel.identifier.class");
244 case METHOD -> I18n.translate("info_panel.identifier.method"); 258 case METHOD -> I18n.translate("info_panel.identifier.method");
245 case FIELD -> I18n.translate("info_panel.identifier.field"); 259 case FIELD -> I18n.translate("info_panel.identifier.field");
246 case PARAMETER, LOCAL_VARIABLE -> I18n.translate("info_panel.identifier.variable"); 260 case PARAMETER, LOCAL_VARIABLE -> I18n.translate("info_panel.identifier.variable");
247 default -> throw new IllegalStateException("Unexpected value: " + type); 261 default -> throw new IllegalStateException("Unexpected value: " + type);
248 }; 262 };
249 263
250 if (this.gui.getController().project.isRenamable(e)) { 264 if (this.gui.getController().project.isRenamable(e)) {
@@ -296,7 +310,5 @@ public class IdentifierPanel {
296 // Add an empty panel with y-weight=1 so that all the other elements get placed at the top edge 310 // Add an empty panel with y-weight=1 so that all the other elements get placed at the top edge
297 c.add(new JPanel(), GridBagConstraintsBuilder.create().pos(0, row).weight(0.0, 1.0).build()); 311 c.add(new JPanel(), GridBagConstraintsBuilder.create().pos(0, row).weight(0.0, 1.0).build());
298 } 312 }
299
300 } 313 }
301
302} 314}
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 7783843d..f82e6663 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
@@ -13,7 +13,6 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry;
13import cuchaz.enigma.utils.I18n; 13import cuchaz.enigma.utils.I18n;
14 14
15public class ObfPanel extends JPanel { 15public class ObfPanel extends JPanel {
16
17 public final ClassSelector obfClasses; 16 public final ClassSelector obfClasses;
18 private final JLabel title = new JLabel(); 17 private final JLabel title = new JLabel();
19 18
@@ -25,9 +24,11 @@ public class ObfPanel extends JPanel {
25 Comparator<ClassEntry> obfClassComparator = (a, b) -> { 24 Comparator<ClassEntry> obfClassComparator = (a, b) -> {
26 String aname = a.getFullName(); 25 String aname = a.getFullName();
27 String bname = b.getFullName(); 26 String bname = b.getFullName();
27
28 if (aname.length() != bname.length()) { 28 if (aname.length() != bname.length()) {
29 return aname.length() - bname.length(); 29 return aname.length() - bname.length();
30 } 30 }
31
31 return aname.compareTo(bname); 32 return aname.compareTo(bname);
32 }; 33 };
33 34
@@ -45,5 +46,4 @@ public class ObfPanel extends JPanel {
45 public void retranslateUi() { 46 public void retranslateUi() {
46 this.title.setText(I18n.translate("info_panel.classes.obfuscated")); 47 this.title.setText(I18n.translate("info_panel.classes.obfuscated"));
47 } 48 }
48
49} 49}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/StructurePanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/StructurePanel.java
index ccded45c..571c638f 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/StructurePanel.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/StructurePanel.java
@@ -1,9 +1,16 @@
1package cuchaz.enigma.gui.panels; 1package cuchaz.enigma.gui.panels;
2 2
3import java.awt.*; 3import java.awt.BorderLayout;
4import java.awt.Component;
5import java.awt.GridBagConstraints;
6import java.awt.GridBagLayout;
4import java.awt.event.MouseEvent; 7import java.awt.event.MouseEvent;
5 8
6import javax.swing.*; 9import javax.swing.JComboBox;
10import javax.swing.JLabel;
11import javax.swing.JPanel;
12import javax.swing.JScrollPane;
13import javax.swing.JTree;
7import javax.swing.tree.DefaultTreeCellRenderer; 14import javax.swing.tree.DefaultTreeCellRenderer;
8import javax.swing.tree.DefaultTreeModel; 15import javax.swing.tree.DefaultTreeModel;
9import javax.swing.tree.TreeNode; 16import javax.swing.tree.TreeNode;
@@ -23,144 +30,144 @@ import cuchaz.enigma.translation.representation.entry.ParentedEntry;
23import cuchaz.enigma.utils.I18n; 30import cuchaz.enigma.utils.I18n;
24 31
25public class StructurePanel { 32public class StructurePanel {
26 private final Gui gui; 33 private final Gui gui;
27 34
28 private final JPanel panel = new JPanel(new BorderLayout()); 35 private final JPanel panel = new JPanel(new BorderLayout());
29 36
30 private final JPanel optionsPanel; 37 private final JPanel optionsPanel;
31 38
32 private final JLabel obfuscationVisibilityLabel = new JLabel(); 39 private final JLabel obfuscationVisibilityLabel = new JLabel();
33 private final JLabel documentationVisibilityLabel = new JLabel(); 40 private final JLabel documentationVisibilityLabel = new JLabel();
34 private final JLabel sortingOrderLabel = new JLabel(); 41 private final JLabel sortingOrderLabel = new JLabel();
35 42
36 private final JComboBox<StructureTreeOptions.ObfuscationVisibility> obfuscationVisibility; 43 private final JComboBox<StructureTreeOptions.ObfuscationVisibility> obfuscationVisibility;
37 private final JComboBox<StructureTreeOptions.DocumentationVisibility> documentationVisibility; 44 private final JComboBox<StructureTreeOptions.DocumentationVisibility> documentationVisibility;
38 private final JComboBox<StructureTreeOptions.SortingOrder> sortingOrder; 45 private final JComboBox<StructureTreeOptions.SortingOrder> sortingOrder;
39 46
40 private final JTree structureTree; 47 private final JTree structureTree;
41 48
42 public StructurePanel(Gui gui) { 49 public StructurePanel(Gui gui) {
43 this.gui = gui; 50 this.gui = gui;
44 51
45 this.optionsPanel = new JPanel(new GridBagLayout()); 52 this.optionsPanel = new JPanel(new GridBagLayout());
46 this.optionsPanel.setVisible(false); 53 this.optionsPanel.setVisible(false);
47 54
48 GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(5).fill(GridBagConstraints.HORIZONTAL); 55 GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(5).fill(GridBagConstraints.HORIZONTAL);
49 56
50 this.optionsPanel.add(this.obfuscationVisibilityLabel, cb.pos(0, 0).build()); 57 this.optionsPanel.add(this.obfuscationVisibilityLabel, cb.pos(0, 0).build());
51 this.obfuscationVisibility = new JComboBox<>(StructureTreeOptions.ObfuscationVisibility.values()); 58 this.obfuscationVisibility = new JComboBox<>(StructureTreeOptions.ObfuscationVisibility.values());
52 this.obfuscationVisibility.setRenderer(new StructureOptionListCellRenderer()); 59 this.obfuscationVisibility.setRenderer(new StructureOptionListCellRenderer());
53 this.obfuscationVisibility.addActionListener(event -> this.showStructure(gui.getActiveEditor())); 60 this.obfuscationVisibility.addActionListener(event -> this.showStructure(gui.getActiveEditor()));
54 this.optionsPanel.add(this.obfuscationVisibility, cb.pos(1, 0).build()); 61 this.optionsPanel.add(this.obfuscationVisibility, cb.pos(1, 0).build());
55 62
56 this.optionsPanel.add(this.documentationVisibilityLabel, cb.pos(0, 1).build()); 63 this.optionsPanel.add(this.documentationVisibilityLabel, cb.pos(0, 1).build());
57 this.documentationVisibility = new JComboBox<>(StructureTreeOptions.DocumentationVisibility.values()); 64 this.documentationVisibility = new JComboBox<>(StructureTreeOptions.DocumentationVisibility.values());
58 this.documentationVisibility.setRenderer(new StructureOptionListCellRenderer()); 65 this.documentationVisibility.setRenderer(new StructureOptionListCellRenderer());
59 this.documentationVisibility.addActionListener(event -> this.showStructure(gui.getActiveEditor())); 66 this.documentationVisibility.addActionListener(event -> this.showStructure(gui.getActiveEditor()));
60 this.optionsPanel.add(this.documentationVisibility, cb.pos(1, 1).build()); 67 this.optionsPanel.add(this.documentationVisibility, cb.pos(1, 1).build());
61 68
62 this.optionsPanel.add(this.sortingOrderLabel, cb.pos(0, 2).build()); 69 this.optionsPanel.add(this.sortingOrderLabel, cb.pos(0, 2).build());
63 this.sortingOrder = new JComboBox<>(StructureTreeOptions.SortingOrder.values()); 70 this.sortingOrder = new JComboBox<>(StructureTreeOptions.SortingOrder.values());
64 this.sortingOrder.setRenderer(new StructureOptionListCellRenderer()); 71 this.sortingOrder.setRenderer(new StructureOptionListCellRenderer());
65 this.sortingOrder.addActionListener(event -> this.showStructure(gui.getActiveEditor())); 72 this.sortingOrder.addActionListener(event -> this.showStructure(gui.getActiveEditor()));
66 this.optionsPanel.add(this.sortingOrder, cb.pos(1, 2).build()); 73 this.optionsPanel.add(this.sortingOrder, cb.pos(1, 2).build());
67 74
68 this.structureTree = new JTree(); 75 this.structureTree = new JTree();
69 this.structureTree.setModel(null); 76 this.structureTree.setModel(null);
70 this.structureTree.setCellRenderer(new StructureTreeCellRenderer(gui)); 77 this.structureTree.setCellRenderer(new StructureTreeCellRenderer(gui));
71 this.structureTree.setSelectionModel(new SingleTreeSelectionModel()); 78 this.structureTree.setSelectionModel(new SingleTreeSelectionModel());
72 this.structureTree.setShowsRootHandles(true); 79 this.structureTree.setShowsRootHandles(true);
73 this.structureTree.addMouseListener(GuiUtil.onMouseClick(this::onClick)); 80 this.structureTree.addMouseListener(GuiUtil.onMouseClick(this::onClick));
74 81
75 this.retranslateUi(); 82 this.retranslateUi();
76 83
77 this.panel.add(this.optionsPanel, BorderLayout.NORTH); 84 this.panel.add(this.optionsPanel, BorderLayout.NORTH);
78 this.panel.add(new JScrollPane(this.structureTree)); 85 this.panel.add(new JScrollPane(this.structureTree));
79 } 86 }
80 87
81 public void showStructure(EditorPanel editor) { 88 public void showStructure(EditorPanel editor) {
82 structureTree.setModel(null); 89 structureTree.setModel(null);
83 90
84 if (editor == null) { 91 if (editor == null) {
85 this.optionsPanel.setVisible(false); 92 this.optionsPanel.setVisible(false);
86 return; 93 return;
87 } 94 }
88 95
89 ClassEntry classEntry = editor.getClassHandle().getRef(); 96 ClassEntry classEntry = editor.getClassHandle().getRef();
90 if (classEntry == null) return; 97
91 98 if (classEntry == null) {
92 this.optionsPanel.setVisible(true); 99 return;
93 100 }
94 // get the class structure 101
95 StructureTreeNode node = this.gui.getController().getClassStructure(classEntry, this.getOptions()); 102 this.optionsPanel.setVisible(true);
96 103
97 // show the tree at the root 104 // get the class structure
98 TreePath path = GuiUtil.getPathToRoot(node); 105 StructureTreeNode node = this.gui.getController().getClassStructure(classEntry, this.getOptions());
99 structureTree.setModel(new DefaultTreeModel((TreeNode) path.getPathComponent(0))); 106
100 structureTree.expandPath(path); 107 // show the tree at the root
101 structureTree.setSelectionRow(structureTree.getRowForPath(path)); 108 TreePath path = GuiUtil.getPathToRoot(node);
102 } 109 structureTree.setModel(new DefaultTreeModel((TreeNode) path.getPathComponent(0)));
103 110 structureTree.expandPath(path);
104 private void onClick(MouseEvent event) { 111 structureTree.setSelectionRow(structureTree.getRowForPath(path));
105 if (event.getClickCount() >= 2 && event.getButton() == MouseEvent.BUTTON1) { 112 }
106 // get the selected node 113
107 TreePath path = structureTree.getSelectionPath(); 114 private void onClick(MouseEvent event) {
108 if (path == null) { 115 if (event.getClickCount() >= 2 && event.getButton() == MouseEvent.BUTTON1) {
109 return; 116 // get the selected node
110 } 117 TreePath path = structureTree.getSelectionPath();
111 118
112 Object node = path.getLastPathComponent(); 119 if (path == null) {
113 120 return;
114 if (node instanceof StructureTreeNode) { 121 }
115 this.gui.getController().navigateTo(((StructureTreeNode) node).getEntry()); 122
116 } 123 Object node = path.getLastPathComponent();
117 } 124
118 } 125 if (node instanceof StructureTreeNode) {
119 126 this.gui.getController().navigateTo(((StructureTreeNode) node).getEntry());
120 /** 127 }
121 * Creates and returns the options of this structure panel. 128 }
122 */ 129 }
123 private StructureTreeOptions getOptions() { 130
124 return new StructureTreeOptions( 131 /**
125 (StructureTreeOptions.ObfuscationVisibility) this.obfuscationVisibility.getSelectedItem(), 132 * Creates and returns the options of this structure panel.
126 (StructureTreeOptions.DocumentationVisibility) this.documentationVisibility.getSelectedItem(), 133 */
127 (StructureTreeOptions.SortingOrder) this.sortingOrder.getSelectedItem() 134 private StructureTreeOptions getOptions() {
128 ); 135 return new StructureTreeOptions((StructureTreeOptions.ObfuscationVisibility) this.obfuscationVisibility.getSelectedItem(), (StructureTreeOptions.DocumentationVisibility) this.documentationVisibility.getSelectedItem(), (StructureTreeOptions.SortingOrder) this.sortingOrder.getSelectedItem());
129 } 136 }
130 137
131 public void retranslateUi() { 138 public void retranslateUi() {
132 this.obfuscationVisibilityLabel.setText(I18n.translate("structure.options.obfuscation")); 139 this.obfuscationVisibilityLabel.setText(I18n.translate("structure.options.obfuscation"));
133 this.documentationVisibilityLabel.setText(I18n.translate("structure.options.documentation")); 140 this.documentationVisibilityLabel.setText(I18n.translate("structure.options.documentation"));
134 this.sortingOrderLabel.setText(I18n.translate("structure.options.sorting")); 141 this.sortingOrderLabel.setText(I18n.translate("structure.options.sorting"));
135 } 142 }
136 143
137 public JPanel getPanel() { 144 public JPanel getPanel() {
138 return this.panel; 145 return this.panel;
139 } 146 }
140 147
141 private static class StructureTreeCellRenderer extends DefaultTreeCellRenderer { 148 private static class StructureTreeCellRenderer extends DefaultTreeCellRenderer {
142 private final Gui gui; 149 private final Gui gui;
143 150
144 StructureTreeCellRenderer(Gui gui) { 151 StructureTreeCellRenderer(Gui gui) {
145 this.gui = gui; 152 this.gui = gui;
146 } 153 }
147 154
148 @Override 155 @Override
149 public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { 156 public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
150 Component c = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); 157 Component c = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
151 ParentedEntry<?> entry = ((StructureTreeNode) value).getEntry(); 158 ParentedEntry<?> entry = ((StructureTreeNode) value).getEntry();
152 159
153 if (entry instanceof ClassEntry classEntry) { 160 if (entry instanceof ClassEntry classEntry) {
154 this.setIcon(GuiUtil.getClassIcon(gui, classEntry)); 161 this.setIcon(GuiUtil.getClassIcon(gui, classEntry));
155 } else if (entry instanceof MethodEntry methodEntry) { 162 } else if (entry instanceof MethodEntry methodEntry) {
156 this.setIcon(GuiUtil.getMethodIcon(methodEntry)); 163 this.setIcon(GuiUtil.getMethodIcon(methodEntry));
157 } else if (entry instanceof FieldEntry) { 164 } else if (entry instanceof FieldEntry) {
158 this.setIcon(GuiUtil.FIELD_ICON); 165 this.setIcon(GuiUtil.FIELD_ICON);
159 } 166 }
160 167
161 this.setText("<html>" + ((StructureTreeNode) value).toHtml()); 168 this.setText("<html>" + ((StructureTreeNode) value).toHtml());
162 169
163 return c; 170 return c;
164 } 171 }
165 } 172 }
166} 173}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/CallsTreeCellRenderer.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/CallsTreeCellRenderer.java
index 0aa6510c..3791a1ec 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/CallsTreeCellRenderer.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/CallsTreeCellRenderer.java
@@ -1,45 +1,51 @@
1package cuchaz.enigma.gui.renderer; 1package cuchaz.enigma.gui.renderer;
2 2
3import cuchaz.enigma.analysis.*; 3import java.awt.Component;
4
5import javax.swing.JTree;
6import javax.swing.tree.DefaultTreeCellRenderer;
7
8import cuchaz.enigma.analysis.ClassReferenceTreeNode;
9import cuchaz.enigma.analysis.EntryReference;
10import cuchaz.enigma.analysis.FieldReferenceTreeNode;
11import cuchaz.enigma.analysis.MethodReferenceTreeNode;
12import cuchaz.enigma.analysis.ReferenceTreeNode;
4import cuchaz.enigma.gui.Gui; 13import cuchaz.enigma.gui.Gui;
5import cuchaz.enigma.gui.config.UiConfig; 14import cuchaz.enigma.gui.config.UiConfig;
6import cuchaz.enigma.gui.util.GuiUtil; 15import cuchaz.enigma.gui.util.GuiUtil;
7import cuchaz.enigma.translation.representation.entry.MethodEntry; 16import cuchaz.enigma.translation.representation.entry.MethodEntry;
8 17
9import javax.swing.*;
10import javax.swing.tree.DefaultTreeCellRenderer;
11import java.awt.*;
12
13public class CallsTreeCellRenderer extends DefaultTreeCellRenderer { 18public class CallsTreeCellRenderer extends DefaultTreeCellRenderer {
14 private final Gui gui; 19 private final Gui gui;
15 20
16 public CallsTreeCellRenderer(Gui gui) { 21 public CallsTreeCellRenderer(Gui gui) {
17 this.gui = gui; 22 this.gui = gui;
18 } 23 }
19 24
20 @Override 25 @Override
21 public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { 26 public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
22 Component c = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); 27 Component c = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
23 EntryReference<?, ?> reference = ((ReferenceTreeNode<?, ?>) value).getReference(); 28 EntryReference<?, ?> reference = ((ReferenceTreeNode<?, ?>) value).getReference();
24 29
25 this.setForeground(UiConfig.getTextColor()); 30 this.setForeground(UiConfig.getTextColor());
26 31
27 // if the node represents the method calling the entry 32 // if the node represents the method calling the entry
28 if (reference != null) { 33 if (reference != null) {
29 if (reference.context instanceof MethodEntry) { 34 if (reference.context instanceof MethodEntry) {
30 this.setIcon(GuiUtil.getMethodIcon((MethodEntry) reference.context)); 35 this.setIcon(GuiUtil.getMethodIcon((MethodEntry) reference.context));
31 } 36 }
32 // if the node represents the called entry 37
33 } else { 38 // if the node represents the called entry
34 if (value instanceof ClassReferenceTreeNode node) { 39 } else {
35 this.setIcon(GuiUtil.getClassIcon(this.gui, node.getEntry())); 40 if (value instanceof ClassReferenceTreeNode node) {
36 } else if (value instanceof MethodReferenceTreeNode node) { 41 this.setIcon(GuiUtil.getClassIcon(this.gui, node.getEntry()));
37 this.setIcon(GuiUtil.getMethodIcon(node.getEntry())); 42 } else if (value instanceof MethodReferenceTreeNode node) {
38 } else if (value instanceof FieldReferenceTreeNode) { 43 this.setIcon(GuiUtil.getMethodIcon(node.getEntry()));
39 this.setIcon(GuiUtil.FIELD_ICON); 44 } else if (value instanceof FieldReferenceTreeNode) {
40 } 45 this.setIcon(GuiUtil.FIELD_ICON);
41 } 46 }
42 47 }
43 return c; 48
44 } 49 return c;
50 }
45} 51}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/ImplementationsTreeCellRenderer.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/ImplementationsTreeCellRenderer.java
index 7bf39005..b4126c02 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/ImplementationsTreeCellRenderer.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/ImplementationsTreeCellRenderer.java
@@ -1,34 +1,35 @@
1package cuchaz.enigma.gui.renderer; 1package cuchaz.enigma.gui.renderer;
2 2
3import java.awt.Component;
4
5import javax.swing.JTree;
6import javax.swing.tree.DefaultTreeCellRenderer;
7
3import cuchaz.enigma.analysis.ClassImplementationsTreeNode; 8import cuchaz.enigma.analysis.ClassImplementationsTreeNode;
4import cuchaz.enigma.analysis.MethodImplementationsTreeNode; 9import cuchaz.enigma.analysis.MethodImplementationsTreeNode;
5import cuchaz.enigma.gui.Gui; 10import cuchaz.enigma.gui.Gui;
6import cuchaz.enigma.gui.config.UiConfig; 11import cuchaz.enigma.gui.config.UiConfig;
7import cuchaz.enigma.gui.util.GuiUtil; 12import cuchaz.enigma.gui.util.GuiUtil;
8 13
9import javax.swing.*;
10import javax.swing.tree.DefaultTreeCellRenderer;
11import java.awt.*;
12
13public class ImplementationsTreeCellRenderer extends DefaultTreeCellRenderer { 14public class ImplementationsTreeCellRenderer extends DefaultTreeCellRenderer {
14 private final Gui gui; 15 private final Gui gui;
15 16
16 public ImplementationsTreeCellRenderer(Gui gui) { 17 public ImplementationsTreeCellRenderer(Gui gui) {
17 this.gui = gui; 18 this.gui = gui;
18 } 19 }
19 20
20 @Override 21 @Override
21 public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { 22 public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
22 Component c = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); 23 Component c = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
23 24
24 this.setForeground(UiConfig.getTextColor()); 25 this.setForeground(UiConfig.getTextColor());
25 26
26 if (value instanceof ClassImplementationsTreeNode node) { 27 if (value instanceof ClassImplementationsTreeNode node) {
27 this.setIcon(GuiUtil.getClassIcon(this.gui, node.getClassEntry())); 28 this.setIcon(GuiUtil.getClassIcon(this.gui, node.getClassEntry()));
28 } else if (value instanceof MethodImplementationsTreeNode node) { 29 } else if (value instanceof MethodImplementationsTreeNode node) {
29 this.setIcon(GuiUtil.getMethodIcon(node.getMethodEntry())); 30 this.setIcon(GuiUtil.getMethodIcon(node.getMethodEntry()));
30 } 31 }
31 32
32 return c; 33 return c;
33 } 34 }
34} 35}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/InheritanceTreeCellRenderer.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/InheritanceTreeCellRenderer.java
index a1025531..04bf0f93 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/InheritanceTreeCellRenderer.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/InheritanceTreeCellRenderer.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 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 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.gui.renderer; 12package cuchaz.enigma.gui.renderer;
13 13
@@ -37,6 +37,7 @@ public class InheritanceTreeCellRenderer extends DefaultTreeCellRenderer {
37 if (!(value instanceof MethodInheritanceTreeNode node) || node.isImplemented()) { 37 if (!(value instanceof MethodInheritanceTreeNode node) || node.isImplemented()) {
38 ret.setForeground(UiConfig.getTextColor()); 38 ret.setForeground(UiConfig.getTextColor());
39 ret.setFont(ret.getFont().deriveFont(Font.PLAIN)); 39 ret.setFont(ret.getFont().deriveFont(Font.PLAIN));
40
40 if (value instanceof ClassInheritanceTreeNode) { 41 if (value instanceof ClassInheritanceTreeNode) {
41 this.setIcon(GuiUtil.getClassIcon(this.gui, ((ClassInheritanceTreeNode) value).getClassEntry())); 42 this.setIcon(GuiUtil.getClassIcon(this.gui, ((ClassInheritanceTreeNode) value).getClassEntry()));
42 } else if (value instanceof MethodInheritanceTreeNode) { 43 } else if (value instanceof MethodInheritanceTreeNode) {
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/MessageListCellRenderer.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/MessageListCellRenderer.java
index b6ae0c50..123990e4 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/MessageListCellRenderer.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/MessageListCellRenderer.java
@@ -10,15 +10,15 @@ import cuchaz.enigma.network.Message;
10// For now, just render the translated text. 10// For now, just render the translated text.
11// TODO: Icons or something later? 11// TODO: Icons or something later?
12public class MessageListCellRenderer extends DefaultListCellRenderer { 12public class MessageListCellRenderer extends DefaultListCellRenderer {
13
14 @Override 13 @Override
15 public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) { 14 public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
16 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 15 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
17 Message message = (Message) value; 16 Message message = (Message) value;
17
18 if (message != null) { 18 if (message != null) {
19 setText(message.translate()); 19 setText(message.translate());
20 } 20 }
21
21 return this; 22 return this;
22 } 23 }
23
24} 24}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/StructureOptionListCellRenderer.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/StructureOptionListCellRenderer.java
index f9a1cae6..09cdc9bd 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/StructureOptionListCellRenderer.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/StructureOptionListCellRenderer.java
@@ -1,21 +1,22 @@
1package cuchaz.enigma.gui.renderer; 1package cuchaz.enigma.gui.renderer;
2 2
3import java.awt.Component;
4
5import javax.swing.DefaultListCellRenderer;
6import javax.swing.JList;
7
3import cuchaz.enigma.analysis.StructureTreeOptions; 8import cuchaz.enigma.analysis.StructureTreeOptions;
4import cuchaz.enigma.utils.I18n; 9import cuchaz.enigma.utils.I18n;
5 10
6import javax.swing.*;
7import java.awt.*;
8
9public class StructureOptionListCellRenderer extends DefaultListCellRenderer { 11public class StructureOptionListCellRenderer extends DefaultListCellRenderer {
12 @Override
13 public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
14 Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
10 15
11 @Override 16 if (value instanceof StructureTreeOptions.Option option) {
12 public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) { 17 this.setText(I18n.translate(option.getTranslationKey()));
13 Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 18 }
14
15 if (value instanceof StructureTreeOptions.Option option) {
16 this.setText(I18n.translate(option.getTranslationKey()));
17 }
18 19
19 return c; 20 return c;
20 } 21 }
21} 22}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/search/SearchEntry.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/search/SearchEntry.java
index 91727c38..93507bcd 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/search/SearchEntry.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/search/SearchEntry.java
@@ -3,7 +3,6 @@ package cuchaz.enigma.gui.search;
3import java.util.List; 3import java.util.List;
4 4
5public interface SearchEntry { 5public interface SearchEntry {
6
7 List<String> getSearchableNames(); 6 List<String> getSearchableNames();
8 7
9 /** 8 /**
@@ -13,5 +12,4 @@ public interface SearchEntry {
13 * @return a unique identifier for this search entry 12 * @return a unique identifier for this search entry
14 */ 13 */
15 String getIdentifier(); 14 String getIdentifier();
16
17} 15}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/search/SearchUtil.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/search/SearchUtil.java
index a3b35faa..c8212ce5 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/search/SearchUtil.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/search/SearchUtil.java
@@ -1,6 +1,14 @@
1package cuchaz.enigma.gui.search; 1package cuchaz.enigma.gui.search;
2 2
3import java.util.*; 3import java.util.ArrayList;
4import java.util.Arrays;
5import java.util.Collection;
6import java.util.Collections;
7import java.util.Comparator;
8import java.util.HashMap;
9import java.util.List;
10import java.util.Locale;
11import java.util.Map;
4import java.util.concurrent.Executor; 12import java.util.concurrent.Executor;
5import java.util.concurrent.Executors; 13import java.util.concurrent.Executors;
6import java.util.concurrent.atomic.AtomicBoolean; 14import java.util.concurrent.atomic.AtomicBoolean;
@@ -14,7 +22,6 @@ import java.util.stream.Stream;
14import cuchaz.enigma.utils.Pair; 22import cuchaz.enigma.utils.Pair;
15 23
16public class SearchUtil<T extends SearchEntry> { 24public class SearchUtil<T extends SearchEntry> {
17
18 private final Map<T, Entry<T>> entries = new HashMap<>(); 25 private final Map<T, Entry<T>> entries = new HashMap<>();
19 private final Map<String, Integer> hitCount = new HashMap<>(); 26 private final Map<String, Integer> hitCount = new HashMap<>();
20 private final Executor searchExecutor = Executors.newWorkStealingPool(); 27 private final Executor searchExecutor = Executors.newWorkStealingPool();
@@ -45,12 +52,7 @@ public class SearchUtil<T extends SearchEntry> {
45 } 52 }
46 53
47 public Stream<T> search(String term) { 54 public Stream<T> search(String term) {
48 return entries.values().parallelStream() 55 return entries.values().parallelStream().map(e -> new Pair<>(e, e.getScore(term, hitCount.getOrDefault(e.searchEntry.getIdentifier(), 0)))).filter(e -> e.b > 0).sorted(Comparator.comparingDouble(o -> -o.b)).map(e -> e.a.searchEntry).sequential();
49 .map(e -> new Pair<>(e, e.getScore(term, hitCount.getOrDefault(e.searchEntry.getIdentifier(), 0))))
50 .filter(e -> e.b > 0)
51 .sorted(Comparator.comparingDouble(o -> -o.b))
52 .map(e -> e.a.searchEntry)
53 .sequential();
54 } 56 }
55 57
56 public SearchControl asyncSearch(String term, SearchResultConsumer<T> consumer) { 58 public SearchControl asyncSearch(String term, SearchResultConsumer<T> consumer) {
@@ -61,21 +63,36 @@ public class SearchUtil<T extends SearchEntry> {
61 AtomicInteger size = new AtomicInteger(); 63 AtomicInteger size = new AtomicInteger();
62 AtomicBoolean control = new AtomicBoolean(false); 64 AtomicBoolean control = new AtomicBoolean(false);
63 AtomicInteger elapsed = new AtomicInteger(); 65 AtomicInteger elapsed = new AtomicInteger();
66
64 for (Entry<T> value : entries.values()) { 67 for (Entry<T> value : entries.values()) {
65 searchExecutor.execute(() -> { 68 searchExecutor.execute(() -> {
66 try { 69 try {
67 if (control.get()) return; 70 if (control.get()) {
71 return;
72 }
73
68 float score = value.getScore(term, hitCount.getOrDefault(value.searchEntry.getIdentifier(), 0)); 74 float score = value.getScore(term, hitCount.getOrDefault(value.searchEntry.getIdentifier(), 0));
69 if (score <= 0) return; 75
76 if (score <= 0) {
77 return;
78 }
79
70 score = -score; // sort descending 80 score = -score; // sort descending
81
71 try { 82 try {
72 scoresLock.lock(); 83 scoresLock.lock();
73 if (control.get()) return; 84
85 if (control.get()) {
86 return;
87 }
88
74 int dataSize = size.getAndIncrement(); 89 int dataSize = size.getAndIncrement();
75 int index = Arrays.binarySearch(scores, 0, dataSize, score); 90 int index = Arrays.binarySearch(scores, 0, dataSize, score);
91
76 if (index < 0) { 92 if (index < 0) {
77 index = ~index; 93 index = ~index;
78 } 94 }
95
79 System.arraycopy(scores, index, scores, index + 1, dataSize - index); 96 System.arraycopy(scores, index, scores, index + 1, dataSize - index);
80 scores[index] = score; 97 scores[index] = score;
81 consumer.add(index, value.searchEntry); 98 consumer.add(index, value.searchEntry);
@@ -113,7 +130,6 @@ public class SearchUtil<T extends SearchEntry> {
113 } 130 }
114 131
115 public static final class Entry<T extends SearchEntry> { 132 public static final class Entry<T extends SearchEntry> {
116
117 public final T searchEntry; 133 public final T searchEntry;
118 private final String[][] components; 134 private final String[][] components;
119 135
@@ -124,9 +140,7 @@ public class SearchUtil<T extends SearchEntry> {
124 140
125 public float getScore(String term, int hits) { 141 public float getScore(String term, int hits) {
126 String ucTerm = term.toUpperCase(Locale.ROOT); 142 String ucTerm = term.toUpperCase(Locale.ROOT);
127 float maxScore = (float) Arrays.stream(components) 143 float maxScore = (float) Arrays.stream(components).mapToDouble(name -> getScoreFor(ucTerm, name)).max().orElse(0.0);
128 .mapToDouble(name -> getScoreFor(ucTerm, name))
129 .max().orElse(0.0);
130 return maxScore * (hits + 1); 144 return maxScore * (hits + 1);
131 } 145 }
132 146
@@ -156,17 +170,20 @@ public class SearchUtil<T extends SearchEntry> {
156 String component = name[componentIndex]; 170 String component = name[componentIndex];
157 float posMultiplier = (name.length - componentIndex) * 0.3f; 171 float posMultiplier = (name.length - componentIndex) * 0.3f;
158 Map<String, Float> newSnapshots = new HashMap<>(); 172 Map<String, Float> newSnapshots = new HashMap<>();
173
159 for (Map.Entry<String, Float> snapshot : snapshots.entrySet()) { 174 for (Map.Entry<String, Float> snapshot : snapshots.entrySet()) {
160 String remaining = snapshot.getKey(); 175 String remaining = snapshot.getKey();
161 float score = snapshot.getValue(); 176 float score = snapshot.getValue();
162 component = component.toUpperCase(Locale.ROOT); 177 component = component.toUpperCase(Locale.ROOT);
163 int l = compareEqualLength(remaining, component); 178 int l = compareEqualLength(remaining, component);
179
164 for (int i = 1; i <= l; i++) { 180 for (int i = 1; i <= l; i++) {
165 float baseScore = scorePerChar * i; 181 float baseScore = scorePerChar * i;
166 float chainBonus = (i - 1) * 0.5f; 182 float chainBonus = (i - 1) * 0.5f;
167 merge(newSnapshots, Collections.singletonMap(remaining.substring(i), score + baseScore * posMultiplier + chainBonus), Math::max); 183 merge(newSnapshots, Collections.singletonMap(remaining.substring(i), score + baseScore * posMultiplier + chainBonus), Math::max);
168 } 184 }
169 } 185 }
186
170 merge(snapshots, newSnapshots, Math::max); 187 merge(snapshots, newSnapshots, Math::max);
171 } 188 }
172 189
@@ -180,24 +197,24 @@ public class SearchUtil<T extends SearchEntry> {
180 } 197 }
181 198
182 public static <T extends SearchEntry> Entry<T> from(T e) { 199 public static <T extends SearchEntry> Entry<T> from(T e) {
183 String[][] components = e.getSearchableNames().parallelStream() 200 String[][] components = e.getSearchableNames().parallelStream().map(Entry::wordwiseSplit).toArray(String[][]::new);
184 .map(Entry::wordwiseSplit)
185 .toArray(String[][]::new);
186 return new Entry<>(e, components); 201 return new Entry<>(e, components);
187 } 202 }
188 203
189 private static int compareEqualLength(String s1, String s2) { 204 private static int compareEqualLength(String s1, String s2) {
190 int len = 0; 205 int len = 0;
206
191 while (len < s1.length() && len < s2.length() && s1.charAt(len) == s2.charAt(len)) { 207 while (len < s1.length() && len < s2.length() && s1.charAt(len) == s2.charAt(len)) {
192 len += 1; 208 len += 1;
193 } 209 }
210
194 return len; 211 return len;
195 } 212 }
196 213
197 /** 214 /**
198 * Splits the given input into components, trying to detect word parts. 215 * Splits the given input into components, trying to detect word parts.
199 * <p> 216 *
200 * Example of how words get split (using <code>|</code> as seperator): 217 * <p>Example of how words get split (using <code>|</code> as seperator):
201 * <p><code>MinecraftClientGame -> Minecraft|Client|Game</code></p> 218 * <p><code>MinecraftClientGame -> Minecraft|Client|Game</code></p>
202 * <p><code>HTTPInputStream -> HTTP|Input|Stream</code></p> 219 * <p><code>HTTPInputStream -> HTTP|Input|Stream</code></p>
203 * <p><code>class_932 -> class|_|932</code></p> 220 * <p><code>class_932 -> class|_|932</code></p>
@@ -210,46 +227,57 @@ public class SearchUtil<T extends SearchEntry> {
210 */ 227 */
211 private static String[] wordwiseSplit(String input) { 228 private static String[] wordwiseSplit(String input) {
212 List<String> list = new ArrayList<>(); 229 List<String> list = new ArrayList<>();
230
213 while (!input.isEmpty()) { 231 while (!input.isEmpty()) {
214 int take; 232 int take;
233
215 if (Character.isLetter(input.charAt(0))) { 234 if (Character.isLetter(input.charAt(0))) {
216 if (input.length() == 1) { 235 if (input.length() == 1) {
217 take = 1; 236 take = 1;
218 } else { 237 } else {
219 boolean nextSegmentIsUppercase = Character.isUpperCase(input.charAt(0)) && Character.isUpperCase(input.charAt(1)); 238 boolean nextSegmentIsUppercase = Character.isUpperCase(input.charAt(0)) && Character.isUpperCase(input.charAt(1));
239
220 if (nextSegmentIsUppercase) { 240 if (nextSegmentIsUppercase) {
221 int nextLowercase = 1; 241 int nextLowercase = 1;
242
222 while (Character.isUpperCase(input.charAt(nextLowercase))) { 243 while (Character.isUpperCase(input.charAt(nextLowercase))) {
223 nextLowercase += 1; 244 nextLowercase += 1;
245
224 if (nextLowercase == input.length()) { 246 if (nextLowercase == input.length()) {
225 nextLowercase += 1; 247 nextLowercase += 1;
226 break; 248 break;
227 } 249 }
228 } 250 }
251
229 take = nextLowercase - 1; 252 take = nextLowercase - 1;
230 } else { 253 } else {
231 int nextUppercase = 1; 254 int nextUppercase = 1;
255
232 while (nextUppercase < input.length() && Character.isLowerCase(input.charAt(nextUppercase))) { 256 while (nextUppercase < input.length() && Character.isLowerCase(input.charAt(nextUppercase))) {
233 nextUppercase += 1; 257 nextUppercase += 1;
234 } 258 }
259
235 take = nextUppercase; 260 take = nextUppercase;
236 } 261 }
237 } 262 }
238 } else if (Character.isDigit(input.charAt(0))) { 263 } else if (Character.isDigit(input.charAt(0))) {
239 int nextNonNum = 1; 264 int nextNonNum = 1;
265
240 while (nextNonNum < input.length() && Character.isLetter(input.charAt(nextNonNum)) && !Character.isLowerCase(input.charAt(nextNonNum))) { 266 while (nextNonNum < input.length() && Character.isLetter(input.charAt(nextNonNum)) && !Character.isLowerCase(input.charAt(nextNonNum))) {
241 nextNonNum += 1; 267 nextNonNum += 1;
242 } 268 }
269
243 take = nextNonNum; 270 take = nextNonNum;
244 } else { 271 } else {
245 take = 1; 272 take = 1;
246 } 273 }
274
247 list.add(input.substring(0, take)); 275 list.add(input.substring(0, take));
248 input = input.substring(take); 276 input = input.substring(take);
249 } 277 }
278
250 return list.toArray(new String[0]); 279 return list.toArray(new String[0]);
251 } 280 }
252
253 } 281 }
254 282
255 @FunctionalInterface 283 @FunctionalInterface
@@ -264,5 +292,4 @@ public class SearchUtil<T extends SearchEntry> {
264 292
265 float getProgress(); 293 float getProgress();
266 } 294 }
267
268} 295}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java
index 20d6a0eb..99b5572b 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java
@@ -1,5 +1,10 @@
1package cuchaz.enigma.gui.stats; 1package cuchaz.enigma.gui.stats;
2 2
3import java.util.EnumSet;
4import java.util.HashMap;
5import java.util.Map;
6import java.util.Set;
7
3import cuchaz.enigma.EnigmaProject; 8import cuchaz.enigma.EnigmaProject;
4import cuchaz.enigma.ProgressListener; 9import cuchaz.enigma.ProgressListener;
5import cuchaz.enigma.analysis.index.EntryIndex; 10import cuchaz.enigma.analysis.index.EntryIndex;
@@ -7,109 +12,112 @@ import cuchaz.enigma.translation.mapping.EntryRemapper;
7import cuchaz.enigma.translation.mapping.EntryResolver; 12import cuchaz.enigma.translation.mapping.EntryResolver;
8import cuchaz.enigma.translation.mapping.ResolutionStrategy; 13import cuchaz.enigma.translation.mapping.ResolutionStrategy;
9import cuchaz.enigma.translation.representation.TypeDescriptor; 14import cuchaz.enigma.translation.representation.TypeDescriptor;
10import cuchaz.enigma.translation.representation.entry.*; 15import cuchaz.enigma.translation.representation.entry.ClassEntry;
16import cuchaz.enigma.translation.representation.entry.Entry;
17import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
18import cuchaz.enigma.translation.representation.entry.FieldEntry;
19import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
20import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
21import cuchaz.enigma.translation.representation.entry.MethodEntry;
11import cuchaz.enigma.utils.I18n; 22import cuchaz.enigma.utils.I18n;
12 23
13import java.util.*;
14
15public class StatsGenerator { 24public class StatsGenerator {
16 private final EnigmaProject project; 25 private final EnigmaProject project;
17 private final EntryIndex entryIndex; 26 private final EntryIndex entryIndex;
18 private final EntryRemapper mapper; 27 private final EntryRemapper mapper;
19 private final EntryResolver entryResolver; 28 private final EntryResolver entryResolver;
20 29
21 public StatsGenerator(EnigmaProject project) { 30 public StatsGenerator(EnigmaProject project) {
22 this.project = project; 31 this.project = project;
23 this.entryIndex = project.getJarIndex().getEntryIndex(); 32 this.entryIndex = project.getJarIndex().getEntryIndex();
24 this.mapper = project.getMapper(); 33 this.mapper = project.getMapper();
25 this.entryResolver = project.getJarIndex().getEntryResolver(); 34 this.entryResolver = project.getJarIndex().getEntryResolver();
26 } 35 }
27 36
28 public StatsResult generate(ProgressListener progress, Set<StatsMember> includedMembers, String topLevelPackage, boolean includeSynthetic) { 37 public StatsResult generate(ProgressListener progress, Set<StatsMember> includedMembers, String topLevelPackage, boolean includeSynthetic) {
29 includedMembers = EnumSet.copyOf(includedMembers); 38 includedMembers = EnumSet.copyOf(includedMembers);
30 int totalWork = 0; 39 int totalWork = 0;
31 int totalMappable = 0; 40 int totalMappable = 0;
32 41
33 if (includedMembers.contains(StatsMember.METHODS) || includedMembers.contains(StatsMember.PARAMETERS)) { 42 if (includedMembers.contains(StatsMember.METHODS) || includedMembers.contains(StatsMember.PARAMETERS)) {
34 totalWork += entryIndex.getMethods().size(); 43 totalWork += entryIndex.getMethods().size();
35 } 44 }
36 45
37 if (includedMembers.contains(StatsMember.FIELDS)) { 46 if (includedMembers.contains(StatsMember.FIELDS)) {
38 totalWork += entryIndex.getFields().size(); 47 totalWork += entryIndex.getFields().size();
39 } 48 }
40 49
41 if (includedMembers.contains(StatsMember.CLASSES)) { 50 if (includedMembers.contains(StatsMember.CLASSES)) {
42 totalWork += entryIndex.getClasses().size(); 51 totalWork += entryIndex.getClasses().size();
43 } 52 }
44 53
45 progress.init(totalWork, I18n.translate("progress.stats")); 54 progress.init(totalWork, I18n.translate("progress.stats"));
46 55
47 Map<String, Integer> counts = new HashMap<>(); 56 Map<String, Integer> counts = new HashMap<>();
48 57
49 int numDone = 0; 58 int numDone = 0;
50 if (includedMembers.contains(StatsMember.METHODS) || includedMembers.contains(StatsMember.PARAMETERS)) { 59
51 for (MethodEntry method : entryIndex.getMethods()) { 60 if (includedMembers.contains(StatsMember.METHODS) || includedMembers.contains(StatsMember.PARAMETERS)) {
52 progress.step(numDone++, I18n.translate("type.methods")); 61 for (MethodEntry method : entryIndex.getMethods()) {
53 MethodEntry root = entryResolver 62 progress.step(numDone++, I18n.translate("type.methods"));
54 .resolveEntry(method, ResolutionStrategy.RESOLVE_ROOT) 63 MethodEntry root = entryResolver.resolveEntry(method, ResolutionStrategy.RESOLVE_ROOT).stream().findFirst().orElseThrow(AssertionError::new);
55 .stream() 64
56 .findFirst() 65 if (root == method) {
57 .orElseThrow(AssertionError::new); 66 if (includedMembers.contains(StatsMember.METHODS) && !((MethodDefEntry) method).getAccess().isSynthetic()) {
58 67 update(counts, method);
59 if (root == method) { 68 totalMappable++;
60 if (includedMembers.contains(StatsMember.METHODS) && !((MethodDefEntry) method).getAccess().isSynthetic()) { 69 }
61 update(counts, method); 70
62 totalMappable ++; 71 if (includedMembers.contains(StatsMember.PARAMETERS) && (!((MethodDefEntry) method).getAccess().isSynthetic() || includeSynthetic)) {
63 } 72 int index = ((MethodDefEntry) method).getAccess().isStatic() ? 0 : 1;
64 73
65 if (includedMembers.contains(StatsMember.PARAMETERS) && (!((MethodDefEntry) method).getAccess().isSynthetic() || includeSynthetic)) { 74 for (TypeDescriptor argument : method.getDesc().getArgumentDescs()) {
66 int index = ((MethodDefEntry) method).getAccess().isStatic() ? 0 : 1; 75 update(counts, new LocalVariableEntry(method, index, "", true, null));
67 for (TypeDescriptor argument : method.getDesc().getArgumentDescs()) { 76 index += argument.getSize();
68 update(counts, new LocalVariableEntry(method, index, "", true,null)); 77 totalMappable++;
69 index += argument.getSize(); 78 }
70 totalMappable ++; 79 }
71 } 80 }
72 } 81 }
73 } 82 }
74 } 83
75 } 84 if (includedMembers.contains(StatsMember.FIELDS)) {
76 85 for (FieldEntry field : entryIndex.getFields()) {
77 if (includedMembers.contains(StatsMember.FIELDS)) { 86 progress.step(numDone++, I18n.translate("type.fields"));
78 for (FieldEntry field : entryIndex.getFields()) { 87
79 progress.step(numDone++, I18n.translate("type.fields")); 88 if (!((FieldDefEntry) field).getAccess().isSynthetic()) {
80 if (!((FieldDefEntry)field).getAccess().isSynthetic()) { 89 update(counts, field);
81 update(counts, field); 90 totalMappable++;
82 totalMappable ++; 91 }
83 } 92 }
84 } 93 }
85 } 94
86 95 if (includedMembers.contains(StatsMember.CLASSES)) {
87 if (includedMembers.contains(StatsMember.CLASSES)) { 96 for (ClassEntry clazz : entryIndex.getClasses()) {
88 for (ClassEntry clazz : entryIndex.getClasses()) { 97 progress.step(numDone++, I18n.translate("type.classes"));
89 progress.step(numDone++, I18n.translate("type.classes")); 98 update(counts, clazz);
90 update(counts, clazz); 99 totalMappable++;
91 totalMappable ++; 100 }
92 } 101 }
93 } 102
94 103 progress.step(-1, I18n.translate("progress.stats.data"));
95 progress.step(-1, I18n.translate("progress.stats.data")); 104
96 105 StatsResult.Tree<Integer> tree = new StatsResult.Tree<>();
97 StatsResult.Tree<Integer> tree = new StatsResult.Tree<>(); 106
98 107 for (Map.Entry<String, Integer> entry : counts.entrySet()) {
99 for (Map.Entry<String, Integer> entry : counts.entrySet()) { 108 if (entry.getKey().startsWith(topLevelPackage)) {
100 if (entry.getKey().startsWith(topLevelPackage)) { 109 tree.getNode(entry.getKey()).value = entry.getValue();
101 tree.getNode(entry.getKey()).value = entry.getValue(); 110 }
102 } 111 }
103 } 112
104 113 tree.collapse(tree.root);
105 tree.collapse(tree.root); 114 return new StatsResult(totalMappable, counts.values().stream().mapToInt(i -> i).sum(), tree);
106 return new StatsResult(totalMappable, counts.values().stream().mapToInt(i -> i).sum(), tree); 115 }
107 } 116
108 117 private void update(Map<String, Integer> counts, Entry<?> entry) {
109 private void update(Map<String, Integer> counts, Entry<?> entry) { 118 if (project.isObfuscated(entry)) {
110 if (project.isObfuscated(entry)) { 119 String parent = mapper.deobfuscate(entry.getAncestry().get(0)).getName().replace('/', '.');
111 String parent = mapper.deobfuscate(entry.getAncestry().get(0)).getName().replace('/', '.'); 120 counts.put(parent, counts.getOrDefault(parent, 0) + 1);
112 counts.put(parent, counts.getOrDefault(parent, 0) + 1); 121 }
113 } 122 }
114 }
115} 123}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsMember.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsMember.java
index 0e2452fa..0037ab5b 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsMember.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsMember.java
@@ -1,8 +1,8 @@
1package cuchaz.enigma.gui.stats; 1package cuchaz.enigma.gui.stats;
2 2
3public enum StatsMember { 3public enum StatsMember {
4 CLASSES, 4 CLASSES,
5 METHODS, 5 METHODS,
6 FIELDS, 6 FIELDS,
7 PARAMETERS 7 PARAMETERS
8} 8}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsResult.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsResult.java
index 0a71a647..12726c0b 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsResult.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsResult.java
@@ -1,14 +1,13 @@
1package cuchaz.enigma.gui.stats; 1package cuchaz.enigma.gui.stats;
2 2
3import com.google.gson.GsonBuilder;
4
5import java.util.ArrayList; 3import java.util.ArrayList;
6import java.util.HashMap; 4import java.util.HashMap;
7import java.util.List; 5import java.util.List;
8import java.util.Map; 6import java.util.Map;
9 7
10public final class StatsResult { 8import com.google.gson.GsonBuilder;
11 9
10public final class StatsResult {
12 private final int total; 11 private final int total;
13 private final int unmapped; 12 private final int unmapped;
14 private final Tree<Integer> tree; 13 private final Tree<Integer> tree;
@@ -101,5 +100,4 @@ public final class StatsResult {
101 } 100 }
102 } 101 }
103 } 102 }
104
105} 103}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/AbstractListCellRenderer.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/AbstractListCellRenderer.java
index 612e3e92..f8ce36db 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/AbstractListCellRenderer.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/AbstractListCellRenderer.java
@@ -3,11 +3,16 @@ package cuchaz.enigma.gui.util;
3import java.awt.Component; 3import java.awt.Component;
4import java.awt.event.MouseEvent; 4import java.awt.event.MouseEvent;
5 5
6import javax.swing.*; 6import javax.swing.BorderFactory;
7import javax.swing.JComponent;
8import javax.swing.JList;
9import javax.swing.JPanel;
10import javax.swing.ListCellRenderer;
11import javax.swing.UIDefaults;
12import javax.swing.UIManager;
7import javax.swing.border.Border; 13import javax.swing.border.Border;
8 14
9public abstract class AbstractListCellRenderer<E> extends JPanel implements ListCellRenderer<E> { 15public abstract class AbstractListCellRenderer<E> extends JPanel implements ListCellRenderer<E> {
10
11 private static final Border NO_FOCUS_BORDER = BorderFactory.createEmptyBorder(1, 1, 1, 1); 16 private static final Border NO_FOCUS_BORDER = BorderFactory.createEmptyBorder(1, 1, 1, 1);
12 17
13 private Border noFocusBorder; 18 private Border noFocusBorder;
@@ -21,22 +26,27 @@ public abstract class AbstractListCellRenderer<E> extends JPanel implements List
21 Border border = UIManager.getLookAndFeel().getDefaults().getBorder("List.List.cellNoFocusBorder"); 26 Border border = UIManager.getLookAndFeel().getDefaults().getBorder("List.List.cellNoFocusBorder");
22 noFocusBorder = border != null ? border : NO_FOCUS_BORDER; 27 noFocusBorder = border != null ? border : NO_FOCUS_BORDER;
23 } 28 }
29
24 return noFocusBorder; 30 return noFocusBorder;
25 } 31 }
26 32
27 protected Border getBorder(boolean isSelected, boolean cellHasFocus) { 33 protected Border getBorder(boolean isSelected, boolean cellHasFocus) {
28 Border b = null; 34 Border b = null;
35
29 if (cellHasFocus) { 36 if (cellHasFocus) {
30 UIDefaults defaults = UIManager.getLookAndFeel().getDefaults(); 37 UIDefaults defaults = UIManager.getLookAndFeel().getDefaults();
38
31 if (isSelected) { 39 if (isSelected) {
32 b = defaults.getBorder("List.focusSelectedCellHighlightBorder"); 40 b = defaults.getBorder("List.focusSelectedCellHighlightBorder");
33 } 41 }
42
34 if (b == null) { 43 if (b == null) {
35 b = defaults.getBorder("List.focusCellHighlightBorder"); 44 b = defaults.getBorder("List.focusCellHighlightBorder");
36 } 45 }
37 } else { 46 } else {
38 b = getNoFocusBorder(); 47 b = getNoFocusBorder();
39 } 48 }
49
40 return b; 50 return b;
41 } 51 }
42 52
@@ -68,10 +78,11 @@ public abstract class AbstractListCellRenderer<E> extends JPanel implements List
68 @Override 78 @Override
69 public String getToolTipText(MouseEvent event) { 79 public String getToolTipText(MouseEvent event) {
70 Component c = getComponentAt(event.getPoint()); 80 Component c = getComponentAt(event.getPoint());
81
71 if (c instanceof JComponent) { 82 if (c instanceof JComponent) {
72 return ((JComponent) c).getToolTipText(); 83 return ((JComponent) c).getToolTipText();
73 } 84 }
85
74 return getToolTipText(); 86 return getToolTipText();
75 } 87 }
76
77} 88}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/GridBagConstraintsBuilder.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/GridBagConstraintsBuilder.java
index 6a756867..2d8aa73e 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/GridBagConstraintsBuilder.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/GridBagConstraintsBuilder.java
@@ -3,7 +3,6 @@ package cuchaz.enigma.gui.util;
3import java.awt.GridBagConstraints; 3import java.awt.GridBagConstraints;
4 4
5public final class GridBagConstraintsBuilder { 5public final class GridBagConstraintsBuilder {
6
7 private final GridBagConstraints inner; 6 private final GridBagConstraints inner;
8 7
9 private GridBagConstraintsBuilder(GridBagConstraints inner) { 8 private GridBagConstraintsBuilder(GridBagConstraints inner) {
@@ -136,5 +135,4 @@ public final class GridBagConstraintsBuilder {
136 public GridBagConstraints build() { 135 public GridBagConstraints build() {
137 return (GridBagConstraints) this.inner.clone(); 136 return (GridBagConstraints) this.inner.clone();
138 } 137 }
139
140} 138}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/GuiUtil.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/GuiUtil.java
index 3b8ecbc5..d0784243 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/GuiUtil.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/GuiUtil.java
@@ -1,8 +1,17 @@
1package cuchaz.enigma.gui.util; 1package cuchaz.enigma.gui.util;
2 2
3import java.awt.*; 3import java.awt.Color;
4import java.awt.Cursor;
5import java.awt.Desktop;
6import java.awt.Font;
7import java.awt.Toolkit;
4import java.awt.datatransfer.StringSelection; 8import java.awt.datatransfer.StringSelection;
5import java.awt.event.*; 9import java.awt.event.MouseAdapter;
10import java.awt.event.MouseEvent;
11import java.awt.event.MouseListener;
12import java.awt.event.WindowAdapter;
13import java.awt.event.WindowEvent;
14import java.awt.event.WindowListener;
6import java.awt.font.TextAttribute; 15import java.awt.font.TextAttribute;
7import java.io.IOException; 16import java.io.IOException;
8import java.net.URI; 17import java.net.URI;
@@ -13,7 +22,14 @@ import java.util.Map;
13import java.util.NoSuchElementException; 22import java.util.NoSuchElementException;
14import java.util.function.Consumer; 23import java.util.function.Consumer;
15 24
16import javax.swing.*; 25import javax.swing.Icon;
26import javax.swing.JComponent;
27import javax.swing.JLabel;
28import javax.swing.JToolTip;
29import javax.swing.Popup;
30import javax.swing.PopupFactory;
31import javax.swing.Timer;
32import javax.swing.ToolTipManager;
17import javax.swing.tree.TreeNode; 33import javax.swing.tree.TreeNode;
18import javax.swing.tree.TreePath; 34import javax.swing.tree.TreePath;
19 35
@@ -28,160 +44,160 @@ import cuchaz.enigma.translation.representation.entry.MethodEntry;
28import cuchaz.enigma.utils.Os; 44import cuchaz.enigma.utils.Os;
29 45
30public class GuiUtil { 46public class GuiUtil {
31 public static final Icon CLASS_ICON = loadIcon("class"); 47 public static final Icon CLASS_ICON = loadIcon("class");
32 public static final Icon INTERFACE_ICON = loadIcon("interface"); 48 public static final Icon INTERFACE_ICON = loadIcon("interface");
33 public static final Icon ENUM_ICON = loadIcon("enum"); 49 public static final Icon ENUM_ICON = loadIcon("enum");
34 public static final Icon ANNOTATION_ICON = loadIcon("annotation"); 50 public static final Icon ANNOTATION_ICON = loadIcon("annotation");
35 public static final Icon RECORD_ICON = loadIcon("record"); 51 public static final Icon RECORD_ICON = loadIcon("record");
36 public static final Icon METHOD_ICON = loadIcon("method"); 52 public static final Icon METHOD_ICON = loadIcon("method");
37 public static final Icon FIELD_ICON = loadIcon("field"); 53 public static final Icon FIELD_ICON = loadIcon("field");
38 public static final Icon CONSTRUCTOR_ICON = loadIcon("constructor"); 54 public static final Icon CONSTRUCTOR_ICON = loadIcon("constructor");
39 55
40 public static void openUrl(String url) { 56 public static void openUrl(String url) {
41 try { 57 try {
42 switch (Os.getOs()) { 58 switch (Os.getOs()) {
43 case LINUX: 59 case LINUX:
44 new ProcessBuilder("/usr/bin/env", "xdg-open", url).start(); 60 new ProcessBuilder("/usr/bin/env", "xdg-open", url).start();
45 break; 61 break;
46 default: 62 default:
47 if (Desktop.isDesktopSupported()) { 63 if (Desktop.isDesktopSupported()) {
48 Desktop desktop = Desktop.getDesktop(); 64 Desktop desktop = Desktop.getDesktop();
49 desktop.browse(new URI(url)); 65 desktop.browse(new URI(url));
50 } 66 }
51 } 67 }
52 } catch (IOException ex) { 68 } catch (IOException ex) {
53 throw new RuntimeException(ex); 69 throw new RuntimeException(ex);
54 } catch (URISyntaxException ex) { 70 } catch (URISyntaxException ex) {
55 throw new IllegalArgumentException(ex); 71 throw new IllegalArgumentException(ex);
56 } 72 }
57 } 73 }
58 74
59 public static JLabel unboldLabel(JLabel label) { 75 public static JLabel unboldLabel(JLabel label) {
60 Font font = label.getFont(); 76 Font font = label.getFont();
61 label.setFont(font.deriveFont(font.getStyle() & ~Font.BOLD)); 77 label.setFont(font.deriveFont(font.getStyle() & ~Font.BOLD));
62 return label; 78 return label;
63 } 79 }
64 80
65 /** 81 /**
66 * Puts the provided {@code text} in the system clipboard. 82 * Puts the provided {@code text} in the system clipboard.
67 */ 83 */
68 public static void copyToClipboard(String text) { 84 public static void copyToClipboard(String text) {
69 Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(text), null); 85 Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(text), null);
70 } 86 }
71 87
72 public static void showPopup(JComponent component, String text, int x, int y) { 88 public static void showPopup(JComponent component, String text, int x, int y) {
73 // from https://stackoverflow.com/questions/39955015/java-swing-show-tooltip-as-a-message-dialog 89 // from https://stackoverflow.com/questions/39955015/java-swing-show-tooltip-as-a-message-dialog
74 JToolTip tooltip = new JToolTip(); 90 JToolTip tooltip = new JToolTip();
75 tooltip.setTipText(text); 91 tooltip.setTipText(text);
76 Popup p = PopupFactory.getSharedInstance().getPopup(component, tooltip, x + 10, y); 92 Popup p = PopupFactory.getSharedInstance().getPopup(component, tooltip, x + 10, y);
77 p.show(); 93 p.show();
78 Timer t = new Timer(1000, e -> p.hide()); 94 Timer t = new Timer(1000, e -> p.hide());
79 t.setRepeats(false); 95 t.setRepeats(false);
80 t.start(); 96 t.start();
81 } 97 }
82 98
83 public static void showToolTipNow(JComponent component) { 99 public static void showToolTipNow(JComponent component) {
84 // HACKHACK: trick the tooltip manager into showing the tooltip right now 100 // HACKHACK: trick the tooltip manager into showing the tooltip right now
85 ToolTipManager manager = ToolTipManager.sharedInstance(); 101 ToolTipManager manager = ToolTipManager.sharedInstance();
86 int oldDelay = manager.getInitialDelay(); 102 int oldDelay = manager.getInitialDelay();
87 manager.setInitialDelay(0); 103 manager.setInitialDelay(0);
88 manager.mouseMoved(new MouseEvent(component, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, 0, 0, 0, false)); 104 manager.mouseMoved(new MouseEvent(component, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, 0, 0, 0, false));
89 manager.setInitialDelay(oldDelay); 105 manager.setInitialDelay(oldDelay);
90 } 106 }
91 107
92 public static JLabel createLink(String text, Runnable action) { 108 public static JLabel createLink(String text, Runnable action) {
93 JLabel link = new JLabel(text); 109 JLabel link = new JLabel(text);
94 link.setForeground(Color.BLUE.darker()); 110 link.setForeground(Color.BLUE.darker());
95 link.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); 111 link.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
96 @SuppressWarnings("unchecked") 112 @SuppressWarnings("unchecked") Map<TextAttribute, Object> attributes = (Map<TextAttribute, Object>) link.getFont().getAttributes();
97 Map<TextAttribute, Object> attributes = (Map<TextAttribute, Object>) link.getFont().getAttributes(); 113 attributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
98 attributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); 114 link.setFont(link.getFont().deriveFont(attributes));
99 link.setFont(link.getFont().deriveFont(attributes)); 115 link.addMouseListener(new MouseAdapter() {
100 link.addMouseListener(new MouseAdapter() { 116 @Override
101 @Override 117 public void mousePressed(MouseEvent e) {
102 public void mousePressed(MouseEvent e) { 118 action.run();
103 action.run(); 119 }
104 } 120 });
105 }); 121 return link;
106 return link; 122 }
107 } 123
108 124 public static Icon loadIcon(String name) {
109 public static Icon loadIcon(String name) { 125 String path = "icons/" + name + ".svg";
110 String path = "icons/" + name + ".svg"; 126
111 127 // Do an eager check for a missing icon since FlatSVGIcon does it later at render time
112 // Do an eager check for a missing icon since FlatSVGIcon does it later at render time 128 if (GuiUtil.class.getResource('/' + path) == null) {
113 if (GuiUtil.class.getResource('/' + path) == null) { 129 throw new NoSuchElementException("Missing icon: '" + name + "' at " + path);
114 throw new NoSuchElementException("Missing icon: '" + name + "' at " + path); 130 }
115 } 131
116 132 // Note: the width and height are scaled automatically because the FlatLaf UI scale
117 // Note: the width and height are scaled automatically because the FlatLaf UI scale 133 // is set in LookAndFeel.setGlobalLAF()
118 // is set in LookAndFeel.setGlobalLAF() 134 return new FlatSVGIcon(path, 16, 16, GuiUtil.class.getClassLoader());
119 return new FlatSVGIcon(path, 16, 16, GuiUtil.class.getClassLoader()); 135 }
120 } 136
121 137 public static Icon getClassIcon(Gui gui, ClassEntry entry) {
122 public static Icon getClassIcon(Gui gui, ClassEntry entry) { 138 EntryIndex entryIndex = gui.getController().project.getJarIndex().getEntryIndex();
123 EntryIndex entryIndex = gui.getController().project.getJarIndex().getEntryIndex(); 139 AccessFlags access = entryIndex.getClassAccess(entry);
124 AccessFlags access = entryIndex.getClassAccess(entry); 140
125 141 if (access != null) {
126 if (access != null) { 142 if (access.isAnnotation()) {
127 if (access.isAnnotation()) { 143 return ANNOTATION_ICON;
128 return ANNOTATION_ICON; 144 } else if (access.isInterface()) {
129 } else if (access.isInterface()) { 145 return INTERFACE_ICON;
130 return INTERFACE_ICON; 146 } else if (access.isEnum()) {
131 } else if (access.isEnum()) { 147 return ENUM_ICON;
132 return ENUM_ICON; 148 } else if (entryIndex.getDefinition(entry).isRecord()) {
133 } else if (entryIndex.getDefinition(entry).isRecord()) { 149 return RECORD_ICON;
134 return RECORD_ICON; 150 }
135 } 151 }
136 } 152
137 153 return CLASS_ICON;
138 return CLASS_ICON; 154 }
139 } 155
140 156 public static Icon getMethodIcon(MethodEntry entry) {
141 public static Icon getMethodIcon(MethodEntry entry) { 157 if (entry.isConstructor()) {
142 if (entry.isConstructor()) { 158 return CONSTRUCTOR_ICON;
143 return CONSTRUCTOR_ICON; 159 }
144 } 160
145 return METHOD_ICON; 161 return METHOD_ICON;
146 } 162 }
147 163
148 public static TreePath getPathToRoot(TreeNode node) { 164 public static TreePath getPathToRoot(TreeNode node) {
149 List<TreeNode> nodes = Lists.newArrayList(); 165 List<TreeNode> nodes = Lists.newArrayList();
150 TreeNode n = node; 166 TreeNode n = node;
151 167
152 do { 168 do {
153 nodes.add(n); 169 nodes.add(n);
154 n = n.getParent(); 170 n = n.getParent();
155 } while (n != null); 171 } while (n != null);
156 172
157 Collections.reverse(nodes); 173 Collections.reverse(nodes);
158 return new TreePath(nodes.toArray()); 174 return new TreePath(nodes.toArray());
159 } 175 }
160 176
161 public static MouseListener onMouseClick(Consumer<MouseEvent> op) { 177 public static MouseListener onMouseClick(Consumer<MouseEvent> op) {
162 return new MouseAdapter() { 178 return new MouseAdapter() {
163 @Override 179 @Override
164 public void mouseClicked(MouseEvent e) { 180 public void mouseClicked(MouseEvent e) {
165 op.accept(e); 181 op.accept(e);
166 } 182 }
167 }; 183 };
168 } 184 }
169 185
170 public static MouseListener onMousePress(Consumer<MouseEvent> op) { 186 public static MouseListener onMousePress(Consumer<MouseEvent> op) {
171 return new MouseAdapter() { 187 return new MouseAdapter() {
172 @Override 188 @Override
173 public void mousePressed(MouseEvent e) { 189 public void mousePressed(MouseEvent e) {
174 op.accept(e); 190 op.accept(e);
175 } 191 }
176 }; 192 };
177 } 193 }
178 194
179 public static WindowListener onWindowClose(Consumer<WindowEvent> op) { 195 public static WindowListener onWindowClose(Consumer<WindowEvent> op) {
180 return new WindowAdapter() { 196 return new WindowAdapter() {
181 @Override 197 @Override
182 public void windowClosing(WindowEvent e) { 198 public void windowClosing(WindowEvent e) {
183 op.accept(e); 199 op.accept(e);
184 } 200 }
185 }; 201 };
186 } 202 }
187} 203}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/History.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/History.java
index b1286998..f1a8a7a9 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/History.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/History.java
@@ -1,9 +1,9 @@
1package cuchaz.enigma.gui.util; 1package cuchaz.enigma.gui.util;
2 2
3import com.google.common.collect.Queues;
4
5import java.util.Deque; 3import java.util.Deque;
6 4
5import com.google.common.collect.Queues;
6
7public class History<T> { 7public class History<T> {
8 private final Deque<T> previous = Queues.newArrayDeque(); 8 private final Deque<T> previous = Queues.newArrayDeque();
9 private final Deque<T> next = Queues.newArrayDeque(); 9 private final Deque<T> next = Queues.newArrayDeque();
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/LanguageChangeListener.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/LanguageChangeListener.java
index 9f53a44f..818e112b 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/LanguageChangeListener.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/LanguageChangeListener.java
@@ -1,11 +1,9 @@
1package cuchaz.enigma.gui.util; 1package cuchaz.enigma.gui.util;
2 2
3public interface LanguageChangeListener { 3public interface LanguageChangeListener {
4
5 void retranslateUi(); 4 void retranslateUi();
6 5
7 default boolean isValid() { 6 default boolean isValid() {
8 return true; 7 return true;
9 } 8 }
10
11} 9}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/LanguageUtil.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/LanguageUtil.java
index d3e63763..30a91809 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/LanguageUtil.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/LanguageUtil.java
@@ -4,7 +4,6 @@ import java.util.ArrayList;
4import java.util.List; 4import java.util.List;
5 5
6public final class LanguageUtil { 6public final class LanguageUtil {
7
8 private static final List<LanguageChangeListener> listeners = new ArrayList<>(); 7 private static final List<LanguageChangeListener> listeners = new ArrayList<>();
9 8
10 public LanguageUtil() { 9 public LanguageUtil() {
@@ -21,5 +20,4 @@ public final class LanguageUtil {
21 public static void dispatchLanguageChange() { 20 public static void dispatchLanguageChange() {
22 listeners.forEach(LanguageChangeListener::retranslateUi); 21 listeners.forEach(LanguageChangeListener::retranslateUi);
23 } 22 }
24
25} 23}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/ScaleChangeListener.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/ScaleChangeListener.java
index d045c6d5..243f26fc 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/ScaleChangeListener.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/ScaleChangeListener.java
@@ -2,7 +2,5 @@ package cuchaz.enigma.gui.util;
2 2
3@FunctionalInterface 3@FunctionalInterface
4public interface ScaleChangeListener { 4public interface ScaleChangeListener {
5
6 void onScaleChanged(float scale, float oldScale); 5 void onScaleChanged(float scale, float oldScale);
7
8} 6}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/ScaleUtil.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/ScaleUtil.java
index 28e37693..bc587fa7 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/ScaleUtil.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/ScaleUtil.java
@@ -21,7 +21,6 @@ import de.sciss.syntaxpane.DefaultSyntaxKit;
21import cuchaz.enigma.gui.config.UiConfig; 21import cuchaz.enigma.gui.config.UiConfig;
22 22
23public class ScaleUtil { 23public class ScaleUtil {
24
25 private static List<ScaleChangeListener> listeners = new ArrayList<>(); 24 private static List<ScaleChangeListener> listeners = new ArrayList<>();
26 25
27 public static void setScaleFactor(float scaleFactor) { 26 public static void setScaleFactor(float scaleFactor) {
@@ -110,15 +109,19 @@ public class ScaleUtil {
110 109
111 private static BasicTweaker createTweakerForCurrentLook(float dpiScaling) { 110 private static BasicTweaker createTweakerForCurrentLook(float dpiScaling) {
112 String testString = UIManager.getLookAndFeel().getName().toLowerCase(); 111 String testString = UIManager.getLookAndFeel().getName().toLowerCase();
112
113 if (testString.contains("windows")) { 113 if (testString.contains("windows")) {
114 return new WindowsTweaker(dpiScaling, testString.contains("classic")); 114 return new WindowsTweaker(dpiScaling, testString.contains("classic"));
115 } 115 }
116
116 if (testString.contains("metal")) { 117 if (testString.contains("metal")) {
117 return new MetalTweaker(dpiScaling); 118 return new MetalTweaker(dpiScaling);
118 } 119 }
120
119 if (testString.contains("nimbus")) { 121 if (testString.contains("nimbus")) {
120 return new NimbusTweaker(dpiScaling); 122 return new NimbusTweaker(dpiScaling);
121 } 123 }
124
122 return new BasicTweaker(dpiScaling); 125 return new BasicTweaker(dpiScaling);
123 } 126 }
124} 127}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/SingleTreeSelectionModel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/SingleTreeSelectionModel.java
index 8915264b..9d967b8c 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/SingleTreeSelectionModel.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/SingleTreeSelectionModel.java
@@ -4,8 +4,7 @@ import javax.swing.tree.DefaultTreeSelectionModel;
4import javax.swing.tree.TreeSelectionModel; 4import javax.swing.tree.TreeSelectionModel;
5 5
6public class SingleTreeSelectionModel extends DefaultTreeSelectionModel { 6public class SingleTreeSelectionModel extends DefaultTreeSelectionModel {
7 7 public SingleTreeSelectionModel() {
8 public SingleTreeSelectionModel() { 8 this.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
9 this.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); 9 }
10 }
11} 10}