Connect to another device without disconnecting first

Connect and Discover stay enabled while a device is connected. Pressing
Connect in the dialog drops the current device before the new one is
tried; cancelling the dialog leaves the connection alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 23:49:25 +03:00
co-authored by Claude Opus 5.5
parent dbeeb78916
commit 9b1d029b14
3 changed files with 32 additions and 9 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ so later rebinding would only ever be seen by the module that did it.
import configparser import configparser
import os import os
VERSION = "0.0.0.140" VERSION = "0.0.0.141"
PROPERTIES_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "editor.properties") PROPERTIES_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "editor.properties")
DEFAULT_GRID_SIZE = 10 DEFAULT_GRID_SIZE = 10
DEFAULT_ADD_TIMESTAMP = True DEFAULT_ADD_TIMESTAMP = True
+17 -4
View File
@@ -21,8 +21,9 @@ import app_state
class ConnectDialog: class ConnectDialog:
"""Modal dialog for entering device connection parameters.""" """Modal dialog for entering device connection parameters."""
def __init__(self, parent, on_connect_callback): def __init__(self, parent, on_connect_callback, on_before_connect=None):
self._callback = on_connect_callback self._callback = on_connect_callback
self._before_connect = on_before_connect
self._thread = None self._thread = None
self._cancelled = False self._cancelled = False
@@ -103,6 +104,11 @@ class ConnectDialog:
self._status_label.config(text="Invalid port number", foreground="#c00000") self._status_label.config(text="Invalid port number", foreground="#c00000")
return return
# Runs here, on the main thread, rather than in the worker: it is where a
# device already connected is let go, and that takes the UI down with it.
if self._before_connect is not None:
self._before_connect()
self._btn_connect.config(state="disabled") self._btn_connect.config(state="disabled")
self._status_label.config(text="Connecting...", foreground="#666666") self._status_label.config(text="Connecting...", foreground="#666666")
@@ -169,9 +175,10 @@ class DiscoverDialog:
"""Modal dialog that broadcasts DASP DISCOVER, lists responding """Modal dialog that broadcasts DASP DISCOVER, lists responding
devices, and lets the user pick one to connect to.""" devices, and lets the user pick one to connect to."""
def __init__(self, parent, on_connect_callback): def __init__(self, parent, on_connect_callback, on_before_connect=None):
self._parent = parent self._parent = parent
self._callback = on_connect_callback self._callback = on_connect_callback
self._before_connect = on_before_connect
self._discover_thread = None self._discover_thread = None
self._dlg = tk.Toplevel(parent) self._dlg = tk.Toplevel(parent)
@@ -318,7 +325,7 @@ class DiscoverDialog:
host = values[0] host = values[0]
port = self._port_var.get().strip() port = self._port_var.get().strip()
self._dlg.destroy() self._dlg.destroy()
_CredentialsDialog(self._parent, self._callback, host, port) _CredentialsDialog(self._parent, self._callback, host, port, self._before_connect)
# ──────────────────────────────────────────────────────────────────── # ────────────────────────────────────────────────────────────────────
@@ -328,8 +335,9 @@ class DiscoverDialog:
class _CredentialsDialog: class _CredentialsDialog:
"""Small modal that asks for username and password, then connects.""" """Small modal that asks for username and password, then connects."""
def __init__(self, parent, on_connect_callback, host, port): def __init__(self, parent, on_connect_callback, host, port, on_before_connect=None):
self._callback = on_connect_callback self._callback = on_connect_callback
self._before_connect = on_before_connect
self._host = host self._host = host
self._port = port self._port = port
self._thread = None self._thread = None
@@ -397,6 +405,11 @@ class _CredentialsDialog:
self._status_label.config(text="Invalid port", foreground="#c00000") self._status_label.config(text="Invalid port", foreground="#c00000")
return return
# Runs here, on the main thread, rather than in the worker: it is where a
# device already connected is let go, and that takes the UI down with it.
if self._before_connect is not None:
self._before_connect()
self._btn_connect.config(state="disabled") self._btn_connect.config(state="disabled")
self._status_label.config(text="Connecting...", foreground="#666666") self._status_label.config(text="Connecting...", foreground="#666666")
+14 -4
View File
@@ -2316,7 +2316,8 @@ def do_device_connect():
wiresheet.render_components([]) wiresheet.render_components([])
app_state.window.title(app_state.base_window_title()) app_state.window.title(app_state.base_window_title())
connect_dialog.ConnectDialog(app_state.window, _connect_to_device) connect_dialog.ConnectDialog(app_state.window, _connect_to_device,
on_before_connect=_drop_device_before_connect)
def do_device_discover(): def do_device_discover():
@@ -2337,7 +2338,18 @@ def do_device_discover():
wiresheet.render_components([]) wiresheet.render_components([])
app_state.window.title(app_state.base_window_title()) app_state.window.title(app_state.base_window_title())
connect_dialog.DiscoverDialog(app_state.window, _connect_to_device) connect_dialog.DiscoverDialog(app_state.window, _connect_to_device,
on_before_connect=_drop_device_before_connect)
def _drop_device_before_connect():
"""One device at a time: the one already connected goes before the next is tried.
Called when Connect is pressed, not when the dialog opens, so backing out of the
dialog leaves the current connection alone.
"""
if app_state.device_session is not None:
do_device_disconnect()
def _connect_to_device(host, port, user, password): def _connect_to_device(host, port, user, password):
@@ -2358,8 +2370,6 @@ def _connect_to_device(host, port, user, password):
def _on_connected(ds, root_comp): def _on_connected(ds, root_comp):
"""Main-thread callback after successful connect.""" """Main-thread callback after successful connect."""
app_state.window.title(app_state.base_window_title_live()) app_state.window.title(app_state.base_window_title_live())
menu_device.entryconfig("Connect...", state="disabled")
menu_device.entryconfig("Discover...", state="disabled")
menu_device.entryconfig("Disconnect", state="normal") menu_device.entryconfig("Disconnect", state="normal")
menu_device.entryconfig("Download to SAX...", state="normal") menu_device.entryconfig("Download to SAX...", state="normal")
app_state.set_status(f"Connected to {app_state.device_host}:{app_state.device_port}") app_state.set_status(f"Connected to {app_state.device_host}:{app_state.device_port}")