Remove recently used connections, keep only saved connections with alphabetical sorting
This commit is contained in:
162
rdp_client.py
162
rdp_client.py
@@ -366,33 +366,16 @@ class RDPClient:
|
|||||||
left_frame = ttk.Frame(main_frame)
|
left_frame = ttk.Frame(main_frame)
|
||||||
left_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=(0, 10))
|
left_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=(0, 10))
|
||||||
left_frame.rowconfigure(1, weight=1)
|
left_frame.rowconfigure(1, weight=1)
|
||||||
left_frame.rowconfigure(3, weight=1)
|
left_frame.rowconfigure(1, weight=1) # Only saved connections now
|
||||||
left_frame.columnconfigure(0, weight=1)
|
left_frame.columnconfigure(0, weight=1)
|
||||||
|
|
||||||
# Recent Connections
|
# Saved Connections (now the main/only connections list)
|
||||||
recent_label = ttk.Label(left_frame, text="Recent Connections", font=('Arial', 10, 'bold'))
|
|
||||||
recent_label.grid(row=0, column=0, sticky=tk.W, pady=(0, 5))
|
|
||||||
|
|
||||||
# Recent connections frame with listbox and scrollbar
|
|
||||||
recent_frame = ttk.Frame(left_frame)
|
|
||||||
recent_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), pady=(0, 10))
|
|
||||||
recent_frame.rowconfigure(0, weight=1)
|
|
||||||
recent_frame.columnconfigure(0, weight=1)
|
|
||||||
|
|
||||||
self.recent_listbox = tk.Listbox(recent_frame, font=('Arial', 9), height=6, width=30)
|
|
||||||
recent_scrollbar = ttk.Scrollbar(recent_frame, orient="vertical", command=self.recent_listbox.yview)
|
|
||||||
self.recent_listbox.configure(yscrollcommand=recent_scrollbar.set)
|
|
||||||
|
|
||||||
self.recent_listbox.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
|
|
||||||
recent_scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))
|
|
||||||
|
|
||||||
# Saved Connections
|
|
||||||
saved_label = ttk.Label(left_frame, text="Saved Connections", font=('Arial', 10, 'bold'))
|
saved_label = ttk.Label(left_frame, text="Saved Connections", font=('Arial', 10, 'bold'))
|
||||||
saved_label.grid(row=2, column=0, sticky=tk.W, pady=(10, 5))
|
saved_label.grid(row=0, column=0, sticky=tk.W, pady=(0, 5))
|
||||||
|
|
||||||
# Saved connections frame with listbox and scrollbar
|
# Saved connections frame with listbox and scrollbar
|
||||||
saved_frame = ttk.Frame(left_frame)
|
saved_frame = ttk.Frame(left_frame)
|
||||||
saved_frame.grid(row=3, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
|
saved_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
|
||||||
saved_frame.rowconfigure(0, weight=1)
|
saved_frame.rowconfigure(0, weight=1)
|
||||||
saved_frame.columnconfigure(0, weight=1)
|
saved_frame.columnconfigure(0, weight=1)
|
||||||
|
|
||||||
@@ -405,7 +388,7 @@ class RDPClient:
|
|||||||
|
|
||||||
# Connection buttons
|
# Connection buttons
|
||||||
conn_buttons_frame = ttk.Frame(left_frame)
|
conn_buttons_frame = ttk.Frame(left_frame)
|
||||||
conn_buttons_frame.grid(row=4, column=0, pady=(10, 0), sticky=(tk.W, tk.E))
|
conn_buttons_frame.grid(row=2, column=0, pady=(10, 0), sticky=(tk.W, tk.E))
|
||||||
|
|
||||||
ttk.Button(conn_buttons_frame, text="Connect",
|
ttk.Button(conn_buttons_frame, text="Connect",
|
||||||
command=self._connect_selected).pack(side=tk.LEFT, padx=(0, 5))
|
command=self._connect_selected).pack(side=tk.LEFT, padx=(0, 5))
|
||||||
@@ -465,8 +448,6 @@ class RDPClient:
|
|||||||
# Bind listbox selection
|
# Bind listbox selection
|
||||||
self.connections_listbox.bind('<<ListboxSelect>>', self._on_connection_select)
|
self.connections_listbox.bind('<<ListboxSelect>>', self._on_connection_select)
|
||||||
self.connections_listbox.bind('<Double-Button-1>', self._connect_selected)
|
self.connections_listbox.bind('<Double-Button-1>', self._connect_selected)
|
||||||
self.recent_listbox.bind('<<ListboxSelect>>', self._on_recent_select)
|
|
||||||
self.recent_listbox.bind('<Double-Button-1>', self._connect_recent)
|
|
||||||
|
|
||||||
# Keyboard shortcuts
|
# Keyboard shortcuts
|
||||||
self._setup_keyboard_shortcuts()
|
self._setup_keyboard_shortcuts()
|
||||||
@@ -503,55 +484,16 @@ class RDPClient:
|
|||||||
self.connections_listbox.bind('<F2>', lambda e: self._edit_selected())
|
self.connections_listbox.bind('<F2>', lambda e: self._edit_selected())
|
||||||
self.connections_listbox.bind('<Control-t>', lambda e: self._test_selected_connection())
|
self.connections_listbox.bind('<Control-t>', lambda e: self._test_selected_connection())
|
||||||
|
|
||||||
self.recent_listbox.bind('<Return>', lambda e: self._connect_selected())
|
# Set initial focus
|
||||||
self.recent_listbox.bind('<Delete>', lambda e: self._delete_selected())
|
self.connections_listbox.focus_set()
|
||||||
self.recent_listbox.bind('<F2>', lambda e: self._edit_selected())
|
if self.connections_listbox.size() > 0:
|
||||||
self.recent_listbox.bind('<Control-t>', lambda e: self._test_selected_connection())
|
self.connections_listbox.selection_set(0)
|
||||||
|
|
||||||
# Set focus handling
|
|
||||||
self.root.bind('<Tab>', self._handle_tab_focus)
|
|
||||||
self.root.bind('<Shift-Tab>', self._handle_shift_tab_focus)
|
|
||||||
|
|
||||||
# Add tooltip information for shortcuts
|
# Add tooltip information for shortcuts
|
||||||
self._add_keyboard_shortcuts_info()
|
self._add_keyboard_shortcuts_info()
|
||||||
|
|
||||||
def _handle_tab_focus(self, event):
|
# Add tooltip information for shortcuts
|
||||||
"""Handle Tab key for focus navigation"""
|
self._add_keyboard_shortcuts_info()
|
||||||
current_focus = self.root.focus_get()
|
|
||||||
|
|
||||||
if current_focus == self.recent_listbox:
|
|
||||||
self.connections_listbox.focus_set()
|
|
||||||
if self.connections_listbox.size() > 0:
|
|
||||||
self.connections_listbox.selection_set(0)
|
|
||||||
elif current_focus == self.connections_listbox:
|
|
||||||
self.recent_listbox.focus_set()
|
|
||||||
if self.recent_listbox.size() > 0:
|
|
||||||
self.recent_listbox.selection_set(0)
|
|
||||||
else:
|
|
||||||
self.recent_listbox.focus_set()
|
|
||||||
if self.recent_listbox.size() > 0:
|
|
||||||
self.recent_listbox.selection_set(0)
|
|
||||||
|
|
||||||
return "break" # Prevent default Tab behavior
|
|
||||||
|
|
||||||
def _handle_shift_tab_focus(self, event):
|
|
||||||
"""Handle Shift+Tab key for reverse focus navigation"""
|
|
||||||
current_focus = self.root.focus_get()
|
|
||||||
|
|
||||||
if current_focus == self.connections_listbox:
|
|
||||||
self.recent_listbox.focus_set()
|
|
||||||
if self.recent_listbox.size() > 0:
|
|
||||||
self.recent_listbox.selection_set(0)
|
|
||||||
elif current_focus == self.recent_listbox:
|
|
||||||
self.connections_listbox.focus_set()
|
|
||||||
if self.connections_listbox.size() > 0:
|
|
||||||
self.connections_listbox.selection_set(0)
|
|
||||||
else:
|
|
||||||
self.connections_listbox.focus_set()
|
|
||||||
if self.connections_listbox.size() > 0:
|
|
||||||
self.connections_listbox.selection_set(0)
|
|
||||||
|
|
||||||
return "break" # Prevent default Shift+Tab behavior
|
|
||||||
|
|
||||||
def _add_keyboard_shortcuts_info(self):
|
def _add_keyboard_shortcuts_info(self):
|
||||||
"""Add keyboard shortcuts information to the status bar or help"""
|
"""Add keyboard shortcuts information to the status bar or help"""
|
||||||
@@ -563,11 +505,9 @@ class RDPClient:
|
|||||||
def clear_shortcuts_hint(event):
|
def clear_shortcuts_hint(event):
|
||||||
self.status_var.set("Ready")
|
self.status_var.set("Ready")
|
||||||
|
|
||||||
# Show shortcuts hint when certain widgets get focus
|
# Show shortcuts hint when connections listbox gets focus
|
||||||
self.connections_listbox.bind('<FocusIn>', show_shortcuts_hint)
|
self.connections_listbox.bind('<FocusIn>', show_shortcuts_hint)
|
||||||
self.recent_listbox.bind('<FocusIn>', show_shortcuts_hint)
|
|
||||||
self.connections_listbox.bind('<FocusOut>', clear_shortcuts_hint)
|
self.connections_listbox.bind('<FocusOut>', clear_shortcuts_hint)
|
||||||
self.recent_listbox.bind('<FocusOut>', clear_shortcuts_hint)
|
|
||||||
|
|
||||||
def _show_help(self):
|
def _show_help(self):
|
||||||
"""Show keyboard shortcuts help dialog"""
|
"""Show keyboard shortcuts help dialog"""
|
||||||
@@ -588,15 +528,12 @@ Connection List Shortcuts:
|
|||||||
• Double-click - Connect to selected connection
|
• Double-click - Connect to selected connection
|
||||||
• Delete - Delete selected connection
|
• Delete - Delete selected connection
|
||||||
• F2 - Edit selected connection
|
• F2 - Edit selected connection
|
||||||
• Tab - Switch between Recent and Saved connections
|
|
||||||
|
|
||||||
Navigation:
|
Navigation:
|
||||||
• Tab - Move between Recent and Saved connections
|
• Arrow keys - Navigate within connections list
|
||||||
• Shift+Tab - Move between connections (reverse)
|
|
||||||
• Arrow keys - Navigate within lists
|
|
||||||
|
|
||||||
Tips:
|
Tips:
|
||||||
• Recent connections show usage count (e.g., "Server (5x)")
|
• Connections are sorted alphabetically by name
|
||||||
• Double-click any connection to connect quickly
|
• Double-click any connection to connect quickly
|
||||||
• Use Test Connection to verify server availability
|
• Use Test Connection to verify server availability
|
||||||
• Import/Export to backup or share connection profiles
|
• Import/Export to backup or share connection profiles
|
||||||
@@ -612,50 +549,17 @@ Multi-Monitor Support:
|
|||||||
messagebox.showinfo("Keyboard Shortcuts", help_text)
|
messagebox.showinfo("Keyboard Shortcuts", help_text)
|
||||||
|
|
||||||
def _refresh_connections_list(self):
|
def _refresh_connections_list(self):
|
||||||
"""Refresh the connections listbox"""
|
"""Refresh the connections listbox with sorted saved connections"""
|
||||||
self.connections_listbox.delete(0, tk.END)
|
self.connections_listbox.delete(0, tk.END)
|
||||||
for name in sorted(self.connections.keys()):
|
# Sort connections by name (case-insensitive)
|
||||||
|
for name in sorted(self.connections.keys(), key=str.lower):
|
||||||
self.connections_listbox.insert(tk.END, name)
|
self.connections_listbox.insert(tk.END, name)
|
||||||
|
|
||||||
# Refresh recent connections
|
|
||||||
self.recent_listbox.delete(0, tk.END)
|
|
||||||
for entry in self.history[:10]: # Show last 10 recent connections
|
|
||||||
name = entry.get('name', '')
|
|
||||||
count = entry.get('count', 0)
|
|
||||||
if name in self.connections: # Only show if connection still exists
|
|
||||||
display_text = f"{name} ({count}x)"
|
|
||||||
self.recent_listbox.insert(tk.END, display_text)
|
|
||||||
|
|
||||||
# Clear details if no connections
|
# Clear details if no connections
|
||||||
if not self.connections:
|
if not self.connections:
|
||||||
for label in self.details_labels.values():
|
for label in self.details_labels.values():
|
||||||
label.config(text="")
|
label.config(text="")
|
||||||
|
|
||||||
def _on_recent_select(self, event=None):
|
|
||||||
"""Handle recent connection selection"""
|
|
||||||
selection = self.recent_listbox.curselection()
|
|
||||||
if selection:
|
|
||||||
display_text = self.recent_listbox.get(selection[0])
|
|
||||||
# Extract connection name (everything before " (")
|
|
||||||
name = display_text.split(' (')[0]
|
|
||||||
if name in self.connections:
|
|
||||||
# Clear saved connections selection
|
|
||||||
self.connections_listbox.selection_clear(0, tk.END)
|
|
||||||
# Update details
|
|
||||||
conn = self.connections[name]
|
|
||||||
self._update_details(conn)
|
|
||||||
|
|
||||||
def _connect_recent(self, event=None):
|
|
||||||
"""Connect to selected recent connection"""
|
|
||||||
selection = self.recent_listbox.curselection()
|
|
||||||
if not selection:
|
|
||||||
return
|
|
||||||
|
|
||||||
display_text = self.recent_listbox.get(selection[0])
|
|
||||||
name = display_text.split(' (')[0]
|
|
||||||
if name in self.connections:
|
|
||||||
self._connect_to(name)
|
|
||||||
|
|
||||||
def _update_details(self, conn):
|
def _update_details(self, conn):
|
||||||
"""Update the details panel with connection info"""
|
"""Update the details panel with connection info"""
|
||||||
self.details_labels["server"].config(text=conn.get("server", ""))
|
self.details_labels["server"].config(text=conn.get("server", ""))
|
||||||
@@ -676,8 +580,6 @@ Multi-Monitor Support:
|
|||||||
name = self.connections_listbox.get(selection[0])
|
name = self.connections_listbox.get(selection[0])
|
||||||
conn = self.connections[name]
|
conn = self.connections[name]
|
||||||
|
|
||||||
# Clear recent connections selection
|
|
||||||
self.recent_listbox.selection_clear(0, tk.END)
|
|
||||||
# Update details
|
# Update details
|
||||||
self._update_details(conn)
|
self._update_details(conn)
|
||||||
|
|
||||||
@@ -706,7 +608,7 @@ Multi-Monitor Support:
|
|||||||
self.credentials[name]["password"] = self._encrypt_password(dialog.result["password"])
|
self.credentials[name]["password"] = self._encrypt_password(dialog.result["password"])
|
||||||
self._save_credentials()
|
self._save_credentials()
|
||||||
|
|
||||||
# Add new connection to history so it appears in recent connections
|
# Add new connection to history
|
||||||
self._add_to_history(name)
|
self._add_to_history(name)
|
||||||
|
|
||||||
self._refresh_connections_list()
|
self._refresh_connections_list()
|
||||||
@@ -714,16 +616,12 @@ Multi-Monitor Support:
|
|||||||
|
|
||||||
def _edit_selected(self):
|
def _edit_selected(self):
|
||||||
"""Edit selected connection"""
|
"""Edit selected connection"""
|
||||||
# Check which listbox has a selection
|
# Check saved connections selection
|
||||||
saved_selection = self.connections_listbox.curselection()
|
saved_selection = self.connections_listbox.curselection()
|
||||||
recent_selection = self.recent_listbox.curselection()
|
|
||||||
|
|
||||||
name = None
|
name = None
|
||||||
if saved_selection:
|
if saved_selection:
|
||||||
name = self.connections_listbox.get(saved_selection[0])
|
name = self.connections_listbox.get(saved_selection[0])
|
||||||
elif recent_selection:
|
|
||||||
display_text = self.recent_listbox.get(recent_selection[0])
|
|
||||||
name = display_text.split(' (')[0]
|
|
||||||
|
|
||||||
if not name:
|
if not name:
|
||||||
messagebox.showwarning("No Selection", "Please select a connection to edit.")
|
messagebox.showwarning("No Selection", "Please select a connection to edit.")
|
||||||
@@ -782,16 +680,12 @@ Multi-Monitor Support:
|
|||||||
|
|
||||||
def _delete_selected(self):
|
def _delete_selected(self):
|
||||||
"""Delete selected connection"""
|
"""Delete selected connection"""
|
||||||
# Check which listbox has a selection
|
# Check saved connections selection
|
||||||
saved_selection = self.connections_listbox.curselection()
|
saved_selection = self.connections_listbox.curselection()
|
||||||
recent_selection = self.recent_listbox.curselection()
|
|
||||||
|
|
||||||
name = None
|
name = None
|
||||||
if saved_selection:
|
if saved_selection:
|
||||||
name = self.connections_listbox.get(saved_selection[0])
|
name = self.connections_listbox.get(saved_selection[0])
|
||||||
elif recent_selection:
|
|
||||||
display_text = self.recent_listbox.get(recent_selection[0])
|
|
||||||
name = display_text.split(' (')[0]
|
|
||||||
|
|
||||||
if not name:
|
if not name:
|
||||||
messagebox.showwarning("No Selection", "Please select a connection to delete.")
|
messagebox.showwarning("No Selection", "Please select a connection to delete.")
|
||||||
@@ -817,18 +711,12 @@ Multi-Monitor Support:
|
|||||||
|
|
||||||
def _connect_selected(self, event=None):
|
def _connect_selected(self, event=None):
|
||||||
"""Connect to selected connection"""
|
"""Connect to selected connection"""
|
||||||
# Check which listbox has a selection
|
# Check saved connections selection
|
||||||
saved_selection = self.connections_listbox.curselection()
|
saved_selection = self.connections_listbox.curselection()
|
||||||
recent_selection = self.recent_listbox.curselection()
|
|
||||||
|
|
||||||
if saved_selection:
|
if saved_selection:
|
||||||
name = self.connections_listbox.get(saved_selection[0])
|
name = self.connections_listbox.get(saved_selection[0])
|
||||||
self._connect_to(name)
|
self._connect_to(name)
|
||||||
elif recent_selection:
|
|
||||||
display_text = self.recent_listbox.get(recent_selection[0])
|
|
||||||
name = display_text.split(' (')[0]
|
|
||||||
if name in self.connections:
|
|
||||||
self._connect_to(name)
|
|
||||||
else:
|
else:
|
||||||
messagebox.showwarning("No Selection", "Please select a connection to connect.")
|
messagebox.showwarning("No Selection", "Please select a connection to connect.")
|
||||||
|
|
||||||
@@ -853,7 +741,7 @@ Multi-Monitor Support:
|
|||||||
# Build and execute RDP command
|
# Build and execute RDP command
|
||||||
self._add_to_history(name)
|
self._add_to_history(name)
|
||||||
self._execute_rdp_connection(conn, password)
|
self._execute_rdp_connection(conn, password)
|
||||||
self._refresh_connections_list() # Refresh to update recent connections
|
self._refresh_connections_list() # Refresh connections list
|
||||||
|
|
||||||
def _execute_rdp_connection(self, conn, password):
|
def _execute_rdp_connection(self, conn, password):
|
||||||
"""Execute the RDP connection in a separate thread"""
|
"""Execute the RDP connection in a separate thread"""
|
||||||
@@ -1225,16 +1113,12 @@ Multi-Monitor Support:
|
|||||||
|
|
||||||
def _test_selected_connection(self):
|
def _test_selected_connection(self):
|
||||||
"""Test the selected connection for reachability"""
|
"""Test the selected connection for reachability"""
|
||||||
# Check which listbox has a selection
|
# Check saved connections selection
|
||||||
saved_selection = self.connections_listbox.curselection()
|
saved_selection = self.connections_listbox.curselection()
|
||||||
recent_selection = self.recent_listbox.curselection()
|
|
||||||
|
|
||||||
name = None
|
name = None
|
||||||
if saved_selection:
|
if saved_selection:
|
||||||
name = self.connections_listbox.get(saved_selection[0])
|
name = self.connections_listbox.get(saved_selection[0])
|
||||||
elif recent_selection:
|
|
||||||
display_text = self.recent_listbox.get(recent_selection[0])
|
|
||||||
name = display_text.split(' (')[0]
|
|
||||||
|
|
||||||
if not name:
|
if not name:
|
||||||
messagebox.showwarning("No Selection", "Please select a connection to test.")
|
messagebox.showwarning("No Selection", "Please select a connection to test.")
|
||||||
|
|||||||
Reference in New Issue
Block a user