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 000000000..62c836a8b Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/exportvscode16.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/exportvscode32.png b/src/com/jpexs/decompiler/flash/gui/graphics/exportvscode32.png new file mode 100644 index 000000000..a6cd6cb24 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/exportvscode32.png differ 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();