mirror of
https://github.com/EDCD/EDMarketConnector.git
synced 2025-05-01 16:01:30 +03:00
Merge pull request #2408 from HullSeals/enhancement/2406/common-core-refactor
[#2406] Duplicate Code Refactor
This commit is contained in:
commit
ed964b3e55
23
EDMC.py
23
EDMC.py
@ -10,12 +10,12 @@ from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import locale
|
||||
import os
|
||||
import queue
|
||||
import sys
|
||||
from time import sleep, time
|
||||
from typing import TYPE_CHECKING, Any
|
||||
from common_utils import log_locale, SERVER_RETRY
|
||||
|
||||
# isort: off
|
||||
os.environ["EDMC_NO_UI"] = "1"
|
||||
@ -52,31 +52,12 @@ import eddn # noqa: E402
|
||||
|
||||
|
||||
# isort: on
|
||||
|
||||
|
||||
def log_locale(prefix: str) -> None:
|
||||
"""Log the current state of locale settings."""
|
||||
logger.debug(f'''Locale: {prefix}
|
||||
Locale LC_COLLATE: {locale.getlocale(locale.LC_COLLATE)}
|
||||
Locale LC_CTYPE: {locale.getlocale(locale.LC_CTYPE)}
|
||||
Locale LC_MONETARY: {locale.getlocale(locale.LC_MONETARY)}
|
||||
Locale LC_NUMERIC: {locale.getlocale(locale.LC_NUMERIC)}
|
||||
Locale LC_TIME: {locale.getlocale(locale.LC_TIME)}'''
|
||||
)
|
||||
|
||||
|
||||
tr.install_dummy()
|
||||
|
||||
SERVER_RETRY = 5 # retry pause for Companion servers [s]
|
||||
EXIT_SUCCESS, EXIT_SERVER, EXIT_CREDENTIALS, EXIT_VERIFICATION, EXIT_LAGGING, EXIT_SYS_ERR, EXIT_ARGS, \
|
||||
EXIT_JOURNAL_READ_ERR, EXIT_COMMANDER_UNKNOWN = range(9)
|
||||
|
||||
|
||||
def versioncmp(versionstring) -> list:
|
||||
"""Quick and dirty version comparison assuming "strict" numeric only version numbers."""
|
||||
return list(map(int, versionstring.split('.')))
|
||||
|
||||
|
||||
def deep_get(target: dict | companion.CAPIData, *args: str, default=None) -> Any:
|
||||
"""
|
||||
Walk into a dict and return the specified deep value.
|
||||
@ -108,7 +89,7 @@ def deep_get(target: dict | companion.CAPIData, *args: str, default=None) -> Any
|
||||
return current
|
||||
|
||||
|
||||
def main(): # noqa: C901, CCR001
|
||||
def main() -> None: # noqa: C901, CCR001
|
||||
"""Run the main code of the program."""
|
||||
try:
|
||||
# arg parsing
|
||||
|
@ -335,8 +335,6 @@ class EDMCContextFilter(logging.Filter):
|
||||
# <https://stackoverflow.com/questions/2203424/python-how-to-retrieve-class-information-from-a-frame-object#2220759>
|
||||
try:
|
||||
frame_info = inspect.getframeinfo(frame)
|
||||
# raise(IndexError) # TODO: Remove, only for testing
|
||||
|
||||
except Exception:
|
||||
# Separate from the print below to guarantee we see at least this much.
|
||||
print('EDMCLogging:EDMCContextFilter:caller_attributes(): Failed in `inspect.getframinfo(frame)`')
|
||||
|
@ -38,17 +38,17 @@ from monitor import monitor
|
||||
from EDMCLogging import get_main_logger
|
||||
|
||||
|
||||
def get_sys_report(config: config.AbstractConfig) -> str:
|
||||
def get_sys_report(active_config: config.AbstractConfig) -> str:
|
||||
"""Gather system information about Elite, the Host Computer, and EDMC."""
|
||||
# Calculate Requested Information
|
||||
plt = platform.uname()
|
||||
locale.setlocale(locale.LC_ALL, "")
|
||||
lcl = locale.getlocale()
|
||||
monitor.currentdir = config.get_str(
|
||||
"journaldir", default=config.default_journal_dir
|
||||
monitor.currentdir = active_config.get_str(
|
||||
"journaldir", default=active_config.default_journal_dir
|
||||
)
|
||||
if not monitor.currentdir:
|
||||
monitor.currentdir = config.default_journal_dir
|
||||
monitor.currentdir = active_config.default_journal_dir
|
||||
try:
|
||||
logfile = monitor.journal_newest_filename(monitor.currentdir)
|
||||
if logfile is None:
|
||||
@ -108,21 +108,21 @@ def copy_sys_report(root: tk.Tk, report: str) -> None:
|
||||
messagebox.showinfo("System Profiler", "System Report copied to Clipboard", parent=root)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
def main(active_config: config.AbstractConfig) -> None:
|
||||
"""Entry Point for the System Profiler."""
|
||||
# Now Let's Begin
|
||||
root: tk.Tk = tk.Tk()
|
||||
root.withdraw() # Hide the window initially to calculate the dimensions
|
||||
try:
|
||||
icon_image = tk.PhotoImage(
|
||||
file=path.join(cur_config.respath_path, "io.edcd.EDMarketConnector.png")
|
||||
file=path.join(active_config.respath_path, "io.edcd.EDMarketConnector.png")
|
||||
)
|
||||
|
||||
root.iconphoto(True, icon_image)
|
||||
except tk.TclError:
|
||||
root.iconbitmap(path.join(cur_config.respath_path, "EDMarketConnector.ico"))
|
||||
root.iconbitmap(path.join(active_config.respath_path, "EDMarketConnector.ico"))
|
||||
|
||||
sys_report = get_sys_report(cur_config)
|
||||
sys_report = get_sys_report(active_config)
|
||||
|
||||
# Set up styling
|
||||
style = ttk.Style(root)
|
||||
@ -182,7 +182,8 @@ if __name__ == "__main__":
|
||||
# Args: Only work if not frozen
|
||||
parser = argparse.ArgumentParser(
|
||||
prog=appname,
|
||||
description="Prints diagnostic and debugging information about the current EDMC configuration.",
|
||||
description="Prints diagnostic and debugging information "
|
||||
"about the current EDMC configuration.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--out-console",
|
||||
@ -203,4 +204,4 @@ if __name__ == "__main__":
|
||||
print(sys_report)
|
||||
sys.exit(0)
|
||||
|
||||
main()
|
||||
main(cur_config)
|
||||
|
@ -68,6 +68,7 @@ from config import appversion, appversion_nobuild, config, copyright
|
||||
from EDMCLogging import edmclogger, logger, logging
|
||||
from journal_lock import JournalLock, JournalLockResult
|
||||
from update import check_for_fdev_updates
|
||||
from common_utils import log_locale, SERVER_RETRY
|
||||
|
||||
if __name__ == '__main__': # noqa: C901
|
||||
# Command-line arguments
|
||||
@ -416,8 +417,6 @@ from monitor import monitor
|
||||
from theme import theme
|
||||
from ttkHyperlinkLabel import HyperlinkLabel, SHIPYARD_HTML_TEMPLATE
|
||||
|
||||
SERVER_RETRY = 5 # retry pause for Companion servers [s]
|
||||
|
||||
|
||||
class AppWindow:
|
||||
"""Define the main application window."""
|
||||
@ -837,8 +836,7 @@ class AppWindow:
|
||||
r' if downgrading between major versions with significant changes.\r\n\r\n'
|
||||
'Do you want to open GitHub to download the latest release?'
|
||||
)
|
||||
update_msg = update_msg.replace('\\n', '\n')
|
||||
update_msg = update_msg.replace('\\r', '\r')
|
||||
update_msg = update_msg.replace('\\n', '\n').replace('\\r', '\r')
|
||||
stable_popup = tk.messagebox.askyesno(title=title, message=update_msg)
|
||||
if stable_popup:
|
||||
webbrowser.open("https://github.com/EDCD/eDMarketConnector/releases/latest")
|
||||
@ -1979,17 +1977,6 @@ def test_logging() -> None:
|
||||
logger.debug('Test from EDMarketConnector.py top-level test_logging()')
|
||||
|
||||
|
||||
def log_locale(prefix: str) -> None:
|
||||
"""Log all of the current local settings."""
|
||||
logger.debug(f'''Locale: {prefix}
|
||||
Locale LC_COLLATE: {locale.getlocale(locale.LC_COLLATE)}
|
||||
Locale LC_CTYPE: {locale.getlocale(locale.LC_CTYPE)}
|
||||
Locale LC_MONETARY: {locale.getlocale(locale.LC_MONETARY)}
|
||||
Locale LC_NUMERIC: {locale.getlocale(locale.LC_NUMERIC)}
|
||||
Locale LC_TIME: {locale.getlocale(locale.LC_TIME)}'''
|
||||
)
|
||||
|
||||
|
||||
def setup_killswitches(filename: str | None):
|
||||
"""Download and setup the main killswitch list."""
|
||||
logger.debug('fetching killswitches...')
|
||||
@ -2061,17 +2048,15 @@ def validate_providers():
|
||||
|
||||
# LANG: Popup-text about Reset Providers
|
||||
popup_text = tr.tl(r'One or more of your URL Providers were invalid, and have been reset:\r\n\r\n')
|
||||
for provider in reset_providers:
|
||||
for provider, (old_prov, new_prov) in reset_providers.items():
|
||||
# LANG: Text About What Provider Was Reset
|
||||
popup_text += tr.tl(r'{PROVIDER} was set to {OLDPROV}, and has been reset to {NEWPROV}\r\n')
|
||||
popup_text = popup_text.format(
|
||||
popup_text += tr.tl(r'{PROVIDER} was set to {OLDPROV}, and has been reset to {NEWPROV}\r\n').format(
|
||||
PROVIDER=provider,
|
||||
OLDPROV=reset_providers[provider][0],
|
||||
NEWPROV=reset_providers[provider][1]
|
||||
OLDPROV=old_prov,
|
||||
NEWPROV=new_prov
|
||||
)
|
||||
# And now we do need these to be actual \r\n
|
||||
popup_text = popup_text.replace('\\n', '\n')
|
||||
popup_text = popup_text.replace('\\r', '\r')
|
||||
popup_text = popup_text.replace('\\n', '\n').replace('\\r', '\r')
|
||||
|
||||
tk.messagebox.showinfo(
|
||||
# LANG: Popup window title for Reset Providers
|
||||
@ -2243,8 +2228,7 @@ sys.path: {sys.path}'''
|
||||
detail = tr.tl( # LANG: EDMC Critical Error Details
|
||||
r"Here's what EDMC Detected:\r\n\r\n{ERR}\r\n\r\nDo you want to file a Bug Report on GitHub?"
|
||||
).format(ERR=err)
|
||||
detail = detail.replace('\\n', '\n')
|
||||
detail = detail.replace('\\r', '\r')
|
||||
detail = detail.replace('\\n', '\n').replace('\\r', '\r')
|
||||
msg = tk.messagebox.askyesno(
|
||||
title=title, message=message, detail=detail, icon=tkinter.messagebox.ERROR, type=tkinter.messagebox.YESNO,
|
||||
parent=root
|
||||
@ -2275,8 +2259,7 @@ sys.path: {sys.path}'''
|
||||
DISABLED='.disabled'
|
||||
)
|
||||
# And now we do need these to be actual \r\n
|
||||
popup_text = popup_text.replace('\\n', '\n')
|
||||
popup_text = popup_text.replace('\\r', '\r')
|
||||
popup_text = popup_text.replace('\\n', '\n').replace('\\r', '\r')
|
||||
|
||||
tk.messagebox.showinfo(
|
||||
# LANG: Popup window title for list of 'broken' plugins that failed to load
|
||||
@ -2306,8 +2289,7 @@ sys.path: {sys.path}'''
|
||||
DISABLED='.disabled'
|
||||
)
|
||||
# And now we do need these to be actual \r\n
|
||||
popup_text = popup_text.replace('\\n', '\n')
|
||||
popup_text = popup_text.replace('\\r', '\r')
|
||||
popup_text = popup_text.replace('\\n', '\n').replace('\\r', '\r')
|
||||
|
||||
tk.messagebox.showinfo(
|
||||
# LANG: Popup window title for list of 'enabled' plugins that don't work with Python 3.x
|
||||
|
10
PLUGINS.md
10
PLUGINS.md
@ -153,6 +153,16 @@ See [#1327 - ModuleNotFound when creating a new plugin.](https://github.com/EDCD
|
||||
for some discussion.
|
||||
|
||||
|
||||
## Common Resources
|
||||
|
||||
Some plugins may wish to use resources available in a different plugin, or use
|
||||
common assets across plugins. This is possible, however care must be taken to
|
||||
ensure that the plugins do not attempt to load non-existent data or create
|
||||
circular imports.
|
||||
|
||||
For an example of how this is done, look at the code in `plugins/common_coreutils.py`
|
||||
and the usage of these functions in other core plugins.
|
||||
|
||||
---
|
||||
|
||||
## Logging
|
||||
|
1
build.py
1
build.py
@ -121,6 +121,7 @@ def build() -> None:
|
||||
"plugins/edsy.py",
|
||||
"plugins/inara.py",
|
||||
"plugins/spansh_core.py",
|
||||
"plugins/common_coreutils.py"
|
||||
]
|
||||
options: dict = {
|
||||
"py2exe": {
|
||||
|
61
common_utils.py
Normal file
61
common_utils.py
Normal file
@ -0,0 +1,61 @@
|
||||
"""
|
||||
common_utils.py - Common functions and modules.
|
||||
|
||||
Copyright (c) EDCD, All Rights Reserved
|
||||
Licensed under the GNU General Public License.
|
||||
See LICENSE file.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import sys
|
||||
import locale
|
||||
from typing import TYPE_CHECKING
|
||||
from EDMCLogging import get_main_logger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import tkinter as tk
|
||||
logger = get_main_logger()
|
||||
|
||||
SERVER_RETRY = 5 # retry pause for Companion servers [s]
|
||||
|
||||
if sys.platform == 'win32':
|
||||
import ctypes
|
||||
from ctypes.wintypes import POINT, RECT, SIZE, UINT, BOOL
|
||||
import win32gui
|
||||
try:
|
||||
CalculatePopupWindowPosition = ctypes.windll.user32.CalculatePopupWindowPosition
|
||||
CalculatePopupWindowPosition.argtypes = [
|
||||
ctypes.POINTER(POINT), ctypes.POINTER(SIZE), UINT, ctypes.POINTER(RECT), ctypes.POINTER(RECT)
|
||||
]
|
||||
CalculatePopupWindowPosition.restype = BOOL
|
||||
except Exception: # Not supported under Wine 4.0
|
||||
CalculatePopupWindowPosition = None # type: ignore
|
||||
|
||||
|
||||
def ensure_on_screen(self, parent: tk.Tk):
|
||||
"""
|
||||
Ensure a pop-up window is on the printable screen area.
|
||||
|
||||
:param self: The calling class instance of tk.TopLevel
|
||||
:param parent: The parent window
|
||||
"""
|
||||
# Ensure fully on-screen
|
||||
if sys.platform == 'win32' and CalculatePopupWindowPosition:
|
||||
position = RECT()
|
||||
win32gui.GetWindowRect(win32gui.GetParent(self.winfo_id()))
|
||||
if CalculatePopupWindowPosition(
|
||||
POINT(parent.winfo_rootx(), parent.winfo_rooty()),
|
||||
SIZE(position.right - position.left, position.bottom - position.top), # type: ignore
|
||||
0x10000, None, position
|
||||
):
|
||||
self.geometry(f"+{position.left}+{position.top}")
|
||||
|
||||
|
||||
def log_locale(prefix: str) -> None:
|
||||
"""Log all of the current local settings."""
|
||||
logger.debug(f'''Locale: {prefix}
|
||||
Locale LC_COLLATE: {locale.getlocale(locale.LC_COLLATE)}
|
||||
Locale LC_CTYPE: {locale.getlocale(locale.LC_CTYPE)}
|
||||
Locale LC_MONETARY: {locale.getlocale(locale.LC_MONETARY)}
|
||||
Locale LC_NUMERIC: {locale.getlocale(locale.LC_NUMERIC)}
|
||||
Locale LC_TIME: {locale.getlocale(locale.LC_TIME)}'''
|
||||
)
|
190
plugins/common_coreutils.py
Normal file
190
plugins/common_coreutils.py
Normal file
@ -0,0 +1,190 @@
|
||||
"""
|
||||
common_coreutils.py - Common Plugin Functions.
|
||||
|
||||
Copyright (c) EDCD, All Rights Reserved
|
||||
Licensed under the GNU General Public License.
|
||||
See LICENSE file.
|
||||
|
||||
This is an EDMC 'core' plugin.
|
||||
|
||||
All EDMC plugins are *dynamically* loaded at run-time.
|
||||
|
||||
We build for Windows using `py2exe`.
|
||||
`py2exe` can't possibly know about anything in the dynamically loaded core plugins.
|
||||
|
||||
Thus, you **MUST** check if any imports you add in this file are only
|
||||
referenced in this file (or only in any other core plugin), and if so...
|
||||
|
||||
YOU MUST ENSURE THAT PERTINENT ADJUSTMENTS ARE MADE IN
|
||||
`build.py` TO ENSURE THE FILES ARE ACTUALLY PRESENT
|
||||
IN AN END-USER INSTALLATION ON WINDOWS.
|
||||
"""
|
||||
# pylint: disable=import-error
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Mapping, cast
|
||||
import tkinter as tk
|
||||
import base64
|
||||
import gzip
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import myNotebook as nb # noqa: N813
|
||||
from EDMCLogging import get_main_logger
|
||||
from companion import CAPIData
|
||||
from l10n import translations as tr
|
||||
|
||||
logger = get_main_logger()
|
||||
if not os.getenv('EDMC_NO_UI'): # Functions using show_password_var MUST have TK set up
|
||||
show_password_var = tk.BooleanVar()
|
||||
|
||||
# Global Padding Preferences
|
||||
PADX = 10
|
||||
BUTTONX = 12 # indent Checkbuttons and Radiobuttons
|
||||
PADY = 1 # close spacing
|
||||
BOXY = 2 # box spacing
|
||||
SEPY = 10 # seperator line spacing
|
||||
STATION_UNDOCKED = '×' # "Station" name to display when not docked = U+00D7
|
||||
|
||||
|
||||
def plugin_start3(plugin_dir: str) -> str:
|
||||
"""
|
||||
Start the plugin.
|
||||
|
||||
:param plugin_dir: NAme of directory this was loaded from.
|
||||
:return: Identifier string for this plugin.
|
||||
"""
|
||||
return 'CommonCoreUtils'
|
||||
|
||||
|
||||
def api_keys_label_common(this, cur_row: int, frame: nb.Frame):
|
||||
"""
|
||||
Prepare the box for API Key Loading. This is an EDMC Common Function.
|
||||
|
||||
:param this: The module global from the calling module.
|
||||
:param cur_row: The current row in the calling module's config page.
|
||||
:param frame: The current frame in the calling module's config page.
|
||||
:return: The updated module global from the calling module.
|
||||
"""
|
||||
# LANG: EDSM API key label
|
||||
this.apikey_label = nb.Label(frame, text=tr.tl('API Key'))
|
||||
this.apikey_label.grid(row=cur_row, padx=PADX, pady=PADY, sticky=tk.W)
|
||||
this.apikey = nb.EntryMenu(frame, show="*", width=50)
|
||||
this.apikey.grid(row=cur_row, column=1, padx=PADX, pady=BOXY, sticky=tk.EW)
|
||||
return this
|
||||
|
||||
|
||||
def show_pwd_var_common(frame: nb.Frame, cur_row: int, this):
|
||||
"""
|
||||
Allow unmasking of the API Key. This is an EDMC Common Function.
|
||||
|
||||
:param cur_row: The current row in the calling module's config page.
|
||||
:param frame: The current frame in the calling module's config page.
|
||||
"""
|
||||
show_password_var.set(False) # Password is initially masked
|
||||
|
||||
show_password_checkbox = nb.Checkbutton(
|
||||
frame,
|
||||
text=tr.tl('Show API Key'), # LANG: Text EDSM Show API Key
|
||||
variable=show_password_var,
|
||||
command=lambda: toggle_password_visibility_common(this)
|
||||
)
|
||||
show_password_checkbox.grid(row=cur_row, columnspan=2, padx=BUTTONX, pady=PADY, sticky=tk.W)
|
||||
|
||||
|
||||
# Return a URL for the current ship
|
||||
def shipyard_url_common(loadout: Mapping[str, Any]) -> str:
|
||||
"""
|
||||
Construct a URL for ship loadout. This is an EDMC Common Function.
|
||||
|
||||
:param loadout: The ship loadout data.
|
||||
:return: The constructed URL for the ship loadout.
|
||||
"""
|
||||
# Convert loadout to JSON and gzip compress it
|
||||
string = json.dumps(loadout, ensure_ascii=False, sort_keys=True, separators=(',', ':')).encode('utf-8')
|
||||
if not string:
|
||||
return ''
|
||||
|
||||
out = io.BytesIO()
|
||||
with gzip.GzipFile(fileobj=out, mode='w') as f:
|
||||
f.write(string)
|
||||
|
||||
encoded_data = base64.urlsafe_b64encode(out.getvalue()).decode().replace('=', '%3D')
|
||||
return encoded_data
|
||||
|
||||
|
||||
def station_link_common(data: CAPIData, this):
|
||||
"""
|
||||
Set the Staion Name. This is an EDMC Common Function.
|
||||
|
||||
:param data: A CAPI Data Entry.
|
||||
:param this: The module global from the calling module.
|
||||
"""
|
||||
if data['commander']['docked'] or this.on_foot and this.station_name:
|
||||
this.station_link['text'] = this.station_name
|
||||
elif data['lastStarport']['name'] and data['lastStarport']['name'] != "":
|
||||
this.station_link['text'] = STATION_UNDOCKED
|
||||
else:
|
||||
this.station_link['text'] = ''
|
||||
|
||||
|
||||
def this_format_common(this, state: Mapping[str, Any]):
|
||||
"""
|
||||
Gather Common 'This' Elements. This is an EDMC Common Function.
|
||||
|
||||
:param this: The module global from the calling module.
|
||||
:param state: `monitor.state`.
|
||||
"""
|
||||
this.system_address = state['SystemAddress']
|
||||
this.system_name = state['SystemName']
|
||||
this.system_population = state['SystemPopulation']
|
||||
this.station_name = state['StationName']
|
||||
this.station_marketid = state['MarketID']
|
||||
this.station_type = state['StationType']
|
||||
this.on_foot = state['OnFoot']
|
||||
|
||||
|
||||
def toggle_password_visibility_common(this):
|
||||
"""
|
||||
Toggle if the API Key is visible or not. This is an EDMC Common Function.
|
||||
|
||||
:param this: The module global from the calling module.
|
||||
"""
|
||||
if show_password_var.get():
|
||||
this.apikey.config(show="") # type: ignore
|
||||
else:
|
||||
this.apikey.config(show="*") # type: ignore
|
||||
|
||||
|
||||
def station_name_setter_common(this):
|
||||
"""
|
||||
Set the Station Name. This is an EDMC Common Function.
|
||||
|
||||
:param this: The module global from the calling module.
|
||||
"""
|
||||
to_set: str = cast(str, this.station_name)
|
||||
if not to_set:
|
||||
if this.system_population is not None and this.system_population > 0:
|
||||
to_set = STATION_UNDOCKED
|
||||
else:
|
||||
to_set = ''
|
||||
|
||||
this.station_link['text'] = to_set
|
||||
|
||||
|
||||
def cmdr_data_initial_common(this, data: CAPIData):
|
||||
"""
|
||||
Set the common CMDR Data. This is an EDMC Common Function.
|
||||
|
||||
:param this: The module global from the calling module.
|
||||
:param data: The latest merged CAPI data.
|
||||
"""
|
||||
# Always store initially, even if we're not the *current* system provider.
|
||||
if not this.station_marketid and data['commander']['docked']:
|
||||
this.station_marketid = data['lastStarport']['id']
|
||||
|
||||
# Only trust CAPI if these aren't yet set
|
||||
if not this.system_name:
|
||||
this.system_name = data['lastSystem']['name']
|
||||
if not this.station_name and data['commander']['docked']:
|
||||
this.station_name = data['lastStarport']['name']
|
@ -19,12 +19,10 @@ referenced in this file (or only in any other core plugin), and if so...
|
||||
`build.py` TO ENSURE THE FILES ARE ACTUALLY PRESENT
|
||||
IN AN END-USER INSTALLATION ON WINDOWS.
|
||||
"""
|
||||
# pylint: disable=import-error
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
import gzip
|
||||
import io
|
||||
import json
|
||||
from typing import Any, Mapping
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
import myNotebook as nb # noqa: N813 # its not my fault.
|
||||
@ -32,6 +30,7 @@ from EDMCLogging import get_main_logger
|
||||
from plug import show_error
|
||||
from config import config
|
||||
from l10n import translations as tr
|
||||
from plugins.common_coreutils import PADX, PADY, BOXY, shipyard_url_common
|
||||
|
||||
|
||||
class CoriolisConfig:
|
||||
@ -82,10 +81,6 @@ def plugin_start3(path: str) -> str:
|
||||
|
||||
def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> nb.Frame:
|
||||
"""Set up plugin preferences."""
|
||||
PADX = 10 # noqa: N806
|
||||
PADY = 1 # noqa: N806
|
||||
BOXY = 2 # noqa: N806 # box spacing
|
||||
|
||||
# Save the old text values for the override mode, so we can update them if the language is changed
|
||||
coriolis_config.override_text_old_auto = tr.tl('Auto') # LANG: Coriolis normal/beta selection - auto
|
||||
coriolis_config.override_text_old_normal = tr.tl('Normal') # LANG: Coriolis normal/beta selection - normal
|
||||
@ -207,14 +202,14 @@ def _get_target_url(is_beta: bool) -> str:
|
||||
return coriolis_config.normal_url
|
||||
|
||||
|
||||
def shipyard_url(loadout, is_beta) -> str | bool:
|
||||
"""Return a URL for the current ship."""
|
||||
# most compact representation
|
||||
string = json.dumps(loadout, ensure_ascii=False, sort_keys=True, separators=(',', ':')).encode('utf-8')
|
||||
if not string:
|
||||
return False
|
||||
out = io.BytesIO()
|
||||
with gzip.GzipFile(fileobj=out, mode='w') as f:
|
||||
f.write(string)
|
||||
encoded = base64.urlsafe_b64encode(out.getvalue()).decode().replace('=', '%3D')
|
||||
return _get_target_url(is_beta) + encoded
|
||||
# Return a URL for the current ship
|
||||
def shipyard_url(loadout: Mapping[str, Any], is_beta: bool) -> bool | str:
|
||||
"""
|
||||
Construct a URL for ship loadout.
|
||||
|
||||
:param loadout: The ship loadout data.
|
||||
:param is_beta: Whether the game is in beta.
|
||||
:return: The constructed URL for the ship loadout.
|
||||
"""
|
||||
encoded_data = shipyard_url_common(loadout)
|
||||
return _get_target_url(is_beta) + encoded_data if encoded_data else False
|
||||
|
@ -18,6 +18,7 @@ referenced in this file (or only in any other core plugin), and if so...
|
||||
`build.py` TO ENSURE THE FILES ARE ACTUALLY PRESENT
|
||||
IN AN END-USER INSTALLATION ON WINDOWS.
|
||||
"""
|
||||
# pylint: disable=import-error
|
||||
from __future__ import annotations
|
||||
|
||||
import http
|
||||
@ -47,6 +48,7 @@ from prefs import prefsVersion
|
||||
from ttkHyperlinkLabel import HyperlinkLabel
|
||||
from util import text
|
||||
from l10n import translations as tr
|
||||
from plugins.common_coreutils import PADX, PADY, BUTTONX, this_format_common
|
||||
|
||||
logger = get_main_logger()
|
||||
|
||||
@ -2145,10 +2147,6 @@ def plugin_prefs(parent, cmdr: str, is_beta: bool) -> Frame:
|
||||
:param is_beta: `bool` - True if this is a beta version of the Game.
|
||||
:return: The tkinter frame we created.
|
||||
"""
|
||||
PADX = 10 # noqa: N806
|
||||
BUTTONX = 12 # noqa: N806 # indent Checkbuttons and Radiobuttons
|
||||
PADY = 1 # noqa: N806
|
||||
|
||||
if prefsVersion.shouldSetDefaults('0.0.0.0', not bool(config.get_int('output'))):
|
||||
output: int = config.OUT_EDDN_SEND_STATION_DATA | config.OUT_EDDN_SEND_NON_STATION # default settings
|
||||
|
||||
@ -2349,11 +2347,7 @@ def journal_entry( # noqa: C901, CCR001
|
||||
this.body_id = state['BodyID']
|
||||
this.body_type = state['BodyType']
|
||||
this.coordinates = state['StarPos']
|
||||
this.system_address = state['SystemAddress']
|
||||
this.system_name = state['SystemName']
|
||||
this.station_name = state['StationName']
|
||||
this.station_type = state['StationType']
|
||||
this.station_marketid = state['MarketID']
|
||||
this_format_common(this, state)
|
||||
|
||||
if event_name == 'docked':
|
||||
# Trigger a send/retry of pending EDDN messages
|
||||
|
@ -18,6 +18,7 @@ referenced in this file (or only in any other core plugin), and if so...
|
||||
`build.py` TO ENSURE THE FILES ARE ACTUALLY PRESENT
|
||||
IN AN END-USER INSTALLATION ON WINDOWS.
|
||||
"""
|
||||
# pylint: disable=import-error
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
@ -40,6 +41,9 @@ from edmc_data import DEBUG_WEBSERVER_HOST, DEBUG_WEBSERVER_PORT
|
||||
from EDMCLogging import get_main_logger
|
||||
from ttkHyperlinkLabel import HyperlinkLabel
|
||||
from l10n import translations as tr
|
||||
from plugins.common_coreutils import (api_keys_label_common, PADX, PADY, BUTTONX, SEPY, BOXY, STATION_UNDOCKED,
|
||||
show_pwd_var_common, station_link_common, this_format_common,
|
||||
cmdr_data_initial_common)
|
||||
|
||||
|
||||
# TODO:
|
||||
@ -118,9 +122,7 @@ class This:
|
||||
|
||||
|
||||
this = This()
|
||||
show_password_var = tk.BooleanVar()
|
||||
|
||||
STATION_UNDOCKED: str = '×' # "Station" name to display when not docked = U+00D7
|
||||
__cleanup = str.maketrans({' ': None, '\n': None})
|
||||
IMG_KNOWN_B64 = """
|
||||
R0lGODlhEAAQAMIEAFWjVVWkVWS/ZGfFZ////////////////yH5BAEKAAQALAAAAAAQABAAAAMvSLrc/lAFIUIkYOgNXt5g14Dk0AQlaC1CuglM6w7wgs7r
|
||||
@ -269,14 +271,6 @@ def plugin_stop() -> None:
|
||||
logger.debug('Done.')
|
||||
|
||||
|
||||
def toggle_password_visibility():
|
||||
"""Toggle if the API Key is visible or not."""
|
||||
if show_password_var.get():
|
||||
this.apikey.config(show="") # type: ignore
|
||||
else:
|
||||
this.apikey.config(show="*") # type: ignore
|
||||
|
||||
|
||||
def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> nb.Frame:
|
||||
"""
|
||||
Plugin preferences setup hook.
|
||||
@ -289,12 +283,6 @@ def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> nb.Fr
|
||||
:param is_beta: Whether game beta was detected.
|
||||
:return: An instance of `myNotebook.Frame`.
|
||||
"""
|
||||
PADX = 10 # noqa: N806
|
||||
BUTTONX = 12 # noqa: N806
|
||||
PADY = 1 # noqa: N806
|
||||
BOXY = 2 # noqa: N806
|
||||
SEPY = 10 # noqa: N806
|
||||
|
||||
frame = nb.Frame(parent)
|
||||
frame.columnconfigure(1, weight=1)
|
||||
|
||||
@ -349,23 +337,10 @@ def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> nb.Fr
|
||||
|
||||
cur_row += 1
|
||||
# LANG: EDSM API key label
|
||||
this.apikey_label = nb.Label(frame, text=tr.tl('API Key'))
|
||||
this.apikey_label.grid(row=cur_row, padx=PADX, pady=PADY, sticky=tk.W)
|
||||
this.apikey = nb.EntryMenu(frame, show="*", width=50)
|
||||
this.apikey.grid(row=cur_row, column=1, padx=PADX, pady=BOXY, sticky=tk.EW)
|
||||
api_keys_label_common(this, cur_row, frame)
|
||||
cur_row += 1
|
||||
|
||||
prefs_cmdr_changed(cmdr, is_beta)
|
||||
|
||||
show_password_var.set(False) # Password is initially masked
|
||||
|
||||
show_password_checkbox = nb.Checkbutton(
|
||||
frame,
|
||||
text=tr.tl('Show API Key'), # LANG: Text EDSM Show API Key
|
||||
variable=show_password_var,
|
||||
command=toggle_password_visibility
|
||||
)
|
||||
show_password_checkbox.grid(row=cur_row, columnspan=2, padx=BUTTONX, pady=PADY, sticky=tk.W)
|
||||
show_pwd_var_common(frame, cur_row, this)
|
||||
|
||||
return frame
|
||||
|
||||
@ -544,11 +519,7 @@ def journal_entry( # noqa: C901, CCR001
|
||||
|
||||
this.game_version = state['GameVersion']
|
||||
this.game_build = state['GameBuild']
|
||||
this.system_address = state['SystemAddress']
|
||||
this.system_name = state['SystemName']
|
||||
this.system_population = state['SystemPopulation']
|
||||
this.station_name = state['StationName']
|
||||
this.station_marketid = state['MarketID']
|
||||
this_format_common(this, state)
|
||||
|
||||
entry = new_entry
|
||||
|
||||
@ -658,7 +629,7 @@ Queueing: {entry!r}'''
|
||||
|
||||
|
||||
# Update system data
|
||||
def cmdr_data(data: CAPIData, is_beta: bool) -> str | None: # noqa: CCR001
|
||||
def cmdr_data(data: CAPIData, is_beta: bool) -> str | None:
|
||||
"""
|
||||
Process new CAPI data.
|
||||
|
||||
@ -668,14 +639,7 @@ def cmdr_data(data: CAPIData, is_beta: bool) -> str | None: # noqa: CCR001
|
||||
"""
|
||||
system = data['lastSystem']['name']
|
||||
|
||||
# Always store initially, even if we're not the *current* system provider.
|
||||
if not this.station_marketid and data['commander']['docked']:
|
||||
this.station_marketid = data['lastStarport']['id']
|
||||
# Only trust CAPI if these aren't yet set
|
||||
if not this.system_name:
|
||||
this.system_name = data['lastSystem']['name']
|
||||
if not this.station_name and data['commander']['docked']:
|
||||
this.station_name = data['lastStarport']['name']
|
||||
cmdr_data_initial_common(this, data)
|
||||
|
||||
# TODO: Fire off the EDSM API call to trigger the callback for the icons
|
||||
|
||||
@ -687,13 +651,7 @@ def cmdr_data(data: CAPIData, is_beta: bool) -> str | None: # noqa: CCR001
|
||||
this.system_link.update_idletasks()
|
||||
if config.get_str('station_provider') == 'EDSM':
|
||||
if this.station_link:
|
||||
if data['commander']['docked'] or this.on_foot and this.station_name:
|
||||
this.station_link['text'] = this.station_name
|
||||
elif data['lastStarport']['name'] and data['lastStarport']['name'] != "":
|
||||
this.station_link['text'] = STATION_UNDOCKED
|
||||
else:
|
||||
this.station_link['text'] = ''
|
||||
|
||||
station_link_common(data, this)
|
||||
# Do *NOT* set 'url' here, as it's set to a function that will call
|
||||
# through correctly. We don't want a static string.
|
||||
this.station_link.update_idletasks()
|
||||
|
@ -20,11 +20,8 @@ referenced in this file (or only in any other core plugin), and if so...
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
import gzip
|
||||
import io
|
||||
import json
|
||||
from typing import Any, Mapping
|
||||
from plugins.common_coreutils import shipyard_url_common # pylint: disable=E0401
|
||||
|
||||
|
||||
def plugin_start3(plugin_dir: str) -> str:
|
||||
@ -46,17 +43,7 @@ def shipyard_url(loadout: Mapping[str, Any], is_beta: bool) -> bool | str:
|
||||
:param is_beta: Whether the game is in beta.
|
||||
:return: The constructed URL for the ship loadout.
|
||||
"""
|
||||
# Convert loadout to JSON and gzip compress it
|
||||
string = json.dumps(loadout, ensure_ascii=False, sort_keys=True, separators=(',', ':')).encode('utf-8')
|
||||
if not string:
|
||||
return False
|
||||
|
||||
out = io.BytesIO()
|
||||
with gzip.GzipFile(fileobj=out, mode='w') as f:
|
||||
f.write(string)
|
||||
|
||||
encoded_data = shipyard_url_common(loadout)
|
||||
# Construct the URL using the appropriate base URL based on is_beta
|
||||
base_url = 'https://edsy.org/beta/#/I=' if is_beta else 'https://edsy.org/#/I='
|
||||
encoded_data = base64.urlsafe_b64encode(out.getvalue()).decode().replace('=', '%3D')
|
||||
|
||||
return base_url + encoded_data
|
||||
return base_url + encoded_data if encoded_data else False
|
||||
|
@ -18,6 +18,7 @@ referenced in this file (or only in any other core plugin), and if so...
|
||||
`build.py` TO ENSURE THE FILES ARE ACTUALLY PRESENT
|
||||
IN AN END-USER INSTALLATION ON WINDOWS.
|
||||
"""
|
||||
# pylint: disable=import-error
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
@ -43,6 +44,8 @@ from EDMCLogging import get_main_logger
|
||||
from monitor import monitor
|
||||
from ttkHyperlinkLabel import HyperlinkLabel
|
||||
from l10n import translations as tr
|
||||
from plugins.common_coreutils import (api_keys_label_common, PADX, PADY, BUTTONX, SEPY, station_name_setter_common,
|
||||
show_pwd_var_common, station_link_common, this_format_common)
|
||||
|
||||
logger = get_main_logger()
|
||||
|
||||
@ -115,7 +118,7 @@ class This:
|
||||
self.system_address: str | None = None # type: ignore
|
||||
self.system_population: int | None = None
|
||||
self.station_link: tk.Widget = None # type: ignore
|
||||
self.station = None
|
||||
self.station_name = None
|
||||
self.station_marketid = None
|
||||
|
||||
# Prefs UI
|
||||
@ -144,15 +147,12 @@ class This:
|
||||
|
||||
|
||||
this = This()
|
||||
show_password_var = tk.BooleanVar()
|
||||
|
||||
# last time we updated, if unset in config this is 0, which means an instant update
|
||||
LAST_UPDATE_CONF_KEY = 'inara_last_update'
|
||||
EVENT_COLLECT_TIME = 31 # Minimum time to take collecting events before requesting a send
|
||||
WORKER_WAIT_TIME = 35 # Minimum time for worker to wait between sends
|
||||
|
||||
STATION_UNDOCKED: str = '×' # "Station" name to display when not docked = U+00D7
|
||||
|
||||
|
||||
TARGET_URL = 'https://inara.cz/inapi/v1/'
|
||||
DEBUG = 'inara' in debug_senders
|
||||
@ -187,9 +187,9 @@ def station_url(system_name: str, station_name: str) -> str:
|
||||
if system_name and station_name:
|
||||
return requests.utils.requote_uri(f'https://inara.cz/galaxy-station/?search={system_name}%20[{station_name}]')
|
||||
|
||||
if this.system_name and this.station:
|
||||
if this.system_name and this.station_name:
|
||||
return requests.utils.requote_uri(
|
||||
f'https://inara.cz/galaxy-station/?search={this.system_name}%20[{this.station}]')
|
||||
f'https://inara.cz/galaxy-station/?search={this.system_name}%20[{this.station_name}]')
|
||||
|
||||
if system_name:
|
||||
return system_url(system_name)
|
||||
@ -233,21 +233,8 @@ def plugin_stop() -> None:
|
||||
logger.debug('Done.')
|
||||
|
||||
|
||||
def toggle_password_visibility():
|
||||
"""Toggle if the API Key is visible or not."""
|
||||
if show_password_var.get():
|
||||
this.apikey.config(show="")
|
||||
else:
|
||||
this.apikey.config(show="*")
|
||||
|
||||
|
||||
def plugin_prefs(parent: ttk.Notebook, cmdr: str, is_beta: bool) -> nb.Frame:
|
||||
"""Plugin Preferences UI hook."""
|
||||
PADX = 10 # noqa: N806
|
||||
BUTTONX = 12 # noqa: N806 # indent Checkbuttons and Radiobuttons
|
||||
PADY = 1 # noqa: N806 # close spacing
|
||||
BOXY = 2 # noqa: N806 # box spacing
|
||||
SEPY = 10 # noqa: N806 # seperator line spacing
|
||||
cur_row = 0
|
||||
|
||||
frame = nb.Frame(parent)
|
||||
@ -287,22 +274,10 @@ def plugin_prefs(parent: ttk.Notebook, cmdr: str, is_beta: bool) -> nb.Frame:
|
||||
cur_row += 1
|
||||
|
||||
# LANG: Inara API key label
|
||||
this.apikey_label = nb.Label(frame, text=tr.tl('API Key')) # Inara setting
|
||||
this.apikey_label.grid(row=cur_row, padx=PADX, pady=PADY, sticky=tk.W)
|
||||
this.apikey = nb.EntryMenu(frame, show="*", width=50)
|
||||
this.apikey.grid(row=cur_row, column=1, padx=PADX, pady=BOXY, sticky=tk.EW)
|
||||
api_keys_label_common(this, cur_row, frame)
|
||||
cur_row += 1
|
||||
|
||||
prefs_cmdr_changed(cmdr, is_beta)
|
||||
|
||||
show_password_var.set(False) # Password is initially masked
|
||||
show_password_checkbox = nb.Checkbutton(
|
||||
frame,
|
||||
text=tr.tl('Show API Key'), # LANG: Text Inara Show API key
|
||||
variable=show_password_var,
|
||||
command=toggle_password_visibility,
|
||||
)
|
||||
show_password_checkbox.grid(row=cur_row, columnspan=2, padx=BUTTONX, pady=PADY, sticky=tk.W)
|
||||
show_pwd_var_common(frame, cur_row, this)
|
||||
|
||||
return frame
|
||||
|
||||
@ -411,15 +386,11 @@ def journal_entry( # noqa: C901, CCR001
|
||||
# But then we update all the tracking copies before any other checks,
|
||||
# because they're relevant for URL providing even if *sending* isn't
|
||||
# appropriate.
|
||||
this.on_foot = state['OnFoot']
|
||||
event_name: str = entry['event']
|
||||
this.cmdr = cmdr
|
||||
this.FID = state['FID']
|
||||
this.multicrew = bool(state['Role'])
|
||||
this.system_name = state['SystemName']
|
||||
this.system_address = state['SystemAddress']
|
||||
this.station = state['StationName']
|
||||
this.station_marketid = state['MarketID']
|
||||
this_format_common(this, state)
|
||||
|
||||
if not monitor.is_live_galaxy():
|
||||
# Since Update 14 on 2022-11-29 Inara only accepts Live data.
|
||||
@ -613,7 +584,7 @@ def journal_entry( # noqa: C901, CCR001
|
||||
|
||||
elif event_name == 'Undocked':
|
||||
this.undocked = True
|
||||
this.station = None
|
||||
this.station_name = None
|
||||
|
||||
elif event_name == 'SupercruiseEntry':
|
||||
this.undocked = False
|
||||
@ -1368,14 +1339,7 @@ def journal_entry( # noqa: C901, CCR001
|
||||
this.system_link.update_idletasks()
|
||||
|
||||
if config.get_str('station_provider') == 'Inara':
|
||||
to_set: str = cast(str, this.station)
|
||||
if not to_set:
|
||||
if this.system_population is not None and this.system_population > 0:
|
||||
to_set = STATION_UNDOCKED
|
||||
else:
|
||||
to_set = ''
|
||||
|
||||
this.station_link['text'] = to_set
|
||||
station_name_setter_common(this)
|
||||
# Do *NOT* set 'url' here, as it's set to a function that will call
|
||||
# through correctly. We don't want a static string.
|
||||
this.station_link.update_idletasks()
|
||||
@ -1383,7 +1347,7 @@ def journal_entry( # noqa: C901, CCR001
|
||||
return '' # No error
|
||||
|
||||
|
||||
def cmdr_data(data: CAPIData, is_beta): # noqa: CCR001, reanalyze me later
|
||||
def cmdr_data(data: CAPIData, is_beta):
|
||||
"""CAPI event hook."""
|
||||
this.cmdr = data['commander']['name']
|
||||
|
||||
@ -1394,8 +1358,8 @@ def cmdr_data(data: CAPIData, is_beta): # noqa: CCR001, reanalyze me later
|
||||
# Only trust CAPI if these aren't yet set
|
||||
this.system_name = this.system_name if this.system_name else data['lastSystem']['name']
|
||||
|
||||
if not this.station and data['commander']['docked']:
|
||||
this.station = data['lastStarport']['name']
|
||||
if not this.station_name and data['commander']['docked']:
|
||||
this.station_name = data['lastStarport']['name']
|
||||
|
||||
# Override standard URL functions
|
||||
if config.get_str('system_provider') == 'Inara':
|
||||
@ -1405,14 +1369,7 @@ def cmdr_data(data: CAPIData, is_beta): # noqa: CCR001, reanalyze me later
|
||||
this.system_link.update_idletasks()
|
||||
|
||||
if config.get_str('station_provider') == 'Inara':
|
||||
if data['commander']['docked'] or this.on_foot and this.station:
|
||||
this.station_link['text'] = this.station
|
||||
|
||||
elif data['lastStarport']['name'] and data['lastStarport']['name'] != "":
|
||||
this.station_link['text'] = STATION_UNDOCKED
|
||||
|
||||
else:
|
||||
this.station_link['text'] = ''
|
||||
station_link_common(data, this)
|
||||
|
||||
# Do *NOT* set 'url' here, as it's set to a function that will call
|
||||
# through correctly. We don't want a static string.
|
||||
|
@ -18,14 +18,17 @@ referenced in this file (or only in any other core plugin), and if so...
|
||||
`build.py` TO ENSURE THE FILES ARE ACTUALLY PRESENT
|
||||
IN AN END-USER INSTALLATION ON WINDOWS.
|
||||
"""
|
||||
# pylint: disable=import-error
|
||||
from __future__ import annotations
|
||||
|
||||
import tkinter as tk
|
||||
from typing import Any, cast
|
||||
from typing import Any
|
||||
import requests
|
||||
from companion import CAPIData
|
||||
from config import appname, config
|
||||
from EDMCLogging import get_main_logger
|
||||
from plugins.common_coreutils import (station_link_common, this_format_common,
|
||||
cmdr_data_initial_common, station_name_setter_common)
|
||||
|
||||
logger = get_main_logger()
|
||||
|
||||
@ -47,7 +50,6 @@ class This:
|
||||
|
||||
|
||||
this = This()
|
||||
STATION_UNDOCKED: str = '×' # "Station" name to display when not docked = U+00D7
|
||||
|
||||
|
||||
def plugin_start3(plugin_dir: str) -> str:
|
||||
@ -91,12 +93,7 @@ def journal_entry(
|
||||
:param state: `monitor.state`
|
||||
:return: None if no error, else an error string.
|
||||
"""
|
||||
this.on_foot = state['OnFoot']
|
||||
this.system_address = state['SystemAddress']
|
||||
this.system_name = state['SystemName']
|
||||
this.system_population = state['SystemPopulation']
|
||||
this.station_name = state['StationName']
|
||||
this.station_marketid = state['MarketID']
|
||||
this_format_common(this, state)
|
||||
|
||||
# Only actually change URLs if we are current provider.
|
||||
if config.get_str('system_provider') == 'spansh':
|
||||
@ -106,14 +103,7 @@ def journal_entry(
|
||||
this.system_link.update_idletasks()
|
||||
|
||||
if config.get_str('station_provider') == 'spansh':
|
||||
to_set: str = cast(str, this.station_name)
|
||||
if not to_set:
|
||||
if this.system_population is not None and this.system_population > 0:
|
||||
to_set = STATION_UNDOCKED
|
||||
else:
|
||||
to_set = ''
|
||||
|
||||
this.station_link['text'] = to_set
|
||||
station_name_setter_common(this)
|
||||
# Do *NOT* set 'url' here, as it's set to a function that will call
|
||||
# through correctly. We don't want a static string.
|
||||
this.station_link.update_idletasks()
|
||||
@ -129,15 +119,7 @@ def cmdr_data(data: CAPIData, is_beta: bool) -> str | None:
|
||||
:param is_beta: Whether game beta was detected.
|
||||
:return: Optional error string.
|
||||
"""
|
||||
# Always store initially, even if we're not the *current* system provider.
|
||||
if not this.station_marketid and data['commander']['docked']:
|
||||
this.station_marketid = data['lastStarport']['id']
|
||||
|
||||
# Only trust CAPI if these aren't yet set
|
||||
if not this.system_name:
|
||||
this.system_name = data['lastSystem']['name']
|
||||
if not this.station_name and data['commander']['docked']:
|
||||
this.station_name = data['lastStarport']['name']
|
||||
cmdr_data_initial_common(this, data)
|
||||
|
||||
# Override standard URL functions
|
||||
if config.get_str('system_provider') == 'spansh':
|
||||
@ -146,12 +128,7 @@ def cmdr_data(data: CAPIData, is_beta: bool) -> str | None:
|
||||
# through correctly. We don't want a static string.
|
||||
this.system_link.update_idletasks()
|
||||
if config.get_str('station_provider') == 'spansh':
|
||||
if data['commander']['docked'] or this.on_foot and this.station_name:
|
||||
this.station_link['text'] = this.station_name
|
||||
elif data['lastStarport']['name'] and data['lastStarport']['name'] != "":
|
||||
this.station_link['text'] = STATION_UNDOCKED
|
||||
else:
|
||||
this.station_link['text'] = ''
|
||||
station_link_common(data, this)
|
||||
# Do *NOT* set 'url' here, as it's set to a function that will call
|
||||
# through correctly. We don't want a static string.
|
||||
this.station_link.update_idletasks()
|
||||
|
19
prefs.py
19
prefs.py
@ -24,6 +24,7 @@ from l10n import translations as tr
|
||||
from monitor import monitor
|
||||
from theme import theme
|
||||
from ttkHyperlinkLabel import HyperlinkLabel
|
||||
from common_utils import ensure_on_screen
|
||||
logger = get_main_logger()
|
||||
|
||||
|
||||
@ -187,7 +188,6 @@ if sys.platform == 'win32':
|
||||
import ctypes
|
||||
import winreg
|
||||
from ctypes.wintypes import LPCWSTR, LPWSTR, MAX_PATH, POINT, RECT, SIZE, UINT, BOOL
|
||||
import win32gui
|
||||
import win32api
|
||||
is_wine = False
|
||||
try:
|
||||
@ -307,15 +307,7 @@ class PreferencesDialog(tk.Toplevel):
|
||||
self.grab_set()
|
||||
|
||||
# Ensure fully on-screen
|
||||
if sys.platform == 'win32' and CalculatePopupWindowPosition:
|
||||
position = RECT()
|
||||
win32gui.GetWindowRect(win32gui.GetParent(self.winfo_id()))
|
||||
if CalculatePopupWindowPosition(
|
||||
POINT(parent.winfo_rootx(), parent.winfo_rooty()),
|
||||
SIZE(position.right - position.left, position.bottom - position.top), # type: ignore
|
||||
0x10000, None, position
|
||||
):
|
||||
self.geometry(f"+{position.left}+{position.top}")
|
||||
ensure_on_screen(self, parent)
|
||||
|
||||
# Set Log Directory
|
||||
self.logfile_loc = Path(config.app_dir_path / 'logs')
|
||||
@ -829,7 +821,8 @@ class PreferencesDialog(tk.Toplevel):
|
||||
appearance_frame,
|
||||
# LANG: Appearance - Help/hint text for UI scaling selection
|
||||
text=tr.tl('100 means Default{CR}Restart Required for{CR}changes to take effect!')
|
||||
).grid(column=3, padx=self.PADX, pady=self.PADY, sticky=tk.E, row=cur_row)
|
||||
) # E1111
|
||||
self.ui_scaling_defaultis.grid(column=3, padx=self.PADX, pady=self.PADY, sticky=tk.E, row=cur_row)
|
||||
|
||||
# Transparency slider
|
||||
ttk.Separator(appearance_frame, orient=tk.HORIZONTAL).grid(
|
||||
@ -1308,10 +1301,10 @@ class PreferencesDialog(tk.Toplevel):
|
||||
self._destroy()
|
||||
# Send to the Post Config if we updated the update branch or need to restart
|
||||
post_flags = {
|
||||
'Update': True if self.curr_update_track != self.update_paths.get() else False,
|
||||
'Update': self.curr_update_track != self.update_paths.get(), # Just needs bool not true if else false
|
||||
'Track': self.update_paths.get(),
|
||||
'Parent': self,
|
||||
'Restart_Req': True if self.req_restart else False
|
||||
'Restart_Req': self.req_restart # Sipmle Bool Needed
|
||||
}
|
||||
if self.callback:
|
||||
self.callback(**post_flags)
|
||||
|
@ -64,9 +64,19 @@ COMMENT_SAME_LINE_RE = re.compile(r"^.*?(#.*)$")
|
||||
COMMENT_OWN_LINE_RE = re.compile(r"^\s*?(#.*)$")
|
||||
|
||||
|
||||
def extract_comments( # noqa: CCR001
|
||||
call: ast.Call, lines: list[str], file: pathlib.Path
|
||||
) -> str | None:
|
||||
def _extract_lang_comment(line: str, pattern: re.Pattern, file: pathlib.Path,
|
||||
lineno: int) -> tuple[str | None, str | None]:
|
||||
"""Attempt to extract a LANG comment from a line using a given regex pattern."""
|
||||
match = pattern.match(line)
|
||||
if match:
|
||||
comment = match.group(1).strip()
|
||||
if comment.startswith("# LANG:"):
|
||||
return comment.replace("# LANG:", "").strip(), None
|
||||
return None, f"Unknown comment for {file}:{lineno} {line}"
|
||||
return None, None
|
||||
|
||||
|
||||
def extract_comments(call: ast.Call, lines: list[str], file: pathlib.Path) -> str | None:
|
||||
"""
|
||||
Extract comments from source code based on the given call.
|
||||
|
||||
@ -86,29 +96,13 @@ def extract_comments( # noqa: CCR001
|
||||
above_comment: str | None = None
|
||||
current_line = lines[current].strip()
|
||||
current_comment: str | None = None
|
||||
|
||||
bad_comment: str | None = None
|
||||
if above_line is not None:
|
||||
match = COMMENT_OWN_LINE_RE.match(above_line)
|
||||
if match:
|
||||
above_comment = match.group(1).strip()
|
||||
if not above_comment.startswith("# LANG:"):
|
||||
bad_comment = f"Unknown comment for {file}:{call.lineno} {above_line}"
|
||||
above_comment = None
|
||||
|
||||
else:
|
||||
above_comment = above_comment.replace("# LANG:", "").strip()
|
||||
if above_line:
|
||||
above_comment, bad_comment = _extract_lang_comment(above_line, COMMENT_OWN_LINE_RE, file, call.lineno)
|
||||
|
||||
if current_line is not None:
|
||||
match = COMMENT_SAME_LINE_RE.match(current_line)
|
||||
if match:
|
||||
current_comment = match.group(1).strip()
|
||||
if not current_comment.startswith("# LANG:"):
|
||||
bad_comment = f"Unknown comment for {file}:{call.lineno} {current_line}"
|
||||
current_comment = None
|
||||
|
||||
else:
|
||||
current_comment = current_comment.replace("# LANG:", "").strip()
|
||||
if current_line:
|
||||
current_comment, bad_comment = _extract_lang_comment(current_line, COMMENT_SAME_LINE_RE, file, call.lineno)
|
||||
|
||||
if current_comment is not None:
|
||||
out = current_comment
|
||||
|
28
stats.py
28
stats.py
@ -20,25 +20,10 @@ from edmc_data import ship_name_map
|
||||
from hotkey import hotkeymgr
|
||||
from l10n import Locale, translations as tr
|
||||
from monitor import monitor
|
||||
from common_utils import ensure_on_screen
|
||||
|
||||
logger = EDMCLogging.get_main_logger()
|
||||
|
||||
if sys.platform == 'win32':
|
||||
import ctypes
|
||||
from ctypes.wintypes import POINT, RECT, SIZE, UINT, BOOL
|
||||
import win32gui
|
||||
|
||||
try:
|
||||
CalculatePopupWindowPosition = ctypes.windll.user32.CalculatePopupWindowPosition
|
||||
CalculatePopupWindowPosition.argtypes = [
|
||||
ctypes.POINTER(POINT), ctypes.POINTER(SIZE), UINT, ctypes.POINTER(RECT), ctypes.POINTER(RECT)
|
||||
]
|
||||
CalculatePopupWindowPosition.restype = BOOL
|
||||
|
||||
except Exception: # Not supported under Wine 4.0
|
||||
CalculatePopupWindowPosition = None # type: ignore
|
||||
|
||||
|
||||
CR_LINES_START = 1
|
||||
CR_LINES_END = 3
|
||||
RANK_LINES_START = 3
|
||||
@ -418,16 +403,7 @@ class StatsResults(tk.Toplevel):
|
||||
self.grab_set()
|
||||
|
||||
# Ensure fully on-screen
|
||||
if sys.platform == 'win32' and CalculatePopupWindowPosition:
|
||||
position = RECT()
|
||||
win32gui.GetWindowRect(win32gui.GetParent(self.winfo_id()))
|
||||
if CalculatePopupWindowPosition(
|
||||
POINT(parent.winfo_rootx(), parent.winfo_rooty()),
|
||||
# - is evidently supported on the C side
|
||||
SIZE(position.right - position.left, position.bottom - position.top), # type: ignore
|
||||
0x10000, None, position
|
||||
):
|
||||
self.geometry(f"+{position.left}+{position.top}")
|
||||
ensure_on_screen(self, parent)
|
||||
|
||||
def addpage(
|
||||
self, parent, header: list[str] | None = None, align: str | None = None
|
||||
|
Loading…
x
Reference in New Issue
Block a user