TagTree context menu moved to separate control, support to loadmultiple inner swfs from binary data tags

This commit is contained in:
2014-11-10 21:11:22 +01:00
parent 9129fd1010
commit 819fa5ee49
4 changed files with 430 additions and 339 deletions
@@ -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();
@@ -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<SWFList> 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;
}
@@ -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<SWFList> swfs;
public void createContextMenu(final List<SWFList> 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<TreeItem> 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<SWFList> swfs, List<TreeItem> 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<Integer> 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<TreeItem> sel = getSelected(this);
List<Tag> 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<TreeItem> getSelection(SWF swf, List<TreeItem> sel) {
List<TreeItem> ret = new ArrayList<>();
for (TreeItem d : sel) {
if (d instanceof SWFList) {
continue;
}
if (d.getSwf() != swf) {
continue;
}
@@ -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 <http://www.gnu.org/licenses/>.
*/
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<TreeItem> 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<TreeItem> items) {
if (items.isEmpty()) {
return;
}
final List<SWFList> 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<Integer> 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<TreeItem> 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<TreeItem> sel = tagTree.getSelected(tagTree);
List<Tag> 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<TreeItem> 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);
}
}
}
}
}
}