mirror of
https://github.com/EDCD/EDMarketConnector.git
synced 2025-05-02 08:21:31 +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 argparse
|
||||||
import json
|
import json
|
||||||
import locale
|
|
||||||
import os
|
import os
|
||||||
import queue
|
import queue
|
||||||
import sys
|
import sys
|
||||||
from time import sleep, time
|
from time import sleep, time
|
||||||
from typing import TYPE_CHECKING, Any
|
from typing import TYPE_CHECKING, Any
|
||||||
|
from common_utils import log_locale, SERVER_RETRY
|
||||||
|
|
||||||
# isort: off
|
# isort: off
|
||||||
os.environ["EDMC_NO_UI"] = "1"
|
os.environ["EDMC_NO_UI"] = "1"
|
||||||
@ -52,31 +52,12 @@ import eddn # noqa: E402
|
|||||||
|
|
||||||
|
|
||||||
# isort: on
|
# 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()
|
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_SUCCESS, EXIT_SERVER, EXIT_CREDENTIALS, EXIT_VERIFICATION, EXIT_LAGGING, EXIT_SYS_ERR, EXIT_ARGS, \
|
||||||
EXIT_JOURNAL_READ_ERR, EXIT_COMMANDER_UNKNOWN = range(9)
|
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:
|
def deep_get(target: dict | companion.CAPIData, *args: str, default=None) -> Any:
|
||||||
"""
|
"""
|
||||||
Walk into a dict and return the specified deep value.
|
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
|
return current
|
||||||
|
|
||||||
|
|
||||||
def main(): # noqa: C901, CCR001
|
def main() -> None: # noqa: C901, CCR001
|
||||||
"""Run the main code of the program."""
|
"""Run the main code of the program."""
|
||||||
try:
|
try:
|
||||||
# arg parsing
|
# 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>
|
# <https://stackoverflow.com/questions/2203424/python-how-to-retrieve-class-information-from-a-frame-object#2220759>
|
||||||
try:
|
try:
|
||||||
frame_info = inspect.getframeinfo(frame)
|
frame_info = inspect.getframeinfo(frame)
|
||||||
# raise(IndexError) # TODO: Remove, only for testing
|
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
# Separate from the print below to guarantee we see at least this much.
|
# Separate from the print below to guarantee we see at least this much.
|
||||||
print('EDMCLogging:EDMCContextFilter:caller_attributes(): Failed in `inspect.getframinfo(frame)`')
|
print('EDMCLogging:EDMCContextFilter:caller_attributes(): Failed in `inspect.getframinfo(frame)`')
|
||||||
|
@ -38,17 +38,17 @@ from monitor import monitor
|
|||||||
from EDMCLogging import get_main_logger
|
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."""
|
"""Gather system information about Elite, the Host Computer, and EDMC."""
|
||||||
# Calculate Requested Information
|
# Calculate Requested Information
|
||||||
plt = platform.uname()
|
plt = platform.uname()
|
||||||
locale.setlocale(locale.LC_ALL, "")
|
locale.setlocale(locale.LC_ALL, "")
|
||||||
lcl = locale.getlocale()
|
lcl = locale.getlocale()
|
||||||
monitor.currentdir = config.get_str(
|
monitor.currentdir = active_config.get_str(
|
||||||
"journaldir", default=config.default_journal_dir
|
"journaldir", default=active_config.default_journal_dir
|
||||||
)
|
)
|
||||||
if not monitor.currentdir:
|
if not monitor.currentdir:
|
||||||
monitor.currentdir = config.default_journal_dir
|
monitor.currentdir = active_config.default_journal_dir
|
||||||
try:
|
try:
|
||||||
logfile = monitor.journal_newest_filename(monitor.currentdir)
|
logfile = monitor.journal_newest_filename(monitor.currentdir)
|
||||||
if logfile is None:
|
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)
|
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."""
|
"""Entry Point for the System Profiler."""
|
||||||
# Now Let's Begin
|
# Now Let's Begin
|
||||||
root: tk.Tk = tk.Tk()
|
root: tk.Tk = tk.Tk()
|
||||||
root.withdraw() # Hide the window initially to calculate the dimensions
|
root.withdraw() # Hide the window initially to calculate the dimensions
|
||||||
try:
|
try:
|
||||||
icon_image = tk.PhotoImage(
|
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)
|
root.iconphoto(True, icon_image)
|
||||||
except tk.TclError:
|
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
|
# Set up styling
|
||||||
style = ttk.Style(root)
|
style = ttk.Style(root)
|
||||||
@ -182,7 +182,8 @@ if __name__ == "__main__":
|
|||||||
# Args: Only work if not frozen
|
# Args: Only work if not frozen
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
prog=appname,
|
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(
|
parser.add_argument(
|
||||||
"--out-console",
|
"--out-console",
|
||||||
@ -203,4 +204,4 @@ if __name__ == "__main__":
|
|||||||
print(sys_report)
|
print(sys_report)
|
||||||
sys.exit(0)
|
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 EDMCLogging import edmclogger, logger, logging
|
||||||
from journal_lock import JournalLock, JournalLockResult
|
from journal_lock import JournalLock, JournalLockResult
|
||||||
from update import check_for_fdev_updates
|
from update import check_for_fdev_updates
|
||||||
|
from common_utils import log_locale, SERVER_RETRY
|
||||||
|
|
||||||
if __name__ == '__main__': # noqa: C901
|
if __name__ == '__main__': # noqa: C901
|
||||||
# Command-line arguments
|
# Command-line arguments
|
||||||
@ -416,8 +417,6 @@ from monitor import monitor
|
|||||||
from theme import theme
|
from theme import theme
|
||||||
from ttkHyperlinkLabel import HyperlinkLabel, SHIPYARD_HTML_TEMPLATE
|
from ttkHyperlinkLabel import HyperlinkLabel, SHIPYARD_HTML_TEMPLATE
|
||||||
|
|
||||||
SERVER_RETRY = 5 # retry pause for Companion servers [s]
|
|
||||||
|
|
||||||
|
|
||||||
class AppWindow:
|
class AppWindow:
|
||||||
"""Define the main application window."""
|
"""Define the main application window."""
|
||||||
@ -837,8 +836,7 @@ class AppWindow:
|
|||||||
r' if downgrading between major versions with significant changes.\r\n\r\n'
|
r' if downgrading between major versions with significant changes.\r\n\r\n'
|
||||||
'Do you want to open GitHub to download the latest release?'
|
'Do you want to open GitHub to download the latest release?'
|
||||||
)
|
)
|
||||||
update_msg = update_msg.replace('\\n', '\n')
|
update_msg = update_msg.replace('\\n', '\n').replace('\\r', '\r')
|
||||||
update_msg = update_msg.replace('\\r', '\r')
|
|
||||||
stable_popup = tk.messagebox.askyesno(title=title, message=update_msg)
|
stable_popup = tk.messagebox.askyesno(title=title, message=update_msg)
|
||||||
if stable_popup:
|
if stable_popup:
|
||||||
webbrowser.open("https://github.com/EDCD/eDMarketConnector/releases/latest")
|
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()')
|
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):
|
def setup_killswitches(filename: str | None):
|
||||||
"""Download and setup the main killswitch list."""
|
"""Download and setup the main killswitch list."""
|
||||||
logger.debug('fetching killswitches...')
|
logger.debug('fetching killswitches...')
|
||||||
@ -2061,17 +2048,15 @@ def validate_providers():
|
|||||||
|
|
||||||
# LANG: Popup-text about Reset 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')
|
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
|
# 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 += tr.tl(r'{PROVIDER} was set to {OLDPROV}, and has been reset to {NEWPROV}\r\n').format(
|
||||||
popup_text = popup_text.format(
|
|
||||||
PROVIDER=provider,
|
PROVIDER=provider,
|
||||||
OLDPROV=reset_providers[provider][0],
|
OLDPROV=old_prov,
|
||||||
NEWPROV=reset_providers[provider][1]
|
NEWPROV=new_prov
|
||||||
)
|
)
|
||||||
# And now we do need these to be actual \r\n
|
# And now we do need these to be actual \r\n
|
||||||
popup_text = popup_text.replace('\\n', '\n')
|
popup_text = popup_text.replace('\\n', '\n').replace('\\r', '\r')
|
||||||
popup_text = popup_text.replace('\\r', '\r')
|
|
||||||
|
|
||||||
tk.messagebox.showinfo(
|
tk.messagebox.showinfo(
|
||||||
# LANG: Popup window title for Reset Providers
|
# LANG: Popup window title for Reset Providers
|
||||||
@ -2243,8 +2228,7 @@ sys.path: {sys.path}'''
|
|||||||
detail = tr.tl( # LANG: EDMC Critical Error Details
|
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?"
|
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)
|
).format(ERR=err)
|
||||||
detail = detail.replace('\\n', '\n')
|
detail = detail.replace('\\n', '\n').replace('\\r', '\r')
|
||||||
detail = detail.replace('\\r', '\r')
|
|
||||||
msg = tk.messagebox.askyesno(
|
msg = tk.messagebox.askyesno(
|
||||||
title=title, message=message, detail=detail, icon=tkinter.messagebox.ERROR, type=tkinter.messagebox.YESNO,
|
title=title, message=message, detail=detail, icon=tkinter.messagebox.ERROR, type=tkinter.messagebox.YESNO,
|
||||||
parent=root
|
parent=root
|
||||||
@ -2275,8 +2259,7 @@ sys.path: {sys.path}'''
|
|||||||
DISABLED='.disabled'
|
DISABLED='.disabled'
|
||||||
)
|
)
|
||||||
# And now we do need these to be actual \r\n
|
# And now we do need these to be actual \r\n
|
||||||
popup_text = popup_text.replace('\\n', '\n')
|
popup_text = popup_text.replace('\\n', '\n').replace('\\r', '\r')
|
||||||
popup_text = popup_text.replace('\\r', '\r')
|
|
||||||
|
|
||||||
tk.messagebox.showinfo(
|
tk.messagebox.showinfo(
|
||||||
# LANG: Popup window title for list of 'broken' plugins that failed to load
|
# LANG: Popup window title for list of 'broken' plugins that failed to load
|
||||||
@ -2306,8 +2289,7 @@ sys.path: {sys.path}'''
|
|||||||
DISABLED='.disabled'
|
DISABLED='.disabled'
|
||||||
)
|
)
|
||||||
# And now we do need these to be actual \r\n
|
# And now we do need these to be actual \r\n
|
||||||
popup_text = popup_text.replace('\\n', '\n')
|
popup_text = popup_text.replace('\\n', '\n').replace('\\r', '\r')
|
||||||
popup_text = popup_text.replace('\\r', '\r')
|
|
||||||
|
|
||||||
tk.messagebox.showinfo(
|
tk.messagebox.showinfo(
|
||||||
# LANG: Popup window title for list of 'enabled' plugins that don't work with Python 3.x
|
# 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.
|
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
|
## Logging
|
||||||
|
1
build.py
1
build.py
@ -121,6 +121,7 @@ def build() -> None:
|
|||||||
"plugins/edsy.py",
|
"plugins/edsy.py",
|
||||||
"plugins/inara.py",
|
"plugins/inara.py",
|
||||||
"plugins/spansh_core.py",
|
"plugins/spansh_core.py",
|
||||||
|
"plugins/common_coreutils.py"
|
||||||
]
|
]
|
||||||
options: dict = {
|
options: dict = {
|
||||||
"py2exe": {
|
"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
|
`build.py` TO ENSURE THE FILES ARE ACTUALLY PRESENT
|
||||||
IN AN END-USER INSTALLATION ON WINDOWS.
|
IN AN END-USER INSTALLATION ON WINDOWS.
|
||||||
"""
|
"""
|
||||||
|
# pylint: disable=import-error
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import base64
|
from typing import Any, Mapping
|
||||||
import gzip
|
|
||||||
import io
|
|
||||||
import json
|
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import ttk
|
from tkinter import ttk
|
||||||
import myNotebook as nb # noqa: N813 # its not my fault.
|
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 plug import show_error
|
||||||
from config import config
|
from config import config
|
||||||
from l10n import translations as tr
|
from l10n import translations as tr
|
||||||
|
from plugins.common_coreutils import PADX, PADY, BOXY, shipyard_url_common
|
||||||
|
|
||||||
|
|
||||||
class CoriolisConfig:
|
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:
|
def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> nb.Frame:
|
||||||
"""Set up plugin preferences."""
|
"""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
|
# 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_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
|
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
|
return coriolis_config.normal_url
|
||||||
|
|
||||||
|
|
||||||
def shipyard_url(loadout, is_beta) -> str | bool:
|
# Return a URL for the current ship
|
||||||
"""Return a URL for the current ship."""
|
def shipyard_url(loadout: Mapping[str, Any], is_beta: bool) -> bool | str:
|
||||||
# most compact representation
|
"""
|
||||||
string = json.dumps(loadout, ensure_ascii=False, sort_keys=True, separators=(',', ':')).encode('utf-8')
|
Construct a URL for ship loadout.
|
||||||
if not string:
|
|
||||||
return False
|
:param loadout: The ship loadout data.
|
||||||
out = io.BytesIO()
|
:param is_beta: Whether the game is in beta.
|
||||||
with gzip.GzipFile(fileobj=out, mode='w') as f:
|
:return: The constructed URL for the ship loadout.
|
||||||
f.write(string)
|
"""
|
||||||
encoded = base64.urlsafe_b64encode(out.getvalue()).decode().replace('=', '%3D')
|
encoded_data = shipyard_url_common(loadout)
|
||||||
return _get_target_url(is_beta) + encoded
|
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
|
`build.py` TO ENSURE THE FILES ARE ACTUALLY PRESENT
|
||||||
IN AN END-USER INSTALLATION ON WINDOWS.
|
IN AN END-USER INSTALLATION ON WINDOWS.
|
||||||
"""
|
"""
|
||||||
|
# pylint: disable=import-error
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import http
|
import http
|
||||||
@ -47,6 +48,7 @@ from prefs import prefsVersion
|
|||||||
from ttkHyperlinkLabel import HyperlinkLabel
|
from ttkHyperlinkLabel import HyperlinkLabel
|
||||||
from util import text
|
from util import text
|
||||||
from l10n import translations as tr
|
from l10n import translations as tr
|
||||||
|
from plugins.common_coreutils import PADX, PADY, BUTTONX, this_format_common
|
||||||
|
|
||||||
logger = get_main_logger()
|
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.
|
:param is_beta: `bool` - True if this is a beta version of the Game.
|
||||||
:return: The tkinter frame we created.
|
: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'))):
|
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
|
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_id = state['BodyID']
|
||||||
this.body_type = state['BodyType']
|
this.body_type = state['BodyType']
|
||||||
this.coordinates = state['StarPos']
|
this.coordinates = state['StarPos']
|
||||||
this.system_address = state['SystemAddress']
|
this_format_common(this, state)
|
||||||
this.system_name = state['SystemName']
|
|
||||||
this.station_name = state['StationName']
|
|
||||||
this.station_type = state['StationType']
|
|
||||||
this.station_marketid = state['MarketID']
|
|
||||||
|
|
||||||
if event_name == 'docked':
|
if event_name == 'docked':
|
||||||
# Trigger a send/retry of pending EDDN messages
|
# 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
|
`build.py` TO ENSURE THE FILES ARE ACTUALLY PRESENT
|
||||||
IN AN END-USER INSTALLATION ON WINDOWS.
|
IN AN END-USER INSTALLATION ON WINDOWS.
|
||||||
"""
|
"""
|
||||||
|
# pylint: disable=import-error
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
@ -40,6 +41,9 @@ from edmc_data import DEBUG_WEBSERVER_HOST, DEBUG_WEBSERVER_PORT
|
|||||||
from EDMCLogging import get_main_logger
|
from EDMCLogging import get_main_logger
|
||||||
from ttkHyperlinkLabel import HyperlinkLabel
|
from ttkHyperlinkLabel import HyperlinkLabel
|
||||||
from l10n import translations as tr
|
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:
|
# TODO:
|
||||||
@ -118,9 +122,7 @@ class This:
|
|||||||
|
|
||||||
|
|
||||||
this = 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})
|
__cleanup = str.maketrans({' ': None, '\n': None})
|
||||||
IMG_KNOWN_B64 = """
|
IMG_KNOWN_B64 = """
|
||||||
R0lGODlhEAAQAMIEAFWjVVWkVWS/ZGfFZ////////////////yH5BAEKAAQALAAAAAAQABAAAAMvSLrc/lAFIUIkYOgNXt5g14Dk0AQlaC1CuglM6w7wgs7r
|
R0lGODlhEAAQAMIEAFWjVVWkVWS/ZGfFZ////////////////yH5BAEKAAQALAAAAAAQABAAAAMvSLrc/lAFIUIkYOgNXt5g14Dk0AQlaC1CuglM6w7wgs7r
|
||||||
@ -269,14 +271,6 @@ def plugin_stop() -> None:
|
|||||||
logger.debug('Done.')
|
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:
|
def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> nb.Frame:
|
||||||
"""
|
"""
|
||||||
Plugin preferences setup hook.
|
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.
|
:param is_beta: Whether game beta was detected.
|
||||||
:return: An instance of `myNotebook.Frame`.
|
: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 = nb.Frame(parent)
|
||||||
frame.columnconfigure(1, weight=1)
|
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
|
cur_row += 1
|
||||||
# LANG: EDSM API key label
|
# LANG: EDSM API key label
|
||||||
this.apikey_label = nb.Label(frame, text=tr.tl('API Key'))
|
api_keys_label_common(this, cur_row, frame)
|
||||||
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)
|
|
||||||
cur_row += 1
|
cur_row += 1
|
||||||
|
|
||||||
prefs_cmdr_changed(cmdr, is_beta)
|
prefs_cmdr_changed(cmdr, is_beta)
|
||||||
|
show_pwd_var_common(frame, cur_row, this)
|
||||||
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)
|
|
||||||
|
|
||||||
return frame
|
return frame
|
||||||
|
|
||||||
@ -544,11 +519,7 @@ def journal_entry( # noqa: C901, CCR001
|
|||||||
|
|
||||||
this.game_version = state['GameVersion']
|
this.game_version = state['GameVersion']
|
||||||
this.game_build = state['GameBuild']
|
this.game_build = state['GameBuild']
|
||||||
this.system_address = state['SystemAddress']
|
this_format_common(this, state)
|
||||||
this.system_name = state['SystemName']
|
|
||||||
this.system_population = state['SystemPopulation']
|
|
||||||
this.station_name = state['StationName']
|
|
||||||
this.station_marketid = state['MarketID']
|
|
||||||
|
|
||||||
entry = new_entry
|
entry = new_entry
|
||||||
|
|
||||||
@ -658,7 +629,7 @@ Queueing: {entry!r}'''
|
|||||||
|
|
||||||
|
|
||||||
# Update system data
|
# 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.
|
Process new CAPI data.
|
||||||
|
|
||||||
@ -668,14 +639,7 @@ def cmdr_data(data: CAPIData, is_beta: bool) -> str | None: # noqa: CCR001
|
|||||||
"""
|
"""
|
||||||
system = data['lastSystem']['name']
|
system = data['lastSystem']['name']
|
||||||
|
|
||||||
# Always store initially, even if we're not the *current* system provider.
|
cmdr_data_initial_common(this, data)
|
||||||
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']
|
|
||||||
|
|
||||||
# TODO: Fire off the EDSM API call to trigger the callback for the icons
|
# 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()
|
this.system_link.update_idletasks()
|
||||||
if config.get_str('station_provider') == 'EDSM':
|
if config.get_str('station_provider') == 'EDSM':
|
||||||
if this.station_link:
|
if this.station_link:
|
||||||
if data['commander']['docked'] or this.on_foot and this.station_name:
|
station_link_common(data, this)
|
||||||
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'] = ''
|
|
||||||
|
|
||||||
# Do *NOT* set 'url' here, as it's set to a function that will call
|
# Do *NOT* set 'url' here, as it's set to a function that will call
|
||||||
# through correctly. We don't want a static string.
|
# through correctly. We don't want a static string.
|
||||||
this.station_link.update_idletasks()
|
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
|
from __future__ import annotations
|
||||||
|
|
||||||
import base64
|
|
||||||
import gzip
|
|
||||||
import io
|
|
||||||
import json
|
|
||||||
from typing import Any, Mapping
|
from typing import Any, Mapping
|
||||||
|
from plugins.common_coreutils import shipyard_url_common # pylint: disable=E0401
|
||||||
|
|
||||||
|
|
||||||
def plugin_start3(plugin_dir: str) -> str:
|
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.
|
:param is_beta: Whether the game is in beta.
|
||||||
:return: The constructed URL for the ship loadout.
|
:return: The constructed URL for the ship loadout.
|
||||||
"""
|
"""
|
||||||
# Convert loadout to JSON and gzip compress it
|
encoded_data = shipyard_url_common(loadout)
|
||||||
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)
|
|
||||||
|
|
||||||
# Construct the URL using the appropriate base URL based on is_beta
|
# 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='
|
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 if encoded_data else False
|
||||||
|
|
||||||
return base_url + encoded_data
|
|
||||||
|
@ -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
|
`build.py` TO ENSURE THE FILES ARE ACTUALLY PRESENT
|
||||||
IN AN END-USER INSTALLATION ON WINDOWS.
|
IN AN END-USER INSTALLATION ON WINDOWS.
|
||||||
"""
|
"""
|
||||||
|
# pylint: disable=import-error
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
@ -43,6 +44,8 @@ from EDMCLogging import get_main_logger
|
|||||||
from monitor import monitor
|
from monitor import monitor
|
||||||
from ttkHyperlinkLabel import HyperlinkLabel
|
from ttkHyperlinkLabel import HyperlinkLabel
|
||||||
from l10n import translations as tr
|
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()
|
logger = get_main_logger()
|
||||||
|
|
||||||
@ -115,7 +118,7 @@ class This:
|
|||||||
self.system_address: str | None = None # type: ignore
|
self.system_address: str | None = None # type: ignore
|
||||||
self.system_population: int | None = None
|
self.system_population: int | None = None
|
||||||
self.station_link: tk.Widget = None # type: ignore
|
self.station_link: tk.Widget = None # type: ignore
|
||||||
self.station = None
|
self.station_name = None
|
||||||
self.station_marketid = None
|
self.station_marketid = None
|
||||||
|
|
||||||
# Prefs UI
|
# Prefs UI
|
||||||
@ -144,15 +147,12 @@ class This:
|
|||||||
|
|
||||||
|
|
||||||
this = 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 time we updated, if unset in config this is 0, which means an instant update
|
||||||
LAST_UPDATE_CONF_KEY = 'inara_last_update'
|
LAST_UPDATE_CONF_KEY = 'inara_last_update'
|
||||||
EVENT_COLLECT_TIME = 31 # Minimum time to take collecting events before requesting a send
|
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
|
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/'
|
TARGET_URL = 'https://inara.cz/inapi/v1/'
|
||||||
DEBUG = 'inara' in debug_senders
|
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:
|
if system_name and station_name:
|
||||||
return requests.utils.requote_uri(f'https://inara.cz/galaxy-station/?search={system_name}%20[{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(
|
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:
|
if system_name:
|
||||||
return system_url(system_name)
|
return system_url(system_name)
|
||||||
@ -233,21 +233,8 @@ def plugin_stop() -> None:
|
|||||||
logger.debug('Done.')
|
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:
|
def plugin_prefs(parent: ttk.Notebook, cmdr: str, is_beta: bool) -> nb.Frame:
|
||||||
"""Plugin Preferences UI hook."""
|
"""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
|
cur_row = 0
|
||||||
|
|
||||||
frame = nb.Frame(parent)
|
frame = nb.Frame(parent)
|
||||||
@ -287,22 +274,10 @@ def plugin_prefs(parent: ttk.Notebook, cmdr: str, is_beta: bool) -> nb.Frame:
|
|||||||
cur_row += 1
|
cur_row += 1
|
||||||
|
|
||||||
# LANG: Inara API key label
|
# LANG: Inara API key label
|
||||||
this.apikey_label = nb.Label(frame, text=tr.tl('API Key')) # Inara setting
|
api_keys_label_common(this, cur_row, frame)
|
||||||
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)
|
|
||||||
cur_row += 1
|
cur_row += 1
|
||||||
|
|
||||||
prefs_cmdr_changed(cmdr, is_beta)
|
prefs_cmdr_changed(cmdr, is_beta)
|
||||||
|
show_pwd_var_common(frame, cur_row, this)
|
||||||
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)
|
|
||||||
|
|
||||||
return frame
|
return frame
|
||||||
|
|
||||||
@ -411,15 +386,11 @@ def journal_entry( # noqa: C901, CCR001
|
|||||||
# But then we update all the tracking copies before any other checks,
|
# But then we update all the tracking copies before any other checks,
|
||||||
# because they're relevant for URL providing even if *sending* isn't
|
# because they're relevant for URL providing even if *sending* isn't
|
||||||
# appropriate.
|
# appropriate.
|
||||||
this.on_foot = state['OnFoot']
|
|
||||||
event_name: str = entry['event']
|
event_name: str = entry['event']
|
||||||
this.cmdr = cmdr
|
this.cmdr = cmdr
|
||||||
this.FID = state['FID']
|
this.FID = state['FID']
|
||||||
this.multicrew = bool(state['Role'])
|
this.multicrew = bool(state['Role'])
|
||||||
this.system_name = state['SystemName']
|
this_format_common(this, state)
|
||||||
this.system_address = state['SystemAddress']
|
|
||||||
this.station = state['StationName']
|
|
||||||
this.station_marketid = state['MarketID']
|
|
||||||
|
|
||||||
if not monitor.is_live_galaxy():
|
if not monitor.is_live_galaxy():
|
||||||
# Since Update 14 on 2022-11-29 Inara only accepts Live data.
|
# 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':
|
elif event_name == 'Undocked':
|
||||||
this.undocked = True
|
this.undocked = True
|
||||||
this.station = None
|
this.station_name = None
|
||||||
|
|
||||||
elif event_name == 'SupercruiseEntry':
|
elif event_name == 'SupercruiseEntry':
|
||||||
this.undocked = False
|
this.undocked = False
|
||||||
@ -1368,14 +1339,7 @@ def journal_entry( # noqa: C901, CCR001
|
|||||||
this.system_link.update_idletasks()
|
this.system_link.update_idletasks()
|
||||||
|
|
||||||
if config.get_str('station_provider') == 'Inara':
|
if config.get_str('station_provider') == 'Inara':
|
||||||
to_set: str = cast(str, this.station)
|
station_name_setter_common(this)
|
||||||
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
|
|
||||||
# Do *NOT* set 'url' here, as it's set to a function that will call
|
# Do *NOT* set 'url' here, as it's set to a function that will call
|
||||||
# through correctly. We don't want a static string.
|
# through correctly. We don't want a static string.
|
||||||
this.station_link.update_idletasks()
|
this.station_link.update_idletasks()
|
||||||
@ -1383,7 +1347,7 @@ def journal_entry( # noqa: C901, CCR001
|
|||||||
return '' # No error
|
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."""
|
"""CAPI event hook."""
|
||||||
this.cmdr = data['commander']['name']
|
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
|
# Only trust CAPI if these aren't yet set
|
||||||
this.system_name = this.system_name if this.system_name else data['lastSystem']['name']
|
this.system_name = this.system_name if this.system_name else data['lastSystem']['name']
|
||||||
|
|
||||||
if not this.station and data['commander']['docked']:
|
if not this.station_name and data['commander']['docked']:
|
||||||
this.station = data['lastStarport']['name']
|
this.station_name = data['lastStarport']['name']
|
||||||
|
|
||||||
# Override standard URL functions
|
# Override standard URL functions
|
||||||
if config.get_str('system_provider') == 'Inara':
|
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()
|
this.system_link.update_idletasks()
|
||||||
|
|
||||||
if config.get_str('station_provider') == 'Inara':
|
if config.get_str('station_provider') == 'Inara':
|
||||||
if data['commander']['docked'] or this.on_foot and this.station:
|
station_link_common(data, this)
|
||||||
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'] = ''
|
|
||||||
|
|
||||||
# Do *NOT* set 'url' here, as it's set to a function that will call
|
# Do *NOT* set 'url' here, as it's set to a function that will call
|
||||||
# through correctly. We don't want a static string.
|
# 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
|
`build.py` TO ENSURE THE FILES ARE ACTUALLY PRESENT
|
||||||
IN AN END-USER INSTALLATION ON WINDOWS.
|
IN AN END-USER INSTALLATION ON WINDOWS.
|
||||||
"""
|
"""
|
||||||
|
# pylint: disable=import-error
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from typing import Any, cast
|
from typing import Any
|
||||||
import requests
|
import requests
|
||||||
from companion import CAPIData
|
from companion import CAPIData
|
||||||
from config import appname, config
|
from config import appname, config
|
||||||
from EDMCLogging import get_main_logger
|
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()
|
logger = get_main_logger()
|
||||||
|
|
||||||
@ -47,7 +50,6 @@ class This:
|
|||||||
|
|
||||||
|
|
||||||
this = This()
|
this = This()
|
||||||
STATION_UNDOCKED: str = '×' # "Station" name to display when not docked = U+00D7
|
|
||||||
|
|
||||||
|
|
||||||
def plugin_start3(plugin_dir: str) -> str:
|
def plugin_start3(plugin_dir: str) -> str:
|
||||||
@ -91,12 +93,7 @@ def journal_entry(
|
|||||||
:param state: `monitor.state`
|
:param state: `monitor.state`
|
||||||
:return: None if no error, else an error string.
|
:return: None if no error, else an error string.
|
||||||
"""
|
"""
|
||||||
this.on_foot = state['OnFoot']
|
this_format_common(this, 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']
|
|
||||||
|
|
||||||
# Only actually change URLs if we are current provider.
|
# Only actually change URLs if we are current provider.
|
||||||
if config.get_str('system_provider') == 'spansh':
|
if config.get_str('system_provider') == 'spansh':
|
||||||
@ -106,14 +103,7 @@ def journal_entry(
|
|||||||
this.system_link.update_idletasks()
|
this.system_link.update_idletasks()
|
||||||
|
|
||||||
if config.get_str('station_provider') == 'spansh':
|
if config.get_str('station_provider') == 'spansh':
|
||||||
to_set: str = cast(str, this.station_name)
|
station_name_setter_common(this)
|
||||||
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
|
|
||||||
# Do *NOT* set 'url' here, as it's set to a function that will call
|
# Do *NOT* set 'url' here, as it's set to a function that will call
|
||||||
# through correctly. We don't want a static string.
|
# through correctly. We don't want a static string.
|
||||||
this.station_link.update_idletasks()
|
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.
|
:param is_beta: Whether game beta was detected.
|
||||||
:return: Optional error string.
|
:return: Optional error string.
|
||||||
"""
|
"""
|
||||||
# Always store initially, even if we're not the *current* system provider.
|
cmdr_data_initial_common(this, data)
|
||||||
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']
|
|
||||||
|
|
||||||
# Override standard URL functions
|
# Override standard URL functions
|
||||||
if config.get_str('system_provider') == 'spansh':
|
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.
|
# through correctly. We don't want a static string.
|
||||||
this.system_link.update_idletasks()
|
this.system_link.update_idletasks()
|
||||||
if config.get_str('station_provider') == 'spansh':
|
if config.get_str('station_provider') == 'spansh':
|
||||||
if data['commander']['docked'] or this.on_foot and this.station_name:
|
station_link_common(data, this)
|
||||||
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'] = ''
|
|
||||||
# Do *NOT* set 'url' here, as it's set to a function that will call
|
# Do *NOT* set 'url' here, as it's set to a function that will call
|
||||||
# through correctly. We don't want a static string.
|
# through correctly. We don't want a static string.
|
||||||
this.station_link.update_idletasks()
|
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 monitor import monitor
|
||||||
from theme import theme
|
from theme import theme
|
||||||
from ttkHyperlinkLabel import HyperlinkLabel
|
from ttkHyperlinkLabel import HyperlinkLabel
|
||||||
|
from common_utils import ensure_on_screen
|
||||||
logger = get_main_logger()
|
logger = get_main_logger()
|
||||||
|
|
||||||
|
|
||||||
@ -187,7 +188,6 @@ if sys.platform == 'win32':
|
|||||||
import ctypes
|
import ctypes
|
||||||
import winreg
|
import winreg
|
||||||
from ctypes.wintypes import LPCWSTR, LPWSTR, MAX_PATH, POINT, RECT, SIZE, UINT, BOOL
|
from ctypes.wintypes import LPCWSTR, LPWSTR, MAX_PATH, POINT, RECT, SIZE, UINT, BOOL
|
||||||
import win32gui
|
|
||||||
import win32api
|
import win32api
|
||||||
is_wine = False
|
is_wine = False
|
||||||
try:
|
try:
|
||||||
@ -307,15 +307,7 @@ class PreferencesDialog(tk.Toplevel):
|
|||||||
self.grab_set()
|
self.grab_set()
|
||||||
|
|
||||||
# Ensure fully on-screen
|
# Ensure fully on-screen
|
||||||
if sys.platform == 'win32' and CalculatePopupWindowPosition:
|
ensure_on_screen(self, parent)
|
||||||
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}")
|
|
||||||
|
|
||||||
# Set Log Directory
|
# Set Log Directory
|
||||||
self.logfile_loc = Path(config.app_dir_path / 'logs')
|
self.logfile_loc = Path(config.app_dir_path / 'logs')
|
||||||
@ -829,7 +821,8 @@ class PreferencesDialog(tk.Toplevel):
|
|||||||
appearance_frame,
|
appearance_frame,
|
||||||
# LANG: Appearance - Help/hint text for UI scaling selection
|
# LANG: Appearance - Help/hint text for UI scaling selection
|
||||||
text=tr.tl('100 means Default{CR}Restart Required for{CR}changes to take effect!')
|
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
|
# Transparency slider
|
||||||
ttk.Separator(appearance_frame, orient=tk.HORIZONTAL).grid(
|
ttk.Separator(appearance_frame, orient=tk.HORIZONTAL).grid(
|
||||||
@ -1308,10 +1301,10 @@ class PreferencesDialog(tk.Toplevel):
|
|||||||
self._destroy()
|
self._destroy()
|
||||||
# Send to the Post Config if we updated the update branch or need to restart
|
# Send to the Post Config if we updated the update branch or need to restart
|
||||||
post_flags = {
|
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(),
|
'Track': self.update_paths.get(),
|
||||||
'Parent': self,
|
'Parent': self,
|
||||||
'Restart_Req': True if self.req_restart else False
|
'Restart_Req': self.req_restart # Sipmle Bool Needed
|
||||||
}
|
}
|
||||||
if self.callback:
|
if self.callback:
|
||||||
self.callback(**post_flags)
|
self.callback(**post_flags)
|
||||||
|
@ -64,9 +64,19 @@ COMMENT_SAME_LINE_RE = re.compile(r"^.*?(#.*)$")
|
|||||||
COMMENT_OWN_LINE_RE = re.compile(r"^\s*?(#.*)$")
|
COMMENT_OWN_LINE_RE = re.compile(r"^\s*?(#.*)$")
|
||||||
|
|
||||||
|
|
||||||
def extract_comments( # noqa: CCR001
|
def _extract_lang_comment(line: str, pattern: re.Pattern, file: pathlib.Path,
|
||||||
call: ast.Call, lines: list[str], file: pathlib.Path
|
lineno: int) -> tuple[str | None, 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.
|
Extract comments from source code based on the given call.
|
||||||
|
|
||||||
@ -86,29 +96,13 @@ def extract_comments( # noqa: CCR001
|
|||||||
above_comment: str | None = None
|
above_comment: str | None = None
|
||||||
current_line = lines[current].strip()
|
current_line = lines[current].strip()
|
||||||
current_comment: str | None = None
|
current_comment: str | None = None
|
||||||
|
|
||||||
bad_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:
|
if above_line:
|
||||||
above_comment = above_comment.replace("# LANG:", "").strip()
|
above_comment, bad_comment = _extract_lang_comment(above_line, COMMENT_OWN_LINE_RE, file, call.lineno)
|
||||||
|
|
||||||
if current_line is not None:
|
if current_line:
|
||||||
match = COMMENT_SAME_LINE_RE.match(current_line)
|
current_comment, bad_comment = _extract_lang_comment(current_line, COMMENT_SAME_LINE_RE, file, call.lineno)
|
||||||
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_comment is not None:
|
if current_comment is not None:
|
||||||
out = current_comment
|
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 hotkey import hotkeymgr
|
||||||
from l10n import Locale, translations as tr
|
from l10n import Locale, translations as tr
|
||||||
from monitor import monitor
|
from monitor import monitor
|
||||||
|
from common_utils import ensure_on_screen
|
||||||
|
|
||||||
logger = EDMCLogging.get_main_logger()
|
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_START = 1
|
||||||
CR_LINES_END = 3
|
CR_LINES_END = 3
|
||||||
RANK_LINES_START = 3
|
RANK_LINES_START = 3
|
||||||
@ -418,16 +403,7 @@ class StatsResults(tk.Toplevel):
|
|||||||
self.grab_set()
|
self.grab_set()
|
||||||
|
|
||||||
# Ensure fully on-screen
|
# Ensure fully on-screen
|
||||||
if sys.platform == 'win32' and CalculatePopupWindowPosition:
|
ensure_on_screen(self, parent)
|
||||||
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}")
|
|
||||||
|
|
||||||
def addpage(
|
def addpage(
|
||||||
self, parent, header: list[str] | None = None, align: str | None = None
|
self, parent, header: list[str] | None = None, align: str | None = None
|
||||||
|
Loading…
x
Reference in New Issue
Block a user