From 4621b181e42fa18acd3d81645d8c1cf63193f3dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sun, 1 Dec 2024 13:36:16 +0100 Subject: [PATCH] Added: #2374 Quick filter by folder type (Ctrl+F on Resources view tag tree) --- CHANGELOG.md | 2 + .../decompiler/flash/gui/ImagePanel.java | 3 +- .../jpexs/decompiler/flash/gui/MainPanel.java | 27 ++- .../flash/gui/QuickTreeFilterInterface.java | 29 +++ .../flash/gui/QuickTreeFilterPanel.java | 199 ++++++++++++++++++ .../flash/gui/QuickTreeFindPanel.java | 8 +- .../flash/gui/tagtree/AbstractTagTree.java | 5 + .../flash/gui/tagtree/FilteredTreeModel.java | 33 ++- .../flash/gui/tagtree/TagTreeModel.java | 138 +++++++++--- 9 files changed, 402 insertions(+), 42 deletions(-) create mode 100644 src/com/jpexs/decompiler/flash/gui/QuickTreeFilterInterface.java create mode 100644 src/com/jpexs/decompiler/flash/gui/QuickTreeFilterPanel.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 79e664982..e76a6dfe8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. ### Added - FLA export - accessibility for AS3 files - [#2375] Sound sync event/start/stop handling (for playback in FFDec) +- [#2374] Quick filter by folder type (Ctrl+F on Resources view tag tree) ### Fixed - [#2375] Added limit of simultaneously played sounds @@ -3677,6 +3678,7 @@ Major version of SWF to XML export changed to 2. [alpha 8]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha7...alpha8 [alpha 7]: https://github.com/jindrapetrik/jpexs-decompiler/releases/tag/alpha7 [#2375]: https://www.free-decompiler.com/flash/issues/2375 +[#2374]: https://www.free-decompiler.com/flash/issues/2374 [#2366]: https://www.free-decompiler.com/flash/issues/2366 [#2367]: https://www.free-decompiler.com/flash/issues/2367 [#2372]: https://www.free-decompiler.com/flash/issues/2372 diff --git a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java index f672f245a..a95fb2b01 100644 --- a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java @@ -768,7 +768,8 @@ public final class ImagePanel extends JPanel implements MediaDisplay { } public void fireMediaDisplayStateChanged() { - for (MediaDisplayListener l : listeners) { + List ls = new ArrayList<>(listeners); + for (MediaDisplayListener l : ls) { l.mediaDisplayStateChanged(this); } } diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 5bbac413d..75934efb2 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -405,7 +405,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se private final JTabbedPane detailPanel; - private QuickTreeFindPanel quickTreeFindPanel; + private QuickTreeFilterPanel quickTreeFindPanel; private QuickTreeFindPanel quickTagListFindPanel; @@ -1827,7 +1827,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se mainMenu.updateComponents(null); previewPanel.clear(); - dumpPreviewPanel.clear(); + dumpPreviewPanel.clear(); + doFilter(); return true; } @@ -1883,30 +1884,37 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se return filter.trim().length() < 3; } - private void doFilter(AbstractTagTree tree, QuickTreeFindPanel findPanel, List> unfilteredExpandedNodes) { + private void doFilter(AbstractTagTree tree, QuickTreeFilterInterface findPanel, List> unfilteredExpandedNodes) { TreeModel model = tree.getModel(); String oldFilter = ""; + List oldFoldersFilter = new ArrayList<>(); if (model instanceof FilteredTreeModel) { oldFilter = ((FilteredTreeModel) model).getFilter(); + oldFoldersFilter = ((FilteredTreeModel) model).getFoldersFilter(); } String newFilter = findPanel.getFilter(); + List newFoldersFilter = findPanel.getFolders(); - if (isFilterEmpty(oldFilter)) { - unfilteredExpandedNodes.clear(); - ; + if (isFilterEmpty(oldFilter) && oldFoldersFilter.isEmpty()) { + unfilteredExpandedNodes.clear(); unfilteredExpandedNodes.addAll(View.getExpandedNodes(tree)); } - if (oldFilter.trim().equals(newFilter.trim())) { + if ( + oldFilter.trim().equals(newFilter.trim()) + && oldFoldersFilter.equals(newFoldersFilter) + ) { return; } TreePath[] selectionPaths = tree.getSelectionPaths(); - tree.setModel(new FilteredTreeModel(newFilter, tree.getFullModel(), tree)); + tree.setModel(new FilteredTreeModel(newFilter, newFoldersFilter, tree.getFullModel(), tree)); if (!isFilterEmpty(newFilter)) { for (int i = 0; i < tree.getRowCount(); i++) { tree.expandRow(i); } + } else if (!newFoldersFilter.isEmpty()) { + View.expandTreeNodes(tree, unfilteredExpandedNodes); } else { tree.setModel(tree.getFullModel()); View.expandTreeNodes(tree, unfilteredExpandedNodes); @@ -1916,6 +1924,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se public void doFilter() { View.checkAccess(); + quickTreeFindPanel.updateFolders(); doFilter(tagTree, quickTreeFindPanel, unfilteredTreeExpandedNodes); doFilter(tagListTree, quickTagListFindPanel, unfilteredTagListExpandedNodes); } @@ -5647,7 +5656,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se JPanel r = new JPanel(new BorderLayout()); r.add(resourcesClipboardPanel, BorderLayout.NORTH); r.add(tagTreeScrollPanel = new FasterScrollPane(tagTree), BorderLayout.CENTER); - quickTreeFindPanel = new QuickTreeFindPanel(); + quickTreeFindPanel = new QuickTreeFilterPanel(tagTree); quickTreeFindPanel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { diff --git a/src/com/jpexs/decompiler/flash/gui/QuickTreeFilterInterface.java b/src/com/jpexs/decompiler/flash/gui/QuickTreeFilterInterface.java new file mode 100644 index 000000000..7b0a119a5 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/QuickTreeFilterInterface.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2024 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.gui; + +import java.util.List; + +/** + * + * @author JPEXS + */ +public interface QuickTreeFilterInterface { + public String getFilter(); + + public List getFolders(); +} diff --git a/src/com/jpexs/decompiler/flash/gui/QuickTreeFilterPanel.java b/src/com/jpexs/decompiler/flash/gui/QuickTreeFilterPanel.java new file mode 100644 index 000000000..bfcb95a14 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/QuickTreeFilterPanel.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2022-2024 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.gui; + +import com.jpexs.decompiler.flash.gui.tagtree.TagTree; +import com.jpexs.decompiler.flash.gui.tagtree.TagTreeModel; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.UIManager; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +/** + * @author JPEXS + */ +public class QuickTreeFilterPanel extends JPanel implements QuickTreeFilterInterface { + + private List listeners = new ArrayList<>(); + + private JTextField filterField = new MyTextField(""); + private final TagTree tagTree; + + private JPanel foldersPanel; + + private List foldersList = new ArrayList<>(); + private List folderLabelsList = new ArrayList<>(); + private Map labelToFolder = new HashMap<>(); + + private Set selectedFolders = new LinkedHashSet<>(); + + public QuickTreeFilterPanel(TagTree tagTree) { + this.tagTree = tagTree; + filterField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void changedUpdate(DocumentEvent e) { + warn(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + warn(); + } + + @Override + public void insertUpdate(DocumentEvent e) { + warn(); + } + + public void warn() { + fireAction(); + } + }); + + JPanel quickFindPanel = new JPanel(new BorderLayout(4, 0)); + + quickFindPanel.add(filterField, BorderLayout.CENTER); + quickFindPanel.add(new JLabel(View.getIcon("search16")), BorderLayout.WEST); + JLabel closeSearchButton = new JLabel(View.getIcon("cancel16")); + closeSearchButton.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + filterField.setText(""); + setVisible(false); + fireAction(); + } + }); + closeSearchButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + quickFindPanel.add(closeSearchButton, BorderLayout.EAST); + + setLayout(new BorderLayout()); + add(quickFindPanel, BorderLayout.NORTH); + + foldersPanel = new JPanel(new WrapLayout(WrapLayout.LEFT)); + + add(foldersPanel, BorderLayout.CENTER); + setVisible(false); + } + + public void updateFolders() { + foldersPanel.removeAll(); + folderLabelsList.clear(); + foldersPanel.setSize(new Dimension(getParent().getWidth(), 47)); + + labelToFolder.clear(); + foldersList = ((TagTreeModel) tagTree.getFullModel()).getAvailableFolders(); + for (String f : foldersList) { + String icon = "folder" + f.toLowerCase(Locale.ENGLISH) + "16"; + if (f.equals("header")) { + icon = "header16"; + } + JLabel lab = new JLabel(AppStrings.translate("node." + f), View.getIcon(icon), JLabel.LEFT); + lab.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + labelToFolder.put(lab, f); + lab.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (selectedFolders.contains(f)) { + selectedFolders.remove(f); + } else { + selectedFolders.add(f); + } + labelHilight(lab, selectedFolders.contains(f)); + fireAction(); + } + }); + folderLabelsList.add(lab); + foldersPanel.add(lab); + labelHilight(lab, selectedFolders.contains(f)); + } + } + + private Color fixColor(Color color) { + return new Color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + } + + private void labelHilight(JLabel label, boolean hilight) { + label.setOpaque(true); + if (hilight) { + label.setBackground(fixColor(UIManager.getColor("Tree.selectionBackground"))); + label.setForeground(fixColor(UIManager.getColor("Tree.selectionForeground"))); + } else { + label.setBackground(fixColor(UIManager.getColor("Tree.textBackground"))); + label.setForeground(fixColor(UIManager.getColor("Tree.textForeground"))); + } + label.repaint(); + } + + private void fireAction() { + for (ActionListener listener : listeners) { + listener.actionPerformed(new ActionEvent(this, 0, "")); + } + } + + public void addActionListener(ActionListener listener) { + listeners.add(listener); + } + + public void removeActionListener(ActionListener listener) { + listeners.remove(listener); + } + + public String getFilter() { + return filterField.getText().trim(); + } + + @Override + public void setVisible(boolean aFlag) { + super.setVisible(aFlag); + if (aFlag) { + View.execInEventDispatchLater(new Runnable() { + @Override + public void run() { + updateFolders(); + } + }); + + filterField.requestFocusInWindow(); + } else { + filterField.setText(""); + selectedFolders.clear(); + } + } + + @Override + public List getFolders() { + return new ArrayList<>(selectedFolders); + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/QuickTreeFindPanel.java b/src/com/jpexs/decompiler/flash/gui/QuickTreeFindPanel.java index e36b5bb57..d060fb5cc 100644 --- a/src/com/jpexs/decompiler/flash/gui/QuickTreeFindPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/QuickTreeFindPanel.java @@ -33,7 +33,7 @@ import javax.swing.event.DocumentListener; /** * @author JPEXS */ -public class QuickTreeFindPanel extends JPanel { +public class QuickTreeFindPanel extends JPanel implements QuickTreeFilterInterface { private List listeners = new ArrayList<>(); @@ -62,7 +62,7 @@ public class QuickTreeFindPanel extends JPanel { } }); - setLayout(new BorderLayout()); + setLayout(new BorderLayout(4, 0)); add(filterField, BorderLayout.CENTER); add(new JLabel(View.getIcon("search16")), BorderLayout.WEST); JLabel closeSearchButton = new JLabel(View.getIcon("cancel16")); @@ -107,4 +107,8 @@ public class QuickTreeFindPanel extends JPanel { } } + @Override + public List getFolders() { + return new ArrayList<>(); + } } diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java b/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java index 2b27a971b..2a2b28464 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java @@ -30,6 +30,7 @@ import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.gui.MainPanel; import com.jpexs.decompiler.flash.gui.TreeNodeType; import com.jpexs.decompiler.flash.gui.View; +import com.jpexs.decompiler.flash.gui.abc.ClassesListTreeModel; import com.jpexs.decompiler.flash.gui.soleditor.Cookie; import com.jpexs.decompiler.flash.iggy.conversion.IggySwfBundle; import com.jpexs.decompiler.flash.tags.CSMTextSettingsTag; @@ -183,6 +184,10 @@ public abstract class AbstractTagTree extends JTree { return View.getIcon("foldersounds16"); } + if (val instanceof ClassesListTreeModel) { + return View.getIcon("folderscripts16"); + } + TreeNodeType type = getTreeNodeType(val); if (type == TreeNodeType.FOLDER && folderExpanded) { diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/FilteredTreeModel.java b/src/com/jpexs/decompiler/flash/gui/tagtree/FilteredTreeModel.java index fbb0dea42..4ad3c4b60 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/FilteredTreeModel.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/FilteredTreeModel.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.gui.tagtree; import com.jpexs.decompiler.flash.gui.abc.ClassesListTreeModel; import com.jpexs.decompiler.flash.treeitems.FolderItem; +import com.jpexs.decompiler.flash.treeitems.HeaderItem; import com.jpexs.decompiler.flash.treeitems.Openable; import com.jpexs.decompiler.flash.treeitems.OpenableList; import com.jpexs.decompiler.flash.treeitems.TreeItem; @@ -37,6 +38,8 @@ import javax.swing.tree.TreePath; public class FilteredTreeModel implements TreeModel { private String filter; + + private List foldersFilter; private TreeItem root; private Map> subItems = new WeakHashMap<>(); @@ -49,8 +52,13 @@ public class FilteredTreeModel implements TreeModel { return filter; } - public FilteredTreeModel(String filter, AbstractTagTreeModel fullModel, JTree tree) { + public List getFoldersFilter() { + return foldersFilter; + } + + public FilteredTreeModel(String filter, List foldersFilter, AbstractTagTreeModel fullModel, JTree tree) { this.filter = filter; + this.foldersFilter = foldersFilter; this.tree = tree; fullModel.addTreeModelListener(new TreeModelListener() { @@ -114,13 +122,34 @@ public class FilteredTreeModel implements TreeModel { private void buildTree(AbstractTagTreeModel fullModel, TreeItem item, String path, String searchPath, List selectionPaths) { List items = fullModel.getAllChildren(item); List newSubItems = new ArrayList<>(); - if (filter.trim().isEmpty()) { + if (filter.trim().isEmpty() && foldersFilter.isEmpty()) { newSubItems.addAll(items); } else { for (TreeItem ti : items) { String subPath = path + "." + ti.toString(); String searchSubPath = isItemSearchable(ti) ? searchPath + "." + ti.toString() : searchPath; boolean matches = searchSubPath.toLowerCase().contains(filter.toLowerCase()); + + if (!foldersFilter.isEmpty()) { + if (ti instanceof ClassesListTreeModel) { + if (!foldersFilter.contains("scripts")) { + continue; + } + } + if (ti instanceof FolderItem) { + FolderItem f = (FolderItem) ti; + if (!foldersFilter.contains(f.getName())) { + continue; + } + } + if (ti instanceof HeaderItem) { + HeaderItem h = (HeaderItem) ti; + if (!foldersFilter.contains("header")) { + continue; + } + } + } + if (fullModel.isLeaf(ti)) { if (matches || selectionPaths.contains(subPath)) { newSubItems.add(ti); diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java index 7bd646783..e37997995 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java @@ -55,10 +55,13 @@ import com.jpexs.decompiler.flash.treeitems.OpenableList; import com.jpexs.decompiler.flash.treeitems.TreeItem; import java.io.File; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.WeakHashMap; import javax.swing.event.TreeModelEvent; import javax.swing.event.TreeModelListener; @@ -70,7 +73,7 @@ import javax.swing.tree.TreePath; public class TagTreeModel extends AbstractTagTreeModel { public static final String FOLDER_COOKIES = "cookies"; - + public static final String FOLDER_SHAPES = "shapes"; public static final String FOLDER_MORPHSHAPES = "morphshapes"; @@ -99,6 +102,25 @@ public class TagTreeModel extends AbstractTagTreeModel { public static final String FOLDER_SCENES = "scenes"; + public static final List FOLDERS_ORDER = Arrays.asList( + "header", + "cookies", + "shapes", + "morphshapes", + "sprites", + "texts", + "images", + "movies", + "sounds", + "buttons", + "fonts", + "binaryData", + "frames", + "scenes", + "others", + "scripts" + ); + private final List listeners = new ArrayList<>(); private final TagTreeRoot root = new TagTreeRoot(); @@ -282,7 +304,7 @@ public class TagTreeModel extends AbstractTagTreeModel { } } } - + List cookies = new ArrayList<>(); if (swf.getFile() != null) { List solFiles = SharedObjectsStorage.getSolFilesForLocalFile(new File(swf.getFile())); @@ -291,34 +313,69 @@ public class TagTreeModel extends AbstractTagTreeModel { } } - nodeList.add(new HeaderItem(swf, translate("node.header"))); - - addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.cookies"), FOLDER_COOKIES, swf, cookies); - addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.shapes"), FOLDER_SHAPES, swf, shapes); - addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.morphshapes"), FOLDER_MORPHSHAPES, swf, morphShapes); - addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.sprites"), FOLDER_SPRITES, swf, sprites); - addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.texts"), FOLDER_TEXTS, swf, texts); - addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.images"), FOLDER_IMAGES, swf, images); - addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.movies"), FOLDER_MOVIES, swf, movies); - addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.sounds"), FOLDER_SOUNDS, swf, sounds); - addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.buttons"), FOLDER_BUTTONS, swf, buttons); - addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.fonts"), FOLDER_FONTS, swf, fonts); - addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.binaryData"), FOLDER_BINARY_DATA, swf, binaryData); - addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.frames"), FOLDER_FRAMES, swf, frames); - addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.scenes"), FOLDER_SCENES, swf, scenes); - addFolderItem(nodeList, emptyFolders, true /*always add*/, translate("node.others"), FOLDER_OTHERS, swf, others); - Map currentTagScriptCache = new HashMap<>(); - if (swf.isAS3()) { - if (!swf.getAbcList().isEmpty()) { - nodeList.add(new ClassesListTreeModel(swf, Configuration.flattenASPackages.get())); - } - } else { - List subNodes = swf.getFirstLevelASMNodes(currentTagScriptCache); - if (subNodes.size() > 0) { - TreeItem actionScriptNode = new FolderItem(translate("node.scripts"), FOLDER_SCRIPTS, swf, subNodes); - nodeList.add(actionScriptNode); + for (String key : FOLDERS_ORDER) { + switch (key) { + case "header": + nodeList.add(new HeaderItem(swf, translate("node.header"))); + break; + case "cookies": + addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.cookies"), FOLDER_COOKIES, swf, cookies); + break; + case "shapes": + addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.shapes"), FOLDER_SHAPES, swf, shapes); + break; + case "morphshapes": + addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.morphshapes"), FOLDER_MORPHSHAPES, swf, morphShapes); + break; + case "sprites": + addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.sprites"), FOLDER_SPRITES, swf, sprites); + break; + case "texts": + addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.texts"), FOLDER_TEXTS, swf, texts); + break; + case "images": + addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.images"), FOLDER_IMAGES, swf, images); + break; + case "movies": + addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.movies"), FOLDER_MOVIES, swf, movies); + break; + case "sounds": + addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.sounds"), FOLDER_SOUNDS, swf, sounds); + break; + case "buttons": + addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.buttons"), FOLDER_BUTTONS, swf, buttons); + break; + case "fonts": + addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.fonts"), FOLDER_FONTS, swf, fonts); + break; + case "binaryData": + addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.binaryData"), FOLDER_BINARY_DATA, swf, binaryData); + break; + case "frames": + addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.frames"), FOLDER_FRAMES, swf, frames); + break; + case "scenes": + addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.scenes"), FOLDER_SCENES, swf, scenes); + break; + case "others": + addFolderItem(nodeList, emptyFolders, true /*always add*/, translate("node.others"), FOLDER_OTHERS, swf, others); + break; + case "scripts": + if (swf.isAS3()) { + if (!swf.getAbcList().isEmpty()) { + nodeList.add(new ClassesListTreeModel(swf, Configuration.flattenASPackages.get())); + } + } else { + List subNodes = swf.getFirstLevelASMNodes(currentTagScriptCache); + + if (subNodes.size() > 0) { + TreeItem actionScriptNode = new FolderItem(translate("node.scripts"), FOLDER_SCRIPTS, swf, subNodes); + nodeList.add(actionScriptNode); + } + } + break; } } @@ -330,6 +387,31 @@ public class TagTreeModel extends AbstractTagTreeModel { swfInfos.put(swf, swfInfo); } + public List getAvailableFolders() { + Set folderNames = new LinkedHashSet<>(); + folderNames.add("header"); + for (TagTreeSwfInfo swfInfo : swfInfos.values()) { + for (TreeItem item : swfInfo.folders) { + if (item instanceof FolderItem) { + FolderItem f = (FolderItem) item; + folderNames.add(f.getName()); + } + if (item instanceof ClassesListTreeModel) { + folderNames.add("scripts"); + } + } + } + + List ret = new ArrayList<>(); + for (String f : FOLDERS_ORDER) { + if (folderNames.contains(f)) { + ret.add(f); + } + } + + return ret; + } + private void addFolderItem(List nodeList, List emptyList, boolean addAllFolders, String title, String folderName, SWF swf, List items) { FolderItem node = new FolderItem(title, folderName, swf, items); if (addAllFolders || !items.isEmpty()) {