diff --git a/CHANGELOG.md b/CHANGELOG.md index b5919cf8a..6612a26af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,8 @@ All notable changes to this project will be documented in this file. - [#1865] ConcurrentModificationException on SWF close - NullPointerException on expanding needed/dependent characters on basic tag info - Copy/Move with dependencies should copy mapped tags too +- Recalculating dependencies in the loop (now only on change) +- Dependencies handling ## [16.2.0] - 2022-11-08 ### Added diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/CSMTextSettingsTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/CSMTextSettingsTag.java index d33c9820c..ff153a726 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/CSMTextSettingsTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/CSMTextSettingsTag.java @@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.decompiler.flash.types.annotations.SWFVersion; import com.jpexs.helpers.ByteArrayRange; import java.io.IOException; +import java.util.Set; /** * @@ -124,4 +125,9 @@ public class CSMTextSettingsTag extends Tag implements CharacterIdTag { public String toString() { return super.toString() + " (" + textID + ")"; } + + @Override + public void getNeededCharacters(Set needed) { + needed.add(textID); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java index 759bb74f2..f95b47c30 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java @@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.decompiler.flash.types.annotations.SWFVersion; import com.jpexs.helpers.ByteArrayRange; import java.io.IOException; +import java.util.Set; /** * @@ -97,4 +98,9 @@ public class DefineButtonCxformTag extends Tag implements CharacterIdTag { public String toString() { return super.toString() + " (" + buttonId + ")"; } + + @Override + public void getNeededCharacters(Set needed) { + needed.add(buttonId); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java index 16c92b8e6..00f87984f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java @@ -155,6 +155,7 @@ public class DefineButtonSoundTag extends Tag implements CharacterIdTag { if (buttonSoundChar3 != 0) { needed.add(buttonSoundChar3); } + needed.add(buttonId); } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java index 3472eca1e..32738b3af 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java @@ -31,6 +31,7 @@ import com.jpexs.helpers.ByteArrayRange; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * @@ -116,4 +117,9 @@ public class DefineFontAlignZonesTag extends Tag implements CharacterIdTag { public String toString() { return super.toString() + " (" + fontID + ")"; } + + @Override + public void getNeededCharacters(Set needed) { + needed.add(fontID); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java index d218c068d..f984e867e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java @@ -30,6 +30,7 @@ import com.jpexs.helpers.utf8.Utf8Helper; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * @@ -189,4 +190,9 @@ public class DefineFontInfo2Tag extends FontInfoTag { public boolean isShiftJIS() { return fontFlagsShiftJIS; } + + @Override + public void getNeededCharacters(Set needed) { + needed.add(fontID); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java index 1cd6c155c..2790dea42 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java @@ -29,6 +29,7 @@ import com.jpexs.helpers.utf8.Utf8Helper; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * @@ -191,4 +192,9 @@ public class DefineFontInfoTag extends FontInfoTag { public boolean isAnsi() { return fontFlagsANSI; } + + @Override + public void getNeededCharacters(Set needed) { + needed.add(fontID); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontNameTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontNameTag.java index a844d9f4b..a09be6671 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontNameTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontNameTag.java @@ -25,6 +25,7 @@ import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.decompiler.flash.types.annotations.SWFVersion; import com.jpexs.helpers.ByteArrayRange; import java.io.IOException; +import java.util.Set; /** * @@ -94,4 +95,9 @@ public class DefineFontNameTag extends Tag implements CharacterIdTag { public String toString() { return super.toString() + " (" + fontId + ")"; } + + @Override + public void getNeededCharacters(Set needed) { + needed.add(fontId); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineScalingGridTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineScalingGridTag.java index 1b0ba247e..5176573c3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineScalingGridTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineScalingGridTag.java @@ -37,6 +37,7 @@ import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.PathIterator; import java.io.IOException; +import java.util.Set; /** * @@ -214,5 +215,10 @@ public class DefineScalingGridTag extends Tag implements CharacterIdTag { public String toString() { return super.toString() + " (" + characterId + ")"; } + + @Override + public void getNeededCharacters(Set needed) { + needed.add(characterId); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java index f26ce377c..de51e0d9c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java @@ -456,10 +456,12 @@ public class DefineSpriteTag extends DrawableTag implements Timelined { } @Override - public Set getMissingNeededCharacters() { + public Set getMissingNeededCharacters(Set needed) { Set ret = new LinkedHashSet<>(); for (Tag tag : getTags()) { - Set sub = tag.getMissingNeededCharacters(); + Set subNeeded = new HashSet<>(); + tag.getNeededCharactersDeep(subNeeded); + Set sub = tag.getMissingNeededCharacters(subNeeded); ret.addAll(sub); } return ret; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java index 0e0a43a9c..e4e83233b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoInitActionTag.java @@ -38,6 +38,7 @@ import com.jpexs.helpers.Helper; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * @@ -264,4 +265,9 @@ public class DoInitActionTag extends Tag implements CharacterIdTag, ASMSource { public Tag getTag() { return null; //? } + + @Override + public void getNeededCharacters(Set needed) { + needed.add(spriteId); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FreeCharacterTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FreeCharacterTag.java index fb0266462..2929bfb60 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FreeCharacterTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/FreeCharacterTag.java @@ -25,6 +25,7 @@ import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.decompiler.flash.types.annotations.SWFVersion; import com.jpexs.helpers.ByteArrayRange; import java.io.IOException; +import java.util.Set; /** * @@ -82,4 +83,9 @@ public class FreeCharacterTag extends Tag implements CharacterIdTag { public void setCharacterId(int characterId) { this.characterId = characterId; } + + @Override + public void getNeededCharacters(Set needed) { + needed.add(characterId); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/NameCharacterTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/NameCharacterTag.java index 95497afdd..b151df70a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/NameCharacterTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/NameCharacterTag.java @@ -25,6 +25,7 @@ import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.decompiler.flash.types.annotations.SWFVersion; import com.jpexs.helpers.ByteArrayRange; import java.io.IOException; +import java.util.Set; /** * @@ -91,4 +92,9 @@ public class NameCharacterTag extends Tag implements CharacterIdTag { public void setCharacterId(int characterId) { this.characterId = characterId; } + + @Override + public void getNeededCharacters(Set needed) { + needed.add(characterId); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObjectTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObjectTag.java index 136567aed..3b4d03380 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObjectTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/RemoveObjectTag.java @@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.decompiler.flash.types.annotations.SWFVersion; import com.jpexs.helpers.ByteArrayRange; import java.io.IOException; +import java.util.Set; /** * Removes the specified character @@ -105,4 +106,9 @@ public class RemoveObjectTag extends RemoveTag implements CharacterIdTag { public void setCharacterId(int characterId) { this.characterId = characterId; } + + @Override + public void getNeededCharacters(Set needed) { + needed.add(characterId); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java index f24bb0b01..5b5298160 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHead2Tag.java @@ -34,6 +34,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * @@ -263,4 +264,6 @@ public class SoundStreamHead2Tag extends Tag implements SoundStreamHeadTypeTag { public String toString() { return getName() + (virtualCharacterId > 0 ? " (" + virtualCharacterId + ")" : ""); } + + //getNeededCharacters intentionally not defined } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java index 6230341a8..0cb593e04 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java @@ -35,6 +35,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * @@ -273,4 +274,13 @@ public class SoundStreamHeadTag extends Tag implements SoundStreamHeadTypeTag { public String toString() { return getName() + (virtualCharacterId > 0 ? " (" + virtualCharacterId + ")" : ""); } + + @Override + public void getNeededCharacters(Set needed) { + if (virtualCharacterId > 0) { + needed.add(virtualCharacterId); + } + } + + //getNeededCharacters intentionally not defined } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java index 0e388f069..1c314cfb3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/Tag.java @@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.abc.CopyOutputStream; +import com.jpexs.decompiler.flash.amf.amf3.ListSet; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; @@ -599,15 +600,14 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { public void getNeededCharacters(Set needed) { } - public Set getMissingNeededCharacters() { - Set needed = new LinkedHashSet<>(); - getNeededCharacters(needed); - if (needed.isEmpty()) { - return needed; + public Set getMissingNeededCharacters(Set needed) { + Set needed2 = new ListSet<>(needed); + if (needed2.isEmpty()) { + return new LinkedHashSet<>(); } Timelined tim = getTimelined(); if (tim == null) { - return needed; + return needed2; } ReadOnlyTagList tags = tim.getTags(); for (int i = tags.indexOf(this) - 1; i >= -1; i--) { @@ -624,13 +624,13 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { } if (tags.get(i) instanceof CharacterTag) { int charId = ((CharacterTag) tags.get(i)).getCharacterId(); - needed.remove(charId); - if (needed.isEmpty()) { - return needed; + needed2.remove(charId); + if (needed2.isEmpty()) { + return needed2; } } } - return needed; + return needed2; } @Override @@ -725,7 +725,7 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { bounds.getHeight() / SWF.unitDivisor)); } - Set needed = new LinkedHashSet<>(); + /*Set needed = new LinkedHashSet<>(); getNeededCharactersDeep(needed); if (needed.size() > 0) { @@ -745,7 +745,7 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { if(dependent2 != null && dependent2.size() > 0) { tagInfo.addInfo("general", "dependentFrames", Helper.joinStrings(dependent2, ", ")); } - } + }*/ } public String getCharset() { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/VideoFrameTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/VideoFrameTag.java index 4618f0c8f..44acf564c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/VideoFrameTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/VideoFrameTag.java @@ -25,6 +25,7 @@ import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.decompiler.flash.types.annotations.SWFVersion; import com.jpexs.helpers.ByteArrayRange; import java.io.IOException; +import java.util.Set; /** * @@ -96,4 +97,9 @@ public class VideoFrameTag extends Tag implements CharacterIdTag { public void setCharacterId(int characterId) { this.streamID = characterId; } + + @Override + public void getNeededCharacters(Set needed) { + needed.add(streamID); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java index d21ad34f0..1c3707cb7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java @@ -70,11 +70,6 @@ public abstract class ButtonTag extends DrawableTag implements Timelined { for (BUTTONRECORD r : getRecords()) { needed.add(r.characterId); } - - DefineButtonSoundTag sounds = getSounds(); - if (sounds != null) { - sounds.getNeededCharacters(needed); - } } @Override diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index 7480c5695..3fdedbb69 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -1369,6 +1369,7 @@ public class Main { mainFrame.getPanel().tagTree.setExpandPathString(resourcesPathStr); mainFrame.getPanel().tagListTree.setExpandPathString(tagListPathStr); } + mainFrame.getPanel().updateMissingNeededCharacters(); } if (executeAfterOpen != null) { diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 57bd09b88..d4e3d6ca3 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -31,9 +31,9 @@ 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.types.traits.Trait; +import com.jpexs.decompiler.flash.amf.amf3.ListSet; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.configuration.ConfigurationItem; -import com.jpexs.decompiler.flash.configuration.SwfSpecificConfiguration; import com.jpexs.decompiler.flash.configuration.SwfSpecificCustomConfiguration; import com.jpexs.decompiler.flash.dumpview.DumpInfo; import com.jpexs.decompiler.flash.dumpview.DumpInfoSwfNode; @@ -124,6 +124,7 @@ 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.DefineFontNameTag; import com.jpexs.decompiler.flash.tags.DefineShape2Tag; import com.jpexs.decompiler.flash.tags.DefineSoundTag; import com.jpexs.decompiler.flash.tags.DefineSpriteTag; @@ -197,7 +198,6 @@ import java.awt.Desktop; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; -import java.awt.Graphics; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; @@ -228,7 +228,6 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.ConcurrentModificationException; import java.util.HashMap; import java.util.HashSet; @@ -238,6 +237,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.Random; import java.util.Set; import java.util.WeakHashMap; @@ -253,12 +253,9 @@ import javax.swing.Icon; import javax.swing.JColorChooser; import javax.swing.JFileChooser; import javax.swing.JLabel; -import javax.swing.JLayeredPane; 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.JTextField; @@ -270,11 +267,9 @@ import javax.swing.event.DocumentListener; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.filechooser.FileFilter; -import javax.swing.plaf.basic.BasicScrollPaneUI; import javax.swing.plaf.basic.BasicTreeUI; import javax.swing.tree.DefaultTreeSelectionModel; import javax.swing.tree.TreePath; -import javax.swing.tree.TreeSelectionModel; import jsyntaxpane.DefaultSyntaxKit; /** @@ -394,9 +389,10 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se private static final Logger logger = Logger.getLogger(MainPanel.class.getName()); + private Map> neededCharacters = new WeakHashMap<>(); private Map> missingNeededCharacters = new WeakHashMap<>(); - private Thread calculateMissingNeededThread; + private CalculateMissingNeededThread calculateMissingNeededThread; private List> orderedClipboard = new ArrayList<>(); private Map clipboard = new WeakHashMap<>(); @@ -1146,23 +1142,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se //Opening files with drag&drop to main window enableDrop(true); - calculateMissingNeededThread = new Thread("calculateMissingNeededThread") { - @Override - public void run() { - while (true) { - try { - calculateMissingNeededCharacters(); - } catch (ConcurrentModificationException cme) { - //ignore - } - try { - Thread.sleep(1000); - } catch (InterruptedException ex) { - return; - } - } - } - }; + calculateMissingNeededThread = new CalculateMissingNeededThread(); calculateMissingNeededThread.start(); } @@ -2960,6 +2940,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se swf.clearImageCache(); reload(true); + updateMissingNeededCharacters(); } } @@ -3045,6 +3026,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se ViewMessages.showMessageDialog(MainPanel.this, translate("import.script.result").replace("%count%", Integer.toString(countAs2 + countAs3))); if (countAs2 != 0 || countAs3 != 0) { reload(true); + updateMissingNeededCharacters(); } }); } @@ -3457,6 +3439,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } reload(true); + updateMissingNeededCharacters(); } public void refreshDecompiled() { @@ -4344,7 +4327,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se character.getNeededCharactersDeep(needed); needed.remove(buttonRecord.characterId); needed.add(buttonRecord.characterId); - + for (int n : needed) { CharacterTag neededCharacter; try { @@ -4354,10 +4337,10 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se return; } neededCharacter.setSwf(swf); - neededCharacter.setTimelined(swf); + neededCharacter.setTimelined(swf); swf.addTag(neededCharacter); } - + PlaceObject2Tag placeTag = new PlaceObject2Tag(swf, false, 1, buttonRecord.characterId, buttonRecord.placeMatrix, buttonRecord.colorTransform, 0, null, -1, null); swf.addTag(placeTag); placeTag.setTimelined(swf); @@ -4460,6 +4443,36 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se Tag tag = (Tag) treeItem; TagInfo tagInfo = new TagInfo(treeItem.getSwf()); tag.getTagInfo(tagInfo); + + Set 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 dependent = tag.getSwf().getDependentCharacters(characterId); + if (dependent != null) { + if (dependent.size() > 0) { + tagInfo.addInfo("general", "dependentCharacters", Helper.joinStrings(dependent, ", ")); + } + } + + Set 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); @@ -4941,29 +4954,78 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se Helper.emptyObject(this); } - private static void calculateMissingNeededCharacters(Map> missingNeededCharacters, Timelined tim) { + private static void calculateMissingNeededCharacters(Map> neededMap, Map> missingNeededCharacters, Timelined tim) { List tags = tim.getTags().toArrayList(); for (Tag t : tags) { - missingNeededCharacters.put(t, t.getMissingNeededCharacters()); + Set needed = new LinkedHashSet<>(); + t.getNeededCharactersDeep(needed); + neededMap.put(t, needed); + missingNeededCharacters.put(t, t.getMissingNeededCharacters(needed)); if (t instanceof DefineSpriteTag) { - calculateMissingNeededCharacters(missingNeededCharacters, (DefineSpriteTag) t); + calculateMissingNeededCharacters(neededMap, missingNeededCharacters, (DefineSpriteTag) t); } } } - public void calculateMissingNeededCharacters() { + public void updateMissingNeededCharacters() { + if (calculateMissingNeededThread != null) { + calculateMissingNeededThread.recalculate(); + } + } + + private void calculateMissingNeededCharacters() { Map> missingNeededCharacters = new WeakHashMap<>(); + Map> neededCharacters = new WeakHashMap<>(); + List swfsLists = new ArrayList<>(swfs); for (SWFList swfList : swfsLists) { for (SWF swf : swfList) { - calculateMissingNeededCharacters(missingNeededCharacters, swf); + calculateMissingNeededCharacters(neededCharacters, missingNeededCharacters, swf); } } - if (!missingNeededCharacters.equals(this.missingNeededCharacters)) { - this.missingNeededCharacters = missingNeededCharacters; - tagTree.setMissingNeededCharacters(missingNeededCharacters); - tagListTree.setMissingNeededCharacters(missingNeededCharacters); - } + this.neededCharacters = neededCharacters; + this.missingNeededCharacters = missingNeededCharacters; + tagTree.setMissingNeededCharacters(missingNeededCharacters); + tagListTree.setMissingNeededCharacters(missingNeededCharacters); } + class CalculateMissingNeededThread extends Thread { + + public CalculateMissingNeededThread() { + super("calculateMissingNeededThread"); + } + + 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; + } + } + } + } + } }