mirror of
https://github.com/EDCD/EDMarketConnector.git
synced 2025-04-14 08:17:13 +03:00
Poll logs for current system.
This commit is contained in:
parent
e50cd2b808
commit
d485a73243
@ -30,6 +30,7 @@ import eddb
|
||||
import prefs
|
||||
from config import appname, applongname, config
|
||||
from hotkey import hotkeymgr
|
||||
from monitor import monitor
|
||||
|
||||
l10n.Translations().install()
|
||||
EDDB = eddb.EDDB()
|
||||
@ -169,6 +170,12 @@ class AppWindow:
|
||||
self.w.bind_all('<<Invoke>>', self.getandsend) # user-generated
|
||||
hotkeymgr.register(self.w, config.getint('hotkey_code'), config.getint('hotkey_mods'))
|
||||
|
||||
# Install log monitoring
|
||||
monitor.set_callback(self.system_change)
|
||||
if (config.getint('output') & config.OUT_LOG_AUTO) and (config.getint('output') & (config.OUT_LOG_AUTO|config.OUT_LOG_EDSM)):
|
||||
monitor.enable_logging()
|
||||
monitor.start()
|
||||
|
||||
# call after credentials have changed
|
||||
def login(self):
|
||||
self.status['text'] = _('Logging in...')
|
||||
@ -362,6 +369,13 @@ class AppWindow:
|
||||
except:
|
||||
pass
|
||||
|
||||
def system_change(self, system, timestamp):
|
||||
if self.system['text'] != system:
|
||||
# TODO: EDSM lookup and csv and/or EDSM log
|
||||
self.system['text'] = system
|
||||
self.station['text'] = EDDB.system(system) and self.STATION_UNDOCKED or ''
|
||||
self.status['text'] = strftime(_('Last updated at {HH}:{MM}:{SS}').format(HH='%H', MM='%M', SS='%S').encode('utf-8'), localtime(timestamp)).decode('utf-8')
|
||||
|
||||
def edsmpoll(self):
|
||||
result = self.edsm.result
|
||||
if result['done']:
|
||||
|
@ -74,6 +74,7 @@ class Config:
|
||||
#OUT_STAT = 64 # No longer available
|
||||
OUT_SHIP_CORIOLIS = 128
|
||||
OUT_LOG_EDSM = 256
|
||||
OUT_LOG_AUTO = 512
|
||||
|
||||
if platform=='darwin':
|
||||
|
||||
|
296
monitor.py
Normal file
296
monitor.py
Normal file
@ -0,0 +1,296 @@
|
||||
import re
|
||||
import threading
|
||||
from os import listdir, pardir, rename, unlink
|
||||
from os.path import exists, isdir, isfile, join
|
||||
from platform import machine
|
||||
from sys import platform
|
||||
from time import strptime, localtime, mktime, sleep, time
|
||||
from datetime import datetime
|
||||
|
||||
if __debug__:
|
||||
from traceback import print_exc
|
||||
|
||||
if platform=='darwin':
|
||||
from AppKit import NSWorkspace
|
||||
from Foundation import NSSearchPathForDirectoriesInDomains, NSApplicationSupportDirectory, NSUserDomainMask
|
||||
|
||||
elif platform=='win32':
|
||||
import ctypes
|
||||
|
||||
CSIDL_LOCAL_APPDATA = 0x001C
|
||||
CSIDL_PROGRAM_FILESX86 = 0x002A
|
||||
|
||||
# _winreg that ships with Python 2 doesn't support unicode, so do this instead
|
||||
from ctypes.wintypes import *
|
||||
|
||||
HKEY_LOCAL_MACHINE = 0x80000002
|
||||
KEY_READ = 0x00020019
|
||||
REG_SZ = 1
|
||||
|
||||
RegOpenKeyEx = ctypes.windll.advapi32.RegOpenKeyExW
|
||||
RegOpenKeyEx.restype = LONG
|
||||
RegOpenKeyEx.argtypes = [HKEY, LPCWSTR, DWORD, DWORD, ctypes.POINTER(HKEY)]
|
||||
|
||||
RegCloseKey = ctypes.windll.advapi32.RegCloseKey
|
||||
RegCloseKey.restype = LONG
|
||||
RegCloseKey.argtypes = [HKEY]
|
||||
|
||||
RegQueryValueEx = ctypes.windll.advapi32.RegQueryValueExW
|
||||
RegQueryValueEx.restype = LONG
|
||||
RegQueryValueEx.argtypes = [HKEY, LPCWSTR, LPCVOID, ctypes.POINTER(DWORD), LPCVOID, ctypes.POINTER(DWORD)]
|
||||
|
||||
RegEnumKeyEx = ctypes.windll.advapi32.RegEnumKeyExW
|
||||
RegEnumKeyEx.restype = LONG
|
||||
RegEnumKeyEx.argtypes = [HKEY, DWORD, LPWSTR, ctypes.POINTER(DWORD), ctypes.POINTER(DWORD), LPWSTR, ctypes.POINTER(DWORD), ctypes.POINTER(FILETIME)]
|
||||
|
||||
WNDENUMPROC = ctypes.WINFUNCTYPE(BOOL, HWND, ctypes.POINTER(DWORD))
|
||||
EnumWindows = ctypes.windll.user32.EnumWindows
|
||||
EnumWindows.argtypes = [WNDENUMPROC, LPARAM]
|
||||
GetWindowText = ctypes.windll.user32.GetWindowTextW
|
||||
GetWindowText.argtypes = [HWND, LPWSTR, ctypes.c_int]
|
||||
GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW
|
||||
|
||||
@WNDENUMPROC
|
||||
def EnumWindowsProc(hwnd, lParam):
|
||||
l = GetWindowTextLength(hwnd) + 1
|
||||
buf = ctypes.create_unicode_buffer(l)
|
||||
if GetWindowText(hwnd, buf, l) and buf.value.startswith('Elite - Dangerous'):
|
||||
lParam[0] = 1
|
||||
return False # stop enumeration
|
||||
return True
|
||||
|
||||
|
||||
class EDLogs:
|
||||
|
||||
def __init__(self):
|
||||
self.logdir = self._logdir()
|
||||
self.logging_enabled = self._logging_enabled
|
||||
self._restart_required = False
|
||||
self.observer = None
|
||||
self.callback = None
|
||||
|
||||
def set_callback(self, callback):
|
||||
self.callback = callback
|
||||
|
||||
def enable_logging(self):
|
||||
if self.logging_enabled():
|
||||
return True
|
||||
elif self._enable_logging():
|
||||
self._restart_required = self._ED_is_running()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def restart_required(self):
|
||||
if not self._ED_is_running():
|
||||
self._restart_required = False
|
||||
return self._restart_required
|
||||
|
||||
def logging_enabled_in_file(self, appconf):
|
||||
if not isfile(appconf):
|
||||
return False
|
||||
|
||||
with open(appconf, 'rU') as f:
|
||||
content = f.read().lower()
|
||||
start = content.find('<network')
|
||||
end = content.find('</network>')
|
||||
if start >= 0 and end >= 0:
|
||||
return bool(re.search('verboselogging\s*=\s*\"1\"', content[start+8:end]))
|
||||
else:
|
||||
return False
|
||||
|
||||
def enable_logging_in_file(self, appconf):
|
||||
try:
|
||||
if not exists(appconf):
|
||||
with open(appconf, 'wt') as f:
|
||||
f.write('<AppConfig>\n\t<Network\n\t\tVerboseLogging="1"\n\t>\n\t</Network>\n</AppConfig>\n')
|
||||
return True
|
||||
|
||||
with open(appconf, 'rU') as f:
|
||||
content = f.read()
|
||||
f.close()
|
||||
backup = appconf[:-4] + '_backup.xml'
|
||||
if exists(backup):
|
||||
unlink(backup)
|
||||
rename(appconf, backup)
|
||||
|
||||
with open(appconf, 'wt') as f:
|
||||
start = content.lower().find('<network')
|
||||
if start >= 0:
|
||||
f.write(content[:start+8] + '\n\t\tVerboseLogging="1"' + content[start+8:])
|
||||
else:
|
||||
start = content.lower().find("</appconfig>")
|
||||
if start >= 0:
|
||||
f.write(content[:start] + '\t<Network\n\t\tVerboseLogging="1"\n\t>\n\t</Network>\n' + content[start:])
|
||||
else:
|
||||
f.write(content) # eh ?
|
||||
return False
|
||||
|
||||
assert self._logging_enabled()
|
||||
return self.logging_enabled_in_file(appconf)
|
||||
except:
|
||||
if __debug__: print_exc()
|
||||
return False
|
||||
|
||||
def start(self):
|
||||
self.stop()
|
||||
if not self.logdir or not self.callback:
|
||||
return False
|
||||
self.observer = threading.Thread(target = self.worker, name = 'netLog worker')
|
||||
self.observer.daemon = True
|
||||
self.observer.start()
|
||||
|
||||
def stop(self):
|
||||
if self.observer:
|
||||
self.observer.stop()
|
||||
self.observer = None
|
||||
|
||||
def worker(self):
|
||||
regexp = re.compile('{(.+)} System:[^\(]*\(([^\)]+)')
|
||||
|
||||
# Seek to the end of the latest log file
|
||||
logfiles = sorted([x for x in listdir(self.logdir) if x.startswith('netLog.')])
|
||||
logfile = logfiles and logfiles[-1] or None
|
||||
if logfile:
|
||||
loghandle = open(join(self.logdir, logfile), 'rt')
|
||||
loghandle.seek(0, 2) # seek to EOF
|
||||
else:
|
||||
loghandle = None
|
||||
|
||||
while True:
|
||||
# Check whether new log file started, e.g. client restarted. Assumes logs sort alphabetically.
|
||||
logfiles = sorted([x for x in listdir(self.logdir) if x.startswith('netLog.')])
|
||||
newlogfile = logfiles and logfiles[-1] or None
|
||||
if logfile != newlogfile:
|
||||
logfile = newlogfile
|
||||
if loghandle:
|
||||
loghandle.close()
|
||||
loghandle = open(join(self.logdir, logfile), 'rt')
|
||||
|
||||
if logfile:
|
||||
system = visited = None
|
||||
loghandle.seek(0, 1) # reset EOF flag
|
||||
|
||||
for line in loghandle:
|
||||
match = regexp.match(line)
|
||||
if match:
|
||||
system, visited = match.group(2), match.group(1)
|
||||
|
||||
if system:
|
||||
self._restart_required = False # clearly logging is working
|
||||
# Convert local time string to UTC date and time
|
||||
visited_struct = strptime(visited, '%H:%M:%S')
|
||||
now = localtime()
|
||||
if now.tm_hour == 0 and visited_struct.tm_hour == 23:
|
||||
# Crossed midnight between timestamp and poll
|
||||
now = localtime(time()-60)
|
||||
datetime_struct = datetime(now.tm_year, now.tm_mon, now.tm_mday, visited_struct.tm_hour, visited_struct.tm_min, visited_struct.tm_sec).timetuple() # still local time
|
||||
self.callback(system, mktime(datetime_struct))
|
||||
|
||||
sleep(10) # New system gets posted to log file before hyperspace ends, so don't need to poll too often
|
||||
|
||||
|
||||
if platform=='darwin':
|
||||
|
||||
def _logdir(self):
|
||||
# https://support.frontier.co.uk/kb/faq.php?id=97
|
||||
suffix = join('Frontier Developments', 'Elite Dangerous')
|
||||
paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, True)
|
||||
if len(paths) and isdir(paths[0]) and isfile(join(paths[0], suffix, 'AppNetCfg.xml')) and isdir(join(paths[0], suffix, 'Logs')):
|
||||
return join(paths[0], suffix, 'Logs')
|
||||
else:
|
||||
return None
|
||||
|
||||
def _logging_enabled(self):
|
||||
return self.logdir and self.logging_enabled_in_file(join(self.logdir, pardir, 'AppConfigLocal.xml'))
|
||||
|
||||
def _enable_logging(self):
|
||||
return self.logdir and self.enable_logging_in_file(join(self.logdir, pardir, 'AppConfigLocal.xml'))
|
||||
|
||||
def _ED_is_running(self):
|
||||
for x in NSWorkspace.sharedWorkspace().runningApplications():
|
||||
if x.bundleIdentifier() == 'uk.co.frontier.EliteDangerous':
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
elif platform=='win32':
|
||||
|
||||
def _logdir(self):
|
||||
# First try under the Launcher
|
||||
key = HKEY()
|
||||
if not RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
machine().endswith('64') and
|
||||
r'SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall' or # Assumes that the launcher is a 32bit process
|
||||
r'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall',
|
||||
0, KEY_READ, ctypes.byref(key)):
|
||||
buf = ctypes.create_unicode_buffer(MAX_PATH)
|
||||
i = 0
|
||||
while True:
|
||||
size = DWORD(MAX_PATH)
|
||||
if RegEnumKeyEx(key, i, buf, ctypes.byref(size), None, None, None, None):
|
||||
break
|
||||
|
||||
subkey = HKEY()
|
||||
if not RegOpenKeyEx(key, buf, 0, KEY_READ, ctypes.byref(subkey)):
|
||||
valtype = DWORD()
|
||||
valsize = DWORD((len('Frontier Developments')+1)*2)
|
||||
valbuf = ctypes.create_unicode_buffer(valsize.value / 2)
|
||||
if not RegQueryValueEx(subkey, 'Publisher', 0, ctypes.byref(valtype), valbuf, ctypes.byref(valsize)) and valtype.value == REG_SZ and valbuf.value == 'Frontier Developments':
|
||||
if not RegQueryValueEx(subkey, 'InstallLocation', 0, ctypes.byref(valtype), None, ctypes.byref(valsize)) and valtype.value == REG_SZ:
|
||||
valbuf = ctypes.create_unicode_buffer(valsize.value / 2)
|
||||
if not RegQueryValueEx(subkey, 'InstallLocation', 0, ctypes.byref(valtype), valbuf, ctypes.byref(valsize)):
|
||||
custpath = join(valbuf.value, 'Products')
|
||||
if isdir(custpath):
|
||||
for d in listdir(custpath):
|
||||
if d.startswith('FORC-FDEV-D-1') and isfile(join(custpath, d, 'AppConfig.xml')) and isdir(join(custpath, d, 'Logs')):
|
||||
RegCloseKey(subkey)
|
||||
RegCloseKey(key)
|
||||
return join(custpath, d, 'Logs')
|
||||
RegCloseKey(subkey)
|
||||
i += 1
|
||||
RegCloseKey(key)
|
||||
|
||||
# https://support.elitedangerous.com/kb/faq.php?id=108
|
||||
programs = ctypes.create_unicode_buffer(MAX_PATH)
|
||||
ctypes.windll.shell32.SHGetSpecialFolderPathW(0, programs, CSIDL_PROGRAM_FILESX86, 0)
|
||||
applocal = ctypes.create_unicode_buffer(MAX_PATH)
|
||||
ctypes.windll.shell32.SHGetSpecialFolderPathW(0, applocal, CSIDL_LOCAL_APPDATA, 0)
|
||||
for base in [join(programs.value, 'Steam', 'steamapps', 'common', 'Elite Dangerous', 'Products'),
|
||||
join(programs.value, 'Frontier', 'Products'),
|
||||
join(applocal.value, 'Frontier_Developments', 'Products')]:
|
||||
if isdir(base):
|
||||
for d in listdir(base):
|
||||
if d.startswith('FORC-FDEV-D-1') and isfile(join(base, d, 'AppConfig.xml')) and isdir(join(base, d, 'Logs')):
|
||||
return join(base, d, 'Logs')
|
||||
|
||||
return None
|
||||
|
||||
def _logging_enabled(self):
|
||||
return self.logdir and (self.logging_enabled_in_file(join(self.logdir, pardir, 'AppConfigLocal.xml')) or
|
||||
self.logging_enabled_in_file(join(self.logdir, pardir, 'AppConfig.xml')))
|
||||
|
||||
def _enable_logging(self):
|
||||
return self.logdir and self.enable_logging_in_file(isfile(join(self.logdir, pardir, 'AppConfigLocal.xml')) and join(self.logdir, pardir, 'AppConfigLocal.xml') or join(self.logdir, pardir, 'AppConfig.xml'))
|
||||
|
||||
def _ED_is_running(self):
|
||||
retval = DWORD(0)
|
||||
EnumWindows(EnumWindowsProc, ctypes.addressof(retval))
|
||||
return bool(retval)
|
||||
|
||||
elif platform=='linux2':
|
||||
|
||||
def _logdir(self):
|
||||
return None
|
||||
|
||||
def _logging_enabled(self):
|
||||
return False
|
||||
|
||||
def _enable_logging(self):
|
||||
return False
|
||||
|
||||
def _ED_is_running(self):
|
||||
return False
|
||||
|
||||
# singleton
|
||||
monitor = EDLogs()
|
85
prefs.py
85
prefs.py
@ -11,6 +11,7 @@ from ttkHyperlinkLabel import HyperlinkLabel
|
||||
|
||||
from config import applongname, config
|
||||
from hotkey import hotkeymgr
|
||||
from monitor import monitor
|
||||
|
||||
|
||||
if platform == 'darwin':
|
||||
@ -71,7 +72,7 @@ class PreferencesDialog(tk.Toplevel):
|
||||
frame.grid(sticky=tk.NSEW)
|
||||
|
||||
credframe = ttk.LabelFrame(frame, text=_('Credentials')) # Section heading in settings
|
||||
credframe.grid(padx=10, pady=10, sticky=tk.NSEW)
|
||||
credframe.grid(padx=10, pady=5, sticky=tk.NSEW)
|
||||
credframe.columnconfigure(1, weight=1)
|
||||
|
||||
ttk.Label(credframe, text=_('Please log in with your Elite: Dangerous account details')).grid(row=0, columnspan=2, sticky=tk.W) # Use same text as E:D Launcher's login dialog
|
||||
@ -90,30 +91,35 @@ class PreferencesDialog(tk.Toplevel):
|
||||
child.grid_configure(padx=5, pady=3)
|
||||
|
||||
outframe = ttk.LabelFrame(frame, text=_('Output')) # Section heading in settings
|
||||
outframe.grid(padx=10, pady=10, sticky=tk.NSEW)
|
||||
outframe.grid(padx=10, pady=5, sticky=tk.NSEW)
|
||||
|
||||
output = config.getint('output') or (config.OUT_EDDN | config.OUT_SHIP_EDS)
|
||||
ttk.Label(outframe, text=_('Please choose what data to save')).grid(row=0, columnspan=2, padx=5, pady=3, sticky=tk.W)
|
||||
self.out_eddn= tk.IntVar(value = (output & config.OUT_EDDN) and 1 or 0)
|
||||
ttk.Checkbutton(outframe, text=_('Send station data to the Elite Dangerous Data Network'), variable=self.out_eddn, command=self.outvarchanged).grid(row=1, columnspan=2, padx=5, sticky=tk.W)
|
||||
self.out_csv = tk.IntVar(value = (output & config.OUT_CSV ) and 1 or 0)
|
||||
ttk.Checkbutton(outframe, text=_('Market data in CSV format file'), variable=self.out_csv, command=self.outvarchanged).grid(row=2, columnspan=2, padx=5, sticky=tk.W)
|
||||
self.out_bpc = tk.IntVar(value = (output & config.OUT_BPC ) and 1 or 0)
|
||||
ttk.Checkbutton(outframe, text=_("Market data in Slopey's BPC format file"), variable=self.out_bpc, command=self.outvarchanged).grid(row=3, columnspan=2, padx=5, sticky=tk.W)
|
||||
self.out_td = tk.IntVar(value = (output & config.OUT_TD ) and 1 or 0)
|
||||
ttk.Checkbutton(outframe, text=_('Market data in Trade Dangerous format file'), variable=self.out_td, command=self.outvarchanged).grid(row=4, columnspan=2, padx=5, sticky=tk.W)
|
||||
self.out_ship_eds= tk.IntVar(value = (output & config.OUT_SHIP_EDS) and 1 or 0)
|
||||
ttk.Checkbutton(outframe, text=_('Ship loadout in E:D Shipyard format file'), variable=self.out_ship_eds, command=self.outvarchanged).grid(row=5, columnspan=2, padx=5, pady=(5,0), sticky=tk.W)
|
||||
self.out_ship_coriolis= tk.IntVar(value = (output & config.OUT_SHIP_CORIOLIS) and 1 or 0)
|
||||
ttk.Checkbutton(outframe, text=_('Ship loadout in Coriolis format file'), variable=self.out_ship_coriolis, command=self.outvarchanged).grid(row=6, columnspan=2, padx=5, sticky=tk.W)
|
||||
self.out_log_edsm = tk.IntVar(value = (output & config.OUT_LOG_EDSM ) and 1 or 0)
|
||||
ttk.Checkbutton(outframe, text=_('Send flight log to Elite Dangerous Star Map'), variable=self.out_log_edsm, command=self.outvarchanged).grid(row=7, columnspan=2, padx=5, pady=(5,0), sticky=tk.W)
|
||||
self.out_log_file = tk.IntVar(value = (output & config.OUT_LOG_FILE ) and 1 or 0)
|
||||
ttk.Checkbutton(outframe, text=_('Flight log in CSV format file'), variable=self.out_log_file, command=self.outvarchanged).grid(row=8, columnspan=2, padx=5, sticky=tk.W)
|
||||
ttk.Label(outframe, text=_('Please choose what data to save')).grid(row=0, padx=5, pady=3, sticky=tk.W)
|
||||
self.out_eddn= tk.IntVar(value = (output & config.OUT_EDDN) and 1)
|
||||
ttk.Checkbutton(outframe, text=_('Send station data to the Elite Dangerous Data Network'), variable=self.out_eddn, command=self.outvarchanged).grid(row=1, padx=5, sticky=tk.W)
|
||||
self.out_csv = tk.IntVar(value = (output & config.OUT_CSV ) and 1)
|
||||
ttk.Checkbutton(outframe, text=_('Market data in CSV format file'), variable=self.out_csv, command=self.outvarchanged).grid(row=2, padx=5, sticky=tk.W)
|
||||
self.out_bpc = tk.IntVar(value = (output & config.OUT_BPC ) and 1)
|
||||
ttk.Checkbutton(outframe, text=_("Market data in Slopey's BPC format file"), variable=self.out_bpc, command=self.outvarchanged).grid(row=3, padx=5, sticky=tk.W)
|
||||
self.out_td = tk.IntVar(value = (output & config.OUT_TD ) and 1)
|
||||
ttk.Checkbutton(outframe, text=_('Market data in Trade Dangerous format file'), variable=self.out_td, command=self.outvarchanged).grid(row=4, padx=5, sticky=tk.W)
|
||||
self.out_ship_eds= tk.IntVar(value = (output & config.OUT_SHIP_EDS) and 1)
|
||||
ttk.Checkbutton(outframe, text=_('Ship loadout in E:D Shipyard format file'), variable=self.out_ship_eds, command=self.outvarchanged).grid(row=5, padx=5, pady=(5,0), sticky=tk.W)
|
||||
self.out_ship_coriolis= tk.IntVar(value = (output & config.OUT_SHIP_CORIOLIS) and 1)
|
||||
ttk.Checkbutton(outframe, text=_('Ship loadout in Coriolis format file'), variable=self.out_ship_coriolis, command=self.outvarchanged).grid(row=6, padx=5, sticky=tk.W)
|
||||
self.out_log_edsm = tk.IntVar(value = (output & config.OUT_LOG_EDSM) and 1)
|
||||
ttk.Checkbutton(outframe, text=_('Send flight log to Elite Dangerous Star Map'), variable=self.out_log_edsm, command=self.outvarchanged).grid(row=7, padx=5, pady=(5,0), sticky=tk.W)
|
||||
self.out_log_file = tk.IntVar(value = (output & config.OUT_LOG_FILE) and 1)
|
||||
ttk.Checkbutton(outframe, text=_('Flight log in CSV format file'), variable=self.out_log_file, command=self.outvarchanged).grid(row=8, padx=5, sticky=tk.W)
|
||||
self.out_log_auto = tk.IntVar(value = monitor.logdir and (output & config.OUT_LOG_AUTO) and 1 or 0)
|
||||
if monitor.logdir:
|
||||
self.out_log_auto_button = ttk.Checkbutton(outframe, text=_('Automatically make a log entry on entering a system'), variable=self.out_log_auto, command=self.outvarchanged) # Output setting
|
||||
self.out_log_auto_button.grid(row=9, padx=5, sticky=tk.W)
|
||||
self.out_log_auto_text = ttk.Label(outframe)
|
||||
|
||||
self.dir_label = ttk.Label(frame, text=_('File location'), foreground=style.lookup('TLabelframe.Label', 'foreground')) # Section heading in settings
|
||||
dirframe = ttk.LabelFrame(frame, labelwidget = self.dir_label)
|
||||
dirframe.grid(padx=10, pady=10, sticky=tk.NSEW)
|
||||
dirframe.grid(padx=10, pady=5, sticky=tk.NSEW)
|
||||
dirframe.columnconfigure(0, weight=1)
|
||||
|
||||
self.outdir = ttk.Entry(dirframe, takefocus=False)
|
||||
@ -128,7 +134,7 @@ class PreferencesDialog(tk.Toplevel):
|
||||
|
||||
self.edsm_label = HyperlinkLabel(frame, text=_('Elite Dangerous Star Map credentials'), disabledforeground=style.lookup('TLabelframe.Label', 'foreground'), url='http://www.edsm.net/settings/api', underline=True) # Section heading in settings
|
||||
edsmframe = ttk.LabelFrame(frame, labelwidget = self.edsm_label)
|
||||
edsmframe.grid(padx=10, pady=10, sticky=tk.NSEW)
|
||||
edsmframe.grid(padx=10, pady=5, sticky=tk.NSEW)
|
||||
edsmframe.columnconfigure(1, weight=1)
|
||||
|
||||
ttk.Label(edsmframe, text=_('Cmdr name')).grid(row=0, sticky=tk.W) # EDSM & privacy setting
|
||||
@ -151,7 +157,7 @@ class PreferencesDialog(tk.Toplevel):
|
||||
self.hotkey_play = tk.IntVar(value = not config.getint('hotkey_mute'))
|
||||
hotkeyframe = ttk.LabelFrame(frame, text=platform == 'darwin' and _('Keyboard shortcut') or # Section heading in settings on OSX
|
||||
_('Hotkey')) # Section heading in settings on Windows
|
||||
hotkeyframe.grid(padx=10, pady=10, sticky=tk.NSEW)
|
||||
hotkeyframe.grid(padx=10, pady=5, sticky=tk.NSEW)
|
||||
hotkeyframe.columnconfigure(1, weight=1)
|
||||
if platform == 'darwin' and not was_accessible_at_launch:
|
||||
if AXIsProcessTrusted():
|
||||
@ -171,10 +177,10 @@ class PreferencesDialog(tk.Toplevel):
|
||||
self.hotkey_play_btn.grid(row=2, columnspan=2, padx=5, sticky=tk.W)
|
||||
|
||||
privacyframe = ttk.LabelFrame(frame, text=_('Privacy')) # Section heading in settings
|
||||
privacyframe.grid(padx=10, pady=10, sticky=tk.NSEW)
|
||||
privacyframe.grid(padx=10, pady=5, sticky=tk.NSEW)
|
||||
|
||||
self.out_anon= tk.IntVar(value = config.getint('anonymous') and 1)
|
||||
ttk.Label(privacyframe, text=_('How do you want to be identified in the saved data')).grid(row=0, columnspan=2, padx=5, sticky=tk.W)
|
||||
ttk.Label(privacyframe, text=_('How do you want to be identified in the saved data')).grid(row=0, padx=5, sticky=tk.W)
|
||||
ttk.Radiobutton(privacyframe, text=_('Cmdr name'), variable=self.out_anon, value=0).grid(padx=5, sticky=tk.W) # Privacy setting
|
||||
ttk.Radiobutton(privacyframe, text=_('Pseudo-anonymized ID'), variable=self.out_anon, value=1).grid(padx=5, sticky=tk.W) # Privacy setting
|
||||
|
||||
@ -182,17 +188,20 @@ class PreferencesDialog(tk.Toplevel):
|
||||
self.protocol("WM_DELETE_WINDOW", self.apply) # close button applies changes
|
||||
else:
|
||||
buttonframe = ttk.Frame(frame)
|
||||
buttonframe.grid(padx=10, pady=10, sticky=tk.NSEW)
|
||||
buttonframe.grid(padx=10, pady=5, sticky=tk.NSEW)
|
||||
buttonframe.columnconfigure(0, weight=1)
|
||||
ttk.Label(buttonframe).grid(row=0, column=0) # spacer
|
||||
ttk.Button(buttonframe, text=_('OK'), command=self.apply).grid(row=0, column=1, sticky=tk.E)
|
||||
button = ttk.Button(buttonframe, text=_('OK'), command=self.apply)
|
||||
button.grid(row=0, column=1, sticky=tk.E)
|
||||
button.bind("<Return>", lambda event:self.apply())
|
||||
self.protocol("WM_DELETE_WINDOW", self._destroy)
|
||||
|
||||
# Selectively disable buttons depending on output settings
|
||||
self.outvarchanged()
|
||||
|
||||
# disable hotkey for the duration
|
||||
# disable hotkey and log monitoring for the duration
|
||||
hotkeymgr.unregister()
|
||||
monitor.stop()
|
||||
|
||||
# wait for window to appear on screen before calling grab_set
|
||||
self.wait_visibility()
|
||||
@ -205,6 +214,20 @@ class PreferencesDialog(tk.Toplevel):
|
||||
self.outbutton['state'] = local and tk.NORMAL or tk.DISABLED
|
||||
self.outdir['state'] = local and 'readonly' or tk.DISABLED
|
||||
|
||||
if monitor.logdir:
|
||||
log = self.out_log_edsm.get() or self.out_log_file.get()
|
||||
self.out_log_auto_button['state'] = log and tk.NORMAL or tk.DISABLED
|
||||
|
||||
self.out_log_auto_text['text'] = ''
|
||||
if log and self.out_log_auto.get():
|
||||
if not monitor.enable_logging():
|
||||
self.out_log_auto_text['text'] = "Can't enable automatic logging!" # Shouldn't happen - don't translate
|
||||
self.out_log_auto_text.grid(row=10, padx=(25,5), sticky=tk.EW)
|
||||
elif monitor.restart_required():
|
||||
self.out_log_auto_text['text'] = _('Re-start Elite: Dangerous for automatic logging') # Output settings prompt
|
||||
self.out_log_auto_text.grid(row=10, padx=(25,5), sticky=tk.EW)
|
||||
|
||||
|
||||
edsm = self.out_log_edsm.get()
|
||||
self.edsm_label['state'] = edsm and tk.NORMAL or tk.DISABLED
|
||||
self.edsm_cmdr['state'] = edsm and tk.NORMAL or tk.DISABLED
|
||||
@ -290,7 +313,7 @@ class PreferencesDialog(tk.Toplevel):
|
||||
config.set('username', self.username.get().strip())
|
||||
config.set('password', self.password.get().strip())
|
||||
|
||||
config.set('output', (self.out_eddn.get() and config.OUT_EDDN or 0) + (self.out_bpc.get() and config.OUT_BPC or 0) + (self.out_td.get() and config.OUT_TD or 0) + (self.out_csv.get() and config.OUT_CSV or 0) + (self.out_ship_eds.get() and config.OUT_SHIP_EDS or 0) + (self.out_log_file.get() and config.OUT_LOG_FILE or 0) + (self.out_ship_coriolis.get() and config.OUT_SHIP_CORIOLIS or 0) + (self.out_log_edsm.get() and config.OUT_LOG_EDSM or 0))
|
||||
config.set('output', (self.out_eddn.get() and config.OUT_EDDN) + (self.out_bpc.get() and config.OUT_BPC) + (self.out_td.get() and config.OUT_TD) + (self.out_csv.get() and config.OUT_CSV) + (self.out_ship_eds.get() and config.OUT_SHIP_EDS) + (self.out_log_file.get() and config.OUT_LOG_FILE) + (self.out_ship_coriolis.get() and config.OUT_SHIP_CORIOLIS) + (self.out_log_edsm.get() and config.OUT_LOG_EDSM) + (self.out_log_auto.get() and config.OUT_LOG_AUTO))
|
||||
config.set('outdir', expanduser(self.outdir.get()))
|
||||
|
||||
config.set('edsm_cmdrname', self.edsm_cmdr.get().strip())
|
||||
@ -309,8 +332,11 @@ class PreferencesDialog(tk.Toplevel):
|
||||
self.callback()
|
||||
|
||||
def _destroy(self):
|
||||
# Re-enable hotkey monitoring before exit
|
||||
# Re-enable hotkey and log monitoring before exit
|
||||
hotkeymgr.register(self.parent, config.getint('hotkey_code'), config.getint('hotkey_mods'))
|
||||
if (config.getint('output') & config.OUT_LOG_AUTO) and (config.getint('output') & (config.OUT_LOG_AUTO|config.OUT_LOG_EDSM)):
|
||||
monitor.enable_logging()
|
||||
monitor.start()
|
||||
self.destroy()
|
||||
|
||||
if platform == 'darwin':
|
||||
@ -371,6 +397,7 @@ class AuthenticationDialog(tk.Toplevel):
|
||||
self.code.focus_set()
|
||||
ttk.Label(frame).grid(row=1, column=2) # spacer
|
||||
self.button = ttk.Button(frame, text=_('OK'), command=self.apply, state=tk.DISABLED)
|
||||
self.button.bind("<Return>", lambda event:self.apply())
|
||||
self.button.grid(row=1, column=3, sticky=tk.E)
|
||||
|
||||
for child in frame.winfo_children():
|
||||
|
Loading…
x
Reference in New Issue
Block a user