diff --git a/jadx-gui/libs/mapping-io-0.4.0-SNAPSHOT.jar b/jadx-gui/libs/mapping-io-0.4.0-SNAPSHOT.jar index c5cf62872025eb472af471632b554ff539c4d875..d06bcd83664e83c3525ca5ba3ff71ee3121be713 100644 Binary files a/jadx-gui/libs/mapping-io-0.4.0-SNAPSHOT.jar and b/jadx-gui/libs/mapping-io-0.4.0-SNAPSHOT.jar differ diff --git a/jadx-gui/src/main/java/jadx/gui/settings/JadxProject.java b/jadx-gui/src/main/java/jadx/gui/settings/JadxProject.java index f45e651377fdcb3509d297cd12a98e5c9f229488..7555ee435b547b4f809fcd9f78688582a6730388 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/JadxProject.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/JadxProject.java @@ -57,6 +57,18 @@ public class JadxProject { this.mainWindow = mainWindow; } + public @Nullable Path getWorkingDir() { + if (projectPath != null) { + return projectPath.toAbsolutePath().getParent(); + } + List files = data.getFiles(); + if (!files.isEmpty()) { + Path path = files.get(0); + return path.toAbsolutePath().getParent(); + } + return null; + } + @Nullable public Path getProjectPath() { return projectPath; @@ -166,7 +178,7 @@ public class JadxProject { Path path = files.get(0); return path.resolveSibling(path.getFileName() + ".cache"); } - throw new JadxRuntimeException("Can't get working dir"); + throw new JadxRuntimeException("Failed to build cache dir"); } public boolean isEnableLiveReload() { diff --git a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java index 01ea5ab82f9548a172bf351247a61f1f71d04ced..71a52f1715dd09381c0063bb066d64bf2ba462ad 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -44,6 +44,7 @@ import javax.swing.Action; import javax.swing.Box; import javax.swing.ImageIcon; import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; @@ -85,7 +86,6 @@ import jadx.api.JavaNode; import jadx.api.ResourceFile; import jadx.api.plugins.utils.CommonFileUtils; import jadx.core.Jadx; -import jadx.core.dex.nodes.RootNode; import jadx.core.utils.ListUtils; import jadx.core.utils.StringUtils; import jadx.core.utils.files.FileUtils; @@ -362,17 +362,28 @@ public class MainWindow extends JFrame { } private void exportMappings(MappingFormat mappingFormat) { - RootNode rootNode = wrapper.getDecompiler().getRoot(); - - Thread exportThread = new Thread(() -> { - new MappingExporter(rootNode).exportMappings( - Paths.get(project.getProjectPath().getParent().toString(), - "mappings" + (mappingFormat.hasSingleFile() ? "." + mappingFormat.fileExt : "")), - project.getCodeData(), mappingFormat); - }); - - backgroundExecutor.execute(NLS.str("progress.export_mappings"), exportThread); - update(); + FileDialog fileDialog = new FileDialog(this, FileDialog.OpenMode.CUSTOM_SAVE); + fileDialog.setTitle(NLS.str("file.export_mappings_as")); + Path workingDir = project.getWorkingDir(); + Path baseDir = workingDir != null ? workingDir : settings.getLastSaveFilePath(); + if (mappingFormat.hasSingleFile()) { + fileDialog.setSelectedFile(baseDir.resolve("mappings." + mappingFormat.fileExt)); + fileDialog.setFileExtList(Collections.singletonList(mappingFormat.fileExt)); + fileDialog.setSelectionMode(JFileChooser.FILES_ONLY); + } else { + fileDialog.setCurrentDir(baseDir); + fileDialog.setSelectionMode(JFileChooser.DIRECTORIES_ONLY); + } + List paths = fileDialog.show(); + if (paths.size() != 1) { + return; + } + Path savePath = paths.get(0); + LOG.info("Export mappings to: {}", savePath.toAbsolutePath()); + backgroundExecutor.execute(NLS.str("progress.export_mappings"), + () -> new MappingExporter(wrapper.getDecompiler().getRoot()) + .exportMappings(savePath, project.getCodeData(), mappingFormat), + s -> update()); } void open(List paths) { diff --git a/jadx-gui/src/main/java/jadx/gui/ui/dialog/FileDialog.java b/jadx-gui/src/main/java/jadx/gui/ui/dialog/FileDialog.java index 4bbaf772b2590b83fe4631853524bfd81b8bfe29..f3d7ced0f3d4817084cb2eb2b4f12aa5b7e405e3 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/dialog/FileDialog.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/dialog/FileDialog.java @@ -27,7 +27,12 @@ import jadx.gui.utils.NLS; public class FileDialog { public enum OpenMode { - OPEN, ADD, SAVE_PROJECT, EXPORT + OPEN, + ADD, + SAVE_PROJECT, + EXPORT, + CUSTOM_SAVE, + CUSTOM_OPEN } private final MainWindow mainWindow; @@ -44,6 +49,26 @@ public class FileDialog { initForMode(mode); } + public void setTitle(String title) { + this.title = title; + } + + public void setFileExtList(List fileExtList) { + this.fileExtList = fileExtList; + } + + public void setSelectionMode(int selectionMode) { + this.selectionMode = selectionMode; + } + + public void setSelectedFile(Path path) { + this.selectedFile = path; + } + + public void setCurrentDir(Path currentDir) { + this.currentDir = currentDir; + } + public List show() { FileChooser fileChooser = buildFileChooser(); int ret = isOpen ? fileChooser.showOpenDialog(mainWindow) : fileChooser.showSaveDialog(mainWindow); @@ -66,10 +91,6 @@ public class FileDialog { return currentDir; } - public void setSelectedFile(Path path) { - this.selectedFile = path; - } - private void initForMode(OpenMode mode) { switch (mode) { case OPEN: @@ -101,6 +122,14 @@ public class FileDialog { currentDir = mainWindow.getSettings().getLastSaveFilePath(); isOpen = false; break; + + case CUSTOM_SAVE: + isOpen = false; + break; + + case CUSTOM_OPEN: + isOpen = true; + break; } } @@ -110,7 +139,7 @@ public class FileDialog { fileChooser.setFileSelectionMode(selectionMode); fileChooser.setMultiSelectionEnabled(isOpen); fileChooser.setAcceptAllFileFilterUsed(true); - if (!fileExtList.isEmpty()) { + if (Utils.notEmpty(fileExtList)) { String description = NLS.str("file_dialog.supported_files") + ": (" + Utils.listToString(fileExtList) + ')'; fileChooser.setFileFilter(new FileNameExtensionFilter(description, fileExtList.toArray(new String[0]))); }