summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Juuz2024-04-06 14:06:40 +0300
committerGravatar GitHub2024-04-06 12:06:40 +0100
commit3030b646ae58cc9448721f429ab5591fab4ca897 (patch)
tree041281fb190b011114d66d5f8f77cd2dd1e91f70
parentAdd Vineflower decompiler (#541) (diff)
downloadenigma-3030b646ae58cc9448721f429ab5591fab4ca897.tar.gz
enigma-3030b646ae58cc9448721f429ab5591fab4ca897.tar.xz
enigma-3030b646ae58cc9448721f429ab5591fab4ca897.zip
Add file extensions to open and save dialogs (#532)
* Add file extensions to Save As dialog * Include leading dots in file extensions for simplicity * Add file extensions to open mappings dialogs * Remove unused tinyMappingsFileChooser * Use the same file chooser for all mapping IO * Fix NPE by using Enigma directories as the default mapping format Fixes #533. * Fix code style * Allow .mappings extension for single Enigma files * gradlew.bat --------- Co-authored-by: NebelNidas <nebelnidas@gmail.com>
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java16
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java6
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java29
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/util/ExtensionFileFilter.java118
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java62
-rw-r--r--enigma/src/main/resources/lang/en_us.json1
6 files changed, 197 insertions, 35 deletions
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 11013153..05146d4a 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java
@@ -63,6 +63,7 @@ import cuchaz.enigma.gui.panels.IdentifierPanel;
63import cuchaz.enigma.gui.panels.ObfPanel; 63import cuchaz.enigma.gui.panels.ObfPanel;
64import cuchaz.enigma.gui.panels.StructurePanel; 64import cuchaz.enigma.gui.panels.StructurePanel;
65import cuchaz.enigma.gui.renderer.MessageListCellRenderer; 65import cuchaz.enigma.gui.renderer.MessageListCellRenderer;
66import cuchaz.enigma.gui.util.ExtensionFileFilter;
66import cuchaz.enigma.gui.util.GuiUtil; 67import cuchaz.enigma.gui.util.GuiUtil;
67import cuchaz.enigma.gui.util.LanguageUtil; 68import cuchaz.enigma.gui.util.LanguageUtil;
68import cuchaz.enigma.gui.util.ScaleUtil; 69import cuchaz.enigma.gui.util.ScaleUtil;
@@ -117,8 +118,7 @@ public class Gui {
117 private final JLabel connectionStatusLabel = new JLabel(); 118 private final JLabel connectionStatusLabel = new JLabel();
118 119
119 public final JFileChooser jarFileChooser = new JFileChooser(); 120 public final JFileChooser jarFileChooser = new JFileChooser();
120 public final JFileChooser tinyMappingsFileChooser = new JFileChooser(); 121 public final JFileChooser mappingsFileChooser = new JFileChooser();
121 public final JFileChooser enigmaMappingsFileChooser = new JFileChooser();
122 public final JFileChooser exportSourceFileChooser = new JFileChooser(); 122 public final JFileChooser exportSourceFileChooser = new JFileChooser();
123 public final JFileChooser exportJarFileChooser = new JFileChooser(); 123 public final JFileChooser exportJarFileChooser = new JFileChooser();
124 public SearchDialog searchDialog; 124 public SearchDialog searchDialog;
@@ -147,10 +147,6 @@ public class Gui {
147 147
148 private void setupUi() { 148 private void setupUi() {
149 this.jarFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); 149 this.jarFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
150 this.tinyMappingsFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
151
152 this.enigmaMappingsFileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
153 this.enigmaMappingsFileChooser.setAcceptAllFileFilterUsed(false);
154 150
155 this.exportSourceFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); 151 this.exportSourceFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
156 this.exportSourceFileChooser.setAcceptAllFileFilterUsed(false); 152 this.exportSourceFileChooser.setAcceptAllFileFilterUsed(false);
@@ -322,7 +318,7 @@ public class Gui {
322 } 318 }
323 319
324 public void setMappingsFile(Path path) { 320 public void setMappingsFile(Path path) {
325 this.enigmaMappingsFileChooser.setSelectedFile(path != null ? path.toFile() : null); 321 this.mappingsFileChooser.setSelectedFile(path != null ? path.toFile() : null);
326 updateUiState(); 322 updateUiState();
327 } 323 }
328 324
@@ -436,8 +432,10 @@ public class Gui {
436 } 432 }
437 433
438 public CompletableFuture<Void> saveMapping() { 434 public CompletableFuture<Void> saveMapping() {
439 if (this.enigmaMappingsFileChooser.getSelectedFile() != null || this.enigmaMappingsFileChooser.showSaveDialog(this.mainWindow.frame()) == JFileChooser.APPROVE_OPTION) { 435 ExtensionFileFilter.setupFileChooser(this.mappingsFileChooser, this.controller.getLoadedMappingFormat());
440 return this.controller.saveMappings(this.enigmaMappingsFileChooser.getSelectedFile().toPath()); 436
437 if (this.mappingsFileChooser.getSelectedFile() != null || this.mappingsFileChooser.showSaveDialog(this.mainWindow.frame()) == JFileChooser.APPROVE_OPTION) {
438 return this.controller.saveMappings(ExtensionFileFilter.getSavePath(this.mappingsFileChooser));
441 } 439 }
442 440
443 return CompletableFuture.completedFuture(null); 441 return CompletableFuture.completedFuture(null);
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 c5799019..ad10abfc 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java
@@ -99,7 +99,7 @@ public class GuiController implements ClientPacketHandler {
99 private IndexTreeBuilder indexTreeBuilder; 99 private IndexTreeBuilder indexTreeBuilder;
100 100
101 private Path loadedMappingPath; 101 private Path loadedMappingPath;
102 private MappingFormat loadedMappingFormat; 102 private MappingFormat loadedMappingFormat = MappingFormat.ENIGMA_DIRECTORY;
103 103
104 private ClassHandleProvider chp; 104 private ClassHandleProvider chp;
105 105
@@ -180,6 +180,10 @@ public class GuiController implements ClientPacketHandler {
180 chp.invalidateJavadoc(); 180 chp.invalidateJavadoc();
181 } 181 }
182 182
183 public MappingFormat getLoadedMappingFormat() {
184 return loadedMappingFormat;
185 }
186
183 public CompletableFuture<Void> saveMappings(Path path) { 187 public CompletableFuture<Void> saveMappings(Path path) {
184 return saveMappings(path, loadedMappingFormat); 188 return saveMappings(path, loadedMappingFormat);
185 } 189 }
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 30e35861..35129799 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
@@ -34,6 +34,7 @@ import cuchaz.enigma.gui.dialog.CreateServerDialog;
34import cuchaz.enigma.gui.dialog.FontDialog; 34import cuchaz.enigma.gui.dialog.FontDialog;
35import cuchaz.enigma.gui.dialog.SearchDialog; 35import cuchaz.enigma.gui.dialog.SearchDialog;
36import cuchaz.enigma.gui.dialog.StatsDialog; 36import cuchaz.enigma.gui.dialog.StatsDialog;
37import cuchaz.enigma.gui.util.ExtensionFileFilter;
37import cuchaz.enigma.gui.util.GuiUtil; 38import cuchaz.enigma.gui.util.GuiUtil;
38import cuchaz.enigma.gui.util.LanguageUtil; 39import cuchaz.enigma.gui.util.LanguageUtil;
39import cuchaz.enigma.gui.util.ScaleUtil; 40import cuchaz.enigma.gui.util.ScaleUtil;
@@ -175,7 +176,7 @@ public class MenuBar {
175 176
176 this.jarCloseItem.setEnabled(jarOpen); 177 this.jarCloseItem.setEnabled(jarOpen);
177 this.openMappingsMenu.setEnabled(jarOpen); 178 this.openMappingsMenu.setEnabled(jarOpen);
178 this.saveMappingsItem.setEnabled(jarOpen && this.gui.enigmaMappingsFileChooser.getSelectedFile() != null && connectionState != ConnectionState.CONNECTED); 179 this.saveMappingsItem.setEnabled(jarOpen && this.gui.mappingsFileChooser.getSelectedFile() != null && connectionState != ConnectionState.CONNECTED);
179 this.saveMappingsAsMenu.setEnabled(jarOpen); 180 this.saveMappingsAsMenu.setEnabled(jarOpen);
180 this.closeMappingsItem.setEnabled(jarOpen); 181 this.closeMappingsItem.setEnabled(jarOpen);
181 this.reloadMappingsItem.setEnabled(jarOpen); 182 this.reloadMappingsItem.setEnabled(jarOpen);
@@ -250,7 +251,7 @@ public class MenuBar {
250 } 251 }
251 252
252 private void onSaveMappingsClicked() { 253 private void onSaveMappingsClicked() {
253 this.gui.getController().saveMappings(this.gui.enigmaMappingsFileChooser.getSelectedFile().toPath()); 254 this.gui.getController().saveMappings(this.gui.mappingsFileChooser.getSelectedFile().toPath());
254 } 255 }
255 256
256 private void openMappingsDiscardPrompt(Runnable then) { 257 private void openMappingsDiscardPrompt(Runnable then) {
@@ -422,12 +423,13 @@ public class MenuBar {
422 private static void addOpenMappingsMenuEntry(String text, MappingFormat format, boolean mappingIo, JMenu openMappingsMenu, Gui gui) { 423 private static void addOpenMappingsMenuEntry(String text, MappingFormat format, boolean mappingIo, JMenu openMappingsMenu, Gui gui) {
423 JMenuItem item = new JMenuItem(text); 424 JMenuItem item = new JMenuItem(text);
424 item.addActionListener(event -> { 425 item.addActionListener(event -> {
425 gui.enigmaMappingsFileChooser.setCurrentDirectory(new File(UiConfig.getLastSelectedDir())); 426 ExtensionFileFilter.setupFileChooser(gui.mappingsFileChooser, format);
427 gui.mappingsFileChooser.setCurrentDirectory(new File(UiConfig.getLastSelectedDir()));
426 428
427 if (gui.enigmaMappingsFileChooser.showOpenDialog(gui.getFrame()) == JFileChooser.APPROVE_OPTION) { 429 if (gui.mappingsFileChooser.showOpenDialog(gui.getFrame()) == JFileChooser.APPROVE_OPTION) {
428 File selectedFile = gui.enigmaMappingsFileChooser.getSelectedFile(); 430 File selectedFile = gui.mappingsFileChooser.getSelectedFile();
429 gui.getController().openMappings(format, selectedFile.toPath(), mappingIo); 431 gui.getController().openMappings(format, selectedFile.toPath(), mappingIo);
430 UiConfig.setLastSelectedDir(gui.enigmaMappingsFileChooser.getCurrentDirectory().toString()); 432 UiConfig.setLastSelectedDir(gui.mappingsFileChooser.getCurrentDirectory().toString());
431 } 433 }
432 }); 434 });
433 openMappingsMenu.add(item); 435 openMappingsMenu.add(item);
@@ -453,15 +455,18 @@ public class MenuBar {
453 private static void addSaveMappingsAsMenuEntry(String text, MappingFormat format, boolean mappingIo, JMenu saveMappingsAsMenu, JMenuItem saveMappingsItem, Gui gui) { 455 private static void addSaveMappingsAsMenuEntry(String text, MappingFormat format, boolean mappingIo, JMenu saveMappingsAsMenu, JMenuItem saveMappingsItem, Gui gui) {
454 JMenuItem item = new JMenuItem(text); 456 JMenuItem item = new JMenuItem(text);
455 item.addActionListener(event -> { 457 item.addActionListener(event -> {
456 // TODO: Use a specific file chooser for it 458 JFileChooser fileChooser = gui.mappingsFileChooser;
457 if (gui.enigmaMappingsFileChooser.getCurrentDirectory() == null) { 459 ExtensionFileFilter.setupFileChooser(fileChooser, format);
458 gui.enigmaMappingsFileChooser.setCurrentDirectory(new File(UiConfig.getLastSelectedDir())); 460
461 if (fileChooser.getCurrentDirectory() == null) {
462 fileChooser.setCurrentDirectory(new File(UiConfig.getLastSelectedDir()));
459 } 463 }
460 464
461 if (gui.enigmaMappingsFileChooser.showSaveDialog(gui.getFrame()) == JFileChooser.APPROVE_OPTION) { 465 if (fileChooser.showSaveDialog(gui.getFrame()) == JFileChooser.APPROVE_OPTION) {
462 gui.getController().saveMappings(gui.enigmaMappingsFileChooser.getSelectedFile().toPath(), format, mappingIo); 466 Path savePath = ExtensionFileFilter.getSavePath(fileChooser);
467 gui.getController().saveMappings(savePath, format, mappingIo);
463 saveMappingsItem.setEnabled(true); 468 saveMappingsItem.setEnabled(true);
464 UiConfig.setLastSelectedDir(gui.enigmaMappingsFileChooser.getCurrentDirectory().toString()); 469 UiConfig.setLastSelectedDir(fileChooser.getCurrentDirectory().toString());
465 } 470 }
466 }); 471 });
467 saveMappingsAsMenu.add(item); 472 saveMappingsAsMenu.add(item);
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/ExtensionFileFilter.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/ExtensionFileFilter.java
new file mode 100644
index 00000000..a514cae5
--- /dev/null
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/ExtensionFileFilter.java
@@ -0,0 +1,118 @@
1package cuchaz.enigma.gui.util;
2
3import java.io.File;
4import java.nio.file.Path;
5import java.util.List;
6import java.util.Locale;
7import java.util.StringJoiner;
8
9import javax.swing.JFileChooser;
10import javax.swing.filechooser.FileFilter;
11
12import cuchaz.enigma.translation.mapping.serde.MappingFormat;
13import cuchaz.enigma.utils.I18n;
14
15public final class ExtensionFileFilter extends FileFilter {
16 private final String formatName;
17 private final List<String> extensions;
18
19 /**
20 * Constructs an {@code ExtensionFileFilter}.
21 *
22 * @param formatName the human-readable name of the file format
23 * @param extensions the file extensions with their leading dots (e.g. {@code .txt})
24 */
25 public ExtensionFileFilter(String formatName, List<String> extensions) {
26 this.formatName = formatName;
27 this.extensions = extensions;
28 }
29
30 public List<String> getExtensions() {
31 return extensions;
32 }
33
34 @Override
35 public boolean accept(File f) {
36 // Always accept directories so the user can see them.
37 if (f.isDirectory()) {
38 return true;
39 }
40
41 for (String extension : extensions) {
42 if (f.getName().endsWith(extension)) {
43 return true;
44 }
45 }
46
47 return false;
48 }
49
50 @Override
51 public String getDescription() {
52 var joiner = new StringJoiner(", ");
53
54 for (String extension : extensions) {
55 joiner.add("*" + extension);
56 }
57
58 return I18n.translateFormatted("menu.file.mappings.file_filter", formatName, joiner.toString());
59 }
60
61 /**
62 * Sets up a file chooser with a mapping format. This method resets the choosable filters,
63 * and adds and selects a new filter based on the provided mapping format.
64 *
65 * @param fileChooser the mapping format
66 */
67 public static void setupFileChooser(JFileChooser fileChooser, MappingFormat format) {
68 // Remove previous custom filters.
69 fileChooser.resetChoosableFileFilters();
70
71 if (format.getFileType().isDirectory()) {
72 fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
73 } else {
74 fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
75 String formatName = I18n.translate("mapping_format." + format.name().toLowerCase(Locale.ROOT));
76 var filter = new ExtensionFileFilter(formatName, format.getFileType().extensions());
77 // Add our new filter to the list...
78 fileChooser.addChoosableFileFilter(filter);
79 // ...and choose it as the default.
80 fileChooser.setFileFilter(filter);
81 }
82 }
83
84 /**
85 * Fixes a missing file extension in a save file path when the selected filter
86 * is an {@code ExtensionFileFilter}.
87 *
88 * @param fileChooser the file chooser to check
89 * @return the fixed path
90 */
91 public static Path getSavePath(JFileChooser fileChooser) {
92 Path savePath = fileChooser.getSelectedFile().toPath();
93
94 if (fileChooser.getFileFilter() instanceof ExtensionFileFilter extensionFilter) {
95 // Check that the file name ends with the extension.
96 String fileName = savePath.getFileName().toString();
97 boolean hasExtension = false;
98
99 for (String extension : extensionFilter.getExtensions()) {
100 if (fileName.endsWith(extension)) {
101 hasExtension = true;
102 break;
103 }
104 }
105
106 if (!hasExtension) {
107 String defaultExtension = extensionFilter.getExtensions().get(0);
108 // If not, add the extension.
109 savePath = savePath.resolveSibling(fileName + defaultExtension);
110 // Store the adjusted file, so that it shows up properly
111 // the next time this dialog is used.
112 fileChooser.setSelectedFile(savePath.toFile());
113 }
114 }
115
116 return savePath;
117 }
118}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java
index 4521591e..aeac9db4 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java
@@ -33,28 +33,30 @@ import cuchaz.enigma.translation.mapping.tree.EntryTree;
33import cuchaz.enigma.utils.I18n; 33import cuchaz.enigma.utils.I18n;
34 34
35public enum MappingFormat { 35public enum MappingFormat {
36 ENIGMA_FILE(EnigmaMappingsWriter.FILE, EnigmaMappingsReader.FILE, net.fabricmc.mappingio.format.MappingFormat.ENIGMA_FILE, true), 36 ENIGMA_FILE(EnigmaMappingsWriter.FILE, EnigmaMappingsReader.FILE, FileType.MAPPING, net.fabricmc.mappingio.format.MappingFormat.ENIGMA_FILE, true),
37 ENIGMA_DIRECTORY(EnigmaMappingsWriter.DIRECTORY, EnigmaMappingsReader.DIRECTORY, net.fabricmc.mappingio.format.MappingFormat.ENIGMA_DIR, true), 37 ENIGMA_DIRECTORY(EnigmaMappingsWriter.DIRECTORY, EnigmaMappingsReader.DIRECTORY, FileType.DIRECTORY, net.fabricmc.mappingio.format.MappingFormat.ENIGMA_DIR, true),
38 ENIGMA_ZIP(EnigmaMappingsWriter.ZIP, EnigmaMappingsReader.ZIP, null, false), 38 ENIGMA_ZIP(EnigmaMappingsWriter.ZIP, EnigmaMappingsReader.ZIP, FileType.ZIP, null, false),
39 TINY_V2(new TinyV2Writer("intermediary", "named"), new TinyV2Reader(), net.fabricmc.mappingio.format.MappingFormat.TINY_2_FILE, true), 39 TINY_V2(new TinyV2Writer("intermediary", "named"), new TinyV2Reader(), FileType.TINY, net.fabricmc.mappingio.format.MappingFormat.TINY_2_FILE, true),
40 TINY_FILE(TinyMappingsWriter.INSTANCE, TinyMappingsReader.INSTANCE, net.fabricmc.mappingio.format.MappingFormat.TINY_FILE, true), 40 TINY_FILE(TinyMappingsWriter.INSTANCE, TinyMappingsReader.INSTANCE, FileType.TINY, net.fabricmc.mappingio.format.MappingFormat.TINY_FILE, true),
41 SRG_FILE(SrgMappingsWriter.INSTANCE, null, net.fabricmc.mappingio.format.MappingFormat.SRG_FILE, true), 41 SRG_FILE(SrgMappingsWriter.INSTANCE, null, FileType.SRG, net.fabricmc.mappingio.format.MappingFormat.SRG_FILE, true),
42 XSRG_FILE(null, null, net.fabricmc.mappingio.format.MappingFormat.XSRG_FILE, true), 42 XSRG_FILE(null, null, FileType.XSRG, net.fabricmc.mappingio.format.MappingFormat.XSRG_FILE, true),
43 CSRG_FILE(null, null, net.fabricmc.mappingio.format.MappingFormat.CSRG_FILE, false), 43 CSRG_FILE(null, null, FileType.CSRG, net.fabricmc.mappingio.format.MappingFormat.CSRG_FILE, false),
44 TSRG_FILE(null, null, net.fabricmc.mappingio.format.MappingFormat.TSRG_FILE, false), 44 TSRG_FILE(null, null, FileType.TSRG, net.fabricmc.mappingio.format.MappingFormat.TSRG_FILE, false),
45 TSRG_2_FILE(null, null, net.fabricmc.mappingio.format.MappingFormat.TSRG_2_FILE, false), 45 TSRG_2_FILE(null, null, FileType.TSRG, net.fabricmc.mappingio.format.MappingFormat.TSRG_2_FILE, false),
46 PROGUARD(null, ProguardMappingsReader.INSTANCE, net.fabricmc.mappingio.format.MappingFormat.PROGUARD_FILE, true), 46 PROGUARD(null, ProguardMappingsReader.INSTANCE, FileType.TXT, net.fabricmc.mappingio.format.MappingFormat.PROGUARD_FILE, true),
47 RECAF(RecafMappingsWriter.INSTANCE, RecafMappingsReader.INSTANCE, null, false); 47 RECAF(RecafMappingsWriter.INSTANCE, RecafMappingsReader.INSTANCE, FileType.TXT, null, false);
48 48
49 private final MappingsWriter writer; 49 private final MappingsWriter writer;
50 private final MappingsReader reader; 50 private final MappingsReader reader;
51 private final FileType fileType;
51 private final net.fabricmc.mappingio.format.MappingFormat mappingIoCounterpart; 52 private final net.fabricmc.mappingio.format.MappingFormat mappingIoCounterpart;
52 private final boolean hasMappingIoWriter; 53 private final boolean hasMappingIoWriter;
53 private boolean lastUsedMappingIoWriter; 54 private boolean lastUsedMappingIoWriter;
54 55
55 MappingFormat(MappingsWriter writer, MappingsReader reader, net.fabricmc.mappingio.format.MappingFormat mappingIoCounterpart, boolean hasMappingIoWriter) { 56 MappingFormat(MappingsWriter writer, MappingsReader reader, FileType fileType, net.fabricmc.mappingio.format.MappingFormat mappingIoCounterpart, boolean hasMappingIoWriter) {
56 this.writer = writer; 57 this.writer = writer;
57 this.reader = reader; 58 this.reader = reader;
59 this.fileType = fileType;
58 this.mappingIoCounterpart = mappingIoCounterpart; 60 this.mappingIoCounterpart = mappingIoCounterpart;
59 this.hasMappingIoWriter = hasMappingIoWriter; 61 this.hasMappingIoWriter = hasMappingIoWriter;
60 } 62 }
@@ -126,6 +128,11 @@ public enum MappingFormat {
126 return reader; 128 return reader;
127 } 129 }
128 130
131 @ApiStatus.Internal
132 public FileType getFileType() {
133 return fileType;
134 }
135
129 @Nullable 136 @Nullable
130 @ApiStatus.Internal 137 @ApiStatus.Internal
131 public net.fabricmc.mappingio.format.MappingFormat getMappingIoCounterpart() { 138 public net.fabricmc.mappingio.format.MappingFormat getMappingIoCounterpart() {
@@ -164,4 +171,33 @@ public enum MappingFormat {
164 .filter(MappingFormat::isWritable) 171 .filter(MappingFormat::isWritable)
165 .toList(); 172 .toList();
166 } 173 }
174
175 /**
176 * A file type. It can be either a single file with an extension, or a directory
177 * with a {@code null} extension.
178 *
179 * <p>If a file type has multiple extensions, the default for saving will be the first one.
180 *
181 * @param extensions the file extensions with the leading dot {@code .}, or an empty list for a directory
182 */
183 @ApiStatus.Internal
184 public record FileType(List<String> extensions) {
185 public static final FileType DIRECTORY = new FileType();
186 public static final FileType MAPPING = new FileType(".mapping", ".mappings");
187 public static final FileType SRG = new FileType(".srg");
188 public static final FileType XSRG = new FileType(".xsrg");
189 public static final FileType CSRG = new FileType(".csrg");
190 public static final FileType TSRG = new FileType(".tsrg");
191 public static final FileType TINY = new FileType(".tiny");
192 public static final FileType TXT = new FileType(".txt");
193 public static final FileType ZIP = new FileType(".zip");
194
195 public FileType(String... extensions) {
196 this(List.of(extensions));
197 }
198
199 public boolean isDirectory() {
200 return extensions.isEmpty();
201 }
202 }
167} 203}
diff --git a/enigma/src/main/resources/lang/en_us.json b/enigma/src/main/resources/lang/en_us.json
index 2a3cfb2d..42228144 100644
--- a/enigma/src/main/resources/lang/en_us.json
+++ b/enigma/src/main/resources/lang/en_us.json
@@ -22,6 +22,7 @@
22 "menu.file.mappings.save_as": "Save Mappings As...", 22 "menu.file.mappings.save_as": "Save Mappings As...",
23 "menu.file.mappings.close": "Close Mappings", 23 "menu.file.mappings.close": "Close Mappings",
24 "menu.file.mappings.drop": "Drop Invalid Mappings", 24 "menu.file.mappings.drop": "Drop Invalid Mappings",
25 "menu.file.mappings.file_filter": "%s (%s)",
25 "menu.file.reload_mappings": "Reload Mappings", 26 "menu.file.reload_mappings": "Reload Mappings",
26 "menu.file.reload_all": "Reload Jar/Mappings", 27 "menu.file.reload_all": "Reload Jar/Mappings",
27 "menu.file.export.source": "Export Source...", 28 "menu.file.export.source": "Export Source...",