From e8b15e1ad6a99e293278d01332e15954e875b1ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sat, 30 Aug 2025 18:22:52 +0200 Subject: [PATCH] Added: #2526 Option to disable drag & drop from Resources view to avoid problems on Mac OS --- CHANGELOG.md | 2 + .../flash/configuration/Configuration.java | 5 +- src/com/jpexs/decompiler/flash/gui/Main.java | 10 +- .../jpexs/decompiler/flash/gui/MainPanel.java | 148 ++++++++++-------- .../locales/AdvancedSettingsDialog.properties | 3 + .../AdvancedSettingsDialog_cs.properties | 3 + .../flash/gui/taglistview/TagListTree.java | 2 +- 7 files changed, 105 insertions(+), 68 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af878adef..108329554 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ All notable changes to this project will be documented in this file. - view tagIDTagLength field parts - show type after colon, not in parenthesis - view bytes length in bytes fields +- [#2526] Option to disable drag & drop from Resources view to avoid problems on Mac OS ### Fixed - [#2474] Gotos incorrectly decompiled @@ -3991,6 +3992,7 @@ Major version of SWF to XML export changed to 2. [#2499]: https://www.free-decompiler.com/flash/issues/2499 [#2504]: https://www.free-decompiler.com/flash/issues/2504 [#2519]: https://www.free-decompiler.com/flash/issues/2519 +[#2526]: https://www.free-decompiler.com/flash/issues/2526 [#2474]: https://www.free-decompiler.com/flash/issues/2474 [#2480]: https://www.free-decompiler.com/flash/issues/2480 [#2338]: https://www.free-decompiler.com/flash/issues/2338 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java index 81528fb78..d39e472d7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java @@ -16,7 +16,6 @@ */ package com.jpexs.decompiler.flash.configuration; -import com.jpexs.decompiler.flash.ApplicationInfo; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.configuration.enums.GridSnapAccuracy; import com.jpexs.decompiler.flash.configuration.enums.GuidesSnapAccuracy; @@ -1163,6 +1162,10 @@ public final class Configuration { @ConfigurationCategory("script") public static ConfigurationItem showVarsWithDontEnumerateFlag = null; + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("ui") + public static ConfigurationItem allowDragAndDropFromResourcesTree = null; + private static Map configurationDescriptions = new LinkedHashMap<>(); private static Map configurationTitles = new LinkedHashMap<>(); diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index f6f9b1eee..acbc5b09c 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -1030,7 +1030,7 @@ public class Main { return; } lastTimeStartWork = nowTime; - View.execInEventDispatch(() -> { + View.execInEventDispatchLater(() -> { if (mainFrame != null) { mainFrame.getPanel().setWorkStatus(name, worker); if (percent == -1) { @@ -1042,11 +1042,11 @@ public class Main { if (loadingDialog != null) { loadingDialog.setDetail(name); loadingDialog.setPercent(percent); - } - if (CommandLineArgumentParser.isCommandLineMode()) { - System.out.println(name); - } + } }); + if (CommandLineArgumentParser.isCommandLineMode()) { + System.out.println(name); + } } public static void stopWork() { diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index a08879d4e..7a2f8bedf 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -228,11 +228,14 @@ import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceAdapter; import java.awt.dnd.DragSourceDragEvent; import java.awt.dnd.DragSourceDropEvent; import java.awt.dnd.DragSourceEvent; import java.awt.dnd.DragSourceListener; import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetAdapter; +import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -273,6 +276,7 @@ import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.Icon; import javax.swing.JColorChooser; +import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JOptionPane; @@ -284,6 +288,7 @@ import javax.swing.JSplitPane; import javax.swing.JTabbedPane; import javax.swing.JTree; import javax.swing.SwingConstants; +import javax.swing.TransferHandler; import javax.swing.UIManager; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; @@ -442,6 +447,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se private Map breakpointsListDialogs = new WeakHashMap<>(); private boolean loadingScrollPosEnabled = true; + + private static final DataFlavor TREE_FILE_FLAVOR = new DataFlavor(TreeFileFlavor.class, "TreeFile"); public synchronized void setLoadingScrollPosEnabled(boolean loadingScrollPosEnabled) { this.loadingScrollPosEnabled = loadingScrollPosEnabled; @@ -833,7 +840,11 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se || (actionPanel != null && actionPanel.isEditing()) || previewPanel.isEditing() || headerPanel.isEditing(); } - + + private class TreeFileFlavor { + + } + private class MyTreeSelectionModel extends DefaultTreeSelectionModel { @Override @@ -1146,26 +1157,37 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se tagListTree = new TagListTree(null, this); tagListTree.addTreeSelectionListener(this); - tagListTree.setSelectionModel(new MyTreeSelectionModel()); - + tagListTree.setSelectionModel(new MyTreeSelectionModel()); + DragSource dragSource = DragSource.getDefaultDragSource(); - dragSource.createDefaultDragGestureRecognizer(tagTree, DnDConstants.ACTION_COPY_OR_MOVE, new DragGestureListener() { + dragSource.createDefaultDragGestureRecognizer(tagTree, DnDConstants.ACTION_COPY_OR_MOVE, new DragGestureListener() { @Override public void dragGestureRecognized(DragGestureEvent dge) { + if (!Configuration.allowDragAndDropFromResourcesTree.get()) { + return; + } dge.startDrag(DragSource.DefaultCopyDrop, new Transferable() { + + private List cachedFiles = null; + @Override public DataFlavor[] getTransferDataFlavors() { - return new DataFlavor[]{DataFlavor.javaFileListFlavor}; + return new DataFlavor[]{TREE_FILE_FLAVOR, DataFlavor.javaFileListFlavor}; } @Override public boolean isDataFlavorSupported(DataFlavor flavor) { - return flavor.equals(DataFlavor.javaFileListFlavor); - } - + return flavor.equals(TREE_FILE_FLAVOR) || flavor.equals(DataFlavor.javaFileListFlavor); + } + @Override public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { if (flavor.equals(DataFlavor.javaFileListFlavor)) { + if (cachedFiles != null) { + Main.stopWork(); + return cachedFiles; + } + List files; String tempDir = System.getProperty("java.io.tmpdir"); if (!tempDir.endsWith(File.separator)) { @@ -1183,6 +1205,9 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } catch (InterruptedException ex) { logger.log(Level.SEVERE, null, ex); return null; + } catch (Throwable t) { + logger.log(Level.SEVERE, null, t); + return null; } files.clear(); @@ -1196,34 +1221,14 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se f.deleteOnExit(); } new File(tempDir).deleteOnExit(); - return files; + cachedFiles = files; + + return cachedFiles; } return null; } - }, new DragSourceListener() { - @Override - public void dragEnter(DragSourceDragEvent dsde) { - enableDrop(false); - } - - @Override - public void dragOver(DragSourceDragEvent dsde) { - } - - @Override - public void dropActionChanged(DragSourceDragEvent dsde) { - } - - @Override - public void dragExit(DragSourceEvent dse) { - } - - @Override - public void dragDropEnd(DragSourceDropEvent dsde) { - enableDrop(true); - } - }); + }, new DragSourceAdapter() {}); } }); @@ -1411,7 +1416,53 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se }); //Opening files with drag&drop to main window - enableDrop(true); + new DropTarget(this, new DropTargetAdapter() { + @Override + public void dragEnter(DropTargetDragEvent dtde) { + if (dtde.isDataFlavorSupported(TREE_FILE_FLAVOR) + || !dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { + dtde.rejectDrag(); + } else { + dtde.acceptDrag(DnDConstants.ACTION_COPY); + } + } + + @Override + public void dragOver(DropTargetDragEvent dtde) { + if (dtde.isDataFlavorSupported(TREE_FILE_FLAVOR) + || !dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { + dtde.rejectDrag(); + } else { + dtde.acceptDrag(DnDConstants.ACTION_COPY); + } + } + + @Override + public void drop(DropTargetDropEvent dtde) { + if (dtde.isDataFlavorSupported(TREE_FILE_FLAVOR) + || !dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { + dtde.rejectDrop(); + return; + } + try { + dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); + @SuppressWarnings("unchecked") + List droppedFiles = (List) dtde.getTransferable().getTransferData(DataFlavor.javaFileListFlavor); + if (droppedFiles != null && !droppedFiles.isEmpty()) { + OpenableSourceInfo[] sourceInfos = new OpenableSourceInfo[droppedFiles.size()]; + for (int i = 0; i < droppedFiles.size(); i++) { + sourceInfos[i] = new OpenableSourceInfo(null, droppedFiles.get(i).getAbsolutePath(), null); + } + Main.openFile(sourceInfos, null, true); + dtde.dropComplete(true); + } + } catch (UnsupportedFlavorException | IOException ex) { + dtde.dropComplete(false); + //ignored + } + } + }); + calculateMissingNeededThread = new CalculateMissingNeededThread(); calculateMissingNeededThread.start(); pinsPanel.load(); @@ -1886,31 +1937,6 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se return true; } - private void enableDrop(boolean value) { - if (value) { - setDropTarget(new DropTarget() { - @Override - public synchronized void drop(DropTargetDropEvent dtde) { - try { - dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); - @SuppressWarnings("unchecked") - List droppedFiles = (List) dtde.getTransferable().getTransferData(DataFlavor.javaFileListFlavor); - if (droppedFiles != null && !droppedFiles.isEmpty()) { - OpenableSourceInfo[] sourceInfos = new OpenableSourceInfo[droppedFiles.size()]; - for (int i = 0; i < droppedFiles.size(); i++) { - sourceInfos[i] = new OpenableSourceInfo(null, droppedFiles.get(i).getAbsolutePath(), null); - } - Main.openFile(sourceInfos, null, true); - } - } catch (UnsupportedFlavorException | IOException ex) { - //ignored - } - } - }); - } else { - setDropTarget(null); - } - } public void updateClassesList() { String selectionPath = getCurrentTree().getSelectionPathString(); @@ -2086,7 +2112,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se List ret = new ArrayList<>(); List sel = getSelection(null, selection); - + Set usedOpenables = new HashSet<>(); Set usedOpenableLists = new HashSet<>(); @@ -2101,7 +2127,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se usedOpenableLists.add(list); } } - + Map usedSwfsIds = new HashMap<>(); for (Openable openable : usedOpenables) { @@ -6778,7 +6804,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se if (calculateMissingNeededThread != null) { calculateMissingNeededThread.interrupt(); } - setDropTarget(null); + //setDropTarget(null); disposeInner(this); Helper.emptyObject(this); } diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties index 754bb8731..9c94caafa 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties @@ -639,3 +639,6 @@ config.description.autoDeobfuscateIdentifiers = Obfuscated names that are not va config.name.showVarsWithDontEnumerateFlag = Debugger - show vars with DontEnumerate flag config.description.showVarsWithDontEnumerateFlag = While debugging ActionScript, show also variables with special DontEnumerate flag, which are internal to flash. It is recommended to hide them as they are usually not relevant. + +config.name.allowDragAndDropFromResourcesTree = Allow drag and drop from resources view tree +config.description.allowDragAndDropFromResourcesTree = Enable drag and drop items from tree of resources view to export them. On Mac OS, drag out is annoying as it requires all files to be exported before drag starts. Set this to false to avoid accidentally dragging and freezing the application. diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties index 20590ae01..bc2c31cdf 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties @@ -639,3 +639,6 @@ config.description.autoDeobfuscateIdentifiers = Obfuskovan\u00e9 n\u00e1zvy kter config.name.showVarsWithDontEnumerateFlag = Lad\u011bn\u00ed - zobrazit prom\u011bnn\u00e9 s p\u0159\u00edznakem DontEnumerate config.description.showVarsWithDontEnumerateFlag = B\u011bhem lad\u011bn\u00ed ActionScriptu zobrazit tak\u00e9 prom\u011bnn\u00e9 se speci\u00e1ln\u00edm p\u0159\u00edznakem DontEnumerate, kter\u00fd je intern\u00ed pro flash. Je doporu\u010deno tyto polo\u017eky skr\u00fdt, jeliko\u017e jsou obvykle nerelevantn\u00ed. + +config.name.allowDragAndDropFromResourcesTree = Povolit drag and drop ze stromu zobrazen\u00ed Zdroj\u016f +config.description.allowDragAndDropFromResourcesTree = Povolit drag and drop polo\u017eek ze stromu v zobrazen\u00ed zdroj\u016f pro jejich export. Na Mac OS je ta\u017een\u00ed nep\u0159\u00edjemn\u00e9, jeliko\u017e vy\u017eaduje m\u00edt v\u0161echny soubory exportovan\u00e9 p\u0159edem ne\u017e ta\u017een\u00ed za\u010dne. Vypn\u011bte toto tedy pro zabr\u00e1n\u011bn\u00ed ta\u017een\u00ed omylem a zamrznut\u00ed aplikace. diff --git a/src/com/jpexs/decompiler/flash/gui/taglistview/TagListTree.java b/src/com/jpexs/decompiler/flash/gui/taglistview/TagListTree.java index bc0f5318b..773799a79 100644 --- a/src/com/jpexs/decompiler/flash/gui/taglistview/TagListTree.java +++ b/src/com/jpexs/decompiler/flash/gui/taglistview/TagListTree.java @@ -50,7 +50,7 @@ public class TagListTree extends AbstractTagTree { public TagListTree(TagListTreeModel model, MainPanel mainPanel) { super(model, mainPanel); setCellRenderer(new TagListTreeCellRenderer()); - setDragEnabled(true); + setDragEnabled(true); setDropMode(DropMode.ON_OR_INSERT); setTransferHandler(new TreeTransferHandler(mainPanel)); }