Clone tags and frames

This commit is contained in:
Exund
2022-10-23 19:36:10 +02:00
committed by Jindra Petřík
parent 8e011e6392
commit 2fb840baac
8 changed files with 167 additions and 22 deletions

View File

@@ -3190,13 +3190,19 @@ public final class SWF implements SWFContainerItem, Timelined {
updateCharacters();
}
}
public int indexOfTag(Tag tag) {
return tags.indexOf(tag);
}
/**
* Adds a tag to the SWF If targetTreeItem is: - Frame: adds the tag to the
* Adds a tag to the SWF If targetTreeItem is:
* - Frame: adds the tag to the
* Frame. Frame can be a frame of the main timeline or a DefineSprite frame
* - DefineSprite: adds the tag to the end of the DefineSprite's tag list -
* Any other tag in the SWF: adds the new tag exactly before the specified
* tag - Other: adds the tag to the end of the SWF's tag list
* - DefineSprite: adds the tag to the end of the DefineSprite's tag list
* - Any other tag in the SWF: adds the new tag exactly before the specified
* tag
* - Other: adds the tag to the end of the SWF's tag list
*
* @param tag
* @param targetTreeItem

View File

@@ -327,6 +327,11 @@ public class DefineSpriteTag extends DrawableTag implements Timelined {
subTags.add(index, tag);
}
@Override
public int indexOfTag(Tag tag) {
return subTags.indexOf(tag);
}
@Override
public void createOriginalData() {
super.createOriginalData();

View File

@@ -172,6 +172,11 @@ public abstract class ButtonTag extends DrawableTag implements Timelined {
@Override
public void addTag(int index, Tag tag) {
}
@Override
public int indexOfTag(Tag tag) {
return -1;
}
@Override
public void replaceTag(int index, Tag newTag) {

View File

@@ -12,7 +12,8 @@
* 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.ReadOnlyTagList;
@@ -42,4 +43,6 @@ public interface Timelined extends BoundedTag {
public void addTag(int index, Tag tag);
public void replaceTag(int index, Tag newTag);
public int indexOfTag(Tag tag);
}

View File

@@ -4175,6 +4175,11 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
public void replaceTag(int index, Tag newTag) {
}
@Override
public int indexOfTag(Tag tag) {
return -1;
}
@Override
public RECT getRectWithStrokes() {
return getRect();

View File

@@ -857,4 +857,6 @@ work.deobfuscating_pcode = Deobfuscating pcode
work.injecting_debuginfo = Injecting debug info
work.generating_swd = Generating SWD file
button.replaceRefs = Replace references with other character ID
button.replaceRefs = Replace references with other character ID
contextmenu.cloneTag = Clone tag

View File

@@ -125,7 +125,7 @@ public class TagTreeContextMenu extends JPopupMenu {
private JMenuItem replaceNoFillMenuItem;
private JMenuItem replaceWithTagMenuItem;
private JMenuItem replaceRefsWithTagMenuItem;
private JMenuItem rawEditMenuItem;
@@ -142,6 +142,8 @@ public class TagTreeContextMenu extends JPopupMenu {
private JMenu addTagMenu;
private JMenuItem cloneTagMenuItem;
private JMenu moveTagMenu;
private JMenu copyTagMenu;
@@ -176,6 +178,10 @@ public class TagTreeContextMenu extends JPopupMenu {
});
add(removeWithDependenciesMenuItem);
cloneTagMenuItem = new JMenuItem(mainPanel.translate("contextmenu.cloneTag"));
cloneTagMenuItem.addActionListener(this::cloneTagActionPerformed);
add(cloneTagMenuItem);
undoTagMenuItem = new JMenuItem(mainPanel.translate("contextmenu.undo"));
undoTagMenuItem.addActionListener(this::undoTagActionPerformed);
add(undoTagMenuItem);
@@ -195,7 +201,7 @@ public class TagTreeContextMenu extends JPopupMenu {
replaceWithTagMenuItem = new JMenuItem(mainPanel.translate("button.replaceWithTag"));
replaceWithTagMenuItem.addActionListener(this::replaceWithTagActionPerformed);
add(replaceWithTagMenuItem);
replaceRefsWithTagMenuItem = new JMenuItem(mainPanel.translate("button.replaceRefs"));
replaceRefsWithTagMenuItem.addActionListener(this::replaceRefsWithTagActionPerformed);
add(replaceRefsWithTagMenuItem);
@@ -324,7 +330,6 @@ public class TagTreeContextMenu extends JPopupMenu {
continue;
}
canRemove = false;
break;
} else {
@@ -386,6 +391,23 @@ public class TagTreeContextMenu extends JPopupMenu {
break;
}
}
boolean allSelectedIsTagOrFrame = true;
for (TreeItem item : items) {
if (!(item instanceof Tag)) {
if (item instanceof TagScript) {
Tag tag = ((TagScript) item).getTag();
if (tag instanceof DoActionTag || tag instanceof DoInitActionTag) {
continue;
}
} else if(item instanceof Frame) {
continue;
}
allSelectedIsTagOrFrame = false;
break;
}
}
boolean allSelectedIsBinaryData = true;
for (TreeItem item : items) {
@@ -424,9 +446,33 @@ public class TagTreeContextMenu extends JPopupMenu {
}
}
boolean noSelectParentChild = true;
Set<Timelined> selected = new HashSet<>();
Set<Timelined> parents = new HashSet<>();
for (TreeItem item : items) {
Timelined t = item.getSwf().getTimelined(item);
Timelined parent = null;
if (t != item.getSwf()) {
selected.add(t);
} else if (item instanceof Tag) {
Tag tag = (Tag) item;
Timelined temp = tag.getTimelined();
if (!(temp instanceof SWF)) {
parents.add(temp);
parent = temp;
}
}
if (selected.contains(parent) || parents.contains(t)) {
noSelectParentChild = false;
break;
}
}
expandRecursiveMenuItem.setVisible(false);
removeMenuItem.setVisible(canRemove);
removeWithDependenciesMenuItem.setVisible(canRemove && !allDoNotHaveDependencies);
cloneTagMenuItem.setVisible(allSelectedIsTagOrFrame && noSelectParentChild);
undoTagMenuItem.setVisible(allSelectedIsTag);
exportSelectionMenuItem.setEnabled(tagTree.hasExportableNodes());
replaceMenuItem.setVisible(false);
@@ -817,7 +863,7 @@ public class TagTreeContextMenu extends JPopupMenu {
mainPanel.refreshTree(swf);
}
}
private void replaceRefsWithTagActionPerformed(ActionEvent evt) {
TreeItem itemr = tagTree.getCurrentTreeItem();
if (itemr == null) {
@@ -830,11 +876,11 @@ public class TagTreeContextMenu extends JPopupMenu {
ReplaceCharacterDialog replaceCharacterDialog = new ReplaceCharacterDialog(Main.getDefaultDialogsOwner());
if (replaceCharacterDialog.showDialog(swf, characterId) == AppDialog.OK_OPTION) {
int newCharacterId = replaceCharacterDialog.getCharacterId();
for (Tag tag : swf.getTags()) {
replaceRef(tag, characterId, newCharacterId);
}
swf.assignExportNamesToSymbols();
swf.assignClassesToSymbols();
swf.clearImageCache();
@@ -844,22 +890,22 @@ public class TagTreeContextMenu extends JPopupMenu {
mainPanel.refreshTree(swf);
}
}
private void replaceRef(Tag tag, int characterId, int newCharacterId) {
if(tag instanceof DefineSpriteTag) {
DefineSpriteTag sprite = (DefineSpriteTag)tag;
if (tag instanceof DefineSpriteTag) {
DefineSpriteTag sprite = (DefineSpriteTag) tag;
for (Tag subTag : sprite.getTags()) {
replaceRef(subTag, characterId, newCharacterId);
}
sprite.clearReadOnlyListCache();
}
if(tag instanceof PlaceObjectTypeTag) {
PlaceObjectTypeTag placeTag = (PlaceObjectTypeTag)tag;
if(placeTag.getCharacterId() == characterId) {
if (tag instanceof PlaceObjectTypeTag) {
PlaceObjectTypeTag placeTag = (PlaceObjectTypeTag) tag;
if (placeTag.getCharacterId() == characterId) {
placeTag.setCharacterId(newCharacterId);
placeTag.setModified(true);
Timelined tim = placeTag.getTimelined();
if(tim != null) {
if (tim != null) {
tim.resetTimeline();
}
}
@@ -1412,8 +1458,7 @@ public class TagTreeContextMenu extends JPopupMenu {
TreePath tPath = path.pathByAddingChild(t);
if ((t instanceof TagScript) && (((TagScript) t).getTag() instanceof ASMSource)) {
out.add(tPath);
}
else if (t instanceof ASMSource) {
} else if (t instanceof ASMSource) {
out.add(tPath);
} else {
populateScriptSubs(tPath, t, out);
@@ -1704,4 +1749,78 @@ public class TagTreeContextMenu extends JPopupMenu {
}
}
}
private void cloneTagActionPerformed(ActionEvent e) {
List<TreeItem> items = tagTree.getSelected();
Set<SWF> swfs = new HashSet<>();
try {
for (TreeItem item : items) {
SWF swf = item.getSwf();
swfs.add(swf);
if (item instanceof Tag) {
Tag tag = (Tag) item;
Tag copyTag = tag.cloneTag();
copyTag.setSwf(swf, true);
Timelined timelined = tag.getTimelined();
int idx = timelined.indexOfTag(tag);
timelined.addTag(idx + 1, copyTag);
copyTag.setTimelined(timelined);
chechUniqueCharacterId(copyTag);
copyTag.setModified(true);
timelined.resetTimeline();
} else if (item instanceof Frame) {
Frame f = (Frame) item;
Timelined timelined = f.timeline.timelined;
int i;
boolean isLast = f.showFrameTag == null;
if(isLast) {
f.showFrameTag = new ShowFrameTag(swf);
Tag last = f.innerTags.get(f.innerTags.size() - 1);
int idx = timelined.indexOfTag(last) + 1;
timelined.addTag(idx, f.showFrameTag);
f.showFrameTag.setTimelined(timelined);
i = idx;
} else {
i = timelined.indexOfTag(f.showFrameTag);
}
for (Tag tag : f.innerTags) {
Tag copyTag = tag.cloneTag();
copyTag.setSwf(swf, true);
timelined.addTag(++i, copyTag);
copyTag.setTimelined(timelined);
chechUniqueCharacterId(copyTag);
copyTag.setModified(true);
}
if(!isLast) {
ShowFrameTag next = new ShowFrameTag(swf);
timelined.addTag(++i, next);
next.setTimelined(timelined);
}
timelined.resetTimeline();
}
}
for (SWF swf : swfs) {
swf.assignExportNamesToSymbols();
swf.assignClassesToSymbols();
swf.clearImageCache();
swf.updateCharacters();
mainPanel.refreshTree(swf);
}
} catch (IOException | InterruptedException ex) {
logger.log(Level.SEVERE, null, ex);
}
}
}

View File

@@ -264,7 +264,7 @@ public class TagTreeModel implements TreeModel {
TreeItem sound = sounds.get(i);
if (sound instanceof SoundStreamHeadTypeTag) {
List<SoundStreamBlockTag> blocks = ((SoundStreamHeadTypeTag) sound).getBlocks();
if (blocks.isEmpty()) {
if (blocks == null || blocks.isEmpty()) {
sounds.remove(i);
}
}