From 982b44a0e6061179068d5288e53d2f296cd3c0b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sat, 21 Oct 2023 00:04:07 +0200 Subject: [PATCH] Added ActionScript Debugger - Call stack frames switching - view variables around call stack Added ActionScript Debugger - Highlight lines of callstack Changed Basic tag info panel always visible even when nothing to display (to avoid flickering) --- CHANGELOG.md | 5 + .../decompiler/flash/gui/DebugPanel.java | 104 ++------- .../decompiler/flash/gui/DebugStackPanel.java | 166 +++++++++++++++ .../decompiler/flash/gui/DebuggerHandler.java | 73 ++++++- src/com/jpexs/decompiler/flash/gui/Main.java | 11 +- .../jpexs/decompiler/flash/gui/MainPanel.java | 197 +++++++++++++----- .../decompiler/flash/gui/TagInfoPanel.java | 4 +- .../decompiler/flash/gui/abc/ABCPanel.java | 4 +- .../flash/gui/action/ActionPanel.java | 3 + .../gui/editor/DebuggableEditorPane.java | 25 +++ .../gui/editor/LineMarkedEditorPane.java | 11 + 11 files changed, 460 insertions(+), 143 deletions(-) create mode 100644 src/com/jpexs/decompiler/flash/gui/DebugStackPanel.java diff --git a/CHANGELOG.md b/CHANGELOG.md index a4a1618ed..84ce2f3ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,12 +8,17 @@ All notable changes to this project will be documented in this file. do not restore window size to larger value that actual screen size - [#1717] AS1/2/3 Option to hide P-code panel - [#2005] Export files to directories by bundle names on multiple bundle (zips, etc.) selection +- ActionScript Debugger - Call stack frames switching - view variables around call stack +- ActionScript Debugger - Highlight lines of callstack ### Fixed - [#1306], [#1768] Maximizing window on other than main monitor - AS3 Cast exception when used tree filter and then direct editing - [#2013] AS3 Multiname renaming - closing the script when renaming the class, nullpointer exception +### Changed +- Basic tag info panel always visible even when nothing to display (to avoid flickering) + ## [19.1.2] - 2023-10-16 ### Fixed - [#2099] Smart number formatting always on diff --git a/src/com/jpexs/decompiler/flash/gui/DebugPanel.java b/src/com/jpexs/decompiler/flash/gui/DebugPanel.java index 29bb43de4..fe0eb1f69 100644 --- a/src/com/jpexs/decompiler/flash/gui/DebugPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/DebugPanel.java @@ -61,18 +61,16 @@ public class DebugPanel extends JPanel { private MyTreeTable debugLocalsTable; //JTable debugLocalsTable; - private MyTreeTable debugScopeTable; - - private JTable callStackTable; - - private JTable stackTable; + private MyTreeTable debugScopeTable; private JTable constantPoolTable; private JTabbedPane varTabs; - private BreakListener listener; + private BreakListener breakListener; + private DebuggerHandler.FrameChangeListener frameChangeListener; + private JTextArea traceLogTextarea; private int logLength = 0; @@ -215,8 +213,6 @@ public class DebugPanel extends JPanel { //debugScopeTable.addMouseListener(watchHandler); debugScopeTable = new MyTreeTable(new ABCPanel.VariablesTableModel(debugScopeTable, new ArrayList<>(), new ArrayList<>()), false); - callStackTable = new JTable(); - stackTable = new JTable(); constantPoolTable = new JTable(); traceLogTextarea = new JTextArea(); traceLogTextarea.setEditable(false); @@ -258,30 +254,33 @@ public class DebugPanel extends JPanel { refresh(); } }); + + Main.getDebugHandler().addFrameChangeListener(frameChangeListener = new DebuggerHandler.FrameChangeListener() { + @Override + public void frameChanged() { + View.execInEventDispatchLater(new Runnable() { + @Override + public void run() { + refresh(); + } + }); + } + }); - Main.getDebugHandler().addBreakListener(listener = new DebuggerHandler.BreakListener() { + Main.getDebugHandler().addBreakListener(breakListener = new DebuggerHandler.BreakListener() { @Override public void doContinue() { View.execInEventDispatch(new Runnable() { - @Override public void run() { refresh(); } - }); } @Override - public void breakAt(String scriptName, int line, int classIndex, int traitIndex, int methodIndex) { - View.execInEventDispatch(new Runnable() { - - @Override - public void run() { - refresh(); - } - }); + public void breakAt(String scriptName, int line, int classIndex, int traitIndex, int methodIndex) { } }); @@ -406,52 +405,6 @@ public class DebugPanel extends JPanel { debugLocalsTable.setTreeModel(new ABCPanel.VariablesTableModel(debugLocalsTable, new ArrayList<>(), new ArrayList<>())); debugScopeTable.setTreeModel(new ABCPanel.VariablesTableModel(debugScopeTable, new ArrayList<>(), new ArrayList<>())); } - InBreakAtExt info = Main.getDebugHandler().getBreakInfo(); - if (info != null) { - //InBreakReason reason = Main.getDebugHandler().getBreakReason(); - List callStackFiles = new ArrayList<>(); - List callStackLines = new ArrayList<>(); - - callStackFiles.add(Main.getDebugHandler().moduleToString(info.file)); - callStackLines.add(info.line); - - for (int i = 0; i < info.files.size(); i++) { - callStackFiles.add(Main.getDebugHandler().moduleToString(info.files.get(i))); - callStackLines.add(info.lines.get(i)); - } - Object[][] data = new Object[callStackFiles.size()][2]; - for (int i = 0; i < callStackFiles.size(); i++) { - data[i][0] = callStackFiles.get(i); - data[i][1] = callStackLines.get(i); - } - - DefaultTableModel tm = new DefaultTableModel(data, new Object[]{ - AppStrings.translate("callStack.header.file"), - AppStrings.translate("callStack.header.line") - }) { - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - - }; - callStackTable.setModel(tm); - - Object[][] data2 = new Object[info.stacks.size()][1]; - for (int i = 0; i < info.stacks.size(); i++) { - data2[i][0] = info.stacks.get(i); - } - stackTable.setModel(new DefaultTableModel(data2, new Object[]{AppStrings.translate("stack.header.item")}) { - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - - }); - } else { - callStackTable.setModel(new DefaultTableModel()); - stackTable.setModel(new DefaultTableModel()); - } InConstantPool cpool = Main.getDebugHandler().getConstantPool(); if (cpool != null) { Object[][] data2 = new Object[cpool.vars.size()][2]; @@ -469,6 +422,8 @@ public class DebugPanel extends JPanel { } }); + } else { + constantPoolTable.setModel(new DefaultTableModel()); } varTabs.removeAll(); @@ -503,21 +458,7 @@ public class DebugPanel extends JPanel { pa.add(new FasterScrollPane(constantPoolTable), BorderLayout.CENTER); varTabs.addTab(AppStrings.translate("constantpool.header"), pa); } - - if (callStackTable.getRowCount() > 0) { - tabTypes.add(SelectedTab.CALLSTACK); - - pa = new JPanel(new BorderLayout()); - pa.add(new FasterScrollPane(callStackTable), BorderLayout.CENTER); - varTabs.addTab(AppStrings.translate("callStack.header"), pa); - } - if (stackTable.getRowCount() > 0) { - tabTypes.add(SelectedTab.STACK); - - pa = new JPanel(new BorderLayout()); - pa.add(new FasterScrollPane(stackTable), BorderLayout.CENTER); - varTabs.addTab(AppStrings.translate("stack.header"), pa); - } + if (logLength > 0) { tabTypes.add(SelectedTab.LOG); @@ -560,6 +501,7 @@ public class DebugPanel extends JPanel { } public void dispose() { - Main.getDebugHandler().removeBreakListener(listener); + Main.getDebugHandler().removeBreakListener(breakListener); + Main.getDebugHandler().removeFrameChangeListener(frameChangeListener); } } diff --git a/src/com/jpexs/decompiler/flash/gui/DebugStackPanel.java b/src/com/jpexs/decompiler/flash/gui/DebugStackPanel.java new file mode 100644 index 000000000..b057dc0ba --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/DebugStackPanel.java @@ -0,0 +1,166 @@ +/* + * 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.debugger.flash.messages.in.InBreakAtExt; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableCellRenderer; + +/** + * + * @author JPEXS + */ +public class DebugStackPanel extends JPanel { + + private JTable stackTable; + + private boolean active = false; + + private int depth = 0; + + public DebugStackPanel() { + stackTable = new JTable(); + Main.getDebugHandler().addFrameChangeListener(new DebuggerHandler.FrameChangeListener() { + @Override + public void frameChanged() { + depth = Main.getDebugHandler().getDepth(); + refresh(); + } + }); + Main.getDebugHandler().addBreakListener(new DebuggerHandler.BreakListener() { + @Override + public void breakAt(String scriptName, int line, int classIndex, int traitIndex, int methodIndex) { + + } + + @Override + public void doContinue() { + clear(); + } + }); + + Main.getDebugHandler().addConnectionListener(new DebuggerHandler.ConnectionListener() { + @Override + public void connected() { + } + + @Override + public void disconnected() { + clear(); + } + }); + + //JLabel titleLabel = new JLabel(AppStrings.translate("callStack.header"), JLabel.CENTER); + + setLayout(new BorderLayout()); + //add(titleLabel, BorderLayout.NORTH); + add(new FasterScrollPane(stackTable), BorderLayout.CENTER); + + stackTable.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton(e)) { + int row = stackTable.rowAtPoint(e.getPoint()); + if (row >= 0) { + String scriptName = (String) stackTable.getModel().getValueAt(row, 0); + int line = (int)(Integer) stackTable.getModel().getValueAt(row, 1); + Main.getMainFrame().getPanel().gotoScriptLine(Main.getMainFrame().getPanel().getCurrentSwf(), + scriptName, line, -1, -1, -1); + Main.getDebugHandler().setDepth(row); + } + } + } + }); + } + + public void clear() { + stackTable.setModel(new DefaultTableModel()); + active = false; + } + + public boolean isActive() { + return active; + } + + public void refresh() { + InBreakAtExt info = Main.getDebugHandler().getBreakInfo(); + if (info == null) { + clear(); + return; + } + active = true; + Object[][] data = new Object[info.files.size()][3]; + for (int i = 0; i < info.files.size(); i++) { + data[i][0] = Main.getDebugHandler().moduleToString(info.files.get(i)); + data[i][1] = info.lines.get(i); + data[i][2] = info.stacks.get(i); + } + + DefaultTableModel tm = new DefaultTableModel(data, new Object[]{ + AppStrings.translate("callStack.header.file"), + AppStrings.translate("callStack.header.line"), + AppStrings.translate("stack.header.item") + }) { + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + + }; + stackTable.setModel(tm); + + View.execInEventDispatchLater(new Runnable() { + @Override + public void run() { + TableCellRenderer renderer = new DefaultTableCellRenderer() { + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if (row == depth) { + label.setFont(label.getFont().deriveFont(Font.BOLD)); + } + return label; + } + + }; + stackTable.getColumnModel().getColumn(0).setCellRenderer(renderer); + stackTable.getColumnModel().getColumn(1).setCellRenderer(renderer); + stackTable.getColumnModel().getColumn(2).setCellRenderer(renderer); + repaint(); + } + }); + } + + public int getDepth() { + return depth; + } + + public void setDepth(int depth) { + this.depth = depth; + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java index 79ceb0702..370df3192 100644 --- a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java +++ b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java @@ -103,6 +103,10 @@ public class DebuggerHandler implements DebugConnectionListener { private int breakIp = -1; private String breakScriptName = null; + + private List stackScriptNames = new ArrayList<>(); + + private List stackLines = new ArrayList<>(); public static class ActionScriptException extends Exception { @@ -129,12 +133,30 @@ public class DebuggerHandler implements DebugConnectionListener { return breakIp; } + public int getDepth() { + return depth; + } + public String getBreakScriptName() { if (!isPaused()) { return "-"; } return breakScriptName; } + + public synchronized List getStackScripts() { + if (!isPaused()) { + return new ArrayList<>(); + } + return stackScriptNames; + } + + public synchronized List getStackLines() { + if (!isPaused()) { + return new ArrayList<>(); + } + return stackLines; + } public InGetVariable getVariable(long parentId, String varName, boolean children) { try { @@ -324,6 +346,8 @@ public class DebuggerHandler implements DebugConnectionListener { } private InFrame frame; + + private int depth; private InConstantPool pool; @@ -334,9 +358,16 @@ public class DebuggerHandler implements DebugConnectionListener { private final List breakListeners = new CopyOnWriteArrayList<>(); private final List traceListeners = new ArrayList<>(); + + private final List frameChangeListeners = new ArrayList<>(); private final List clisteners = new ArrayList<>(); + public void setDepth(int depth) { + this.depth = depth; + refreshFrame(); + } + public String moduleToString(int file) { if (!modulePaths.containsKey(file)) { return "unknown"; @@ -369,6 +400,11 @@ public class DebuggerHandler implements DebugConnectionListener { public void trace(String... val); } + + public static interface FrameChangeListener { + + public void frameChanged(); + } public static interface BreakListener { @@ -380,6 +416,14 @@ public class DebuggerHandler implements DebugConnectionListener { public void addBreakListener(BreakListener l) { breakListeners.add(l); } + + public void addFrameChangeListener(FrameChangeListener l) { + frameChangeListeners.add(l); + } + + public void removeFrameChangeListener(FrameChangeListener l) { + frameChangeListeners.remove(l); + } public void addTraceListener(TraceListener l) { traceListeners.add(l); @@ -406,11 +450,14 @@ public class DebuggerHandler implements DebugConnectionListener { return; } try { - frame = commands.getFrame(0); + frame = commands.getFrame(depth); pool = commands.getConstantPool(0); } catch (IOException ex) { //ignore } + for (FrameChangeListener l : frameChangeListeners) { + l.frameChanged(); + } } public synchronized InFrame getFrame() { @@ -438,8 +485,8 @@ public class DebuggerHandler implements DebugConnectionListener { public List getSwfs() { return swfs; - } - + } + public void disconnect() { frame = null; pool = null; @@ -586,6 +633,7 @@ public class DebuggerHandler implements DebugConnectionListener { name = DottedChain.parseWithSuffix(pkg).addWithSuffix(clsNameWithSuffix).toString(); } } + Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "Script added - index {0} name: {1}", new Object[]{file, name}); modulePaths.put(file, name); scriptToModule.put(name, file); con.dropMessage(sc); @@ -714,6 +762,16 @@ public class DebuggerHandler implements DebugConnectionListener { synchronized (DebuggerHandler.this) { breakScriptName = newBreakScriptName; breakIp = message.line; + + if (breakInfo != null) { + List files = new ArrayList<>(); + for (int i = 0; i < breakInfo.files.size(); i++) { + files.add(Main.getDebugHandler().moduleToString(breakInfo.files.get(i))); + } + stackScriptNames = files; + List lines = new ArrayList<>(breakInfo.lines); + stackLines = lines; + } } if (reasonInt == InBreakReason.REASON_SCRIPT_LOADED) { @@ -725,9 +783,8 @@ public class DebuggerHandler implements DebugConnectionListener { } else { Main.startWork(AppStrings.translate("work.breakat") + newBreakScriptName + ":" + message.line + " " + AppStrings.translate("debug.break.reason." + reason), null); } - frame = commands.getFrame(0); - pool = commands.getConstantPool(0); - + depth = 0; + refreshFrame(); for (BreakListener l : breakListeners) { l.breakAt(newBreakScriptName, message.line, moduleToClassIndex.containsKey(message.file) ? moduleToClassIndex.get(message.file) : -1, @@ -746,13 +803,13 @@ public class DebuggerHandler implements DebugConnectionListener { synchronized (this) { connected = true; } - if (!isAS3) { + /*if (!isAS3) { try { commands.getConnection().writeMessage(new OutRewind(commands.getConnection())); } catch (IOException ex) { Logger.getLogger(DebuggerHandler.class.getName()).log(Level.SEVERE, null, ex); } - } + }*/ for (ConnectionListener l : clisteners) { l.connected(); diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index 7af7c62c9..2f0fe453a 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -22,6 +22,7 @@ import com.eclipsesource.json.JsonObject; import com.eclipsesource.json.JsonValue; import com.jpexs.debugger.flash.Debugger; import com.jpexs.debugger.flash.DebuggerCommands; +import com.jpexs.debugger.flash.DebuggerConnection; import com.jpexs.debugger.flash.Variable; import com.jpexs.debugger.flash.VariableType; import com.jpexs.debugger.flash.messages.in.InCallFunction; @@ -682,6 +683,14 @@ public class Main { public static synchronized String getIpClass() { return getDebugHandler().getBreakScriptName(); } + + public static synchronized List getStackLines() { + return getDebugHandler().getStackLines(); + } + + public static synchronized List getStackClasses() { + return getDebugHandler().getStackScripts(); + } public static synchronized boolean isBreakPointValid(String scriptName, int line) { return !getDebugHandler().isBreakpointInvalid(scriptName, line); @@ -3201,6 +3210,6 @@ public class Main { } catch (Exception ex) { throw new RuntimeException("Problems with creating the log files"); - } + } } } diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 6b3deb3c5..22a2ca348 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -366,11 +366,13 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se private static final String CARDHEADER = "Header card"; - private static final String DETAILCARDAS3NAVIGATOR = "Traits list"; + private static final int DETAILCARDAS3NAVIGATOR = 1; - private static final String DETAILCARDTAGINFO = "Tag information"; + private static final int DETAILCARDTAGINFO = 0; - private static final String DETAILCARDEMPTYPANEL = "Empty card"; + private static final int DETAILCARDEMPTYPANEL = -1; + + private static final int DETAILCARDDEBUGSTACKFRAME = 2; private static final String SPLIT_PANE1 = "SPLITPANE1"; @@ -390,7 +392,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se private final JPersistentSplitPane splitPane2; - private JPanel detailPanel; + private JTabbedPane detailPanel; private QuickTreeFindPanel quickTreeFindPanel; @@ -411,6 +413,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se private final PreviewPanel dumpPreviewPanel; private final TagInfoPanel tagInfoPanel; + + private final DebugStackPanel debugStackPanel; private TreePanelMode treePanelMode; @@ -1024,7 +1028,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se public String translate(String key) { return mainFrame.translate(key); } - + public MainPanel(MainFrame mainFrame, MainFrameMenu mainMenu, FlashPlayerPanel flashPanel, FlashPlayerPanel previewFlashPanel) { super(); @@ -1038,18 +1042,56 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se setLayout(new BorderLayout()); openables = new ObservableList<>(); - detailPanel = new JPanel(); - detailPanel.setLayout(new CardLayout()); + detailPanel = new JTabbedPane(); + //detailPanel.setLayout(new CardLayout()); - JPanel whitePanel = new JPanel(); + /*JPanel whitePanel = new JPanel(); if (View.isOceanic()) { whitePanel.setBackground(Color.white); } detailPanel.add(whitePanel, DETAILCARDEMPTYPANEL); - +*/ tagInfoPanel = new TagInfoPanel(this); - detailPanel.add(tagInfoPanel, DETAILCARDTAGINFO); + + debugStackPanel = new DebugStackPanel(); + Main.getDebugHandler().addBreakListener(new DebuggerHandler.BreakListener() { + @Override + public void breakAt(String scriptName, int line, int classIndex, int traitIndex, int methodIndex) { + View.execInEventDispatchLater(new Runnable() { + @Override + public void run() { + showDetail(DETAILCARDDEBUGSTACKFRAME); + } + }); + } + @Override + public void doContinue() { + View.execInEventDispatchLater(new Runnable() { + @Override + public void run() { + showDetail(DETAILCARDEMPTYPANEL); + } + }); + } + }); + Main.getDebugHandler().addConnectionListener(new DebuggerHandler.ConnectionListener(){ + @Override + public void connected() { + + } + + @Override + public void disconnected() { + View.execInEventDispatchLater(new Runnable() { + @Override + public void run() { + reload(true); + } + }); + } + }); + UIManager.getDefaults().put("TreeUI", BasicTreeUI.class.getName()); tagTree = new TagTree(null, this); tagTree.addTreeSelectionListener(this); @@ -1412,8 +1454,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se public ABCPanel getABCPanel() { if (abcPanel == null) { abcPanel = new ABCPanel(this); - displayPanel.add(abcPanel, CARDACTIONSCRIPT3PANEL); - detailPanel.add(abcPanel.navigatorPanel, DETAILCARDAS3NAVIGATOR); + displayPanel.add(abcPanel, CARDACTIONSCRIPT3PANEL); } return abcPanel; @@ -2486,32 +2527,57 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se public void gotoScriptLine(SWF swf, String scriptName, int line, int classIndex, int traitIndex, int methodIndex) { View.checkAccess(); - gotoScriptName(swf, scriptName); - if (abcPanel != null) { - if (Main.isDebugPCode()) { - if (classIndex != -1) { - boolean classChanged = false; - if (abcPanel.decompiledTextArea.getClassIndex() != classIndex) { - abcPanel.decompiledTextArea.setClassIndex(classIndex); - classChanged = true; - } - if (traitIndex != -10 && (classChanged || abcPanel.decompiledTextArea.lastTraitIndex != traitIndex)) { - abcPanel.decompiledTextArea.gotoTrait(traitIndex); - } - } - abcPanel.detailPanel.methodTraitPanel.methodCodePanel.gotoInstrLine(line); - } else { - abcPanel.decompiledTextArea.gotoLine(line); - } - } else if (actionPanel != null) { - if (Main.isDebugPCode()) { - actionPanel.editor.gotoLine(line); - } else { - actionPanel.decompiledEditor.gotoLine(line); - } + if (abcPanel != null && swf.isAS3()) { + abcPanel.decompiledTextArea.addScriptListener(new Runnable() { + @Override + public void run() { + abcPanel.decompiledTextArea.removeScriptListener(this); + View.execInEventDispatchLater(new Runnable() { + @Override + public void run() { + if (Main.isDebugPCode()) { + if (classIndex != -1) { + boolean classChanged = false; + if (abcPanel.decompiledTextArea.getClassIndex() != classIndex) { + abcPanel.decompiledTextArea.setClassIndex(classIndex); + classChanged = true; + } + if (traitIndex != -10 && (classChanged || abcPanel.decompiledTextArea.lastTraitIndex != traitIndex)) { + abcPanel.decompiledTextArea.gotoTrait(traitIndex); + } + } + abcPanel.detailPanel.methodTraitPanel.methodCodePanel.gotoInstrLine(line); + } else { + abcPanel.decompiledTextArea.gotoLine(line); + } + scrollPosStorage.saveScrollPos(oldItem); + refreshBreakPoints(); + } + }); + } + }); + + } else if (actionPanel != null && !swf.isAS3()) { + actionPanel.addScriptListener(new Runnable() { + @Override + public void run() { + actionPanel.removeScriptListener(this); + View.execInEventDispatchLater(new Runnable() { + @Override + public void run() { + if (Main.isDebugPCode()) { + actionPanel.editor.gotoLine(line); + } else { + actionPanel.decompiledEditor.gotoLine(line); + } + scrollPosStorage.saveScrollPos(oldItem); + refreshBreakPoints(); + } + }); + } + }); } - refreshBreakPoints(); - + gotoScriptName(swf, scriptName); } public void refreshBreakPoints() { @@ -2561,11 +2627,16 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se String rawScriptName = scriptName; if (rawScriptName.startsWith("#PCODE ")) { rawScriptName = rawScriptName.substring("#PCODE ".length()); - } + } Map asms = swf.getASMs(true); - if (actionPanel != null && asms.containsKey(rawScriptName)) { - actionPanel.setSource(asms.get(rawScriptName), true); + if (asms.containsKey(rawScriptName)) { + oldItem = null; + getCurrentTree().setSelectionPath(null); + setTagTreeSelectedNode(getCurrentTree(), asms.get(rawScriptName)); } + /*if (actionPanel != null && asms.containsKey(rawScriptName)) { + actionPanel.setSource(asms.get(rawScriptName), true); + }*/ } } @@ -4698,16 +4769,40 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } return null; - } + } - private void showDetail(String card) { - CardLayout cl = (CardLayout) (detailPanel.getLayout()); - cl.show(detailPanel, card); - if (card.equals(DETAILCARDEMPTYPANEL)) { - if (detailPanel.isVisible()) { - detailPanel.setVisible(false); + private void showDetail(int card) { + if (debugStackPanel.isActive() && card != DETAILCARDDEBUGSTACKFRAME) { + return; + } + + detailPanel.removeAll(); + int pos = 0; + + if (card == DETAILCARDTAGINFO) { + detailPanel.addTab(AppStrings.translate("taginfo.header"), tagInfoPanel); + if (card == DETAILCARDTAGINFO) { + detailPanel.setSelectedIndex(pos); } - } else if (!detailPanel.isVisible()) { + pos++; + } + if (card == DETAILCARDAS3NAVIGATOR || card == DETAILCARDDEBUGSTACKFRAME) { + if (abcPanel != null && getCurrentSwf() != null && getCurrentSwf().isAS3()) { + detailPanel.addTab(AppStrings.translate("traits"), abcPanel.navigatorPanel); + if (card == DETAILCARDAS3NAVIGATOR) { + detailPanel.setSelectedIndex(pos); + } + pos++; + } + } + if (debugStackPanel.isActive()) { + detailPanel.addTab(AppStrings.translate("callStack.header"), debugStackPanel); + if (card == DETAILCARDDEBUGSTACKFRAME) { + detailPanel.setSelectedIndex(pos); + } + pos++; + } + if (currentView != VIEW_DUMP) { detailPanel.setVisible(true); } } @@ -4971,9 +5066,11 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } showTreePanelCard(DUMP_VIEW); treePanelMode = TreePanelMode.DUMP_TREE; - showDetail(DETAILCARDEMPTYPANEL); + //showDetail(DETAILCARDEMPTYPANEL); + showDetail(DETAILCARDEMPTYPANEL); reload(true); updateUiWithCurrentOpenable(); + detailPanel.setVisible(false); return true; case VIEW_RESOURCES: pinsPanel.setVisible(true); @@ -4993,6 +5090,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } }); + detailPanel.setVisible(true); refreshPins(); reload(true); updateUiWithCurrentOpenable(); @@ -5029,6 +5127,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } showTreePanelCard(TAGLIST_VIEW); treePanelMode = TreePanelMode.TAGLIST_TREE; + detailPanel.setVisible(true); refreshPins(); reload(true); updateUiWithCurrentOpenable(); diff --git a/src/com/jpexs/decompiler/flash/gui/TagInfoPanel.java b/src/com/jpexs/decompiler/flash/gui/TagInfoPanel.java index d844563e5..c599560a9 100644 --- a/src/com/jpexs/decompiler/flash/gui/TagInfoPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/TagInfoPanel.java @@ -54,8 +54,8 @@ public class TagInfoPanel extends JPanel { public TagInfoPanel(MainPanel mainPanel) { this.mainPanel = mainPanel; setLayout(new BorderLayout()); - JLabel topLabel = new JLabel(AppStrings.translate("taginfo.header"), JLabel.CENTER); - add(topLabel, BorderLayout.NORTH); + //JLabel topLabel = new JLabel(AppStrings.translate("taginfo.header"), JLabel.CENTER); + //add(topLabel, BorderLayout.NORTH); add(new FasterScrollPane(editorPane), BorderLayout.CENTER); editorPane.setContentType("text/html"); diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java index 8d3172463..3e28fb235 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java @@ -1116,8 +1116,8 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener 0 && ipPath != null && ipPath.equals(scriptName)) { addColorMarker(ip + firstLineOffset(), IP_MARKER); } + List stackLines = Main.getStackLines(); + List stackClasses = Main.getStackClasses(); + for (int i = 1; i < stackClasses.size(); i++) { + String cls = stackClasses.get(i); + int line = stackLines.get(i); + if (cls.equals(scriptName)) { + addColorMarker(line + firstLineOffset(), STACK_MARKER); + } + } } @Override @@ -161,6 +179,13 @@ public class DebuggableEditorPane extends LineMarkedEditorPane implements BreakP ((Graphics2D) g).setStroke(new BasicStroke(0.5f)); boolean drawText = true; + if (hasColorMarker(line, STACK_MARKER)) { + g.setColor(BG_STACK_COLOR); + g.fillPolygon(new int[]{x + 5, x + 15, x + 15}, new int[]{textY, textY, textY - 10}, 3); + g.setColor(Color.black); + g.drawPolygon(new int[]{x + 5, x + 15, x + 15}, new int[]{textY, textY, textY - 10}, 3); + drawText = false; + } if (hasColorMarker(line, INVALID_BREAKPOINT_MARKER)) { g.setColor(BG_INVALID_BREAKPOINT_COLOR); g.fillOval(x + 5, textY - 10, 10, 10); diff --git a/src/com/jpexs/decompiler/flash/gui/editor/LineMarkedEditorPane.java b/src/com/jpexs/decompiler/flash/gui/editor/LineMarkedEditorPane.java index 224dddf54..82b261ce2 100644 --- a/src/com/jpexs/decompiler/flash/gui/editor/LineMarkedEditorPane.java +++ b/src/com/jpexs/decompiler/flash/gui/editor/LineMarkedEditorPane.java @@ -218,6 +218,17 @@ public class LineMarkedEditorPane extends UndoFixedEditorPane implements LinkHan int pos = ActionUtils.getDocumentPosition(this, line, 0); if (pos != -1) { setCaretPosition(pos); + com.jpexs.decompiler.flash.gui.View.execInEventDispatchLater(new Runnable() { + @Override + public void run() { + try { + Rectangle r = modelToView(pos); + scrollRectToVisible(r); + } catch (BadLocationException ex) { + //ignore + } + } + }); } }