From d0936e1a46f20d5e073d9ff0d75534590e72eb16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Fri, 11 Nov 2022 19:11:40 +0100 Subject: [PATCH] Added Show button records in the tree, preview them --- CHANGELOG.md | 1 + .../decompiler/flash/SWFInputStream.java | 18 +++--- .../flash/tags/DefineButton2Tag.java | 2 +- .../flash/tags/DefineButtonTag.java | 2 +- .../decompiler/flash/types/BUTTONRECORD.java | 48 ++++++++++++++- .../jpexs/decompiler/flash/gui/MainPanel.java | 44 ++++++++++++++ .../decompiler/flash/gui/TreeNodeType.java | 1 + .../flash/gui/graphics/buttonrecord16.png | Bin 0 -> 733 bytes .../gui/taglistview/TagListTreeModel.java | 56 ++++++++++++++---- .../flash/gui/tagtree/AbstractTagTree.java | 5 ++ .../flash/gui/tagtree/TagTreeModel.java | 10 ++++ 11 files changed, 165 insertions(+), 22 deletions(-) create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/buttonrecord16.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 43d5883e1..483a6aef8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ All notable changes to this project will be documented in this file. - Moving tags up and down in the taglist view (context menuitem + ALT up/down shortcut) - [#1701] Setting charset for SWF files with version 5 or lower (GUI, commandline) - [#1864] Commandline: Allow to set special value "/dev/stdin" for input files to read from stdin (even on Windows) +- Show button records in the tree, preview them ### Fixed - Exception when bundle selected diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java index 2a711c9d4..df0ea0236 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java @@ -202,6 +202,7 @@ import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.TagStub; import com.jpexs.decompiler.flash.tags.UnknownTag; import com.jpexs.decompiler.flash.tags.VideoFrameTag; +import com.jpexs.decompiler.flash.tags.base.ButtonTag; import com.jpexs.decompiler.flash.tags.gfx.DefineCompactedFont; import com.jpexs.decompiler.flash.tags.gfx.DefineExternalGradient; import com.jpexs.decompiler.flash.tags.gfx.DefineExternalImage; @@ -2457,17 +2458,17 @@ public class SWFInputStream implements AutoCloseable { /** * Reads list of BUTTONRECORD values from the stream * - * @param inDefineButton2 Whether read from inside of DefineButton2Tag or - * not + * @param swf + * @param buttonTag * @param name * @return List of BUTTONRECORD values * @throws IOException */ - public List readBUTTONRECORDList(boolean inDefineButton2, String name) throws IOException { + public List readBUTTONRECORDList(SWF swf, ButtonTag buttonTag, String name) throws IOException { List ret = new ArrayList<>(); newDumpLevel(name, "BUTTONRECORDList"); BUTTONRECORD br; - while ((br = readBUTTONRECORD(inDefineButton2, "record")) != null) { + while ((br = readBUTTONRECORD(swf, buttonTag, "record")) != null) { ret.add(br); } endDumpLevel(); @@ -2477,13 +2478,14 @@ public class SWFInputStream implements AutoCloseable { /** * Reads one BUTTONRECORD value from the stream * - * @param inDefineButton2 True when in DefineButton2 + * @param swf + * @param tag * @param name * @return BUTTONRECORD value * @throws IOException */ - public BUTTONRECORD readBUTTONRECORD(boolean inDefineButton2, String name) throws IOException { - BUTTONRECORD ret = new BUTTONRECORD(); + public BUTTONRECORD readBUTTONRECORD(SWF swf, ButtonTag tag, String name) throws IOException { + BUTTONRECORD ret = new BUTTONRECORD(swf, tag); newDumpLevel(name, "BUTTONRECORD"); ret.reserved = (int) readUB(2, "reserved"); ret.buttonHasBlendMode = readUB(1, "buttonHasBlendMode") == 1; @@ -2503,7 +2505,7 @@ public class SWFInputStream implements AutoCloseable { ret.characterId = readUI16("characterId"); ret.placeDepth = readUI16("placeDepth"); ret.placeMatrix = readMatrix("placeMatrix"); - if (inDefineButton2) { + if (tag instanceof DefineButton2Tag) { ret.colorTransform = readCXFORMWITHALPHA("colorTransform"); if (ret.buttonHasFilterList) { ret.filterList = readFILTERLIST("filterList"); 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 0c4287128..1648ab71c 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 @@ -109,7 +109,7 @@ public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer { reserved = (int) sis.readUB(7, "reserved"); trackAsMenu = sis.readUB(1, "trackAsMenu") == 1; int actionOffset = sis.readUI16("actionOffset"); - characters = sis.readBUTTONRECORDList(true, "characters"); + characters = sis.readBUTTONRECORDList(swf, this, "characters"); if (actionOffset > 0) { actions = sis.readBUTTONCONDACTIONList(swf, this, "actions"); } 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 27a855238..44d579301 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 @@ -101,7 +101,7 @@ public class DefineButtonTag extends ButtonTag implements ASMSourceContainer { @Override public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { buttonId = sis.readUI16("buttonId"); - characters = sis.readBUTTONRECORDList(false, "characters"); + characters = sis.readBUTTONRECORDList(swf, this, "characters"); actionBytes = sis.readByteRangeEx(sis.available(), "actionBytes", DumpInfoSpecialType.ACTION_BYTES, sis.getPos()); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONRECORD.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONRECORD.java index 363cbe723..1313ea546 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONRECORD.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONRECORD.java @@ -16,8 +16,13 @@ */ package com.jpexs.decompiler.flash.types; +import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.tags.DefineButton2Tag; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.ButtonTag; +import com.jpexs.decompiler.flash.treeitems.TreeItem; import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.Internal; import com.jpexs.decompiler.flash.types.annotations.Reserved; import com.jpexs.decompiler.flash.types.annotations.SWFArray; import com.jpexs.decompiler.flash.types.annotations.SWFType; @@ -30,7 +35,7 @@ import java.util.List; * * @author JPEXS */ -public class BUTTONRECORD implements Serializable { +public class BUTTONRECORD implements Serializable, TreeItem { @Reserved @SWFType(value = BasicType.UB, count = 2) @@ -104,8 +109,47 @@ public class BUTTONRECORD implements Serializable { @Conditional(value = {"buttonHasBlendMode"}, tags = {DefineButton2Tag.ID}) public int blendMode; + @Internal + private SWF swf; + + @Internal + private ButtonTag tag; + + public BUTTONRECORD(SWF swf, ButtonTag tag) { + this.swf = swf; + this.tag = tag; + } + + public BUTTONRECORD() { + swf = null; + tag = null; + } + @Override public String toString() { - return "[BUTTONRECORD character:" + characterId + ", depth:" + placeDepth + ", state:" + ((buttonStateDown ? "down " : "") + (buttonStateHitTest ? "hit " : "") + (buttonStateOver ? "over " : "") + (buttonStateUp ? "up " : "")) + "]"; + return "BUTTONRECORD (" + characterId + ") Depth:" + placeDepth + " State:" + ((buttonStateDown ? "down " : "") + (buttonStateHitTest ? "hit " : "") + (buttonStateOver ? "over " : "") + (buttonStateUp ? "up " : "")); } + + @Override + public SWF getSwf() { + return swf; + } + + public void setModified() { + if (tag != null) { + tag.setModified(true); + } + } + + @Override + public boolean isModified() { + if (tag != null) { + return tag.isModified(); + } + return false; + } + + public ButtonTag getTag() { + return tag; + } } diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 0cff896de..11ca29416 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -133,7 +133,9 @@ import com.jpexs.decompiler.flash.tags.EndTag; import com.jpexs.decompiler.flash.tags.FileAttributesTag; import com.jpexs.decompiler.flash.tags.JPEGTablesTag; import com.jpexs.decompiler.flash.tags.MetadataTag; +import com.jpexs.decompiler.flash.tags.PlaceObject2Tag; import com.jpexs.decompiler.flash.tags.PlaceObjectTag; +import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag; import com.jpexs.decompiler.flash.tags.ShowFrameTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.TagInfo; @@ -164,6 +166,7 @@ import com.jpexs.decompiler.flash.treeitems.FolderItem; import com.jpexs.decompiler.flash.treeitems.HeaderItem; import com.jpexs.decompiler.flash.treeitems.SWFList; import com.jpexs.decompiler.flash.treeitems.TreeItem; +import com.jpexs.decompiler.flash.types.BUTTONRECORD; import com.jpexs.decompiler.flash.types.FILLSTYLE; import static com.jpexs.decompiler.flash.types.FILLSTYLE.CLIPPED_BITMAP; import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; @@ -4324,6 +4327,44 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } else { previewPanel.setParametersPanelVisible(false); } + } else if (treeItem instanceof BUTTONRECORD) { + BUTTONRECORD buttonRecord = (BUTTONRECORD) treeItem; + previewPanel.setParametersPanelVisible(false); + SWF swf = new SWF(buttonRecord.getSwf().getCharset()); + swf.frameCount = 1; + swf.frameRate = buttonRecord.getSwf().frameRate; + swf.displayRect = buttonRecord.getTag().getRect(); + if (swf.getBackgroundColor() != null) { + SetBackgroundColorTag setBackgroundColorTag = new SetBackgroundColorTag(swf, swf.getBackgroundColor().backgroundColor); + swf.addTag(setBackgroundColorTag); + setBackgroundColorTag.setTimelined(swf); + } + CharacterTag character = buttonRecord.getSwf().getCharacter(buttonRecord.characterId); + Set needed = new LinkedHashSet<>(); + character.getNeededCharactersDeep(needed); + needed.remove(buttonRecord.characterId); + needed.add(buttonRecord.characterId); + + for (int n : needed) { + CharacterTag neededCharacter; + try { + neededCharacter = (CharacterTag) buttonRecord.getSwf().getCharacter(n).cloneTag(); + } catch (InterruptedException | IOException ex) { + Logger.getLogger(MainPanel.class.getName()).log(Level.SEVERE, null, ex); + return; + } + neededCharacter.setSwf(swf); + neededCharacter.setTimelined(swf); + swf.addTag(neededCharacter); + } + + PlaceObject2Tag placeTag = new PlaceObject2Tag(swf, false, 1, buttonRecord.characterId, buttonRecord.placeMatrix, buttonRecord.colorTransform, 0, null, -1, null); + swf.addTag(placeTag); + placeTag.setTimelined(swf); + ShowFrameTag showFrameTag = new ShowFrameTag(swf); + swf.addTag(showFrameTag); + showFrameTag.setTimelined(swf); + previewPanel.showImagePanel(swf, swf, 0, true, true); } else { previewPanel.showEmpty(); } @@ -4493,6 +4534,9 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se showCard(CARDPREVIEWPANEL); } else if (treeItem instanceof Tag) { showGenericTag((Tag) treeItem); + } else if (treeItem instanceof BUTTONRECORD) { + showPreview(treeItem, previewPanel, -1, null); + showCard(CARDPREVIEWPANEL); } else { showCard(CARDEMPTYPANEL); } diff --git a/src/com/jpexs/decompiler/flash/gui/TreeNodeType.java b/src/com/jpexs/decompiler/flash/gui/TreeNodeType.java index d1518fac5..5df6cdc84 100644 --- a/src/com/jpexs/decompiler/flash/gui/TreeNodeType.java +++ b/src/com/jpexs/decompiler/flash/gui/TreeNodeType.java @@ -31,6 +31,7 @@ public enum TreeNodeType { MORPH_SHAPE, SPRITE, BUTTON, + BUTTON_RECORD, AS, AS_CLASS, AS_INTERFACE, diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/buttonrecord16.png b/src/com/jpexs/decompiler/flash/gui/graphics/buttonrecord16.png new file mode 100644 index 0000000000000000000000000000000000000000..6332fefea4be19eeadf211b0b202b272e8564898 GIT binary patch literal 733 zcmV<30wVp1P)9VHk(~TedF+gQSL8D5xnVSSWAVY>J9b+m>@{iq7_KE}go~11+5s4;8hc+i0Xa zI1j@EX5!S+Me6HNqKzU5YQwL;-W5$p%ZMKMeR<%zp69-~?<4?8|C8S?bklXr4v&Ov zb&06v2|-x?qB`90yn>Qi%Sh2^G4n)$ZdyvTPf9}1)_buUT7>`e2G&2VU@~Bb(o+Mz zi4)>IxlSY${Dj4k={-9RzU^W5g9|2V5RZ2ZulL9s2xQbZ@r6eP9Ra5u(s|C0Nj#&4>wTSkb?%#=9?@ z^oxDy-O@tyN{L@by(WWvQ3%CyEu8x{+#Jb4-h&K9Owi)2pgg+heWDyked|3R$$kL@A z#sp1v-r+=G4B8D6DqsDH0@7OztA7aT9qc1Py{()w`m``?Y0&gi2=ROcc-9+nU^I6< zT=e_Y=vSnG@?3Ue{BW5ONFttcE!R-R_W4O01|0-|K-YNXLo2`4Qv z`r1LxR6#yf3FB%T95gJnaKKivA~Z}S9A(ZxEDK}O3T04USJ P00000NkvXXu0mjf^IS-S literal 0 HcmV?d00001 diff --git a/src/com/jpexs/decompiler/flash/gui/taglistview/TagListTreeModel.java b/src/com/jpexs/decompiler/flash/gui/taglistview/TagListTreeModel.java index ea24c60fa..ed2eb3e15 100644 --- a/src/com/jpexs/decompiler/flash/gui/taglistview/TagListTreeModel.java +++ b/src/com/jpexs/decompiler/flash/gui/taglistview/TagListTreeModel.java @@ -24,6 +24,8 @@ import com.jpexs.decompiler.flash.gui.tagtree.AbstractTagTreeModel; import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; import com.jpexs.decompiler.flash.tags.DefineSpriteTag; import com.jpexs.decompiler.flash.tags.base.ASMSourceContainer; +import com.jpexs.decompiler.flash.tags.base.ButtonAction; +import com.jpexs.decompiler.flash.tags.base.ButtonTag; import com.jpexs.decompiler.flash.timeline.Frame; import com.jpexs.decompiler.flash.timeline.Timelined; import com.jpexs.decompiler.flash.treeitems.HeaderItem; @@ -97,9 +99,18 @@ public class TagListTreeModel extends AbstractTagTreeModel { return ((Frame) parentNode).allInnerTags.get(index); } else if (parentNode instanceof DefineBinaryDataTag) { return ((DefineBinaryDataTag) parentNode).innerSwf; - } else if (parentNode instanceof ASMSourceContainer) { + } + + if (parentNode instanceof ButtonTag) { + if (index < ((ButtonTag) parentNode).getRecords().size()) { + return ((ButtonTag) parentNode).getRecords().get(index); + } + index -= ((ButtonTag) parentNode).getRecords().size(); + } + if (parentNode instanceof ASMSourceContainer) { return ((ASMSourceContainer)parentNode).getSubItems().get(index); } + throw new Error("Unsupported parent type: " + parentNode.getClass().getName()); } @@ -107,7 +118,7 @@ public class TagListTreeModel extends AbstractTagTreeModel { public int getChildCount(Object parent) { TreeItem parentNode = (TreeItem) parent; if (parentNode == root) { - return swfs.size(); + return swfs.size(); } else if (parentNode instanceof SWFList) { return ((SWFList) parentNode).swfs.size(); } else if (parentNode instanceof SWF) { @@ -120,11 +131,17 @@ public class TagListTreeModel extends AbstractTagTreeModel { return ((DefineSpriteTag) parentNode).getTimeline().getFrameCount(); } else if (parentNode instanceof DefineBinaryDataTag) { return (((DefineBinaryDataTag) parentNode).innerSwf == null ? 0 : 1); - } else if (parentNode instanceof ASMSourceContainer) { - return ((ASMSourceContainer)parentNode).getSubItems().size(); } + int size = 0; + if (parentNode instanceof ButtonTag) { + size += ((ButtonTag) parentNode).getRecords().size(); + } + if (parentNode instanceof ASMSourceContainer) { + size += ((ASMSourceContainer)parentNode).getSubItems().size(); + } + - return 0; + return size; } @Override @@ -165,9 +182,23 @@ public class TagListTreeModel extends AbstractTagTreeModel { return ((Frame) parentNode).allInnerTags.indexOf(child); } else if (parentNode instanceof DefineBinaryDataTag) { return ((DefineBinaryDataTag) parentNode).innerSwf == child ? 0 : -1; - } else if (parentNode instanceof ASMSourceContainer) { - return ((ASMSourceContainer)parentNode).getSubItems().indexOf(child); } + int base = 0; + if (parentNode instanceof ButtonTag) { + int index = ((ButtonTag) parentNode).getRecords().indexOf(child); + if (index > -1) { + return index; + } + base = ((ButtonTag) parentNode).getRecords().size(); + } + if (parentNode instanceof ASMSourceContainer) { + int index = ((ASMSourceContainer)parentNode).getSubItems().indexOf(child); + if (index == -1) { + return -1; + } + return base + index; + } + return -1; } @@ -270,11 +301,16 @@ public class TagListTreeModel extends AbstractTagTreeModel { } else { return new ArrayList<>(0); } - } else if (parentNode instanceof ASMSourceContainer) { - return ((ASMSourceContainer)parentNode).getSubItems(); } + List ret = new ArrayList<>(); + if (parentNode instanceof ButtonTag) { + ret.addAll(((ButtonTag) parentNode).getRecords()); + } + if (parentNode instanceof ASMSourceContainer) { + ret.addAll(((ASMSourceContainer)parentNode).getSubItems()); + } - return new ArrayList<>(); + return ret; } @Override diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java b/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java index 2c66c36aa..843a8a81b 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java @@ -95,6 +95,7 @@ import com.jpexs.decompiler.flash.treeitems.HeaderItem; import com.jpexs.decompiler.flash.treeitems.SWFList; import com.jpexs.decompiler.flash.treeitems.TreeItem; import com.jpexs.decompiler.flash.types.BUTTONCONDACTION; +import com.jpexs.decompiler.flash.types.BUTTONRECORD; import com.jpexs.decompiler.flash.types.CLIPACTIONRECORD; import java.awt.Color; import java.util.ArrayList; @@ -217,6 +218,10 @@ public abstract class AbstractTagTree extends JTree { if (t instanceof ButtonTag) { return TreeNodeType.BUTTON; } + + if (t instanceof BUTTONRECORD) { + return TreeNodeType.BUTTON_RECORD; + } if (t instanceof DefineVideoStreamTag) { return TreeNodeType.MOVIE; diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java index 082c8cece..e1fdc8172 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java @@ -29,6 +29,7 @@ import com.jpexs.decompiler.flash.tags.SoundStreamBlockTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.ASMSource; import com.jpexs.decompiler.flash.tags.base.ASMSourceContainer; +import com.jpexs.decompiler.flash.tags.base.ButtonTag; import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag; @@ -44,6 +45,7 @@ import com.jpexs.decompiler.flash.treeitems.FolderItem; import com.jpexs.decompiler.flash.treeitems.HeaderItem; import com.jpexs.decompiler.flash.treeitems.SWFList; import com.jpexs.decompiler.flash.treeitems.TreeItem; +import com.jpexs.decompiler.flash.types.BUTTONRECORD; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -541,6 +543,8 @@ public class TagTreeModel extends AbstractTagTreeModel { } else { return new ArrayList<>(); } + } else if (parentNode instanceof ButtonTag) { + return ((ButtonTag) parentNode).getRecords(); } return result; @@ -614,6 +618,8 @@ public class TagTreeModel extends AbstractTagTreeModel { return clt.getChild(clt.getRoot(), index); } else if (parentNode instanceof AS3ClassTreeItem) { return ((AS3Package) parentNode).getChild(index); + } else if (parentNode instanceof ButtonTag) { + return ((ButtonTag) parentNode).getRecords().get(index); } throw new Error("Unsupported parent type: " + parentNode.getClass().getName()); @@ -654,6 +660,8 @@ public class TagTreeModel extends AbstractTagTreeModel { return mappedSize + clt.getChildCount(clt.getRoot()); } else if (parentNode instanceof AS3Package) { return mappedSize + ((AS3Package) parentNode).getChildCount(); + } else if (parentNode instanceof ButtonTag) { + return mappedSize + ((ButtonTag) parentNode).getRecords().size(); } else if (parentNode instanceof CharacterTag) { return mappedSize; } @@ -723,6 +731,8 @@ public class TagTreeModel extends AbstractTagTreeModel { return indexOfAdd(baseIndex, clt.getIndexOfChild(clt.getRoot(), childNode)); } else if (parentNode instanceof AS3ClassTreeItem) { return indexOfAdd(baseIndex, ((AS3Package) parentNode).getIndexOfChild((AS3ClassTreeItem) childNode)); + } else if (parentNode instanceof ButtonTag) { + return indexOfAdd(baseIndex, ((ButtonTag) parentNode).getRecords().indexOf(childNode)); } else if (parentNode instanceof CharacterTag) { return indexOfAdd(baseIndex, getMappedCharacters(((CharacterTag) parentNode).getSwf(), (CharacterTag) parentNode).indexOf(childNode)); }