diff --git a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java index 0579233e6..265e25caa 100644 --- a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java +++ b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java @@ -32,12 +32,14 @@ import com.jpexs.debugger.flash.messages.in.InNumScript; import com.jpexs.debugger.flash.messages.in.InScript; import com.jpexs.debugger.flash.messages.in.InSetBreakpoint; import com.jpexs.debugger.flash.messages.in.InSwfInfo; +import com.jpexs.debugger.flash.messages.in.InTrace; import com.jpexs.debugger.flash.messages.in.InVersion; import com.jpexs.debugger.flash.messages.out.OutGetBreakReason; import com.jpexs.decompiler.flash.abc.ClassPath; import com.jpexs.decompiler.flash.abc.ScriptPack; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.graph.DottedChain; +import com.jpexs.helpers.CancellableWorker; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -67,10 +69,21 @@ public class DebuggerHandler implements DebugConnectionListener { private InBreakAtExt breakInfo; private InBreakReason breakReason; - private final List listeners = new ArrayList<>(); + private final List varListeners = new ArrayList<>(); + + private final List traceListeners = new ArrayList<>(); private final List clisteners = new ArrayList<>(); + public void notSuspended() { + frame = null; + breakInfo = null; + breakReason = null; + for (VariableChangedListener l : varListeners) { + l.variablesChanged(); + } + } + public String moduleToString(int file) { if (!modulePaths.containsKey(file)) { return "unknown"; @@ -94,6 +107,12 @@ public class DebuggerHandler implements DebugConnectionListener { } + public static interface TraceListener { + + public void trace(String... val); + + } + public static interface VariableChangedListener { public void variablesChanged(); @@ -101,11 +120,19 @@ public class DebuggerHandler implements DebugConnectionListener { } public void addVariableChangedListener(VariableChangedListener l) { - listeners.add(l); + varListeners.add(l); + } + + public void addTraceListener(TraceListener l) { + traceListeners.add(l); + } + + public void removeTraceListener(TraceListener l) { + traceListeners.remove(l); } public void removeVariableChangedListener(VariableChangedListener l) { - listeners.remove(l); + varListeners.remove(l); } public void addConnectionListener(ConnectionListener l) { @@ -147,7 +174,7 @@ public class DebuggerHandler implements DebugConnectionListener { for (ConnectionListener l : clisteners) { l.disconnected(); } - for (VariableChangedListener l : listeners) { + for (VariableChangedListener l : varListeners) { l.variablesChanged(); } } @@ -265,7 +292,7 @@ public class DebuggerHandler implements DebugConnectionListener { breakReason = con.sendMessage(new OutGetBreakReason(con), InBreakReason.class); frame = commands.getFrame(0); - for (VariableChangedListener l : listeners) { + for (VariableChangedListener l : varListeners) { l.variablesChanged(); } @@ -308,6 +335,24 @@ public class DebuggerHandler implements DebugConnectionListener { commands.sendContinue(); } + new CancellableWorker() { + + @Override + protected Object doInBackground() throws Exception { + try { + while (isConnected()) { + InTrace tr = con.getMessage(InTrace.class); + for (TraceListener l : traceListeners) { + l.trace(tr.text); + } + } + } catch (IOException ex) { + //ignore + } + return null; + } + }.execute(); + } catch (IOException ex) { connected = false; } diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index cd3ebc3e9..c8ecd5f1f 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -164,6 +164,13 @@ public class Main { private static int ip = 0; private static ClassPath ipClass = null; + public static void debuggerNotSuspended() { + getDebugHandler().notSuspended(); + mainFrame.getPanel().clearDebuggerColors(); + ip = 0; + ipClass = null; + } + public static void clearBreakPoints(ScriptPack pack) { if (breakPointMap.containsKey(pack)) { breakPointMap.remove(pack); @@ -1144,6 +1151,18 @@ public class Main { */ flashDebugger = new Debugger(); debugHandler = new DebuggerHandler(); + debugHandler.addConnectionListener(new DebuggerHandler.ConnectionListener() { + + @Override + public void connected() { + } + + @Override + public void disconnected() { + ip = 0; + ipClass = null; + } + }); flashDebugger.addConnectionListener(debugHandler); flashDebugger.start(); } catch (IOException ex) { diff --git a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java index bc0b40f73..b8cc2584a 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java @@ -1339,6 +1339,8 @@ public abstract class MainFrameMenu implements MenuBuilder { } public boolean stepOverActionPerformed(ActionEvent evt) { + Main.debuggerNotSuspended(); + try { DebuggerCommands cmd = Main.getDebugHandler().getCommands(); @@ -1354,6 +1356,8 @@ public abstract class MainFrameMenu implements MenuBuilder { } public boolean stepIntoActionPerformed(ActionEvent evt) { + Main.debuggerNotSuspended(); + try { DebuggerCommands cmd = Main.getDebugHandler().getCommands(); mainFrame.getPanel().clearDebuggerColors(); @@ -1369,6 +1373,8 @@ public abstract class MainFrameMenu implements MenuBuilder { } public boolean stepOutActionPerformed(ActionEvent evt) { + Main.debuggerNotSuspended(); + try { DebuggerCommands cmd = Main.getDebugHandler().getCommands(); mainFrame.getPanel().clearDebuggerColors(); @@ -1383,9 +1389,10 @@ public abstract class MainFrameMenu implements MenuBuilder { } public boolean continueActionPerformed(ActionEvent evt) { + Main.debuggerNotSuspended(); + try { DebuggerCommands cmd = Main.getDebugHandler().getCommands(); - mainFrame.getPanel().clearDebuggerColors(); Main.startWork(AppStrings.translate("work.debugging") + "...", null); cmd.sendContinue(); } catch (IOException ex) { diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java index d2c7a4bfb..ce3f530a9 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java @@ -152,16 +152,7 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener())); - debugLocalsTable = new JTable(new VariablesTableModel(new ArrayList<>())); - //debugArgumentsTable = new JTable(new VariablesTableModel(new ArrayList<>())); - debugScopeTable = new JTable(new VariablesTableModel(new ArrayList<>())); - callStackTable = new JTable(); - stackTable = new JTable(); - - Main.getDebugHandler().addVariableChangedListener(new DebuggerHandler.VariableChangedListener() { - - @Override - public void variablesChanged() { - InFrame f = Main.getDebugHandler().getFrame(); - if (f != null) { - debugRegistersTable.setModel(new VariablesTableModel(f.registers)); - List locals = new ArrayList<>(); - locals.addAll(f.arguments); - locals.addAll(f.variables); - debugLocalsTable.setModel(new VariablesTableModel(locals)); - //debugArgumentsTable.setModel(new VariablesTableModel(f.arguments)); - debugScopeTable.setModel(new VariablesTableModel(f.scopeChain)); - debugPanel.setVisible(true); - } else { - debugPanel.setVisible(false); - return; - } - 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") - }); - 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")})); - } else { - callStackTable.setModel(new DefaultTableModel()); - stackTable.setModel(new DefaultTableModel()); - } - - varTabs.removeAll(); - JPanel pa; - if (debugRegistersTable.getRowCount() > 0) { - pa = new JPanel(new BorderLayout()); - pa.add(new JScrollPane(debugRegistersTable), BorderLayout.CENTER); - varTabs.addTab(AppStrings.translate("variables.header.registers"), pa); - } - if (debugLocalsTable.getRowCount() > 0) { - pa = new JPanel(new BorderLayout()); - pa.add(new JScrollPane(debugLocalsTable), BorderLayout.CENTER); - varTabs.addTab(AppStrings.translate("variables.header.locals"), pa); - } - - if (debugScopeTable.getRowCount() > 0) { - pa = new JPanel(new BorderLayout()); - pa.add(new JScrollPane(debugScopeTable), BorderLayout.CENTER); - varTabs.addTab(AppStrings.translate("variables.header.scopeChain"), pa); - } - - if (callStackTable.getRowCount() > 0) { - pa = new JPanel(new BorderLayout()); - pa.add(new JScrollPane(callStackTable), BorderLayout.CENTER); - varTabs.addTab(AppStrings.translate("callStack.header"), pa); - } - if (stackTable.getRowCount() > 0) { - pa = new JPanel(new BorderLayout()); - pa.add(new JScrollPane(stackTable), BorderLayout.CENTER); - varTabs.addTab(AppStrings.translate("stack.header"), pa); - } - varTabs.setSelectedIndex(0); - - } - }); - - varTabs = new JTabbedPane(); - - debugPanel.add(new HeaderLabel(AppStrings.translate("debugpanel.header")), BorderLayout.NORTH); - debugPanel.add(new JScrollPane(varTabs), BorderLayout.CENTER); + debugPanel = new DebugPanel(); JPersistentSplitPane sp2; diff --git a/src/com/jpexs/decompiler/flash/gui/abc/DebugPanel.java b/src/com/jpexs/decompiler/flash/gui/abc/DebugPanel.java new file mode 100644 index 000000000..d18a8ba53 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/abc/DebugPanel.java @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2015 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.abc; + +import com.jpexs.debugger.flash.Variable; +import com.jpexs.debugger.flash.messages.in.InBreakAtExt; +import com.jpexs.debugger.flash.messages.in.InFrame; +import com.jpexs.decompiler.flash.gui.AppStrings; +import com.jpexs.decompiler.flash.gui.DebuggerHandler; +import com.jpexs.decompiler.flash.gui.DebuggerHandler.VariableChangedListener; +import com.jpexs.decompiler.flash.gui.HeaderLabel; +import com.jpexs.decompiler.flash.gui.Main; +import com.jpexs.decompiler.flash.gui.View; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTabbedPane; +import javax.swing.JTable; +import javax.swing.JTextArea; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.table.DefaultTableModel; + +/** + * + * @author JPEXS + */ +public class DebugPanel extends JPanel { + + private JTable debugRegistersTable; + private JTable debugLocalsTable; + private JTable debugScopeTable; + private JTable callStackTable; + private JTable stackTable; + private JTabbedPane varTabs; + private VariableChangedListener listener; + private JTextArea traceLogTextarea; + private int logLength = 0; + private List tabTypes = new ArrayList<>(); + + public static enum SelectedTab { + + LOG, STACK, SCOPECHAIN, LOCALS, REGISTERS, CALLSTACK + } + + private SelectedTab selectedTab = null; + + public DebugPanel() { + super(new BorderLayout()); + debugRegistersTable = new JTable(new ABCPanel.VariablesTableModel(new ArrayList<>())); + debugLocalsTable = new JTable(new ABCPanel.VariablesTableModel(new ArrayList<>())); + debugScopeTable = new JTable(new ABCPanel.VariablesTableModel(new ArrayList<>())); + callStackTable = new JTable(); + stackTable = new JTable(); + traceLogTextarea = new JTextArea(); + traceLogTextarea.setEditable(false); + traceLogTextarea.setOpaque(false); + traceLogTextarea.setFont(new JLabel().getFont()); + traceLogTextarea.setBackground(Color.white); + + Main.getDebugHandler().addTraceListener(new DebuggerHandler.TraceListener() { + + @Override + public void trace(String... val) { + for (String s : val) { + String add = "trace: " + s + "\r\n"; + boolean wasEmpty = logLength == 0; + logLength += add.length(); + traceLogTextarea.append(add); + try { + traceLogTextarea.setCaretPosition(logLength); + } catch (IllegalArgumentException iex) { + //ignore + } + if (wasEmpty) { + refresh(); + } + } + } + }); + + Main.getDebugHandler().addVariableChangedListener(listener = new DebuggerHandler.VariableChangedListener() { + + @Override + public void variablesChanged() { + refresh(); + } + }); + + varTabs = new JTabbedPane(); + varTabs.addChangeListener(new ChangeListener() { + + @Override + public void stateChanged(ChangeEvent e) { + if (e.getSource() == varTabs) { + synchronized (DebugPanel.this) { + int si = varTabs.getSelectedIndex(); + if (si > -1 && si < tabTypes.size()) { + selectedTab = tabTypes.get(si); + } + } + } + } + }); + + add(new HeaderLabel(AppStrings.translate("debugpanel.header")), BorderLayout.NORTH); + add(varTabs, BorderLayout.CENTER); + } + + public void refresh() { + + View.execInEventDispatch(new Runnable() { + + @Override + public void run() { + synchronized (DebugPanel.this) { + SelectedTab oldSel = selectedTab; + SelectedTab firstVisible = null; + SelectedTab newSel = null; + InFrame f = Main.getDebugHandler().getFrame(); + if (f != null) { + debugRegistersTable.setModel(new ABCPanel.VariablesTableModel(f.registers)); + List locals = new ArrayList<>(); + locals.addAll(f.arguments); + locals.addAll(f.variables); + debugLocalsTable.setModel(new ABCPanel.VariablesTableModel(locals)); + debugScopeTable.setModel(new ABCPanel.VariablesTableModel(f.scopeChain)); + } else { + debugRegistersTable.setModel(new DefaultTableModel()); + debugLocalsTable.setModel(new DefaultTableModel()); + debugScopeTable.setModel(new DefaultTableModel()); + } + 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") + }); + 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")})); + } else { + callStackTable.setModel(new DefaultTableModel()); + stackTable.setModel(new DefaultTableModel()); + } + + varTabs.removeAll(); + tabTypes.clear(); + JPanel pa; + if (debugRegistersTable.getRowCount() > 0) { + tabTypes.add(SelectedTab.REGISTERS); + pa = new JPanel(new BorderLayout()); + pa.add(new JScrollPane(debugRegistersTable), BorderLayout.CENTER); + varTabs.addTab(AppStrings.translate("variables.header.registers"), pa); + } + if (debugLocalsTable.getRowCount() > 0) { + tabTypes.add(SelectedTab.LOCALS); + + pa = new JPanel(new BorderLayout()); + pa.add(new JScrollPane(debugLocalsTable), BorderLayout.CENTER); + varTabs.addTab(AppStrings.translate("variables.header.locals"), pa); + } + + if (debugScopeTable.getRowCount() > 0) { + tabTypes.add(SelectedTab.SCOPECHAIN); + + pa = new JPanel(new BorderLayout()); + pa.add(new JScrollPane(debugScopeTable), BorderLayout.CENTER); + varTabs.addTab(AppStrings.translate("variables.header.scopeChain"), pa); + } + + if (callStackTable.getRowCount() > 0) { + tabTypes.add(SelectedTab.CALLSTACK); + + pa = new JPanel(new BorderLayout()); + pa.add(new JScrollPane(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 JScrollPane(stackTable), BorderLayout.CENTER); + varTabs.addTab(AppStrings.translate("stack.header"), pa); + } + if (logLength > 0) { + tabTypes.add(SelectedTab.LOG); + + pa = new JPanel(new BorderLayout()); + pa.add(new JScrollPane(traceLogTextarea), BorderLayout.CENTER); + JButton clearButton = new JButton(AppStrings.translate("debuglog.button.clear")); + clearButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + traceLogTextarea.setText(""); + logLength = 0; + refresh(); + } + }); + JPanel butPanel = new JPanel(new FlowLayout()); + butPanel.add(clearButton); + pa.add(butPanel, BorderLayout.SOUTH); + varTabs.addTab(AppStrings.translate("debuglog.header"), pa); + } + boolean newVisible = !tabTypes.isEmpty(); + if (newVisible != isVisible()) { + setVisible(newVisible); + } + if (!tabTypes.isEmpty()) { + if (oldSel != null && tabTypes.contains(oldSel)) { + selectedTab = oldSel; + } else { + selectedTab = tabTypes.get(0); + } + varTabs.setSelectedIndex(tabTypes.indexOf(selectedTab)); + } else { + selectedTab = null; + } + } + } + }); + + } + + public void dispose() { + Main.getDebugHandler().removeVariableChangedListener(listener); + } + +} diff --git a/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java b/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java index f5c0d1a25..286711dd1 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java @@ -739,9 +739,15 @@ public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretL } public void refreshMarkers() { - Set bkptLines = Main.getPackBreakPoints(script); removeColorMarkerOnAllLines(FG_BREAKPOINT_COLOR, BG_BREAKPOINT_COLOR, PRIORITY_BREAKPOINT); removeColorMarkerOnAllLines(FG_INVALID_BREAKPOINT_COLOR, BG_INVALID_BREAKPOINT_COLOR, PRIORITY_INVALID_BREAKPOINT); + removeColorMarkerOnAllLines(FG_IP_COLOR, BG_IP_COLOR, PRIORITY_IP); + + if (script == null) { + return; + } + + Set bkptLines = Main.getPackBreakPoints(script); for (int line : bkptLines) { if (Main.isBreakPointValid(script, line)) { @@ -750,7 +756,6 @@ public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretL addColorMarker(line, FG_INVALID_BREAKPOINT_COLOR, BG_INVALID_BREAKPOINT_COLOR, PRIORITY_INVALID_BREAKPOINT); } } - removeColorMarkerOnAllLines(FG_IP_COLOR, BG_IP_COLOR, PRIORITY_IP); int ip = Main.getIp(script); ClassPath ipPath = Main.getIpClass(); if (ip > 0 && ipPath != null && ipPath.equals(script.getClassPath())) { diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index 5a06d6d90..7f7ca7d2a 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -675,4 +675,7 @@ work.running = Running work.debugging = Debugging work.debugging.instrumenting = Preparing SWF for debugging work.breakat = Breat at\u0020 -work.halted = Run halted. Press Continue (F5) to run again \ No newline at end of file +work.halted = Run halted. Press Continue (F5) to run again + +debuglog.header = Log +debuglog.button.clear = Clear \ No newline at end of file