Fixed: AS 1/2/3 - Fast switching of scripts causing incorrect caret position remembered

Fixed: AS 1/2 - Remembering caret position for frames
This commit is contained in:
Jindra Petřík
2025-05-02 08:45:26 +02:00
parent a8114651e3
commit d9c866c7d6
8 changed files with 126 additions and 39 deletions

View File

@@ -45,6 +45,8 @@ All notable changes to this project will be documented in this file.
- [#2355] AS1/2 Simplify expressions feature colliding with some other features like hex values
- Exception on FFDec start when simple editor is on
- [#2419] AS3 - There should be empty line after class header
- AS 1/2/3 - Fast switching of scripts causing incorrect caret position remembered
- AS 1/2 - Remembering caret position for frames
## [22.0.2] - 2025-01-17
### Added

View File

@@ -235,12 +235,12 @@ public class TraitClass extends Trait implements TraitWithSlot {
}
}
}
//class header
instanceInfo.getClassHeaderStr(convertData.assetsDir, writer, abc, fullyQualifiedNames, false, allowEmbed);
writer.endTrait();
writer.startBlock();
writer.startClass(class_info);
writer.startBlock();
first.setVal(true);

View File

@@ -1001,12 +1001,14 @@ public abstract class Action implements GraphSourceItem {
throw ex;
} catch (Exception | OutOfMemoryError | StackOverflowError ex) {
ex.printStackTrace();
convertException = ex;
Throwable cause = ex.getCause();
if (ex instanceof ExecutionException && cause instanceof Exception) {
convertException = cause;
}
if (ex instanceof ExecutionException && cause instanceof InterruptedException) {
throw (InterruptedException) cause;
}
if (convertException instanceof TimeoutException) {
logger.log(Level.SEVERE, "Decompilation timeout in: " + path, convertException);
} else {

View File

@@ -420,6 +420,19 @@ public abstract class GraphTextWriter {
public GraphTextWriter startBlock() {
return startBlock("{");
}
/**
* Starts block, but do not continue to new line.
* @return GraphTextWriter
*/
public GraphTextWriter startBlockNoNewLine() {
if (formatting.beginBlockOnNewLine) {
newLine();
} else {
append(" ");
}
return append("{");
}
/**
* Ends block.

View File

@@ -20,6 +20,7 @@ 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.timeline.TagScript;
import com.jpexs.decompiler.flash.treeitems.AS3ClassTreeItem;
import com.jpexs.decompiler.flash.treeitems.FolderItem;
import com.jpexs.decompiler.flash.treeitems.TreeItem;
@@ -29,7 +30,10 @@ import java.util.List;
import java.util.Objects;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JScrollPane;
import javax.swing.text.BadLocationException;
/**
* Storage for remembering scroll/caret positions of scripts / preview folder.
@@ -115,6 +119,11 @@ public class ScrollPosStorage {
//move to bottom
storage.remove(index);
storage.add(sitem);
TreeItem asmItem = item;
if (asmItem instanceof TagScript) {
asmItem = ((TagScript) item).getTag();
}
if (Configuration.rememberScriptsScrollPos.get()) {
if (item instanceof ScriptPack) {
@@ -122,7 +131,7 @@ public class ScrollPosStorage {
@Override
public void run() {
if (sitem.getActionScriptCaret() < mainPanel.getABCPanel().decompiledTextArea.getDocument().getLength()) {
mainPanel.getABCPanel().decompiledTextArea.setCaretPosition(sitem.getActionScriptCaret());
mainPanel.getABCPanel().decompiledTextArea.setCaretPositionForCurrentScript(sitem.getActionScriptCaret(), (ScriptPack) item);
}
try {
@@ -149,10 +158,10 @@ public class ScrollPosStorage {
}
});
} else if (item instanceof ASMSource) {
} else if (asmItem instanceof ASMSource) {
mainPanel.getActionPanel().runWhenLoaded(new Runnable() {
@Override
public void run() {
public void run() {
if (sitem.getActionScriptCaret() < mainPanel.getActionPanel().decompiledEditor.getDocument().getLength()) {
mainPanel.getActionPanel().decompiledEditor.setCaretPosition(sitem.getActionScriptCaret());
}
@@ -203,10 +212,15 @@ public class ScrollPosStorage {
public void saveScrollPos(TreeItem item) {
boolean doSave = false;
TreeItem asmItem = item;
if (item instanceof TagScript) {
asmItem = ((TagScript) item).getTag();
}
if (item instanceof ScriptPack) {
doSave = true;
}
if (item instanceof ASMSource) {
if (asmItem instanceof ASMSource) {
doSave = true;
}
if (item instanceof FolderItem) {
@@ -230,19 +244,38 @@ public class ScrollPosStorage {
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();
synchronized (mainPanel.getABCPanel().decompiledTextArea) {
if (!mainPanel.getABCPanel().decompiledTextArea.isScriptLoaded()) {
return;
}
if (mainPanel.getABCPanel().decompiledTextArea.getScriptLeaf() != item) {
return;
}
actionScriptCaret = mainPanel.getABCPanel().decompiledTextArea.getCaretPosition();
actionScriptScrollHorizontal = mainPanel.getABCPanel().decompiledScrollPane.getHorizontalScrollBar().getValue();
actionScriptScrollVertical = mainPanel.getABCPanel().decompiledScrollPane.getVerticalScrollBar().getValue();
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 (asmItem instanceof ASMSource) {
synchronized (mainPanel.getActionPanel()) {
if (!mainPanel.getActionPanel().isScriptLoaded()) {
return;
}
if (mainPanel.getActionPanel().getSrc() != asmItem) {
return;
}
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;

View File

@@ -2111,9 +2111,8 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener<Scr
setDecompiledEditMode(false);
detailPanel.setEditMode(false);
detailPanel.methodTraitPanel.methodCodePanel.clear();
decompiledTextArea.setNoTrait();
setAbc(scriptPack.abc);
decompiledTextArea.setScript(scriptPack, true);
decompiledTextArea.setNoTrait();
decompiledTextArea.setScript(scriptPack, true);
}
}

View File

@@ -60,6 +60,8 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.Token;
import jsyntaxpane.TokenType;
@@ -97,6 +99,10 @@ public class DecompiledEditorPane extends DebuggableEditorPane implements CaretL
private boolean scriptLoaded = true;
public synchronized boolean isScriptLoaded() {
return scriptLoaded;
}
public void addScriptListener(Runnable l) {
scriptListeners.add(l);
}
@@ -140,7 +146,7 @@ public class DecompiledEditorPane extends DebuggableEditorPane implements CaretL
return script.abc.findTraitByTraitId(classIndex, lastTraitIndex);
}
public ScriptPack getScriptLeaf() {
public synchronized ScriptPack getScriptLeaf() {
return script;
}
@@ -870,21 +876,27 @@ public class DecompiledEditorPane extends DebuggableEditorPane implements CaretL
this.abcPanel = abcPanel;
}
public void clearScript() {
public synchronized void clearScript() {
script = null;
}
public void setScript(ScriptPack scriptLeaf, boolean force) {
View.checkAccess();
if (setSourceWorker != null) {
setSourceWorker.cancel(true);
setSourceWorker = null;
}
scriptLoaded = false;
synchronized (this) {
scriptLoaded = false;
}
if (!force && this.script == scriptLeaf) {
scriptLoaded = true;
if (!force && this.script == scriptLeaf) {
synchronized (this) {
scriptLoaded = true;
}
fireScript();
return;
}
@@ -974,7 +986,7 @@ public class DecompiledEditorPane extends DebuggableEditorPane implements CaretL
}
}
private void setSourceCompleted(ScriptPack scriptLeaf, HighlightedText decompiledText) {
private synchronized void setSourceCompleted(ScriptPack scriptLeaf, HighlightedText decompiledText) {
View.checkAccess();
if (decompiledText == null) {
@@ -991,19 +1003,22 @@ public class DecompiledEditorPane extends DebuggableEditorPane implements CaretL
} else {
abcPanel.brokenHintPanel.setVisible(false);
}
setText(hilightedCode);
if (highlightedText.getClassHighlights().size() > 0) {
try {
setCaretPosition(highlightedText.getClassHighlights().get(0).startPos);
int pos = highlightedText.getClassHighlights().get(0).startPos + 1;
setCaretPosition(pos); //+1 for position just after class name
caretUpdate(null);
} catch (Exception ex) { //sometimes happens
//ignore
}
}
}
scriptLoaded = true;
scriptLoaded = true;
fireScript();
}
@@ -1030,7 +1045,7 @@ public class DecompiledEditorPane extends DebuggableEditorPane implements CaretL
}
@Override
public void setText(String t) {
public synchronized void setText(String t) {
super.setText(t);
setCaretPosition(0);
}
@@ -1054,4 +1069,19 @@ public class DecompiledEditorPane extends DebuggableEditorPane implements CaretL
// not found: so return existing text
return super.getToolTipText();
}
public synchronized void setCaretPositionForCurrentScript(int position, ScriptPack expectedScript) {
if (expectedScript != this.script) {
return;
}
if (!scriptLoaded) {
return;
}
setCaretPosition(position);
}
@Override
public synchronized void setCaretPosition(int position) {
super.setCaretPosition(position);
}
}

View File

@@ -194,6 +194,10 @@ public class ActionPanel extends JPanel implements SearchListener<ScriptSearchRe
private boolean scriptLoaded = true;
public synchronized boolean isScriptLoaded() {
return scriptLoaded;
}
public void addScriptListener(Runnable listener) {
scriptListeners.add(listener);
}
@@ -202,7 +206,7 @@ public class ActionPanel extends JPanel implements SearchListener<ScriptSearchRe
scriptListeners.remove(listener);
}
public void runWhenLoaded(Runnable l) {
public synchronized void runWhenLoaded(Runnable l) {
if (scriptLoaded) {
l.run();
} else {
@@ -223,7 +227,7 @@ public class ActionPanel extends JPanel implements SearchListener<ScriptSearchRe
}
}
public void clearSource() {
public synchronized void clearSource() {
View.checkAccess();
lastCode = null;
@@ -492,9 +496,9 @@ public class ActionPanel extends JPanel implements SearchListener<ScriptSearchRe
return listener;
}
public void setSource(final ASMSource src, final boolean useCache) {
public synchronized void setSource(final ASMSource src, final boolean useCache) {
View.checkAccess();
scriptLoaded = false;
if (setSourceWorker != null) {
@@ -610,7 +614,7 @@ public class ActionPanel extends JPanel implements SearchListener<ScriptSearchRe
}
}
private void setSourceCompleted(ASMSource asm, HighlightedText decompiledText, ActionList actions) {
private synchronized void setSourceCompleted(ASMSource asm, HighlightedText decompiledText, ActionList actions) {
View.checkAccess();
if (decompiledText == null) {
@@ -1430,4 +1434,8 @@ public class ActionPanel extends JPanel implements SearchListener<ScriptSearchRe
return (saveButton.isVisible() && saveButton.isEnabled())
|| (saveDecompiledButton.isVisible() && saveDecompiledButton.isEnabled());
}
public synchronized ASMSource getSrc() {
return src;
}
}