From 954f4f387bb1566b1e76f302a5df141f8d1b7b0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sun, 6 Nov 2022 18:45:31 +0100 Subject: [PATCH] Added Checking missing needed character tags and their proper position (Marking them as red - with tooltip) --- CHANGELOG.md | 1 + .../flash/tags/DefineSpriteTag.java | 11 +++++ .../com/jpexs/decompiler/flash/tags/Tag.java | 32 +++++++++++++ .../jpexs/decompiler/flash/gui/MainPanel.java | 45 +++++++++++++++++++ .../flash/gui/locales/MainFrame.properties | 5 +++ .../flash/gui/locales/MainFrame_cs.properties | 11 ++++- .../flash/gui/taglistview/TagListTree.java | 2 +- .../taglistview/TagListTreeCellRenderer.java | 24 ++++++++++ .../flash/gui/tagtree/AbstractTagTree.java | 16 +++++++ .../decompiler/flash/gui/tagtree/TagTree.java | 22 +++++++++ 10 files changed, 167 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d8039694..770b0c793 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file. - Show in Hex dump command from other views for tags - Show in Taglist command from dump view for tags - Create new empty SWF file +- Checking missing needed character tags and their proper position (Marking them as red - with tooltip) ### Fixed - Flash viewer - subtract blend mode 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 78020efaf..9c42a20b5 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 @@ -48,6 +48,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -445,4 +446,14 @@ public class DefineSpriteTag extends DrawableTag implements Timelined { public RECT getRectWithStrokes() { return getRect(); //? } + + @Override + public Set getMissingNeededCharacters() { + Set ret = new LinkedHashSet<>(); + for (Tag tag : getTags()) { + Set sub = tag.getMissingNeededCharacters(); + ret.addAll(sub); + } + return ret; + } } 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 981a9011e..58a45d2c9 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 @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.tags; +import com.jpexs.decompiler.flash.ReadOnlyTagList; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; @@ -594,6 +595,37 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { @Override public void getNeededCharacters(Set needed) { } + + public Set getMissingNeededCharacters() { + Set needed = new LinkedHashSet<>(); + getNeededCharacters(needed); + if (needed.isEmpty()) { + return needed; + } + Timelined tim = getTimelined(); + ReadOnlyTagList tags = tim.getTags(); + for (int i = tags.indexOf(this) - 1; i >= -1; i--) { + if (i == -1) { + if (tim instanceof SWF) { + break; + } else { + Timelined parent = ((Tag) tim).getTimelined(); + tags = parent.getTags(); + i = tags.indexOf((Tag) tim); + tim = parent; + continue; + } + } + if (tags.get(i) instanceof CharacterTag) { + int charId = ((CharacterTag) tags.get(i)).getCharacterId(); + needed.remove(charId); + if (needed.isEmpty()) { + return needed; + } + } + } + return needed; + } @Override public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index a9d951a2d..bf0700ee9 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -230,6 +230,7 @@ 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; @@ -373,6 +374,10 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se private TagTreeContextMenu contextPopupMenu; private static final Logger logger = Logger.getLogger(MainPanel.class.getName()); + + private Map> missingNeededCharacters = new WeakHashMap<>(); + + private Thread calculateMissingNeededThread; private class MyTreeSelectionModel extends DefaultTreeSelectionModel { @@ -882,6 +887,20 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se //Opening files with drag&drop to main window enableDrop(true); + calculateMissingNeededThread = new Thread() { + @Override + public void run() { + while(true) { + calculateMissingNeededCharacters(); + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + return; + } + } + } + }; + calculateMissingNeededThread.start(); } public void closeTagTreeSearch() { @@ -4475,5 +4494,31 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se setDropTarget(null); disposeInner(this); Helper.emptyObject(this); + if (calculateMissingNeededThread != null) { + calculateMissingNeededThread.interrupt(); + } } + + private static void calculateMissingNeededCharacters(Map> missingNeededCharacters, Timelined tim) { + for (Tag t: tim.getTags()) { + missingNeededCharacters.put(t, t.getMissingNeededCharacters()); + if (t instanceof DefineSpriteTag) { + calculateMissingNeededCharacters(missingNeededCharacters, (DefineSpriteTag) t); + } + } + } + + public void calculateMissingNeededCharacters() { + Map> missingNeededCharacters = new WeakHashMap<>(); + List swfsLists = new ArrayList<>(swfs); + for (SWFList swfList : swfsLists) { + for (SWF swf : swfList) { + calculateMissingNeededCharacters(missingNeededCharacters, swf); + } + } + this.missingNeededCharacters = missingNeededCharacters; + tagTree.setMissingNeededCharacters(missingNeededCharacters); + tagListTree.setMissingNeededCharacters(missingNeededCharacters); + } + } diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index 1d7b7ed0d..c5189d0df 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -911,3 +911,8 @@ contextmenu.showInHexDump = Show Hex dump menu.file.new = New empty new.filename = untitled + +error.missing.characterTag.single = ERROR: The tag requires character tag %tag% but it is not defined before this tag. \ +Define this character or change tag order by moving tag into proper position. +error.missing.characterTags.multi = ERROR: The tag requires character tags %tags% but they are not defined before this tag. \ +Define these characters or change tag order by moving tags into proper position. \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties index 3f033dc28..17afa9db5 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties @@ -876,4 +876,13 @@ a/nebo ActionDefineFunction/2.\r\nM\u016f\u017eete zkusit zkr\u00e1tit skript a/ contextmenu.attachTag = Nav\u00e1zat tag -contextmenu.showInHexDump = Zobrazit Hex dump \ No newline at end of file +contextmenu.showInHexDump = Zobrazit Hex dump + +menu.file.new = Nov\u00fd pr\u00e1zdn\u00fd + +new.filename = bezn\u00e1zvu + +error.missing.characterTag.single = CHYBA: Tento tag vy\u017eaduje charakterov\u00fd tag %tag%, ale ten nen\u00ed p\u0159ed t\u00edmto tagem definov\u00e1n. \ +Definujte tento charakter nebo zm\u011b\u0148te po\u0159ad\u00ed tag\u016f jeho p\u0159esunut\u00edm do spr\u00e1vn\u00e9 polohy. +error.missing.characterTags.multi = CHYBA: Tento tag vy\u017eaduje charakterov\u00e9 tagy %tags%, ale tyto nejsou p\u0159ed t\u00edmto tagem definov\u00e1ny. \ +Definujte tyto charaktery nebo zm\u011b\u0148te po\u0159ad\u00ed tag\u016f jejich p\u0159esunut\u00edm do spr\u00e1vn\u00e9 polohy. \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/taglistview/TagListTree.java b/src/com/jpexs/decompiler/flash/gui/taglistview/TagListTree.java index 1149e8beb..19b8f53c1 100644 --- a/src/com/jpexs/decompiler/flash/gui/taglistview/TagListTree.java +++ b/src/com/jpexs/decompiler/flash/gui/taglistview/TagListTree.java @@ -32,7 +32,7 @@ public class TagListTree extends AbstractTagTree { public TagListTree(TagListTreeModel model, MainPanel mainPanel) { super(model, mainPanel); - setCellRenderer(new TagListTreeCellRenderer()); + setCellRenderer(new TagListTreeCellRenderer()); } @Override diff --git a/src/com/jpexs/decompiler/flash/gui/taglistview/TagListTreeCellRenderer.java b/src/com/jpexs/decompiler/flash/gui/taglistview/TagListTreeCellRenderer.java index f541d12c1..45b02cd82 100644 --- a/src/com/jpexs/decompiler/flash/gui/taglistview/TagListTreeCellRenderer.java +++ b/src/com/jpexs/decompiler/flash/gui/taglistview/TagListTreeCellRenderer.java @@ -16,8 +16,10 @@ */ package com.jpexs.decompiler.flash.gui.taglistview; +import com.jpexs.decompiler.flash.gui.AppStrings; import com.jpexs.decompiler.flash.gui.TreeNodeType; import com.jpexs.decompiler.flash.gui.View; +import com.jpexs.decompiler.flash.gui.tagtree.AbstractTagTree; import com.jpexs.decompiler.flash.gui.tagtree.TagTree; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.timeline.Frame; @@ -26,6 +28,10 @@ import com.jpexs.decompiler.flash.treeitems.TreeItem; import java.awt.Color; import java.awt.Component; import java.awt.Font; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; import javax.swing.JLabel; import javax.swing.JTree; import javax.swing.plaf.basic.BasicLabelUI; @@ -96,6 +102,24 @@ public class TagListTreeCellRenderer extends DefaultTreeCellRenderer { setForeground(Color.BLACK); } } + setToolTipText(null); + AbstractTagTree aTree = (AbstractTagTree) tree; + Map> allMissingNeededCharacters = aTree.getMissingNeededCharacters(); + if (allMissingNeededCharacters.containsKey((TreeItem)value)) { + Set missingNeededCharacters = allMissingNeededCharacters.get(value); + if (!missingNeededCharacters.isEmpty()) { + List missingAsStr = new ArrayList<>(); + for (int v:missingNeededCharacters) { + missingAsStr.add("" + v); + } + if (missingAsStr.size() == 1) { + lab.setToolTipText(AppStrings.translate("error.missing.characterTag.single").replace("%tag%", missingAsStr.get(0))); + } else { + lab.setToolTipText(AppStrings.translate("error.missing.characterTag.multi").replace("%tags%",String.join(", ", missingAsStr))); + } + lab.setForeground(Color.red); + } + } } } return renderer; diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java b/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java index 669486311..8d5745450 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java @@ -89,6 +89,7 @@ import com.jpexs.decompiler.flash.timeline.AS3Package; import com.jpexs.decompiler.flash.timeline.Frame; import com.jpexs.decompiler.flash.timeline.FrameScript; import com.jpexs.decompiler.flash.timeline.TagScript; +import com.jpexs.decompiler.flash.timeline.Timelined; import com.jpexs.decompiler.flash.treeitems.FolderItem; import com.jpexs.decompiler.flash.treeitems.HeaderItem; import com.jpexs.decompiler.flash.treeitems.SWFList; @@ -102,8 +103,11 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; import javax.swing.Icon; import javax.swing.JTree; +import javax.swing.ToolTipManager; import javax.swing.plaf.basic.BasicTreeUI; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; @@ -118,6 +122,8 @@ public abstract class AbstractTagTree extends JTree { protected final MainPanel mainPanel; private static final Map ICONS; + + protected Map> missingNeededCharacters = new WeakHashMap<>(); static { ICONS = new HashMap<>(); @@ -129,6 +135,15 @@ public abstract class AbstractTagTree extends JTree { } } + public Map> getMissingNeededCharacters() { + return missingNeededCharacters; + } + + public void setMissingNeededCharacters(Map> missingNeededCharacters) { + this.missingNeededCharacters = missingNeededCharacters; + repaint(); + } + public static Icon getIconForType(TreeNodeType t) { return ICONS.get(t); } @@ -149,6 +164,7 @@ public abstract class AbstractTagTree extends JTree { } } }); + ToolTipManager.sharedInstance().registerComponent(this); } public static TreeNodeType getTreeNodeType(TreeItem t) { diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java index f9b141665..e657c9daf 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java @@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction; import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter; import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst; import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.gui.AppStrings; import com.jpexs.decompiler.flash.gui.MainPanel; import com.jpexs.decompiler.flash.gui.TreeNodeType; import com.jpexs.decompiler.flash.gui.View; @@ -129,6 +130,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; +import java.util.Map; +import java.util.Set; import javax.swing.JTree; import javax.swing.plaf.basic.BasicLabelUI; import javax.swing.tree.DefaultTreeCellRenderer; @@ -224,6 +227,25 @@ public class TagTree extends AbstractTagTree { setForeground(Color.BLACK); } } + setToolTipText(null); + + AbstractTagTree aTree = (AbstractTagTree) tree; + Map> allMissingNeededCharacters = aTree.getMissingNeededCharacters(); + if (allMissingNeededCharacters.containsKey((TreeItem)value)) { + Set missingNeededCharacters = allMissingNeededCharacters.get(value); + if (!missingNeededCharacters.isEmpty()) { + List missingAsStr = new ArrayList<>(); + for (int v:missingNeededCharacters) { + missingAsStr.add("" + v); + } + if (missingAsStr.size() == 1) { + setToolTipText(AppStrings.translate("error.missing.characterTag.single").replace("%tag%", missingAsStr.get(0))); + } else { + setToolTipText(AppStrings.translate("error.missing.characterTag.multi").replace("%tags%",String.join(", ", missingAsStr))); + } + setForeground(Color.red); + } + } return this; }