1+ import os
2+ import sys
3+ import platform
4+ import subprocess
5+ from pathlib import Path
6+ from typing import Optional
7+ from PyQt6 .QtWidgets import QMessageBox
8+ from PyQt6 .QtCore import Qt
9+ from .config import get_config_path , load_config , save_config
10+
11+
12+ def get_shortcut_preference () -> Optional [bool ]:
13+ """Get the saved preference for creating shortcuts."""
14+ config = load_config ()
15+ return config .get ("shortcut_created" )
16+
17+
18+ def save_shortcut_preference (created : bool ) -> None :
19+ """Save the preference for creating shortcuts."""
20+ config = load_config ()
21+ config ["shortcut_created" ] = created
22+ save_config (config )
23+
24+
25+ def create_windows_shortcut () -> bool :
26+ """Create a Windows Start Menu shortcut."""
27+ try :
28+ import win32com .client
29+
30+ # Get the Start Menu path
31+ start_menu = Path (os .environ ['APPDATA' ]) / "Microsoft" / "Windows" / "Start Menu" / "Programs"
32+ shortcut_path = start_menu / "SSH Tunnel Manager.lnk"
33+
34+ # Get the executable path
35+ if getattr (sys , 'frozen' , False ):
36+ # Running as compiled executable
37+ target_path = sys .executable
38+ else :
39+ # Running as Python script
40+ target_path = sys .executable
41+ arguments = f'"{ sys .argv [0 ]} "'
42+
43+ # Create shortcut
44+ shell = win32com .client .Dispatch ("WScript.Shell" )
45+ shortcut = shell .CreateShortCut (str (shortcut_path ))
46+ shortcut .TargetPath = target_path
47+ if not getattr (sys , 'frozen' , False ):
48+ shortcut .Arguments = arguments
49+ shortcut .WorkingDirectory = str (Path (target_path ).parent )
50+ shortcut .IconLocation = target_path
51+ shortcut .Description = "SSH Tunnel Manager - Manage your SSH tunnels with ease"
52+ shortcut .save ()
53+
54+ return True
55+ except Exception as e :
56+ print (f"Error creating Windows shortcut: { e } " )
57+ return False
58+
59+
60+ def create_linux_desktop_entry () -> bool :
61+ """Create a Linux desktop entry for the application launcher."""
62+ try :
63+ # Get the desktop entry path
64+ desktop_dir = Path .home () / ".local" / "share" / "applications"
65+ desktop_dir .mkdir (parents = True , exist_ok = True )
66+ desktop_file = desktop_dir / "ssh-tunnel-manager.desktop"
67+
68+ # Get the executable command
69+ if getattr (sys , 'frozen' , False ):
70+ # Running as compiled executable
71+ exec_command = sys .executable
72+ else :
73+ # Running as Python script - use the console script entry point
74+ exec_command = "ssh-tunnel-manager"
75+
76+ # Get icon path
77+ icon_path = Path (__file__ ).parent / "icon.ico"
78+ if not icon_path .exists ():
79+ icon_path = "ssh-tunnel-manager" # Fallback to icon name
80+
81+ # Create desktop entry content
82+ desktop_content = f"""[Desktop Entry]
83+ Version=1.0
84+ Type=Application
85+ Name=SSH Tunnel Manager
86+ Comment=Manage your SSH tunnels with ease
87+ Exec={ exec_command }
88+ Icon={ icon_path }
89+ Terminal=false
90+ Categories=Network;Utility;
91+ StartupNotify=true
92+ """
93+
94+ # Write desktop file
95+ desktop_file .write_text (desktop_content )
96+
97+ # Make it executable
98+ desktop_file .chmod (0o755 )
99+
100+ # Update desktop database
101+ try :
102+ subprocess .run (["update-desktop-database" , str (desktop_dir )],
103+ capture_output = True , check = False )
104+ except :
105+ pass # Not critical if this fails
106+
107+ return True
108+ except Exception as e :
109+ print (f"Error creating Linux desktop entry: { e } " )
110+ return False
111+
112+
113+ def create_shortcut () -> bool :
114+ """Create a shortcut based on the current platform."""
115+ system = platform .system ()
116+
117+ if system == "Windows" :
118+ return create_windows_shortcut ()
119+ elif system == "Linux" :
120+ return create_linux_desktop_entry ()
121+ else :
122+ print (f"Unsupported platform: { system } " )
123+ return False
124+
125+
126+ def check_and_ask_shortcut (parent = None ) -> None :
127+ """Check if we should ask about creating a shortcut and handle the response."""
128+ # Check if we've already asked
129+ preference = get_shortcut_preference ()
130+ if preference is not None :
131+ # Already asked, don't ask again
132+ return
133+
134+ # Prepare the message based on platform
135+ system = platform .system ()
136+ if system == "Windows" :
137+ location = "Windows Start Menu"
138+ elif system == "Linux" :
139+ location = "application launcher"
140+ else :
141+ # Unsupported platform, don't ask
142+ save_shortcut_preference (False )
143+ return
144+
145+ # Create and show the message box
146+ msg_box = QMessageBox (parent )
147+ msg_box .setWindowTitle ("Create Shortcut" )
148+ msg_box .setText (f"Would you like to add SSH Tunnel Manager to your { location } ?" )
149+ msg_box .setInformativeText ("This will make it easier to launch the application in the future." )
150+ msg_box .setStandardButtons (QMessageBox .StandardButton .Yes | QMessageBox .StandardButton .No )
151+ msg_box .setDefaultButton (QMessageBox .StandardButton .Yes )
152+ msg_box .setIcon (QMessageBox .Icon .Question )
153+
154+ # Show the dialog and get the response
155+ response = msg_box .exec ()
156+
157+ if response == QMessageBox .StandardButton .Yes :
158+ # Try to create the shortcut
159+ success = create_shortcut ()
160+ save_shortcut_preference (success )
161+
162+ if success :
163+ QMessageBox .information (
164+ parent ,
165+ "Success" ,
166+ f"SSH Tunnel Manager has been added to your { location } !" ,
167+ QMessageBox .StandardButton .Ok
168+ )
169+ else :
170+ QMessageBox .warning (
171+ parent ,
172+ "Error" ,
173+ "Failed to create the shortcut. You can try again later by running the application with administrator privileges." ,
174+ QMessageBox .StandardButton .Ok
175+ )
176+ else :
177+ # User said no, save the preference
178+ save_shortcut_preference (False )
0 commit comments