diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java index 68a640f33..324bdf93c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -153,6 +153,7 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.EmptyStackException; import java.util.HashMap; import java.util.HashSet; @@ -179,7 +180,7 @@ public final class SWF implements SWFContainerItem, Timelined { * Default version of SWF file format */ public static final int DEFAULT_VERSION = 10; - + /** * Maximum SWF file format version * Needs to be fixed when SWF versions reaches this value @@ -358,7 +359,7 @@ public final class SWF implements SWFContainerItem, Timelined { if (characters == null) { Map chars = new HashMap<>(); parseCharacters(tags, chars); - characters = chars; + characters = Collections.unmodifiableMap(chars); } } } @@ -506,10 +507,12 @@ public final class SWF implements SWFContainerItem, Timelined { } public void resetTimelines(Timelined timelined) { - timelined.getTimeline().reset(); - for (Tag t : timelined.getTimeline().tags) { - if (t instanceof Timelined) { - resetTimelines((Timelined) t); + timelined.resetTimeline(); + if (timelined instanceof SWF) { + for (Tag t : ((SWF) timelined).tags) { + if (t instanceof Timelined) { + resetTimelines((Timelined) t); + } } } } @@ -570,6 +573,13 @@ public final class SWF implements SWFContainerItem, Timelined { return timeline; } + @Override + public void resetTimeline() { + if (timeline != null) { + timeline.reset(this); + } + } + /** * Gets all tags with specified id * @@ -869,9 +879,7 @@ public final class SWF implements SWFContainerItem, Timelined { this.tags = tags; if (!checkOnly) { checkInvalidSprites(); - Map chars = new HashMap<>(); - parseCharacters(tags, chars); - characters = chars; + updateCharacters(); assignExportNamesToSymbols(); assignClassesToSymbols(); SWFDecompilerPlugin.fireSwfParsed(this); @@ -2381,14 +2389,14 @@ public final class SWF implements SWFContainerItem, Timelined { if (drawableFrameCount == 0) { drawableFrameCount = 1; } - + int dframe; if (timeline.fontFrameNum != -1) { dframe = timeline.fontFrameNum; } else { dframe = (time + layer.time) % drawableFrameCount; } - + if (character instanceof ButtonTag) { dframe = ButtonTag.FRAME_UP; if (renderContext.stateUnderCursor == layer) { @@ -2731,7 +2739,7 @@ public final class SWF implements SWFContainerItem, Timelined { DefineSpriteTag sprite = (DefineSpriteTag) timelined; sprite.setModified(true); } - timelined.getTimeline().reset(); + timelined.resetTimeline(); } else { // timeline should be always the swf here if (removeDependencies) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java index 3865662bc..e611739a9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java @@ -188,6 +188,22 @@ public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer { } } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = false; + for (int i = 0; i < characters.size(); i++) { + BUTTONRECORD character = characters.get(i); + if (character.characterId == oldCharacterId) { + character.characterId = newCharacterId; + modified = true; + } + } + if (modified) { + setModified(true); + } + return modified; + } + @Override public boolean removeCharacter(int characterId) { boolean modified = false; @@ -269,7 +285,19 @@ public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer { } timeline = new Timeline(swf, this, new ArrayList(), buttonId, getRect()); + initTimeline(timeline); + return timeline; + } + @Override + public void resetTimeline() { + if (timeline != null) { + timeline.reset(swf, this, new ArrayList(), buttonId, getRect()); + initTimeline(timeline); + } + } + + private void initTimeline(Timeline timeline) { int maxDepth = 0; Frame frameUp = new Frame(timeline, 0); Frame frameDown = new Frame(timeline, 0); @@ -321,7 +349,6 @@ public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer { } timeline.addFrame(frameHit); - return timeline; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java index ab9c740ec..715f6afc2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java @@ -239,6 +239,22 @@ public class DefineButtonTag extends ButtonTag implements ASMSource { } } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = false; + for (int i = 0; i < characters.size(); i++) { + BUTTONRECORD character = characters.get(i); + if (character.characterId == oldCharacterId) { + character.characterId = newCharacterId; + modified = true; + } + } + if (modified) { + setModified(true); + } + return modified; + } + @Override public boolean removeCharacter(int characterId) { boolean modified = false; @@ -351,8 +367,21 @@ public class DefineButtonTag extends ButtonTag implements ASMSource { if (timeline != null) { return timeline; } - timeline = new Timeline(swf, this, new ArrayList(), buttonId, getRect()); + timeline = new Timeline(swf, this, new ArrayList(), buttonId, getRect()); + initTimeline(timeline); + return timeline; + } + + @Override + public void resetTimeline() { + if (timeline != null) { + timeline.reset(swf, this, new ArrayList(), buttonId, getRect()); + initTimeline(timeline); + } + } + + private void initTimeline(Timeline timeline) { ColorTransform clrTrans = null; for (Tag t : swf.tags) { if (t instanceof DefineButtonCxformTag) { @@ -405,8 +434,6 @@ public class DefineButtonTag extends ButtonTag implements ASMSource { frameHit = frameUp; } timeline.addFrame(frameHit); - - return timeline; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java index 4601bf266..267253c0b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java @@ -879,6 +879,16 @@ public class DefineEditTextTag extends TextTag { } } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + if (fontId == oldCharacterId) { + fontId = newCharacterId; + setModified(true); + return true; + } + return false; + } + @Override public boolean removeCharacter(int characterId) { if (fontId == characterId) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java index ebbfd2c77..4a19b04b3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java @@ -101,6 +101,18 @@ public class DefineMorphShape2Tag extends MorphShapeTag { endEdges.getNeededCharacters(needed); } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = false; + modified |= morphFillStyles.replaceCharacter(oldCharacterId, newCharacterId); + modified |= startEdges.replaceCharacter(oldCharacterId, newCharacterId); + modified |= endEdges.replaceCharacter(oldCharacterId, newCharacterId); + if (modified) { + setModified(true); + } + return modified; + } + @Override public boolean removeCharacter(int characterId) { boolean modified = false; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java index 7f71e94f7..972c1a475 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java @@ -88,6 +88,18 @@ public class DefineMorphShapeTag extends MorphShapeTag { endEdges.getNeededCharacters(needed); } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = false; + modified |= morphFillStyles.replaceCharacter(oldCharacterId, newCharacterId); + modified |= startEdges.replaceCharacter(oldCharacterId, newCharacterId); + modified |= endEdges.replaceCharacter(oldCharacterId, newCharacterId); + if (modified) { + setModified(true); + } + return modified; + } + @Override public boolean removeCharacter(int characterId) { boolean modified = false; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java index 1ca802a10..4eec5bbc7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java @@ -72,6 +72,15 @@ public class DefineShape2Tag extends ShapeTag { getShapes().getNeededCharacters(needed); } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId); + if (modified) { + setModified(true); + } + return modified; + } + @Override public boolean removeCharacter(int characterId) { boolean modified = getShapes().removeCharacter(characterId); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java index 14319392e..5d3342f4c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java @@ -72,6 +72,15 @@ public class DefineShape3Tag extends ShapeTag { getShapes().getNeededCharacters(needed); } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId); + if (modified) { + setModified(true); + } + return modified; + } + @Override public boolean removeCharacter(int characterId) { boolean modified = getShapes().removeCharacter(characterId); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java index 8a53527a7..85b8f4993 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java @@ -85,6 +85,15 @@ public class DefineShape4Tag extends ShapeTag { getShapes().getNeededCharacters(needed); } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId); + if (modified) { + setModified(true); + } + return modified; + } + @Override public boolean removeCharacter(int characterId) { boolean modified = getShapes().removeCharacter(characterId); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java index 294add1c6..6f551fdc6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java @@ -71,6 +71,15 @@ public class DefineShapeTag extends ShapeTag { getShapes().getNeededCharacters(needed); } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId); + if (modified) { + setModified(true); + } + return modified; + } + @Override public boolean removeCharacter(int characterId) { boolean modified = getShapes().removeCharacter(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 a71e902b3..221100093 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 @@ -93,6 +93,13 @@ public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timeli return timeline; } + @Override + public void resetTimeline() { + if (timeline != null) { + timeline.reset(swf, this, subTags, spriteId, getRect()); + } + } + @Override public int getCharacterId() { return spriteId; @@ -288,6 +295,15 @@ public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timeli } } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = getTimeline().replaceCharacter(oldCharacterId, newCharacterId); + if (modified) { + setModified(true); + } + return modified; + } + @Override public boolean removeCharacter(int characterId) { boolean modified = getTimeline().removeCharacter(characterId); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java index b2b1e42fa..b6028b84c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java @@ -579,6 +579,21 @@ public class DefineText2Tag extends TextTag { } } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = false; + for (TEXTRECORD tr : textRecords) { + if (tr.fontId == oldCharacterId) { + tr.fontId = newCharacterId; + modified = true; + } + } + if (modified) { + setModified(true); + } + return modified; + } + @Override public boolean removeCharacter(int characterId) { boolean modified = false; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java index aa99a563a..a8dbde91d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java @@ -591,6 +591,21 @@ public class DefineTextTag extends TextTag { } } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = false; + for (TEXTRECORD tr : textRecords) { + if (tr.fontId == oldCharacterId) { + tr.fontId = newCharacterId; + modified = true; + } + } + if (modified) { + setModified(true); + } + return modified; + } + @Override public boolean removeCharacter(int characterId) { boolean modified = false; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java index c72e9c089..4804c8c94 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject2Tag.java @@ -303,6 +303,11 @@ public class PlaceObject2Tag extends PlaceObjectTypeTag implements ASMSourceCont } } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + return false; + } + @Override public boolean removeCharacter(int characterId) { // the place object tag will be removed diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java index b4e7365e3..2b1a53016 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject3Tag.java @@ -438,6 +438,11 @@ public class PlaceObject3Tag extends PlaceObjectTypeTag implements ASMSourceCont } } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + return false; + } + @Override public boolean removeCharacter(int characterId) { // the place object tag will be removed diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java index aa94232e8..95930e580 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObject4Tag.java @@ -441,6 +441,11 @@ public class PlaceObject4Tag extends PlaceObjectTypeTag implements ASMSourceCont } } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + return false; + } + @Override public boolean removeCharacter(int characterId) { // the place object tag will be removed diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java index f9f887349..ad0e374de 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/PlaceObjectTag.java @@ -146,6 +146,11 @@ public class PlaceObjectTag extends PlaceObjectTypeTag { needed.add(characterId); } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + return false; + } + @Override public boolean removeCharacter(int characterId) { // the place object tag will be removed 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 8986151b9..8bb230759 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 @@ -573,6 +573,11 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable { public void getNeededCharacters(Set needed) { } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + return false; + } + @Override public boolean removeCharacter(int characterId) { return false; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/NeedsCharacters.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/NeedsCharacters.java index 91dcde7c6..ce7c52d85 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/NeedsCharacters.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/NeedsCharacters.java @@ -1,18 +1,19 @@ /* * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.tags.base; import java.util.Set; @@ -25,5 +26,7 @@ public interface NeedsCharacters { public void getNeededCharacters(Set needed); + public boolean replaceCharacter(int oldCharacterId, int newCharacterId); + public boolean removeCharacter(int characterId); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java index b9a340003..4c04c42a6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java @@ -133,6 +133,11 @@ public abstract class ShapeTag extends CharacterTag implements DrawableTag, Lazy getShapes().getNeededCharacters(needed); } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + return getShapes().replaceCharacter(oldCharacterId, newCharacterId); + } + @Override public boolean removeCharacter(int characterId) { return getShapes().removeCharacter(characterId); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java index 6ba93029e..ad1ae3204 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java @@ -72,7 +72,7 @@ public class Timeline { public int maxDepth; public int fontFrameNum = -1; - + public List tags; private final List frames = new ArrayList<>(); @@ -124,7 +124,11 @@ public class Timeline { return depthMaxFrame; } - public void reset() { + public void reset(SWF swf) { + reset(swf, null, swf.tags, 0, swf.displayRect); + } + + public void reset(SWF swf, Tag parentTag, List tags, int id, RECT displayRect) { initialized = false; frames.clear(); depthMaxFrame.clear(); @@ -132,6 +136,13 @@ public class Timeline { asmSourceContainers.clear(); actionFrames.clear(); otherTags.clear(); + this.id = id; + this.swf = swf; + this.displayRect = displayRect; + this.frameRate = swf.frameRate; + this.timelined = parentTag == null ? swf : (Timelined) parentTag; + this.parentTag = parentTag; + this.tags = tags; as2RootPackage = new AS2Package(null, null, swf); } @@ -425,6 +436,18 @@ public class Timeline { } } + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = false; + for (int i = 0; i < tags.size(); i++) { + Tag t = tags.get(i); + if (t instanceof CharacterIdTag && ((CharacterIdTag) t).getCharacterId() == oldCharacterId) { + ((CharacterIdTag) t).setCharacterId(newCharacterId); + modified = true; + } + } + return modified; + } + public boolean removeCharacter(int characterId) { boolean modified = false; for (int i = 0; i < tags.size(); i++) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timelined.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timelined.java index 7f3cd6544..d6ac774ff 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timelined.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timelined.java @@ -1,18 +1,19 @@ /* * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.timeline; import com.jpexs.decompiler.flash.tags.base.BoundedTag; @@ -24,4 +25,6 @@ import com.jpexs.decompiler.flash.tags.base.BoundedTag; public interface Timelined extends BoundedTag { public Timeline getTimeline(); + + public void resetTimeline(); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLE.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLE.java index 873690ff5..22c928fb9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLE.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLE.java @@ -79,6 +79,15 @@ public class FILLSTYLE implements NeedsCharacters, Serializable { } } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + if (bitmapId == oldCharacterId) { + bitmapId = newCharacterId; + return true; + } + return false; + } + @Override public boolean removeCharacter(int characterId) { if (bitmapId == characterId) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLEARRAY.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLEARRAY.java index 6dbf918a0..68890711f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLEARRAY.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLEARRAY.java @@ -1,18 +1,19 @@ /* * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.types; import com.jpexs.decompiler.flash.tags.base.NeedsCharacters; @@ -34,6 +35,15 @@ public class FILLSTYLEARRAY implements NeedsCharacters, Serializable { } } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = false; + for (FILLSTYLE fs : fillStyles) { + modified |= fs.replaceCharacter(oldCharacterId, newCharacterId); + } + return modified; + } + @Override public boolean removeCharacter(int characterId) { boolean modified = false; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE.java index ad6296fa4..d1558e226 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE.java @@ -1,18 +1,19 @@ /* * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.types; import com.jpexs.decompiler.flash.tags.DefineShape3Tag; @@ -39,6 +40,11 @@ public class LINESTYLE implements NeedsCharacters, Serializable { public void getNeededCharacters(Set needed) { } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + return false; + } + @Override public boolean removeCharacter(int characterId) { return false; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java index 95c0b2177..599622932 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java @@ -76,6 +76,14 @@ public class LINESTYLE2 extends LINESTYLE implements Serializable { } } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + if (fillType != null) { + return fillType.replaceCharacter(oldCharacterId, newCharacterId); + } + return false; + } + @Override public boolean removeCharacter(int characterId) { if (fillType != null) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLEARRAY.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLEARRAY.java index c9ad56beb..10c80a7a6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLEARRAY.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLEARRAY.java @@ -1,18 +1,19 @@ /* * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.types; import com.jpexs.decompiler.flash.tags.base.NeedsCharacters; @@ -34,6 +35,15 @@ public class LINESTYLEARRAY implements NeedsCharacters, Serializable { } } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = false; + for (LINESTYLE ls : lineStyles) { + modified |= ls.replaceCharacter(oldCharacterId, newCharacterId); + } + return modified; + } + @Override public boolean removeCharacter(int characterId) { boolean modified = false; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLE.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLE.java index 4a1183eb4..d8b3bc2c3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLE.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLE.java @@ -81,6 +81,15 @@ public class MORPHFILLSTYLE implements NeedsCharacters, Serializable { } } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + if (bitmapId == oldCharacterId) { + bitmapId = newCharacterId; + return true; + } + return false; + } + @Override public boolean removeCharacter(int characterId) { if (bitmapId == characterId) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLEARRAY.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLEARRAY.java index 0fa3b606f..22ecac31b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLEARRAY.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLEARRAY.java @@ -1,18 +1,19 @@ /* * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.types; import com.jpexs.decompiler.flash.tags.base.NeedsCharacters; @@ -34,6 +35,15 @@ public class MORPHFILLSTYLEARRAY implements NeedsCharacters, Serializable { } } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = false; + for (MORPHFILLSTYLE fs : fillStyles) { + modified |= fs.replaceCharacter(oldCharacterId, newCharacterId); + } + return modified; + } + @Override public boolean removeCharacter(int characterId) { boolean modified = false; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPE.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPE.java index 899c89e8d..4b157c6f8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPE.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPE.java @@ -52,6 +52,15 @@ public class SHAPE implements NeedsCharacters, Serializable { } } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = false; + for (SHAPERECORD r : shapeRecords) { + modified |= r.replaceCharacter(oldCharacterId, newCharacterId); + } + return modified; + } + @Override public boolean removeCharacter(int characterId) { boolean modified = false; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java index 0952c0733..bee109c95 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java @@ -42,6 +42,17 @@ public class SHAPEWITHSTYLE extends SHAPE implements NeedsCharacters, Serializab } } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = false; + modified |= fillStyles.replaceCharacter(oldCharacterId, newCharacterId); + modified |= lineStyles.replaceCharacter(oldCharacterId, newCharacterId); + for (SHAPERECORD r : shapeRecords) { + modified |= r.replaceCharacter(oldCharacterId, newCharacterId); + } + return modified; + } + @Override public boolean removeCharacter(int characterId) { boolean modified = false; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java index ae5872c9b..f0c0bd123 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java @@ -59,6 +59,11 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali public void getNeededCharacters(Set needed) { } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + return false; + } + @Override public boolean removeCharacter(int characterId) { return false; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/StyleChangeRecord.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/StyleChangeRecord.java index 1c9be0e2f..290eedf41 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/StyleChangeRecord.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/shaperecords/StyleChangeRecord.java @@ -89,6 +89,14 @@ public final class StyleChangeRecord extends SHAPERECORD implements Cloneable { } } + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + if (fillStyles != null) { + return fillStyles.replaceCharacter(oldCharacterId, newCharacterId); + } + return false; + } + @Override public boolean removeCharacter(int characterId) { if (fillStyles != null) { diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 95e451ccc..ffc2d5b7d 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -850,7 +850,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec } } - refreshTree(null); + refreshTree(); if (updateNeeded) { View.execInEventDispatch(() -> { @@ -1090,42 +1090,42 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec ret.addAll(new ImageExporter().exportImages(handler, selFile + File.separator + "images", images, new ImageExportSettings(export.getValue(ImageExportMode.class)), evl)); } - + if (export.isOptionEnabled(ShapeExportMode.class)) { ret.addAll(new ShapeExporter().exportShapes(handler, selFile + File.separator + "shapes", shapes, new ShapeExportSettings(export.getValue(ShapeExportMode.class), export.getZoom()), evl)); } - + if (export.isOptionEnabled(MorphShapeExportMode.class)) { ret.addAll(new MorphShapeExporter().exportMorphShapes(handler, selFile + File.separator + "morphshapes", morphshapes, new MorphShapeExportSettings(export.getValue(MorphShapeExportMode.class), export.getZoom()), evl)); } - + if (export.isOptionEnabled(TextExportMode.class)) { ret.addAll(new TextExporter().exportTexts(handler, selFile + File.separator + TextExportSettings.EXPORT_FOLDER_NAME, texts, new TextExportSettings(export.getValue(TextExportMode.class), Configuration.textExportSingleFile.get(), export.getZoom()), evl)); } - + if (export.isOptionEnabled(MovieExportMode.class)) { ret.addAll(new MovieExporter().exportMovies(handler, selFile + File.separator + "movies", movies, new MovieExportSettings(export.getValue(MovieExportMode.class)), evl)); } - + if (export.isOptionEnabled(SoundExportMode.class)) { ret.addAll(new SoundExporter().exportSounds(handler, selFile + File.separator + "sounds", sounds, new SoundExportSettings(export.getValue(SoundExportMode.class)), evl)); } - + if (export.isOptionEnabled(BinaryDataExportMode.class)) { ret.addAll(new BinaryDataExporter().exportBinaryData(handler, selFile + File.separator + "binaryData", binaryData, new BinaryDataExportSettings(export.getValue(BinaryDataExportMode.class)), evl)); } - + if (export.isOptionEnabled(FontExportMode.class)) { ret.addAll(new FontExporter().exportFonts(handler, selFile + File.separator + "fonts", fonts, new FontExportSettings(export.getValue(FontExportMode.class)), evl)); } - + if (export.isOptionEnabled(SymbolClassExportMode.class)) { ret.addAll(new SymbolClassExporter().exportNames(selFile, symbolNames, evl)); } @@ -1176,7 +1176,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec } } } - + return ret; } @@ -1187,42 +1187,42 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec new ImageExporter().exportImages(handler, selFile + File.separator + "images", swf.tags, new ImageExportSettings(export.getValue(ImageExportMode.class)), evl); } - + if (export.isOptionEnabled(ShapeExportMode.class)) { new ShapeExporter().exportShapes(handler, selFile + File.separator + "shapes", swf.tags, new ShapeExportSettings(export.getValue(ShapeExportMode.class), export.getZoom()), evl); } - + if (export.isOptionEnabled(MorphShapeExportMode.class)) { new MorphShapeExporter().exportMorphShapes(handler, selFile + File.separator + "morphshapes", swf.tags, new MorphShapeExportSettings(export.getValue(MorphShapeExportMode.class), export.getZoom()), evl); } - + if (export.isOptionEnabled(TextExportMode.class)) { new TextExporter().exportTexts(handler, selFile + File.separator + TextExportSettings.EXPORT_FOLDER_NAME, swf.tags, new TextExportSettings(export.getValue(TextExportMode.class), Configuration.textExportSingleFile.get(), export.getZoom()), evl); } - + if (export.isOptionEnabled(MovieExportMode.class)) { new MovieExporter().exportMovies(handler, selFile + File.separator + "movies", swf.tags, new MovieExportSettings(export.getValue(MovieExportMode.class)), evl); } - + if (export.isOptionEnabled(SoundExportMode.class)) { new SoundExporter().exportSounds(handler, selFile + File.separator + "sounds", swf.tags, new SoundExportSettings(export.getValue(SoundExportMode.class)), evl); } - + if (export.isOptionEnabled(BinaryDataExportMode.class)) { new BinaryDataExporter().exportBinaryData(handler, selFile + File.separator + "binaryData", swf.tags, new BinaryDataExportSettings(export.getValue(BinaryDataExportMode.class)), evl); } - + if (export.isOptionEnabled(FontExportMode.class)) { new FontExporter().exportFonts(handler, selFile + File.separator + "fonts", swf.tags, new FontExportSettings(export.getValue(FontExportMode.class)), evl); } - + if (export.isOptionEnabled(SymbolClassExportMode.class)) { new SymbolClassExporter().exportNames(selFile, swf.tags, evl); } @@ -2091,24 +2091,23 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec } public void refreshTree() { - refreshTree(null); + refreshTree(new SWF[0]); } public void refreshTree(SWF swf) { + refreshTree(new SWF[]{swf}); + } + + public void refreshTree(SWF[] swfs) { clear(); showCard(CARDEMPTYPANEL); TreeItem treeItem = tagTree.getCurrentTreeItem(); - TagTreeModel ttm = tagTree.getModel(); - if (ttm != null) { - List> expandedNodes = View.getExpandedNodes(tagTree); - ttm.updateSwf(swf); - View.expandTreeNodes(tagTree, expandedNodes); - } + tagTree.updateSwfs(swfs); if (treeItem != null) { SWF treeItemSwf = treeItem.getSwf().getRootSwf(); - if (swfs.contains(treeItemSwf.swfList)) { + if (this.swfs.contains(treeItemSwf.swfList)) { setTagTreeSelectedNode(treeItem); } } @@ -2902,7 +2901,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec public static Timelined makeTimelined(final Tag tag) { return makeTimelined(tag, -1); } - + public static Timelined makeTimelined(final Tag tag, final int fontFrameNum) { return new Timelined() { @@ -2915,6 +2914,19 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec return tim; } tim = new Timeline(tag.getSwf(), null, new ArrayList<>(), ((CharacterTag) tag).getCharacterId(), getRect()); + initTimeline(tim); + return tim; + } + + @Override + public void resetTimeline() { + if (tim != null) { + tim.reset(tag.getSwf(), null, new ArrayList<>(), ((CharacterTag) tag).getCharacterId(), getRect()); + initTimeline(tim); + } + } + + private void initTimeline(Timeline timeline) { if (tag instanceof MorphShapeTag) { tim.frameRate = MORPH_SHAPE_ANIMATION_FRAME_RATE; int framesCnt = tim.frameRate * MORPH_SHAPE_ANIMATION_LENGTH; @@ -2934,7 +2946,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec if (frame < 0 || frame >= pageCount) { frame = 0; } - + Frame f = new Frame(tim, 0); DepthState ds = new DepthState(tag.getSwf(), f); ds.characterId = ((CharacterTag) tag).getCharacterId(); @@ -2952,7 +2964,6 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec tim.addFrame(f); } tim.displayRect = getRect(); - return tim; } @Override diff --git a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java index a17ac5ae6..983a56687 100644 --- a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java @@ -1190,7 +1190,7 @@ public class PreviewPanel extends JSplitPane implements ActionListener { SWF swf = tag.getSwf(); swf.clearImageCache(); swf.updateCharacters(); - tag.getTimelined().getTimeline().reset(); + tag.getTimelined().resetTimeline(); mainPanel.repaintTree(); mainPanel.setTagTreeSelectedNode(tag); genericEditButton.setVisible(true); diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagIdClassMap.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagIdClassMap.java index e543d6ffa..d7144b555 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagIdClassMap.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagIdClassMap.java @@ -1,16 +1,16 @@ /* * Copyright (C) 2010-2015 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 . */ @@ -104,7 +104,7 @@ import java.util.Map; */ public class TagIdClassMap { - private static final Map tagIdClassMap = new HashMap<>(); + private static final Map> tagIdClassMap = new HashMap<>(); private static final Map classTagIdMap = new HashMap<>(); @@ -190,12 +190,12 @@ public class TagIdClassMap { addTag(FontTextureInfo.ID, FontTextureInfo.class); } - private static void addTag(int tagId, Class cl) { + private static void addTag(int tagId, Class cl) { tagIdClassMap.put(tagId, cl); classTagIdMap.put(cl, tagId); } - public static Class getClassByTagId(int tagId) { + public static Class getClassByTagId(int tagId) { return tagIdClassMap.get(tagId); } diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java index 385c2e002..3c602a113 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java @@ -593,6 +593,15 @@ public class TagTree extends JTree { return item; } + public void updateSwfs(SWF[] swfs) { + TagTreeModel ttm = getModel(); + if (ttm != null) { + List> expandedNodes = View.getExpandedNodes(this); + ttm.updateSwf(null); // todo: honfika: update only the changed swfs, but there was an exception when i tried it + View.expandTreeNodes(this, expandedNodes); + } + } + @Override public TagTreeModel getModel() { return (TagTreeModel) super.getModel(); diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java index 1ef3d59d9..160b67aff 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java @@ -64,6 +64,8 @@ import javax.swing.tree.TreePath; */ public class TagTreeContextMenu extends JPopupMenu { + private static final Logger logger = Logger.getLogger(TagTreeContextMenu.class.getName()); + private final MainPanel mainPanel; private final TagTree tagTree; @@ -336,7 +338,7 @@ public class TagTreeContextMenu extends JPopupMenu { addTagMenu.removeAll(); if (allowedTagTypes != null) { for (Integer tagId : allowedTagTypes) { - final Class cl = TagIdClassMap.getClassByTagId(tagId); + final Class cl = TagIdClassMap.getClassByTagId(tagId); JMenuItem tagItem = new JMenuItem(cl.getSimpleName()); tagItem.addActionListener((ActionEvent ae) -> { addTagActionPerformed(ae, firstItem, cl); @@ -368,13 +370,13 @@ public class TagTreeContextMenu extends JPopupMenu { if (targetSwf != singleSwf) { JMenuItem swfItem = new JMenuItem(targetSwf.getShortFileName()); swfItem.addActionListener((ActionEvent ae) -> { - copyTagActionPerformed(ae, items, targetSwf); + moveTagActionPerformed(ae, items, targetSwf); }); moveTagMenu.add(swfItem); swfItem = new JMenuItem(targetSwf.getShortFileName()); swfItem.addActionListener((ActionEvent ae) -> { - moveTagActionPerformed(ae, items, targetSwf); + copyTagActionPerformed(ae, items, targetSwf); }); copyTagMenu.add(swfItem); @@ -406,7 +408,7 @@ public class TagTreeContextMenu extends JPopupMenu { } } - private void addTagActionPerformed(ActionEvent evt, TreeItem firstItem, Class cl) { + private void addTagActionPerformed(ActionEvent evt, TreeItem firstItem, Class cl) { try { SWF swf = firstItem.getSwf(); Tag t = (Tag) cl.getDeclaredConstructor(SWF.class).newInstance(new Object[]{swf}); @@ -430,14 +432,27 @@ public class TagTreeContextMenu extends JPopupMenu { swf.tags.add(t); } } - timelined.getTimeline().reset(); + timelined.resetTimeline(); swf.updateCharacters(); mainPanel.refreshTree(swf); } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException ex) { - Logger.getLogger(TagTreeContextMenu.class.getName()).log(Level.SEVERE, null, ex); + logger.log(Level.SEVERE, null, ex); } } - + + private void chechUniqueCharacterId(Tag tag) { + if (tag instanceof CharacterTag) { + CharacterTag characterTag = (CharacterTag) tag; + int characterId = characterTag.getCharacterId(); + SWF swf = tag.getSwf(); + if (swf.getCharacter(characterId) != null) { + 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}); + } + } + } + private void moveTagActionPerformed(ActionEvent evt, List items, SWF targetSwf) { SWF sourceSwf = items.get(0).getSwf(); for (TreeItem item : items) { @@ -445,6 +460,8 @@ public class TagTreeContextMenu extends JPopupMenu { sourceSwf.tags.remove(tag); tag.setSwf(targetSwf); targetSwf.tags.add(tag); + chechUniqueCharacterId(tag); + targetSwf.updateCharacters(); tag.setModified(true); } @@ -456,9 +473,11 @@ public class TagTreeContextMenu extends JPopupMenu { targetSwf.clearImageCache(); sourceSwf.updateCharacters(); targetSwf.updateCharacters(); - mainPanel.refreshTree(null); // refresh all opened swfs + sourceSwf.resetTimelines(sourceSwf); + targetSwf.resetTimelines(targetSwf); + mainPanel.refreshTree(new SWF[]{sourceSwf, targetSwf}); } - + private void copyTagActionPerformed(ActionEvent evt, List items, SWF targetSwf) { try { for (TreeItem item : items) { @@ -466,6 +485,8 @@ public class TagTreeContextMenu extends JPopupMenu { Tag copyTag = tag.cloneTag(); copyTag.setSwf(targetSwf); targetSwf.tags.add(copyTag); + chechUniqueCharacterId(copyTag); + targetSwf.updateCharacters(); copyTag.setModified(true); } @@ -475,10 +496,10 @@ public class TagTreeContextMenu extends JPopupMenu { targetSwf.updateCharacters(); mainPanel.refreshTree(targetSwf); } catch (IOException | InterruptedException ex) { - Logger.getLogger(TagTreeContextMenu.class.getName()).log(Level.SEVERE, null, ex); + logger.log(Level.SEVERE, null, ex); } } - + private void copyTagWithDependenciesActionPerformed(ActionEvent evt, List items, SWF targetSwf) { try { SWF sourceSwf = items.get(0).getSwf(); @@ -490,16 +511,22 @@ public class TagTreeContextMenu extends JPopupMenu { 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 (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); } @@ -511,7 +538,7 @@ public class TagTreeContextMenu extends JPopupMenu { targetSwf.updateCharacters(); mainPanel.refreshTree(targetSwf); } catch (IOException | InterruptedException ex) { - Logger.getLogger(TagTreeContextMenu.class.getName()).log(Level.SEVERE, null, ex); + logger.log(Level.SEVERE, null, ex); } } @@ -527,7 +554,7 @@ public class TagTreeContextMenu extends JPopupMenu { mainPanel.loadFromBinaryTag(binaryDatas); } - + private void rawEditActionPerformed(ActionEvent evt) { TreeItem itemr = tagTree.getCurrentTreeItem(); if (itemr == null) { @@ -536,7 +563,7 @@ public class TagTreeContextMenu extends JPopupMenu { mainPanel.showGenericTag((Tag) itemr); } - + private void jumpToCharacterActionPerformed(ActionEvent evt) { TreeItem itemj = tagTree.getCurrentTreeItem(); if (itemj == null || !(itemj instanceof CharacterIdTag)) { @@ -546,7 +573,7 @@ public class TagTreeContextMenu extends JPopupMenu { CharacterIdTag characterIdTag = (CharacterIdTag) itemj; mainPanel.setTagTreeSelectedNode(itemj.getSwf().getCharacter(characterIdTag.getCharacterId())); } - + private void expandRecursiveActionPerformed(ActionEvent evt) { TreePath path = tagTree.getSelectionPath(); if (path == null) { @@ -554,7 +581,7 @@ public class TagTreeContextMenu extends JPopupMenu { } View.expandTreeNodes(tagTree, path, true); } - + private void removeItemActionPerformed(ActionEvent evt, boolean removeDependencies) { List sel = tagTree.getSelected(tagTree); @@ -600,11 +627,11 @@ public class TagTreeContextMenu extends JPopupMenu { swf.removeTags(tagsToRemoveBySwf.get(swf), removeDependencies); } - mainPanel.refreshTree(null); + mainPanel.refreshTree(); } } } - + private void undoTagActionPerformed(ActionEvent evt) { List sel = tagTree.getSelected(tagTree); @@ -616,14 +643,14 @@ public class TagTreeContextMenu extends JPopupMenu { tag.getSwf().clearAllCache(); tagTree.getModel().updateNode(item); } catch (InterruptedException | IOException ex) { - Logger.getLogger(TagTreeContextMenu.class.getName()).log(Level.SEVERE, null, ex); + logger.log(Level.SEVERE, null, ex); } } } mainPanel.repaintTree(); } - + private void closeSwfActionPerformed(ActionEvent evt) { List sel = tagTree.getSelected(tagTree); for (TreeItem item : sel) { @@ -633,7 +660,7 @@ public class TagTreeContextMenu extends JPopupMenu { // embedded swf swf.binaryData.innerSwf = null; swf.clearTagSwfs(); - mainPanel.refreshTree(null); + mainPanel.refreshTree(); } else { Main.closeFile(swf.swfList); }