From 819fa5ee495ed54942576c7c6d26cca194364d8b Mon Sep 17 00:00:00 2001 From: "honfika@gmail.com" Date: Mon, 10 Nov 2014 21:11:22 +0100 Subject: [PATCH] TagTree context menu moved to separate control, support to loadmultiple inner swfs from binary data tags --- .../flash/gui/FolderPreviewPanel.java | 2 +- .../jpexs/decompiler/flash/gui/MainPanel.java | 8 +- .../decompiler/flash/gui/tagtree/TagTree.java | 345 +-------------- .../flash/gui/tagtree/TagTreeContextMenu.java | 414 ++++++++++++++++++ 4 files changed, 430 insertions(+), 339 deletions(-) create mode 100644 src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java diff --git a/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java b/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java index cf1ec40b4..bd2aeb159 100644 --- a/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java @@ -130,7 +130,7 @@ public class FolderPreviewPanel extends JPanel { } if (e.getButton() == MouseEvent.BUTTON3) { - mainPanel.tagTree.updateContextMenu(mainPanel.tagTree.swfs, new ArrayList<>(selectedItems.values())); + mainPanel.tagTree.contextPopupMenu.update(new ArrayList<>(selectedItems.values())); mainPanel.tagTree.contextPopupMenu.show(FolderPreviewPanel.this, e.getX(), e.getY()); } repaint(); diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index e3e3ca3da..459b64ff0 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -471,7 +471,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec } }); - tagTree.createContextMenu(swfs); + tagTree.createContextMenu(); dumpTree = new DumpTree(null, this); dumpTree.addTreeSelectionListener(this); @@ -1120,6 +1120,10 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec } } + public List getSwfs() { + return swfs; + } + public SWFList getCurrentSwfList() { SWF swf = getCurrentSwf(); if (swf == null) { @@ -1140,7 +1144,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec return swfs.get(0).get(0); } - if (treeNode instanceof SWFBundle) { + if (treeNode instanceof SWFList) { return null; } diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java index b2bb7cf52..bf61b3214 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java @@ -20,8 +20,6 @@ import com.jpexs.decompiler.flash.SWC; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.ZippedSWFBundle; import com.jpexs.decompiler.flash.abc.ScriptPack; -import com.jpexs.decompiler.flash.gui.Main; -import com.jpexs.decompiler.flash.gui.MainFrameRibbonMenu; import com.jpexs.decompiler.flash.gui.MainPanel; import com.jpexs.decompiler.flash.gui.TreeNodeType; import com.jpexs.decompiler.flash.gui.View; @@ -96,8 +94,6 @@ import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.VideoFrameTag; import com.jpexs.decompiler.flash.tags.base.ASMSource; import com.jpexs.decompiler.flash.tags.base.ButtonTag; -import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.ContainerItem; import com.jpexs.decompiler.flash.tags.base.ImageTag; import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; @@ -109,42 +105,26 @@ import com.jpexs.decompiler.flash.timeline.AS3Package; import com.jpexs.decompiler.flash.timeline.Frame; import com.jpexs.decompiler.flash.timeline.FrameScript; import com.jpexs.decompiler.flash.timeline.TagScript; -import com.jpexs.decompiler.flash.timeline.Timelined; import com.jpexs.decompiler.flash.treeitems.AS3ClassTreeItem; import com.jpexs.decompiler.flash.treeitems.FolderItem; import com.jpexs.decompiler.flash.treeitems.HeaderItem; import com.jpexs.decompiler.flash.treeitems.SWFList; import com.jpexs.decompiler.flash.treeitems.TreeItem; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.utf8.Utf8Helper; import java.awt.Color; import java.awt.Component; import java.awt.Font; import java.awt.Graphics; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.swing.Icon; import javax.swing.JComponent; -import javax.swing.JMenu; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import javax.swing.JPopupMenu; import javax.swing.JTree; -import javax.swing.SwingUtilities; import javax.swing.plaf.basic.BasicLabelUI; import javax.swing.plaf.basic.BasicTreeUI; import javax.swing.tree.DefaultTreeCellRenderer; -import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; @@ -152,16 +132,9 @@ import javax.swing.tree.TreeSelectionModel; * * @author JPEXS */ -public class TagTree extends JTree implements ActionListener { - - private static final String ACTION_RAW_EDIT = "RAWEDIT"; - private static final String ACTION_JUMP_TO_CHARACTER = "JUMPTOCHARACTER"; - private static final String ACTION_REMOVE_ITEM = "REMOVEITEM"; - private static final String ACTION_REMOVE_ITEM_WITH_DEPENDENCIES = "REMOVEITEMWITHDEPENDENCIES"; - private static final String ACTION_CLOSE_SWF = "CLOSESWF"; - private static final String ACTION_EXPAND_RECURSIVE = "EXPANDRECURSIVE"; - private static final String ACTION_OPEN_SWFINSIDE = "OPENSWFINSIDE"; +public class TagTree extends JTree { + public TagTreeContextMenu contextPopupMenu; private final MainPanel mainPanel; public class TagTreeCellRenderer extends DefaultTreeCellRenderer { @@ -252,6 +225,10 @@ public class TagTree extends JTree implements ActionListener { }); } + public void createContextMenu() { + contextPopupMenu = new TagTreeContextMenu(this, mainPanel); + } + public static TreeNodeType getTreeNodeType(TreeItem t) { if (t instanceof TagScript) { @@ -425,313 +402,6 @@ public class TagTree extends JTree implements ActionListener { SoundStreamBlockTag.ID, SoundStreamHeadTag.ID, SoundStreamHead2Tag.ID); } - JMenuItem expandRecursiveMenuItem; - JMenuItem removeMenuItem; - JMenuItem removeWithDependenciesMenuItem; - JMenuItem exportSelectionMenuItem; - JMenuItem replaceSelectionMenuItem; - JMenuItem rawEditMenuItem; - JMenuItem jumpToCharacterMenuItem; - JMenuItem closeSelectionMenuItem; - JMenu addTagMenu; - JMenu moveTagMenu; - JMenuItem openSWFInsideTagMenuItem; - public JPopupMenu contextPopupMenu; - public List swfs; - - public void createContextMenu(final List swfs) { - this.swfs = swfs; - contextPopupMenu = new JPopupMenu(); - expandRecursiveMenuItem = new JMenuItem(mainPanel.translate("contextmenu.expandAll")); - expandRecursiveMenuItem.addActionListener(this); - expandRecursiveMenuItem.setActionCommand(ACTION_EXPAND_RECURSIVE); - contextPopupMenu.add(expandRecursiveMenuItem); - - removeMenuItem = new JMenuItem(mainPanel.translate("contextmenu.remove")); - removeMenuItem.addActionListener(this); - removeMenuItem.setActionCommand(ACTION_REMOVE_ITEM); - contextPopupMenu.add(removeMenuItem); - - removeWithDependenciesMenuItem = new JMenuItem(mainPanel.translate("contextmenu.removeWithDependencies")); - removeWithDependenciesMenuItem.addActionListener(this); - removeWithDependenciesMenuItem.setActionCommand(ACTION_REMOVE_ITEM_WITH_DEPENDENCIES); - contextPopupMenu.add(removeWithDependenciesMenuItem); - - exportSelectionMenuItem = new JMenuItem(mainPanel.translate("menu.file.export.selection")); - exportSelectionMenuItem.setActionCommand(MainFrameRibbonMenu.ACTION_EXPORT_SEL); - exportSelectionMenuItem.addActionListener(mainPanel); - contextPopupMenu.add(exportSelectionMenuItem); - - replaceSelectionMenuItem = new JMenuItem(mainPanel.translate("button.replace")); - replaceSelectionMenuItem.setActionCommand(MainPanel.ACTION_REPLACE); - replaceSelectionMenuItem.addActionListener(mainPanel); - contextPopupMenu.add(replaceSelectionMenuItem); - - rawEditMenuItem = new JMenuItem(mainPanel.translate("contextmenu.rawEdit")); - rawEditMenuItem.setActionCommand(ACTION_RAW_EDIT); - rawEditMenuItem.addActionListener(this); - rawEditMenuItem.setVisible(false); - contextPopupMenu.add(rawEditMenuItem); - - jumpToCharacterMenuItem = new JMenuItem(mainPanel.translate("contextmenu.jumpToCharacter")); - jumpToCharacterMenuItem.setActionCommand(ACTION_JUMP_TO_CHARACTER); - jumpToCharacterMenuItem.addActionListener(this); - jumpToCharacterMenuItem.setVisible(false); - contextPopupMenu.add(jumpToCharacterMenuItem); - - closeSelectionMenuItem = new JMenuItem(mainPanel.translate("contextmenu.closeSwf")); - closeSelectionMenuItem.setActionCommand(ACTION_CLOSE_SWF); - closeSelectionMenuItem.addActionListener(this); - contextPopupMenu.add(closeSelectionMenuItem); - - addTagMenu = new JMenu(mainPanel.translate("contextmenu.addTag")); - contextPopupMenu.add(addTagMenu); - - moveTagMenu = new JMenu(mainPanel.translate("contextmenu.moveTag")); - contextPopupMenu.add(moveTagMenu); - - openSWFInsideTagMenuItem = new JMenuItem(mainPanel.translate("contextmenu.openswfinside")); - contextPopupMenu.add(openSWFInsideTagMenuItem); - openSWFInsideTagMenuItem.setActionCommand(ACTION_OPEN_SWFINSIDE); - openSWFInsideTagMenuItem.addActionListener(this); - - addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - if (SwingUtilities.isRightMouseButton(e)) { - - int row = getClosestRowForLocation(e.getX(), e.getY()); - int[] selectionRows = getSelectionRows(); - if (!Helper.contains(selectionRows, row)) { - setSelectionRow(row); - } - - TreePath[] paths = getSelectionPaths(); - if (paths == null || paths.length == 0) { - return; - } - boolean allSelectedIsTagOrFrame = true; - for (TreePath treePath : paths) { - TreeItem tag = (TreeItem) treePath.getLastPathComponent(); - if (!(tag instanceof Tag) && !(tag instanceof Frame)) { - allSelectedIsTagOrFrame = false; - break; - } - } - - replaceSelectionMenuItem.setVisible(false); - closeSelectionMenuItem.setVisible(false); - moveTagMenu.setVisible(false); - addTagMenu.setVisible(false); - expandRecursiveMenuItem.setVisible(false); - openSWFInsideTagMenuItem.setVisible(false); - - if (paths.length == 1) { - TreeItem item = (TreeItem) paths[0].getLastPathComponent(); - List li = new ArrayList<>(); - li.add(item); - updateContextMenu(swfs, li); - } - - removeMenuItem.setVisible(allSelectedIsTagOrFrame); - exportSelectionMenuItem.setEnabled(hasExportableNodes()); - contextPopupMenu.show(e.getComponent(), e.getX(), e.getY()); - } - } - }); - } - - public void updateContextMenu(final List swfs, List items) { - - replaceSelectionMenuItem.setVisible(false); - closeSelectionMenuItem.setVisible(false); - moveTagMenu.setVisible(false); - addTagMenu.setVisible(false); - expandRecursiveMenuItem.setVisible(false); - openSWFInsideTagMenuItem.setVisible(false); - removeMenuItem.setVisible(true); - for (TreeItem t : items) { - if (!((t instanceof Tag) || (t instanceof Frame))) { - removeMenuItem.setVisible(false); - } - } - exportSelectionMenuItem.setEnabled(!items.isEmpty() && !getSelection(items.get(0).getSwf(), items).isEmpty()); - - final TreeItem item = items.get(0); - if (item instanceof ImageTag && ((ImageTag) item).importSupported()) { - replaceSelectionMenuItem.setVisible(true); - } - - if (item instanceof DefineBinaryDataTag) { - replaceSelectionMenuItem.setVisible(true); - DefineBinaryDataTag bin = (DefineBinaryDataTag) item; - if (bin.isSwfData()) { - openSWFInsideTagMenuItem.setVisible(true); - } - } - - if (item instanceof DefineSoundTag) { - replaceSelectionMenuItem.setVisible(true); - } - - if (item instanceof SWF) { - closeSelectionMenuItem.setVisible(true); - } - - List allowedTagTypes = null; - if (item instanceof FolderItem) { - allowedTagTypes = getSwfFolderItemNestedTagIds(((FolderItem) item).getName(), item.getSwf().gfx); - } else if (item instanceof DefineSpriteTag) { - allowedTagTypes = getSpriteNestedTagIds(); - } - - addTagMenu.removeAll(); - if (allowedTagTypes != null) { - for (Integer tagId : allowedTagTypes) { - final Class cl = TagIdClassMap.getClassByTagId(tagId); - JMenuItem tagItem = new JMenuItem(cl.getSimpleName()); - tagItem.addActionListener(new ActionListener() { - - @Override - @SuppressWarnings("unchecked") - public void actionPerformed(ActionEvent ae) { - try { - SWF swf = item.getSwf(); - Tag t = (Tag) cl.getDeclaredConstructor(SWF.class).newInstance(new Object[]{swf}); - boolean isDefineSprite = item instanceof DefineSpriteTag; - Timelined timelined = isDefineSprite ? (DefineSpriteTag) item : swf; - t.setTimelined(timelined); - if (isDefineSprite) { - ((DefineSpriteTag) item).subTags.add(t); - } else { - swf.tags.add(t); - } - timelined.getTimeline().reset(); - swf.updateCharacters(); - mainPanel.refreshTree(); - } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException ex) { - Logger.getLogger(TagTree.class.getName()).log(Level.SEVERE, null, ex); - } - } - }); - addTagMenu.add(tagItem); - } - addTagMenu.setVisible(true); - } - - if (item instanceof Tag && swfs.size() > 1) { - final Tag tag = (Tag) item; - moveTagMenu.removeAll(); - for (SWFList targetSwfList : swfs) { - for (final SWF targetSwf : targetSwfList) { - if (targetSwf != tag.getSwf()) { - JMenuItem swfItem = new JMenuItem(targetSwf.getShortFileName()); - swfItem.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent ae) { - tag.getSwf().tags.remove(tag); - tag.setSwf(targetSwf); - targetSwf.tags.add(tag); - mainPanel.refreshTree(); - } - }); - moveTagMenu.add(swfItem); - } - } - } - moveTagMenu.setVisible(true); - } - - TreeModel model = getModel(); - expandRecursiveMenuItem.setVisible(model.getChildCount(item) > 0); - - jumpToCharacterMenuItem.setVisible(item instanceof CharacterIdTag && !(item instanceof CharacterTag)); - - rawEditMenuItem.setVisible(item instanceof Tag); - } - - @Override - public void actionPerformed(ActionEvent e) { - switch (e.getActionCommand()) { - case ACTION_OPEN_SWFINSIDE: - Object itemo = getLastSelectedPathComponent(); - if (itemo == null) { - return; - } - if (itemo instanceof DefineBinaryDataTag) { - mainPanel.loadFromBinaryTag((DefineBinaryDataTag) itemo); - } - break; - case ACTION_RAW_EDIT: { - TreeItem itemr = getCurrentTreeItem(); - if (itemr == null) { - return; - } - - mainPanel.showGenericTag((Tag) itemr); - } - break; - case ACTION_JUMP_TO_CHARACTER: { - TreeItem itemj = getCurrentTreeItem(); - if (itemj == null || !(itemj instanceof CharacterIdTag)) { - return; - } - - CharacterIdTag characterIdTag = (CharacterIdTag) itemj; - mainPanel.setTagTreeSelectedNode(itemj.getSwf().characters.get(characterIdTag.getCharacterId())); - } - break; - case ACTION_EXPAND_RECURSIVE: { - TreePath path = getSelectionPath(); - if (path == null) { - return; - } - View.expandTreeNodesRecursive(this, path, true); - } - break; - case ACTION_REMOVE_ITEM: - case ACTION_REMOVE_ITEM_WITH_DEPENDENCIES: - List sel = getSelected(this); - - List tagsToRemove = new ArrayList<>(); - for (TreeItem tag : sel) { - if (tag instanceof Tag) { - tagsToRemove.add((Tag) tag); - } else if (tag instanceof Frame) { - Frame frameNode = (Frame) tag; - Frame frame = frameNode.timeline.getFrames().get(frameNode.frame); - if (frame.showFrameTag != null) { - tagsToRemove.add(frame.showFrameTag); - } else { - // this should be the last frame, so remove the inner tags - tagsToRemove.addAll(frame.innerTags); - } - } - } - - 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(); - } - } 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) { - for (Tag tag : tagsToRemove) { - tag.getSwf().removeTag(tag, removeDependencies); - } - mainPanel.refreshTree(); - } - } - break; - case ACTION_CLOSE_SWF: { - Main.closeFile(mainPanel.getCurrentSwfList()); - } - } - } - public boolean hasExportableNodes() { return !getSelection(mainPanel.getCurrentSwf()).isEmpty(); } @@ -794,6 +464,9 @@ public class TagTree extends JTree implements ActionListener { public List getSelection(SWF swf, List sel) { List ret = new ArrayList<>(); for (TreeItem d : sel) { + if (d instanceof SWFList) { + continue; + } if (d.getSwf() != swf) { continue; } diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java new file mode 100644 index 000000000..7411911c3 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2010-2014 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.tagtree; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.gui.Main; +import com.jpexs.decompiler.flash.gui.MainFrameRibbonMenu; +import com.jpexs.decompiler.flash.gui.MainPanel; +import com.jpexs.decompiler.flash.gui.View; +import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; +import com.jpexs.decompiler.flash.tags.DefineSoundTag; +import com.jpexs.decompiler.flash.tags.DefineSpriteTag; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.timeline.Frame; +import com.jpexs.decompiler.flash.timeline.Timelined; +import com.jpexs.decompiler.flash.treeitems.FolderItem; +import com.jpexs.decompiler.flash.treeitems.SWFList; +import com.jpexs.decompiler.flash.treeitems.TreeItem; +import com.jpexs.helpers.Helper; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPopupMenu; +import javax.swing.SwingUtilities; +import javax.swing.tree.TreePath; + +/** + * + * @author JPEXS + */ +public class TagTreeContextMenu extends JPopupMenu implements ActionListener { + + private static final String ACTION_RAW_EDIT = "RAWEDIT"; + private static final String ACTION_JUMP_TO_CHARACTER = "JUMPTOCHARACTER"; + private static final String ACTION_REMOVE_ITEM = "REMOVEITEM"; + private static final String ACTION_REMOVE_ITEM_WITH_DEPENDENCIES = "REMOVEITEMWITHDEPENDENCIES"; + private static final String ACTION_CLOSE_SWF = "CLOSESWF"; + private static final String ACTION_EXPAND_RECURSIVE = "EXPANDRECURSIVE"; + private static final String ACTION_OPEN_SWFINSIDE = "OPENSWFINSIDE"; + + private final MainPanel mainPanel; + private final TagTree tagTree; + + private JMenuItem expandRecursiveMenuItem; + private JMenuItem removeMenuItem; + private JMenuItem removeWithDependenciesMenuItem; + private JMenuItem exportSelectionMenuItem; + private JMenuItem replaceMenuItem; + private JMenuItem rawEditMenuItem; + private JMenuItem jumpToCharacterMenuItem; + private JMenuItem closeMenuItem; + private JMenu addTagMenu; + private JMenu moveTagMenu; + private JMenuItem openSWFInsideTagMenuItem; + + public TagTreeContextMenu(final TagTree tagTree, MainPanel mainPanel) { + this.mainPanel = mainPanel; + this.tagTree = tagTree; + expandRecursiveMenuItem = new JMenuItem(mainPanel.translate("contextmenu.expandAll")); + expandRecursiveMenuItem.addActionListener(this); + expandRecursiveMenuItem.setActionCommand(ACTION_EXPAND_RECURSIVE); + add(expandRecursiveMenuItem); + + removeMenuItem = new JMenuItem(mainPanel.translate("contextmenu.remove")); + removeMenuItem.addActionListener(this); + removeMenuItem.setActionCommand(ACTION_REMOVE_ITEM); + add(removeMenuItem); + + removeWithDependenciesMenuItem = new JMenuItem(mainPanel.translate("contextmenu.removeWithDependencies")); + removeWithDependenciesMenuItem.addActionListener(this); + removeWithDependenciesMenuItem.setActionCommand(ACTION_REMOVE_ITEM_WITH_DEPENDENCIES); + add(removeWithDependenciesMenuItem); + + exportSelectionMenuItem = new JMenuItem(mainPanel.translate("menu.file.export.selection")); + exportSelectionMenuItem.setActionCommand(MainFrameRibbonMenu.ACTION_EXPORT_SEL); + exportSelectionMenuItem.addActionListener(mainPanel); + add(exportSelectionMenuItem); + + replaceMenuItem = new JMenuItem(mainPanel.translate("button.replace")); + replaceMenuItem.setActionCommand(MainPanel.ACTION_REPLACE); + replaceMenuItem.addActionListener(mainPanel); + add(replaceMenuItem); + + rawEditMenuItem = new JMenuItem(mainPanel.translate("contextmenu.rawEdit")); + rawEditMenuItem.setActionCommand(ACTION_RAW_EDIT); + rawEditMenuItem.addActionListener(this); + rawEditMenuItem.setVisible(false); + add(rawEditMenuItem); + + jumpToCharacterMenuItem = new JMenuItem(mainPanel.translate("contextmenu.jumpToCharacter")); + jumpToCharacterMenuItem.setActionCommand(ACTION_JUMP_TO_CHARACTER); + jumpToCharacterMenuItem.addActionListener(this); + jumpToCharacterMenuItem.setVisible(false); + add(jumpToCharacterMenuItem); + + closeMenuItem = new JMenuItem(mainPanel.translate("contextmenu.closeSwf")); + closeMenuItem.setActionCommand(ACTION_CLOSE_SWF); + closeMenuItem.addActionListener(this); + add(closeMenuItem); + + addTagMenu = new JMenu(mainPanel.translate("contextmenu.addTag")); + add(addTagMenu); + + moveTagMenu = new JMenu(mainPanel.translate("contextmenu.moveTag")); + add(moveTagMenu); + + openSWFInsideTagMenuItem = new JMenuItem(mainPanel.translate("contextmenu.openswfinside")); + add(openSWFInsideTagMenuItem); + openSWFInsideTagMenuItem.setActionCommand(ACTION_OPEN_SWFINSIDE); + openSWFInsideTagMenuItem.addActionListener(this); + + tagTree.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (SwingUtilities.isRightMouseButton(e)) { + + int row = tagTree.getClosestRowForLocation(e.getX(), e.getY()); + int[] selectionRows = tagTree.getSelectionRows(); + if (!Helper.contains(selectionRows, row)) { + tagTree.setSelectionRow(row); + } + + TreePath[] paths = tagTree.getSelectionPaths(); + if (paths == null || paths.length == 0) { + return; + } + + List li = new ArrayList<>(); + for (TreePath treePath : paths) { + TreeItem item = (TreeItem) treePath.getLastPathComponent(); + li.add(item); + } + + update(li); + show(e.getComponent(), e.getX(), e.getY()); + } + } + }); + } + + public void update(List items) { + + if (items.isEmpty()) { + return; + } + + final List swfs = mainPanel.getSwfs(); + + boolean allSelectedIsTagOrFrame = true; + for (TreeItem item : items) { + if (!(item instanceof Tag) && !(item instanceof Frame)) { + allSelectedIsTagOrFrame = false; + break; + } + } + + boolean allSelectedIsBinaryData = true; + for (TreeItem item : items) { + if (!(item instanceof DefineBinaryDataTag)) { + allSelectedIsBinaryData = false; + break; + } + } + + boolean allSelectedIsSwf = true; + for (TreeItem item : items) { + if (!(item instanceof SWF) && !(item instanceof SWFList)) { + allSelectedIsSwf = false; + break; + } else if (item instanceof SWF) { + // Do not allow to close SWF in bundle + if (((SWF) item).swfList.isBundle) { + allSelectedIsSwf = false; + } + } + } + + expandRecursiveMenuItem.setVisible(false); + removeMenuItem.setVisible(allSelectedIsTagOrFrame); + removeWithDependenciesMenuItem.setVisible(allSelectedIsTagOrFrame); + exportSelectionMenuItem.setEnabled(tagTree.hasExportableNodes()); + replaceMenuItem.setVisible(false); + rawEditMenuItem.setVisible(false); + jumpToCharacterMenuItem.setVisible(false); + closeMenuItem.setVisible(allSelectedIsSwf); + addTagMenu.setVisible(false); + moveTagMenu.setVisible(false); + openSWFInsideTagMenuItem.setVisible(false); + + final TreeItem firstItem = items.get(0); + boolean singleSelect = items.size() == 1; + + if (singleSelect) { + // replace + if (firstItem instanceof ImageTag && ((ImageTag) firstItem).importSupported()) { + replaceMenuItem.setVisible(true); + } + + if (firstItem instanceof DefineBinaryDataTag) { + replaceMenuItem.setVisible(true); + } + + if (firstItem instanceof DefineSoundTag) { + replaceMenuItem.setVisible(true); + } + + List allowedTagTypes = null; + if (firstItem instanceof FolderItem) { + allowedTagTypes = tagTree.getSwfFolderItemNestedTagIds(((FolderItem) firstItem).getName(), firstItem.getSwf().gfx); + } else if (firstItem instanceof DefineSpriteTag) { + allowedTagTypes = tagTree.getSpriteNestedTagIds(); + } + + addTagMenu.removeAll(); + if (allowedTagTypes != null) { + for (Integer tagId : allowedTagTypes) { + final Class cl = TagIdClassMap.getClassByTagId(tagId); + JMenuItem tagItem = new JMenuItem(cl.getSimpleName()); + tagItem.addActionListener(new ActionListener() { + + @Override + @SuppressWarnings("unchecked") + public void actionPerformed(ActionEvent ae) { + try { + SWF swf = firstItem.getSwf(); + Tag t = (Tag) cl.getDeclaredConstructor(SWF.class).newInstance(new Object[]{swf}); + boolean isDefineSprite = firstItem instanceof DefineSpriteTag; + Timelined timelined = isDefineSprite ? (DefineSpriteTag) firstItem : swf; + t.setTimelined(timelined); + if (isDefineSprite) { + ((DefineSpriteTag) firstItem).subTags.add(t); + } else { + swf.tags.add(t); + } + timelined.getTimeline().reset(); + swf.updateCharacters(); + mainPanel.refreshTree(); + } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException ex) { + Logger.getLogger(TagTree.class.getName()).log(Level.SEVERE, null, ex); + } + } + }); + addTagMenu.add(tagItem); + } + addTagMenu.setVisible(true); + } + + if (firstItem instanceof Tag && swfs.size() > 1) { + final Tag tag = (Tag) firstItem; + moveTagMenu.removeAll(); + for (SWFList targetSwfList : swfs) { + for (final SWF targetSwf : targetSwfList) { + if (targetSwf != tag.getSwf()) { + JMenuItem swfItem = new JMenuItem(targetSwf.getShortFileName()); + swfItem.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent ae) { + tag.getSwf().tags.remove(tag); + tag.setSwf(targetSwf); + targetSwf.tags.add(tag); + mainPanel.refreshTree(); + } + }); + moveTagMenu.add(swfItem); + } + } + } + moveTagMenu.setVisible(true); + } + + if (tagTree.getModel().getChildCount(firstItem) > 0) { + expandRecursiveMenuItem.setVisible(true); + } + + if (firstItem instanceof CharacterIdTag && !(firstItem instanceof CharacterTag)) { + jumpToCharacterMenuItem.setVisible(true); + } + + if (firstItem instanceof Tag) { + rawEditMenuItem.setVisible(firstItem instanceof Tag); + } + } + + if (allSelectedIsBinaryData) { + boolean anyInnerSwf = false; + for (TreeItem item : items) { + DefineBinaryDataTag binary = (DefineBinaryDataTag) item; + + // inner swf is not loaded yet + if (binary.innerSwf == null && binary.isSwfData()) { + anyInnerSwf = true; + } + } + + openSWFInsideTagMenuItem.setVisible(anyInnerSwf); + } + } + + @Override + public void actionPerformed(ActionEvent e) { + switch (e.getActionCommand()) { + case ACTION_OPEN_SWFINSIDE: { + List sel = tagTree.getSelected(tagTree); + for (TreeItem item : sel) { + if (item instanceof DefineBinaryDataTag) { + mainPanel.loadFromBinaryTag((DefineBinaryDataTag) item); + } + } + } + break; + case ACTION_RAW_EDIT: { + TreeItem itemr = tagTree.getCurrentTreeItem(); + if (itemr == null) { + return; + } + + mainPanel.showGenericTag((Tag) itemr); + } + break; + case ACTION_JUMP_TO_CHARACTER: { + TreeItem itemj = tagTree.getCurrentTreeItem(); + if (itemj == null || !(itemj instanceof CharacterIdTag)) { + return; + } + + CharacterIdTag characterIdTag = (CharacterIdTag) itemj; + mainPanel.setTagTreeSelectedNode(itemj.getSwf().characters.get(characterIdTag.getCharacterId())); + } + break; + case ACTION_EXPAND_RECURSIVE: { + TreePath path = tagTree.getSelectionPath(); + if (path == null) { + return; + } + View.expandTreeNodesRecursive(tagTree, path, true); + } + break; + case ACTION_REMOVE_ITEM: + case ACTION_REMOVE_ITEM_WITH_DEPENDENCIES: { + List sel = tagTree.getSelected(tagTree); + + List tagsToRemove = new ArrayList<>(); + for (TreeItem tag : sel) { + if (tag instanceof Tag) { + tagsToRemove.add((Tag) tag); + } else if (tag instanceof Frame) { + Frame frameNode = (Frame) tag; + Frame frame = frameNode.timeline.getFrames().get(frameNode.frame); + if (frame.showFrameTag != null) { + tagsToRemove.add(frame.showFrameTag); + } else { + // this should be the last frame, so remove the inner tags + tagsToRemove.addAll(frame.innerTags); + } + } + } + + 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(); + } + } 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) { + for (Tag tag : tagsToRemove) { + tag.getSwf().removeTag(tag, removeDependencies); + } + mainPanel.refreshTree(); + } + } + } + break; + case ACTION_CLOSE_SWF: { + List sel = tagTree.getSelected(tagTree); + for (TreeItem item : sel) { + if (item instanceof SWF) { + Main.closeFile(((SWF) item).swfList); + } else if (item instanceof SWFList) { + Main.closeFile((SWFList) item); + } + } + } + } + } +}