diff --git a/libsrc/ffdec_lib/testdata/embedded.swf b/libsrc/ffdec_lib/testdata/embedded.swf new file mode 100644 index 000000000..910436355 Binary files /dev/null and b/libsrc/ffdec_lib/testdata/embedded.swf differ diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 50f0d3f98..4287fe99e 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -613,7 +613,6 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec }); detailPanel.setVisible(false); - showView(getCurrentView()); updateUi(); this.swfs.addCollectionChangedListener((e) -> { @@ -639,6 +638,19 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec dumpTree.expandRow(i); } } + + if (swfs.isEmpty()) { + tagTree.setUI(new BasicTreeUI() { + { + setHashColor(Color.gray); + } + }); + dumpTree.setUI(new BasicTreeUI() { + { + setHashColor(Color.gray); + } + }); + } }); //Opening files with drag&drop to main window @@ -731,6 +743,8 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec mainFrame.setTitle(ApplicationInfo.applicationVerName); mainMenu.updateComponents(null); + + showView(getCurrentView()); } private boolean closeConfirmation(SWFList swfList) { @@ -765,7 +779,8 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec } /*for (SWFList swfList : swfs) { - for (SWF swf : swfList) { + List swfs2 = new ArrayList<>(swfList); + for (SWF swf : swfs2) { swf.clearTagSwfs(); } }*/ @@ -831,7 +846,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec } } - refreshTree(); + refreshTree(null); if (updateNeeded) { View.execInEventDispatch(new Runnable() { @@ -1189,7 +1204,6 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec } if (treeItem instanceof Timelined) { Timelined t = (Timelined) treeItem; - Timeline tim = t.getTimeline(); Frame f = tagTree.getModel().getFrame(treeItem.getSwf(), t, frame); if (f != null) { setTagTreeSelectedNode(f); @@ -1771,7 +1785,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec swf.clearAllCache(); swf.assignExportNamesToSymbols(); swf.assignClassesToSymbols(); - refreshTree(); + refreshTree(swf); } catch (IOException ex) { logger.log(Level.SEVERE, null, ex); } @@ -1936,7 +1950,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec swf.removeTag(tag, true); } } - refreshTree(); + refreshTree(swf); } private void clear() { @@ -2102,11 +2116,12 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec byte[] data = Helper.readFile(selfile.getAbsolutePath()); try { Tag newTag = new ImageImporter().importImage(it, data); + SWF swf = it.getSwf(); if (newTag != null) { - refreshTree(); + refreshTree(swf); setTagTreeSelectedNode(newTag); } - it.getSwf().clearImageCache(); + swf.clearImageCache(); } catch (IOException ex) { logger.log(Level.SEVERE, "Invalid image", ex); View.showMessageDialog(null, translate("error.image.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE); @@ -2123,11 +2138,12 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec byte[] data = Helper.readFile(selfile.getAbsolutePath()); try { Tag newTag = new ShapeImporter().importImage(st, data); + SWF swf = st.getSwf(); if (newTag != null) { - refreshTree(); + refreshTree(swf); setTagTreeSelectedNode(newTag); } - st.getSwf().clearImageCache(); + swf.clearImageCache(); } catch (IOException ex) { logger.log(Level.SEVERE, "Invalid image", ex); View.showMessageDialog(null, translate("error.image.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE); @@ -2170,7 +2186,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec } private File showImportFileChooser(String filter) { - String[] filterArray = filter.split("\\|"); + String[] filterArray = filter.length() > 0 ? filter.split("\\|") : new String[0]; JFileChooser fc = new JFileChooser(); fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get())); diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java index e32dad00a..e66987fad 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java @@ -349,7 +349,7 @@ public class TagTreeContextMenu extends JPopupMenu implements ActionListener { } timelined.getTimeline().reset(); swf.updateCharacters(); - mainPanel.refreshTree(); + mainPanel.refreshTree(swf); } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException ex) { Logger.getLogger(TagTreeContextMenu.class.getName()).log(Level.SEVERE, null, ex); } @@ -383,7 +383,7 @@ public class TagTreeContextMenu extends JPopupMenu implements ActionListener { targetSwf.assignClassesToSymbols(); sourceSwf.clearImageCache(); targetSwf.clearImageCache(); - mainPanel.refreshTree(); + mainPanel.refreshTree(null); // refresh all opened swfs } }); moveTagMenu.add(swfItem); @@ -401,7 +401,7 @@ public class TagTreeContextMenu extends JPopupMenu implements ActionListener { targetSwf.assignExportNamesToSymbols(); targetSwf.assignClassesToSymbols(); targetSwf.clearImageCache(); - mainPanel.refreshTree(); + mainPanel.refreshTree(targetSwf); } catch (IOException | InterruptedException ex) { Logger.getLogger(TagTreeContextMenu.class.getName()).log(Level.SEVERE, null, ex); } @@ -509,18 +509,21 @@ public class TagTreeContextMenu extends JPopupMenu implements ActionListener { } boolean removeDependencies = e.getActionCommand().equals(ACTION_REMOVE_ITEM_WITH_DEPENDENCIES); - if (tagsToRemove.size() == 1) { - Tag tag = tagsToRemove.get(0); - if (View.showConfirmDialog(this, mainPanel.translate("message.confirm.remove").replace("%item%", tag.toString()), mainPanel.translate("message.confirm"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) { - tag.getSwf().removeTag(tag, removeDependencies); - mainPanel.refreshTree(); + if (tagsToRemove.size() > 0) { + String confirmationMessage; + if (tagsToRemove.size() == 1) { + Tag tag = tagsToRemove.get(0); + confirmationMessage = mainPanel.translate("message.confirm.remove").replace("%item%", tag.toString()); + } else { + confirmationMessage = mainPanel.translate("message.confirm.removemultiple").replace("%count%", Integer.toString(tagsToRemove.size())); } - } else if (tagsToRemove.size() > 1) { - if (View.showConfirmDialog(this, mainPanel.translate("message.confirm.removemultiple").replace("%count%", Integer.toString(tagsToRemove.size())), mainPanel.translate("message.confirm"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) { + + if (View.showConfirmDialog(this, confirmationMessage, mainPanel.translate("message.confirm"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) { for (Tag tag : tagsToRemove) { tag.getSwf().removeTag(tag, removeDependencies); } - mainPanel.refreshTree(); + + mainPanel.refreshTree(null); } } break; @@ -551,7 +554,7 @@ public class TagTreeContextMenu extends JPopupMenu implements ActionListener { if (swf.binaryData != null) { // embedded swf swf.binaryData.innerSwf = null; - mainPanel.refreshTree(); + mainPanel.refreshTree(null); } else { Main.closeFile(swf.swfList); } diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java index 77054ba34..98cfa65e6 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java @@ -45,7 +45,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.WeakHashMap; import javax.swing.event.TreeModelEvent; import javax.swing.event.TreeModelListener; import javax.swing.tree.TreeModel; @@ -85,7 +84,7 @@ public class TagTreeModel implements TreeModel { private final List swfs; - private final Map swfInfos = new WeakHashMap<>(); + private final Map swfInfos = new HashMap<>(); private final boolean addAllFolders; @@ -101,6 +100,7 @@ public class TagTreeModel implements TreeModel { } public void updateSwfs(CollectionChangedEvent e) { + boolean cleanMap = false; switch (e.getAction()) { case ADD: { TreePath rootPath = new TreePath(new Object[]{root}); @@ -110,15 +110,32 @@ public class TagTreeModel implements TreeModel { case REMOVE: { TreePath rootPath = new TreePath(new Object[]{root}); fireTreeNodesRemoved(new TreeModelEvent(this, rootPath, new int[]{e.getOldIndex()}, new Object[]{e.getOldItem()})); + cleanMap = true; break; } default: + cleanMap = true; fireTreeStructureChanged(new TreeModelEvent(this, new TreePath(root))); } + + if (cleanMap) { + List toRemove = new ArrayList<>(); + for (SWF swf : swfInfos.keySet()) { + SWF swf2 = swf.getRootSwf(); + if (swf2 != null && !swfs.contains(swf2.swfList)) { + toRemove.add(swf); + } + } + + for (SWF swf : toRemove) { + swfInfos.remove(swf); + } + } } public void updateSwf(SWF swf) { - TreePath changedPath = getTreePath(swf == null ? getRoot() : swf); + swfInfos.clear(); + TreePath changedPath = getTreePath(swf == null ? root : swf); fireTreeStructureChanged(new TreeModelEvent(this, changedPath)); } @@ -412,8 +429,10 @@ public class TagTreeModel implements TreeModel { public TreePath getTreePath(TreeItem obj) { List path = new ArrayList<>(); - path.add(getRoot()); - path = searchTreeItem(obj, getRoot(), path); + path.add(root); + if (obj != root) { + path = searchTreeItem(obj, root, path); + } if (path == null) { return null; }