From 07df4a86408e8fb2a4bb946b4b23add4eb23b1b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sun, 29 Jan 2023 21:45:21 +0100 Subject: [PATCH] Added Remembering script+folder scroll/caret position when switching between items, saving for pinned items --- CHANGELOG.md | 1 + .../flash/configuration/Configuration.java | 16 + src/com/jpexs/decompiler/flash/gui/Main.java | 4 + .../jpexs/decompiler/flash/gui/MainPanel.java | 38 +- .../jpexs/decompiler/flash/gui/PinsPanel.java | 31 ++ .../flash/gui/ScrollPosStorage.java | 449 ++++++++++++++++++ .../flash/gui/abc/DecompiledEditorPane.java | 23 +- .../flash/gui/abc/MethodCodePanel.java | 10 +- .../flash/gui/action/ActionPanel.java | 19 + .../locales/AdvancedSettingsDialog.properties | 12 + .../AdvancedSettingsDialog_cs.properties | 12 + 11 files changed, 605 insertions(+), 10 deletions(-) create mode 100644 src/com/jpexs/decompiler/flash/gui/ScrollPosStorage.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b8fa2ced..255571382 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file. ## [Unreleased] ### Added - [#1029] Better separation of library and main app, dependencies inside library zip, library readme +- Remembering script+folder scroll/caret position when switching between items, saving for pinned items ### Fixed - [#1948] Timeout while deobfuscation did not skip method diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java index 2f215d4b9..06e07c091 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java @@ -887,6 +887,22 @@ public final class Configuration { @ConfigurationCategory("display") public static ConfigurationItem disableBitmapSmoothing = null; + @ConfigurationDefaultString("") + public static ConfigurationItem pinnedItemsScrollPos = null; + + @ConfigurationDefaultInt(30) + @ConfigurationCategory("ui") + public static ConfigurationItem maxRememberedScrollposItems = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("ui") + public static ConfigurationItem rememberScriptsScrollPos = null; + + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("ui") + public static ConfigurationItem rememberFoldersScrollPos = null; + + private enum OSId { WINDOWS, OSX, UNIX } diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index 98290216b..f716b20df 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -2789,6 +2789,10 @@ public class Main { } public static void exit() { + if (mainFrame != null && mainFrame.getPanel() != null) { + mainFrame.getPanel().scrollPosStorage.saveScrollPos(mainFrame.getPanel().getCurrentTree().getCurrentTreeItem()); + mainFrame.getPanel().savePins(); + } try { searchResultsStorage.save(); } catch (IOException ex) { diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 41d8db0d1..0a0d0f391 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -441,6 +441,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se private List> unfilteredTreeExpandedNodes = new ArrayList<>(); private List> unfilteredTagListExpandedNodes = new ArrayList<>(); + + public ScrollPosStorage scrollPosStorage; public void savePins() { pinsPanel.save(); @@ -1225,6 +1227,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se }); detailPanel.setVisible(false); + scrollPosStorage = new ScrollPosStorage(this); + updateUi(); this.openables.addCollectionChangedListener((e) -> { @@ -1321,7 +1325,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se resetAllTimelines(); refreshTree(); } - }); + }); } public void resetAllTimelines() { @@ -1429,9 +1433,18 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se List abcList = swf.getAbcList(); boolean hasAbc = !abcList.isEmpty(); - - if (hasAbc) { - getABCPanel().setAbc(abcList.get(0).getABC()); + + if (hasAbc) { + boolean abcFound = false; + for (ABCContainerTag c : abcList) { + if (getABCPanel().abc == c.getABC()) { + abcFound = true; + break; + } + } + if (!abcFound) { + getABCPanel().setAbc(abcList.get(0).getABC()); + } } } mainMenu.updateComponents(openable); @@ -1511,6 +1524,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se return false; } } + + scrollPosStorage.saveScrollPos(getCurrentTree().getCurrentTreeItem()); clearPins(); @@ -4478,7 +4493,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se if (treeItem == null) { return; } - + if (!(treeItem instanceof OpenableList)) { Openable openable = treeItem.getOpenable(); if (openables.isEmpty()) { @@ -4496,7 +4511,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } else { updateUi(); } - + reload(false, false); if (source == dumpTree) { @@ -5015,7 +5030,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se showDetail(DETAILCARDEMPTYPANEL); showCard(CARDEMPTYPANEL); } - + public void reload(boolean forceReload) { reload(forceReload, true); } @@ -5066,6 +5081,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } if (oldItem != treeItem) { + scrollPosStorage.saveScrollPos(oldItem); closeTag(); } @@ -5247,6 +5263,14 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se folderPreviewPanel.selectedItems = folderItems; folderPreviewScrollBar.setValue(scrollValue); + View.execInEventDispatchLater(new Runnable(){ + @Override + public void run() { + scrollPosStorage.loadScrollPos(oldItem); + } + }); + + } public void repaintTree() { diff --git a/src/com/jpexs/decompiler/flash/gui/PinsPanel.java b/src/com/jpexs/decompiler/flash/gui/PinsPanel.java index 55100e9d2..80891c305 100644 --- a/src/com/jpexs/decompiler/flash/gui/PinsPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/PinsPanel.java @@ -47,6 +47,7 @@ public class PinsPanel extends JPanel { private List missingTagTreePaths = new ArrayList<>(); private List missingTagListPaths = new ArrayList<>(); + private List missingScrollPos = new ArrayList<>(); private static final String PATHS_SEPARATOR = "{#sep#}"; @@ -61,6 +62,9 @@ public class PinsPanel extends JPanel { */ public void destroy() { items.clear(); + missingScrollPos.clear(); + missingTagListPaths.clear(); + missingTagTreePaths.clear(); rebuild(); save(); } @@ -81,8 +85,11 @@ public class PinsPanel extends JPanel { tagListPath = ""; } + String scrollPos = mainPanel.scrollPosStorage.getSerializedScrollPos(item); + missingTagTreePaths.add(tagTreePath); missingTagListPaths.add(tagListPath); + missingScrollPos.add(scrollPos); } items.clear(); rebuild(); @@ -232,15 +239,18 @@ public class PinsPanel extends JPanel { public void save() { StringBuilder tagTreePathsBuilder = new StringBuilder(); StringBuilder tagListPathsBuilder = new StringBuilder(); + StringBuilder scrollPosesBuilder = new StringBuilder(); boolean first = true; for (int i = 0; i < missingTagTreePaths.size(); i++) { if (!first) { tagTreePathsBuilder.append(PATHS_SEPARATOR); tagListPathsBuilder.append(PATHS_SEPARATOR); + scrollPosesBuilder.append(PATHS_SEPARATOR); } tagTreePathsBuilder.append(missingTagTreePaths.get(i)); tagListPathsBuilder.append(missingTagListPaths.get(i)); + scrollPosesBuilder.append(missingScrollPos.get(i)); first = false; } @@ -259,17 +269,23 @@ public class PinsPanel extends JPanel { if (tagListPath == null) { tagListPath = ""; } + + String scrollPos = mainPanel.scrollPosStorage.getSerializedScrollPos(item); + if (!first) { tagTreePathsBuilder.append(PATHS_SEPARATOR); tagListPathsBuilder.append(PATHS_SEPARATOR); + scrollPosesBuilder.append(PATHS_SEPARATOR); } tagTreePathsBuilder.append(tagTreePath); tagListPathsBuilder.append(tagListPath); + scrollPosesBuilder.append(scrollPos); first = false; } Configuration.pinnedItemsTagTreePaths.set(tagTreePathsBuilder.toString()); Configuration.pinnedItemsTagListPaths.set(tagListPathsBuilder.toString()); + Configuration.pinnedItemsScrollPos.set(scrollPosesBuilder.toString()); } public void load() { @@ -278,10 +294,14 @@ public class PinsPanel extends JPanel { List missingTagTreePaths = new ArrayList<>(); List missingTagListPaths = new ArrayList<>(); + List missingScrollPos = new ArrayList<>(); String tagTreePathsCombined = Configuration.pinnedItemsTagTreePaths.get() + PATHS_SEPARATOR + PATHS_END; String tagListPathsCombined = Configuration.pinnedItemsTagListPaths.get() + PATHS_SEPARATOR + PATHS_END; + String scrollPosCombined = Configuration.pinnedItemsScrollPos.get() + PATHS_SEPARATOR + PATHS_END; + String[] tagTreePaths = tagTreePathsCombined.split(Pattern.quote(PATHS_SEPARATOR)); String[] tagListPaths = tagListPathsCombined.split(Pattern.quote(PATHS_SEPARATOR)); + String[] scrollPoses = scrollPosCombined.split(Pattern.quote(PATHS_SEPARATOR)); if (tagTreePaths.length != tagListPaths.length) { return; } @@ -293,16 +313,24 @@ public class PinsPanel extends JPanel { if (item == null || (item instanceof TreeRoot)) { item = mainPanel.tagListTree.getTreeItemFromPathString(tagListPath); } + String scrollPosStr = ""; + if (!Configuration.pinnedItemsScrollPos.get().isEmpty()) { + scrollPosStr = scrollPoses[i]; + } + if (item != null && !(item instanceof TreeRoot)) { items.add(item); + mainPanel.scrollPosStorage.setSerializedScrollPos(item, scrollPosStr); } else { missingTagTreePaths.add(tagTreePath); missingTagListPaths.add(tagListPath); + missingScrollPos.add(scrollPosStr); } } this.items = items; this.missingTagTreePaths = missingTagTreePaths; this.missingTagListPaths = missingTagListPaths; + this.missingScrollPos = missingScrollPos; rebuild(); } @@ -321,9 +349,12 @@ public class PinsPanel extends JPanel { if (tagListPath == null) { tagListPath = ""; } + + String scrollPos = mainPanel.scrollPosStorage.getSerializedScrollPos(item); missingTagTreePaths.add(tagTreePath); missingTagListPaths.add(tagListPath); + missingScrollPos.add(scrollPos); items.remove(i); i--; diff --git a/src/com/jpexs/decompiler/flash/gui/ScrollPosStorage.java b/src/com/jpexs/decompiler/flash/gui/ScrollPosStorage.java new file mode 100644 index 000000000..97b785f67 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/ScrollPosStorage.java @@ -0,0 +1,449 @@ +/* + * Copyright (C) 2023 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 . + */ +package com.jpexs.decompiler.flash.gui; + +import com.jpexs.decompiler.flash.abc.ScriptPack; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.tags.base.ASMSource; +import com.jpexs.decompiler.flash.timeline.AS2Package; +import com.jpexs.decompiler.flash.treeitems.AS3ClassTreeItem; +import com.jpexs.decompiler.flash.treeitems.FolderItem; +import com.jpexs.decompiler.flash.treeitems.TreeItem; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Timer; +import java.util.TimerTask; +import javax.swing.JScrollPane; + +/** + * Storage for remembering scroll/caret positions of scripts / preview folder. + * + * @author JPEXS + */ +public class ScrollPosStorage { + + private final MainPanel mainPanel; + private final List storage = new ArrayList<>(); + + private static final String PATHS_SEPARATOR = "{#sep#}"; + private static final String POS_SEPARATOR = ";"; + + public ScrollPosStorage(MainPanel mainPanel) { + this.mainPanel = mainPanel; + } + + private int indexOf(TreeItem item) { + for (int i = 0; i < storage.size(); i++) { + ScrollPosItem sitem = storage.get(i); + TreeItem titem = sitem.getItem(); + if (titem == null) { + storage.remove(i); + i--; + continue; + } + if (titem == item) { + return i; + } + } + return -1; + } + + public void setSerializedScrollPos(TreeItem item, String serializedScrollPos) { + if (serializedScrollPos.isEmpty()) { + int index = indexOf(item); + if (index > -1) { + storage.remove(index); + } + return; + } + String[] parts = (serializedScrollPos + POS_SEPARATOR).split(POS_SEPARATOR); + int actionScriptScrollHorizontal = Integer.parseInt(parts[0]); + int actionScriptScrollVertical = Integer.parseInt(parts[1]); + int actionScriptCaret = Integer.parseInt(parts[2]); + int pcodeScrollHorizontal = Integer.parseInt(parts[3]); + int pcodeScrollVertical = Integer.parseInt(parts[4]); + int pcodeCaret = Integer.parseInt(parts[5]); + int folderPreviewScrollVertical = Integer.parseInt(parts[6]); + int folderListScrollVertical = Integer.parseInt(parts[7]); + int index = indexOf(item); + ScrollPosItem sitem = new ScrollPosItem(item, actionScriptScrollHorizontal, actionScriptScrollVertical, actionScriptCaret, pcodeScrollHorizontal, pcodeScrollVertical, pcodeCaret, folderPreviewScrollVertical, folderListScrollVertical); + if (index > -1) { + storage.set(index, sitem); + } else { + storage.add(sitem); + } + } + + public String getSerializedScrollPos(TreeItem item) { + int index = indexOf(item); + if (index == -1) { + return ""; + } + ScrollPosItem sitem = storage.get(index); + return sitem.getActionScriptScrollHorizontal() + ";" + + sitem.getActionScriptScrollVertical() + ";" + + sitem.getActionScriptCaret() + ";" + + sitem.getPcodeScrollHorizontal() + ";" + + sitem.getPcodeScrollVertical() + ";" + + sitem.getPcodeCaret() + ";" + + sitem.getFolderPreviewScrollVertical() + ";" + + sitem.getFolderListScrollVertical(); + } + + public void loadScrollPos(TreeItem item) { + int index = indexOf(item); + if (index == -1) { + return; + } + ScrollPosItem sitem = storage.get(index); + //move to bottom + storage.remove(index); + storage.add(sitem); + + if (Configuration.rememberScriptsScrollPos.get()) { + if (item instanceof ScriptPack) { + mainPanel.getABCPanel().decompiledTextArea.runWhenLoaded(new Runnable() { + @Override + public void run() { + if (sitem.getActionScriptCaret() < mainPanel.getABCPanel().decompiledTextArea.getDocument().getLength()) { + mainPanel.getABCPanel().decompiledTextArea.setCaretPosition(sitem.getActionScriptCaret()); + } + + try { + mainPanel.getABCPanel().detailPanel.methodTraitPanel.methodCodePanel.getSourceTextArea().setCaretPosition(sitem.getPcodeCaret()); + } catch (IllegalArgumentException iex) { + + } + + Timer tim = new Timer(); + tim.schedule(new TimerTask() { + @Override + public void run() { + View.execInEventDispatch(new Runnable() { + @Override + public void run() { + mainPanel.getABCPanel().decompiledScrollPane.getHorizontalScrollBar().setValue(sitem.getActionScriptScrollHorizontal()); + mainPanel.getABCPanel().decompiledScrollPane.getVerticalScrollBar().setValue(sitem.getActionScriptScrollVertical()); + mainPanel.getABCPanel().detailPanel.methodTraitPanel.methodCodePanel.getSourceScrollPane().getHorizontalScrollBar().setValue(sitem.getPcodeScrollHorizontal()); + mainPanel.getABCPanel().detailPanel.methodTraitPanel.methodCodePanel.getSourceScrollPane().getVerticalScrollBar().setValue(sitem.getPcodeScrollVertical()); + } + }); + } + }, 100); + + } + }); + } else if (item instanceof ASMSource) { + mainPanel.getActionPanel().runWhenLoaded(new Runnable() { + @Override + public void run() { + if (sitem.getActionScriptCaret() < mainPanel.getActionPanel().decompiledEditor.getDocument().getLength()) { + mainPanel.getActionPanel().decompiledEditor.setCaretPosition(sitem.getActionScriptCaret()); + } + + try { + mainPanel.getActionPanel().editor.setCaretPosition(sitem.getPcodeCaret()); + } catch (IllegalArgumentException iex) { + + } + + Timer tim = new Timer(); + tim.schedule(new TimerTask() { + @Override + public void run() { + View.execInEventDispatch(new Runnable() { + @Override + public void run() { + ((JScrollPane) mainPanel.getActionPanel().decompiledEditor.getParent().getParent()).getHorizontalScrollBar().setValue(sitem.getActionScriptScrollHorizontal()); + ((JScrollPane) mainPanel.getActionPanel().decompiledEditor.getParent().getParent()).getVerticalScrollBar().setValue(sitem.getActionScriptScrollVertical()); + ((JScrollPane) mainPanel.getActionPanel().editor.getParent().getParent()).getHorizontalScrollBar().setValue(sitem.getPcodeScrollHorizontal()); + ((JScrollPane) mainPanel.getActionPanel().editor.getParent().getParent()).getVerticalScrollBar().setValue(sitem.getPcodeScrollVertical()); + } + }); + } + }, 100); + + } + }); + } + } + if (Configuration.rememberFoldersScrollPos.get()) { + Timer tim = new Timer(); + tim.schedule(new TimerTask() { + @Override + public void run() { + View.execInEventDispatchLater(new Runnable() { + @Override + public void run() { + ((JScrollPane) mainPanel.folderPreviewPanel.getParent().getParent()).getVerticalScrollBar().setValue(sitem.getFolderPreviewScrollVertical()); + ((JScrollPane) mainPanel.folderListPanel.getParent().getParent()).getVerticalScrollBar().setValue(sitem.getFolderListScrollVertical()); + } + }); + } + },10); + } + } + + public void saveScrollPos(TreeItem item) { + + boolean doSave = false; + if (item instanceof ScriptPack) { + doSave = true; + } + if (item instanceof ASMSource) { + doSave = true; + } + if (item instanceof FolderItem) { + doSave = true; + } + if (item instanceof AS3ClassTreeItem) { + doSave = true; + } + if (item instanceof AS2Package) { + doSave = true; + } + + if (!doSave) { + return; + } + + int actionScriptScrollHorizontal = 0; + int actionScriptScrollVertical = 0; + int actionScriptCaret = 0; + int pcodeScrollHorizontal = 0; + int pcodeScrollVertical = 0; + int pcodeCaret = 0; + if (item instanceof ScriptPack) { + actionScriptScrollHorizontal = mainPanel.getABCPanel().decompiledScrollPane.getHorizontalScrollBar().getValue(); + actionScriptScrollVertical = mainPanel.getABCPanel().decompiledScrollPane.getVerticalScrollBar().getValue(); + actionScriptCaret = mainPanel.getABCPanel().decompiledTextArea.getCaretPosition(); + pcodeScrollHorizontal = mainPanel.getABCPanel().detailPanel.methodTraitPanel.methodCodePanel.getSourceScrollPane().getHorizontalScrollBar().getValue(); + pcodeScrollVertical = mainPanel.getABCPanel().detailPanel.methodTraitPanel.methodCodePanel.getSourceScrollPane().getVerticalScrollBar().getValue(); + pcodeCaret = mainPanel.getABCPanel().detailPanel.methodTraitPanel.methodCodePanel.getSourceTextArea().getCaretPosition(); + } else if (item instanceof ASMSource) { + actionScriptScrollHorizontal = ((JScrollPane) mainPanel.getActionPanel().decompiledEditor.getParent().getParent()).getHorizontalScrollBar().getValue(); + actionScriptScrollVertical = ((JScrollPane) mainPanel.getActionPanel().decompiledEditor.getParent().getParent()).getVerticalScrollBar().getValue(); + actionScriptCaret = mainPanel.getActionPanel().decompiledEditor.getCaretPosition(); + pcodeScrollHorizontal = ((JScrollPane) mainPanel.getActionPanel().editor.getParent().getParent()).getHorizontalScrollBar().getValue(); + pcodeScrollVertical = ((JScrollPane) mainPanel.getActionPanel().editor.getParent().getParent()).getVerticalScrollBar().getValue(); + pcodeCaret = mainPanel.getActionPanel().editor.getCaretPosition(); + } + int folderPreviewScrollVertical = 0; + int folderListScrollVertical = 0; + if (!(item instanceof ScriptPack) && !(item instanceof ASMSource)) { + folderPreviewScrollVertical = ((JScrollPane) mainPanel.folderPreviewPanel.getParent().getParent()).getVerticalScrollBar().getValue(); + } + if (!(item instanceof ScriptPack) && !(item instanceof ASMSource)) { + folderListScrollVertical = ((JScrollPane) mainPanel.folderListPanel.getParent().getParent()).getVerticalScrollBar().getValue(); + } + + ScrollPosItem savedItem = new ScrollPosItem(item, + actionScriptScrollHorizontal, + actionScriptScrollVertical, + actionScriptCaret, + pcodeScrollHorizontal, + pcodeScrollVertical, + pcodeCaret, + folderPreviewScrollVertical, + folderListScrollVertical); + + int index = indexOf(item); + + if (savedItem.isEmpty()) { + if (index > -1) { + storage.remove(index); + } + return; + } + if (index > -1) { + storage.set(index, savedItem); + } else { + storage.add(savedItem); + } + if (storage.size() > Configuration.maxRememberedScrollposItems.get()) { + for (int i = 0; i < storage.size(); i++) { + TreeItem it = storage.get(i).getItem(); + if (it != null && mainPanel.isPinned(item)) { + continue; + } + storage.remove(0); + break; + } + } + } +} + +class ScrollPosItem { + + private final WeakReference item; + private final int actionScriptScrollHorizontal; + private final int actionScriptScrollVertical; + private final int actionScriptCaret; + private final int pcodeScrollHorizontal; + private final int pcodeScrollVertical; + private final int pcodeCaret; + private final int folderPreviewScrollVertical; + private final int folderListScrollVertical; + + public TreeItem getItem() { + return item.get(); + } + + public int getActionScriptScrollHorizontal() { + return actionScriptScrollHorizontal; + } + + public int getActionScriptScrollVertical() { + return actionScriptScrollVertical; + } + + public int getActionScriptCaret() { + return actionScriptCaret; + } + + public int getPcodeScrollHorizontal() { + return pcodeScrollHorizontal; + } + + public int getPcodeScrollVertical() { + return pcodeScrollVertical; + } + + public int getPcodeCaret() { + return pcodeCaret; + } + + public int getFolderPreviewScrollVertical() { + return folderPreviewScrollVertical; + } + + public int getFolderListScrollVertical() { + return folderListScrollVertical; + } + + public ScrollPosItem(TreeItem item, int actionScriptScrollHorizontal, int actionScriptScrollVertical, int actionScriptCaret, int pcodeScrollHorizontal, int pcodeScrollVertical, int pcodeCaret, int folderPreviewScrollVertical, int folderListScrollVertical) { + this.item = new WeakReference<>(item); + this.actionScriptScrollHorizontal = actionScriptScrollHorizontal; + this.actionScriptScrollVertical = actionScriptScrollVertical; + this.actionScriptCaret = actionScriptCaret; + this.pcodeScrollHorizontal = pcodeScrollHorizontal; + this.pcodeScrollVertical = pcodeScrollVertical; + this.pcodeCaret = pcodeCaret; + this.folderPreviewScrollVertical = folderPreviewScrollVertical; + this.folderListScrollVertical = folderListScrollVertical; + } + + @Override + public int hashCode() { + int hash = 5; + hash = 79 * hash + Objects.hashCode(this.item.get()); + hash = 79 * hash + this.actionScriptScrollHorizontal; + hash = 79 * hash + this.actionScriptScrollVertical; + hash = 79 * hash + this.actionScriptCaret; + hash = 79 * hash + this.pcodeScrollHorizontal; + hash = 79 * hash + this.pcodeScrollVertical; + hash = 79 * hash + this.pcodeCaret; + hash = 79 * hash + this.folderPreviewScrollVertical; + hash = 79 * hash + this.folderListScrollVertical; + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ScrollPosItem other = (ScrollPosItem) obj; + if (this.actionScriptScrollHorizontal != other.actionScriptScrollHorizontal) { + return false; + } + if (this.actionScriptScrollVertical != other.actionScriptScrollVertical) { + return false; + } + if (this.actionScriptCaret != other.actionScriptCaret) { + return false; + } + if (this.pcodeScrollHorizontal != other.pcodeScrollHorizontal) { + return false; + } + if (this.pcodeScrollVertical != other.pcodeScrollVertical) { + return false; + } + if (this.pcodeCaret != other.pcodeCaret) { + return false; + } + if (this.folderPreviewScrollVertical != other.folderPreviewScrollVertical) { + return false; + } + if (this.folderListScrollVertical != other.folderListScrollVertical) { + return false; + } + return this.item.get() == other.item.get(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("ScrollPosItem{"); + sb.append("actionScriptScrollHorizontal=").append(actionScriptScrollHorizontal); + sb.append(", actionScriptScrollVertical=").append(actionScriptScrollVertical); + sb.append(", actionScriptCaret=").append(actionScriptCaret); + sb.append(", pcodeScrollHorizontal=").append(pcodeScrollHorizontal); + sb.append(", pcodeScrollVertical=").append(pcodeScrollVertical); + sb.append(", pcodeCaret=").append(pcodeCaret); + sb.append(", folderPreviewScrollVertical=").append(folderPreviewScrollVertical); + sb.append(", folderListScrollVertical=").append(folderListScrollVertical); + sb.append('}'); + return sb.toString(); + } + + public boolean isEmpty() { + if (actionScriptScrollHorizontal > 0) { + return false; + } + if (actionScriptScrollVertical > 0) { + return false; + } + if (actionScriptCaret > 0) { + return false; + } + if (pcodeScrollHorizontal > 0) { + return false; + } + if (pcodeScrollVertical > 0) { + return false; + } + if (pcodeCaret > 0) { + return false; + } + if (folderPreviewScrollVertical > 0) { + return false; + } + if (folderListScrollVertical > 0) { + return false; + } + return true; + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java b/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java index 1a586d07e..4510f65be 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java @@ -94,10 +94,26 @@ public class DecompiledEditorPane extends DebuggableEditorPane implements CaretL private CancellableWorker setSourceWorker; private final List scriptListeners = new ArrayList<>(); + + private boolean scriptLoaded = true; public void addScriptListener(Runnable l) { scriptListeners.add(l); } + + public void runWhenLoaded(Runnable l) { + if (scriptLoaded) { + l.run(); + } else { + addScriptListener(new Runnable() { + @Override + public void run() { + l.run(); + removeScriptListener(this); + } + }); + } + } public ABCPanel getAbcPanel() { return abcPanel; @@ -771,11 +787,14 @@ public class DecompiledEditorPane extends DebuggableEditorPane implements CaretL setSourceWorker.cancel(true); setSourceWorker = null; } + scriptLoaded = false; - if (!force && this.script == scriptLeaf) { + if (!force && this.script == scriptLeaf) { + scriptLoaded = true; fireScript(); return; } + String sn = scriptLeaf.getClassPath().toString(); setScriptName(sn); @@ -881,6 +900,8 @@ public class DecompiledEditorPane extends DebuggableEditorPane implements CaretL } } } + + scriptLoaded = true; fireScript(); } diff --git a/src/com/jpexs/decompiler/flash/gui/abc/MethodCodePanel.java b/src/com/jpexs/decompiler/flash/gui/abc/MethodCodePanel.java index c89bab5a7..68bcdfeec 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/MethodCodePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/MethodCodePanel.java @@ -47,6 +47,8 @@ public class MethodCodePanel extends JPanel { private final ASMSourceEditorPane sourceTextArea; + private final FasterScrollPane sourceScrollPane; + public JPanel buttonsPanel; private final JToggleButton hexButton; @@ -58,6 +60,10 @@ public class MethodCodePanel extends JPanel { public ABC getABC() { return sourceTextArea.abc; } + + public FasterScrollPane getSourceScrollPane() { + return sourceScrollPane; + } public void refreshMarkers() { sourceTextArea.refreshMarkers(); @@ -127,9 +133,9 @@ public class MethodCodePanel extends JPanel { docsPanel = new DocsPanel(); sourceTextArea.addDocsListener(docsPanel); if (Configuration.displayAs3PCodeDocsPanel.get()) { - add(new JPersistentSplitPane(JSplitPane.VERTICAL_SPLIT, new FasterScrollPane(sourceTextArea), new FasterScrollPane(docsPanel), Configuration.guiAvm2DocsSplitPaneDividerLocationPercent)); + add(new JPersistentSplitPane(JSplitPane.VERTICAL_SPLIT, sourceScrollPane = new FasterScrollPane(sourceTextArea), new FasterScrollPane(docsPanel), Configuration.guiAvm2DocsSplitPaneDividerLocationPercent)); } else { - add(new FasterScrollPane(sourceTextArea)); + add(sourceScrollPane = new FasterScrollPane(sourceTextArea)); } sourceTextArea.changeContentType("text/flasm3"); sourceTextArea.setFont(Configuration.getSourceFont()); diff --git a/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java b/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java index 142d58c71..7b3678ef9 100644 --- a/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java @@ -182,6 +182,8 @@ public class ActionPanel extends JPanel implements SearchListener scriptListeners = new ArrayList<>(); + + private boolean scriptLoaded = true; public void addScriptListener(Runnable listener) { scriptListeners.add(listener); @@ -190,6 +192,20 @@ public class ActionPanel extends JPanel implements SearchListener list = new ArrayList<>(scriptListeners); @@ -462,6 +478,8 @@ public class ActionPanel extends JPanel implements SearchListener