diff --git a/EDMarketConnector.py b/EDMarketConnector.py
index af7a2b665..747d50ce5 100755
--- a/EDMarketConnector.py
+++ b/EDMarketConnector.py
@@ -417,25 +417,10 @@ def already_running_popup():
from l10n import translations as tr
from monitor import monitor
from theme import theme
-from ttkHyperlinkLabel import HyperlinkLabel
+from ttkHyperlinkLabel import HyperlinkLabel, SHIPYARD_HTML_TEMPLATE
SERVER_RETRY = 5 # retry pause for Companion servers [s]
-SHIPYARD_HTML_TEMPLATE = """
-
-
-
-
- Redirecting you to your {ship_name} at {provider_name}...
-
-
-
- You should be redirected to your {ship_name} at {provider_name} shortly...
-
-
-
-"""
-
class AppWindow:
"""Define the main application window."""
@@ -500,13 +485,13 @@ def open_window(systray: 'SysTrayIcon') -> None:
self.cmdr_label = tk.Label(frame, name='cmdr_label')
self.cmdr = tk.Label(frame, compound=tk.RIGHT, anchor=tk.W, name='cmdr')
self.ship_label = tk.Label(frame, name='ship_label')
- self.ship = HyperlinkLabel(frame, compound=tk.RIGHT, url=self.shipyard_url, name='ship')
+ self.ship = HyperlinkLabel(frame, compound=tk.RIGHT, url=self.shipyard_url, name='ship', popup_copy=True)
self.suit_label = tk.Label(frame, name='suit_label')
self.suit = tk.Label(frame, compound=tk.RIGHT, anchor=tk.W, name='suit')
self.system_label = tk.Label(frame, name='system_label')
self.system = HyperlinkLabel(frame, compound=tk.RIGHT, url=self.system_url, popup_copy=True, name='system')
self.station_label = tk.Label(frame, name='station_label')
- self.station = HyperlinkLabel(frame, compound=tk.RIGHT, url=self.station_url, name='station')
+ self.station = HyperlinkLabel(frame, compound=tk.RIGHT, url=self.station_url, name='station', popup_copy=True)
# system and station text is set/updated by the 'provider' plugins
# edsm and inara. Look for:
#
@@ -1613,7 +1598,7 @@ def plugin_error(self, event=None) -> None:
hotkeymgr.play_bad()
def shipyard_url(self, shipname: str) -> str | None:
- """Despatch a ship URL to the configured handler."""
+ """Dispatch a ship URL to the configured handler."""
if not (loadout := monitor.ship()):
logger.warning('No ship loadout, aborting.')
return ''
@@ -1640,13 +1625,13 @@ def shipyard_url(self, shipname: str) -> str | None:
return f'file://localhost/{file_name}'
def system_url(self, system: str) -> str | None:
- """Despatch a system URL to the configured handler."""
+ """Dispatch a system URL to the configured handler."""
return plug.invoke(
config.get_str('system_provider', default='EDSM'), 'EDSM', 'system_url', monitor.state['SystemName']
)
def station_url(self, station: str) -> str | None:
- """Despatch a station URL to the configured handler."""
+ """Dispatch a station URL to the configured handler."""
return plug.invoke(
config.get_str('station_provider', default='EDSM'), 'EDSM', 'station_url',
monitor.state['SystemName'], monitor.state['StationName']
diff --git a/L10n/en.template b/L10n/en.template
index b2c46d7cf..38a7fbed6 100644
--- a/L10n/en.template
+++ b/L10n/en.template
@@ -788,3 +788,6 @@
/* myNotebook.py: Can't Paste Images or Files in Text; */
"Cannot paste non-text content." = "Cannot paste non-text content.";
+
+/* ttkHyperlinkLabel.py: Open Element In Selected Provider; */
+"Open in {URL}" = "Open in {URL}";
\ No newline at end of file
diff --git a/myNotebook.py b/myNotebook.py
index 43acfebdf..8a3cf9010 100644
--- a/myNotebook.py
+++ b/myNotebook.py
@@ -121,7 +121,7 @@ def paste(self) -> None:
class Entry(EntryMenu):
"""Custom ttk.Entry class to fix some display issues."""
- # DEPRECATED: Migrate to EntryMenu. Will remove in 5.12 or later.
+ # DEPRECATED: Migrate to EntryMenu. Will remove in 6.0 or later.
def __init__(self, master: ttk.Frame | None = None, **kw):
EntryMenu.__init__(self, master, **kw)
@@ -139,7 +139,7 @@ def __init__(self, master: ttk.Frame | None = None, **kw):
class ColoredButton(tk.Button):
"""Custom tk.Button class to fix some display issues."""
- # DEPRECATED: Migrate to tk.Button. Will remove in 5.12 or later.
+ # DEPRECATED: Migrate to tk.Button. Will remove in 6.0 or later.
def __init__(self, master: ttk.Frame | None = None, **kw):
tk.Button.__init__(self, master, **kw)
diff --git a/ttkHyperlinkLabel.py b/ttkHyperlinkLabel.py
index d026f619d..3ec0a26d7 100644
--- a/ttkHyperlinkLabel.py
+++ b/ttkHyperlinkLabel.py
@@ -19,14 +19,34 @@
May be imported by plugins
"""
from __future__ import annotations
-
+import html
+from functools import partial
import sys
import tkinter as tk
import webbrowser
from tkinter import font as tk_font
from tkinter import ttk
from typing import Any
+import plug
+from os import path
+from config import config, logger
from l10n import translations as tr
+from monitor import monitor
+
+SHIPYARD_HTML_TEMPLATE = """
+
+
+
+
+ Redirecting you to your {ship_name} at {provider_name}...
+
+
+
+ You should be redirected to your {ship_name} at {provider_name} shortly...
+
+
+
+"""
class HyperlinkLabel(tk.Label or ttk.Label): # type: ignore
@@ -64,6 +84,72 @@ def __init__(self, master: ttk.Frame | tk.Frame | None = None, **kw: Any) -> Non
text=kw.get('text'),
font=kw.get('font', ttk.Style().lookup('TLabel', 'font')))
+ # Add Menu Options
+ self.plug_options = kw.pop('plug_options', None)
+ self.name = kw.get('name', None)
+ if self.name == 'ship':
+ self.menu.add_separator()
+ for url in plug.provides('shipyard_url'):
+ self.menu.add_command(
+ label=tr.tl("Open in {URL}").format(URL=url), # LANG: Open Element In Selected Provider
+ command=partial(self.open_shipyard, url)
+ )
+
+ if self.name == 'station':
+ self.menu.add_separator()
+ for url in plug.provides('station_url'):
+ self.menu.add_command(
+ label=tr.tl("Open in {URL}").format(URL=url), # LANG: Open Element In Selected Provider
+ command=partial(self.open_station, url)
+ )
+
+ if self.name == 'system':
+ self.menu.add_separator()
+ for url in plug.provides('system_url'):
+ self.menu.add_command(
+ label=tr.tl("Open in {URL}").format(URL=url), # LANG: Open Element In Selected Provider
+ command=partial(self.open_system, url)
+ )
+
+ def open_shipyard(self, url: str):
+ """Open the Current Ship Loadout in the Selected Provider."""
+ if not (loadout := monitor.ship()):
+ logger.warning('No ship loadout, aborting.')
+ return ''
+ if not bool(config.get_int("use_alt_shipyard_open")):
+ opener = plug.invoke(url, 'EDSY', 'shipyard_url', loadout, monitor.is_beta)
+ if opener:
+ return webbrowser.open(opener)
+ else:
+ # Avoid file length limits if possible
+ provider = config.get_str('shipyard_provider', default='EDSY')
+ target = plug.invoke(provider, 'EDSY', 'shipyard_url', loadout, monitor.is_beta)
+ file_name = path.join(config.app_dir_path, "last_shipyard.html")
+
+ with open(file_name, 'w') as f:
+ f.write(SHIPYARD_HTML_TEMPLATE.format(
+ link=html.escape(str(target)),
+ provider_name=html.escape(str(provider)),
+ ship_name=html.escape("Ship")
+ ))
+
+ webbrowser.open(f'file://localhost/{file_name}')
+
+ def open_system(self, url: str):
+ """Open the Current System in the Selected Provider."""
+ opener = plug.invoke(url, 'EDSM', 'system_url', monitor.state['SystemName'])
+ if opener:
+ return webbrowser.open(opener)
+
+ def open_station(self, url: str):
+ """Open the Current Station in the Selected Provider."""
+ opener = plug.invoke(
+ url, 'EDSM', 'station_url',
+ monitor.state['SystemName'], monitor.state['StationName']
+ )
+ if opener:
+ return webbrowser.open(opener)
+
def configure( # noqa: CCR001
self, cnf: dict[str, Any] | None = None, **kw: Any
) -> dict[str, tuple[str, str, str, Any, Any]] | None: