Frame dependencies

Show needed characters for a frame and frames depending on a character in the "Basic tag info" box
This commit is contained in:
Exund
2021-11-28 22:55:22 +01:00
committed by Jindra Petřík
parent 0da5e3c124
commit 6d656228a2
6 changed files with 121 additions and 33 deletions

View File

@@ -304,6 +304,9 @@ public final class SWF implements SWFContainerItem, Timelined {
@Internal
private volatile Map<Integer, Set<Integer>> dependentCharacters;
@Internal
private volatile Map<Integer, Set<Integer>> dependentFrames;
@Internal
private volatile List<ABCContainerTag> abcList;
@@ -488,21 +491,21 @@ public final class SWF implements SWFContainerItem, Timelined {
Map<Integer, Set<Integer>> dep = new HashMap<>();
for (Tag tag : getTags()) {
if (tag instanceof CharacterTag) {
int characterId = ((CharacterTag) tag).getCharacterId();
Set<Integer> needed = new HashSet<>();
tag.getNeededCharacters(needed);
for (Integer needed1 : needed) {
Set<Integer> s = dep.get(needed1);
if (s == null) {
s = new HashSet<>();
dep.put(needed1, s);
}
s.add(characterId);
}
}
int characterId = ((CharacterTag) tag).getCharacterId();
Set<Integer> needed = new HashSet<>();
tag.getNeededCharacters(needed);
for (Integer needed1 : needed) {
Set<Integer> s = dep.get(needed1);
if (s == null) {
s = new HashSet<>();
dep.put(needed1, s);
}
s.add(characterId);
}
}
}
dependentCharacters = dep;
}
}
@@ -545,6 +548,38 @@ public final class SWF implements SWFContainerItem, Timelined {
return dependents;
}
public void computeDependentFrames() {
Map<Integer, Set<Integer>> dep = new HashMap<>();
for (int i = 0; i < timeline.getFrameCount(); i++) {
Frame frame = timeline.getFrame(i);
Set<Integer> needed = new HashSet<>();
frame.getNeededCharacters(needed);
for (Integer needed1 : needed) {
Set<Integer> s = dep.get(needed1);
if (s == null) {
s = new HashSet<>();
dep.put(needed1, s);
}
s.add(i);
}
}
dependentFrames = dep;
}
public Set<Integer> getDependentFrames(int characterId) {
if (dependentFrames == null) {
synchronized (this) {
if (dependentFrames == null) {
computeDependentFrames();
}
}
}
return dependentFrames.get(characterId);
}
public CharacterTag getCharacter(int characterId) {
return getCharacters().get(characterId);
@@ -1446,7 +1481,7 @@ public final class SWF implements SWFContainerItem, Timelined {
}
}
public void assignExportNamesToSymbols() {
public void assignExportNamesToSymbols() {
HashMap<Integer, String> exportNames = new HashMap<>();
for (Tag t : getTags()) {
if (t instanceof ExportAssetsTag) {

View File

@@ -684,6 +684,11 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable {
tagInfo.addInfo("general", "dependentCharacters", Helper.joinStrings(dependent, ", "));
}
}
Set<Integer> dependent2 = swf.getDependentFrames(characterId);
if(dependent2 != null && dependent2.size() > 0) {
tagInfo.addInfo("general", "dependentFrames", Helper.joinStrings(dependent2, ", "));
}
}
}
}

View File

