Add Device > Discover menu with standalone discovery dialog
Discover dialog shows a device list with Port, Wait Time fields and a Discover button. Selecting a device and clicking Connect (or double- clicking) opens a credentials prompt for username/password, then connects. The Connect dialog is reverted to its original simple form. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -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.097"
|
VERSION = "0.0.0.098"
|
||||||
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
|
||||||
|
|||||||
+246
-66
@@ -1,10 +1,9 @@
|
|||||||
"""
|
"""
|
||||||
Connection dialog for connecting to a live Sedona device.
|
Connection and discovery dialogs for live Sedona devices.
|
||||||
|
|
||||||
Modal Toplevel with host, port, username, password fields and device
|
ConnectDialog — manual host/port/user/password entry (Device > Connect).
|
||||||
discovery. Connect runs in a background thread; progress and errors
|
DiscoverDialog — DASP broadcast discovery with device list; selecting a
|
||||||
shown inline. The Discover button sends a DASP broadcast and lists
|
device opens a credentials prompt, then connects (Device > Discover).
|
||||||
responding devices so the user can pick one.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import configparser
|
import configparser
|
||||||
@@ -15,6 +14,10 @@ from tkinter import ttk
|
|||||||
import app_state
|
import app_state
|
||||||
|
|
||||||
|
|
||||||
|
# ────────────────────────────────────────────────────────────────────
|
||||||
|
# ConnectDialog (Device > Connect…)
|
||||||
|
# ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
class ConnectDialog:
|
class ConnectDialog:
|
||||||
"""Modal dialog for entering device connection parameters."""
|
"""Modal dialog for entering device connection parameters."""
|
||||||
|
|
||||||
@@ -22,7 +25,6 @@ class ConnectDialog:
|
|||||||
self._callback = on_connect_callback
|
self._callback = on_connect_callback
|
||||||
self._thread = None
|
self._thread = None
|
||||||
self._cancelled = False
|
self._cancelled = False
|
||||||
self._discover_thread = None
|
|
||||||
|
|
||||||
self._dlg = tk.Toplevel(parent)
|
self._dlg = tk.Toplevel(parent)
|
||||||
self._dlg.title("Connect to Device")
|
self._dlg.title("Connect to Device")
|
||||||
@@ -59,49 +61,6 @@ class ConnectDialog:
|
|||||||
ttk.Entry(frame, textvariable=self._pass_var, width=28, show="*").grid(
|
ttk.Entry(frame, textvariable=self._pass_var, width=28, show="*").grid(
|
||||||
row=row, column=1, columnspan=2, sticky="ew", pady=4)
|
row=row, column=1, columnspan=2, sticky="ew", pady=4)
|
||||||
|
|
||||||
# ── Discovery section ──────────────────────────────────────
|
|
||||||
row += 1
|
|
||||||
sep = ttk.Separator(frame, orient="horizontal")
|
|
||||||
sep.grid(row=row, column=0, columnspan=3, sticky="ew", pady=(12, 4))
|
|
||||||
|
|
||||||
row += 1
|
|
||||||
disc_header = ttk.Frame(frame)
|
|
||||||
disc_header.grid(row=row, column=0, columnspan=3, sticky="ew", pady=(0, 4))
|
|
||||||
|
|
||||||
ttk.Label(disc_header, text="Discovered Devices:").pack(side=tk.LEFT)
|
|
||||||
|
|
||||||
self._btn_discover = ttk.Button(
|
|
||||||
disc_header, text="Discover", command=self._do_discover, width=10)
|
|
||||||
self._btn_discover.pack(side=tk.RIGHT)
|
|
||||||
|
|
||||||
self._wait_var = tk.StringVar(value="10")
|
|
||||||
wait_entry = ttk.Entry(disc_header, textvariable=self._wait_var, width=4,
|
|
||||||
justify="center")
|
|
||||||
wait_entry.pack(side=tk.RIGHT, padx=(0, 4))
|
|
||||||
ttk.Label(disc_header, text="Wait (s):").pack(side=tk.RIGHT, padx=(8, 2))
|
|
||||||
|
|
||||||
row += 1
|
|
||||||
list_frame = ttk.Frame(frame)
|
|
||||||
list_frame.grid(row=row, column=0, columnspan=3, sticky="nsew", pady=(0, 4))
|
|
||||||
frame.rowconfigure(row, weight=1)
|
|
||||||
|
|
||||||
columns = ("ip", "platform")
|
|
||||||
self._dev_tree = ttk.Treeview(
|
|
||||||
list_frame, columns=columns, show="headings", height=5, selectmode="browse")
|
|
||||||
self._dev_tree.heading("ip", text="IP Address")
|
|
||||||
self._dev_tree.heading("platform", text="Platform ID")
|
|
||||||
self._dev_tree.column("ip", width=140, minwidth=100)
|
|
||||||
self._dev_tree.column("platform", width=180, minwidth=100)
|
|
||||||
self._dev_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
|
||||||
|
|
||||||
scrollbar = ttk.Scrollbar(list_frame, orient="vertical", command=self._dev_tree.yview)
|
|
||||||
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
|
||||||
self._dev_tree.configure(yscrollcommand=scrollbar.set)
|
|
||||||
|
|
||||||
self._dev_tree.bind("<<TreeviewSelect>>", self._on_device_selected)
|
|
||||||
self._dev_tree.bind("<Double-1>", lambda e: self._do_connect())
|
|
||||||
|
|
||||||
# ── Status and buttons ─────────────────────────────────────
|
|
||||||
row += 1
|
row += 1
|
||||||
self._status_label = ttk.Label(frame, text="", foreground="#666666")
|
self._status_label = ttk.Label(frame, text="", foreground="#666666")
|
||||||
self._status_label.grid(row=row, column=0, columnspan=3, sticky="w", pady=(8, 4))
|
self._status_label.grid(row=row, column=0, columnspan=3, sticky="w", pady=(8, 4))
|
||||||
@@ -125,6 +84,166 @@ class ConnectDialog:
|
|||||||
y = parent.winfo_y() + (parent.winfo_height() - self._dlg.winfo_height()) // 2
|
y = parent.winfo_y() + (parent.winfo_height() - self._dlg.winfo_height()) // 2
|
||||||
self._dlg.geometry(f"+{x}+{y}")
|
self._dlg.geometry(f"+{x}+{y}")
|
||||||
|
|
||||||
|
def _do_connect(self):
|
||||||
|
host = self._host_var.get().strip()
|
||||||
|
port = self._port_var.get().strip()
|
||||||
|
user = self._user_var.get().strip()
|
||||||
|
password = self._pass_var.get()
|
||||||
|
|
||||||
|
if not host:
|
||||||
|
self._status_label.config(text="Host is required", foreground="#c00000")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
port_int = int(port)
|
||||||
|
except ValueError:
|
||||||
|
self._status_label.config(text="Invalid port number", foreground="#c00000")
|
||||||
|
return
|
||||||
|
|
||||||
|
self._btn_connect.config(state="disabled")
|
||||||
|
self._status_label.config(text="Connecting...", foreground="#666666")
|
||||||
|
|
||||||
|
self._cancelled = False
|
||||||
|
self._thread = threading.Thread(
|
||||||
|
target=self._connect_worker,
|
||||||
|
args=(host, port_int, user, password),
|
||||||
|
daemon=True
|
||||||
|
)
|
||||||
|
self._thread.start()
|
||||||
|
self._poll_connect()
|
||||||
|
|
||||||
|
def _connect_worker(self, host, port, user, password):
|
||||||
|
try:
|
||||||
|
result = self._callback(host, port, user, password)
|
||||||
|
if self._cancelled:
|
||||||
|
return
|
||||||
|
self._result = ("ok", result, host, port, user)
|
||||||
|
except Exception as e:
|
||||||
|
if self._cancelled:
|
||||||
|
return
|
||||||
|
self._result = ("error", str(e), host, port, user)
|
||||||
|
|
||||||
|
def _poll_connect(self):
|
||||||
|
if self._cancelled:
|
||||||
|
return
|
||||||
|
if self._thread is not None and self._thread.is_alive():
|
||||||
|
self._dlg.after(100, self._poll_connect)
|
||||||
|
return
|
||||||
|
|
||||||
|
status, *rest = self._result
|
||||||
|
if status == "ok":
|
||||||
|
_, host, port, user = rest
|
||||||
|
_save_last_connection(host, str(port), user)
|
||||||
|
self._dlg.destroy()
|
||||||
|
else:
|
||||||
|
msg = rest[0]
|
||||||
|
self._status_label.config(text=f"Error: {msg}", foreground="#c00000")
|
||||||
|
self._btn_connect.config(state="normal")
|
||||||
|
|
||||||
|
def _do_cancel(self):
|
||||||
|
self._cancelled = True
|
||||||
|
if self._thread is not None and self._thread.is_alive():
|
||||||
|
import app_state as _as
|
||||||
|
def _cleanup():
|
||||||
|
self._thread.join(timeout=5)
|
||||||
|
if _as.device_session is not None and _as.live_mode:
|
||||||
|
try:
|
||||||
|
_as.device_session.disconnect()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
_as.live_mode = False
|
||||||
|
_as.device_session = None
|
||||||
|
_as.connection_status = "offline"
|
||||||
|
threading.Thread(target=_cleanup, daemon=True).start()
|
||||||
|
self._dlg.destroy()
|
||||||
|
|
||||||
|
|
||||||
|
# ────────────────────────────────────────────────────────────────────
|
||||||
|
# DiscoverDialog (Device > Discover…)
|
||||||
|
# ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
class DiscoverDialog:
|
||||||
|
"""Modal dialog that broadcasts DASP DISCOVER, lists responding
|
||||||
|
devices, and lets the user pick one to connect to."""
|
||||||
|
|
||||||
|
def __init__(self, parent, on_connect_callback):
|
||||||
|
self._parent = parent
|
||||||
|
self._callback = on_connect_callback
|
||||||
|
self._discover_thread = None
|
||||||
|
|
||||||
|
self._dlg = tk.Toplevel(parent)
|
||||||
|
self._dlg.title("Discover Devices")
|
||||||
|
self._dlg.resizable(False, False)
|
||||||
|
self._dlg.transient(parent)
|
||||||
|
self._dlg.grab_set()
|
||||||
|
|
||||||
|
frame = ttk.Frame(self._dlg, padding=16)
|
||||||
|
frame.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
# ── Header row: label + wait + discover button ─────────────
|
||||||
|
row = 0
|
||||||
|
hdr = ttk.Frame(frame)
|
||||||
|
hdr.grid(row=row, column=0, sticky="ew", pady=(0, 8))
|
||||||
|
|
||||||
|
ttk.Label(hdr, text="Discovered Devices:").pack(side=tk.LEFT)
|
||||||
|
|
||||||
|
self._btn_discover = ttk.Button(
|
||||||
|
hdr, text="Discover", command=self._do_discover, width=10)
|
||||||
|
self._btn_discover.pack(side=tk.RIGHT)
|
||||||
|
|
||||||
|
self._wait_var = tk.StringVar(value="10")
|
||||||
|
ttk.Entry(hdr, textvariable=self._wait_var, width=4, justify="center").pack(
|
||||||
|
side=tk.RIGHT, padx=(0, 4))
|
||||||
|
ttk.Label(hdr, text="Wait (s):").pack(side=tk.RIGHT, padx=(8, 2))
|
||||||
|
|
||||||
|
_, port, _ = _load_last_connection()
|
||||||
|
self._port_var = tk.StringVar(value=port)
|
||||||
|
ttk.Entry(hdr, textvariable=self._port_var, width=6, justify="center").pack(
|
||||||
|
side=tk.RIGHT, padx=(0, 4))
|
||||||
|
ttk.Label(hdr, text="Port:").pack(side=tk.RIGHT, padx=(8, 2))
|
||||||
|
|
||||||
|
# ── Device list ────────────────────────────────────────────
|
||||||
|
row += 1
|
||||||
|
list_frame = ttk.Frame(frame)
|
||||||
|
list_frame.grid(row=row, column=0, sticky="nsew", pady=(0, 4))
|
||||||
|
frame.rowconfigure(row, weight=1)
|
||||||
|
|
||||||
|
columns = ("ip", "platform")
|
||||||
|
self._dev_tree = ttk.Treeview(
|
||||||
|
list_frame, columns=columns, show="headings", height=6, selectmode="browse")
|
||||||
|
self._dev_tree.heading("ip", text="IP Address")
|
||||||
|
self._dev_tree.heading("platform", text="Platform ID")
|
||||||
|
self._dev_tree.column("ip", width=150, minwidth=100)
|
||||||
|
self._dev_tree.column("platform", width=220, minwidth=120)
|
||||||
|
self._dev_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
scrollbar = ttk.Scrollbar(list_frame, orient="vertical", command=self._dev_tree.yview)
|
||||||
|
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
||||||
|
self._dev_tree.configure(yscrollcommand=scrollbar.set)
|
||||||
|
|
||||||
|
self._dev_tree.bind("<Double-1>", lambda e: self._do_connect_selected())
|
||||||
|
|
||||||
|
# ── Status + buttons ───────────────────────────────────────
|
||||||
|
row += 1
|
||||||
|
self._status_label = ttk.Label(frame, text="", foreground="#666666")
|
||||||
|
self._status_label.grid(row=row, column=0, sticky="w", pady=(8, 4))
|
||||||
|
|
||||||
|
row += 1
|
||||||
|
btn_frame = ttk.Frame(frame)
|
||||||
|
btn_frame.grid(row=row, column=0, sticky="e", pady=(8, 0))
|
||||||
|
|
||||||
|
ttk.Button(btn_frame, text="Cancel", command=self._dlg.destroy).pack(side=tk.RIGHT)
|
||||||
|
self._btn_connect = ttk.Button(
|
||||||
|
btn_frame, text="Connect", command=self._do_connect_selected)
|
||||||
|
self._btn_connect.pack(side=tk.RIGHT, padx=(0, 8))
|
||||||
|
|
||||||
|
self._dlg.bind("<Escape>", lambda e: self._dlg.destroy())
|
||||||
|
|
||||||
|
self._dlg.update_idletasks()
|
||||||
|
x = parent.winfo_x() + (parent.winfo_width() - self._dlg.winfo_width()) // 2
|
||||||
|
y = parent.winfo_y() + (parent.winfo_height() - self._dlg.winfo_height()) // 2
|
||||||
|
self._dlg.geometry(f"+{x}+{y}")
|
||||||
|
|
||||||
# ── Discovery ──────────────────────────────────────────────────
|
# ── Discovery ──────────────────────────────────────────────────
|
||||||
|
|
||||||
def _do_discover(self):
|
def _do_discover(self):
|
||||||
@@ -180,46 +299,104 @@ class ConnectDialog:
|
|||||||
self._status_label.config(
|
self._status_label.config(
|
||||||
text=f"Found {len(data)} device(s)", foreground="#006600")
|
text=f"Found {len(data)} device(s)", foreground="#006600")
|
||||||
else:
|
else:
|
||||||
self._status_label.config(
|
self._status_label.config(text="No devices found", foreground="#666666")
|
||||||
text="No devices found", foreground="#666666")
|
|
||||||
else:
|
else:
|
||||||
self._status_label.config(
|
self._status_label.config(
|
||||||
text=f"Discovery error: {data}", foreground="#c00000")
|
text=f"Discovery error: {data}", foreground="#c00000")
|
||||||
|
|
||||||
def _on_device_selected(self, event):
|
# ── Connect selected device ────────────────────────────────────
|
||||||
|
|
||||||
|
def _do_connect_selected(self):
|
||||||
sel = self._dev_tree.selection()
|
sel = self._dev_tree.selection()
|
||||||
if not sel:
|
if not sel:
|
||||||
|
self._status_label.config(text="Select a device first", foreground="#c00000")
|
||||||
return
|
return
|
||||||
values = self._dev_tree.item(sel[0], "values")
|
values = self._dev_tree.item(sel[0], "values")
|
||||||
if values:
|
host = values[0]
|
||||||
self._host_var.set(values[0])
|
port = self._port_var.get().strip()
|
||||||
|
self._dlg.destroy()
|
||||||
|
_CredentialsDialog(self._parent, self._callback, host, port)
|
||||||
|
|
||||||
# ── Connect ────────────────────────────────────────────────────
|
|
||||||
|
# ────────────────────────────────────────────────────────────────────
|
||||||
|
# _CredentialsDialog (username / password prompt after discovery)
|
||||||
|
# ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
class _CredentialsDialog:
|
||||||
|
"""Small modal that asks for username and password, then connects."""
|
||||||
|
|
||||||
|
def __init__(self, parent, on_connect_callback, host, port):
|
||||||
|
self._callback = on_connect_callback
|
||||||
|
self._host = host
|
||||||
|
self._port = port
|
||||||
|
self._thread = None
|
||||||
|
self._cancelled = False
|
||||||
|
|
||||||
|
_, _, last_user = _load_last_connection()
|
||||||
|
|
||||||
|
self._dlg = tk.Toplevel(parent)
|
||||||
|
self._dlg.title(f"Connect to {host}")
|
||||||
|
self._dlg.resizable(False, False)
|
||||||
|
self._dlg.transient(parent)
|
||||||
|
self._dlg.grab_set()
|
||||||
|
|
||||||
|
frame = ttk.Frame(self._dlg, padding=16)
|
||||||
|
frame.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
row = 0
|
||||||
|
ttk.Label(frame, text="Host:").grid(row=row, column=0, sticky="e", padx=(0, 8), pady=4)
|
||||||
|
ttk.Label(frame, text=f"{host}:{port}").grid(row=row, column=1, sticky="w", pady=4)
|
||||||
|
|
||||||
|
row += 1
|
||||||
|
ttk.Label(frame, text="Username:").grid(row=row, column=0, sticky="e", padx=(0, 8), pady=4)
|
||||||
|
self._user_var = tk.StringVar(value=last_user)
|
||||||
|
user_entry = ttk.Entry(frame, textvariable=self._user_var, width=24)
|
||||||
|
user_entry.grid(row=row, column=1, sticky="ew", pady=4)
|
||||||
|
|
||||||
|
row += 1
|
||||||
|
ttk.Label(frame, text="Password:").grid(row=row, column=0, sticky="e", padx=(0, 8), pady=4)
|
||||||
|
self._pass_var = tk.StringVar()
|
||||||
|
ttk.Entry(frame, textvariable=self._pass_var, width=24, show="*").grid(
|
||||||
|
row=row, column=1, sticky="ew", pady=4)
|
||||||
|
|
||||||
|
row += 1
|
||||||
|
self._status_label = ttk.Label(frame, text="", foreground="#666666")
|
||||||
|
self._status_label.grid(row=row, column=0, columnspan=2, sticky="w", pady=(8, 4))
|
||||||
|
|
||||||
|
row += 1
|
||||||
|
btn_frame = ttk.Frame(frame)
|
||||||
|
btn_frame.grid(row=row, column=0, columnspan=2, sticky="e", pady=(8, 0))
|
||||||
|
|
||||||
|
ttk.Button(btn_frame, text="Cancel", command=self._do_cancel).pack(side=tk.RIGHT)
|
||||||
|
self._btn_connect = ttk.Button(btn_frame, text="Connect", command=self._do_connect)
|
||||||
|
self._btn_connect.pack(side=tk.RIGHT, padx=(0, 8))
|
||||||
|
|
||||||
|
user_entry.focus_set()
|
||||||
|
self._dlg.bind("<Return>", lambda e: self._do_connect())
|
||||||
|
self._dlg.bind("<Escape>", lambda e: self._do_cancel())
|
||||||
|
|
||||||
|
self._dlg.update_idletasks()
|
||||||
|
x = parent.winfo_x() + (parent.winfo_width() - self._dlg.winfo_width()) // 2
|
||||||
|
y = parent.winfo_y() + (parent.winfo_height() - self._dlg.winfo_height()) // 2
|
||||||
|
self._dlg.geometry(f"+{x}+{y}")
|
||||||
|
|
||||||
def _do_connect(self):
|
def _do_connect(self):
|
||||||
host = self._host_var.get().strip()
|
|
||||||
port = self._port_var.get().strip()
|
|
||||||
user = self._user_var.get().strip()
|
user = self._user_var.get().strip()
|
||||||
password = self._pass_var.get()
|
password = self._pass_var.get()
|
||||||
|
|
||||||
if not host:
|
|
||||||
self._status_label.config(text="Host is required", foreground="#c00000")
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
port_int = int(port)
|
port_int = int(self._port)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self._status_label.config(text="Invalid port number", foreground="#c00000")
|
self._status_label.config(text="Invalid port", foreground="#c00000")
|
||||||
return
|
return
|
||||||
|
|
||||||
self._btn_connect.config(state="disabled")
|
self._btn_connect.config(state="disabled")
|
||||||
self._btn_discover.config(state="disabled")
|
|
||||||
self._status_label.config(text="Connecting...", foreground="#666666")
|
self._status_label.config(text="Connecting...", foreground="#666666")
|
||||||
|
|
||||||
self._cancelled = False
|
self._cancelled = False
|
||||||
self._thread = threading.Thread(
|
self._thread = threading.Thread(
|
||||||
target=self._connect_worker,
|
target=self._connect_worker,
|
||||||
args=(host, port_int, user, password),
|
args=(self._host, port_int, user, password),
|
||||||
daemon=True
|
daemon=True
|
||||||
)
|
)
|
||||||
self._thread.start()
|
self._thread.start()
|
||||||
@@ -252,7 +429,6 @@ class ConnectDialog:
|
|||||||
msg = rest[0]
|
msg = rest[0]
|
||||||
self._status_label.config(text=f"Error: {msg}", foreground="#c00000")
|
self._status_label.config(text=f"Error: {msg}", foreground="#c00000")
|
||||||
self._btn_connect.config(state="normal")
|
self._btn_connect.config(state="normal")
|
||||||
self._btn_discover.config(state="normal")
|
|
||||||
|
|
||||||
def _do_cancel(self):
|
def _do_cancel(self):
|
||||||
self._cancelled = True
|
self._cancelled = True
|
||||||
@@ -272,6 +448,10 @@ class ConnectDialog:
|
|||||||
self._dlg.destroy()
|
self._dlg.destroy()
|
||||||
|
|
||||||
|
|
||||||
|
# ────────────────────────────────────────────────────────────────────
|
||||||
|
# Persistence helpers
|
||||||
|
# ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
def _load_last_connection():
|
def _load_last_connection():
|
||||||
"""Reads last connection params from editor.properties."""
|
"""Reads last connection params from editor.properties."""
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
|
|||||||
@@ -1960,6 +1960,27 @@ def do_device_connect():
|
|||||||
connect_dialog.ConnectDialog(app_state.window, _connect_to_device)
|
connect_dialog.ConnectDialog(app_state.window, _connect_to_device)
|
||||||
|
|
||||||
|
|
||||||
|
def do_device_discover():
|
||||||
|
"""Opens the discover dialog to scan for devices on the network."""
|
||||||
|
if app_state.current_file_path and not app_state.live_mode:
|
||||||
|
if app_state.is_dirty:
|
||||||
|
answer = messagebox.askyesnocancel(
|
||||||
|
"Unsaved Changes",
|
||||||
|
"The current file has unsaved changes.\n\n"
|
||||||
|
"Save before connecting to a device?",
|
||||||
|
)
|
||||||
|
if answer is None:
|
||||||
|
return
|
||||||
|
if answer:
|
||||||
|
sax_file.execute_direct_overwrite_save()
|
||||||
|
sax_file.reset_to_startup_state()
|
||||||
|
sax_file.refresh_treeview_from_dom(None)
|
||||||
|
wiresheet.render_components([])
|
||||||
|
app_state.window.title(app_state.base_window_title())
|
||||||
|
|
||||||
|
connect_dialog.DiscoverDialog(app_state.window, _connect_to_device)
|
||||||
|
|
||||||
|
|
||||||
def _connect_to_device(host, port, user, password):
|
def _connect_to_device(host, port, user, password):
|
||||||
"""Called from the connect dialog's background thread."""
|
"""Called from the connect dialog's background thread."""
|
||||||
ds = device_session.DeviceSession()
|
ds = device_session.DeviceSession()
|
||||||
@@ -1979,6 +2000,7 @@ 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("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}")
|
||||||
@@ -2044,6 +2066,7 @@ def do_device_disconnect():
|
|||||||
|
|
||||||
app_state.window.title(app_state.base_window_title())
|
app_state.window.title(app_state.base_window_title())
|
||||||
menu_device.entryconfig("Connect...", state="normal")
|
menu_device.entryconfig("Connect...", state="normal")
|
||||||
|
menu_device.entryconfig("Discover...", state="normal")
|
||||||
menu_device.entryconfig("Disconnect", state="disabled")
|
menu_device.entryconfig("Disconnect", state="disabled")
|
||||||
menu_device.entryconfig("Download to SAX...", state="disabled")
|
menu_device.entryconfig("Download to SAX...", state="disabled")
|
||||||
app_state.set_status("Disconnected")
|
app_state.set_status("Disconnected")
|
||||||
@@ -2222,6 +2245,7 @@ menu_bar = tk.Menu(window)
|
|||||||
|
|
||||||
menu_device = tk.Menu(menu_bar, tearoff=0)
|
menu_device = tk.Menu(menu_bar, tearoff=0)
|
||||||
menu_device.add_command(label="Connect...", command=do_device_connect)
|
menu_device.add_command(label="Connect...", command=do_device_connect)
|
||||||
|
menu_device.add_command(label="Discover...", command=do_device_discover)
|
||||||
menu_device.add_command(label="Disconnect", command=do_device_disconnect, state="disabled")
|
menu_device.add_command(label="Disconnect", command=do_device_disconnect, state="disabled")
|
||||||
menu_device.add_separator()
|
menu_device.add_separator()
|
||||||
menu_device.add_command(label="Download to SAX...", command=do_download_to_sax, state="disabled")
|
menu_device.add_command(label="Download to SAX...", command=do_download_to_sax, state="disabled")
|
||||||
|
|||||||
Reference in New Issue
Block a user