From b7ca51c7da90d5e7857cb35267430bc52969a9d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sun, 22 Sep 2024 21:45:54 +0200 Subject: [PATCH] Added #2306 Export to VS Code project --- CHANGELOG.md | 2 + .../exporters/swf/SwfVsCodeExporter.java | 417 ++++++++++++++++++ .../decompiler/flash/gui/MainFrameMenu.java | 22 +- .../jpexs/decompiler/flash/gui/MainPanel.java | 74 ++++ .../flash/gui/graphics/exportvscode16.png | Bin 0 -> 5828 bytes .../flash/gui/graphics/exportvscode32.png | Bin 0 -> 7985 bytes .../flash/gui/locales/MainFrame.properties | 15 +- .../flash/gui/tagtree/TagTreeContextMenu.java | 17 + 8 files changed, 540 insertions(+), 7 deletions(-) create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/swf/SwfVsCodeExporter.java create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/exportvscode16.png create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/exportvscode32.png diff --git a/CHANGELOG.md b/CHANGELOG.md index f4c4f231f..33d1e267b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. - FLA export - generating bin/*.dat files for movies and images - [#943], [#1812], [#2287] Export to older binary FLA formats (CS4, CS3, Flash 8, MX 2004, MX, Flash 5) - [#2286] Set SWF version in FlashDevelop project +- [#2306] Export to VS Code project ### Changed - [#1644] Swapped Save all and Save buttons - Save is bigger @@ -3560,6 +3561,7 @@ Major version of SWF to XML export changed to 2. [#1812]: https://www.free-decompiler.com/flash/issues/1812 [#2287]: https://www.free-decompiler.com/flash/issues/2287 [#2286]: https://www.free-decompiler.com/flash/issues/2286 +[#2306]: https://www.free-decompiler.com/flash/issues/2306 [#1644]: https://www.free-decompiler.com/flash/issues/1644 [#2309]: https://www.free-decompiler.com/flash/issues/2309 [#2300]: https://www.free-decompiler.com/flash/issues/2300 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/swf/SwfVsCodeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/swf/SwfVsCodeExporter.java new file mode 100644 index 000000000..2176cfdb6 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/swf/SwfVsCodeExporter.java @@ -0,0 +1,417 @@ +/* + * Copyright (C) 2010-2024 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.exporters.swf; + +import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; +import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.FlashPlayerVersion; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.exporters.settings.ScriptExportSettings; +import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag; +import com.jpexs.decompiler.flash.tags.SoundStreamBlockTag; +import com.jpexs.decompiler.flash.tags.StartSound2Tag; +import com.jpexs.decompiler.flash.tags.StartSoundTag; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.VideoFrameTag; +import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; +import com.jpexs.helpers.utf8.Utf8Helper; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +/** + * Exports SWF to FlashDevelop project. + * + * @author JPEXS + */ +public class SwfVsCodeExporter { + + public static boolean canExportSwf(SWF swf) { + if (!swf.isAS3()) { + return false; + } + //Cannot export if it has something on main timeline + for (Tag t : swf.getTags()) { + if ((t instanceof PlaceObjectTypeTag) + || (t instanceof SoundStreamBlockTag) + || (t instanceof VideoFrameTag) + || (t instanceof StartSoundTag) + || (t instanceof StartSound2Tag)) { + return false; + } + } + return true; + } + + private static String doubleToString(double d) { + String ds = "" + d; + if (ds.endsWith(".0")) { + ds = ds.substring(0, ds.length() - 2); + } + return ds; + } + + /** + * Exports SWF to FlashDevelop project. + * + * @param swf SWF to export + * @param outDir Output file + * @param air + * @param handler Handler for abort, retry, ignore + * @throws IOException On I/O error + */ + public void exportVsCodeProject(SWF swf, File outDir, boolean air, AbortRetryIgnoreHandler handler) throws IOException { + exportVsCodeProject(swf, outDir, air, handler, null); + } + + /** + * Exports SWF to FlashDevelop project. + * + * @param swf SWF to export + * @param outDir Output file + * @param air AIR + * @param handler Handler for abort, retry, ignore + * @param eventListener Event listener + * @throws IOException On I/O error + */ + public void exportVsCodeProject(SWF swf, File outDir, boolean air, AbortRetryIgnoreHandler handler, EventListener eventListener) throws IOException { + if (!swf.isAS3()) { + throw new IllegalArgumentException("SWF must be AS3"); + } + + if (!canExportSwf(swf)) { + throw new IllegalArgumentException("SWF must not contain main timeline"); + } + + String simpleName = outDir.getName(); + if (simpleName.contains(".")) { + simpleName = simpleName.substring(0, simpleName.lastIndexOf(".")); + } + + String simpleNameNoSpaces = simpleName.replace(" ", "").replace("_", ""); + + SetBackgroundColorTag bgColorTag = swf.getBackgroundColor(); + + String documentClass = swf.getDocumentClass(); + + String srcPath = "src"; + String project; + + String flashPlayerVersion = FlashPlayerVersion.getFlashPlayerBySwfVersion(swf.version); + String[] flashPlayerVersions = flashPlayerVersion.split("\\."); + + String airVersion = FlashPlayerVersion.getAirBySwfVersion(swf.version); + String[] airVersions = airVersion.split("\\."); + + project = "{\n" + + " \"config\": \"air\",\n" + + " \"compilerOptions\": {\n" + + " \"source-path\": [\n" + + " \"src\"\n" + + " ],\n" + + " \"library-path\": [\n" + + " \"libs\"\n" + + " ],\n" + + " \"output\": \"bin/"+simpleNameNoSpaces+".swf\",\n" + + " \"default-background-color\": \"" + (bgColorTag == null ? "#FFFFFF" : bgColorTag.backgroundColor.toHexRGB()) + "\",\n" + + " \"default-frame-rate\": " + doubleToString(swf.frameRate) + ",\n" + + " \"default-size\": {\n" + + " \"width\": " + doubleToString(swf.displayRect.getWidth() / SWF.unitDivisor) + ",\n" + + " \"height\": " + doubleToString(swf.displayRect.getWidth() / SWF.unitDivisor) + "\n" + + " },\n" + + " \"swf-version\": " + swf.version + "\n" + // + + " },\n" + + " \"application\": \"src/"+simpleNameNoSpaces+"-app.xml\",\n" + + " \"mainClass\": \"" + documentClass +"\"\n" + + "}"; + + try (FileOutputStream fos = new FileOutputStream(outDir.toPath().resolve("asconfig.json").toFile())) { + fos.write(Utf8Helper.getBytes(project)); + } + + File vscodeDir = outDir.toPath().resolve(".vscode").toFile(); + vscodeDir.mkdirs(); + + String launch = "{\n" + +" \"version\": \"0.2.0\",\n" + +" \"configurations\": [\n" + +" {\n" + +" \"type\": \"swf\",\n" + +" \"request\": \"launch\",\n" + +" \"name\": \"Launch SWF\"\n" + +" }\n" + +" ]\n" + +"}"; + try (FileOutputStream fos = new FileOutputStream(vscodeDir.toPath().resolve("launch.json").toFile())) { + fos.write(Utf8Helper.getBytes(launch)); + } + + String settings = "{\n" + +" \"as3mxml.sdk.framework\": \"c:\\\\flex\"\n" + +"}"; + try (FileOutputStream fos = new FileOutputStream(vscodeDir.toPath().resolve("settings.json").toFile())) { + fos.write(Utf8Helper.getBytes(settings)); + } + + String app = "\n" + +"\n" + +"\n" + +"\n" + +"\n" + +" \n" + +" test-flex\n" + +"\n" + +" \n" + +" "+simpleNameNoSpaces+"\n" + +"\n" + +" \n" + +" \n" + +" \n" + +" \n" + +" 1.0.0\n" + +" \n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +" \n" + +" \n" + +" " + simpleNameNoSpaces + ".swf\n" + +" \n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +"\n" + +" \n" + +" true\n" + +"\n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +"\n" + +" \n" + +"\n" + +" \n" + +"\n" + +" \n" + +"\n" + +" \n" + +"\n" + +" \n" + +"\n" + +" \n" + +"\n" + +" \n" + +"\n" + +" \n" + +"\n" + +" \n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +"\n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +" \n" + +"\n" + +""; + + File srcDir = outDir.toPath().resolve("src").toFile(); + srcDir.mkdirs(); + + try (FileOutputStream fos = new FileOutputStream(srcDir.toPath().resolve(simpleNameNoSpaces + "-app.xml").toFile())) { + fos.write(Utf8Helper.getBytes(app)); + } + + File libsDir = outDir.toPath().resolve("libs").toFile(); + libsDir.mkdirs(); + + boolean parallel = Configuration.parallelSpeedUp.get(); + ScriptExportSettings scriptExportSettings = new ScriptExportSettings(ScriptExportMode.AS, false, false, true, false, false, "/_assets/", Configuration.linkAllClasses.get()); + swf.exportActionScript(handler, srcDir.getAbsolutePath(), scriptExportSettings, parallel, eventListener); + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java index 936421e8f..222254214 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java @@ -27,6 +27,7 @@ import com.jpexs.decompiler.flash.configuration.ConfigurationItemChangeListener; import com.jpexs.decompiler.flash.console.ContextMenuTools; import com.jpexs.decompiler.flash.exporters.swf.SwfFlashDevelopExporter; import com.jpexs.decompiler.flash.exporters.swf.SwfIntelliJIdeaExporter; +import com.jpexs.decompiler.flash.exporters.swf.SwfVsCodeExporter; import com.jpexs.decompiler.flash.gui.debugger.DebuggerTools; import com.jpexs.decompiler.flash.gui.helpers.CheckResources; import com.jpexs.decompiler.flash.search.ScriptSearchResult; @@ -506,6 +507,17 @@ public abstract class MainFrameMenu implements MenuBuilder { mainFrame.getPanel().exportIdea((SWF) openable); } + + protected void exportVsCodeActionPerformed(ActionEvent evt) { + if (Main.isWorking()) { + return; + } + if (mainFrame.getPanel().checkEdited()) { + return; + } + + mainFrame.getPanel().exportVsCode((SWF) openable); + } protected void exportFlaActionPerformed(ActionEvent evt) { if (Main.isWorking()) { @@ -1005,10 +1017,12 @@ public abstract class MainFrameMenu implements MenuBuilder { boolean isAs3 = false; boolean canExportFlashDevelop = false; boolean canExportIdea = false; + boolean canExportVsCode = false; if (swf != null) { isAs3 = swf.isAS3(); canExportFlashDevelop = SwfFlashDevelopExporter.canExportSwf(swf); canExportIdea = SwfIntelliJIdeaExporter.canExportSwf(swf); + canExportVsCode = SwfVsCodeExporter.canExportSwf(swf); } if (abcSelected) { isAs3 = true; @@ -1085,6 +1099,8 @@ public abstract class MainFrameMenu implements MenuBuilder { setMenuEnabled("/file/export/exportFlashDevelop", allSameSwf && openableSelected && isAs3 && !isWorking && canExportFlashDevelop); setMenuEnabled("_/exportIdea", swfSelected && !isWorking && canExportIdea); setMenuEnabled("/file/export/exportIdea", allSameSwf && openableSelected && isAs3 && !isWorking && canExportIdea); + setMenuEnabled("_/exportVsCode", swfSelected && !isWorking && canExportVsCode); + setMenuEnabled("/file/export/exportVsCode", allSameSwf && openableSelected && isAs3 && !isWorking && canExportVsCode); setMenuEnabled("_/exportSelected", openableSelected && !isWorking); setMenuEnabled("/file/export/exportSelected", openableSelected && !isWorking); setMenuEnabled("/file/export/exportXml", swfSelected && !isWorking); @@ -1185,6 +1201,7 @@ public abstract class MainFrameMenu implements MenuBuilder { addMenuItem("_/exportFla", translate("menu.file.export.fla"), "exportfla32", this::exportFlaActionPerformed, PRIORITY_TOP, null, true, null, false); addMenuItem("_/exportFlashDevelop", translate("menu.file.export.flashDevelop"), "exportflashdevelop32", this::exportFlashDevelopActionPerformed, PRIORITY_TOP, null, true, null, false); addMenuItem("_/exportIdea", translate("menu.file.export.idea"), "exportidea32", this::exportIdeaActionPerformed, PRIORITY_TOP, null, true, null, false); + addMenuItem("_/exportVsCode", translate("menu.file.export.vsCode"), "exportvscode32", this::exportVsCodeActionPerformed, PRIORITY_TOP, null, true, null, false); addMenuItem("_/exportAll", translate("menu.file.export.all"), "export32", this::exportAllActionPerformed, PRIORITY_TOP, null, true, null, false); addMenuItem("_/exportSelected", translate("menu.file.export.selection"), "exportsel32", this::exportSelectedActionPerformed, PRIORITY_TOP, null, true, null, false); addSeparator("_"); @@ -1219,8 +1236,9 @@ public abstract class MainFrameMenu implements MenuBuilder { addMenuItem("/file/export", translate("menu.export"), null, null, 0, null, false, null, false); addMenuItem("/file/export/exportFla", translate("menu.file.export.fla"), "exportfla32", this::exportFlaActionPerformed, PRIORITY_TOP, null, true, null, false); - addMenuItem("/file/export/exportFlashDevelop", translate("menu.file.export.flashDevelop"), "exportflashdevelop32", this::exportFlashDevelopActionPerformed, PRIORITY_TOP, null, true, null, false); - addMenuItem("/file/export/exportIdea", translate("menu.file.export.idea"), "exportidea32", this::exportIdeaActionPerformed, PRIORITY_TOP, null, true, null, false); + addMenuItem("/file/export/exportFlashDevelop", translate("menu.file.export.flashDevelop"), "exportflashdevelop32", this::exportFlashDevelopActionPerformed, PRIORITY_MEDIUM, null, true, null, false); + addMenuItem("/file/export/exportIdea", translate("menu.file.export.idea"), "exportidea32", this::exportIdeaActionPerformed, PRIORITY_MEDIUM, null, true, null, false); + addMenuItem("/file/export/exportVsCode", translate("menu.file.export.vsCode"), "exportvscode32", this::exportVsCodeActionPerformed, PRIORITY_MEDIUM, null, true, null, false); addMenuItem("/file/export/exportXml", translate("menu.file.export.xml"), "exportxml32", this::exportXmlActionPerformed, PRIORITY_MEDIUM, null, true, null, false); addMenuItem("/file/export/exportAll", translate("menu.file.export.all"), "export16", this::exportAllActionPerformed, PRIORITY_MEDIUM, null, true, new HotKey("CTRL+SHIFT+E"), false); addMenuItem("/file/export/exportSelected", translate("menu.file.export.selection"), "exportsel16", this::exportSelectedActionPerformed, PRIORITY_MEDIUM, null, true, null, false); diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index dac41a22e..fa7756797 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -91,6 +91,7 @@ import com.jpexs.decompiler.flash.exporters.settings.TextExportSettings; import com.jpexs.decompiler.flash.exporters.swf.SwfFlashDevelopExporter; import com.jpexs.decompiler.flash.exporters.swf.SwfIntelliJIdeaExporter; import com.jpexs.decompiler.flash.exporters.swf.SwfJavaExporter; +import com.jpexs.decompiler.flash.exporters.swf.SwfVsCodeExporter; import com.jpexs.decompiler.flash.exporters.swf.SwfXmlExporter; import com.jpexs.decompiler.flash.flexsdk.MxmlcAs3ScriptReplacer; import com.jpexs.decompiler.flash.gui.abc.ABCExplorerDialog; @@ -3499,6 +3500,79 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } }.execute(); } + + public void exportVsCode(final SWF swf) { + if (swf == null) { + return; + } + + JFileChooser chooser = View.getFileChooserWithIcon("exportvscode"); + chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get())); + chooser.setDialogTitle(translate("export.project.select.directory")); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + chooser.setAcceptAllFileFilterUsed(false); + if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION) { + return; + } + final String fpath = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath(); + Configuration.lastExportDir.set(Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath()); + SwfVsCodeExporter exporter = new SwfVsCodeExporter(); + + long timeBefore = System.currentTimeMillis(); + new CancellableWorker() { + @Override + protected Void doInBackground() throws Exception { + Helper.freeMem(); + + CancellableWorker w = this; + + ProgressListener prog = new ProgressListener() { + @Override + public void progress(int p) { + } + + @Override + public void status(String status) { + Main.startWork(translate("work.exporting.vsCode") + "..." + status, w); + } + }; + EventListener evl = swf.getExportEventListener(); + try { + AbortRetryIgnoreHandler errorHandler = new GuiAbortRetryIgnoreHandler(); + exporter.exportVsCodeProject(swf, new File(fpath), false, errorHandler, evl); + } catch (Exception ex) { + logger.log(Level.SEVERE, "VsCode export error", ex); + ViewMessages.showMessageDialog(MainPanel.this, translate("error.export") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage(), translate("error"), JOptionPane.ERROR_MESSAGE); + } + Helper.freeMem(); + return null; + } + + @Override + protected void onStart() { + Main.startWork(translate("work.exporting.vsCode") + "...", this); + } + + @Override + protected void done() { + Main.stopWork(); + long timeAfter = System.currentTimeMillis(); + final long timeMs = timeAfter - timeBefore; + + View.execInEventDispatch(() -> { + setStatus(translate("export.finishedin").replace("%time%", Helper.formatTimeSec(timeMs))); + }); + + if (Configuration.openFolderAfterFlaExport.get()) { + try { + Desktop.getDesktop().open(new File(fpath).getAbsoluteFile().getParentFile()); + } catch (IOException ex) { + logger.log(Level.SEVERE, null, ex); + } + } + } + }.execute(); + } public void exportFla(final SWF swf) { if (swf == null) { diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/exportvscode16.png b/src/com/jpexs/decompiler/flash/gui/graphics/exportvscode16.png new file mode 100644 index 0000000000000000000000000000000000000000..62c836a8b8d937dfd9992a70d36ab1cc0640d63a GIT binary patch literal 5828 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 literal 0 HcmV?d00001 diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index 4f2c3417b..ed2fe8170 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -967,14 +967,14 @@ warning.cleanAbc=This action will remove items from ABC which have zero usages - tagInfo.idType=Type of the id contextmenu.configurePathResolving=Configure path resolving... contextmenu.setAsLinkage=Set AS linkage -contextmenu.exportFlashDevelop=Export FlashDevelop project +contextmenu.exportFlashDevelop=Export to FlashDevelop filter.as3proj=FlashDevelop AS3 project (*.as3proj) work.exporting.flashDevelop=Exporting FlashDevelop project -menu.file.export.flashDevelop=Export FD project -contextmenu.exportIdea=Export IDEA project +menu.file.export.flashDevelop=Export to FlashDevelop +contextmenu.exportIdea=Export to IntelliJ IDEA filter.iml=IntelliJ IDEA projects (*.iml) work.exporting.idea=Exporting IntelliJ IDEA project -menu.file.export.idea=Export IDEA project +menu.file.export.idea=Export to IntelliJ IDEA contextmenu.exportFla=Export to FLA export.project.select.directory=Select location of the new project directory menu.file.saveAll=Save all @@ -996,4 +996,9 @@ addfunction.result.title=New method info filter.air.as3proj = FlashDevelop AIR AS3 project (*.as3proj) packer.key.title = Key for: %packer% -packer.key = Enter key for the packer "%packer%": \ No newline at end of file +packer.key = Enter key for the packer "%packer%": + +#after 21.0.5 +contextmenu.exportVsCode=Export to VS Code +work.exporting.vsCode=Exporting VS Code +menu.file.export.vsCode=Export to VS Code diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java index 992f9b36d..d25308994 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java @@ -36,6 +36,7 @@ import com.jpexs.decompiler.flash.configuration.CustomConfigurationKeys; import com.jpexs.decompiler.flash.configuration.SwfSpecificCustomConfiguration; import com.jpexs.decompiler.flash.exporters.swf.SwfFlashDevelopExporter; import com.jpexs.decompiler.flash.exporters.swf.SwfIntelliJIdeaExporter; +import com.jpexs.decompiler.flash.exporters.swf.SwfVsCodeExporter; import com.jpexs.decompiler.flash.gui.AppDialog; import com.jpexs.decompiler.flash.gui.AppStrings; import com.jpexs.decompiler.flash.gui.AsLinkageDialog; @@ -217,6 +218,8 @@ public class TagTreeContextMenu extends JPopupMenu { private JMenuItem exportFlashDevelopMenuItem; private JMenuItem exportIdeaMenuItem; + + private JMenuItem exportVsCodeMenuItem; private JMenuItem exportSwfXmlMenuItem; @@ -454,6 +457,11 @@ public class TagTreeContextMenu extends JPopupMenu { exportIdeaMenuItem.addActionListener(this::exportIdeaActionPerformed); exportIdeaMenuItem.setIcon(View.getIcon("exportidea16")); add(exportIdeaMenuItem); + + exportVsCodeMenuItem = new JMenuItem(mainPanel.translate("contextmenu.exportVsCode")); + exportVsCodeMenuItem.addActionListener(this::exportVsCodeActionPerformed); + exportVsCodeMenuItem.setIcon(View.getIcon("exportvscode16")); + add(exportVsCodeMenuItem); exportJavaSourceMenuItem = new JMenuItem(mainPanel.translate("contextmenu.exportJavaSource")); exportJavaSourceMenuItem.addActionListener(new ActionListener() { @@ -1213,6 +1221,7 @@ public class TagTreeContextMenu extends JPopupMenu { exportFlaMenuItem.setVisible(false); exportFlashDevelopMenuItem.setVisible(false); exportIdeaMenuItem.setVisible(false); + exportVsCodeMenuItem.setVisible(false); exportJavaSourceMenuItem.setVisible(allSelectedIsSwf); exportSwfXmlMenuItem.setVisible(allSelectedIsSwf); @@ -1480,6 +1489,9 @@ public class TagTreeContextMenu extends JPopupMenu { if (SwfIntelliJIdeaExporter.canExportSwf(swf)) { exportIdeaMenuItem.setVisible(true); } + if (SwfVsCodeExporter.canExportSwf(swf)) { + exportVsCodeMenuItem.setVisible(true); + } } } @@ -5544,6 +5556,11 @@ public class TagTreeContextMenu extends JPopupMenu { SWF swf = (SWF) getCurrentItem().getOpenable(); mainPanel.exportIdea(swf); } + + public void exportVsCodeActionPerformed(ActionEvent evt) { + SWF swf = (SWF) getCurrentItem().getOpenable(); + mainPanel.exportVsCode(swf); + } public void importScriptsActionPerformed(ActionEvent evt) { Openable openable = getCurrentItem().getOpenable();