@@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.tags.ShowFrameTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.base.ASMSourceContainer;
import com.jpexs.decompiler.flash.tags.base.Exportable;
import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag;
import com.jpexs.decompiler.flash.treeitems.TreeItem;
import com.jpexs.decompiler.flash.types.RGB;
import com.jpexs.decompiler.flash.types.RGBA;
@@ -29,6 +30,7 @@ import com.jpexs.decompiler.flash.types.SOUNDINFO;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
/**
@@ -133,4 +135,13 @@ public class Frame implements TreeItem, Exportable {
}
return false;
}
public void getNeededCharacters(Set<Integer> needed) {
for (Tag t : innerTags) {
if(t instanceof PlaceObjectTypeTag) {
needed.add(((PlaceObjectTypeTag)t).getCharacterId());
}
}
needed.remove(-1);
}
}

View File

@@ -1120,7 +1120,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
tagTree.clearSelection();
for (TreeItem n : nodes) {
if (n instanceof ClassesListTreeModel) {
String filterText = filterField.getText();
String filterText = filterField.getText();
((ClassesListTreeModel) n).setFilter(filterText);
TagTreeModel tm = tagTree.getModel();
TreePath path = tm.getTreePath(n);
@@ -3723,6 +3723,20 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
} 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();
tagInfo.addInfo("general", "neededCharacters", Helper.joinStrings(needed, ", "));
tagInfoPanel.setTagInfos(tagInfo);
showDetail(DETAILCARDTAGINFO);
} else {
showDetail(DETAILCARDEMPTYPANEL);
}
} else {
showDetail(DETAILCARDEMPTYPANEL);
}

View File

@@ -16,11 +16,14 @@
*/
package com.jpexs.decompiler.flash.gui;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.tags.TagInfo;
import com.jpexs.decompiler.flash.treeitems.TreeItem;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -62,11 +65,25 @@ public class TagInfoPanel extends JPanel {
public void hyperlinkUpdate(HyperlinkEvent hyperLink) {
if (HyperlinkEvent.EventType.ACTIVATED.equals(hyperLink.getEventType())) {
String url = hyperLink.getDescription();
String strId = url.substring(7);
Integer id = Integer.parseInt(strId);
URI url;
try {
url = new URI(hyperLink.getDescription());
} catch (Exception ex) {
return;
}
mainPanel.setTagTreeSelectedNode(mainPanel.getCurrentSwf().getCharacter(id));
String scheme = url.getScheme();
String strId = url.getHost();
Integer id = Integer.parseInt(strId);
SWF swf = mainPanel.getCurrentSwf();
TreeItem item = null;
if ("char".equals(scheme)) {
item = swf.getCharacter(id);
} else if ("frame".equals(scheme)) {
item = swf.getTimeline().getFrame(id);
}
mainPanel.setTagTreeSelectedNode(item);
}
}
@@ -92,16 +109,17 @@ public class TagInfoPanel extends JPanel {
} else {
result += "</tr>";
}
result += "<td width='50%' style='text-align:center;'>";
result += mainPanel.translate("tagInfo.header.name");
result += "</td>";
result += "<td width='50%' style='text-align:center;'>";
result += mainPanel.translate("tagInfo.header.value");
result += "</td>";
result += String.format(
"<td width='50%%' style='text-align:center;'>%s</td>",
mainPanel.translate("tagInfo.header.name")
);
result += String.format(
"<td width='50%%' style='text-align:center;'>%s</td>",
mainPanel.translate("tagInfo.header.value")
);
result += "</tr>";
for (TagInfo.TagInfoItem item : items) {
Boolean convertToCharacterList;
flipFlop = !flipFlop;
@@ -114,7 +132,8 @@ public class TagInfoPanel extends JPanel {
String name = item.getName();
String key = "tagInfo." + name;
convertToCharacterList = name.equals("dependentCharacters") || name.equals("neededCharacters");
boolean frameList = name.equals("dependentFrames");
boolean convertToLinkList = name.equals("dependentCharacters") || name.equals("neededCharacters") || frameList;
try {
name = mainPanel.translate(key);
@@ -130,11 +149,10 @@ public class TagInfoPanel extends JPanel {
if (value instanceof Boolean) {
boolean boolValue = (boolean) value;
value = boolValue ? AppStrings.translate("yes") : AppStrings.translate("no");
} else if (convertToCharacterList) {
String strValue = (String) value;
String[] strIds = strValue.split(", ");
} else if (convertToLinkList) {
String[] strIds = ((String) value).split(", ");
List<Integer> sortedIds = new ArrayList<>();
strValue = "";
String strValue = "";
for (String strId : strIds) {
sortedIds.add(Integer.parseInt(strId));
@@ -142,8 +160,11 @@ public class TagInfoPanel extends JPanel {
Collections.sort(sortedIds);
String scheme = frameList ? "frame" : "char";
for (int id : sortedIds) {
strValue += "<a href='jump://" + id + "'>" + id + "</a>, ";
int displayId = frameList ? id + 1 : id;
strValue += String.format("<a href='%s://%d'>%d</a>, ", scheme, id, displayId);
}
value = strValue.substring(0, strValue.length() - 2);

View File

@@ -844,4 +844,6 @@ message.info.importSymbolClass = During importing Symbol-Class, you need to sele
This is the same filename as it is used when exported.
message.info.importXml = For XML importing, you need a XML file in special format - the format in which FFDec exports.\r\n \
The best way to create such XML file is to export XML from existing SWF first.
The best way to create such XML file is to export XML from existing SWF first.
tagInfo.dependentFrames = Dependent Frames