From f198f8606786ae8301cffedbf36169c29ff54986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sun, 15 Feb 2026 17:41:08 +0100 Subject: [PATCH] Switching sessions via combo box. --- .../decompiler/flash/gui/DebugStackPanel.java | 128 +++++++++++++++--- .../decompiler/flash/gui/DebuggerHandler.java | 21 +++ .../decompiler/flash/gui/DebuggerSession.java | 15 +- src/com/jpexs/decompiler/flash/gui/Main.java | 2 +- .../jpexs/decompiler/flash/gui/MainPanel.java | 20 +-- .../decompiler/flash/gui/abc/ABCPanel.java | 16 ++- .../flash/gui/action/ActionPanel.java | 2 + .../flash/gui/locales/MainFrame.properties | 1 + .../flash/gui/locales/MainFrame_cs.properties | 1 + 9 files changed, 172 insertions(+), 34 deletions(-) diff --git a/src/com/jpexs/decompiler/flash/gui/DebugStackPanel.java b/src/com/jpexs/decompiler/flash/gui/DebugStackPanel.java index a9e3aaa59..d1ea7833f 100644 --- a/src/com/jpexs/decompiler/flash/gui/DebugStackPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/DebugStackPanel.java @@ -18,12 +18,22 @@ package com.jpexs.decompiler.flash.gui; import com.jpexs.debugger.flash.messages.in.InBreakAtExt; import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.treeitems.TreeItem; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTable; @@ -37,6 +47,8 @@ import javax.swing.table.TableCellRenderer; */ public class DebugStackPanel extends JPanel { + private JComboBox sessionComboBox = new JComboBox<>(); + private JTable stackTable; private boolean active = false; @@ -89,6 +101,7 @@ public class DebugStackPanel extends JPanel { setLayout(new BorderLayout()); //add(titleLabel, BorderLayout.NORTH); add(new FasterScrollPane(stackTable), BorderLayout.CENTER); + add(sessionComboBox, BorderLayout.NORTH); stackTable.addMouseListener(new MouseAdapter() { @Override @@ -96,23 +109,77 @@ public class DebugStackPanel extends JPanel { if (e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton(e)) { int row = stackTable.rowAtPoint(e.getPoint()); if (row >= 0) { - String swfHash = swfHashes[row]; - String scriptName = (String) stackTable.getModel().getValueAt(row, 1); - int line = (int) (Integer) stackTable.getModel().getValueAt(row, 2); - SWF swf = swfHash == null ? Main.getRunningSWF() : Main.findOpenedSwfByHash(swfHash); - Main.getMainFrame().getPanel().gotoScriptLine(swf, - scriptName, line, classIndices[row], traitIndices[row], methodIndices[row], Main.isDebugPCode()); - DebuggerSession session = null; - if (currentSessionRef != null) { - session = currentSessionRef.get(); - } - if (session != null) { - session.setDepth(row); - } + gotoRow(row); } } } }); + + sessionComboBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + SessionItem selection = (SessionItem) sessionComboBox.getSelectedItem(); + if (selection != null) { + DebuggerSession session = Main.getDebugHandler().getSessionById(selection.id); + if (session != null && session != Main.getCurrentDebugSession()) { + View.execInEventDispatch(new Runnable() { + @Override + public void run() { + refresh(session); + } + }); + View.execInEventDispatchLater(new Runnable() { + @Override + public void run() { + gotoRow(0); + } + }); + } + } + } + }); + } + + private void gotoRow(int row) { + String swfHash = swfHashes[row]; + String scriptName = (String) stackTable.getModel().getValueAt(row, 1); + int line = (int) (Integer) stackTable.getModel().getValueAt(row, 2); + SWF swf = swfHash == null ? Main.getRunningSWF() : Main.findOpenedSwfByHash(swfHash); + boolean scriptFound = Main.getMainFrame().getPanel().gotoScriptLine(swf, + scriptName, line, classIndices[row], traitIndices[row], methodIndices[row], Main.isDebugPCode()); + + if (!scriptFound) { + if (Main.getMainFrame().getPanel().getCurrentView() == MainPanel.VIEW_RESOURCES) { + TreeItem scriptNode = Main.getMainFrame().getPanel().tagTree.getFullModel().getScriptsNode(swf); + if (scriptNode != null) { + scriptFound = true; + Main.getMainFrame().getPanel().setTagTreeSelectedNode(Main.getMainFrame().getPanel().getCurrentTree(), scriptNode); + } + } + if (!scriptFound) { + Main.getMainFrame().getPanel().setTagTreeSelectedNode(Main.getMainFrame().getPanel().getCurrentTree(), swf); + } + } + DebuggerSession session = null; + if (currentSessionRef != null) { + session = currentSessionRef.get(); + } + if (session != null) { + session.setDepth(row); + } + } + + private class SessionItem { + private int id; + + public SessionItem(int id) { + this.id = id; + } + + @Override + public String toString() { + return AppStrings.translate("debug.session").replace("%id%", "" + id); + } } public void clear() { @@ -123,8 +190,34 @@ public class DebugStackPanel extends JPanel { public boolean isActive() { return active; } + public void refresh(DebuggerSession session) { + + Map allSessions = Main.getDebugHandler().getActiveSessions(); + DefaultComboBoxModel model = new DefaultComboBoxModel<>(); + int itemIndex = -1; + int j = 0; + for (int id : allSessions.keySet()) { + DebuggerSession s = allSessions.get(id); + if (s == session) { + itemIndex = j; + } + model.addElement(new SessionItem(id)); + j++; + } + sessionComboBox.setModel(model); + if (itemIndex > -1) { + final int fItemIndex = itemIndex; + View.execInEventDispatchLater(new Runnable() { + @Override + public void run() { + sessionComboBox.setSelectedIndex(fItemIndex); + } + }); + } + + if (session == null) { clear(); return; @@ -147,7 +240,11 @@ public class DebugStackPanel extends JPanel { if (moduleName.contains(":")) { swfHash = moduleName.substring(0, moduleName.indexOf(":")); moduleName = moduleName.substring(moduleName.indexOf(":") + 1); - } + } else { + List debuggedSwfs = new ArrayList<>(session.getDebuggedSwfs().values()); + SWF lastSwf = debuggedSwfs.get(debuggedSwfs.size() - 1); + swfHash = Main.getSwfHash(lastSwf); + } newSwfHashes[i] = swfHash; data[i][0] = swfHash == null ? "unknown" : Main.findOpenedSwfByHash(swfHash).toString(); data[i][1] = moduleName; @@ -157,8 +254,7 @@ public class DebugStackPanel extends JPanel { newClassIndices[i] = newClassIndex == null ? -1 : newClassIndex; Integer newMethodIndex = session.moduleToMethodIndex(f); newMethodIndices[i] = newMethodIndex == null ? -1 : newMethodIndex; - Integer newTraitIndex = session.moduleToTraitIndex(f); - ; + Integer newTraitIndex = session.moduleToTraitIndex(f); newTraitIndices[i] = newTraitIndex == null ? -1 : newTraitIndex; } diff --git a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java index 536f9be88..c7a1d1830 100644 --- a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java +++ b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java @@ -316,4 +316,25 @@ public class DebuggerHandler implements DebugConnectionListener { } return null; } + + public Map getActiveSessions() { + Map ret = new LinkedHashMap<>(); + List currentSessions = new ArrayList<>(sessions); + for (DebuggerSession session : currentSessions) { + if (session.isConnected()) { + ret.put(session.getId(), session); + } + } + return ret; + } + + public DebuggerSession getSessionById(int id) { + List currentSessions = new ArrayList<>(sessions); + for (DebuggerSession session : currentSessions) { + if (session.isConnected() && session.getId() == id) { + return session; + } + } + return null; + } } diff --git a/src/com/jpexs/decompiler/flash/gui/DebuggerSession.java b/src/com/jpexs/decompiler/flash/gui/DebuggerSession.java index cdbea6e06..f8c6795c3 100644 --- a/src/com/jpexs/decompiler/flash/gui/DebuggerSession.java +++ b/src/com/jpexs/decompiler/flash/gui/DebuggerSession.java @@ -153,7 +153,14 @@ public class DebuggerSession { paused = false; } - Main.getMainFrame().getPanel().updateMenu(); + View.execInEventDispatchLater(new Runnable() { + @Override + public void run() { + Main.getMainFrame().getPanel().updateMenu(); + } + }); + + //enlog(DebuggerConnection.class); //enlog(DebuggerCommands.class); @@ -635,6 +642,12 @@ public class DebuggerSession { } } + public int getId() { + return id; + } + + + public boolean containsSwf(SWF swf) { return debuggedSwfs.containsValue(swf); } diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index 660d5ca05..6e9fcf33b 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -3161,7 +3161,7 @@ public class Main { if (Main.getDebugHandler().getNumberOfPausedSessions() > 1 && Main.getCurrentDebugSession() != session) { - Logger.getLogger(Main.class.getName()).log(Level.INFO, "Another SWF ({0}) has reached breakpoint meanwhile", swf.toString()); + Logger.getLogger(Main.class.getName()).log(Level.INFO, "Another SWF ({0}) has reached breakpoint meanwhile", swf == null ? "unknown" : swf.toString()); mainFrame.getPanel().refreshBreakPoints(); return; } diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 09cbd9fb1..44f91f29c 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -2718,7 +2718,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } } - public void gotoScriptMethod(SWF swf, String scriptName, int methodIndex) { + public boolean gotoScriptMethod(SWF swf, String scriptName, int methodIndex) { abcPanel.decompiledTextArea.addScriptListener(new Runnable() { @Override public void run() { @@ -2728,10 +2728,10 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } } }); - gotoScriptName(swf, scriptName); + return gotoScriptName(swf, scriptName); } - public void gotoScriptTrait(SWF swf, String scriptName, int classIndex, int traitIndex) { + public boolean gotoScriptTrait(SWF swf, String scriptName, int classIndex, int traitIndex) { abcPanel.decompiledTextArea.addScriptListener(new Runnable() { @Override public void run() { @@ -2746,7 +2746,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } } }); - gotoScriptName(swf, scriptName); + return gotoScriptName(swf, scriptName); } public void findOrLoadOpenableListByFilePath(String filePath, OpenableListLoaded executeAfterOpen, boolean loadSession) { @@ -2768,7 +2768,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se }, loadSession); } - public void gotoScriptLine(SWF swf, String scriptName, int line, int classIndex, int traitIndex, int methodIndex, boolean pcode) { + public boolean gotoScriptLine(SWF swf, String scriptName, int line, int classIndex, int traitIndex, int methodIndex, boolean pcode) { View.checkAccess(); if (abcPanel != null && swf.isAS3()) { @@ -2822,7 +2822,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } }); } - gotoScriptName(swf, scriptName); + return gotoScriptName(swf, scriptName); } public void refreshBreakPoints() { @@ -2850,11 +2850,11 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se }); }*/ - public void gotoScriptName(SWF mainSwf, String scriptNameWithSwfHash) { + public boolean gotoScriptName(SWF mainSwf, String scriptNameWithSwfHash) { View.checkAccess(); if (mainSwf == null) { - return; + return false; } if (mainSwf.isAS3()) { String rawScriptName = scriptNameWithSwfHash; @@ -2867,7 +2867,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se //if (!abcList.isEmpty()) { ABCPanel abcPanel = getABCPanel(); - abcPanel.hilightScript(mainSwf, rawScriptName); + return abcPanel.hilightScript(mainSwf, rawScriptName); //} } else { String rawScriptName = scriptNameWithSwfHash; @@ -2879,11 +2879,13 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se oldItem = null; getCurrentTree().setSelectionPath(null); setTagTreeSelectedNode(getCurrentTree(), asms.get(rawScriptName)); + return true; } /*if (actionPanel != null && asms.containsKey(rawScriptName)) { actionPanel.setSource(asms.get(rawScriptName), true); }*/ } + return false; } public void gotoDocumentClass(SWF swf) { diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java index db4849d04..edc4b934d 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java @@ -1767,7 +1767,7 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener