summaryrefslogtreecommitdiff
path: root/enigma-swing/src/main/java/cuchaz/enigma/gui/Main.java
blob: dc58464cebe97c807fa4db41699440d04b3a2893 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/*******************************************************************************
* Copyright (c) 2015 Jeff Martin.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public
* License v3.0 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl.html
*
* <p>Contributors:
* Jeff Martin - initial API and implementation
******************************************************************************/

package cuchaz.enigma.gui;

import java.awt.Toolkit;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;

import joptsimple.OptionException;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import joptsimple.OptionSpec;
import joptsimple.ValueConverter;

import cuchaz.enigma.EnigmaProfile;
import cuchaz.enigma.gui.config.Themes;
import cuchaz.enigma.gui.config.UiConfig;
import cuchaz.enigma.gui.dialog.CrashDialog;
import cuchaz.enigma.translation.mapping.serde.MappingFormat;
import cuchaz.enigma.utils.I18n;

public class Main {
	public static void main(String[] args) throws IOException {
		OptionParser parser = new OptionParser();

		OptionSpec<Path> jar = parser.accepts("jar", "Jar file to open at startup; if there are multiple jars, the order must be the same between all collab session members").withRequiredArg().withValuesConvertedBy(PathConverter.INSTANCE);

		OptionSpec<Path> mappings = parser.accepts("mappings", "Mappings file to open at startup").withRequiredArg().withValuesConvertedBy(PathConverter.INSTANCE);

		OptionSpec<Path> profile = parser.accepts("profile", "Profile json to apply at startup").withRequiredArg().withValuesConvertedBy(PathConverter.INSTANCE);

		parser.acceptsAll(List.of("edit-all", "e"), "Enable editing everything");
		parser.acceptsAll(List.of("no-edit-all", "E"), "Disable editing everything");
		parser.acceptsAll(List.of("edit-classes", "c"), "Enable editing class names");
		parser.acceptsAll(List.of("no-edit-classes", "C"), "Disable editing class names");
		parser.acceptsAll(List.of("edit-methods", "m"), "Enable editing method names");
		parser.acceptsAll(List.of("no-edit-methods", "M"), "Disable editing method names");
		parser.acceptsAll(List.of("edit-fields", "f"), "Enable editing field names");
		parser.acceptsAll(List.of("no-edit-fields", "F"), "Disable editing field names");
		parser.acceptsAll(List.of("edit-parameters", "p"), "Enable editing parameter names");
		parser.acceptsAll(List.of("no-edit-parameters", "P"), "Disable editing parameter names");
		parser.acceptsAll(List.of("edit-locals"), "Enable editing local variable names");
		parser.acceptsAll(List.of("no-edit-locals"), "Disable editing local variable names");
		parser.acceptsAll(List.of("edit-javadocs", "d"), "Enable editing Javadocs");
		parser.acceptsAll(List.of("no-edit-javadocs", "D"), "Disable editing Javadocs");

		parser.accepts("single-class-tree", "Unify the deobfuscated and obfuscated class panels");

		parser.accepts("help", "Displays help information");

		try {
			OptionSet options = parser.parse(args);

			if (options.has("help")) {
				parser.printHelpOn(System.out);
				return;
			}

			Set<EditableType> editables = EnumSet.allOf(EditableType.class);

			for (OptionSpec<?> spec : options.specs()) {
				for (String s : spec.options()) {
					switch (s) {
					case "edit-all" -> editables.addAll(List.of(EditableType.values()));
					case "no-edit-all" -> editables.clear();
					case "edit-classes" -> editables.add(EditableType.CLASS);
					case "no-edit-classes" -> editables.remove(EditableType.CLASS);
					case "edit-methods" -> editables.add(EditableType.METHOD);
					case "no-edit-methods" -> editables.remove(EditableType.METHOD);
					case "edit-fields" -> editables.add(EditableType.FIELD);
					case "no-edit-fields" -> editables.remove(EditableType.FIELD);
					case "edit-parameters" -> editables.add(EditableType.PARAMETER);
					case "no-edit-parameters" -> editables.remove(EditableType.PARAMETER);
					case "edit-locals" -> {
						editables.add(EditableType.LOCAL_VARIABLE);
						System.err.println("warning: --edit-locals has no effect as local variables are currently not editable");
					}
					case "no-edit-locals" -> {
						editables.remove(EditableType.LOCAL_VARIABLE);
						System.err.println("warning: --no-edit-locals has no effect as local variables are currently not editable");
					}
					case "edit-javadocs" -> editables.add(EditableType.JAVADOC);
					case "no-edit-javadocs" -> editables.remove(EditableType.JAVADOC);
					}
				}
			}

			EnigmaProfile parsedProfile = EnigmaProfile.read(options.valueOf(profile));

			I18n.setLanguage(UiConfig.getLanguage());

			// Provide fallback anti-aliasing for desktop environments the JRE doesn't recognize
			if (Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints") == null) {
				setDefaultSystemProperty("awt.useSystemAAFontSettings", "lcd");
			}

			// Not setting "swing.aatext" here because that property has been removed:
			// https://bugs.openjdk.org/browse/JDK-6391267

			// If on MacOS, use the system's menu bar, not the in-app one
			setDefaultSystemProperty("apple.laf.useScreenMenuBar", "true");

			Themes.setupTheme();

			Gui gui = new Gui(parsedProfile, editables);
			GuiController controller = gui.getController();

			if (options.has("single-class-tree")) {
				gui.setSingleClassTree(true);
			}

			if (Boolean.parseBoolean(System.getProperty("enigma.catchExceptions", "true"))) {
				// install a global exception handler to the event thread
				CrashDialog.init(gui.getFrame());
				Thread.setDefaultUncaughtExceptionHandler((thread, t) -> {
					t.printStackTrace(System.err);

					if (!ExceptionIgnorer.shouldIgnore(t)) {
						CrashDialog.show(t);
					}
				});
			}

			if (options.has(jar)) {
				List<Path> jarPaths = options.valuesOf(jar);
				controller.openJar(jarPaths).whenComplete((v, t) -> {
					if (options.has(mappings)) {
						Path mappingsPath = options.valueOf(mappings);

						if (Files.isDirectory(mappingsPath)) {
							controller.openMappings(MappingFormat.ENIGMA_DIRECTORY, mappingsPath);
						} else if (mappingsPath.getFileName().toString().toLowerCase().endsWith(".zip")) {
							controller.openMappings(MappingFormat.ENIGMA_ZIP, mappingsPath);
						} else {
							controller.openMappings(MappingFormat.ENIGMA_FILE, mappingsPath);
						}
					}
				});
			}
		} catch (OptionException e) {
			System.out.println("Invalid arguments: " + e.getMessage());
			System.out.println();
			parser.printHelpOn(System.out);
		}
	}

	private static void setDefaultSystemProperty(String property, String value) {
		System.setProperty(property, System.getProperty(property, value));
	}

	public static class PathConverter implements ValueConverter<Path> {
		public static final ValueConverter<Path> INSTANCE = new PathConverter();

		PathConverter() {
		}

		@Override
		public Path convert(String path) {
			// expand ~ to the home dir
			if (path.startsWith("~")) {
				// get the home dir
				Path dirHome = Paths.get(System.getProperty("user.home"));

				// is the path just ~/ or is it ~user/ ?
				if (path.startsWith("~/")) {
					return dirHome.resolve(path.substring(2));
				} else {
					return dirHome.getParent().resolve(path.substring(1));
				}
			}

			return Paths.get(path);
		}

		@Override
		public Class<? extends Path> valueType() {
			return Path.class;
		}

		@Override
		public String valuePattern() {
			return "path";
		}
	}
}