mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-05-24 16:44:32 +00:00
5817 lines
235 KiB
Java
5817 lines
235 KiB
Java
/*
|
|
* Copyright (C) 2010-2022 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;
|
|
|
|
import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler;
|
|
import com.jpexs.decompiler.flash.ApplicationInfo;
|
|
import com.jpexs.decompiler.flash.Bundle;
|
|
import com.jpexs.decompiler.flash.DecompilerPool;
|
|
import com.jpexs.decompiler.flash.EventListener;
|
|
import com.jpexs.decompiler.flash.OpenableSourceInfo;
|
|
import com.jpexs.decompiler.flash.ReadOnlyTagList;
|
|
import com.jpexs.decompiler.flash.SWF;
|
|
import com.jpexs.decompiler.flash.abc.ABC;
|
|
import com.jpexs.decompiler.flash.abc.RenameType;
|
|
import com.jpexs.decompiler.flash.abc.ScriptPack;
|
|
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
|
|
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AbcMultiNameCollisionFixer;
|
|
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.DeobfuscationLevel;
|
|
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.DeobfuscationScope;
|
|
import com.jpexs.decompiler.flash.abc.types.ClassInfo;
|
|
import com.jpexs.decompiler.flash.abc.types.InstanceInfo;
|
|
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
|
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
|
import com.jpexs.decompiler.flash.abc.types.traits.TraitClass;
|
|
import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction;
|
|
import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter;
|
|
import com.jpexs.decompiler.flash.configuration.Configuration;
|
|
import com.jpexs.decompiler.flash.configuration.ConfigurationItem;
|
|
import com.jpexs.decompiler.flash.configuration.ConfigurationItemChangeListener;
|
|
import com.jpexs.decompiler.flash.configuration.CustomConfigurationKeys;
|
|
import com.jpexs.decompiler.flash.configuration.SwfSpecificCustomConfiguration;
|
|
import com.jpexs.decompiler.flash.dumpview.DumpInfo;
|
|
import com.jpexs.decompiler.flash.dumpview.DumpInfoSwfNode;
|
|
import com.jpexs.decompiler.flash.exporters.BinaryDataExporter;
|
|
import com.jpexs.decompiler.flash.exporters.FontExporter;
|
|
import com.jpexs.decompiler.flash.exporters.FrameExporter;
|
|
import com.jpexs.decompiler.flash.exporters.ImageExporter;
|
|
import com.jpexs.decompiler.flash.exporters.MorphShapeExporter;
|
|
import com.jpexs.decompiler.flash.exporters.MovieExporter;
|
|
import com.jpexs.decompiler.flash.exporters.PreviewExporter;
|
|
import com.jpexs.decompiler.flash.exporters.ShapeExporter;
|
|
import com.jpexs.decompiler.flash.exporters.SoundExporter;
|
|
import com.jpexs.decompiler.flash.exporters.SymbolClassExporter;
|
|
import com.jpexs.decompiler.flash.exporters.TextExporter;
|
|
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
|
import com.jpexs.decompiler.flash.exporters.modes.BinaryDataExportMode;
|
|
import com.jpexs.decompiler.flash.exporters.modes.ButtonExportMode;
|
|
import com.jpexs.decompiler.flash.exporters.modes.FontExportMode;
|
|
import com.jpexs.decompiler.flash.exporters.modes.FrameExportMode;
|
|
import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode;
|
|
import com.jpexs.decompiler.flash.exporters.modes.MorphShapeExportMode;
|
|
import com.jpexs.decompiler.flash.exporters.modes.MovieExportMode;
|
|
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
|
import com.jpexs.decompiler.flash.exporters.modes.ShapeExportMode;
|
|
import com.jpexs.decompiler.flash.exporters.modes.SoundExportMode;
|
|
import com.jpexs.decompiler.flash.exporters.modes.SpriteExportMode;
|
|
import com.jpexs.decompiler.flash.exporters.modes.SymbolClassExportMode;
|
|
import com.jpexs.decompiler.flash.exporters.modes.TextExportMode;
|
|
import com.jpexs.decompiler.flash.exporters.script.AS2ScriptExporter;
|
|
import com.jpexs.decompiler.flash.exporters.script.AS3ScriptExporter;
|
|
import com.jpexs.decompiler.flash.exporters.settings.BinaryDataExportSettings;
|
|
import com.jpexs.decompiler.flash.exporters.settings.ButtonExportSettings;
|
|
import com.jpexs.decompiler.flash.exporters.settings.FontExportSettings;
|
|
import com.jpexs.decompiler.flash.exporters.settings.FrameExportSettings;
|
|
import com.jpexs.decompiler.flash.exporters.settings.ImageExportSettings;
|
|
import com.jpexs.decompiler.flash.exporters.settings.MorphShapeExportSettings;
|
|
import com.jpexs.decompiler.flash.exporters.settings.MovieExportSettings;
|
|
import com.jpexs.decompiler.flash.exporters.settings.ScriptExportSettings;
|
|
import com.jpexs.decompiler.flash.exporters.settings.ShapeExportSettings;
|
|
import com.jpexs.decompiler.flash.exporters.settings.SoundExportSettings;
|
|
import com.jpexs.decompiler.flash.exporters.settings.SpriteExportSettings;
|
|
import com.jpexs.decompiler.flash.exporters.settings.SymbolClassExportSettings;
|
|
import com.jpexs.decompiler.flash.exporters.settings.TextExportSettings;
|
|
import com.jpexs.decompiler.flash.exporters.swf.SwfJavaExporter;
|
|
import com.jpexs.decompiler.flash.exporters.swf.SwfXmlExporter;
|
|
import com.jpexs.decompiler.flash.flexsdk.MxmlcAs3ScriptReplacer;
|
|
import com.jpexs.decompiler.flash.flv.FLVInputStream;
|
|
import com.jpexs.decompiler.flash.flv.FLVTAG;
|
|
import com.jpexs.decompiler.flash.flv.VIDEODATA;
|
|
import com.jpexs.decompiler.flash.gui.abc.ABCPanel;
|
|
import com.jpexs.decompiler.flash.gui.abc.ClassesListTreeModel;
|
|
import com.jpexs.decompiler.flash.gui.abc.DecompiledEditorPane;
|
|
import com.jpexs.decompiler.flash.gui.abc.DeobfuscationDialog;
|
|
import com.jpexs.decompiler.flash.gui.action.ActionPanel;
|
|
import com.jpexs.decompiler.flash.gui.controls.JPersistentSplitPane;
|
|
import com.jpexs.decompiler.flash.gui.dumpview.DumpTree;
|
|
import com.jpexs.decompiler.flash.gui.dumpview.DumpTreeModel;
|
|
import com.jpexs.decompiler.flash.gui.dumpview.DumpViewPanel;
|
|
import com.jpexs.decompiler.flash.gui.editor.LineMarkedEditorPane;
|
|
import com.jpexs.decompiler.flash.gui.helpers.CollectionChangedAction;
|
|
import com.jpexs.decompiler.flash.gui.helpers.ObservableList;
|
|
import com.jpexs.decompiler.flash.gui.player.FlashPlayerPanel;
|
|
import com.jpexs.decompiler.flash.gui.taglistview.TagListTree;
|
|
import com.jpexs.decompiler.flash.gui.taglistview.TagListTreeModel;
|
|
import com.jpexs.decompiler.flash.gui.tagtree.AbstractTagTree;
|
|
import com.jpexs.decompiler.flash.gui.tagtree.AbstractTagTreeModel;
|
|
import com.jpexs.decompiler.flash.gui.tagtree.FilteredTreeModel;
|
|
import com.jpexs.decompiler.flash.gui.tagtree.TagTree;
|
|
import com.jpexs.decompiler.flash.gui.tagtree.TagTreeContextMenu;
|
|
import com.jpexs.decompiler.flash.gui.tagtree.TagTreeModel;
|
|
import com.jpexs.decompiler.flash.gui.tagtree.TreeRoot;
|
|
import com.jpexs.decompiler.flash.gui.timeline.TimelineViewPanel;
|
|
import com.jpexs.decompiler.flash.helpers.FileTextWriter;
|
|
import com.jpexs.decompiler.flash.helpers.Freed;
|
|
import com.jpexs.decompiler.flash.importers.AS2ScriptImporter;
|
|
import com.jpexs.decompiler.flash.importers.AS3ScriptImporter;
|
|
import com.jpexs.decompiler.flash.importers.As3ScriptReplacerFactory;
|
|
import com.jpexs.decompiler.flash.importers.As3ScriptReplacerInterface;
|
|
import com.jpexs.decompiler.flash.importers.BinaryDataImporter;
|
|
import com.jpexs.decompiler.flash.importers.FFDecAs3ScriptReplacer;
|
|
import com.jpexs.decompiler.flash.importers.ImageImporter;
|
|
import com.jpexs.decompiler.flash.importers.MovieImporter;
|
|
import com.jpexs.decompiler.flash.importers.ScriptImporterProgressListener;
|
|
import com.jpexs.decompiler.flash.importers.ShapeImporter;
|
|
import com.jpexs.decompiler.flash.importers.SoundImporter;
|
|
import com.jpexs.decompiler.flash.importers.SwfXmlImporter;
|
|
import com.jpexs.decompiler.flash.importers.SymbolClassImporter;
|
|
import com.jpexs.decompiler.flash.importers.TextImporter;
|
|
import com.jpexs.decompiler.flash.importers.svg.SvgImporter;
|
|
import com.jpexs.decompiler.flash.search.ABCSearchResult;
|
|
import com.jpexs.decompiler.flash.search.ActionSearchResult;
|
|
import com.jpexs.decompiler.flash.search.ScriptSearchResult;
|
|
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
|
|
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
|
|
import com.jpexs.decompiler.flash.tags.DefineBitsJPEG3Tag;
|
|
import com.jpexs.decompiler.flash.tags.DefineBitsJPEG4Tag;
|
|
import com.jpexs.decompiler.flash.tags.DefineBitsTag;
|
|
import com.jpexs.decompiler.flash.tags.DefineButtonCxformTag;
|
|
import com.jpexs.decompiler.flash.tags.DefineButtonTag;
|
|
import com.jpexs.decompiler.flash.tags.DefineShape2Tag;
|
|
import com.jpexs.decompiler.flash.tags.DefineSoundTag;
|
|
import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
|
|
import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag;
|
|
import com.jpexs.decompiler.flash.tags.DoActionTag;
|
|
import com.jpexs.decompiler.flash.tags.DoInitActionTag;
|
|
import com.jpexs.decompiler.flash.tags.EndTag;
|
|
import com.jpexs.decompiler.flash.tags.FileAttributesTag;
|
|
import com.jpexs.decompiler.flash.tags.JPEGTablesTag;
|
|
import com.jpexs.decompiler.flash.tags.MetadataTag;
|
|
import com.jpexs.decompiler.flash.tags.PlaceObject2Tag;
|
|
import com.jpexs.decompiler.flash.tags.PlaceObject3Tag;
|
|
import com.jpexs.decompiler.flash.tags.PlaceObjectTag;
|
|
import com.jpexs.decompiler.flash.tags.ProductInfoTag;
|
|
import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag;
|
|
import com.jpexs.decompiler.flash.tags.ShowFrameTag;
|
|
import com.jpexs.decompiler.flash.tags.SoundStreamBlockTag;
|
|
import com.jpexs.decompiler.flash.tags.Tag;
|
|
import com.jpexs.decompiler.flash.tags.TagInfo;
|
|
import com.jpexs.decompiler.flash.tags.UnknownTag;
|
|
import com.jpexs.decompiler.flash.tags.VideoFrameTag;
|
|
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
|
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
|
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.DrawableTag;
|
|
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
|
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
|
import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler;
|
|
import com.jpexs.decompiler.flash.tags.base.MorphShapeTag;
|
|
import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag;
|
|
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
|
|
import com.jpexs.decompiler.flash.tags.base.SoundImportException;
|
|
import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag;
|
|
import com.jpexs.decompiler.flash.tags.base.SoundTag;
|
|
import com.jpexs.decompiler.flash.tags.base.SymbolClassTypeTag;
|
|
import com.jpexs.decompiler.flash.tags.base.TextImportErrorHandler;
|
|
import com.jpexs.decompiler.flash.tags.base.TextTag;
|
|
import com.jpexs.decompiler.flash.tags.base.UnsupportedSamplingRateException;
|
|
import com.jpexs.decompiler.flash.tags.gfx.DefineExternalImage2;
|
|
import com.jpexs.decompiler.flash.tags.gfx.DefineSubImage;
|
|
import com.jpexs.decompiler.flash.tags.text.TextParseException;
|
|
import com.jpexs.decompiler.flash.timeline.DepthState;
|
|
import com.jpexs.decompiler.flash.timeline.Frame;
|
|
import com.jpexs.decompiler.flash.timeline.TagScript;
|
|
import com.jpexs.decompiler.flash.timeline.Timeline;
|
|
import com.jpexs.decompiler.flash.timeline.Timelined;
|
|
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;
|
|
import com.jpexs.decompiler.flash.types.BUTTONRECORD;
|
|
import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA;
|
|
import com.jpexs.decompiler.flash.types.FILLSTYLE;
|
|
import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY;
|
|
import com.jpexs.decompiler.flash.types.LINESTYLEARRAY;
|
|
import com.jpexs.decompiler.flash.types.MATRIX;
|
|
import com.jpexs.decompiler.flash.types.RECT;
|
|
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
|
|
import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord;
|
|
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
|
|
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
|
|
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
|
|
import com.jpexs.decompiler.flash.types.sound.SoundFormat;
|
|
import com.jpexs.decompiler.flash.xfl.FLAVersion;
|
|
import com.jpexs.helpers.ByteArrayRange;
|
|
import com.jpexs.helpers.CancellableWorker;
|
|
import com.jpexs.helpers.Helper;
|
|
import com.jpexs.helpers.Path;
|
|
import com.jpexs.helpers.ProgressListener;
|
|
import com.jpexs.helpers.Reference;
|
|
import com.jpexs.helpers.SerializableImage;
|
|
import java.awt.BorderLayout;
|
|
import java.awt.CardLayout;
|
|
import java.awt.Color;
|
|
import java.awt.Component;
|
|
import java.awt.Container;
|
|
import java.awt.Desktop;
|
|
import java.awt.Dimension;
|
|
import java.awt.FlowLayout;
|
|
import java.awt.Font;
|
|
import java.awt.datatransfer.DataFlavor;
|
|
import java.awt.datatransfer.Transferable;
|
|
import java.awt.datatransfer.UnsupportedFlavorException;
|
|
import java.awt.dnd.DnDConstants;
|
|
import java.awt.dnd.DragGestureEvent;
|
|
import java.awt.dnd.DragGestureListener;
|
|
import java.awt.dnd.DragSource;
|
|
import java.awt.dnd.DragSourceDragEvent;
|
|
import java.awt.dnd.DragSourceDropEvent;
|
|
import java.awt.dnd.DragSourceEvent;
|
|
import java.awt.dnd.DragSourceListener;
|
|
import java.awt.dnd.DropTarget;
|
|
import java.awt.dnd.DropTargetDropEvent;
|
|
import java.awt.event.ActionEvent;
|
|
import java.awt.event.ActionListener;
|
|
import java.awt.event.ComponentAdapter;
|
|
import java.awt.event.ComponentEvent;
|
|
import java.awt.event.KeyAdapter;
|
|
import java.awt.event.KeyEvent;
|
|
import java.awt.image.BufferedImage;
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.FileNotFoundException;
|
|
import java.io.FileOutputStream;
|
|
import java.io.FilenameFilter;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.lang.ref.WeakReference;
|
|
import java.nio.charset.Charset;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collection;
|
|
import java.util.Comparator;
|
|
import java.util.ConcurrentModificationException;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.LinkedHashSet;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
import java.util.Map;
|
|
import java.util.Map.Entry;
|
|
import java.util.Random;
|
|
import java.util.Set;
|
|
import java.util.WeakHashMap;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
import javax.imageio.ImageIO;
|
|
import javax.sound.sampled.LineUnavailableException;
|
|
import javax.sound.sampled.UnsupportedAudioFileException;
|
|
import javax.swing.Box;
|
|
import javax.swing.BoxLayout;
|
|
import javax.swing.Icon;
|
|
import javax.swing.JColorChooser;
|
|
import javax.swing.JFileChooser;
|
|
import javax.swing.JLabel;
|
|
import javax.swing.JOptionPane;
|
|
import javax.swing.JPanel;
|
|
import javax.swing.JProgressBar;
|
|
import javax.swing.JScrollBar;
|
|
import javax.swing.JScrollPane;
|
|
import javax.swing.JSplitPane;
|
|
import javax.swing.JTabbedPane;
|
|
import javax.swing.JTree;
|
|
import javax.swing.SwingConstants;
|
|
import javax.swing.UIManager;
|
|
import javax.swing.event.ChangeEvent;
|
|
import javax.swing.event.ChangeListener;
|
|
import javax.swing.event.TreeSelectionEvent;
|
|
import javax.swing.event.TreeSelectionListener;
|
|
import javax.swing.filechooser.FileFilter;
|
|
import javax.swing.plaf.basic.BasicTreeUI;
|
|
import javax.swing.tree.DefaultTreeSelectionModel;
|
|
import javax.swing.tree.TreeModel;
|
|
import javax.swing.tree.TreePath;
|
|
import jsyntaxpane.DefaultSyntaxKit;
|
|
|
|
/**
|
|
*
|
|
* @author JPEXS
|
|
*/
|
|
public final class MainPanel extends JPanel implements TreeSelectionListener, SearchListener<TextTag>, Freed {
|
|
|
|
private final MainFrame mainFrame;
|
|
|
|
private final ObservableList<OpenableList> openables;
|
|
|
|
private final JPanel welcomePanel;
|
|
|
|
private final TimelineViewPanel timelineViewPanel;
|
|
|
|
private final MainFrameStatusPanel statusPanel;
|
|
|
|
private Thread taskThread;
|
|
|
|
private final MainFrameMenu mainMenu;
|
|
|
|
private final JProgressBar progressBar = new JProgressBar(0, 100);
|
|
|
|
public TagTree tagTree;
|
|
|
|
public FasterScrollPane tagTreeScrollPanel;
|
|
|
|
public DumpTree dumpTree;
|
|
|
|
public TagListTree tagListTree;
|
|
|
|
private ClipboardPanel resourcesClipboardPanel;
|
|
private ClipboardPanel tagListClipboardPanel;
|
|
|
|
private final FlashPlayerPanel flashPanel;
|
|
|
|
private final FlashPlayerPanel flashPanel2;
|
|
|
|
private final JPanel contentPanel;
|
|
|
|
private final JPanel displayPanel;
|
|
|
|
public FolderPreviewPanel folderPreviewPanel;
|
|
|
|
public FolderListPanel folderListPanel;
|
|
|
|
private boolean isWelcomeScreen = true;
|
|
|
|
private static final String CARDPREVIEWPANEL = "Preview card";
|
|
|
|
private static final String CARDFOLDERPREVIEWPANEL = "Folder preview card";
|
|
|
|
private static final String CARDFOLDERLISTPANEL = "Folder list card";
|
|
|
|
private static final String CARDEMPTYPANEL = "Empty card";
|
|
|
|
private static final String CARDDUMPVIEW = "Dump view";
|
|
|
|
private static final String CARDACTIONSCRIPTPANEL = "ActionScript card";
|
|
|
|
private static final String CARDACTIONSCRIPT3PANEL = "ActionScript3 card";
|
|
|
|
private static final String CARDHEADER = "Header card";
|
|
|
|
private static final String DETAILCARDAS3NAVIGATOR = "Traits list";
|
|
|
|
private static final String DETAILCARDTAGINFO = "Tag information";
|
|
|
|
private static final String DETAILCARDEMPTYPANEL = "Empty card";
|
|
|
|
private static final String SPLIT_PANE1 = "SPLITPANE1";
|
|
|
|
private static final String WELCOME_PANEL = "WELCOMEPANEL";
|
|
|
|
private static final String TIMELINE_PANEL = "TIMELINEPANEL";
|
|
|
|
private static final String RESOURCES_VIEW = "RESOURCES";
|
|
|
|
private static final String DUMP_VIEW = "DUMP";
|
|
|
|
private static final String TAGLIST_VIEW = "TAGLIST";
|
|
|
|
private static final String TIMELINE_VIEW = "TIMELINE";
|
|
|
|
private final JPersistentSplitPane splitPane1;
|
|
|
|
private final JPersistentSplitPane splitPane2;
|
|
|
|
private JPanel detailPanel;
|
|
|
|
private QuickTreeFindPanel quickTreeFindPanel;
|
|
|
|
private QuickTreeFindPanel quickTagListFindPanel;
|
|
|
|
private ABCPanel abcPanel;
|
|
|
|
private ActionPanel actionPanel;
|
|
|
|
private final PreviewPanel previewPanel;
|
|
|
|
private final HeaderInfoPanel headerPanel;
|
|
|
|
private DumpViewPanel dumpViewPanel;
|
|
|
|
private final JPanel treePanel;
|
|
|
|
private final PreviewPanel dumpPreviewPanel;
|
|
|
|
private final TagInfoPanel tagInfoPanel;
|
|
|
|
private TreePanelMode treePanelMode;
|
|
|
|
public TreeItem oldItem;
|
|
|
|
private int currentView = VIEW_RESOURCES;
|
|
|
|
public List<SearchResultsDialog> searchResultsDialogs = new ArrayList<>();
|
|
|
|
private TagTreeContextMenu contextPopupMenu;
|
|
|
|
private static final Logger logger = Logger.getLogger(MainPanel.class.getName());
|
|
|
|
private Map<TreeItem, Set<Integer>> neededCharacters = new WeakHashMap<>();
|
|
private Map<TreeItem, Set<Integer>> missingNeededCharacters = new WeakHashMap<>();
|
|
|
|
private CalculateMissingNeededThread calculateMissingNeededThread;
|
|
|
|
private List<WeakReference<TreeItem>> orderedClipboard = new ArrayList<>();
|
|
private Map<TreeItem, Boolean> clipboard = new WeakHashMap<>();
|
|
|
|
private boolean clipboardCut = false;
|
|
|
|
private PinsPanel pinsPanel;
|
|
|
|
private List<List<String>> unfilteredTreeExpandedNodes = new ArrayList<>();
|
|
private List<List<String>> unfilteredTagListExpandedNodes = new ArrayList<>();
|
|
|
|
public void savePins() {
|
|
pinsPanel.save();
|
|
}
|
|
|
|
public void clearPins() {
|
|
pinsPanel.clear();
|
|
}
|
|
|
|
public void refreshPins() {
|
|
pinsPanel.refresh();
|
|
}
|
|
|
|
public void destroyPins() {
|
|
pinsPanel.destroy();
|
|
}
|
|
|
|
public void unpinItem(TreeItem item) {
|
|
pinsPanel.removeItem(item);
|
|
}
|
|
|
|
public void unpinOthers(TreeItem item) {
|
|
pinsPanel.removeOthers(item);
|
|
}
|
|
|
|
public void pinItem(TreeItem item) {
|
|
pinsPanel.pin(item);
|
|
}
|
|
|
|
public int getPinCount() {
|
|
return pinsPanel.getPinCount();
|
|
}
|
|
|
|
public boolean isPinned(TreeItem item) {
|
|
return pinsPanel.isPinned(item);
|
|
}
|
|
|
|
public void replaceItemPin(TreeItem oldItem, TreeItem newItem) {
|
|
pinsPanel.replaceItem(oldItem, newItem);
|
|
}
|
|
|
|
private void handleKeyReleased(KeyEvent e) {
|
|
if (checkEdited()) {
|
|
return;
|
|
}
|
|
Object source = e.getSource();
|
|
List<TreeItem> items = new ArrayList<>();
|
|
if (source == folderPreviewPanel) {
|
|
items.addAll(folderPreviewPanel.selectedItems.values());
|
|
} else if (source == folderListPanel) {
|
|
items.addAll(folderListPanel.selectedItems.values());
|
|
} else {
|
|
AbstractTagTree tree = (AbstractTagTree) e.getSource();
|
|
TreePath[] paths = tree.getSelectionPaths();
|
|
if (paths != null) {
|
|
for (TreePath treePath : paths) {
|
|
TreeItem item = (TreeItem) treePath.getLastPathComponent();
|
|
items.add(item);
|
|
}
|
|
}
|
|
}
|
|
if (items.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
if ((e.getKeyCode() == KeyEvent.VK_UP
|
|
|| e.getKeyCode() == KeyEvent.VK_DOWN)
|
|
&& e.isAltDown() && !e.isControlDown() && !e.isShiftDown()) {
|
|
TreeItem item = items.get(0);
|
|
|
|
if (item instanceof Tag) {
|
|
if (((Tag) item).isReadOnly()) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (e.getKeyCode() == KeyEvent.VK_UP) {
|
|
contextPopupMenu.moveUpDown(item, true);
|
|
}
|
|
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
|
|
contextPopupMenu.moveUpDown(item, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void moveSwfListUpDown(TreeItem item, boolean up) {
|
|
OpenableList openableList = null;
|
|
if (item instanceof Openable) {
|
|
Openable openable = (Openable) item;
|
|
if (openable.getOpenableList() != null && !openable.getOpenableList().isBundle() && openable.getOpenableList().size() == 1) {
|
|
openableList = openable.getOpenableList();
|
|
} else {
|
|
return;
|
|
}
|
|
} else if (item instanceof OpenableList) {
|
|
openableList = (OpenableList) item;
|
|
} else {
|
|
return;
|
|
}
|
|
int index = openables.indexOf(openableList);
|
|
|
|
List<List<String>> expandedTagTree = View.getExpandedNodes(tagTree);
|
|
List<List<String>> expandedTagListTree = View.getExpandedNodes(tagListTree);
|
|
|
|
if (up) {
|
|
if (index <= 0) {
|
|
return;
|
|
}
|
|
openables.move(index, index - 1);
|
|
} else {
|
|
if (index < 0 || index >= openables.size() - 1) {
|
|
return;
|
|
}
|
|
openables.move(index, index + 2);
|
|
}
|
|
View.expandTreeNodes(tagTree, expandedTagTree);
|
|
View.expandTreeNodes(tagListTree, expandedTagListTree);
|
|
TreePath path = getCurrentTree().getFullModel().getTreePath(item);
|
|
getCurrentTree().setSelectionPath(path);
|
|
getCurrentTree().scrollPathToVisible(path);
|
|
repaintTree();
|
|
}
|
|
|
|
public void hideQuickTreeFind() {
|
|
quickTreeFindPanel.setVisible(false);
|
|
quickTagListFindPanel.setVisible(false);
|
|
}
|
|
|
|
private void handleKeyPressed(KeyEvent e) {
|
|
if (checkEdited()) {
|
|
return;
|
|
}
|
|
Object source = e.getSource();
|
|
List<TreeItem> items = new ArrayList<>();
|
|
if (source == folderPreviewPanel) {
|
|
items.addAll(folderPreviewPanel.selectedItems.values());
|
|
} else if (source == folderListPanel) {
|
|
items.addAll(folderListPanel.selectedItems.values());
|
|
} else {
|
|
AbstractTagTree tree = (AbstractTagTree) e.getSource();
|
|
TreePath[] paths = tree.getSelectionPaths();
|
|
if (paths != null) {
|
|
for (TreePath treePath : paths) {
|
|
TreeItem item = (TreeItem) treePath.getLastPathComponent();
|
|
items.add(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (items.isEmpty()) {
|
|
return;
|
|
}
|
|
if ((e.getKeyCode() == 'G') && (e.isControlDown())) {
|
|
Openable openable = items.get(0).getOpenable();
|
|
SWF swf = null;
|
|
if (openable instanceof SWF) {
|
|
swf = (SWF) openable;
|
|
}
|
|
if (swf != null) {
|
|
String val = "";
|
|
boolean valid;
|
|
int characterId = -1;
|
|
do {
|
|
val = ViewMessages.showInputDialog(MainPanel.this, translate("message.input.gotoCharacter"), translate("message.input.gotoCharacter.title"), val);
|
|
if (val == null) {
|
|
break;
|
|
}
|
|
try {
|
|
characterId = Integer.parseInt(val);
|
|
} catch (NumberFormatException nfe) {
|
|
characterId = -1;
|
|
}
|
|
} while (characterId <= 0);
|
|
|
|
if (characterId > 0) {
|
|
CharacterTag tag = swf.getCharacter(characterId);
|
|
if (tag == null) {
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("message.character.notfound").replace("%characterid%", "" + characterId), translate("error"), JOptionPane.ERROR_MESSAGE);
|
|
} else {
|
|
setTagTreeSelectedNode(getCurrentTree(), tag);
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ((e.getKeyCode() == 'F') && (e.isControlDown())) {
|
|
AbstractTagTree tree = getCurrentTree();
|
|
if (tree == tagTree) {
|
|
quickTreeFindPanel.setVisible(true);
|
|
}
|
|
if (tree == tagListTree) {
|
|
quickTagListFindPanel.setVisible(true);
|
|
}
|
|
}
|
|
if ((e.getKeyCode() == KeyEvent.VK_DELETE) && !e.isControlDown() && !e.isAltDown()) {
|
|
if (contextPopupMenu.canRemove(items)) {
|
|
contextPopupMenu.update(items);
|
|
contextPopupMenu.removeItemActionPerformed(null, e.isShiftDown());
|
|
}
|
|
}
|
|
if ((e.getKeyCode() == 'C' || e.getKeyCode() == 'X') && (e.isControlDown())) {
|
|
List<TreeItem> tagItems = new ArrayList<>();
|
|
for (TreeItem item:items) {
|
|
if (item instanceof TagScript) {
|
|
tagItems.add(((TagScript) item).getTag());
|
|
} else if (item instanceof Tag) {
|
|
tagItems.add((Tag) item);
|
|
}
|
|
}
|
|
boolean allWritable = true;
|
|
for (TreeItem item : tagItems) {
|
|
if (((Tag) item).isReadOnly()) {
|
|
allWritable = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (e.getKeyCode() == 'C') {
|
|
if (e.isShiftDown()) {
|
|
contextPopupMenu.copyTagToClipboardWithDependenciesActionPerformed(null, tagItems);
|
|
} else {
|
|
contextPopupMenu.copyTagToClipboardActionPerformed(null, tagItems);
|
|
}
|
|
}
|
|
if (e.getKeyCode() == 'X' && allWritable) {
|
|
contextPopupMenu.update(tagItems);
|
|
if (e.isShiftDown()) {
|
|
contextPopupMenu.cutTagToClipboardWithDependenciesActionPerformed(null);
|
|
} else {
|
|
contextPopupMenu.cutTagToClipboardActionPerformed(null);
|
|
}
|
|
}
|
|
repaintTree();
|
|
}
|
|
if (e.getKeyCode() == 'V' && e.isControlDown()) {
|
|
if (items.size() > 1) {
|
|
return;
|
|
}
|
|
TreeItem firstItem = items.get(0);
|
|
if (!((firstItem instanceof Tag) || (firstItem instanceof Frame))) {
|
|
return;
|
|
}
|
|
contextPopupMenu.update(items);
|
|
if (e.isShiftDown()) {
|
|
contextPopupMenu.pasteAfterActionPerformed(null);
|
|
} else {
|
|
contextPopupMenu.pasteBeforeActionPerformed(null);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void gcClipboard() {
|
|
for (int i = orderedClipboard.size() - 1; i >= 0; i--) {
|
|
WeakReference<TreeItem> ref = orderedClipboard.get(i);
|
|
TreeItem item = ref.get();
|
|
if (item != null) {
|
|
if (item.getOpenable() == null) {
|
|
orderedClipboard.remove(i);
|
|
clipboard.remove(item);
|
|
}
|
|
}
|
|
}
|
|
resourcesClipboardPanel.update();
|
|
tagListClipboardPanel.update();
|
|
}
|
|
|
|
public void emptyClipboard() {
|
|
copyToClipboard(new ArrayList<>());
|
|
}
|
|
|
|
public void copyToClipboard(Collection<TreeItem> items) {
|
|
|
|
orderedClipboard.clear();
|
|
clipboard.clear();
|
|
for (TreeItem item : items) {
|
|
orderedClipboard.add(new WeakReference<>(item));
|
|
clipboard.put(item, true);
|
|
}
|
|
clipboardCut = false;
|
|
resourcesClipboardPanel.update();
|
|
tagListClipboardPanel.update();
|
|
resourcesClipboardPanel.flash();
|
|
tagListClipboardPanel.flash();
|
|
folderPreviewPanel.repaint();
|
|
|
|
}
|
|
|
|
public void cutToClipboard(Collection<TreeItem> items) {
|
|
copyToClipboard(items);
|
|
clipboardCut = true;
|
|
}
|
|
|
|
public boolean clipboardContains(TreeItem item) {
|
|
return clipboard.containsKey(item);
|
|
}
|
|
|
|
public boolean clipboardEmpty() {
|
|
return clipboard.isEmpty();
|
|
}
|
|
|
|
public int getClipboardSize() {
|
|
return clipboard.size();
|
|
}
|
|
|
|
public Set<TreeItem> getClipboardContents() {
|
|
Set<TreeItem> ret = new LinkedHashSet<>();
|
|
for (WeakReference<TreeItem> ref : orderedClipboard) {
|
|
TreeItem item = ref.get();
|
|
if (item != null) {
|
|
ret.add(item);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
public boolean isClipboardCut() {
|
|
return clipboardCut;
|
|
}
|
|
|
|
public boolean checkEdited() {
|
|
if (abcPanel != null && abcPanel.isEditing()) {
|
|
abcPanel.tryAutoSave();
|
|
}
|
|
|
|
if (actionPanel != null && actionPanel.isEditing()) {
|
|
actionPanel.tryAutoSave();
|
|
}
|
|
|
|
if (previewPanel.isEditing()) {
|
|
previewPanel.tryAutoSave();
|
|
}
|
|
|
|
if (headerPanel.isEditing()) {
|
|
headerPanel.tryAutoSave();
|
|
}
|
|
|
|
return (abcPanel != null && abcPanel.isEditing())
|
|
|| (actionPanel != null && actionPanel.isEditing())
|
|
|| previewPanel.isEditing() || headerPanel.isEditing();
|
|
}
|
|
|
|
private class MyTreeSelectionModel extends DefaultTreeSelectionModel {
|
|
|
|
@Override
|
|
public void addSelectionPath(TreePath path) {
|
|
if (checkEdited()) {
|
|
return;
|
|
}
|
|
|
|
super.addSelectionPath(path);
|
|
}
|
|
|
|
@Override
|
|
public void addSelectionPaths(TreePath[] paths) {
|
|
if (checkEdited()) {
|
|
return;
|
|
}
|
|
|
|
super.addSelectionPaths(paths);
|
|
}
|
|
|
|
@Override
|
|
public void setSelectionPath(TreePath path) {
|
|
if (checkEdited()) {
|
|
return;
|
|
}
|
|
|
|
super.setSelectionPath(path);
|
|
}
|
|
|
|
@Override
|
|
public void setSelectionPaths(TreePath[] pPaths) {
|
|
if (checkEdited()) {
|
|
return;
|
|
}
|
|
|
|
super.setSelectionPaths(pPaths);
|
|
}
|
|
|
|
@Override
|
|
public void clearSelection() {
|
|
if (checkEdited()) {
|
|
return;
|
|
}
|
|
|
|
super.clearSelection();
|
|
}
|
|
|
|
public void setSelection(TreePath[] selection) {
|
|
if (checkEdited()) {
|
|
return;
|
|
}
|
|
|
|
this.selection = selection;
|
|
}
|
|
|
|
@Override
|
|
public void removeSelectionPath(TreePath path) {
|
|
if (checkEdited()) {
|
|
return;
|
|
}
|
|
|
|
super.removeSelectionPath(path);
|
|
}
|
|
|
|
@Override
|
|
public void removeSelectionPaths(TreePath[] paths) {
|
|
if (checkEdited()) {
|
|
return;
|
|
}
|
|
|
|
super.removeSelectionPaths(paths);
|
|
}
|
|
}
|
|
|
|
public TagTreeContextMenu getContextPopupMenu() {
|
|
return contextPopupMenu;
|
|
}
|
|
|
|
public void setPercent(int percent) {
|
|
View.checkAccess();
|
|
|
|
progressBar.setValue(percent);
|
|
progressBar.setVisible(true);
|
|
}
|
|
|
|
public void hidePercent() {
|
|
View.checkAccess();
|
|
|
|
if (progressBar.isVisible()) {
|
|
progressBar.setVisible(false);
|
|
}
|
|
}
|
|
|
|
public MainFrame getMainFrame() {
|
|
return mainFrame;
|
|
}
|
|
|
|
static {
|
|
try {
|
|
File.createTempFile("temp", ".swf").delete(); //First call to this is slow, so make it first
|
|
} catch (IOException ex) {
|
|
logger.log(Level.SEVERE, null, ex);
|
|
}
|
|
}
|
|
|
|
public void updateMenu() {
|
|
mainMenu.updateComponents();
|
|
}
|
|
|
|
private static void addTab(JTabbedPane tabbedPane, Component tab, String title, Icon icon) {
|
|
tabbedPane.add(tab);
|
|
|
|
JLabel lbl = new JLabel(title);
|
|
lbl.setIcon(icon);
|
|
lbl.setIconTextGap(5);
|
|
lbl.setHorizontalTextPosition(SwingConstants.RIGHT);
|
|
|
|
tabbedPane.setTabComponentAt(tabbedPane.getTabCount() - 1, lbl);
|
|
}
|
|
|
|
public void setStatus(String s) {
|
|
statusPanel.setStatus(s);
|
|
}
|
|
|
|
public void setEditingStatus() {
|
|
statusPanel.setStatus(translate(Configuration.autoSaveTagModifications.get() ? "status.editing.autosave" : "status.editing"));
|
|
}
|
|
|
|
public void clearEditingStatus() {
|
|
statusPanel.setStatus("");
|
|
}
|
|
|
|
public void setWorkStatus(String s, CancellableWorker worker) {
|
|
statusPanel.setWorkStatus(s, worker);
|
|
mainMenu.updateComponents();
|
|
}
|
|
|
|
public CancellableWorker getCurrentWorker() {
|
|
return statusPanel.getCurrentWorker();
|
|
}
|
|
|
|
private JPanel createWelcomePanel() {
|
|
JPanel welcomePanel = new JPanel();
|
|
welcomePanel.setLayout(new BoxLayout(welcomePanel, BoxLayout.Y_AXIS));
|
|
JLabel welcomeToLabel = new JLabel(translate("startup.welcometo"));
|
|
welcomeToLabel.setFont(welcomeToLabel.getFont().deriveFont(40));
|
|
welcomeToLabel.setAlignmentX(0.5f);
|
|
JPanel appNamePanel = new JPanel(new FlowLayout());
|
|
JLabel jpLabel = new JLabel("JPEXS ");
|
|
jpLabel.setAlignmentX(0.5f);
|
|
jpLabel.setForeground(new Color(0, 0, 160));
|
|
jpLabel.setFont(new Font("Tahoma", Font.BOLD, 50));
|
|
jpLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
|
appNamePanel.add(jpLabel);
|
|
|
|
JLabel ffLabel = new JLabel("Free Flash ");
|
|
ffLabel.setAlignmentX(0.5f);
|
|
ffLabel.setFont(new Font("Tahoma", Font.BOLD, 50));
|
|
ffLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
|
appNamePanel.add(ffLabel);
|
|
|
|
JLabel decLabel = new JLabel("Decompiler");
|
|
decLabel.setAlignmentX(0.5f);
|
|
decLabel.setForeground(Color.red);
|
|
decLabel.setFont(new Font("Tahoma", Font.BOLD, 50));
|
|
decLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
|
appNamePanel.add(decLabel);
|
|
appNamePanel.setAlignmentX(0.5f);
|
|
welcomePanel.add(Box.createGlue());
|
|
welcomePanel.add(welcomeToLabel);
|
|
welcomePanel.add(appNamePanel);
|
|
JLabel startLabel = new JLabel(translate("startup.selectopen"));
|
|
startLabel.setAlignmentX(0.5f);
|
|
startLabel.setFont(startLabel.getFont().deriveFont(30));
|
|
welcomePanel.add(startLabel);
|
|
welcomePanel.add(Box.createGlue());
|
|
return welcomePanel;
|
|
}
|
|
|
|
private JPanel createFolderPreviewCard() {
|
|
JPanel folderPreviewCard = new JPanel(new BorderLayout());
|
|
folderPreviewPanel = new FolderPreviewPanel(this, new ArrayList<>());
|
|
FasterScrollPane folderPreviewScrollPane = new FasterScrollPane(folderPreviewPanel);
|
|
folderPreviewCard.add(folderPreviewScrollPane, BorderLayout.CENTER);
|
|
|
|
folderPreviewPanel.addKeyListener(new KeyAdapter() {
|
|
@Override
|
|
public void keyReleased(KeyEvent e) {
|
|
handleKeyReleased(e);
|
|
}
|
|
|
|
@Override
|
|
public void keyPressed(KeyEvent e) {
|
|
handleKeyPressed(e);
|
|
}
|
|
});
|
|
|
|
return folderPreviewCard;
|
|
}
|
|
|
|
private JPanel createFolderListCard() {
|
|
JPanel folderListCard = new JPanel(new BorderLayout());
|
|
folderListPanel = new FolderListPanel(this, new ArrayList<>());
|
|
folderListCard.add(new FasterScrollPane(folderListPanel), BorderLayout.CENTER);
|
|
|
|
folderListPanel.addKeyListener(new KeyAdapter() {
|
|
@Override
|
|
public void keyReleased(KeyEvent e) {
|
|
handleKeyReleased(e);
|
|
}
|
|
|
|
@Override
|
|
public void keyPressed(KeyEvent e) {
|
|
handleKeyPressed(e);
|
|
}
|
|
});
|
|
|
|
return folderListCard;
|
|
}
|
|
|
|
private JPanel createDumpPreviewCard() {
|
|
JPanel dumpViewCard = new JPanel(new BorderLayout());
|
|
dumpViewPanel = new DumpViewPanel(dumpTree);
|
|
dumpViewCard.add(new FasterScrollPane(dumpViewPanel), BorderLayout.CENTER);
|
|
|
|
return dumpViewCard;
|
|
}
|
|
|
|
public String translate(String key) {
|
|
return mainFrame.translate(key);
|
|
}
|
|
|
|
public MainPanel(MainFrame mainFrame, MainFrameMenu mainMenu, FlashPlayerPanel flashPanel, FlashPlayerPanel previewFlashPanel) {
|
|
super();
|
|
|
|
this.mainFrame = mainFrame;
|
|
this.mainMenu = mainMenu;
|
|
this.flashPanel = flashPanel;
|
|
this.flashPanel2 = previewFlashPanel;
|
|
|
|
mainFrame.setTitle(ApplicationInfo.applicationVerName);
|
|
|
|
setLayout(new BorderLayout());
|
|
openables = new ObservableList<>();
|
|
|
|
detailPanel = new JPanel();
|
|
detailPanel.setLayout(new CardLayout());
|
|
|
|
JPanel whitePanel = new JPanel();
|
|
if (View.isOceanic()) {
|
|
whitePanel.setBackground(Color.white);
|
|
}
|
|
detailPanel.add(whitePanel, DETAILCARDEMPTYPANEL);
|
|
|
|
tagInfoPanel = new TagInfoPanel(this);
|
|
detailPanel.add(tagInfoPanel, DETAILCARDTAGINFO);
|
|
|
|
UIManager.getDefaults().put("TreeUI", BasicTreeUI.class.getName());
|
|
tagTree = new TagTree(null, this);
|
|
tagTree.addTreeSelectionListener(this);
|
|
tagTree.setSelectionModel(new MyTreeSelectionModel());
|
|
|
|
tagListTree = new TagListTree(null, this);
|
|
tagListTree.addTreeSelectionListener(this);
|
|
tagListTree.setSelectionModel(new MyTreeSelectionModel());
|
|
|
|
DragSource dragSource = DragSource.getDefaultDragSource();
|
|
dragSource.createDefaultDragGestureRecognizer(tagTree, DnDConstants.ACTION_COPY_OR_MOVE, new DragGestureListener() {
|
|
@Override
|
|
public void dragGestureRecognized(DragGestureEvent dge) {
|
|
dge.startDrag(DragSource.DefaultCopyDrop, new Transferable() {
|
|
@Override
|
|
public DataFlavor[] getTransferDataFlavors() {
|
|
return new DataFlavor[]{DataFlavor.javaFileListFlavor};
|
|
}
|
|
|
|
@Override
|
|
public boolean isDataFlavorSupported(DataFlavor flavor) {
|
|
return flavor.equals(DataFlavor.javaFileListFlavor);
|
|
}
|
|
|
|
@Override
|
|
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
|
|
if (flavor.equals(DataFlavor.javaFileListFlavor)) {
|
|
List<File> files;
|
|
String tempDir = System.getProperty("java.io.tmpdir");
|
|
if (!tempDir.endsWith(File.separator)) {
|
|
tempDir += File.separator;
|
|
}
|
|
Random rnd = new Random();
|
|
tempDir += "ffdec" + File.separator + "export" + File.separator + System.currentTimeMillis() + "_" + rnd.nextInt(1000);
|
|
File fTempDir = new File(tempDir);
|
|
Path.createDirectorySafe(fTempDir);
|
|
|
|
File ftemp = new File(tempDir);
|
|
ExportDialog exd = new ExportDialog(Main.getDefaultDialogsOwner(), null);
|
|
try {
|
|
files = exportSelection(null, new GuiAbortRetryIgnoreHandler(), tempDir, exd);
|
|
} catch (InterruptedException ex) {
|
|
logger.log(Level.SEVERE, null, ex);
|
|
return null;
|
|
}
|
|
|
|
files.clear();
|
|
|
|
File[] fs = ftemp.listFiles();
|
|
files.addAll(Arrays.asList(fs));
|
|
|
|
Main.stopWork();
|
|
|
|
for (File f : files) {
|
|
f.deleteOnExit();
|
|
}
|
|
new File(tempDir).deleteOnExit();
|
|
return files;
|
|
|
|
}
|
|
return null;
|
|
}
|
|
}, new DragSourceListener() {
|
|
@Override
|
|
public void dragEnter(DragSourceDragEvent dsde) {
|
|
enableDrop(false);
|
|
}
|
|
|
|
@Override
|
|
public void dragOver(DragSourceDragEvent dsde) {
|
|
}
|
|
|
|
@Override
|
|
public void dropActionChanged(DragSourceDragEvent dsde) {
|
|
}
|
|
|
|
@Override
|
|
public void dragExit(DragSourceEvent dse) {
|
|
}
|
|
|
|
@Override
|
|
public void dragDropEnd(DragSourceDropEvent dsde) {
|
|
enableDrop(true);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
List<AbstractTagTree> trees = new ArrayList<>();
|
|
trees.add(tagTree);
|
|
trees.add(tagListTree);
|
|
|
|
contextPopupMenu = new TagTreeContextMenu(trees, this);
|
|
|
|
dumpTree = new DumpTree(null, this);
|
|
dumpTree.addTreeSelectionListener(this);
|
|
dumpTree.createContextMenu();
|
|
|
|
currentView = Configuration.lastView.get();
|
|
|
|
statusPanel = new MainFrameStatusPanel(this);
|
|
add(statusPanel, BorderLayout.SOUTH);
|
|
|
|
displayPanel = new JPanel(new CardLayout());
|
|
|
|
DefaultSyntaxKit.initKit();
|
|
previewPanel = new PreviewPanel(this, flashPanel);
|
|
|
|
dumpPreviewPanel = new PreviewPanel(this, previewFlashPanel);
|
|
dumpPreviewPanel.setReadOnly(true);
|
|
|
|
displayPanel.add(previewPanel, CARDPREVIEWPANEL);
|
|
displayPanel.add(createFolderPreviewCard(), CARDFOLDERPREVIEWPANEL);
|
|
displayPanel.add(createFolderListCard(), CARDFOLDERLISTPANEL);
|
|
displayPanel.add(createDumpPreviewCard(), CARDDUMPVIEW);
|
|
|
|
headerPanel = new HeaderInfoPanel(this);
|
|
displayPanel.add(headerPanel, CARDHEADER);
|
|
|
|
displayPanel.add(new JPanel(), CARDEMPTYPANEL);
|
|
showCard(CARDEMPTYPANEL);
|
|
|
|
LazyCardLayout treePanelLayout = new LazyCardLayout();
|
|
treePanelLayout.registerLayout(createResourcesViewCard(), RESOURCES_VIEW);
|
|
treePanelLayout.registerLayout(createDumpViewCard(), DUMP_VIEW);
|
|
treePanelLayout.registerLayout(createTagListViewCard(), TAGLIST_VIEW);
|
|
treePanel = new JPanel(treePanelLayout);
|
|
|
|
//treePanel.add(searchPanel, BorderLayout.SOUTH);
|
|
//searchPanel.setVisible(false);
|
|
JPanel rightPanel = new JPanel(new BorderLayout());
|
|
rightPanel.add(displayPanel, BorderLayout.CENTER);
|
|
pinsPanel = new PinsPanel(this);
|
|
pinsPanel.addChangeListener(new ChangeListener() {
|
|
@Override
|
|
public void stateChanged(ChangeEvent e) {
|
|
TreeItem item = pinsPanel.getCurrent();
|
|
if ((getCurrentTree() == tagListTree) && (item instanceof TagScript)) {
|
|
item = ((TagScript) item).getTag();
|
|
}
|
|
setTagTreeSelectedNode(getCurrentTree(), item);
|
|
}
|
|
});
|
|
rightPanel.add(pinsPanel, BorderLayout.NORTH);
|
|
|
|
//displayPanel.setBorder(BorderFactory.createLineBorder(Color.black));
|
|
splitPane2 = new JPersistentSplitPane(JSplitPane.VERTICAL_SPLIT, treePanel, detailPanel, Configuration.guiSplitPane2DividerLocationPercent);
|
|
splitPane1 = new JPersistentSplitPane(JSplitPane.HORIZONTAL_SPLIT, splitPane2, rightPanel, Configuration.guiSplitPane1DividerLocationPercent);
|
|
|
|
welcomePanel = createWelcomePanel();
|
|
add(welcomePanel, BorderLayout.CENTER);
|
|
|
|
timelineViewPanel = new TimelineViewPanel();
|
|
|
|
contentPanel = new JPanel(new CardLayout());
|
|
contentPanel.add(welcomePanel, WELCOME_PANEL);
|
|
contentPanel.add(splitPane1, SPLIT_PANE1);
|
|
contentPanel.add(timelineViewPanel, TIMELINE_PANEL);
|
|
add(contentPanel);
|
|
showContentPanelCard(WELCOME_PANEL);
|
|
|
|
tagTree.addKeyListener(new KeyAdapter() {
|
|
@Override
|
|
public void keyReleased(KeyEvent e) {
|
|
handleKeyReleased(e);
|
|
}
|
|
|
|
@Override
|
|
public void keyPressed(KeyEvent e) {
|
|
handleKeyPressed(e);
|
|
}
|
|
});
|
|
tagListTree.addKeyListener(new KeyAdapter() {
|
|
@Override
|
|
public void keyReleased(KeyEvent e) {
|
|
handleKeyReleased(e);
|
|
}
|
|
|
|
@Override
|
|
public void keyPressed(KeyEvent e) {
|
|
handleKeyPressed(e);
|
|
}
|
|
});
|
|
detailPanel.setVisible(false);
|
|
|
|
updateUi();
|
|
|
|
this.openables.addCollectionChangedListener((e) -> {
|
|
AbstractTagTreeModel ttm = tagTree.getFullModel();
|
|
if (ttm != null) {
|
|
if (getCurrentSwf() == null) {
|
|
tagTree.clearSelection();
|
|
}
|
|
ttm.updateSwfs(e);
|
|
tagTree.expandRoot();
|
|
if (Configuration.expandFirstLevelOfTreeOnLoad.get()) {
|
|
if (e.getAction() == CollectionChangedAction.RESET) {
|
|
tagTree.expandFirstLevelNodes();
|
|
} else if (e.getAction() == CollectionChangedAction.ADD) {
|
|
OpenableList list = e.getNewItem();
|
|
if (!list.isBundle() && list.items.size() == 1) {
|
|
tagTree.expandPath(tagTree.getFullModel().getTreePath(list.get(0)));
|
|
} else {
|
|
tagTree.expandPath(tagTree.getFullModel().getTreePath(list));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ttm = tagListTree.getFullModel();
|
|
if (ttm != null) {
|
|
if (getCurrentSwf() == null) {
|
|
tagListTree.clearSelection();
|
|
}
|
|
ttm.updateSwfs(e);
|
|
tagListTree.expandRoot();
|
|
|
|
if (Configuration.expandFirstLevelOfTreeOnLoad.get()) {
|
|
if (e.getAction() == CollectionChangedAction.RESET) {
|
|
tagListTree.expandFirstLevelNodes();
|
|
} else if (e.getAction() == CollectionChangedAction.ADD) {
|
|
OpenableList list = e.getNewItem();
|
|
if (!list.isBundle() && list.items.size() == 1) {
|
|
tagListTree.expandPath(tagListTree.getFullModel().getTreePath(list.get(0)));
|
|
} else {
|
|
tagListTree.expandPath(tagListTree.getFullModel().getTreePath(list));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DumpTreeModel dtm = dumpTree.getModel();
|
|
if (dtm != null) {
|
|
List<List<String>> expandedNodes = View.getExpandedNodes(dumpTree);
|
|
dtm.updateSwfs();
|
|
View.expandTreeNodes(dumpTree, expandedNodes);
|
|
dumpTree.expandRoot();
|
|
if (Configuration.expandFirstLevelOfTreeOnLoad.get()) {
|
|
if (e.getAction() == CollectionChangedAction.RESET) {
|
|
dumpTree.expandFirstLevelNodes();
|
|
} else if (e.getAction() == CollectionChangedAction.ADD) {
|
|
OpenableList list = e.getNewItem();
|
|
for (Openable dopenable : list) {
|
|
if (dopenable instanceof SWF) {
|
|
dumpTree.expandSwfNode((SWF) dopenable);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (openables.isEmpty()) {
|
|
tagTree.setUI(new BasicTreeUI() {
|
|
{
|
|
setHashColor(Color.gray);
|
|
}
|
|
});
|
|
dumpTree.setUI(new BasicTreeUI() {
|
|
{
|
|
setHashColor(Color.gray);
|
|
}
|
|
});
|
|
tagListTree.setUI(new BasicTreeUI() {
|
|
{
|
|
setHashColor(Color.gray);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
//Opening files with drag&drop to main window
|
|
enableDrop(true);
|
|
calculateMissingNeededThread = new CalculateMissingNeededThread();
|
|
calculateMissingNeededThread.start();
|
|
pinsPanel.load();
|
|
|
|
Configuration.flattenASPackages.addListener(new ConfigurationItemChangeListener<Boolean>() {
|
|
@Override
|
|
public void configurationItemChanged(Boolean newValue) {
|
|
resetAllTimelines();
|
|
refreshTree();
|
|
}
|
|
});
|
|
}
|
|
|
|
public void resetAllTimelines() {
|
|
List<OpenableList> openableLists = new ArrayList<>(openables);
|
|
List<SWF> allSwfs = new ArrayList<>();
|
|
for (OpenableList openableList : openableLists) {
|
|
for (Openable openable : openableList) {
|
|
if (openable instanceof SWF) {
|
|
allSwfs.add((SWF) openable);
|
|
}
|
|
}
|
|
for (Openable openable : openableList) {
|
|
if (openable instanceof SWF) {
|
|
Main.populateSwfs((SWF) openable, allSwfs);
|
|
}
|
|
}
|
|
}
|
|
for (SWF swf : allSwfs) {
|
|
swf.resetTimeline();
|
|
}
|
|
}
|
|
|
|
public void loadSwfAtPos(OpenableList newSwfs, int index) {
|
|
View.checkAccess();
|
|
|
|
OpenableList oldSwfList = openables.get(index);
|
|
|
|
List<SWF> allSwfs = new ArrayList<>();
|
|
for (Openable o : oldSwfList.items) {
|
|
if (o instanceof SWF) {
|
|
allSwfs.add((SWF) o);
|
|
Main.populateSwfs((SWF) o, allSwfs);
|
|
}
|
|
}
|
|
|
|
List<List<String>> expandedNodes = View.getExpandedNodes(tagTree);
|
|
previewPanel.clear();
|
|
openables.set(index, newSwfs);
|
|
|
|
for (SWF s : allSwfs) {
|
|
s.clearTagSwfs();
|
|
Main.searchResultsStorage.destroySwf(s);
|
|
}
|
|
Openable openable = newSwfs.size() > 0 ? newSwfs.get(0) : null;
|
|
if (openable != null) {
|
|
updateUi(openable);
|
|
}
|
|
|
|
gcClipboard();
|
|
reload(false);
|
|
View.expandTreeNodes(tagTree, expandedNodes);
|
|
doFilter();
|
|
pinsPanel.load();
|
|
}
|
|
|
|
public void load(OpenableList newOpenables, boolean first) {
|
|
View.checkAccess();
|
|
|
|
List<List<String>> expandedNodes = View.getExpandedNodes(getCurrentTree());
|
|
previewPanel.clear();
|
|
|
|
openables.add(newOpenables);
|
|
Openable openable = newOpenables.size() > 0 ? newOpenables.get(0) : null;
|
|
if (openable != null) {
|
|
updateUi(openable);
|
|
}
|
|
|
|
gcClipboard();
|
|
|
|
reload(false);
|
|
View.expandTreeNodes(getCurrentTree(), expandedNodes);
|
|
doFilter();
|
|
pinsPanel.load();
|
|
}
|
|
|
|
public ABCPanel getABCPanel() {
|
|
if (abcPanel == null) {
|
|
abcPanel = new ABCPanel(this);
|
|
displayPanel.add(abcPanel, CARDACTIONSCRIPT3PANEL);
|
|
detailPanel.add(abcPanel.tabbedPane, DETAILCARDAS3NAVIGATOR);
|
|
}
|
|
|
|
return abcPanel;
|
|
}
|
|
|
|
public ActionPanel getActionPanel() {
|
|
if (actionPanel == null) {
|
|
actionPanel = new ActionPanel(MainPanel.this);
|
|
displayPanel.add(actionPanel, CARDACTIONSCRIPTPANEL);
|
|
}
|
|
|
|
return actionPanel;
|
|
}
|
|
|
|
private void updateUi(final Openable openable) {
|
|
View.checkAccess();
|
|
|
|
if (isWelcomeScreen) {
|
|
showContentPanelCard(SPLIT_PANE1);
|
|
isWelcomeScreen = false;
|
|
}
|
|
SWF swf = null;
|
|
if (openable instanceof SWF) {
|
|
swf = (SWF) openable;
|
|
List<ABCContainerTag> abcList = swf.getAbcList();
|
|
|
|
boolean hasAbc = !abcList.isEmpty();
|
|
|
|
if (hasAbc) {
|
|
getABCPanel().setAbc(abcList.get(0).getABC());
|
|
}
|
|
}
|
|
mainMenu.updateComponents(openable);
|
|
|
|
if (taskThread != null) {
|
|
taskThread.interrupt();
|
|
}
|
|
|
|
if (Configuration._debugMode.get() && swf != null) {
|
|
final SWF fSwf = swf;
|
|
Thread t = new Thread() {
|
|
@Override
|
|
public void run() {
|
|
while (!Thread.currentThread().isInterrupted()) {
|
|
DecompilerPool d = fSwf.getDecompilerPool();
|
|
statusPanel.setStatus(fSwf.getFileTitle() + " " + d.getStat());
|
|
|
|
try {
|
|
Thread.sleep(100);
|
|
} catch (InterruptedException ex) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
t.start();
|
|
taskThread = t;
|
|
}
|
|
}
|
|
|
|
private void updateUi() {
|
|
View.checkAccess();
|
|
|
|
if (!isWelcomeScreen && openables.isEmpty()) {
|
|
showContentPanelCard(WELCOME_PANEL);
|
|
isWelcomeScreen = true;
|
|
quickTagListFindPanel.setVisible(false);
|
|
quickTreeFindPanel.setVisible(false);
|
|
doFilter();
|
|
}
|
|
|
|
mainFrame.setTitle(ApplicationInfo.applicationVerName);
|
|
mainMenu.updateComponents(null);
|
|
|
|
showView(getCurrentView());
|
|
}
|
|
|
|
private boolean closeConfirmation(OpenableList swfList) {
|
|
View.checkAccess();
|
|
|
|
String message = swfList == null
|
|
? translate("message.confirm.closeAll")
|
|
: translate("message.confirm.close").replace("{swfName}", swfList.toString());
|
|
|
|
return ViewMessages.showConfirmDialog(this, message, translate("message.warning"), JOptionPane.OK_CANCEL_OPTION, Configuration.showCloseConfirmation, JOptionPane.OK_OPTION) == JOptionPane.OK_OPTION;
|
|
}
|
|
|
|
public boolean isModified() {
|
|
for (OpenableList openableList : openables) {
|
|
for (Openable openable : openableList) {
|
|
if (openable.isModified()) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public boolean closeAll(boolean showCloseConfirmation, boolean onExit) {
|
|
View.checkAccess();
|
|
|
|
if (showCloseConfirmation && isModified()) {
|
|
boolean closeConfirmResult = closeConfirmation(openables.size() == 1 ? openables.get(0) : null);
|
|
if (!closeConfirmResult) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
clearPins();
|
|
|
|
List<OpenableList> swfsLists = new ArrayList<>(openables);
|
|
|
|
for (SearchResultsDialog sr : searchResultsDialogs) {
|
|
sr.setVisible(false);
|
|
}
|
|
searchResultsDialogs.clear();
|
|
|
|
openables.clear();
|
|
oldItem = null;
|
|
clear();
|
|
updateUi();
|
|
|
|
List<SWF> swfsToClose = new ArrayList<>();
|
|
for (OpenableList openableList : swfsLists) {
|
|
for (Openable openable : openableList) {
|
|
if (openable instanceof SWF) {
|
|
swfsToClose.add((SWF) openable);
|
|
}
|
|
}
|
|
for (Openable openable : openableList) {
|
|
if (openable instanceof SWF) {
|
|
Main.populateSwfs((SWF) openable, swfsToClose);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (SWF swf : swfsToClose) {
|
|
swf.clearTagSwfs();
|
|
if (!onExit) {
|
|
SwfSpecificCustomConfiguration cc = Configuration.getSwfSpecificCustomConfiguration(swf.getShortPathTitle());
|
|
if (cc != null) {
|
|
cc.setCustomData(CustomConfigurationKeys.KEY_LOADED_IMPORT_ASSETS, "");
|
|
}
|
|
}
|
|
}
|
|
|
|
refreshTree();
|
|
|
|
gcClipboard();
|
|
mainMenu.updateComponents(null);
|
|
previewPanel.clear();
|
|
|
|
return true;
|
|
}
|
|
|
|
public boolean close(OpenableList openableList) {
|
|
View.checkAccess();
|
|
|
|
boolean modified = false;
|
|
for (Openable openable : openableList) {
|
|
if (openable.isModified()) {
|
|
modified = true;
|
|
}
|
|
}
|
|
|
|
if (modified) {
|
|
boolean closeConfirmResult = closeConfirmation(openableList);
|
|
if (!closeConfirmResult) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
List<SWF> swfsToClose = new ArrayList<>();
|
|
for (Openable openable : openableList) {
|
|
if (openable instanceof SWF) {
|
|
swfsToClose.add((SWF) openable);
|
|
}
|
|
}
|
|
for (Openable openable : openableList) {
|
|
if (openable instanceof SWF) {
|
|
Main.populateSwfs((SWF) openable, swfsToClose);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < searchResultsDialogs.size(); i++) {
|
|
SearchResultsDialog sr = searchResultsDialogs.get(i);
|
|
for (SWF swf : swfsToClose) {
|
|
sr.removeSwf(swf);
|
|
}
|
|
if (sr.isEmpty()) {
|
|
sr.setVisible(false);
|
|
searchResultsDialogs.remove(i);
|
|
i--;
|
|
}
|
|
}
|
|
for (SWF swf : swfsToClose) {
|
|
Main.searchResultsStorage.destroySwf(swf);
|
|
pinsPanel.removeOpenable(swf);
|
|
SwfSpecificCustomConfiguration cc = Configuration.getSwfSpecificCustomConfiguration(swf.getShortPathTitle());
|
|
if (cc != null) {
|
|
cc.setCustomData(CustomConfigurationKeys.KEY_LOADED_IMPORT_ASSETS, "");
|
|
}
|
|
}
|
|
|
|
openables.remove(openableList);
|
|
oldItem = null;
|
|
clear();
|
|
updateUi();
|
|
|
|
for (SWF swf : swfsToClose) {
|
|
swf.clearTagSwfs();
|
|
}
|
|
|
|
refreshTree();
|
|
|
|
gcClipboard();
|
|
|
|
mainMenu.updateComponents(null);
|
|
previewPanel.clear();
|
|
dumpPreviewPanel.clear();
|
|
return true;
|
|
}
|
|
|
|
private void enableDrop(boolean value) {
|
|
if (value) {
|
|
setDropTarget(new DropTarget() {
|
|
@Override
|
|
public synchronized void drop(DropTargetDropEvent dtde) {
|
|
try {
|
|
dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
|
|
@SuppressWarnings("unchecked")
|
|
List<File> droppedFiles = (List<File>) dtde.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
|
|
if (!droppedFiles.isEmpty()) {
|
|
OpenableSourceInfo[] sourceInfos = new OpenableSourceInfo[droppedFiles.size()];
|
|
for (int i = 0; i < droppedFiles.size(); i++) {
|
|
sourceInfos[i] = new OpenableSourceInfo(null, droppedFiles.get(i).getAbsolutePath(), null);
|
|
}
|
|
Main.openFile(sourceInfos, null);
|
|
}
|
|
} catch (UnsupportedFlavorException | IOException ex) {
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
setDropTarget(null);
|
|
}
|
|
}
|
|
|
|
public void updateClassesList() {
|
|
String selectionPath = getCurrentTree().getSelectionPathString();
|
|
List<TreeItem> nodes = getASTreeNodes(tagTree);
|
|
boolean updateNeeded = false;
|
|
for (TreeItem n : nodes) {
|
|
if (n instanceof ClassesListTreeModel) {
|
|
((ClassesListTreeModel) n).update();
|
|
updateNeeded = true;
|
|
}
|
|
}
|
|
|
|
refreshTree();
|
|
|
|
if (updateNeeded) {
|
|
tagTree.updateUI();
|
|
}
|
|
TreePath tp = getCurrentTree().getTreePathFromString(selectionPath);
|
|
if (tp != null) {
|
|
getCurrentTree().setSelectionPath(tp);
|
|
}
|
|
}
|
|
|
|
private boolean isFilterEmpty(String filter) {
|
|
return filter.trim().length() < 3;
|
|
}
|
|
|
|
private void doFilter(AbstractTagTree tree, QuickTreeFindPanel findPanel, List<List<String>> unfilteredExpandedNodes) {
|
|
TreeModel model = tree.getModel();
|
|
String oldFilter = "";
|
|
if (model instanceof FilteredTreeModel) {
|
|
oldFilter = ((FilteredTreeModel) model).getFilter();
|
|
}
|
|
String newFilter = findPanel.getFilter();
|
|
|
|
if (isFilterEmpty(oldFilter)) {
|
|
unfilteredExpandedNodes.clear();;
|
|
unfilteredExpandedNodes.addAll(View.getExpandedNodes(tree));
|
|
}
|
|
|
|
if (oldFilter.trim().equals(newFilter.trim())) {
|
|
return;
|
|
}
|
|
|
|
TreePath selectionPaths[] = tree.getSelectionPaths();
|
|
tree.setModel(new FilteredTreeModel(newFilter, tree.getFullModel(), tree));
|
|
if (!isFilterEmpty(newFilter)) {
|
|
for (int i = 0; i < tree.getRowCount(); i++) {
|
|
tree.expandRow(i);
|
|
}
|
|
} else {
|
|
tree.setModel(tree.getFullModel());
|
|
View.expandTreeNodes(tree, unfilteredExpandedNodes);
|
|
}
|
|
tree.setSelectionPaths(selectionPaths);
|
|
}
|
|
|
|
public void doFilter() {
|
|
View.checkAccess();
|
|
doFilter(tagTree, quickTreeFindPanel, unfilteredTreeExpandedNodes);
|
|
doFilter(tagListTree, quickTagListFindPanel, unfilteredTagListExpandedNodes);
|
|
}
|
|
|
|
public void renameIdentifier(SWF swf, String identifier) throws InterruptedException {
|
|
String oldName = identifier;
|
|
String newName = ViewMessages.showInputDialog(this, translate("rename.enternew"), oldName);
|
|
if (newName != null) {
|
|
if (!oldName.equals(newName)) {
|
|
swf.renameAS2Identifier(oldName, newName);
|
|
ViewMessages.showMessageDialog(this, translate("rename.finished.identifier"));
|
|
updateClassesList();
|
|
reload(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void renameMultiname(List<ABCContainerTag> abcList, int multiNameIndex) {
|
|
String oldName = "";
|
|
AVM2ConstantPool constants = getABCPanel().abc.constants;
|
|
if (constants.getMultiname(multiNameIndex).name_index > 0) {
|
|
oldName = constants.getString(constants.getMultiname(multiNameIndex).name_index);
|
|
}
|
|
|
|
String newName = ViewMessages.showInputDialog(this, translate("rename.enternew"), oldName);
|
|
if (newName != null) {
|
|
if (!oldName.equals(newName)) {
|
|
int mulCount = 0;
|
|
for (ABCContainerTag cnt : abcList) {
|
|
ABC abc = cnt.getABC();
|
|
for (int m = 1; m < abc.constants.getMultinameCount(); m++) {
|
|
int ni = abc.constants.getMultiname(m).name_index;
|
|
String n = "";
|
|
if (ni > 0) {
|
|
n = abc.constants.getString(ni);
|
|
}
|
|
if (n.equals(oldName)) {
|
|
abc.renameMultiname(m, newName);
|
|
mulCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
int fmulCount = mulCount;
|
|
View.execInEventDispatch(() -> {
|
|
ViewMessages.showMessageDialog(this, translate("rename.finished.multiname").replace("%count%", Integer.toString(fmulCount)));
|
|
if (abcPanel != null) {
|
|
abcPanel.reload();
|
|
}
|
|
|
|
updateClassesList();
|
|
reload(true);
|
|
ABCPanel abcPanel = getABCPanel();
|
|
abcPanel.hilightScript(abcPanel.getSwf(), abcPanel.decompiledTextArea.getScriptLeaf().getClassPath().toRawString());
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
public List<TreeItem> getASTreeNodes(TagTree tree) {
|
|
List<TreeItem> result = new ArrayList<>();
|
|
TagTreeModel tm = (TagTreeModel) tree.getModel();
|
|
if (tm == null) {
|
|
return result;
|
|
}
|
|
TreeItem root = tm.getRoot();
|
|
for (int i = 0; i < tm.getChildCount(root); i++) {
|
|
// first level node can be SWF and SWFBundle
|
|
TreeItem node = tm.getChild(root, i);
|
|
if (node instanceof Bundle) {
|
|
for (int j = 0; j < tm.getChildCount(node); j++) {
|
|
// child of SWFBundle should be SWF
|
|
SWF swfNode = (SWF) tm.getChild(node, j);
|
|
result.add(tm.getScriptsNode(swfNode));
|
|
}
|
|
} else if (node instanceof SWF) {
|
|
SWF swfNode = (SWF) tm.getChild(root, i);
|
|
result.add(tm.getScriptsNode(swfNode));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public boolean confirmExperimental() {
|
|
View.checkAccess();
|
|
|
|
return ViewMessages.showConfirmDialog(this, translate("message.confirm.experimental"), translate("message.warning"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION;
|
|
}
|
|
|
|
private List<TreeItem> getSelection(Openable openable, List<TreeItem> selection) {
|
|
if (currentView == MainPanel.VIEW_RESOURCES) {
|
|
return selection == null ? tagTree.getSelection(openable) : tagTree.getSelectionAndAllSubs(openable, selection);
|
|
} else if (currentView == MainPanel.VIEW_TAGLIST) {
|
|
return selection == null ? tagListTree.getSelection(openable) : tagListTree.getSelectionAndAllSubs(openable, selection);
|
|
}
|
|
return new ArrayList<>();
|
|
}
|
|
|
|
public List<File> exportSelection(List<TreeItem> selection, AbortRetryIgnoreHandler handler, String selFile, ExportDialog export) throws IOException, InterruptedException {
|
|
|
|
List<File> ret = new ArrayList<>();
|
|
List<TreeItem> sel = getSelection(null, selection);
|
|
|
|
Set<Openable> usedOpenables = new HashSet<>();
|
|
for (TreeItem d : sel) {
|
|
Openable selectedNodeOpenable = d.getOpenable();
|
|
if (!usedOpenables.contains(selectedNodeOpenable)) {
|
|
usedOpenables.add(selectedNodeOpenable);
|
|
}
|
|
}
|
|
|
|
Map<String, Integer> usedSwfsIds = new HashMap<>();
|
|
for (Openable openable : usedOpenables) {
|
|
|
|
SWF swf = null;
|
|
if (openable instanceof SWF) {
|
|
swf = (SWF) openable;
|
|
} else {
|
|
swf = ((ABC) openable).getSwf();
|
|
}
|
|
List<ScriptPack> as3scripts = new ArrayList<>();
|
|
List<Tag> images = new ArrayList<>();
|
|
List<Tag> shapes = new ArrayList<>();
|
|
List<Tag> morphshapes = new ArrayList<>();
|
|
List<Tag> sprites = new ArrayList<>();
|
|
List<Tag> buttons = new ArrayList<>();
|
|
List<Tag> movies = new ArrayList<>();
|
|
List<Tag> sounds = new ArrayList<>();
|
|
List<Tag> texts = new ArrayList<>();
|
|
List<TreeItem> as12scripts = new ArrayList<>();
|
|
List<Tag> binaryData = new ArrayList<>();
|
|
Map<Integer, List<Integer>> frames = new HashMap<>();
|
|
List<Tag> fonts = new ArrayList<>();
|
|
List<Tag> symbolNames = new ArrayList<>();
|
|
|
|
for (TreeItem d : sel) {
|
|
Openable selectedNodeSwf = d.getOpenable();
|
|
|
|
if (selectedNodeSwf != openable) {
|
|
continue;
|
|
}
|
|
|
|
if (d instanceof TagScript) {
|
|
Tag tag = ((TagScript) d).getTag();
|
|
if (tag instanceof DoActionTag || tag instanceof DoInitActionTag) {
|
|
as12scripts.add(d);
|
|
}
|
|
}
|
|
|
|
if (d instanceof Tag || d instanceof ASMSource) {
|
|
TreeNodeType nodeType = TagTree.getTreeNodeType(d);
|
|
if (nodeType == TreeNodeType.IMAGE) {
|
|
images.add((Tag) d);
|
|
}
|
|
if (nodeType == TreeNodeType.SHAPE) {
|
|
shapes.add((Tag) d);
|
|
}
|
|
if (nodeType == TreeNodeType.BUTTON) {
|
|
buttons.add((Tag) d);
|
|
}
|
|
if (nodeType == TreeNodeType.MORPH_SHAPE) {
|
|
morphshapes.add((Tag) d);
|
|
}
|
|
if (nodeType == TreeNodeType.SPRITE) {
|
|
sprites.add((Tag) d);
|
|
}
|
|
if ((nodeType == TreeNodeType.AS)
|
|
|| (nodeType == TreeNodeType.AS_FRAME)
|
|
|| (nodeType == TreeNodeType.AS_BUTTON)
|
|
|| (nodeType == TreeNodeType.AS_CLIP)
|
|
|| (nodeType == TreeNodeType.AS_INIT)
|
|
|| (nodeType == TreeNodeType.AS_CLASS)) {
|
|
as12scripts.add(d);
|
|
}
|
|
if (nodeType == TreeNodeType.MOVIE) {
|
|
movies.add((Tag) d);
|
|
}
|
|
if (nodeType == TreeNodeType.SOUND) {
|
|
sounds.add((Tag) d);
|
|
}
|
|
if (nodeType == TreeNodeType.BINARY_DATA) {
|
|
binaryData.add((Tag) d);
|
|
}
|
|
if (nodeType == TreeNodeType.TEXT) {
|
|
texts.add((Tag) d);
|
|
}
|
|
if (nodeType == TreeNodeType.FONT) {
|
|
fonts.add((Tag) d);
|
|
}
|
|
if (nodeType == TreeNodeType.OTHER_TAG) {
|
|
if (d instanceof SymbolClassTypeTag) {
|
|
symbolNames.add((Tag) d);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (d instanceof Frame) {
|
|
Frame fn = (Frame) d;
|
|
Timelined parent = fn.timeline.timelined;
|
|
int frame = fn.frame;
|
|
int parentId = 0;
|
|
if (parent instanceof CharacterTag) {
|
|
parentId = ((CharacterTag) parent).getCharacterId();
|
|
}
|
|
if (!frames.containsKey(parentId)) {
|
|
frames.put(parentId, new ArrayList<>());
|
|
}
|
|
|
|
frames.get(parentId).add(frame);
|
|
}
|
|
|
|
if (d instanceof ScriptPack) {
|
|
as3scripts.add((ScriptPack) d);
|
|
}
|
|
}
|
|
|
|
for (Tag sprite : sprites) {
|
|
frames.put(((DefineSpriteTag) sprite).getCharacterId(), null);
|
|
}
|
|
|
|
String selFile2;
|
|
if (usedOpenables.size() > 1) {
|
|
selFile2 = selFile + File.separator + Helper.getNextId(openable.getTitleOrShortFileName(), usedSwfsIds);
|
|
} else {
|
|
selFile2 = selFile;
|
|
}
|
|
|
|
EventListener evl = swf.getExportEventListener();
|
|
|
|
if (export.isOptionEnabled(ImageExportMode.class)) {
|
|
ret.addAll(new ImageExporter().exportImages(handler, selFile2 + File.separator + ImageExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(images),
|
|
new ImageExportSettings(export.getValue(ImageExportMode.class)), evl));
|
|
}
|
|
|
|
if (export.isOptionEnabled(ShapeExportMode.class)) {
|
|
ret.addAll(new ShapeExporter().exportShapes(handler, selFile2 + File.separator + ShapeExportSettings.EXPORT_FOLDER_NAME, swf, new ReadOnlyTagList(shapes),
|
|
new ShapeExportSettings(export.getValue(ShapeExportMode.class), export.getZoom()), evl, export.getZoom()));
|
|
}
|
|
|
|
if (export.isOptionEnabled(MorphShapeExportMode.class)) {
|
|
ret.addAll(new MorphShapeExporter().exportMorphShapes(handler, selFile2 + File.separator + MorphShapeExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(morphshapes),
|
|
new MorphShapeExportSettings(export.getValue(MorphShapeExportMode.class), export.getZoom()), evl));
|
|
}
|
|
|
|
if (export.isOptionEnabled(TextExportMode.class)) {
|
|
ret.addAll(new TextExporter().exportTexts(handler, selFile2 + File.separator + TextExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(texts),
|
|
new TextExportSettings(export.getValue(TextExportMode.class), Configuration.textExportSingleFile.get(), export.getZoom()), evl));
|
|
}
|
|
|
|
if (export.isOptionEnabled(MovieExportMode.class)) {
|
|
ret.addAll(new MovieExporter().exportMovies(handler, selFile2 + File.separator + MovieExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(movies),
|
|
new MovieExportSettings(export.getValue(MovieExportMode.class)), evl));
|
|
}
|
|
|
|
if (export.isOptionEnabled(SoundExportMode.class)) {
|
|
ret.addAll(new SoundExporter().exportSounds(handler, selFile2 + File.separator + SoundExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(sounds),
|
|
new SoundExportSettings(export.getValue(SoundExportMode.class)), evl));
|
|
}
|
|
|
|
if (export.isOptionEnabled(BinaryDataExportMode.class)) {
|
|
ret.addAll(new BinaryDataExporter().exportBinaryData(handler, selFile2 + File.separator + BinaryDataExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(binaryData),
|
|
new BinaryDataExportSettings(export.getValue(BinaryDataExportMode.class)), evl));
|
|
}
|
|
|
|
if (export.isOptionEnabled(FontExportMode.class)) {
|
|
ret.addAll(new FontExporter().exportFonts(handler, selFile2 + File.separator + FontExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(fonts),
|
|
new FontExportSettings(export.getValue(FontExportMode.class)), evl));
|
|
}
|
|
|
|
if (export.isOptionEnabled(SymbolClassExportMode.class)) {
|
|
ret.addAll(new SymbolClassExporter().exportNames(handler, selFile2 + File.separator + SymbolClassExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(symbolNames),
|
|
new SymbolClassExportSettings(export.getValue(SymbolClassExportMode.class)), evl));
|
|
}
|
|
|
|
FrameExporter frameExporter = new FrameExporter();
|
|
|
|
if (export.isOptionEnabled(FrameExportMode.class)) {
|
|
FrameExportSettings fes = new FrameExportSettings(export.getValue(FrameExportMode.class), export.getZoom());
|
|
if (frames.containsKey(0)) {
|
|
String subFolder = FrameExportSettings.EXPORT_FOLDER_NAME;
|
|
ret.addAll(frameExporter.exportFrames(handler, selFile2 + File.separator + subFolder, swf, 0, frames.get(0), fes, evl));
|
|
}
|
|
}
|
|
|
|
if (export.isOptionEnabled(SpriteExportMode.class)) {
|
|
SpriteExportSettings ses = new SpriteExportSettings(export.getValue(SpriteExportMode.class), export.getZoom());
|
|
for (Entry<Integer, List<Integer>> entry : frames.entrySet()) {
|
|
int containerId = entry.getKey();
|
|
if (containerId != 0) {
|
|
String subFolder = SpriteExportSettings.EXPORT_FOLDER_NAME;
|
|
ret.addAll(frameExporter.exportSpriteFrames(handler, selFile2 + File.separator + subFolder, swf, containerId, entry.getValue(), ses, evl));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (export.isOptionEnabled(ButtonExportMode.class)) {
|
|
ButtonExportSettings bes = new ButtonExportSettings(export.getValue(ButtonExportMode.class), export.getZoom());
|
|
for (Tag tag : buttons) {
|
|
ButtonTag button = (ButtonTag) tag;
|
|
String subFolder = ButtonExportSettings.EXPORT_FOLDER_NAME;
|
|
ret.addAll(frameExporter.exportButtonFrames(handler, selFile2 + File.separator + subFolder, swf, button.getCharacterId(), null, bes, evl));
|
|
}
|
|
}
|
|
|
|
if (export.isOptionEnabled(ScriptExportMode.class)) {
|
|
if (as3scripts.size() > 0 || as12scripts.size() > 0) {
|
|
boolean parallel = Configuration.parallelSpeedUp.get();
|
|
String scriptsFolder = Path.combine(selFile2, ScriptExportSettings.EXPORT_FOLDER_NAME);
|
|
Path.createDirectorySafe(new File(scriptsFolder));
|
|
boolean singleScriptFile = Configuration.scriptExportSingleFile.get();
|
|
if (parallel && singleScriptFile) {
|
|
logger.log(Level.WARNING, AppStrings.translate("export.script.singleFilePallelModeWarning"));
|
|
singleScriptFile = false;
|
|
}
|
|
|
|
ScriptExportSettings scriptExportSettings = new ScriptExportSettings(export.getValue(ScriptExportMode.class), singleScriptFile, false);
|
|
String singleFileName = Path.combine(scriptsFolder, openable.getShortFileName() + scriptExportSettings.getFileExtension());
|
|
try (FileTextWriter writer = scriptExportSettings.singleFile ? new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(singleFileName)) : null) {
|
|
scriptExportSettings.singleFileWriter = writer;
|
|
if (swf.isAS3()) {
|
|
ret.addAll(new AS3ScriptExporter().exportActionScript3(swf, handler, scriptsFolder, as3scripts, scriptExportSettings, parallel, evl));
|
|
} else {
|
|
Map<String, ASMSource> asmsToExport = swf.getASMs(true, as12scripts, false);
|
|
ret.addAll(new AS2ScriptExporter().exportAS2Scripts(handler, scriptsFolder, asmsToExport, scriptExportSettings, parallel, evl));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
public void exportAll(SWF swf, AbortRetryIgnoreHandler handler, String selFile, ExportDialog export) throws IOException, InterruptedException {
|
|
boolean exportAll = false;
|
|
if (exportAll) {
|
|
exportAllDebug(swf, handler, selFile, export);
|
|
return;
|
|
}
|
|
|
|
EventListener evl = swf.getExportEventListener();
|
|
|
|
if (export.isOptionEnabled(ImageExportMode.class)) {
|
|
new ImageExporter().exportImages(handler, Path.combine(selFile, ImageExportSettings.EXPORT_FOLDER_NAME), swf.getTags(),
|
|
new ImageExportSettings(export.getValue(ImageExportMode.class)), evl);
|
|
}
|
|
|
|
if (export.isOptionEnabled(ShapeExportMode.class)) {
|
|
new ShapeExporter().exportShapes(handler, Path.combine(selFile, ShapeExportSettings.EXPORT_FOLDER_NAME), swf, swf.getTags(),
|
|
new ShapeExportSettings(export.getValue(ShapeExportMode.class), export.getZoom()), evl, export.getZoom());
|
|
}
|
|
|
|
if (export.isOptionEnabled(MorphShapeExportMode.class)) {
|
|
new MorphShapeExporter().exportMorphShapes(handler, Path.combine(selFile, MorphShapeExportSettings.EXPORT_FOLDER_NAME), swf.getTags(),
|
|
new MorphShapeExportSettings(export.getValue(MorphShapeExportMode.class), export.getZoom()), evl);
|
|
}
|
|
|
|
if (export.isOptionEnabled(TextExportMode.class)) {
|
|
new TextExporter().exportTexts(handler, Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME), swf.getTags(),
|
|
new TextExportSettings(export.getValue(TextExportMode.class), Configuration.textExportSingleFile.get(), export.getZoom()), evl);
|
|
}
|
|
|
|
if (export.isOptionEnabled(MovieExportMode.class)) {
|
|
new MovieExporter().exportMovies(handler, Path.combine(selFile, MovieExportSettings.EXPORT_FOLDER_NAME), swf.getTags(),
|
|
new MovieExportSettings(export.getValue(MovieExportMode.class)), evl);
|
|
}
|
|
|
|
if (export.isOptionEnabled(SoundExportMode.class)) {
|
|
new SoundExporter().exportSounds(handler, Path.combine(selFile, SoundExportSettings.EXPORT_FOLDER_NAME), swf.getTags(),
|
|
new SoundExportSettings(export.getValue(SoundExportMode.class)), evl);
|
|
}
|
|
|
|
if (export.isOptionEnabled(BinaryDataExportMode.class)) {
|
|
new BinaryDataExporter().exportBinaryData(handler, Path.combine(selFile, BinaryDataExportSettings.EXPORT_FOLDER_NAME), swf.getTags(),
|
|
new BinaryDataExportSettings(export.getValue(BinaryDataExportMode.class)), evl);
|
|
}
|
|
|
|
if (export.isOptionEnabled(FontExportMode.class)) {
|
|
new FontExporter().exportFonts(handler, Path.combine(selFile, FontExportSettings.EXPORT_FOLDER_NAME), swf.getTags(),
|
|
new FontExportSettings(export.getValue(FontExportMode.class)), evl);
|
|
}
|
|
|
|
if (export.isOptionEnabled(SymbolClassExportMode.class)) {
|
|
new SymbolClassExporter().exportNames(handler, Path.combine(selFile, SymbolClassExportSettings.EXPORT_FOLDER_NAME), swf.getTags(),
|
|
new SymbolClassExportSettings(export.getValue(SymbolClassExportMode.class)), evl);
|
|
}
|
|
|
|
FrameExporter frameExporter = new FrameExporter();
|
|
|
|
if (export.isOptionEnabled(FrameExportMode.class)) {
|
|
FrameExportSettings fes = new FrameExportSettings(export.getValue(FrameExportMode.class), export.getZoom());
|
|
frameExporter.exportFrames(handler, Path.combine(selFile, FrameExportSettings.EXPORT_FOLDER_NAME), swf, 0, null, fes, evl);
|
|
}
|
|
|
|
if (export.isOptionEnabled(SpriteExportMode.class)) {
|
|
SpriteExportSettings ses = new SpriteExportSettings(export.getValue(SpriteExportMode.class), export.getZoom());
|
|
for (CharacterTag c : swf.getCharacters().values()) {
|
|
if (c instanceof DefineSpriteTag) {
|
|
frameExporter.exportSpriteFrames(handler, Path.combine(selFile, SpriteExportSettings.EXPORT_FOLDER_NAME), swf, c.getCharacterId(), null, ses, evl);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (export.isOptionEnabled(ButtonExportMode.class)) {
|
|
ButtonExportSettings bes = new ButtonExportSettings(export.getValue(ButtonExportMode.class), export.getZoom());
|
|
for (CharacterTag c : swf.getCharacters().values()) {
|
|
if (c instanceof ButtonTag) {
|
|
frameExporter.exportButtonFrames(handler, Path.combine(selFile, ButtonExportSettings.EXPORT_FOLDER_NAME), swf, c.getCharacterId(), null, bes, evl);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (export.isOptionEnabled(ScriptExportMode.class)) {
|
|
boolean parallel = Configuration.parallelSpeedUp.get();
|
|
String scriptsFolder = Path.combine(selFile, ScriptExportSettings.EXPORT_FOLDER_NAME);
|
|
Path.createDirectorySafe(new File(scriptsFolder));
|
|
boolean singleScriptFile = Configuration.scriptExportSingleFile.get();
|
|
if (parallel && singleScriptFile) {
|
|
logger.log(Level.WARNING, AppStrings.translate("export.script.singleFilePallelModeWarning"));
|
|
singleScriptFile = false;
|
|
}
|
|
|
|
ScriptExportSettings scriptExportSettings = new ScriptExportSettings(export.getValue(ScriptExportMode.class), singleScriptFile, false);
|
|
String singleFileName = Path.combine(scriptsFolder, swf.getShortFileName() + scriptExportSettings.getFileExtension());
|
|
try (FileTextWriter writer = scriptExportSettings.singleFile ? new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(singleFileName)) : null) {
|
|
scriptExportSettings.singleFileWriter = writer;
|
|
swf.exportActionScript(handler, scriptsFolder, scriptExportSettings, parallel, evl);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void exportAllDebug(SWF swf, AbortRetryIgnoreHandler handler, String selFile, ExportDialog export) throws IOException, InterruptedException {
|
|
EventListener evl = swf.getExportEventListener();
|
|
|
|
if (export.isOptionEnabled(ImageExportMode.class)) {
|
|
for (ImageExportMode exportMode : ImageExportMode.values()) {
|
|
new ImageExporter().exportImages(handler, Path.combine(selFile, ImageExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(),
|
|
new ImageExportSettings(exportMode), evl);
|
|
}
|
|
}
|
|
|
|
if (export.isOptionEnabled(ShapeExportMode.class)) {
|
|
for (ShapeExportMode exportMode : ShapeExportMode.values()) {
|
|
new ShapeExporter().exportShapes(handler, Path.combine(selFile, ShapeExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf, swf.getTags(),
|
|
new ShapeExportSettings(exportMode, export.getZoom()), evl, export.getZoom());
|
|
}
|
|
}
|
|
|
|
if (export.isOptionEnabled(MorphShapeExportMode.class)) {
|
|
for (MorphShapeExportMode exportMode : MorphShapeExportMode.values()) {
|
|
new MorphShapeExporter().exportMorphShapes(handler, Path.combine(selFile, MorphShapeExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(),
|
|
new MorphShapeExportSettings(exportMode, export.getZoom()), evl);
|
|
}
|
|
}
|
|
|
|
if (export.isOptionEnabled(TextExportMode.class)) {
|
|
for (TextExportMode exportMode : TextExportMode.values()) {
|
|
new TextExporter().exportTexts(handler, Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(),
|
|
new TextExportSettings(exportMode, Configuration.textExportSingleFile.get(), export.getZoom()), evl);
|
|
}
|
|
}
|
|
|
|
if (export.isOptionEnabled(MovieExportMode.class)) {
|
|
for (MovieExportMode exportMode : MovieExportMode.values()) {
|
|
new MovieExporter().exportMovies(handler, Path.combine(selFile, MovieExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(),
|
|
new MovieExportSettings(exportMode), evl);
|
|
}
|
|
}
|
|
|
|
if (export.isOptionEnabled(SoundExportMode.class)) {
|
|
for (SoundExportMode exportMode : SoundExportMode.values()) {
|
|
new SoundExporter().exportSounds(handler, Path.combine(selFile, SoundExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(),
|
|
new SoundExportSettings(exportMode), evl);
|
|
}
|
|
}
|
|
|
|
if (export.isOptionEnabled(BinaryDataExportMode.class)) {
|
|
for (BinaryDataExportMode exportMode : BinaryDataExportMode.values()) {
|
|
new BinaryDataExporter().exportBinaryData(handler, Path.combine(selFile, BinaryDataExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(),
|
|
new BinaryDataExportSettings(exportMode), evl);
|
|
}
|
|
}
|
|
|
|
if (export.isOptionEnabled(FontExportMode.class)) {
|
|
for (FontExportMode exportMode : FontExportMode.values()) {
|
|
new FontExporter().exportFonts(handler, Path.combine(selFile, FontExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(),
|
|
new FontExportSettings(exportMode), evl);
|
|
}
|
|
}
|
|
|
|
if (export.isOptionEnabled(SymbolClassExportMode.class)) {
|
|
for (SymbolClassExportMode exportMode : SymbolClassExportMode.values()) {
|
|
new SymbolClassExporter().exportNames(handler, Path.combine(selFile, SymbolClassExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(),
|
|
new SymbolClassExportSettings(exportMode), evl);
|
|
}
|
|
}
|
|
|
|
FrameExporter frameExporter = new FrameExporter();
|
|
|
|
if (export.isOptionEnabled(FrameExportMode.class)) {
|
|
for (FrameExportMode exportMode : FrameExportMode.values()) {
|
|
FrameExportSettings fes = new FrameExportSettings(exportMode, export.getZoom());
|
|
frameExporter.exportFrames(handler, Path.combine(selFile, FrameExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf, 0, null, fes, evl);
|
|
}
|
|
}
|
|
|
|
if (export.isOptionEnabled(SpriteExportMode.class)) {
|
|
for (SpriteExportMode exportMode : SpriteExportMode.values()) {
|
|
SpriteExportSettings ses = new SpriteExportSettings(exportMode, export.getZoom());
|
|
for (CharacterTag c : swf.getCharacters().values()) {
|
|
if (c instanceof DefineSpriteTag) {
|
|
frameExporter.exportSpriteFrames(handler, Path.combine(selFile, SpriteExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf, c.getCharacterId(), null, ses, evl);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (export.isOptionEnabled(ButtonExportMode.class)) {
|
|
for (ButtonExportMode exportMode : ButtonExportMode.values()) {
|
|
ButtonExportSettings bes = new ButtonExportSettings(exportMode, export.getZoom());
|
|
for (CharacterTag c : swf.getCharacters().values()) {
|
|
if (c instanceof ButtonTag) {
|
|
frameExporter.exportButtonFrames(handler, Path.combine(selFile, ButtonExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf, c.getCharacterId(), null, bes, evl);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (export.isOptionEnabled(ScriptExportMode.class)) {
|
|
boolean parallel = Configuration.parallelSpeedUp.get();
|
|
for (ScriptExportMode exportMode : ScriptExportMode.values()) {
|
|
String scriptsFolder = Path.combine(selFile, ScriptExportSettings.EXPORT_FOLDER_NAME, exportMode.name());
|
|
Path.createDirectorySafe(new File(scriptsFolder));
|
|
boolean singleScriptFile = Configuration.scriptExportSingleFile.get();
|
|
if (parallel && singleScriptFile) {
|
|
logger.log(Level.WARNING, AppStrings.translate("export.script.singleFilePallelModeWarning"));
|
|
singleScriptFile = false;
|
|
}
|
|
|
|
ScriptExportSettings scriptExportSettings = new ScriptExportSettings(exportMode, singleScriptFile, false);
|
|
String singleFileName = Path.combine(scriptsFolder, swf.getShortFileName() + scriptExportSettings.getFileExtension());
|
|
try (FileTextWriter writer = scriptExportSettings.singleFile ? new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(singleFileName)) : null) {
|
|
scriptExportSettings.singleFileWriter = writer;
|
|
swf.exportActionScript(handler, scriptsFolder, scriptExportSettings, parallel, evl);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public List<OpenableList> getSwfs() {
|
|
return openables;
|
|
}
|
|
|
|
public OpenableList getCurrentSwfList() {
|
|
SWF swf = getCurrentSwf();
|
|
if (swf == null) {
|
|
return null;
|
|
}
|
|
|
|
return swf.openableList;
|
|
}
|
|
|
|
public Openable getCurrentOpenable() {
|
|
if (openables == null || openables.isEmpty()) {
|
|
return null;
|
|
}
|
|
|
|
if (treePanelMode == TreePanelMode.TAG_TREE) {
|
|
TreeItem treeNode = (TreeItem) tagTree.getLastSelectedPathComponent();
|
|
if (treeNode == null || treeNode instanceof OpenableList) {
|
|
return null;
|
|
}
|
|
|
|
return treeNode.getOpenable();
|
|
} else if (treePanelMode == TreePanelMode.DUMP_TREE) {
|
|
DumpInfo dumpInfo = (DumpInfo) dumpTree.getLastSelectedPathComponent();
|
|
|
|
if (dumpInfo == null) {
|
|
return null;
|
|
}
|
|
|
|
return DumpInfoSwfNode.getSwfNode(dumpInfo).getOpenable();
|
|
} else if (treePanelMode == TreePanelMode.TAGLIST_TREE) {
|
|
TreeItem treeNode = (TreeItem) tagListTree.getLastSelectedPathComponent();
|
|
if (treeNode == null || treeNode instanceof OpenableList) {
|
|
return null;
|
|
}
|
|
|
|
return treeNode.getOpenable();
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public SWF getCurrentSwf() {
|
|
Openable openable = getCurrentOpenable();
|
|
if (openable instanceof SWF) {
|
|
return (SWF) openable;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public AbstractTagTree getCurrentTree() {
|
|
if (currentView == VIEW_RESOURCES) {
|
|
return tagTree;
|
|
}
|
|
if (currentView == VIEW_TAGLIST) {
|
|
return tagListTree;
|
|
}
|
|
return tagTree; //???
|
|
}
|
|
|
|
public void gotoFrame(int frame) {
|
|
View.checkAccess();
|
|
|
|
TreeItem treeItem = (TreeItem) getCurrentTree().getLastSelectedPathComponent();
|
|
if (treeItem == null) {
|
|
return;
|
|
}
|
|
if (treeItem instanceof Timelined) {
|
|
Timelined t = (Timelined) treeItem;
|
|
Frame f = tagTree.getFullModel().getFrame((SWF) treeItem.getOpenable(), t, frame);
|
|
if (f != null) {
|
|
setTagTreeSelectedNode(getCurrentTree(), f);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void gotoScriptLine(SWF swf, String scriptName, int line, int classIndex, int traitIndex, int methodIndex) {
|
|
View.checkAccess();
|
|
|
|
gotoScriptName(swf, scriptName);
|
|
if (abcPanel != null) {
|
|
if (Main.isDebugPCode()) {
|
|
if (classIndex != -1) {
|
|
boolean classChanged = false;
|
|
if (abcPanel.decompiledTextArea.getClassIndex() != classIndex) {
|
|
abcPanel.decompiledTextArea.setClassIndex(classIndex);
|
|
classChanged = true;
|
|
}
|
|
if (traitIndex != -10 && (classChanged || abcPanel.decompiledTextArea.lastTraitIndex != traitIndex)) {
|
|
abcPanel.decompiledTextArea.gotoTrait(traitIndex);
|
|
}
|
|
}
|
|
abcPanel.detailPanel.methodTraitPanel.methodCodePanel.gotoInstrLine(line);
|
|
} else {
|
|
abcPanel.decompiledTextArea.gotoLine(line);
|
|
}
|
|
} else if (actionPanel != null) {
|
|
if (Main.isDebugPCode()) {
|
|
actionPanel.editor.gotoLine(line);
|
|
} else {
|
|
actionPanel.decompiledEditor.gotoLine(line);
|
|
}
|
|
}
|
|
refreshBreakPoints();
|
|
|
|
}
|
|
|
|
public void refreshBreakPoints() {
|
|
if (abcPanel != null) {
|
|
abcPanel.decompiledTextArea.refreshMarkers();
|
|
abcPanel.detailPanel.methodTraitPanel.methodCodePanel.refreshMarkers();
|
|
}
|
|
if (actionPanel != null) {
|
|
actionPanel.decompiledEditor.refreshMarkers();
|
|
actionPanel.editor.refreshMarkers();
|
|
}
|
|
}
|
|
|
|
/*
|
|
public void debuggerBreakAt(SWF swf, String cls, int line) {
|
|
View.execInEventDispatchLater(new Runnable() {
|
|
|
|
@Override
|
|
public void run() {
|
|
gotoClassLine(swf, cls, line);
|
|
if (abcPanel != null) {
|
|
abcPanel.decompiledTextArea.addColorMarker(line, DecompiledEditorPane.FG_IP_COLOR, DecompiledEditorPane.BG_IP_COLOR, DecompiledEditorPane.PRIORITY_IP);
|
|
}
|
|
}
|
|
});
|
|
|
|
}*/
|
|
public void gotoScriptName(SWF swf, String scriptName) {
|
|
View.checkAccess();
|
|
|
|
if (swf == null) {
|
|
return;
|
|
}
|
|
if (swf.isAS3()) {
|
|
String rawScriptName = scriptName;
|
|
if (rawScriptName.startsWith("#PCODE ")) {
|
|
rawScriptName = rawScriptName.substring(rawScriptName.indexOf(';') + 1);
|
|
}
|
|
|
|
List<ABCContainerTag> abcList = swf.getAbcList();
|
|
if (!abcList.isEmpty()) {
|
|
ABCPanel abcPanel = getABCPanel();
|
|
abcPanel.setAbc(abcList.get(0).getABC());
|
|
abcPanel.hilightScript(swf, rawScriptName);
|
|
}
|
|
} else {
|
|
String rawScriptName = scriptName;
|
|
if (rawScriptName.startsWith("#PCODE ")) {
|
|
rawScriptName = rawScriptName.substring("#PCODE ".length());
|
|
}
|
|
Map<String, ASMSource> asms = swf.getASMs(true);
|
|
if (actionPanel != null && asms.containsKey(rawScriptName)) {
|
|
actionPanel.setSource(asms.get(rawScriptName), true);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void gotoDocumentClass(SWF swf) {
|
|
View.checkAccess();
|
|
|
|
if (swf == null) {
|
|
return;
|
|
}
|
|
|
|
String documentClass = swf.getDocumentClass();
|
|
if (documentClass != null && currentView != VIEW_DUMP) {
|
|
List<ABCContainerTag> abcList = swf.getAbcList();
|
|
if (!abcList.isEmpty()) {
|
|
ABCPanel abcPanel = getABCPanel();
|
|
for (ABCContainerTag c : abcList) {
|
|
if (c.getABC().findClassByName(documentClass) > -1) {
|
|
abcPanel.setAbc(c.getABC());
|
|
abcPanel.hilightScript(swf, documentClass);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void disableDecompilationChanged() {
|
|
View.checkAccess();
|
|
|
|
clearAllScriptCache();
|
|
|
|
if (abcPanel != null) {
|
|
abcPanel.reload();
|
|
}
|
|
|
|
updateClassesList();
|
|
}
|
|
|
|
private void clearAllScriptCache() {
|
|
for (OpenableList openableList : openables) {
|
|
for (Openable openable : openableList) {
|
|
if (openable instanceof SWF) {
|
|
((SWF) openable).clearScriptCache();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public Set<SWF> getAllSwfs() {
|
|
List<SWF> allSwfs = new ArrayList<>();
|
|
for (OpenableList slist : getSwfs()) {
|
|
for (Openable o : slist.items) {
|
|
if (o instanceof SWF) {
|
|
allSwfs.add((SWF) o);
|
|
Main.populateSwfs((SWF) o, allSwfs);
|
|
}
|
|
}
|
|
}
|
|
return new LinkedHashSet<>(allSwfs);
|
|
}
|
|
|
|
public Set<Openable> getAllOpenablesAndSwfs() {
|
|
List<Openable> allOpenables = new ArrayList<>();
|
|
for (OpenableList slist : getSwfs()) {
|
|
for (Openable o : slist.items) {
|
|
allOpenables.add(o);
|
|
if (o instanceof SWF) {
|
|
List<SWF> subSwfs = new ArrayList<>();
|
|
Main.populateSwfs((SWF) o, subSwfs);
|
|
for (SWF swf : subSwfs) {
|
|
allOpenables.add(swf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return new LinkedHashSet<>(allOpenables);
|
|
}
|
|
|
|
private List<TreeItem> getAllSelected() {
|
|
if (currentView == VIEW_RESOURCES) {
|
|
return tagTree.getAllSelected();
|
|
}
|
|
if (currentView == VIEW_TAGLIST) {
|
|
return tagListTree.getAllSelected();
|
|
}
|
|
return new ArrayList<>();
|
|
}
|
|
|
|
private List<TreeItem> getSelected() {
|
|
if (currentView == VIEW_RESOURCES) {
|
|
return tagTree.getSelected();
|
|
}
|
|
if (currentView == VIEW_TAGLIST) {
|
|
return tagListTree.getSelected();
|
|
}
|
|
return new ArrayList<>();
|
|
}
|
|
|
|
public void searchInActionScriptOrText(Boolean searchInText, Openable openable, boolean useSelection) {
|
|
View.checkAccess();
|
|
|
|
/*if (!(openable instanceof SWF)) { //FIXME for ABCs
|
|
return;
|
|
}*/
|
|
SWF swf = (openable instanceof SWF) ? (SWF) openable : ((ABC) openable).getSwf();
|
|
|
|
Map<Openable, List<ScriptPack>> scopeAs3 = new LinkedHashMap<>();
|
|
Map<SWF, Map<String, ASMSource>> swfToAllASMSourceMap = new HashMap<>();
|
|
Map<SWF, Map<String, ASMSource>> scopeAs12 = new LinkedHashMap<>();
|
|
|
|
Set<Openable> openablesUsed = new LinkedHashSet<>();
|
|
|
|
List<TreeItem> allItems = getAllSelected();
|
|
for (TreeItem t : allItems) {
|
|
if (t instanceof ScriptPack) {
|
|
ScriptPack sp = (ScriptPack) t;
|
|
Openable s = sp.getOpenable(); //Fixme for ABCs
|
|
if (!scopeAs3.containsKey(s)) {
|
|
scopeAs3.put(s, new ArrayList<>());
|
|
}
|
|
scopeAs3.get(s).add(sp);
|
|
openablesUsed.add(s);
|
|
}
|
|
ASMSource as = null;
|
|
if (t instanceof ASMSource) {
|
|
as = (ASMSource) t;
|
|
} else if (t instanceof TagScript) {
|
|
TagScript ts = (TagScript) t;
|
|
if (ts.getTag() instanceof ASMSource) {
|
|
as = (ASMSource) ts.getTag();
|
|
}
|
|
}
|
|
if (as != null) {
|
|
SWF s = as.getSourceTag().getSwf();
|
|
String asId = null;
|
|
Map<String, ASMSource> allSources;
|
|
if (swfToAllASMSourceMap.containsKey(s)) {
|
|
allSources = swfToAllASMSourceMap.get(s);
|
|
} else {
|
|
allSources = s.getASMs(false);
|
|
swfToAllASMSourceMap.put(s, allSources);
|
|
}
|
|
for (String path : allSources.keySet()) {
|
|
if (allSources.get(path) == as) {
|
|
asId = path;
|
|
break;
|
|
}
|
|
}
|
|
if (!scopeAs12.containsKey(s)) {
|
|
scopeAs12.put(s, new LinkedHashMap<>());
|
|
}
|
|
scopeAs12.get(s).put(asId, as);
|
|
openablesUsed.add(s);
|
|
}
|
|
}
|
|
|
|
List<TreeItem> items = getSelected();
|
|
String selected;
|
|
|
|
if (scopeAs12.isEmpty() && scopeAs3.isEmpty()) {
|
|
selected = null;
|
|
} else if (items.size() == 1) {
|
|
selected = items.get(0).toString();
|
|
} else if (items.isEmpty()) {
|
|
selected = null;
|
|
} else {
|
|
selected = AppDialog.translateForDialog("scope.selection.items", SearchDialog.class).replace("%count%", "" + items.size());
|
|
}
|
|
|
|
SearchDialog searchDialog = new SearchDialog(getMainFrame().getWindow(), false, selected, useSelection, openable instanceof ABC);
|
|
if (searchInText != null) {
|
|
if (searchInText) {
|
|
searchDialog.searchInTextsRadioButton.setSelected(true);
|
|
} else {
|
|
searchDialog.searchInASRadioButton.setSelected(true);
|
|
}
|
|
}
|
|
|
|
if (searchDialog.showDialog() == AppDialog.OK_OPTION) {
|
|
final String txt = searchDialog.searchField.getText();
|
|
if (!txt.isEmpty()) {
|
|
|
|
if (searchDialog.getCurrentScope() == SearchDialog.SCOPE_CURRENT_FILE) {
|
|
scopeAs3.clear();
|
|
scopeAs12.clear();
|
|
if (swf.isAS3()) {
|
|
List<ScriptPack> packs = new ArrayList<>();
|
|
if (openable instanceof SWF) {
|
|
packs = ((SWF) openable).getAS3Packs();
|
|
} else {
|
|
ABC abc = (ABC) openable;
|
|
List<ABC> allAbcs = new ArrayList<>();
|
|
allAbcs.add(abc);
|
|
packs = abc.getScriptPacks(null, allAbcs);
|
|
}
|
|
scopeAs3.put(openable, packs);
|
|
} else {
|
|
scopeAs12.put((SWF) openable, swf.getASMs(false));
|
|
}
|
|
openablesUsed.clear();
|
|
openablesUsed.add(openable);
|
|
}
|
|
if (searchDialog.getCurrentScope() == SearchDialog.SCOPE_ALL_FILES) {
|
|
Set<Openable> allOpenables = getAllOpenablesAndSwfs();
|
|
|
|
for (Openable s : allOpenables) {
|
|
SWF ss = (s instanceof SWF) ? (SWF) s : ((ABC) s).getSwf();
|
|
if (ss.isAS3()) {
|
|
List<ScriptPack> packs = new ArrayList<>();
|
|
if (s instanceof SWF) {
|
|
packs = ((SWF) s).getAS3Packs();
|
|
} else {
|
|
ABC abc = (ABC) s;
|
|
List<ABC> allAbcs = new ArrayList<>();
|
|
allAbcs.add(abc);
|
|
packs = abc.getScriptPacks(null, allAbcs);
|
|
}
|
|
scopeAs3.put(s, packs);
|
|
} else {
|
|
scopeAs12.put(ss, ss.getASMs(false));
|
|
}
|
|
}
|
|
openablesUsed.clear();
|
|
openablesUsed.addAll(allOpenables);
|
|
}
|
|
|
|
if (!scopeAs3.isEmpty()) {
|
|
getABCPanel();
|
|
}
|
|
if (!scopeAs12.isEmpty()) {
|
|
getActionPanel();
|
|
}
|
|
|
|
boolean ignoreCase = searchDialog.ignoreCaseCheckBox.isSelected();
|
|
boolean regexp = searchDialog.regexpCheckBox.isSelected();
|
|
|
|
boolean scriptSearch = searchDialog.searchInASRadioButton.isSelected()
|
|
|| searchDialog.searchInPCodeRadioButton.isSelected();
|
|
if (scriptSearch) {
|
|
boolean pCodeSearch = searchDialog.searchInPCodeRadioButton.isSelected();
|
|
new CancellableWorker<Void>() {
|
|
@Override
|
|
protected Void doInBackground() throws Exception {
|
|
|
|
List<ScriptSearchResult> fResult = new ArrayList<>();
|
|
for (Openable s : openablesUsed) {
|
|
if (scopeAs3.containsKey(s)) {
|
|
List<ABCSearchResult> abcResult = getABCPanel().search(s, txt, ignoreCase, regexp, pCodeSearch, this, scopeAs3.get(s));
|
|
fResult.addAll(abcResult);
|
|
if (!abcResult.isEmpty()) {
|
|
Main.searchResultsStorage.addABCResults(s, txt, ignoreCase, regexp, abcResult);
|
|
}
|
|
}
|
|
if (scopeAs12.containsKey(s)) {
|
|
List<ActionSearchResult> actionResult = getActionPanel().search((SWF) s, txt, ignoreCase, regexp, pCodeSearch, this, scopeAs12.get(s));
|
|
fResult.addAll(actionResult);
|
|
if (!actionResult.isEmpty()) {
|
|
Main.searchResultsStorage.addActionResults((SWF) s, txt, ignoreCase, regexp, actionResult);
|
|
}
|
|
}
|
|
}
|
|
Main.searchResultsStorage.finishGroup();
|
|
|
|
View.execInEventDispatch(() -> {
|
|
boolean found = false;
|
|
found = true;
|
|
List<SearchListener<ScriptSearchResult>> listeners = new ArrayList<>();
|
|
listeners.add(getABCPanel());
|
|
listeners.add(getActionPanel());
|
|
SearchResultsDialog<ScriptSearchResult> sr = new SearchResultsDialog<>(getMainFrame().getWindow(), txt, ignoreCase, regexp, listeners);
|
|
sr.setResults(fResult);
|
|
sr.setVisible(true);
|
|
searchResultsDialogs.add(sr);
|
|
if (!found) {
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("message.search.notfound").replace("%searchtext%", txt), translate("message.search.notfound.title"), JOptionPane.INFORMATION_MESSAGE);
|
|
}
|
|
|
|
Main.stopWork();
|
|
});
|
|
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
protected void done() {
|
|
View.execInEventDispatch(() -> {
|
|
Main.stopWork();
|
|
});
|
|
|
|
}
|
|
|
|
}.execute();
|
|
} else if (searchDialog.searchInTextsRadioButton.isSelected()) {
|
|
new CancellableWorker<Void>() {
|
|
@Override
|
|
protected Void doInBackground() throws Exception {
|
|
List<TextTag> textResult;
|
|
SearchPanel<TextTag> textSearchPanel = previewPanel.getTextPanel().getSearchPanel();
|
|
textSearchPanel.setOptions(ignoreCase, regexp);
|
|
textResult = searchText(txt, ignoreCase, regexp, swf);
|
|
|
|
List<TextTag> fTextResult = textResult;
|
|
View.execInEventDispatch(() -> {
|
|
textSearchPanel.setSearchText(txt);
|
|
boolean found = textSearchPanel.setResults(fTextResult);
|
|
if (!found) {
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("message.search.notfound").replace("%searchtext%", txt), translate("message.search.notfound.title"), JOptionPane.INFORMATION_MESSAGE);
|
|
}
|
|
|
|
Main.stopWork();
|
|
});
|
|
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
protected void done() {
|
|
View.execInEventDispatch(() -> {
|
|
Main.stopWork();
|
|
});
|
|
|
|
}
|
|
}.execute();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void replaceText() {
|
|
SearchDialog replaceDialog = new SearchDialog(getMainFrame().getWindow(), true, null, false, false);
|
|
if (replaceDialog.showDialog() == AppDialog.OK_OPTION) {
|
|
final String txt = replaceDialog.searchField.getText();
|
|
if (!txt.isEmpty()) {
|
|
final SWF swf = getCurrentSwf();
|
|
|
|
new CancellableWorker() {
|
|
@Override
|
|
protected Void doInBackground() throws Exception {
|
|
int findCount = 0;
|
|
boolean ignoreCase = replaceDialog.ignoreCaseCheckBox.isSelected();
|
|
boolean regexp = replaceDialog.regexpCheckBox.isSelected();
|
|
String replacement = replaceDialog.replaceField.getText();
|
|
if (!regexp) {
|
|
replacement = Matcher.quoteReplacement(replacement);
|
|
}
|
|
Pattern pat;
|
|
if (regexp) {
|
|
pat = Pattern.compile(txt, ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0);
|
|
} else {
|
|
pat = Pattern.compile(Pattern.quote(txt), ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0);
|
|
}
|
|
List<TextTag> textTags = new ArrayList<>();
|
|
for (Tag tag : swf.getTags()) {
|
|
if (tag instanceof TextTag) {
|
|
textTags.add((TextTag) tag);
|
|
}
|
|
}
|
|
for (TextTag textTag : textTags) {
|
|
if (!replaceDialog.replaceInParametersCheckBox.isSelected()) {
|
|
List<String> texts = textTag.getTexts();
|
|
boolean found = false;
|
|
for (int i = 0; i < texts.size(); i++) {
|
|
String text = texts.get(i);
|
|
if (pat.matcher(text).find()) {
|
|
texts.set(i, text.replaceAll(txt, replacement));
|
|
found = true;
|
|
findCount++;
|
|
}
|
|
}
|
|
if (found) {
|
|
String[] textArray = texts.toArray(new String[texts.size()]);
|
|
textTag.setFormattedText(getMissingCharacterHandler(), textTag.getFormattedText(false).text, textArray);
|
|
}
|
|
} else {
|
|
String text = textTag.getFormattedText(false).text;
|
|
if (pat.matcher(text).find()) {
|
|
textTag.setFormattedText(getMissingCharacterHandler(), text.replaceAll(txt, replacement), null);
|
|
findCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (findCount > 0) {
|
|
swf.clearImageCache();
|
|
repaintTree();
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}.execute();
|
|
}
|
|
}
|
|
}
|
|
|
|
private List<TextTag> searchText(String txt, boolean ignoreCase, boolean regexp, SWF swf) {
|
|
if (txt != null && !txt.isEmpty()) {
|
|
List<TextTag> found = new ArrayList<>();
|
|
Pattern pat;
|
|
if (regexp) {
|
|
pat = Pattern.compile(txt, ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0);
|
|
} else {
|
|
pat = Pattern.compile(Pattern.quote(txt), ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0);
|
|
}
|
|
for (Tag tag : swf.getTags()) {
|
|
if (tag instanceof TextTag) {
|
|
TextTag textTag = (TextTag) tag;
|
|
if (pat.matcher(textTag.getFormattedText(false).text).find()) {
|
|
found.add(textTag);
|
|
}
|
|
}
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public void updateSearchPos(String searchedText, boolean ignoreCase, boolean regExp, TextTag item) {
|
|
View.checkAccess();
|
|
|
|
setTagTreeSelectedNode(getCurrentTree(), item);
|
|
previewPanel.getTextPanel().updateSearchPos();
|
|
}
|
|
|
|
private void setDumpTreeSelectedNode(DumpInfo dumpInfo) {
|
|
DumpTreeModel dtm = (DumpTreeModel) dumpTree.getModel();
|
|
TreePath tp = dtm.getDumpInfoPath(dumpInfo);
|
|
if (tp != null) {
|
|
dumpTree.setSelectionPath(tp);
|
|
dumpTree.scrollPathToVisible(tp);
|
|
} else {
|
|
showCard(CARDEMPTYPANEL);
|
|
}
|
|
}
|
|
|
|
public void setTagTreeSelectedNode(AbstractTagTree tree, TreeItem treeItem) {
|
|
AbstractTagTreeModel ttm = tree.getFullModel();
|
|
TreePath tp = ttm.getTreePath(treeItem);
|
|
if (tp != null) {
|
|
tree.setSelectionPath(tp);
|
|
tree.scrollPathToVisible(tp);
|
|
} else {
|
|
showCard(CARDEMPTYPANEL);
|
|
}
|
|
}
|
|
|
|
public void autoDeobfuscateChanged() {
|
|
Helper.decompilationErrorAdd = AppStrings.translate(Configuration.autoDeobfuscate.get() ? "deobfuscation.comment.failed" : "deobfuscation.comment.tryenable");
|
|
clearAllScriptCache();
|
|
if (abcPanel != null) {
|
|
abcPanel.reload();
|
|
}
|
|
reload(true);
|
|
updateClassesList();
|
|
}
|
|
|
|
public void renameColliding(final Openable openable) {
|
|
View.checkAccess();
|
|
|
|
SWF swf = null;
|
|
if (openable instanceof SWF) {
|
|
swf = (SWF) openable;
|
|
}
|
|
//FIXME for ABCs
|
|
|
|
if (swf == null) {
|
|
return;
|
|
}
|
|
final SWF fswf = swf;
|
|
if (confirmExperimental()) {
|
|
new CancellableWorker<Integer>() {
|
|
@Override
|
|
protected Integer doInBackground() throws Exception {
|
|
AbcMultiNameCollisionFixer fixer = new AbcMultiNameCollisionFixer();
|
|
return fixer.fixCollisions(fswf);
|
|
}
|
|
|
|
@Override
|
|
protected void onStart() {
|
|
Main.startWork(translate("work.renaming.identifiers") + "...", this);
|
|
}
|
|
|
|
@Override
|
|
protected void done() {
|
|
View.execInEventDispatch(() -> {
|
|
try {
|
|
int cnt = get();
|
|
Main.stopWork();
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("message.rename.renamed").replace("%count%", Integer.toString(cnt)));
|
|
fswf.assignClassesToSymbols();
|
|
fswf.clearScriptCache();
|
|
if (abcPanel != null) {
|
|
abcPanel.reload();
|
|
}
|
|
updateClassesList();
|
|
reload(true);
|
|
} catch (Exception ex) {
|
|
logger.log(Level.SEVERE, "Error during renaming identifiers", ex);
|
|
Main.stopWork();
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("error.occured").replace("%error%", ex.getClass().getSimpleName()));
|
|
}
|
|
});
|
|
}
|
|
}.execute();
|
|
}
|
|
}
|
|
|
|
public void renameOneIdentifier(final SWF swf) {
|
|
View.checkAccess();
|
|
|
|
if (swf == null) {
|
|
return;
|
|
}
|
|
|
|
FileAttributesTag fileAttributes = swf.getFileAttributes();
|
|
if (fileAttributes != null && fileAttributes.actionScript3) {
|
|
final int multiName = getABCPanel().decompiledTextArea.getMultinameUnderCaret(new Reference<ABC>(null));
|
|
final List<ABCContainerTag> abcList = swf.getAbcList();
|
|
if (multiName > 0) {
|
|
new CancellableWorker() {
|
|
@Override
|
|
public Void doInBackground() throws Exception {
|
|
renameMultiname(abcList, multiName);
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
protected void onStart() {
|
|
Main.startWork(translate("work.renaming") + "...", this);
|
|
}
|
|
|
|
@Override
|
|
protected void done() {
|
|
Main.stopWork();
|
|
}
|
|
}.execute();
|
|
|
|
} else {
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("message.rename.notfound.multiname"), translate("message.rename.notfound.title"), JOptionPane.INFORMATION_MESSAGE);
|
|
}
|
|
} else {
|
|
final String identifier = getActionPanel().getStringUnderCursor();
|
|
if (identifier != null) {
|
|
new CancellableWorker() {
|
|
@Override
|
|
public Void doInBackground() throws Exception {
|
|
try {
|
|
renameIdentifier(swf, identifier);
|
|
} catch (InterruptedException ex) {
|
|
logger.log(Level.SEVERE, null, ex);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
protected void onStart() {
|
|
Main.startWork(translate("work.renaming") + "...", this);
|
|
}
|
|
|
|
@Override
|
|
protected void done() {
|
|
Main.stopWork();
|
|
}
|
|
}.execute();
|
|
} else {
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("message.rename.notfound.identifier"), translate("message.rename.notfound.title"), JOptionPane.INFORMATION_MESSAGE);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void exportFla(final SWF swf) {
|
|
if (swf == null) {
|
|
return;
|
|
}
|
|
JFileChooser fc = new JFileChooser();
|
|
String selDir = Configuration.lastOpenDir.get();
|
|
fc.setCurrentDirectory(new File(selDir));
|
|
if (!selDir.endsWith(File.separator)) {
|
|
selDir += File.separator;
|
|
}
|
|
String swfShortName = swf.getShortFileName();
|
|
if ("".equals(swfShortName)) {
|
|
swfShortName = "untitled.swf";
|
|
}
|
|
String fileName;
|
|
if (swfShortName.contains(".")) {
|
|
fileName = swfShortName.substring(0, swfShortName.lastIndexOf(".")) + ".fla";
|
|
} else {
|
|
fileName = swfShortName + ".fla";
|
|
}
|
|
final String fSwfShortName = swfShortName;
|
|
|
|
fc.setSelectedFile(new File(selDir + fileName));
|
|
List<FileFilter> flaFilters = new ArrayList<>();
|
|
List<FileFilter> xflFilters = new ArrayList<>();
|
|
List<FLAVersion> versions = new ArrayList<>();
|
|
boolean isAS3 = swf.isAS3();
|
|
for (int i = FLAVersion.values().length - 1; i >= 0; i--) {
|
|
final FLAVersion v = FLAVersion.values()[i];
|
|
if (!isAS3 && v.minASVersion() > 2) {
|
|
// This version does not support AS1/2
|
|
} else {
|
|
versions.add(v);
|
|
FileFilter f = new FileFilter() {
|
|
@Override
|
|
public boolean accept(File f) {
|
|
return f.isDirectory() || (f.getName().toLowerCase(Locale.ENGLISH).endsWith(".fla"));
|
|
}
|
|
|
|
@Override
|
|
public String getDescription() {
|
|
return translate("filter.fla").replace("%version%", v.applicationName());
|
|
}
|
|
};
|
|
if (v == FLAVersion.CS6) {
|
|
fc.setFileFilter(f);
|
|
} else {
|
|
fc.addChoosableFileFilter(f);
|
|
}
|
|
flaFilters.add(f);
|
|
f = new FileFilter() {
|
|
@Override
|
|
public boolean accept(File f) {
|
|
return f.isDirectory() || (f.getName().toLowerCase(Locale.ENGLISH).endsWith(".xfl"));
|
|
}
|
|
|
|
@Override
|
|
public String getDescription() {
|
|
return translate("filter.xfl").replace("%version%", v.applicationName());
|
|
}
|
|
};
|
|
fc.addChoosableFileFilter(f);
|
|
xflFilters.add(f);
|
|
}
|
|
}
|
|
|
|
fc.setAcceptAllFileFilterUsed(false);
|
|
if (fc.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
|
|
Configuration.lastOpenDir.set(Helper.fixDialogFile(fc.getSelectedFile()).getParentFile().getAbsolutePath());
|
|
File sf = Helper.fixDialogFile(fc.getSelectedFile());
|
|
|
|
FileFilter selectedFilter = fc.getFileFilter();
|
|
final boolean compressed = flaFilters.contains(selectedFilter);
|
|
String path = sf.getAbsolutePath();
|
|
if (path.endsWith(".fla") || path.endsWith(".xfl")) {
|
|
path = path.substring(0, path.length() - 4);
|
|
}
|
|
path += compressed ? ".fla" : ".xfl";
|
|
final FLAVersion selectedVersion = versions.get(compressed ? flaFilters.indexOf(selectedFilter) : xflFilters.indexOf(selectedFilter));
|
|
final File selfile = new File(path);
|
|
new CancellableWorker() {
|
|
@Override
|
|
protected Void doInBackground() throws Exception {
|
|
Helper.freeMem();
|
|
try {
|
|
AbortRetryIgnoreHandler errorHandler = new GuiAbortRetryIgnoreHandler();
|
|
if (compressed) {
|
|
swf.exportFla(errorHandler, selfile.getAbsolutePath(), fSwfShortName, ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), selectedVersion);
|
|
} else {
|
|
swf.exportXfl(errorHandler, selfile.getAbsolutePath(), fSwfShortName, ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), selectedVersion);
|
|
}
|
|
} catch (Exception ex) {
|
|
logger.log(Level.SEVERE, "FLA export error", ex);
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("error.export") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage(), translate("error"), JOptionPane.ERROR_MESSAGE);
|
|
}
|
|
Helper.freeMem();
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
protected void onStart() {
|
|
Main.startWork(translate("work.exporting.fla") + "...", this);
|
|
}
|
|
|
|
@Override
|
|
protected void done() {
|
|
if (Configuration.openFolderAfterFlaExport.get()) {
|
|
try {
|
|
Desktop.getDesktop().open(selfile.getAbsoluteFile().getParentFile());
|
|
} catch (IOException ex) {
|
|
logger.log(Level.SEVERE, null, ex);
|
|
}
|
|
}
|
|
|
|
Main.stopWork();
|
|
}
|
|
}.execute();
|
|
}
|
|
}
|
|
|
|
public void importMovie(final SWF swf) {
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importMovies2"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportMovieInfo);
|
|
JFileChooser chooser = new JFileChooser();
|
|
chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get()));
|
|
chooser.setDialogTitle(translate("import.select.directory"));
|
|
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
|
chooser.setAcceptAllFileFilterUsed(false);
|
|
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
|
|
|
|
previewPanel.clear();
|
|
|
|
String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath();
|
|
File moviesDir = new File(Path.combine(selFile, MovieExportSettings.EXPORT_FOLDER_NAME));
|
|
if (!moviesDir.exists()) {
|
|
moviesDir = new File(selFile);
|
|
}
|
|
final File fMoviesDir = moviesDir;
|
|
MovieImporter movieImporter = new MovieImporter();
|
|
|
|
final long timeBefore = System.currentTimeMillis();
|
|
new CancellableWorker<Void>() {
|
|
|
|
private int count = 0;
|
|
|
|
@Override
|
|
public Void doInBackground() throws Exception {
|
|
try {
|
|
count = movieImporter.bulkImport(fMoviesDir, swf, false);
|
|
} catch (Exception ex) {
|
|
logger.log(Level.SEVERE, "Error during import", ex);
|
|
ViewMessages.showMessageDialog(null, translate("error.import") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage());
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
protected void onStart() {
|
|
Main.startWork(translate("work.importing") + "...", this);
|
|
}
|
|
|
|
@Override
|
|
protected void done() {
|
|
Main.stopWork();
|
|
long timeAfter = System.currentTimeMillis();
|
|
final long timeMs = timeAfter - timeBefore;
|
|
|
|
View.execInEventDispatch(() -> {
|
|
refreshTree(swf);
|
|
setStatus(translate("import.finishedin").replace("%time%", Helper.formatTimeSec(timeMs)));
|
|
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("import.movie.result").replace("%count%", Integer.toString(count)));
|
|
if (count != 0) {
|
|
reload(true);
|
|
}
|
|
});
|
|
}
|
|
}.execute();
|
|
}
|
|
}
|
|
|
|
public void importSound(final SWF swf) {
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importSounds2"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportSoundInfo);
|
|
JFileChooser chooser = new JFileChooser();
|
|
chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get()));
|
|
chooser.setDialogTitle(translate("import.select.directory"));
|
|
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
|
chooser.setAcceptAllFileFilterUsed(false);
|
|
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
|
|
|
|
previewPanel.clear();
|
|
|
|
String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath();
|
|
File soundsDir = new File(Path.combine(selFile, SoundExportSettings.EXPORT_FOLDER_NAME));
|
|
if (!soundsDir.exists()) {
|
|
soundsDir = new File(selFile);
|
|
}
|
|
final File fSoundsDir = soundsDir;
|
|
SoundImporter soundImporter = new SoundImporter();
|
|
|
|
final long timeBefore = System.currentTimeMillis();
|
|
new CancellableWorker<Void>() {
|
|
|
|
private int count = 0;
|
|
|
|
@Override
|
|
public Void doInBackground() throws Exception {
|
|
try {
|
|
count = soundImporter.bulkImport(fSoundsDir, swf, false);
|
|
} catch (Exception ex) {
|
|
logger.log(Level.SEVERE, "Error during import", ex);
|
|
ViewMessages.showMessageDialog(null, translate("error.import") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage());
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
protected void onStart() {
|
|
Main.startWork(translate("work.importing") + "...", this);
|
|
}
|
|
|
|
@Override
|
|
protected void done() {
|
|
Main.stopWork();
|
|
long timeAfter = System.currentTimeMillis();
|
|
final long timeMs = timeAfter - timeBefore;
|
|
|
|
View.execInEventDispatch(() -> {
|
|
refreshTree(swf);
|
|
setStatus(translate("import.finishedin").replace("%time%", Helper.formatTimeSec(timeMs)));
|
|
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("import.sound.result").replace("%count%", Integer.toString(count)));
|
|
if (count != 0) {
|
|
reload(true);
|
|
}
|
|
});
|
|
}
|
|
}.execute();
|
|
}
|
|
}
|
|
public void importShape(final SWF swf, boolean noFill) {
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importShapes2"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportShapeInfo);
|
|
JFileChooser chooser = new JFileChooser();
|
|
chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get()));
|
|
chooser.setDialogTitle(translate("import.select.directory"));
|
|
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
|
chooser.setAcceptAllFileFilterUsed(false);
|
|
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
|
|
String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath();
|
|
File shapesDir = new File(Path.combine(selFile, ShapeExportSettings.EXPORT_FOLDER_NAME));
|
|
if (!shapesDir.exists()) {
|
|
shapesDir = new File(selFile);
|
|
}
|
|
final File fShapesDir = shapesDir;
|
|
ShapeImporter shapeImporter = new ShapeImporter();
|
|
SvgImporter svgImporter = new SvgImporter();
|
|
|
|
final long timeBefore = System.currentTimeMillis();
|
|
new CancellableWorker<Void>() {
|
|
|
|
private int count = 0;
|
|
|
|
@Override
|
|
public Void doInBackground() throws Exception {
|
|
try {
|
|
count = shapeImporter.bulkImport(fShapesDir, swf, noFill, false);
|
|
swf.clearImageCache();
|
|
swf.clearShapeCache();
|
|
} catch (Exception ex) {
|
|
logger.log(Level.SEVERE, "Error during import", ex);
|
|
ViewMessages.showMessageDialog(null, translate("error.import") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage());
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
protected void onStart() {
|
|
Main.startWork(translate("work.importing") + "...", this);
|
|
}
|
|
|
|
@Override
|
|
protected void done() {
|
|
Main.stopWork();
|
|
long timeAfter = System.currentTimeMillis();
|
|
final long timeMs = timeAfter - timeBefore;
|
|
|
|
View.execInEventDispatch(() -> {
|
|
refreshTree(swf);
|
|
setStatus(translate("import.finishedin").replace("%time%", Helper.formatTimeSec(timeMs)));
|
|
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("import.shape.result").replace("%count%", Integer.toString(count)));
|
|
if (count != 0) {
|
|
reload(true);
|
|
}
|
|
});
|
|
}
|
|
}.execute();
|
|
}
|
|
}
|
|
|
|
public void importImage(final SWF swf) {
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importImages2"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportImageInfo);
|
|
JFileChooser chooser = new JFileChooser();
|
|
chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get()));
|
|
chooser.setDialogTitle(translate("import.select.directory"));
|
|
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
|
chooser.setAcceptAllFileFilterUsed(false);
|
|
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
|
|
String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath();
|
|
File imagesDir = new File(Path.combine(selFile, ImageExportSettings.EXPORT_FOLDER_NAME));
|
|
if (!imagesDir.exists()) {
|
|
imagesDir = new File(selFile);
|
|
}
|
|
final File fImagesDir = imagesDir;
|
|
ImageImporter imageImporter = new ImageImporter();
|
|
|
|
final long timeBefore = System.currentTimeMillis();
|
|
new CancellableWorker<Void>() {
|
|
|
|
private int count = 0;
|
|
|
|
@Override
|
|
public Void doInBackground() throws Exception {
|
|
try {
|
|
count = imageImporter.bulkImport(fImagesDir, swf, false);
|
|
swf.clearImageCache();
|
|
} catch (Exception ex) {
|
|
logger.log(Level.SEVERE, "Error during import", ex);
|
|
ViewMessages.showMessageDialog(null, translate("error.import") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage());
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
protected void onStart() {
|
|
Main.startWork(translate("work.importing") + "...", this);
|
|
}
|
|
|
|
@Override
|
|
protected void done() {
|
|
Main.stopWork();
|
|
long timeAfter = System.currentTimeMillis();
|
|
final long timeMs = timeAfter - timeBefore;
|
|
|
|
View.execInEventDispatch(() -> {
|
|
refreshTree(swf);
|
|
setStatus(translate("import.finishedin").replace("%time%", Helper.formatTimeSec(timeMs)));
|
|
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("import.image.result").replace("%count%", Integer.toString(count)));
|
|
if (count != 0) {
|
|
reload(true);
|
|
}
|
|
});
|
|
}
|
|
}.execute();
|
|
}
|
|
}
|
|
|
|
public void importText(final SWF swf) {
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importTexts2"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportTextInfo);
|
|
JFileChooser chooser = new JFileChooser();
|
|
chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get()));
|
|
chooser.setDialogTitle(translate("import.select.directory"));
|
|
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
|
chooser.setAcceptAllFileFilterUsed(false);
|
|
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
|
|
String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath();
|
|
boolean textsFolderExists = new File(Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME)).exists();
|
|
File textsFile = new File(Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME, TextExporter.TEXT_EXPORT_FILENAME_FORMATTED));
|
|
if (!textsFolderExists) {
|
|
textsFile = new File(Path.combine(selFile, TextExporter.TEXT_EXPORT_FILENAME_FORMATTED));
|
|
}
|
|
TextImporter textImporter = new TextImporter(getMissingCharacterHandler(), new TextImportErrorHandler() {
|
|
// "configuration items" for the current replace only
|
|
private final ConfigurationItem<Boolean> showAgainImportError = new ConfigurationItem<>("showAgainImportError", true, true);
|
|
|
|
private final ConfigurationItem<Boolean> showAgainInvalidText = new ConfigurationItem<>("showAgainInvalidText", true, true);
|
|
|
|
private String getTextTagInfo(TextTag textTag) {
|
|
StringBuilder ret = new StringBuilder();
|
|
if (textTag != null) {
|
|
ret.append(" TextId: ").append(textTag.getCharacterId()).append(" (").append(String.join(", ", textTag.getTexts())).append(")");
|
|
}
|
|
|
|
return ret.toString();
|
|
}
|
|
|
|
@Override
|
|
public boolean handle(TextTag textTag) {
|
|
String msg = translate("error.text.import");
|
|
logger.log(Level.SEVERE, "{0}{1}", new Object[]{msg, getTextTagInfo(textTag)});
|
|
return ViewMessages.showConfirmDialog(MainPanel.this, msg, translate("error"), JOptionPane.OK_CANCEL_OPTION, showAgainImportError, JOptionPane.OK_OPTION) != JOptionPane.OK_OPTION;
|
|
}
|
|
|
|
@Override
|
|
public boolean handle(TextTag textTag, String message, long line) {
|
|
String msg = translate("error.text.invalid.continue").replace("%text%", message).replace("%line%", Long.toString(line));
|
|
logger.log(Level.SEVERE, "{0}{1}", new Object[]{msg, getTextTagInfo(textTag)});
|
|
return ViewMessages.showConfirmDialog(MainPanel.this, msg, translate("error"), JOptionPane.OK_CANCEL_OPTION, showAgainInvalidText, JOptionPane.OK_OPTION) != JOptionPane.OK_OPTION;
|
|
}
|
|
});
|
|
|
|
// try to import formatted texts
|
|
if (textsFile.exists()) {
|
|
textImporter.importTextsSingleFileFormatted(textsFile, swf);
|
|
} else {
|
|
textsFile = new File(Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME, TextExporter.TEXT_EXPORT_FILENAME_PLAIN));
|
|
if (!textsFolderExists) {
|
|
textsFile = new File(Path.combine(selFile, TextExporter.TEXT_EXPORT_FILENAME_PLAIN));
|
|
}
|
|
// try to import plain texts
|
|
if (textsFile.exists()) {
|
|
textImporter.importTextsSingleFile(textsFile, swf);
|
|
} else {
|
|
textImporter.importTextsMultipleFiles(selFile, swf);
|
|
}
|
|
}
|
|
|
|
swf.clearImageCache();
|
|
reload(true);
|
|
updateMissingNeededCharacters();
|
|
}
|
|
}
|
|
|
|
public As3ScriptReplacerInterface getAs3ScriptReplacer(boolean air) {
|
|
As3ScriptReplacerInterface r = As3ScriptReplacerFactory.createByConfig(air);
|
|
if (!r.isAvailable()) {
|
|
if (r instanceof MxmlcAs3ScriptReplacer) {
|
|
if (ViewMessages.showConfirmDialog(this, AppStrings.translate("message.flexpath.notset"), AppStrings.translate("error"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) {
|
|
Main.advancedSettings("paths");
|
|
}
|
|
} else if (r instanceof FFDecAs3ScriptReplacer) {
|
|
FFDecAs3ScriptReplacer fr = (FFDecAs3ScriptReplacer) r;
|
|
if (fr.isAir()) {
|
|
if (ViewMessages.showConfirmDialog(this, AppStrings.translate("message.airpath.lib.notset"), AppStrings.translate("message.action.airglobal.title"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) {
|
|
Main.advancedSettings("paths");
|
|
}
|
|
} else {
|
|
if (ViewMessages.showConfirmDialog(this, AppStrings.translate("message.playerpath.lib.notset"), AppStrings.translate("message.action.playerglobal.title"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) {
|
|
Main.advancedSettings("paths");
|
|
}
|
|
}
|
|
} else {
|
|
//Not translated yet - just in case there are more Script replacers in the future. Unused now.
|
|
ViewMessages.showConfirmDialog(this, "Current script replacer is not available", "Script replacer not available", JOptionPane.OK_OPTION, JOptionPane.ERROR_MESSAGE);
|
|
}
|
|
return null;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
public void importScript(final Openable openable) {
|
|
As3ScriptReplacerInterface as3ScriptReplacer = getAs3ScriptReplacer(Main.isSwfAir(openable));
|
|
if (as3ScriptReplacer == null) {
|
|
return;
|
|
}
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importScripts2"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportScriptsInfo);
|
|
|
|
JFileChooser chooser = new JFileChooser();
|
|
chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get()));
|
|
chooser.setDialogTitle(translate("import.select.directory"));
|
|
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
|
chooser.setAcceptAllFileFilterUsed(false);
|
|
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
|
|
String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath();
|
|
String scriptsFolder = Path.combine(selFile, ScriptExportSettings.EXPORT_FOLDER_NAME);
|
|
if (!new File(scriptsFolder).exists()) {
|
|
scriptsFolder = selFile;
|
|
}
|
|
final String fScriptsFolder = scriptsFolder;
|
|
final long timeBefore = System.currentTimeMillis();
|
|
new CancellableWorker<Void>() {
|
|
private int countAs2 = 0;
|
|
private int countAs3 = 0;
|
|
|
|
@Override
|
|
public Void doInBackground() throws Exception {
|
|
|
|
SWF swf = (openable instanceof SWF) ? (SWF) openable : ((ABC) openable).getSwf();
|
|
|
|
new AS2ScriptImporter().importScripts(fScriptsFolder, swf.getASMs(true), new ScriptImporterProgressListener() {
|
|
@Override
|
|
public void scriptImported() {
|
|
countAs2++;
|
|
}
|
|
});
|
|
|
|
List<ScriptPack> packs;
|
|
if (openable instanceof SWF) {
|
|
packs = swf.getAS3Packs();
|
|
} else {
|
|
List<ABC> allAbcs = new ArrayList<>();
|
|
ABC abc = (ABC) openable;
|
|
allAbcs.add(abc);
|
|
packs = abc.getScriptPacks(null, allAbcs);
|
|
}
|
|
|
|
new AS3ScriptImporter().importScripts(as3ScriptReplacer, fScriptsFolder, packs, new ScriptImporterProgressListener() {
|
|
@Override
|
|
public void scriptImported() {
|
|
countAs3++;
|
|
}
|
|
}
|
|
);
|
|
|
|
if (countAs3 > 0) {
|
|
updateClassesList();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
protected void onStart() {
|
|
Main.importWorker = this;
|
|
Main.startWork(translate("work.importing_as") + "...", this);
|
|
}
|
|
|
|
@Override
|
|
protected void done() {
|
|
Main.stopWork();
|
|
long timeAfter = System.currentTimeMillis();
|
|
final long timeMs = timeAfter - timeBefore;
|
|
|
|
Main.importWorker = null;
|
|
View.execInEventDispatch(() -> {
|
|
setStatus(translate("importing_as.finishedin").replace("%time%", Helper.formatTimeSec(timeMs)));
|
|
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("import.script.result").replace("%count%", Integer.toString(countAs2 + countAs3)));
|
|
if (countAs2 != 0 || countAs3 != 0) {
|
|
reload(true);
|
|
updateMissingNeededCharacters();
|
|
}
|
|
});
|
|
}
|
|
}.execute();
|
|
|
|
}
|
|
}
|
|
|
|
public void importSymbolClass(final SWF swf) {
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importSymbolClass").replace("%file%", SymbolClassExporter.SYMBOL_CLASS_EXPORT_FILENAME), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportSymbolClassInfo);
|
|
|
|
JFileChooser chooser = new JFileChooser();
|
|
chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get()));
|
|
chooser.setDialogTitle(translate("import.select.directory"));
|
|
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
|
chooser.setAcceptAllFileFilterUsed(false);
|
|
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
|
|
String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath();
|
|
File importFile = new File(Path.combine(selFile, SymbolClassExporter.SYMBOL_CLASS_EXPORT_FILENAME));
|
|
SymbolClassImporter importer = new SymbolClassImporter();
|
|
|
|
if (importFile.exists()) {
|
|
importer.importSymbolClasses(importFile, swf);
|
|
}
|
|
}
|
|
}
|
|
|
|
private String selectExportDir() {
|
|
JFileChooser chooser = new JFileChooser();
|
|
chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get()));
|
|
chooser.setDialogTitle(translate("export.select.directory"));
|
|
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
|
chooser.setAcceptAllFileFilterUsed(false);
|
|
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
|
|
final String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath();
|
|
Configuration.lastExportDir.set(Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath());
|
|
return selFile;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void export(final boolean onlySel, List<TreeItem> selected) {
|
|
View.checkAccess();
|
|
|
|
final SWF swf = getCurrentSwf();
|
|
List<TreeItem> sel = getCurrentTree().getAllSubsForItems(selected);
|
|
if (!onlySel) {
|
|
sel = null;
|
|
} else if (sel.isEmpty()) {
|
|
return;
|
|
}
|
|
final ExportDialog export = new ExportDialog(Main.getDefaultDialogsOwner(), sel);
|
|
if (export.showExportDialog() == AppDialog.OK_OPTION) {
|
|
final String selFile = selectExportDir();
|
|
if (selFile != null) {
|
|
final long timeBefore = System.currentTimeMillis();
|
|
|
|
new CancellableWorker<Void>() {
|
|
@Override
|
|
public Void doInBackground() throws Exception {
|
|
try {
|
|
AbortRetryIgnoreHandler errorHandler = new GuiAbortRetryIgnoreHandler();
|
|
if (onlySel) {
|
|
exportSelection(selected, errorHandler, selFile, export);
|
|
} else {
|
|
exportAll(swf, errorHandler, selFile, export);
|
|
}
|
|
} catch (Exception ex) {
|
|
logger.log(Level.SEVERE, "Error during export", ex);
|
|
ViewMessages.showMessageDialog(null, translate("error.export") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage());
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
protected void onStart() {
|
|
Main.startWork(translate("work.exporting") + "...", this);
|
|
}
|
|
|
|
@Override
|
|
protected void done() {
|
|
Main.stopWork();
|
|
long timeAfter = System.currentTimeMillis();
|
|
final long timeMs = timeAfter - timeBefore;
|
|
|
|
View.execInEventDispatch(() -> {
|
|
setStatus(translate("export.finishedin").replace("%time%", Helper.formatTimeSec(timeMs)));
|
|
});
|
|
}
|
|
}.execute();
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
public void exportJavaSource(List<TreeItem> items) {
|
|
Set<SWF> swfs = new LinkedHashSet<>();
|
|
|
|
for (TreeItem item : items) {
|
|
if (item instanceof OpenableList) {
|
|
OpenableList list = (OpenableList) item;
|
|
for (Openable openable : list) {
|
|
if (openable instanceof SWF) {
|
|
swfs.add((SWF) openable);
|
|
}
|
|
}
|
|
} else {
|
|
Openable openable = item.getOpenable();
|
|
if (openable instanceof SWF) {
|
|
swfs.add((SWF) openable);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (SWF item : swfs) {
|
|
SWF swf = (SWF) item;
|
|
final String selFile = selectExportDir();
|
|
if (selFile != null) {
|
|
Main.startWork(translate("work.exporting") + "...", null);
|
|
|
|
try {
|
|
new SwfJavaExporter().exportJavaCode(swf, selFile);
|
|
Main.stopWork();
|
|
} catch (IOException ex) {
|
|
logger.log(Level.SEVERE, null, ex);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void exportSwfXml(List<TreeItem> items) {
|
|
View.checkAccess();
|
|
|
|
Set<SWF> swfs = new LinkedHashSet<>();
|
|
|
|
for (TreeItem item : items) {
|
|
if (item instanceof OpenableList) {
|
|
OpenableList list = (OpenableList) item;
|
|
for (Openable openable : list) {
|
|
if (openable instanceof SWF) {
|
|
swfs.add((SWF) openable);
|
|
}
|
|
}
|
|
} else {
|
|
Openable openable = item.getOpenable();
|
|
if (openable instanceof SWF) {
|
|
swfs.add((SWF) openable);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (SWF swf : swfs) {
|
|
final String selFile = selectExportDir();
|
|
if (selFile != null) {
|
|
Main.startWork(translate("work.exporting") + "...", null);
|
|
|
|
try {
|
|
File outFile = new File(selFile + File.separator + Helper.makeFileName("swf.xml"));
|
|
new SwfXmlExporter().exportXml(swf, outFile);
|
|
Main.stopWork();
|
|
} catch (IOException ex) {
|
|
logger.log(Level.SEVERE, null, ex);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void importSwfXml(List<TreeItem> items) {
|
|
View.checkAccess();
|
|
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importXml"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportXmlInfo);
|
|
|
|
Set<SWF> swfs = new LinkedHashSet<>();
|
|
|
|
for (TreeItem item : items) {
|
|
if (item instanceof OpenableList) {
|
|
OpenableList list = (OpenableList) item;
|
|
for (Openable openable : list) {
|
|
if (openable instanceof SWF) {
|
|
swfs.add((SWF) openable);
|
|
}
|
|
}
|
|
} else {
|
|
Openable openable = item.getOpenable();
|
|
if (openable instanceof SWF) {
|
|
swfs.add((SWF) openable);
|
|
}
|
|
}
|
|
}
|
|
if (swfs.size() > 1) {
|
|
return;
|
|
}
|
|
|
|
for (SWF swf : swfs) {
|
|
File selectedFile = showImportFileChooser("filter.xml|*.xml", false);
|
|
if (selectedFile != null) {
|
|
File selfile = Helper.fixDialogFile(selectedFile);
|
|
try {
|
|
try (FileInputStream fis = new FileInputStream(selfile)) {
|
|
new SwfXmlImporter().importSwf(swf, fis);
|
|
}
|
|
swf.clearAllCache();
|
|
swf.assignExportNamesToSymbols();
|
|
swf.assignClassesToSymbols();
|
|
refreshTree(swf);
|
|
} catch (IOException ex) {
|
|
logger.log(Level.SEVERE, null, ex);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void renameIdentifiers(final Openable openable) {
|
|
View.checkAccess();
|
|
|
|
SWF swf = null;
|
|
|
|
if (openable instanceof SWF) {
|
|
swf = (SWF) openable;
|
|
}
|
|
//FIXME for ABCs
|
|
|
|
if (swf == null) {
|
|
return;
|
|
}
|
|
|
|
final SWF fswf = swf;
|
|
if (confirmExperimental()) {
|
|
RenameDialog renameDialog = new RenameDialog(Main.getDefaultDialogsOwner());
|
|
if (renameDialog.showRenameDialog() == AppDialog.OK_OPTION) {
|
|
final RenameType renameType = renameDialog.getRenameType();
|
|
new CancellableWorker<Integer>() {
|
|
@Override
|
|
protected Integer doInBackground() throws Exception {
|
|
int cnt = fswf.deobfuscateIdentifiers(renameType);
|
|
return cnt;
|
|
}
|
|
|
|
@Override
|
|
protected void onStart() {
|
|
Main.startWork(translate("work.renaming.identifiers") + "...", this);
|
|
}
|
|
|
|
@Override
|
|
protected void done() {
|
|
View.execInEventDispatch(() -> {
|
|
try {
|
|
int cnt = get();
|
|
Main.stopWork();
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("message.rename.renamed").replace("%count%", Integer.toString(cnt)));
|
|
fswf.assignClassesToSymbols();
|
|
fswf.clearScriptCache();
|
|
if (abcPanel != null) {
|
|
abcPanel.reload();
|
|
}
|
|
updateClassesList();
|
|
reload(true);
|
|
} catch (Exception ex) {
|
|
logger.log(Level.SEVERE, "Error during renaming identifiers", ex);
|
|
Main.stopWork();
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("error.occured").replace("%error%", ex.getClass().getSimpleName()));
|
|
}
|
|
});
|
|
}
|
|
}.execute();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void deobfuscateMethod(Trait t, int scriptIndex, DeobfuscationLevel level, boolean isStatic, int methodIndex, ABC abc) throws InterruptedException {
|
|
if (methodIndex == -1) {
|
|
return;
|
|
}
|
|
MethodBody body = abc.findBody(methodIndex);
|
|
if (body != null) {
|
|
body.deobfuscate(level, t, scriptIndex, methodIndex, isStatic, "");
|
|
}
|
|
}
|
|
|
|
private void deobfuscateTraits(int scriptIndex, DeobfuscationLevel level, List<Trait> traits, ABC abc, boolean isStatic) throws InterruptedException {
|
|
for (Trait t : traits) {
|
|
int methodIndex = -1;
|
|
if (t instanceof TraitMethodGetterSetter) {
|
|
methodIndex = ((TraitMethodGetterSetter) t).method_info;
|
|
}
|
|
if (t instanceof TraitFunction) {
|
|
methodIndex = ((TraitFunction) t).method_info;
|
|
}
|
|
if (methodIndex != -1) {
|
|
deobfuscateMethod(t, scriptIndex, level, isStatic, methodIndex, abc);
|
|
}
|
|
if (t instanceof TraitClass) {
|
|
TraitClass tc = (TraitClass) t;
|
|
ClassInfo ci = abc.class_info.get(tc.class_info);
|
|
deobfuscateMethod(t, scriptIndex, level, true, ci.cinit_index, abc);
|
|
deobfuscateTraits(scriptIndex, level, ci.static_traits.traits, abc, true);
|
|
InstanceInfo ii = abc.instance_info.get(tc.class_info);
|
|
deobfuscateMethod(t, scriptIndex, level, false, ii.iinit_index, abc);
|
|
deobfuscateTraits(scriptIndex, level, ii.instance_traits.traits, abc, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void deobfuscate() {
|
|
View.checkAccess();
|
|
|
|
DeobfuscationDialog deobfuscationDialog = new DeobfuscationDialog(Main.getDefaultDialogsOwner());
|
|
if (deobfuscationDialog.showDialog() == AppDialog.OK_OPTION) {
|
|
DeobfuscationLevel level = deobfuscationDialog.getDeobfuscationLevel();
|
|
new CancellableWorker() {
|
|
@Override
|
|
protected Void doInBackground() throws Exception {
|
|
try {
|
|
ABCPanel abcPanel = getABCPanel();
|
|
DeobfuscationScope scope = deobfuscationDialog.getDeobfuscationScope();
|
|
if (scope == DeobfuscationScope.SWF) {
|
|
SWF swf = abcPanel.getSwf();
|
|
swf.deobfuscate(level);
|
|
} else if (scope == DeobfuscationScope.CLASS) {
|
|
ScriptPack pack = abcPanel.getPack();
|
|
if (pack == null) {
|
|
return null;
|
|
}
|
|
List<Trait> traits = pack.abc.script_info.get(pack.scriptIndex).traits.traits;
|
|
deobfuscateMethod(null, pack.scriptIndex, level, true, pack.abc.script_info.get(pack.scriptIndex).init_index, pack.abc);
|
|
deobfuscateTraits(pack.scriptIndex, level, traits, pack.abc, true);
|
|
} else {
|
|
int mi = abcPanel.detailPanel.methodTraitPanel.methodCodePanel.getMethodIndex();
|
|
int bi = abcPanel.detailPanel.methodTraitPanel.methodCodePanel.getBodyIndex();
|
|
DecompiledEditorPane decompiledTextArea = abcPanel.decompiledTextArea;
|
|
Trait t = abcPanel.decompiledTextArea.getCurrentTrait();
|
|
ABC abc = abcPanel.abc;
|
|
if (bi != -1) {
|
|
int scriptIndex = decompiledTextArea.getScriptLeaf().scriptIndex;
|
|
int classIndex = decompiledTextArea.getClassIndex();
|
|
boolean isStatic = decompiledTextArea.getIsStatic();
|
|
abc.bodies.get(bi).deobfuscate(level, t, scriptIndex, classIndex, isStatic, ""/*FIXME*/);
|
|
}
|
|
abcPanel.detailPanel.methodTraitPanel.methodCodePanel.setMethod(decompiledTextArea.getScriptLeaf().getPathScriptName(), mi, bi, abc, t, abcPanel.detailPanel.methodTraitPanel.methodCodePanel.getScriptIndex());
|
|
}
|
|
} catch (Exception ex) {
|
|
logger.log(Level.SEVERE, "Deobfuscation error", ex);
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("error.deobfuscation"), translate("error"), JOptionPane.ERROR_MESSAGE);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
protected void onStart() {
|
|
Main.deobfuscatePCodeWorker = this;
|
|
Main.startWork(translate("work.deobfuscating") + "...", this);
|
|
}
|
|
|
|
@Override
|
|
protected void done() {
|
|
Main.deobfuscatePCodeWorker = null;
|
|
View.execInEventDispatch(() -> {
|
|
Main.stopWork();
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("work.deobfuscating.complete"));
|
|
|
|
clearAllScriptCache();
|
|
getABCPanel().reload();
|
|
updateClassesList();
|
|
});
|
|
}
|
|
}.execute();
|
|
}
|
|
}
|
|
|
|
public void removeNonScripts(SWF swf) {
|
|
if (swf == null) {
|
|
return;
|
|
}
|
|
|
|
List<Tag> tags = swf.getTags().toArrayList();
|
|
List<Tag> toRemove = new ArrayList<>();
|
|
for (Tag tag : tags) {
|
|
System.out.println(tag.getClass());
|
|
if (!(tag instanceof ABCContainerTag || tag instanceof ASMSource)) {
|
|
toRemove.add(tag);
|
|
}
|
|
}
|
|
|
|
swf.removeTags(toRemove, true, null);
|
|
refreshTree(swf);
|
|
}
|
|
|
|
public void removeExceptSelected(SWF swf) {
|
|
if (swf == null) {
|
|
return;
|
|
}
|
|
|
|
List<TreeItem> sel = getAllSelected();
|
|
Set<Integer> needed = new HashSet<>();
|
|
for (TreeItem item : sel) {
|
|
if (item instanceof CharacterTag) {
|
|
CharacterTag characterTag = (CharacterTag) item;
|
|
characterTag.getNeededCharactersDeep(needed);
|
|
needed.add(characterTag.getCharacterId());
|
|
}
|
|
}
|
|
|
|
List<Tag> tagsToRemove = new ArrayList<>();
|
|
for (Tag tag : swf.getTags()) {
|
|
if (tag instanceof CharacterTag) {
|
|
CharacterTag characterTag = (CharacterTag) tag;
|
|
if (!needed.contains(characterTag.getCharacterId())) {
|
|
tagsToRemove.add(tag);
|
|
}
|
|
}
|
|
}
|
|
|
|
swf.removeTags(tagsToRemove, true, null);
|
|
refreshTree(swf);
|
|
}
|
|
|
|
private void clear() {
|
|
dumpViewPanel.clear();
|
|
previewPanel.clear();
|
|
headerPanel.clear();
|
|
folderPreviewPanel.clear();
|
|
folderListPanel.clear();
|
|
if (abcPanel != null) {
|
|
abcPanel.clearSwf();
|
|
}
|
|
if (actionPanel != null) {
|
|
actionPanel.clearSource();
|
|
}
|
|
}
|
|
|
|
public void refreshTree() {
|
|
refreshTree(new SWF[0]);
|
|
}
|
|
|
|
public void treeOperation(Runnable runnable) {
|
|
TreeItem treeItem = getCurrentTree().getCurrentTreeItem();
|
|
tagTree.clearSelection();
|
|
tagListTree.clearSelection();
|
|
runnable.run();
|
|
clear();
|
|
showCard(CARDEMPTYPANEL);
|
|
|
|
tagTree.updateSwfs(new SWF[0]);
|
|
tagListTree.updateSwfs(new SWF[0]);
|
|
|
|
if (treeItem != null) {
|
|
Openable openable = treeItem.getOpenable();
|
|
if (openable != null) {
|
|
if (openable instanceof SWF) {
|
|
SWF treeItemSwf = ((SWF) openable).getRootSwf();
|
|
if (this.openables.contains(treeItemSwf.openableList)) {
|
|
setTagTreeSelectedNode(getCurrentTree(), treeItem);
|
|
}
|
|
} else {
|
|
if (this.openables.contains(openable.getOpenableList())) {
|
|
setTagTreeSelectedNode(getCurrentTree(), treeItem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
reload(true);
|
|
pinsPanel.refresh();
|
|
}
|
|
|
|
public void refreshTree(Openable openable) {
|
|
refreshTree(new Openable[]{openable});
|
|
}
|
|
|
|
public void refreshTree(Openable[] openables) {
|
|
TreeItem treeItem = null;
|
|
if (currentView == VIEW_RESOURCES || currentView == VIEW_TAGLIST) {
|
|
treeItem = getCurrentTree().getCurrentTreeItem();
|
|
}
|
|
|
|
clear();
|
|
showCard(CARDEMPTYPANEL);
|
|
|
|
tagTree.updateSwfs(openables);
|
|
tagListTree.updateSwfs(openables);
|
|
|
|
if (treeItem != null) {
|
|
Openable openable = treeItem.getOpenable();
|
|
|
|
if (openable instanceof SWF) {
|
|
SWF swf = (SWF) openable;
|
|
SWF treeItemSwf = swf.getRootSwf();
|
|
if (this.openables.contains(treeItemSwf.openableList)) {
|
|
setTagTreeSelectedNode(getCurrentTree(), treeItem);
|
|
}
|
|
} else if (openable != null) {
|
|
if (this.openables.contains(openable.getOpenableList())) {
|
|
setTagTreeSelectedNode(getCurrentTree(), treeItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
reload(true);
|
|
updateMissingNeededCharacters();
|
|
pinsPanel.refresh();
|
|
}
|
|
|
|
public void refreshDecompiled() {
|
|
clearAllScriptCache();
|
|
if (abcPanel != null) {
|
|
abcPanel.reload();
|
|
}
|
|
|
|
reload(true);
|
|
updateClassesList();
|
|
}
|
|
|
|
private MissingCharacterHandler getMissingCharacterHandler() {
|
|
return new MissingCharacterHandler() {
|
|
// "configuration items" for the current replace only
|
|
private final ConfigurationItem<Boolean> showAgainIgnoreMissingCharacters = new ConfigurationItem<>("showAgainIgnoreMissingCharacters", true, true);
|
|
|
|
private boolean ignoreMissingCharacters = false;
|
|
|
|
@Override
|
|
public boolean getIgnoreMissingCharacters() {
|
|
return ignoreMissingCharacters;
|
|
}
|
|
|
|
@Override
|
|
public boolean handle(TextTag textTag, final FontTag font, final char character) {
|
|
String fontName = font.getSwf().sourceFontNamesMap.get(font.getFontId());
|
|
if (fontName == null) {
|
|
fontName = font.getFontName();
|
|
}
|
|
final Font f = FontTag.getInstalledFontsByName().get(fontName);
|
|
if (f == null || !f.canDisplay(character)) {
|
|
String msg = translate("error.font.nocharacter").replace("%char%", "" + character);
|
|
logger.log(Level.SEVERE, "{0} FontId: {1} TextId: {2}", new Object[]{msg, font.getCharacterId(), textTag.getCharacterId()});
|
|
ignoreMissingCharacters = ViewMessages.showConfirmDialog(MainPanel.this, msg, translate("error"),
|
|
JOptionPane.OK_CANCEL_OPTION, JOptionPane.ERROR_MESSAGE,
|
|
showAgainIgnoreMissingCharacters,
|
|
ignoreMissingCharacters ? JOptionPane.OK_OPTION : JOptionPane.CANCEL_OPTION) == JOptionPane.OK_OPTION;
|
|
return false;
|
|
}
|
|
|
|
font.addCharacter(character, f);
|
|
|
|
return true;
|
|
}
|
|
};
|
|
}
|
|
|
|
public boolean saveText(TextTag textTag, String formattedText, String[] texts, LineMarkedEditorPane editor) {
|
|
try {
|
|
if (textTag.setFormattedText(getMissingCharacterHandler(), formattedText, texts)) {
|
|
return true;
|
|
}
|
|
} catch (TextParseException ex) {
|
|
if (editor != null) {
|
|
editor.gotoLine((int) ex.line);
|
|
editor.markError();
|
|
}
|
|
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("error.text.invalid").replace("%text%", ex.text).replace("%line%", Long.toString(ex.line)), translate("error"), JOptionPane.ERROR_MESSAGE);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public boolean previousTag() {
|
|
JTree tree = getCurrentTree();
|
|
|
|
if (tree != null) {
|
|
if (tree.getSelectionRows().length > 0) {
|
|
int row = tree.getSelectionRows()[0];
|
|
if (row > 0) {
|
|
tree.setSelectionRow(row - 1);
|
|
tree.scrollRowToVisible(row - 1);
|
|
previewPanel.focusTextPanel();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public boolean nextTag() {
|
|
JTree tree = getCurrentTree();
|
|
|
|
if (tree != null) {
|
|
if (tree.getSelectionRows().length > 0) {
|
|
int row = tree.getSelectionRows()[0];
|
|
if (row < tree.getRowCount() - 1) {
|
|
tree.setSelectionRow(row + 1);
|
|
tree.scrollRowToVisible(row + 1);
|
|
previewPanel.focusTextPanel();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void selectBkColorButtonActionPerformed(ActionEvent evt) {
|
|
Color newColor = JColorChooser.showDialog(null, AppStrings.translate("dialog.selectbkcolor.title"), View.getSwfBackgroundColor());
|
|
if (newColor != null) {
|
|
View.setSwfBackgroundColor(newColor);
|
|
reload(true);
|
|
}
|
|
}
|
|
|
|
public void replaceButtonActionPerformed(List<TreeItem> items) {
|
|
if (items.size() == 0) {
|
|
return;
|
|
}
|
|
|
|
TreeItem ti0 = items.get(0);
|
|
File file = null;
|
|
if (ti0 instanceof SoundTag) {
|
|
file = showImportFileChooser("filter.sounds|*.mp3;*.wav|filter.sounds.mp3|*.mp3|filter.sounds.wav|*.wav", false);
|
|
}
|
|
if (ti0 instanceof ImageTag) {
|
|
file = showImportFileChooser("filter.images|*.jpg;*.jpeg;*.gif;*.png;*.bmp", true);
|
|
}
|
|
if (ti0 instanceof ShapeTag) {
|
|
file = showImportFileChooser("filter.images|*.jpg;*.jpeg;*.gif;*.png;*.bmp;*.svg", true);
|
|
}
|
|
if (ti0 instanceof DefineVideoStreamTag) {
|
|
file = showImportFileChooser("filter.movies|*.flv", false);
|
|
}
|
|
if (ti0 instanceof DefineBinaryDataTag) {
|
|
file = showImportFileChooser("", false);
|
|
}
|
|
if (ti0 instanceof UnknownTag) {
|
|
file = showImportFileChooser("", false);
|
|
}
|
|
for (TreeItem ti : items) {
|
|
doReplaceAction(ti, file);
|
|
}
|
|
}
|
|
|
|
private void doReplaceAction(TreeItem item, File selectedFile) {
|
|
if (selectedFile == null) {
|
|
return;
|
|
}
|
|
if (item instanceof SoundTag) {
|
|
File selfile = Helper.fixDialogFile(selectedFile);
|
|
SoundTag st = (SoundTag) item;
|
|
int soundFormat = SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN;
|
|
if (selfile.getName().toLowerCase(Locale.ENGLISH).endsWith(".mp3")) {
|
|
soundFormat = SoundFormat.FORMAT_MP3;
|
|
}
|
|
|
|
SoundImporter soundImporter = new SoundImporter();
|
|
|
|
boolean ok = false;
|
|
try {
|
|
ok = soundImporter.importSound(st, new FileInputStream(selfile), soundFormat);
|
|
((Tag)st).getSwf().clearSoundCache();
|
|
} catch (IOException ex) {
|
|
//ignore
|
|
} catch (UnsupportedSamplingRateException ex) {
|
|
String samplingRateKhz = "" + (ex.getSoundRate() / 1000.0) + " kHz";
|
|
List<String> supportedRatesKhz = new ArrayList<>();
|
|
for (int rate : ex.getSupportedRates()) {
|
|
supportedRatesKhz.add("" + (rate / 1000.0) + " kHz");
|
|
}
|
|
ViewMessages.showMessageDialog(this, translate("error.sound.rate").replace("%saplingRate%", samplingRateKhz).replace("%supportedRates%", String.join(", ", supportedRatesKhz)), translate("error"), JOptionPane.ERROR_MESSAGE);
|
|
return;
|
|
} catch (SoundImportException ex) {
|
|
//ignore
|
|
}
|
|
|
|
if (!ok) {
|
|
ViewMessages.showMessageDialog(this, translate("error.sound.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE);
|
|
} else {
|
|
refreshTree(((Tag)st).getSwf());
|
|
reload(true);
|
|
}
|
|
}
|
|
if (item instanceof ImageTag) {
|
|
ImageTag it = (ImageTag) item;
|
|
if (it.importSupported()) {
|
|
File selfile = Helper.fixDialogFile(selectedFile);
|
|
byte[] data = Helper.readFile(selfile.getAbsolutePath());
|
|
try {
|
|
Tag newTag = new ImageImporter().importImage(it, data);
|
|
SWF swf = it.getSwf();
|
|
if (newTag != null) {
|
|
refreshTree(swf);
|
|
setTagTreeSelectedNode(getCurrentTree(), newTag);
|
|
}
|
|
swf.clearImageCache();
|
|
swf.clearShapeCache();
|
|
} catch (IOException ex) {
|
|
logger.log(Level.SEVERE, "Invalid image", ex);
|
|
ViewMessages.showMessageDialog(this, translate("error.image.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE);
|
|
}
|
|
|
|
reload(true);
|
|
}
|
|
}
|
|
if (item instanceof ShapeTag) {
|
|
ShapeTag st = (ShapeTag) item;
|
|
File selfile = Helper.fixDialogFile(selectedFile);
|
|
byte[] data = null;
|
|
String svgText = null;
|
|
if (".svg".equals(Path.getExtension(selfile))) {
|
|
svgText = Helper.readTextFile(selfile.getAbsolutePath());
|
|
showSvgImportWarning();
|
|
} else {
|
|
data = Helper.readFile(selfile.getAbsolutePath());
|
|
}
|
|
try {
|
|
Tag newTag = svgText != null ? new SvgImporter().importSvg(st, svgText) : new ShapeImporter().importImage(st, data);
|
|
SWF swf = st.getSwf();
|
|
if (newTag != null) {
|
|
refreshTree(swf);
|
|
setTagTreeSelectedNode(getCurrentTree(), newTag);
|
|
}
|
|
|
|
swf.clearImageCache();
|
|
swf.clearShapeCache();
|
|
} catch (IOException ex) {
|
|
logger.log(Level.SEVERE, "Invalid image", ex);
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("error.image.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE);
|
|
}
|
|
reload(true);
|
|
}
|
|
if (item instanceof DefineBinaryDataTag) {
|
|
DefineBinaryDataTag bt = (DefineBinaryDataTag) item;
|
|
File selfile = Helper.fixDialogFile(selectedFile);
|
|
byte[] data = Helper.readFile(selfile.getAbsolutePath());
|
|
new BinaryDataImporter().importData(bt, data);
|
|
refreshTree(bt.getSwf());
|
|
reload(true);
|
|
}
|
|
|
|
if (item instanceof UnknownTag) {
|
|
UnknownTag ut = (UnknownTag) item;
|
|
File selfile = Helper.fixDialogFile(selectedFile);
|
|
byte[] data = Helper.readFile(selfile.getAbsolutePath());
|
|
ut.unknownData = new ByteArrayRange(data);
|
|
ut.setModified(true);
|
|
refreshTree(ut.getSwf());
|
|
reload(true);
|
|
}
|
|
|
|
if (item instanceof DefineVideoStreamTag) {
|
|
previewPanel.clear();
|
|
DefineVideoStreamTag movie = (DefineVideoStreamTag) item;
|
|
File selfile = Helper.fixDialogFile(selectedFile);
|
|
try {
|
|
new MovieImporter().importMovie(movie, Helper.readFile(selfile.getAbsolutePath()));
|
|
refreshTree();
|
|
} catch (IOException ex) {
|
|
logger.log(Level.SEVERE, "Invalid movie", ex);
|
|
ViewMessages.showMessageDialog(MainPanel.this, translate("error.movie.invalid") + ": "+ex.getMessage(), translate("error"), JOptionPane.ERROR_MESSAGE);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void replaceNoFillButtonActionPerformed(TreeItem item) {
|
|
if (item == null) {
|
|
return;
|
|
}
|
|
|
|
if (item instanceof ShapeTag) {
|
|
ShapeTag st = (ShapeTag) item;
|
|
String filter = "filter.images|*.jpg;*.jpeg;*.gif;*.png;*.bmp;*.svg";
|
|
File selectedFile = showImportFileChooser(filter, true);
|
|
if (selectedFile != null) {
|
|
File selfile = Helper.fixDialogFile(selectedFile);
|
|
byte[] data = null;
|
|
String svgText = null;
|
|
if (".svg".equals(Path.getExtension(selfile))) {
|
|
svgText = Helper.readTextFile(selfile.getAbsolutePath());
|
|
showSvgImportWarning();
|
|
} else {
|
|
data = Helper.readFile(selfile.getAbsolutePath());
|
|
}
|
|
try {
|
|
Tag newTag = svgText != null ? new SvgImporter().importSvg(st, svgText, false) : new ShapeImporter().importImage(st, data, 0, false);
|
|
SWF swf = st.getSwf();
|
|
if (newTag != null) {
|
|
refreshTree(swf);
|
|
setTagTreeSelectedNode(getCurrentTree(), newTag);
|
|
}
|
|
|
|
swf.clearImageCache();
|
|
swf.clearShapeCache();
|
|
} catch (IOException ex) {
|
|
logger.log(Level.SEVERE, "Invalid image", ex);
|
|
ViewMessages.showMessageDialog(this, translate("error.image.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE);
|
|
}
|
|
reload(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void showSvgImportWarning() {
|
|
ViewMessages.showMessageDialog(this, AppStrings.translate("message.warning.svgImportExperimental"), AppStrings.translate("message.warning"), JOptionPane.WARNING_MESSAGE, Configuration.warningSvgImport);
|
|
}
|
|
|
|
public void replaceAlphaButtonActionPerformed(ActionEvent evt) {
|
|
TreeItem item = getCurrentTree().getCurrentTreeItem();
|
|
if (item == null) {
|
|
return;
|
|
}
|
|
|
|
if (item instanceof DefineBitsJPEG3Tag || item instanceof DefineBitsJPEG4Tag) {
|
|
ImageTag it = (ImageTag) item;
|
|
if (it.importSupported()) {
|
|
File selectedFile = showImportFileChooser("", false);
|
|
if (selectedFile != null) {
|
|
File selfile = Helper.fixDialogFile(selectedFile);
|
|
byte[] data = Helper.readFile(selfile.getAbsolutePath());
|
|
try {
|
|
new ImageImporter().importImageAlpha(it, data);
|
|
SWF swf = it.getSwf();
|
|
swf.clearImageCache();
|
|
swf.clearShapeCache();
|
|
} catch (IOException ex) {
|
|
logger.log(Level.SEVERE, "Invalid alpha channel data", ex);
|
|
ViewMessages.showMessageDialog(this, translate("error.image.alpha.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE);
|
|
}
|
|
|
|
reload(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void exportJavaSourceActionPerformed(List<TreeItem> items) {
|
|
if (Main.isWorking()) {
|
|
return;
|
|
}
|
|
|
|
exportJavaSource(items);
|
|
}
|
|
|
|
public void exportSwfXmlActionPerformed(List<TreeItem> items) {
|
|
if (Main.isWorking()) {
|
|
return;
|
|
}
|
|
|
|
exportSwfXml(items);
|
|
}
|
|
|
|
public void importSwfXmlActionPerformed(List<TreeItem> items) {
|
|
if (Main.isWorking()) {
|
|
return;
|
|
}
|
|
|
|
importSwfXml(items);
|
|
}
|
|
|
|
public void exportSelectionActionPerformed(List<TreeItem> selected) {
|
|
if (Main.isWorking()) {
|
|
return;
|
|
}
|
|
|
|
export(true, selected);
|
|
}
|
|
|
|
public File showImportFileChooser(String filter, boolean imagePreview) {
|
|
String[] filterArray = filter.length() > 0 ? filter.split("\\|") : new String[0];
|
|
|
|
JFileChooser fc = new JFileChooser();
|
|
fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get()));
|
|
if (imagePreview) {
|
|
fc.setAccessory(new FileChooserImagePreview(fc));
|
|
Dimension prefferedSize = new Dimension(fc.getPreferredSize());
|
|
prefferedSize.width += FileChooserImagePreview.PREVIEW_SIZE;
|
|
fc.setPreferredSize(prefferedSize);
|
|
}
|
|
boolean first = true;
|
|
for (int i = 0; i < filterArray.length; i += 2) {
|
|
final String filterName = filterArray[i];
|
|
final String[] extensions = filterArray[i + 1].split(";");
|
|
for (int j = 0; j < extensions.length; j++) {
|
|
if (extensions[j].startsWith("*.")) {
|
|
extensions[j] = extensions[j].substring(1);
|
|
}
|
|
}
|
|
FileFilter ff = new FileFilter() {
|
|
@Override
|
|
public boolean accept(File f) {
|
|
if (f.isDirectory()) {
|
|
return true;
|
|
}
|
|
String fileName = f.getName().toLowerCase(Locale.ENGLISH);
|
|
for (String ext : extensions) {
|
|
if (fileName.endsWith(ext)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public String getDescription() {
|
|
StringBuilder extStr = new StringBuilder();
|
|
boolean first = true;
|
|
for (String ext : extensions) {
|
|
if (first) {
|
|
first = false;
|
|
} else {
|
|
extStr.append(",");
|
|
}
|
|
|
|
extStr.append("*").append(ext);
|
|
}
|
|
|
|
return translate(filterName).replace("%extensions%", extStr);
|
|
}
|
|
};
|
|
if (first) {
|
|
fc.setFileFilter(ff);
|
|
} else {
|
|
fc.addChoosableFileFilter(ff);
|
|
}
|
|
first = false;
|
|
}
|
|
|
|
if (fc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
|
|
File result = fc.getSelectedFile();
|
|
Configuration.lastOpenDir.set(Helper.fixDialogFile(result).getParentFile().getAbsolutePath());
|
|
return result;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private void showDetail(String card) {
|
|
CardLayout cl = (CardLayout) (detailPanel.getLayout());
|
|
cl.show(detailPanel, card);
|
|
if (card.equals(DETAILCARDEMPTYPANEL)) {
|
|
if (detailPanel.isVisible()) {
|
|
detailPanel.setVisible(false);
|
|
}
|
|
} else if (!detailPanel.isVisible()) {
|
|
detailPanel.setVisible(true);
|
|
}
|
|
}
|
|
|
|
private void showCard(String card) {
|
|
CardLayout cl = (CardLayout) (displayPanel.getLayout());
|
|
cl.show(displayPanel, card);
|
|
}
|
|
|
|
private void valueChanged(Object source, TreePath selectedPath) {
|
|
TreeItem treeItem = (TreeItem) selectedPath.getLastPathComponent();
|
|
|
|
if (treeItem == null) {
|
|
return;
|
|
}
|
|
|
|
if (!(treeItem instanceof OpenableList)) {
|
|
Openable openable = treeItem.getOpenable();
|
|
if (openables.isEmpty()) {
|
|
// show welcome panel after closing swfs
|
|
updateUi();
|
|
} else {
|
|
if (openable == null && openables.get(0) != null) {
|
|
openable = openables.get(0).get(0);
|
|
}
|
|
|
|
if (openable != null) {
|
|
updateUi(openable);
|
|
}
|
|
}
|
|
} else {
|
|
updateUi();
|
|
}
|
|
|
|
reload(false);
|
|
|
|
if (source == dumpTree) {
|
|
TreeItem t = null;
|
|
if (treeItem instanceof DumpInfo) {
|
|
DumpInfo di = (DumpInfo) treeItem;
|
|
t = di.getTag();
|
|
if ("BUTTONRECORD".equals(di.type)) {
|
|
DumpInfo recList = di.parent;
|
|
int index = recList.getChildInfos().indexOf(di);
|
|
ButtonTag buttonTag = (ButtonTag) di.parent.parent.getTag();
|
|
if (index < buttonTag.getRecords().size()) { //last is empty, not displayed in resource/taglist views
|
|
t = buttonTag.getRecords().get(index);
|
|
}
|
|
}
|
|
}
|
|
if (t instanceof Tag) {
|
|
t = dumpTree.getOriginalTag(t);
|
|
}
|
|
showPreview(t, dumpPreviewPanel, getFrameForTreeItem(t), getTimelinedForTreeItem(t));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void valueChanged(TreeSelectionEvent e) {
|
|
Object source = e.getSource();
|
|
valueChanged(source, e.getPath());
|
|
}
|
|
|
|
private int getFrameForTreeItem(TreeItem treeItem) {
|
|
if (treeItem == null) {
|
|
return -1;
|
|
}
|
|
if (currentView == VIEW_DUMP) {
|
|
if (treeItem instanceof Tag) {
|
|
return dumpTree.getFrameForItem(treeItem);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
if (currentView == VIEW_TIMELINE) {
|
|
return -1;
|
|
}
|
|
TreePath path = getCurrentTree().getFullModel().getTreePath(treeItem);
|
|
if (path == null) {
|
|
return -1;
|
|
}
|
|
for (int i = path.getPathCount() - 1; i >= 0; i--) {
|
|
if (path.getPathComponent(i) instanceof Frame) {
|
|
Frame frame = (Frame) path.getPathComponent(i);
|
|
return frame.frame;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
private Timelined getTimelinedForTreeItem(TreeItem treeItem) {
|
|
if (treeItem == null) {
|
|
return null;
|
|
}
|
|
|
|
if (currentView == VIEW_DUMP) {
|
|
if (treeItem instanceof Tag) {
|
|
return dumpTree.getTimelinedForItem(treeItem);
|
|
}
|
|
return null;
|
|
}
|
|
if (currentView == VIEW_TIMELINE) {
|
|
return null;
|
|
}
|
|
|
|
TreePath path = getCurrentTree().getFullModel().getTreePath(treeItem);
|
|
if (path == null) {
|
|
return null;
|
|
}
|
|
for (int i = path.getPathCount() - 1; i >= 0; i--) {
|
|
if (path.getPathComponent(i) instanceof Timelined) {
|
|
return (Timelined) path.getPathComponent(i);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void unloadFlashPlayer() {
|
|
if (flashPanel != null) {
|
|
try {
|
|
flashPanel.close();
|
|
} catch (IOException ex) {
|
|
// ignore
|
|
}
|
|
}
|
|
if (flashPanel2 != null) {
|
|
try {
|
|
flashPanel2.close();
|
|
} catch (IOException ex) {
|
|
// ignore
|
|
}
|
|
}
|
|
}
|
|
|
|
public void clearDebuggerColors() {
|
|
if (abcPanel != null) {
|
|
abcPanel.decompiledTextArea.removeColorMarkerOnAllLines(DecompiledEditorPane.IP_MARKER);
|
|
abcPanel.detailPanel.methodTraitPanel.methodCodePanel.clearDebuggerColors();
|
|
}
|
|
if (actionPanel != null) {
|
|
actionPanel.decompiledEditor.removeColorMarkerOnAllLines(DecompiledEditorPane.IP_MARKER);
|
|
actionPanel.editor.removeColorMarkerOnAllLines(DecompiledEditorPane.IP_MARKER);
|
|
}
|
|
}
|
|
|
|
private void stopFlashPlayer() {
|
|
if (flashPanel != null) {
|
|
if (!flashPanel.isStopped()) {
|
|
flashPanel.stopSWF();
|
|
}
|
|
}
|
|
if (flashPanel2 != null) {
|
|
if (!flashPanel2.isStopped()) {
|
|
flashPanel2.stopSWF();
|
|
}
|
|
}
|
|
}
|
|
|
|
public static boolean isAdobeFlashPlayerEnabled() {
|
|
return Configuration.useAdobeFlashPlayerForPreviews.get();
|
|
}
|
|
|
|
public static final int VIEW_RESOURCES = 0;
|
|
|
|
public static final int VIEW_DUMP = 1;
|
|
|
|
public static final int VIEW_TIMELINE = 2;
|
|
|
|
public static final int VIEW_TAGLIST = 3;
|
|
|
|
public int getCurrentView() {
|
|
return currentView;
|
|
}
|
|
|
|
public void setTreeModel(int view) {
|
|
switch (view) {
|
|
case VIEW_DUMP:
|
|
if (dumpTree.getModel() == null) {
|
|
DumpTreeModel dtm = new DumpTreeModel(openables);
|
|
dumpTree.setModel(dtm);
|
|
dumpTree.expandFirstLevelNodes();
|
|
}
|
|
break;
|
|
case VIEW_RESOURCES:
|
|
case VIEW_TAGLIST:
|
|
if (tagTree.getModel() == null) {
|
|
TagTreeModel ttm = new TagTreeModel(openables, Configuration.tagTreeShowEmptyFolders.get());
|
|
tagTree.setModel(ttm);
|
|
//tagTree.expandFirstLevelNodes();
|
|
}
|
|
|
|
if (tagListTree.getModel() == null) {
|
|
TagListTreeModel ttm = new TagListTreeModel(openables);
|
|
tagListTree.setModel(ttm);
|
|
//tagListTree.expandFirstLevelNodes();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
private JPanel createDumpViewCard() {
|
|
JPanel r = new JPanel(new BorderLayout());
|
|
r.add(new JPersistentSplitPane(JSplitPane.VERTICAL_SPLIT, new FasterScrollPane(dumpTree), dumpPreviewPanel, Configuration.guiDumpSplitPaneDividerLocationPercent), BorderLayout.CENTER);
|
|
return r;
|
|
}
|
|
|
|
private JPanel createTagListViewCard() {
|
|
tagListClipboardPanel = new ClipboardPanel(this);
|
|
|
|
JPanel r = new JPanel(new BorderLayout());
|
|
r.add(tagListClipboardPanel, BorderLayout.NORTH);
|
|
r.add(new FasterScrollPane(tagListTree), BorderLayout.CENTER);
|
|
quickTagListFindPanel = new QuickTreeFindPanel();
|
|
quickTagListFindPanel.addActionListener(new ActionListener() {
|
|
@Override
|
|
public void actionPerformed(ActionEvent e) {
|
|
doFilter();
|
|
}
|
|
});
|
|
r.add(quickTagListFindPanel, BorderLayout.SOUTH);
|
|
return r;
|
|
}
|
|
|
|
private JPanel createResourcesViewCard() {
|
|
resourcesClipboardPanel = new ClipboardPanel(this);
|
|
JPanel r = new JPanel(new BorderLayout());
|
|
r.add(resourcesClipboardPanel, BorderLayout.NORTH);
|
|
r.add(tagTreeScrollPanel = new FasterScrollPane(tagTree), BorderLayout.CENTER);
|
|
quickTreeFindPanel = new QuickTreeFindPanel();
|
|
quickTreeFindPanel.addActionListener(new ActionListener() {
|
|
@Override
|
|
public void actionPerformed(ActionEvent e) {
|
|
doFilter();
|
|
}
|
|
});
|
|
r.add(quickTreeFindPanel, BorderLayout.SOUTH);
|
|
return r;
|
|
}
|
|
|
|
private void showContentPanelCard(String card) {
|
|
CardLayout cl = (CardLayout) (contentPanel.getLayout());
|
|
cl.show(contentPanel, card);
|
|
}
|
|
|
|
private void showTreePanelCard(String card) {
|
|
CardLayout cl = (CardLayout) (treePanel.getLayout());
|
|
cl.show(treePanel, card);
|
|
}
|
|
|
|
public boolean showView(int view) {
|
|
View.checkAccess();
|
|
|
|
setTreeModel(view);
|
|
switch (view) {
|
|
case VIEW_DUMP:
|
|
pinsPanel.setVisible(false);
|
|
currentView = view;
|
|
Configuration.lastView.set(currentView);
|
|
if (!isWelcomeScreen) {
|
|
showContentPanelCard(SPLIT_PANE1);
|
|
}
|
|
showTreePanelCard(DUMP_VIEW);
|
|
treePanelMode = TreePanelMode.DUMP_TREE;
|
|
showDetail(DETAILCARDEMPTYPANEL);
|
|
reload(true);
|
|
return true;
|
|
case VIEW_RESOURCES:
|
|
pinsPanel.setVisible(true);
|
|
currentView = view;
|
|
Configuration.lastView.set(currentView);
|
|
if (!isWelcomeScreen) {
|
|
showContentPanelCard(SPLIT_PANE1);
|
|
}
|
|
showTreePanelCard(RESOURCES_VIEW);
|
|
|
|
treePanelMode = TreePanelMode.TAG_TREE;
|
|
|
|
treePanel.addComponentListener(new ComponentAdapter() {
|
|
@Override
|
|
public void componentResized(ComponentEvent e) {
|
|
tagTree.scrollPathToVisible(tagTree.getSelectionPath());
|
|
}
|
|
});
|
|
|
|
refreshPins();
|
|
reload(true);
|
|
return true;
|
|
case VIEW_TIMELINE:
|
|
pinsPanel.setVisible(false);
|
|
currentView = view;
|
|
Configuration.lastView.set(currentView);
|
|
final SWF swf = getCurrentSwf();
|
|
if (swf != null) {
|
|
TreeItem item = tagTree.getCurrentTreeItem();
|
|
if (item instanceof TagScript) {
|
|
item = ((TagScript) item).getTag();
|
|
}
|
|
if (item instanceof Timelined) {
|
|
timelineViewPanel.setTimelined((Timelined) item);
|
|
} else if (item instanceof Frame) {
|
|
timelineViewPanel.setTimelined(((Frame) item).timeline.timelined);
|
|
} else {
|
|
timelineViewPanel.setTimelined(swf);
|
|
}
|
|
showContentPanelCard(TIMELINE_PANEL);
|
|
return true;
|
|
} else {
|
|
showView(VIEW_RESOURCES);
|
|
}
|
|
return false;
|
|
case VIEW_TAGLIST:
|
|
pinsPanel.setVisible(true);
|
|
currentView = view;
|
|
Configuration.lastView.set(currentView);
|
|
if (!isWelcomeScreen) {
|
|
showContentPanelCard(SPLIT_PANE1);
|
|
}
|
|
showTreePanelCard(TAGLIST_VIEW);
|
|
treePanelMode = TreePanelMode.TAGLIST_TREE;
|
|
refreshPins();
|
|
reload(true);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void dumpViewReload(boolean forceReload) {
|
|
showDetail(DETAILCARDEMPTYPANEL);
|
|
|
|
DumpInfo dumpInfo = (DumpInfo) dumpTree.getLastSelectedPathComponent();
|
|
if (dumpInfo == null) {
|
|
showCard(CARDEMPTYPANEL);
|
|
return;
|
|
}
|
|
|
|
dumpViewPanel.revalidate();
|
|
dumpViewPanel.setSelectedNode(dumpInfo);
|
|
showCard(CARDDUMPVIEW);
|
|
}
|
|
|
|
public void loadFromBinaryTag(final DefineBinaryDataTag binaryDataTag) {
|
|
loadFromBinaryTag(Arrays.asList(binaryDataTag));
|
|
}
|
|
|
|
public void loadFromBinaryTag(final List<DefineBinaryDataTag> binaryDataTags) {
|
|
|
|
Main.loadingDialog.setVisible(true);
|
|
new CancellableWorker<Void>() {
|
|
@Override
|
|
protected Void doInBackground() throws Exception {
|
|
try {
|
|
for (DefineBinaryDataTag binaryDataTag : binaryDataTags) {
|
|
String path = binaryDataTag.getSwf().getShortPathTitle() + "/DefineBinaryData (" + binaryDataTag.getCharacterId() + ")";
|
|
try {
|
|
SwfSpecificCustomConfiguration conf = Configuration.getSwfSpecificCustomConfiguration(path);
|
|
String charset = conf == null ? Charset.defaultCharset().name() : conf.getCustomData(CustomConfigurationKeys.KEY_CHARSET, Charset.defaultCharset().name());
|
|
InputStream is = new ByteArrayInputStream(binaryDataTag.binaryData.getRangeData());
|
|
SWF bswf = new SWF(is, null, "(SWF Data)", new ProgressListener() {
|
|
@Override
|
|
public void progress(int p) {
|
|
Main.loadingDialog.setPercent(p);
|
|
}
|
|
}, Configuration.parallelSpeedUp.get(), charset);
|
|
binaryDataTag.innerSwf = bswf;
|
|
bswf.binaryData = binaryDataTag;
|
|
} catch (IOException ex) {
|
|
//ignore
|
|
}
|
|
}
|
|
} catch (InterruptedException ex) {
|
|
//ignore
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
protected void onStart() {
|
|
Main.startWork(AppStrings.translate("work.reading.swf") + "...", this);
|
|
}
|
|
|
|
@Override
|
|
protected void done() {
|
|
View.execInEventDispatch(() -> {
|
|
Main.loadingDialog.setVisible(false);
|
|
refreshTree();
|
|
Main.stopWork();
|
|
});
|
|
}
|
|
}.execute();
|
|
}
|
|
|
|
private void closeTag() {
|
|
View.checkAccess();
|
|
|
|
previewPanel.closeTag();
|
|
}
|
|
|
|
public static void showPreview(TreeItem treeItem, PreviewPanel previewPanel, int frame, Timelined timelinedContainer) {
|
|
previewPanel.clear();
|
|
if (treeItem == null) {
|
|
previewPanel.showEmpty();
|
|
return;
|
|
}
|
|
boolean internalViewer = !isAdobeFlashPlayerEnabled();
|
|
|
|
boolean isVideoButNotDrawable = (treeItem instanceof DefineVideoStreamTag) && (!DefineVideoStreamTag.displayAvailable());
|
|
|
|
if (treeItem instanceof SWF) {
|
|
SWF swf = (SWF) treeItem;
|
|
if (internalViewer) {
|
|
previewPanel.showImagePanel(swf, swf, -1, true, Configuration.autoPlaySwfs.get() && Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), true, false);
|
|
} else {
|
|
previewPanel.setParametersPanelVisible(false);
|
|
//if (flashPanel != null) { //same for flashPanel2
|
|
previewPanel.showFlashViewerPanel();
|
|
previewPanel.showSwf(swf);
|
|
|
|
//}
|
|
}
|
|
} else if ((treeItem instanceof PlaceObjectTypeTag)) {// && (previewPanel != dumpPreviewPanel)) {
|
|
previewPanel.showDisplayEditTagPanel((PlaceObjectTypeTag) treeItem, frame);
|
|
} else if (treeItem instanceof ShapeTag) {
|
|
previewPanel.showDisplayEditTagPanel((ShapeTag)treeItem, 0);
|
|
previewPanel.setImageReplaceButtonVisible(false, false, !((Tag) treeItem).isReadOnly(), false, false);
|
|
} else if (treeItem instanceof MetadataTag) {
|
|
MetadataTag metadataTag = (MetadataTag) treeItem;
|
|
previewPanel.showMetaDataPanel(metadataTag);
|
|
} else if (treeItem instanceof DefineBinaryDataTag) {
|
|
DefineBinaryDataTag binaryTag = (DefineBinaryDataTag) treeItem;
|
|
previewPanel.showBinaryPanel(binaryTag);
|
|
} else if (treeItem instanceof ProductInfoTag) {
|
|
ProductInfoTag productInfoTag = (ProductInfoTag) treeItem;
|
|
previewPanel.showProductInfoPanel(productInfoTag);
|
|
} else if (treeItem instanceof UnknownTag) {
|
|
UnknownTag unknownTag = (UnknownTag) treeItem;
|
|
previewPanel.showUnknownPanel(unknownTag);
|
|
} else if (treeItem instanceof ImageTag) {
|
|
ImageTag imageTag = (ImageTag) treeItem;
|
|
previewPanel.setImageReplaceButtonVisible(!((Tag) imageTag).isReadOnly() && imageTag.importSupported(), imageTag instanceof DefineBitsJPEG3Tag || imageTag instanceof DefineBitsJPEG4Tag, false, false, false);
|
|
SWF imageSWF = makeTimelinedImage(imageTag);
|
|
previewPanel.showImagePanel(imageSWF, imageSWF, 0, false, true, true, true, true, false, false);
|
|
|
|
} else if (!isVideoButNotDrawable && (treeItem instanceof DrawableTag) && (!(treeItem instanceof TextTag)) && (!(treeItem instanceof FontTag)) && internalViewer) {
|
|
final Tag tag = (Tag) treeItem;
|
|
DrawableTag d = (DrawableTag) tag;
|
|
Timelined timelined;
|
|
if (treeItem instanceof Timelined && !(treeItem instanceof ButtonTag)) {
|
|
timelined = (Timelined) tag;
|
|
} else {
|
|
timelined = makeTimelined(tag);
|
|
}
|
|
|
|
previewPanel.setParametersPanelVisible(false);
|
|
if (treeItem instanceof ShapeTag) {
|
|
previewPanel.setImageReplaceButtonVisible(false, false, !((Tag) treeItem).isReadOnly(), false, false);
|
|
}
|
|
if (treeItem instanceof DefineVideoStreamTag) {
|
|
previewPanel.setImageReplaceButtonVisible(false, false, false, false, !((Tag) treeItem).isReadOnly());
|
|
}
|
|
previewPanel.showImagePanel(timelined, tag.getSwf(), -1, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), treeItem instanceof ShapeTag, !Configuration.playFrameSounds.get(), (treeItem instanceof DefineSpriteTag) || (treeItem instanceof ButtonTag), (treeItem instanceof DefineSpriteTag) || (treeItem instanceof ButtonTag) || (treeItem instanceof ShapeTag));
|
|
} else if (treeItem instanceof Frame && internalViewer) {
|
|
Frame fn = (Frame) treeItem;
|
|
SWF swf = (SWF) fn.getOpenable();
|
|
previewPanel.showImagePanel(fn.timeline.timelined, swf, fn.frame, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), true, false);
|
|
} else if (treeItem instanceof ShowFrameTag) {
|
|
SWF swf;
|
|
if (timelinedContainer instanceof DefineSpriteTag) {
|
|
swf = ((DefineSpriteTag) timelinedContainer).getSwf();
|
|
} else {
|
|
swf = (SWF) timelinedContainer;
|
|
}
|
|
previewPanel.showImagePanel(timelinedContainer, swf, frame, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), true, false);
|
|
} else if ((treeItem instanceof SoundTag)) { //&& isInternalFlashViewerSelected() && (Arrays.asList("mp3", "wav").contains(((SoundTag) tagObj).getExportFormat())))) {
|
|
previewPanel.showImagePanel(new SerializableImage(View.loadImage("sound32")));
|
|
previewPanel.setImageReplaceButtonVisible(false, false, false, !((Tag) treeItem).isReadOnly() && (treeItem instanceof SoundTag), false);
|
|
try {
|
|
SoundTagPlayer soundThread = new SoundTagPlayer(null, (SoundTag) treeItem, Configuration.loopMedia.get() ? Integer.MAX_VALUE : 1, true);
|
|
if (!Configuration.autoPlaySounds.get()) {
|
|
soundThread.pause();
|
|
}
|
|
previewPanel.setMedia(soundThread);
|
|
} catch (LineUnavailableException | IOException | UnsupportedAudioFileException ex) {
|
|
logger.log(Level.SEVERE, null, ex);
|
|
}
|
|
} else if ((treeItem instanceof FontTag) && internalViewer) {
|
|
previewPanel.showFontPanel((FontTag) treeItem);
|
|
} else if ((treeItem instanceof TextTag) && internalViewer) {
|
|
previewPanel.showTextPanel((TextTag) treeItem);
|
|
} else if ((treeItem instanceof Frame) || (treeItem instanceof CharacterTag) || (treeItem instanceof FontTag) || (treeItem instanceof SoundStreamHeadTypeTag)) {
|
|
previewPanel.createAndShowTempSwf(treeItem);
|
|
|
|
if (treeItem instanceof TextTag) {
|
|
previewPanel.showTextPanel((TextTag) treeItem);
|
|
} else if (treeItem instanceof FontTag) {
|
|
previewPanel.showFontPanel((FontTag) treeItem);
|
|
} else {
|
|
previewPanel.setParametersPanelVisible(false);
|
|
}
|
|
} else if (treeItem instanceof BUTTONRECORD) {
|
|
BUTTONRECORD buttonRecord = (BUTTONRECORD) treeItem;
|
|
previewPanel.setParametersPanelVisible(false);
|
|
SWF swf = new SWF(buttonRecord.getSwf().getCharset());
|
|
swf.frameCount = 1;
|
|
swf.frameRate = buttonRecord.getSwf().frameRate;
|
|
swf.displayRect = buttonRecord.getTag().getRect();
|
|
if (swf.getBackgroundColor() != null) {
|
|
SetBackgroundColorTag setBackgroundColorTag = new SetBackgroundColorTag(swf, swf.getBackgroundColor().backgroundColor);
|
|
swf.addTag(setBackgroundColorTag);
|
|
setBackgroundColorTag.setTimelined(swf);
|
|
}
|
|
CharacterTag character = buttonRecord.getSwf().getCharacter(buttonRecord.characterId);
|
|
Set<Integer> needed = new LinkedHashSet<>();
|
|
character.getNeededCharactersDeep(needed);
|
|
needed.remove(buttonRecord.characterId);
|
|
needed.add(buttonRecord.characterId);
|
|
|
|
for (int n : needed) {
|
|
CharacterTag neededCharacter;
|
|
try {
|
|
neededCharacter = (CharacterTag) buttonRecord.getSwf().getCharacter(n).cloneTag();
|
|
} catch (InterruptedException | IOException ex) {
|
|
Logger.getLogger(MainPanel.class.getName()).log(Level.SEVERE, null, ex);
|
|
return;
|
|
}
|
|
neededCharacter.setSwf(swf);
|
|
neededCharacter.setTimelined(swf);
|
|
swf.addTag(neededCharacter);
|
|
}
|
|
|
|
PlaceObject3Tag placeTag = buttonRecord.toPlaceObject();
|
|
placeTag.setSwf(swf);
|
|
|
|
swf.addTag(placeTag);
|
|
placeTag.setTimelined(swf);
|
|
ShowFrameTag showFrameTag = new ShowFrameTag(swf);
|
|
swf.addTag(showFrameTag);
|
|
showFrameTag.setTimelined(swf);
|
|
previewPanel.showImagePanel(swf, swf, 0, true, true, !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), true, false);
|
|
} else {
|
|
previewPanel.showEmpty();
|
|
}
|
|
}
|
|
|
|
private void tagListViewReload(boolean forceReload) {
|
|
showDetail(DETAILCARDEMPTYPANEL);
|
|
showCard(CARDEMPTYPANEL);
|
|
}
|
|
|
|
public void reload(boolean forceReload) {
|
|
View.checkAccess();
|
|
|
|
JScrollBar folderPreviewScrollBar = ((JScrollPane)folderPreviewPanel.getParent().getParent()).getVerticalScrollBar();
|
|
int scrollValue = folderPreviewScrollBar.getValue();
|
|
Map<Integer, TreeItem> folderItems = new HashMap<>(folderPreviewPanel.selectedItems);
|
|
|
|
|
|
tagTree.scrollPathToVisible(tagTree.getSelectionPath());
|
|
if (currentView == VIEW_DUMP) {
|
|
dumpViewReload(forceReload);
|
|
return;
|
|
}
|
|
/*else if (currentView == VIEW_TAGLIST) {
|
|
tagListViewReload(forceReload);
|
|
return;
|
|
}*/
|
|
|
|
AbstractTagTree tree = getCurrentTree();
|
|
TreeItem treeItem = null;
|
|
TreePath treePath = tree.getSelectionPath();
|
|
if (treePath != null && tree.getFullModel().treePathExists(treePath)) {
|
|
treeItem = (TreeItem) treePath.getLastPathComponent();
|
|
}
|
|
|
|
// save last selected node to config
|
|
if (treeItem != null && !(treeItem instanceof OpenableList)) {
|
|
Openable openable = treeItem.getOpenable();
|
|
if (openable != null && (openable instanceof SWF)) {
|
|
openable = ((SWF) openable).getRootSwf();
|
|
}
|
|
|
|
if (openable != null) {
|
|
SwfSpecificCustomConfiguration swfCustomConf = Configuration.getOrCreateSwfSpecificCustomConfiguration(openable.getShortPathTitle());
|
|
swfCustomConf.setCustomData(CustomConfigurationKeys.KEY_LAST_SELECTED_PATH_RESOURCES, tagTree.getSelectionPathString());
|
|
swfCustomConf.setCustomData(CustomConfigurationKeys.KEY_LAST_SELECTED_PATH_TAGLIST, tagListTree.getSelectionPathString());
|
|
}
|
|
}
|
|
|
|
if (!forceReload && (treeItem == oldItem)) {
|
|
return;
|
|
}
|
|
|
|
if (oldItem != treeItem) {
|
|
closeTag();
|
|
}
|
|
|
|
oldItem = treeItem;
|
|
|
|
// show the preview of the tag when the user clicks to the tagname inside the scripts node, too
|
|
// this is a little bit inconsistent, beacuse the frames (FrameScript) are not shown
|
|
boolean preferScript = false;
|
|
if (treeItem instanceof TagScript) {
|
|
treeItem = ((TagScript) treeItem).getTag();
|
|
preferScript = true;
|
|
}
|
|
|
|
folderPreviewPanel.clear();
|
|
folderListPanel.clear();
|
|
previewPanel.clear();
|
|
stopFlashPlayer();
|
|
|
|
previewPanel.setImageReplaceButtonVisible(false, false, false, false, false);
|
|
|
|
boolean internalViewer = !isAdobeFlashPlayerEnabled();
|
|
|
|
if (treeItem instanceof ScriptPack) {
|
|
final ScriptPack scriptLeaf = (ScriptPack) treeItem;
|
|
if (!Main.isInited() || !Main.isWorking() || Main.isDebugging()) {
|
|
ABCPanel abcPanel = getABCPanel();
|
|
abcPanel.detailPanel.methodTraitPanel.methodCodePanel.clear();
|
|
abcPanel.setAbc(scriptLeaf.abc);
|
|
abcPanel.decompiledTextArea.setScript(scriptLeaf, true);
|
|
abcPanel.decompiledTextArea.setNoTrait();
|
|
}
|
|
|
|
if (Configuration.displayAs3TraitsListAndConstantsPanel.get()) {
|
|
showDetail(DETAILCARDAS3NAVIGATOR);
|
|
} else {
|
|
showDetail(DETAILCARDEMPTYPANEL);
|
|
}
|
|
showCard(CARDACTIONSCRIPT3PANEL);
|
|
} else if (treeItem instanceof Tag) {
|
|
Tag tag = (Tag) treeItem;
|
|
TagInfo tagInfo = new TagInfo((SWF) treeItem.getOpenable());
|
|
tag.getTagInfo(tagInfo);
|
|
|
|
Set<Integer> needed;
|
|
if (neededCharacters.containsKey(treeItem)) {
|
|
needed = neededCharacters.get(treeItem);
|
|
} else {
|
|
needed = new LinkedHashSet<>();
|
|
tag.getNeededCharactersDeep(needed);
|
|
neededCharacters.put(treeItem, needed);
|
|
}
|
|
|
|
if (needed.size() > 0) {
|
|
tagInfo.addInfo("general", "neededCharacters", Helper.joinStrings(needed, ", "));
|
|
}
|
|
|
|
if (tag instanceof CharacterTag) {
|
|
int characterId = ((CharacterTag) tag).getCharacterId();
|
|
Set<Integer> dependent = tag.getSwf().getDependentCharacters(characterId);
|
|
if (dependent != null) {
|
|
if (dependent.size() > 0) {
|
|
tagInfo.addInfo("general", "dependentCharacters", Helper.joinStrings(dependent, ", "));
|
|
}
|
|
}
|
|
|
|
Set<Integer> dependent2 = tag.getSwf().getDependentFrames(characterId);
|
|
if (dependent2 != null && dependent2.size() > 0) {
|
|
tagInfo.addInfo("general", "dependentFrames", Helper.joinStrings(dependent2, ", "));
|
|
}
|
|
}
|
|
|
|
if (!tagInfo.isEmpty()) {
|
|
tagInfoPanel.setTagInfos(tagInfo);
|
|
showDetail(DETAILCARDTAGINFO);
|
|
} else {
|
|
showDetail(DETAILCARDEMPTYPANEL);
|
|
}
|
|
} else if (treeItem instanceof Frame) {
|
|
Frame frame = (Frame) treeItem;
|
|
Set<Integer> needed = new LinkedHashSet<>();
|
|
|
|
frame.getNeededCharacters(needed);
|
|
|
|
if (!needed.isEmpty()) {
|
|
TagInfo tagInfo = new TagInfo((SWF) treeItem.getOpenable());
|
|
tagInfo.addInfo("general", "neededCharacters", Helper.joinStrings(needed, ", "));
|
|
tagInfoPanel.setTagInfos(tagInfo);
|
|
showDetail(DETAILCARDTAGINFO);
|
|
} else {
|
|
showDetail(DETAILCARDEMPTYPANEL);
|
|
}
|
|
} else {
|
|
showDetail(DETAILCARDEMPTYPANEL);
|
|
}
|
|
|
|
/*if (treeItem instanceof SoundStreamBlockTag) {
|
|
SoundStreamBlockTag block = (SoundStreamBlockTag)treeItem;
|
|
byte[] data = block.streamSoundData.getRangeData();
|
|
try{
|
|
SWFInputStream sis = new SWFInputStream(block.getSwf(), data);
|
|
int sampleCount = sis.readUI16("sampleCount");
|
|
int seekSamples = sis.readSI16("seekSamples");
|
|
System.out.println("sampleCount = "+sampleCount);
|
|
System.out.println("seekSamples = "+seekSamples);
|
|
System.out.println("============");
|
|
}catch(Exception ex){
|
|
|
|
}
|
|
}*/
|
|
if (treeItem instanceof HeaderItem) {
|
|
headerPanel.load((SWF) ((HeaderItem) treeItem).getOpenable());
|
|
showCard(CARDHEADER);
|
|
} else if (treeItem instanceof FolderItem) {
|
|
showFolderPreview((FolderItem) treeItem);
|
|
} else if (treeItem instanceof SWF) {
|
|
showPreview(treeItem, previewPanel, -1, null);
|
|
showCard(CARDPREVIEWPANEL);
|
|
} else if (treeItem instanceof MetadataTag) {
|
|
showPreview(treeItem, previewPanel, -1, null);
|
|
showCard(CARDPREVIEWPANEL);
|
|
} else if (treeItem instanceof DefineBinaryDataTag) {
|
|
showPreview(treeItem, previewPanel, -1, null);
|
|
showCard(CARDPREVIEWPANEL);
|
|
} else if (treeItem instanceof UnknownTag) {
|
|
showPreview(treeItem, previewPanel, -1, null);
|
|
showCard(CARDPREVIEWPANEL);
|
|
} else if (treeItem instanceof ASMSource && (!(treeItem instanceof DrawableTag) || preferScript)) {
|
|
getActionPanel().setSource((ASMSource) treeItem, !forceReload);
|
|
showCard(CARDACTIONSCRIPTPANEL);
|
|
} else if (treeItem instanceof ImageTag) {
|
|
showPreview(treeItem, previewPanel, -1, null);
|
|
showCard(CARDPREVIEWPANEL);
|
|
} else if ((treeItem instanceof DrawableTag) && (!(treeItem instanceof TextTag)) && (!(treeItem instanceof FontTag)) && internalViewer) {
|
|
showPreview(treeItem, previewPanel, -1, null);
|
|
showCard(CARDPREVIEWPANEL);
|
|
} else if ((treeItem instanceof FontTag) && internalViewer) {
|
|
showPreview(treeItem, previewPanel, -1, null);
|
|
showCard(CARDPREVIEWPANEL);
|
|
} else if ((treeItem instanceof TextTag) && internalViewer) {
|
|
showPreview(treeItem, previewPanel, -1, null);
|
|
showCard(CARDPREVIEWPANEL);
|
|
} else if (treeItem instanceof Frame && internalViewer) {
|
|
showPreview(treeItem, previewPanel, -1, null);
|
|
showCard(CARDPREVIEWPANEL);
|
|
} else if (treeItem instanceof ShowFrameTag && internalViewer) {
|
|
showPreview(treeItem, previewPanel, getFrameForTreeItem(treeItem), getTimelinedForTreeItem(treeItem));
|
|
showCard(CARDPREVIEWPANEL);
|
|
} else if ((treeItem instanceof SoundTag)) { //&& isInternalFlashViewerSelected() && (Arrays.asList("mp3", "wav").contains(((SoundTag) tagObj).getExportFormat())))) {
|
|
showPreview(treeItem, previewPanel, -1, null);
|
|
showCard(CARDPREVIEWPANEL);
|
|
} else if ((treeItem instanceof Frame) || (treeItem instanceof CharacterTag) || (treeItem instanceof FontTag) || (treeItem instanceof SoundStreamHeadTypeTag)) {
|
|
showPreview(treeItem, previewPanel, -1, null);
|
|
|
|
showCard(CARDPREVIEWPANEL);
|
|
} else if (treeItem instanceof PlaceObjectTypeTag) {
|
|
showPreview(treeItem, previewPanel, getFrameForTreeItem(treeItem), null);
|
|
showCard(CARDPREVIEWPANEL);
|
|
} else if (treeItem instanceof ProductInfoTag) {
|
|
showPreview(treeItem, previewPanel, -1, null);
|
|
showCard(CARDPREVIEWPANEL);
|
|
} else if (treeItem instanceof Tag) {
|
|
showGenericTag((Tag) treeItem);
|
|
} else if (treeItem instanceof BUTTONRECORD) {
|
|
showPreview(treeItem, previewPanel, -1, null);
|
|
showCard(CARDPREVIEWPANEL);
|
|
} else if (!(treeItem instanceof ScriptPack)) {
|
|
if (treePath == null) {
|
|
showCard(CARDEMPTYPANEL);
|
|
} else {
|
|
showFolderList(treePath);
|
|
}
|
|
}
|
|
if (oldItem instanceof TreeRoot) {
|
|
pinsPanel.setCurrent(null);
|
|
} else {
|
|
pinsPanel.setCurrent(oldItem);
|
|
}
|
|
|
|
folderPreviewPanel.selectedItems = folderItems;
|
|
folderPreviewScrollBar.setValue(scrollValue);
|
|
|
|
}
|
|
|
|
public void repaintTree() {
|
|
tagTree.repaint();
|
|
tagListTree.repaint();
|
|
reload(true);
|
|
}
|
|
|
|
public void showGenericTag(Tag tag) {
|
|
previewPanel.showGenericTagPanel(tag);
|
|
showCard(CARDPREVIEWPANEL);
|
|
}
|
|
|
|
public void showTextTagWithNewValue(TextTag textTag, TextTag newTextTag) {
|
|
|
|
previewPanel.showTextComparePanel(textTag, newTextTag);
|
|
}
|
|
|
|
private void addFolderPreviewItems(List<TreeItem> folderPreviewItems, String folderName, Timelined timelined) {
|
|
switch (folderName) {
|
|
case TagTreeModel.FOLDER_SHAPES:
|
|
for (Tag tag : timelined.getTags()) {
|
|
if (tag instanceof ShapeTag) {
|
|
folderPreviewItems.add(tag);
|
|
}
|
|
if (tag instanceof DefineSpriteTag) {
|
|
addFolderPreviewItems(folderPreviewItems, folderName, (DefineSpriteTag) tag);
|
|
}
|
|
}
|
|
break;
|
|
case TagTreeModel.FOLDER_MORPHSHAPES:
|
|
for (Tag tag : timelined.getTags()) {
|
|
if (tag instanceof MorphShapeTag) {
|
|
folderPreviewItems.add(tag);
|
|
}
|
|
if (tag instanceof DefineSpriteTag) {
|
|
addFolderPreviewItems(folderPreviewItems, folderName, (DefineSpriteTag) tag);
|
|
}
|
|
}
|
|
break;
|
|
case TagTreeModel.FOLDER_SPRITES:
|
|
for (Tag tag : timelined.getTags()) {
|
|
if (tag instanceof DefineSpriteTag) {
|
|
folderPreviewItems.add(tag);
|
|
addFolderPreviewItems(folderPreviewItems, folderName, (DefineSpriteTag) tag);
|
|
}
|
|
}
|
|
break;
|
|
case TagTreeModel.FOLDER_MOVIES:
|
|
for (Tag tag : timelined.getTags()) {
|
|
if (tag instanceof DefineVideoStreamTag) {
|
|
folderPreviewItems.add(tag);
|
|
}
|
|
if (tag instanceof DefineSpriteTag) {
|
|
addFolderPreviewItems(folderPreviewItems, folderName, (DefineSpriteTag) tag);
|
|
}
|
|
}
|
|
break;
|
|
case TagTreeModel.FOLDER_BUTTONS:
|
|
for (Tag tag : timelined.getTags()) {
|
|
if (tag instanceof ButtonTag) {
|
|
folderPreviewItems.add(tag);
|
|
}
|
|
if (tag instanceof DefineSpriteTag) {
|
|
addFolderPreviewItems(folderPreviewItems, folderName, (DefineSpriteTag) tag);
|
|
}
|
|
}
|
|
break;
|
|
case TagTreeModel.FOLDER_FONTS:
|
|
for (Tag tag : timelined.getTags()) {
|
|
if (tag instanceof FontTag) {
|
|
folderPreviewItems.add(tag);
|
|
}
|
|
if (tag instanceof DefineSpriteTag) {
|
|
addFolderPreviewItems(folderPreviewItems, folderName, (DefineSpriteTag) tag);
|
|
}
|
|
}
|
|
break;
|
|
case TagTreeModel.FOLDER_FRAMES:
|
|
for (Frame frame : timelined.getTimeline().getFrames()) {
|
|
folderPreviewItems.add(frame);
|
|
}
|
|
break;
|
|
case TagTreeModel.FOLDER_IMAGES:
|
|
for (Tag tag : timelined.getTags()) {
|
|
if (tag instanceof ImageTag) {
|
|
folderPreviewItems.add(tag);
|
|
}
|
|
if (tag instanceof DefineSpriteTag) {
|
|
addFolderPreviewItems(folderPreviewItems, folderName, (DefineSpriteTag) tag);
|
|
}
|
|
}
|
|
break;
|
|
case TagTreeModel.FOLDER_TEXTS:
|
|
for (Tag tag : timelined.getTags()) {
|
|
if (tag instanceof TextTag) {
|
|
folderPreviewItems.add(tag);
|
|
}
|
|
if (tag instanceof DefineSpriteTag) {
|
|
addFolderPreviewItems(folderPreviewItems, folderName, (DefineSpriteTag) tag);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void showFolderPreview(FolderItem item) {
|
|
String folderName = item.getName();
|
|
if (TagTreeModel.FOLDER_OTHERS.equals(folderName) || TagTreeModel.FOLDER_SCRIPTS.equals(folderName)) {
|
|
showFolderList(tagTree.getFullModel().getTreePath(item));
|
|
return;
|
|
}
|
|
List<TreeItem> folderPreviewItems = new ArrayList<>();
|
|
SWF swf = item.swf;
|
|
addFolderPreviewItems(folderPreviewItems, folderName, swf);
|
|
|
|
folderPreviewPanel.setItems(folderPreviewItems);
|
|
showCard(CARDFOLDERPREVIEWPANEL);
|
|
}
|
|
|
|
private void showFolderList(TreePath path) {
|
|
List<TreeItem> items = new ArrayList<>(getCurrentTree().getFullModel().getAllChildren((TreeItem) path.getLastPathComponent()));
|
|
folderListPanel.setItems(path, items);
|
|
showCard(CARDFOLDERLISTPANEL);
|
|
}
|
|
|
|
private boolean isFreeing;
|
|
|
|
@Override
|
|
public boolean isFreeing() {
|
|
return isFreeing;
|
|
}
|
|
|
|
@Override
|
|
public void free() {
|
|
isFreeing = true;
|
|
}
|
|
|
|
public void setErrorState(ErrorState errorState) {
|
|
statusPanel.setErrorState(errorState);
|
|
}
|
|
|
|
public static Timelined makeTimelined(final Tag tag) {
|
|
return makeTimelined(tag, -1);
|
|
}
|
|
|
|
public static SWF makeTimelinedImage(ImageTag imageTag) {
|
|
SWF swf = new SWF();
|
|
swf.gfx = imageTag.getSwf().gfx;
|
|
swf.version = imageTag.getSwf().version;
|
|
int w = (int) (imageTag.getImageDimension().getWidth() * SWF.unitDivisor);
|
|
int h = (int) (imageTag.getImageDimension().getHeight() * SWF.unitDivisor);
|
|
swf.displayRect = new RECT(0, w, 0, h);
|
|
swf.frameCount = 1;
|
|
swf.frameRate = 1;
|
|
swf.setFile(imageTag.getSwf().getFile()); //DefineSubImage calculates relative paths from it
|
|
try {
|
|
|
|
JPEGTablesTag jpegTablesTag = null;
|
|
if (imageTag instanceof DefineBitsTag) {
|
|
jpegTablesTag = imageTag.getSwf().getJtt();
|
|
}
|
|
Set<Integer> needed = new LinkedHashSet<>();
|
|
imageTag.getNeededCharacters(needed);
|
|
|
|
List<CharacterTag> neededCopies = new ArrayList<>();
|
|
for (int n : needed) {
|
|
CharacterTag ct = imageTag.getSwf().getCharacter(n);
|
|
if (ct != null) {
|
|
ct = (CharacterTag) ct.cloneTag();
|
|
ct.setSwf(swf);
|
|
neededCopies.add(ct);
|
|
}
|
|
}
|
|
if (imageTag instanceof DefineSubImage) {
|
|
DefineExternalImage2 dei2 = (DefineExternalImage2) imageTag.getSwf().getExternalImage2(((DefineSubImage) imageTag).imageId);
|
|
if (dei2 != null) {
|
|
dei2 = (DefineExternalImage2) dei2.cloneTag();
|
|
dei2.setSwf(swf);
|
|
neededCopies.add(dei2);
|
|
}
|
|
}
|
|
|
|
ImageTag imageTagCopy = (ImageTag) imageTag.cloneTag();
|
|
imageTagCopy.setSwf(swf);
|
|
int imageCharId = imageTag.getCharacterId();
|
|
DefineShape2Tag shapeTag = new DefineShape2Tag(swf);
|
|
int shapeCharId = imageCharId + 1;
|
|
shapeTag.shapeId = shapeCharId;
|
|
shapeTag.shapeBounds = new RECT(swf.displayRect);
|
|
|
|
SHAPEWITHSTYLE shapeData = new SHAPEWITHSTYLE();
|
|
FILLSTYLEARRAY fillStyleArray = new FILLSTYLEARRAY();
|
|
FILLSTYLE fillStyles[] = new FILLSTYLE[1];
|
|
FILLSTYLE fillStyle = new FILLSTYLE();
|
|
fillStyle.bitmapId = imageCharId;
|
|
fillStyle.inShape3 = false;
|
|
fillStyle.fillStyleType = FILLSTYLE.CLIPPED_BITMAP;
|
|
fillStyle.bitmapMatrix = Matrix.getScaleInstance(SWF.unitDivisor).toMATRIX();
|
|
fillStyles[0] = fillStyle;
|
|
fillStyleArray.fillStyles = fillStyles;
|
|
shapeData.fillStyles = fillStyleArray;
|
|
shapeData.lineStyles = new LINESTYLEARRAY();
|
|
|
|
List<SHAPERECORD> shapeRecords = new ArrayList<>();
|
|
|
|
StyleChangeRecord scr = new StyleChangeRecord();
|
|
scr.stateFillStyle0 = true;
|
|
scr.fillStyle0 = 1;
|
|
shapeRecords.add(scr);
|
|
|
|
StyleChangeRecord scr2 = new StyleChangeRecord();
|
|
scr2.stateMoveTo = true;
|
|
scr2.moveDeltaX = 0;
|
|
scr2.moveDeltaY = 0;
|
|
scr2.calculateBits();
|
|
shapeRecords.add(scr2);
|
|
|
|
StraightEdgeRecord ser1 = new StraightEdgeRecord();
|
|
ser1.vertLineFlag = true;
|
|
ser1.deltaY = h;
|
|
ser1.calculateBits();
|
|
shapeRecords.add(ser1);
|
|
|
|
StraightEdgeRecord ser2 = new StraightEdgeRecord();
|
|
ser2.deltaX = w;
|
|
shapeRecords.add(ser2);
|
|
|
|
StraightEdgeRecord ser3 = new StraightEdgeRecord();
|
|
ser3.vertLineFlag = true;
|
|
ser3.deltaY = -h;
|
|
shapeRecords.add(ser3);
|
|
|
|
StraightEdgeRecord ser4 = new StraightEdgeRecord();
|
|
ser4.deltaX = -w;
|
|
shapeRecords.add(ser4);
|
|
|
|
shapeRecords.add(new EndShapeRecord());
|
|
|
|
shapeData.shapeRecords = shapeRecords;
|
|
|
|
shapeData.numFillBits = 1;
|
|
shapeData.numLineBits = 0;
|
|
|
|
shapeTag.shapes = shapeData;
|
|
|
|
PlaceObjectTag placeTag = new PlaceObjectTag(swf, shapeCharId, 1, new Matrix().toMATRIX(), null);
|
|
|
|
ShowFrameTag showFrameTag = new ShowFrameTag(swf);
|
|
|
|
EndTag endTag = new EndTag(swf);
|
|
|
|
if (jpegTablesTag != null) {
|
|
swf.addTag(jpegTablesTag);
|
|
}
|
|
for (CharacterTag neededCopy : neededCopies) {
|
|
swf.addTag(neededCopy);
|
|
}
|
|
swf.addTag(imageTagCopy);
|
|
swf.addTag(shapeTag);
|
|
swf.addTag(placeTag);
|
|
swf.addTag(showFrameTag);
|
|
swf.addTag(endTag);
|
|
|
|
} catch (InterruptedException | IOException ex) {
|
|
//ignore
|
|
}
|
|
return swf;
|
|
}
|
|
|
|
public static Timelined makeTimelined(final Tag tag, final int fontFrameNum) {
|
|
|
|
return new Timelined() {
|
|
private Timeline tim;
|
|
|
|
@Override
|
|
public Timeline getTimeline() {
|
|
if (tim == null) {
|
|
Timeline timeline = new Timeline(tag.getSwf(), this, ((CharacterTag) tag).getCharacterId(), getRect());
|
|
initTimeline(timeline);
|
|
tim = timeline;
|
|
}
|
|
|
|
return tim;
|
|
}
|
|
|
|
@Override
|
|
public void resetTimeline() {
|
|
if (tim != null) {
|
|
tim.reset(tag.getSwf(), this, ((CharacterTag) tag).getCharacterId(), getRect());
|
|
initTimeline(tim);
|
|
}
|
|
}
|
|
|
|
private void initTimeline(Timeline timeline) {
|
|
if (tag instanceof MorphShapeTag) {
|
|
timeline.frameRate = PreviewExporter.MORPH_SHAPE_ANIMATION_FRAME_RATE;
|
|
int framesCnt = (int) (timeline.frameRate * PreviewExporter.MORPH_SHAPE_ANIMATION_LENGTH);
|
|
for (int i = 0; i < framesCnt; i++) {
|
|
Frame f = new Frame(timeline, i);
|
|
DepthState ds = new DepthState(tag.getSwf(), f);
|
|
ds.characterId = ((CharacterTag) tag).getCharacterId();
|
|
ds.matrix = new MATRIX();
|
|
ds.ratio = i * 65535 / framesCnt;
|
|
f.layers.put(1, ds);
|
|
f.layersChanged = true;
|
|
timeline.addFrame(f);
|
|
}
|
|
} else if (tag instanceof FontTag) {
|
|
int pageCount = PreviewPanel.getFontPageCount((FontTag) tag);
|
|
int frame = fontFrameNum;
|
|
if (frame < 0 || frame >= pageCount) {
|
|
frame = 0;
|
|
}
|
|
|
|
Frame f = new Frame(timeline, 0);
|
|
DepthState ds = new DepthState(tag.getSwf(), f);
|
|
ds.characterId = ((CharacterTag) tag).getCharacterId();
|
|
ds.matrix = new MATRIX();
|
|
f.layers.put(1, ds);
|
|
f.layersChanged = true;
|
|
timeline.addFrame(f);
|
|
timeline.fontFrameNum = frame;
|
|
} else {
|
|
Frame f = new Frame(timeline, 0);
|
|
DepthState ds = new DepthState(tag.getSwf(), f);
|
|
ds.characterId = ((CharacterTag) tag).getCharacterId();
|
|
ds.matrix = new MATRIX();
|
|
f.layers.put(1, ds);
|
|
timeline.addFrame(f);
|
|
}
|
|
timeline.displayRect = getRect();
|
|
}
|
|
|
|
@Override
|
|
public RECT getRect() {
|
|
return getRect(new HashSet<>());
|
|
}
|
|
|
|
@Override
|
|
public RECT getRect(Set<BoundedTag> added) {
|
|
BoundedTag bt = (BoundedTag) tag;
|
|
if (!added.contains(bt)) {
|
|
return bt.getRect(added);
|
|
}
|
|
return new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE);
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
return tag.hashCode();
|
|
}
|
|
|
|
@Override
|
|
public void setModified(boolean value) {
|
|
}
|
|
|
|
@Override
|
|
public ReadOnlyTagList getTags() {
|
|
return ReadOnlyTagList.EMPTY;
|
|
}
|
|
|
|
@Override
|
|
public void removeTag(int index) {
|
|
}
|
|
|
|
@Override
|
|
public void removeTag(Tag tag) {
|
|
}
|
|
|
|
@Override
|
|
public void addTag(Tag tag) {
|
|
}
|
|
|
|
@Override
|
|
public void addTag(int index, Tag tag) {
|
|
}
|
|
|
|
@Override
|
|
public void replaceTag(int index, Tag newTag) {
|
|
}
|
|
|
|
@Override
|
|
public void replaceTag(Tag oldTag, Tag newTag) {
|
|
}
|
|
|
|
@Override
|
|
public int indexOfTag(Tag tag) {
|
|
return -1;
|
|
}
|
|
|
|
@Override
|
|
public RECT getRectWithStrokes() {
|
|
return getRect();
|
|
}
|
|
|
|
@Override
|
|
public void setFrameCount(int frameCount) {
|
|
throw new UnsupportedOperationException("Not supported yet.");
|
|
}
|
|
|
|
@Override
|
|
public int getFrameCount() {
|
|
return getTimeline().getFrameCount();
|
|
}
|
|
};
|
|
}
|
|
|
|
private void disposeInner(Container container) {
|
|
for (Component c : container.getComponents()) {
|
|
if (c instanceof Container) {
|
|
Container c2 = (Container) c;
|
|
disposeInner(c2);
|
|
}
|
|
}
|
|
|
|
container.removeAll();
|
|
container.setLayout(null);
|
|
if (container instanceof TagEditorPanel) {
|
|
Helper.emptyObject(container);
|
|
}
|
|
}
|
|
|
|
public void dispose() {
|
|
if (calculateMissingNeededThread != null) {
|
|
calculateMissingNeededThread.interrupt();
|
|
}
|
|
setDropTarget(null);
|
|
disposeInner(this);
|
|
Helper.emptyObject(this);
|
|
}
|
|
|
|
private static void calculateMissingNeededCharacters(Map<TreeItem, Set<Integer>> neededMap, Map<TreeItem, Set<Integer>> missingNeededCharacters, Timelined tim) {
|
|
List<Tag> tags = tim.getTags().toArrayList();
|
|
Map<Integer, List<CharacterIdTag>> nestedTags = new HashMap<>();
|
|
for (Tag t : tags) {
|
|
if ((t instanceof CharacterIdTag) && !(t instanceof CharacterTag) && !(t instanceof SoundStreamHeadTypeTag)) {
|
|
int characterId = ((CharacterIdTag) t).getCharacterId();
|
|
if (!nestedTags.containsKey(characterId)) {
|
|
nestedTags.put(characterId, new ArrayList<>());
|
|
}
|
|
nestedTags.get(characterId).add((CharacterIdTag) t);
|
|
}
|
|
|
|
if (!(t instanceof CharacterTag) && !(t instanceof SoundStreamHeadTypeTag)) {
|
|
int characterId = -1;
|
|
if (t instanceof CharacterIdTag) {
|
|
characterId = ((CharacterIdTag) t).getCharacterId();
|
|
}
|
|
Set<Integer> needed = new LinkedHashSet<>();
|
|
t.getNeededCharactersDeep(needed);
|
|
neededMap.put(t, needed);
|
|
if ((t instanceof CharacterIdTag) && !(t instanceof PlaceObjectTypeTag)) {
|
|
needed = new HashSet<>();
|
|
needed.add(characterId);
|
|
}
|
|
|
|
if ((t instanceof PlaceObjectTypeTag) && (characterId != -1) && nestedTags.containsKey(characterId)) {
|
|
for (CharacterIdTag n : nestedTags.get(characterId)) {
|
|
((Tag) n).getNeededCharactersDeep(needed);
|
|
}
|
|
}
|
|
|
|
missingNeededCharacters.put(t, t.getMissingNeededCharacters(needed));
|
|
if (characterId != -1 && tim.getTimeline().swf.getCharacter(characterId) == null) {
|
|
missingNeededCharacters.get(t).add(characterId);
|
|
}
|
|
|
|
}
|
|
/*if (t instanceof DefineSpriteTag) {
|
|
calculateMissingNeededCharacters(neededMap, missingNeededCharacters, (DefineSpriteTag) t);
|
|
}*/
|
|
}
|
|
}
|
|
|
|
public void updateMissingNeededCharacters() {
|
|
if (calculateMissingNeededThread != null) {
|
|
calculateMissingNeededThread.recalculate();
|
|
}
|
|
}
|
|
|
|
private void calculateMissingNeededCharacters() {
|
|
Map<TreeItem, Set<Integer>> missingNeededCharacters = new WeakHashMap<>();
|
|
Map<TreeItem, Set<Integer>> neededCharacters = new WeakHashMap<>();
|
|
|
|
List<OpenableList> swfsLists = new ArrayList<>(openables);
|
|
for (OpenableList swfList : swfsLists) {
|
|
for (Openable openable : swfList) {
|
|
if (openable instanceof SWF) {
|
|
calculateMissingNeededCharacters(neededCharacters, missingNeededCharacters, (SWF) openable);
|
|
//TODO: how about SubSWFs???
|
|
}
|
|
}
|
|
}
|
|
this.neededCharacters = neededCharacters;
|
|
this.missingNeededCharacters = missingNeededCharacters;
|
|
tagTree.setMissingNeededCharacters(missingNeededCharacters);
|
|
tagListTree.setMissingNeededCharacters(missingNeededCharacters);
|
|
}
|
|
|
|
class CalculateMissingNeededThread extends Thread {
|
|
|
|
public CalculateMissingNeededThread() {
|
|
super("calculateMissingNeededThread");
|
|
setPriority(Thread.MIN_PRIORITY);
|
|
}
|
|
|
|
private boolean recalculate = false;
|
|
|
|
public synchronized void recalculate() {
|
|
this.recalculate = true;
|
|
this.notify();
|
|
}
|
|
|
|
@Override
|
|
public void run() {
|
|
while (true) {
|
|
synchronized (this) {
|
|
recalculate = false;
|
|
}
|
|
try {
|
|
calculateMissingNeededCharacters();
|
|
} catch (ConcurrentModificationException cme) {
|
|
//ignore
|
|
}
|
|
synchronized (this) {
|
|
|
|
if (recalculate) {
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
wait();
|
|
} catch (InterruptedException ex) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public String itemToString(TreeItem item) {
|
|
int index = getCurrentTree().getFullModel().getItemIndex(item);
|
|
String itemToStr = item.toString();
|
|
if (index > 1) {
|
|
return itemToStr + " [" + index + "]";
|
|
}
|
|
return itemToStr;
|
|
}
|
|
|
|
public void startEdit() {
|
|
TreeItem treeItem = getCurrentTree().getCurrentTreeItem();
|
|
if (treeItem == null) {
|
|
return;
|
|
}
|
|
if (treeItem instanceof HeaderItem) {
|
|
headerPanel.startEdit();
|
|
} else if (treeItem instanceof PlaceObjectTypeTag) {
|
|
previewPanel.startEditPlaceTag();
|
|
} else if (treeItem instanceof MetadataTag) {
|
|
previewPanel.startEditMetaDataTag();
|
|
} else if (treeItem instanceof DefineBinaryDataTag) {
|
|
//TODO
|
|
} else if (treeItem instanceof FontTag) {
|
|
previewPanel.startEditFontTag();
|
|
} else if (treeItem instanceof TextTag) {
|
|
previewPanel.startEditTextTag();
|
|
} else if (treeItem instanceof ASMSource) {
|
|
//There are two kinds of edit - Script and P-code.
|
|
} else if (treeItem instanceof Tag) {
|
|
Tag tag = (Tag) treeItem;
|
|
previewPanel.showGenericTagPanel(tag);
|
|
previewPanel.startEditGenericTag();
|
|
}
|
|
|
|
}
|
|
}
|