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 8bb230759..e60c042ab 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 @@ -40,6 +40,7 @@ import java.io.Serializable; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -108,7 +109,19 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { } public void setSwf(SWF swf) { + setSwf(swf, false); + } + + public void setSwf(SWF swf, boolean deep) { this.swf = swf; + if (deep) { + if (this instanceof DefineSpriteTag) { + DefineSpriteTag sprite = (DefineSpriteTag) this; + for (Tag subTag : sprite.subTags) { + subTag.setSwf(swf); + } + } + } } public Timelined getTimelined() { @@ -585,7 +598,7 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { public void getNeededCharactersDeep(Set needed) { Set visited = new HashSet<>(); - Set needed2 = new HashSet<>(); + Set needed2 = new LinkedHashSet<>(); getNeededCharacters(needed2); while (visited.size() != needed2.size()) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/helpers/Helper.java b/libsrc/ffdec_lib/src/com/jpexs/helpers/Helper.java index f146545ac..0544414d5 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/helpers/Helper.java +++ b/libsrc/ffdec_lib/src/com/jpexs/helpers/Helper.java @@ -384,10 +384,10 @@ public class Helper { return sb.toString(); } - public static String joinStrings(List arr, String glue) { + public static String joinStrings(Iterable arr, String glue) { StringBuilder ret = new StringBuilder(); boolean first = true; - for (String s : arr) { + for (Object s : arr) { if (!first) { ret.append(glue); } else { diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index ffc2d5b7d..e1b22ebb4 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -2685,6 +2685,15 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec previewPanel.setImageReplaceButtonVisible(false); + /*if (treeItem instanceof Tag) { + Tag tag = (Tag) treeItem; + Set needed = new HashSet<>(); + tag.getNeededCharactersDeep(needed); + String neededStr = Helper.joinStrings(needed, ", "); + // todo: it would be usefule to show this information on the UI + System.out.println("Needed characters: " + neededStr); + }*/ + boolean internalViewer = isInternalFlashViewerSelected(); if (treeItem instanceof HeaderItem) { diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java index 160b67aff..41ab0e4fe 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java @@ -46,6 +46,7 @@ import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -440,7 +441,7 @@ public class TagTreeContextMenu extends JPopupMenu { } } - private void chechUniqueCharacterId(Tag tag) { + private int chechUniqueCharacterId(Tag tag) { if (tag instanceof CharacterTag) { CharacterTag characterTag = (CharacterTag) tag; int characterId = characterTag.getCharacterId(); @@ -449,8 +450,13 @@ public class TagTreeContextMenu extends JPopupMenu { int newCharacterId = swf.getNextCharacterId(); characterTag.setCharacterId(newCharacterId); logger.log(Level.WARNING, "Target SWF already contained chatacter tag with id = {0} => id changed to {1}", new Object[]{characterId, newCharacterId}); + return newCharacterId; } + + return characterId; } + + return -1; } private void moveTagActionPerformed(ActionEvent evt, List items, SWF targetSwf) { @@ -458,7 +464,7 @@ public class TagTreeContextMenu extends JPopupMenu { for (TreeItem item : items) { Tag tag = (Tag) item; sourceSwf.tags.remove(tag); - tag.setSwf(targetSwf); + tag.setSwf(targetSwf, true); targetSwf.tags.add(tag); chechUniqueCharacterId(tag); targetSwf.updateCharacters(); @@ -483,7 +489,7 @@ public class TagTreeContextMenu extends JPopupMenu { for (TreeItem item : items) { Tag tag = (Tag) item; Tag copyTag = tag.cloneTag(); - copyTag.setSwf(targetSwf); + copyTag.setSwf(targetSwf, true); targetSwf.tags.add(copyTag); chechUniqueCharacterId(copyTag); targetSwf.updateCharacters(); @@ -503,32 +509,66 @@ public class TagTreeContextMenu extends JPopupMenu { private void copyTagWithDependenciesActionPerformed(ActionEvent evt, List items, SWF targetSwf) { try { SWF sourceSwf = items.get(0).getSwf(); - Set copiedTags = new HashSet<>(); - Set needed = new HashSet<>(); for (TreeItem item : items) { + Set copiedTags = new HashSet<>(); + Set newTags = new HashSet<>(); + LinkedHashSet needed = new LinkedHashSet<>(); + Map changedCharacterIds = new HashMap<>(); + Tag tag = (Tag) item; tag.getNeededCharactersDeep(needed); - Tag copyTag = tag.cloneTag(); - copyTag.setSwf(targetSwf); + Tag copyTag; + + List neededList = new ArrayList<>(); + for (Integer characterId : needed) { + neededList.add(characterId); + } + + // first add dependencies in reverse order + for (int i = neededList.size() - 1; i >= 0; i--) { + int characterId = neededList.get(i); + Tag neededTag = (Tag) sourceSwf.getCharacter(characterId); + if (!copiedTags.contains(neededTag)) { + copyTag = neededTag.cloneTag(); + copyTag.setSwf(targetSwf, true); + targetSwf.tags.add(copyTag); + if (neededTag instanceof CharacterTag) { + CharacterTag characterTag = (CharacterTag) copyTag; + int oldCharacterId = characterTag.getCharacterId(); + int newCharacterId = chechUniqueCharacterId(copyTag); + changedCharacterIds.put(oldCharacterId, newCharacterId); + } + + targetSwf.updateCharacters(); + targetSwf.getCharacters(); // force rebuild character id cache + copyTag.setModified(true); + copiedTags.add(neededTag); + newTags.add(copyTag); + } + } + + copyTag = tag.cloneTag(); + copyTag.setSwf(targetSwf, true); targetSwf.tags.add(copyTag); - chechUniqueCharacterId(copyTag); + if (tag instanceof CharacterTag) { + CharacterTag characterTag = (CharacterTag) copyTag; + int oldCharacterId = characterTag.getCharacterId(); + int newCharacterId = chechUniqueCharacterId(copyTag); + changedCharacterIds.put(oldCharacterId, newCharacterId); + } + targetSwf.updateCharacters(); targetSwf.getCharacters(); // force rebuild character id cache copyTag.setModified(true); copiedTags.add(tag); - } + newTags.add(copyTag); - for (Integer characterId : needed) { - Tag tag = (Tag) sourceSwf.getCharacter(characterId); - if (!copiedTags.contains(tag)) { - Tag copyTag = tag.cloneTag(); - copyTag.setSwf(targetSwf); - targetSwf.tags.add(copyTag); - chechUniqueCharacterId(copyTag); - targetSwf.updateCharacters(); - targetSwf.getCharacters(); // force rebuild character id cache - copyTag.setModified(true); - copiedTags.add(tag); + for (int oldCharacterId : changedCharacterIds.keySet()) { + int newCharacterId = changedCharacterIds.get(oldCharacterId); + for (Tag newTag : newTags) { + // todo: avoid double replaces + newTag.replaceCharacter(oldCharacterId, newCharacterId); + } } }