1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-04-14 08:17:13 +03:00

Multi-account support

Fixes #121
This commit is contained in:
Jonathan Harris 2017-01-21 21:40:15 +00:00
parent d7aae5dee3
commit a67eb982d8
8 changed files with 201 additions and 92 deletions

View File

@ -82,7 +82,10 @@ try:
config.set('querytime', getmtime(args.j))
else:
session = companion.Session()
session.login(config.get('username'), config.get('password'))
if config.get('cmdrs'):
session.login(config.get('fdev_usernames')[0], config.get('fdev_passwords')[0])
else: # <= 2.25 not yet migrated
session.login(config.get('username'), config.get('password'))
querytime = int(time())
data = session.query()
config.set('querytime', querytime)

View File

@ -236,8 +236,6 @@ class AppWindow:
theme.register(self.theme_close)
theme.register_alternate((self.menubar, self.theme_menubar), {'row':0, 'columnspan':2, 'sticky':tk.NSEW})
self.set_labels()
# update geometry
if config.get('geometry'):
match = re.match('\+([\-\d]+)\+([\-\d]+)', config.get('geometry'))
@ -274,17 +272,25 @@ class AppWindow:
# Load updater after UI creation (for WinSparkle)
import update
self.updater = update.Updater(self.w)
if not getattr(sys, 'frozen', False):
self.updater.checkForUpdates() # Sparkle / WinSparkle does this automatically for packaged apps
# First run
if not config.get('username') or not config.get('password'):
prefs.PreferencesDialog(self.w, self.postprefs)
else:
self.login()
self.postprefs() # Companion login happens in callback from monitor
# Try to obtain exclusive lock on journal cache, even if we don't need it yet
if not eddn.load():
self.status['text'] = 'Error: Is another copy of this app already running?' # Shouldn't happen - don't bother localizing
# callback after the Preferences dialog is applied
def postprefs(self):
self.set_labels() # in case language has changed
self.login() # in case credentials gave changed
# (Re-)install hotkey monitoring
hotkeymgr.register(self.w, config.getint('hotkey_code'), config.getint('hotkey_mods'))
# (Re-)install log monitoring
if not monitor.start(self.w):
self.status['text'] = 'Error: Check %s' % _('E:D journal file location') # Location of the new Journal file in E:D 2.2
# set main window labels, e.g. after language change
def set_labels(self):
@ -321,11 +327,15 @@ class AppWindow:
self.edit_menu.entryconfigure(0, label=_('Copy')) # As in Copy and Paste
def login(self):
self.status['text'] = _('Logging in...')
if not self.status['text']:
self.status['text'] = _('Logging in...')
self.button['state'] = self.theme_button['state'] = tk.DISABLED
self.w.update_idletasks()
try:
self.session.login(config.get('username'), config.get('password'))
if not monitor.cmdr or monitor.cmdr not in config.get('cmdrs'):
raise companion.CredentialsError()
idx = config.get('cmdrs').index(monitor.cmdr)
self.session.login(config.get('fdev_usernames')[idx], config.get('fdev_passwords')[idx])
self.status['text'] = ''
except companion.VerificationRequired:
return prefs.AuthenticationDialog(self.w, partial(self.verify, self.login))
@ -334,21 +344,6 @@ class AppWindow:
except Exception as e:
if __debug__: print_exc()
self.status['text'] = unicode(e)
if not getattr(sys, 'frozen', False):
self.updater.checkForUpdates() # Sparkle / WinSparkle does this automatically for packaged apps
# Try to obtain exclusive lock on journal cache, even if we don't need it yet
if not eddn.load():
self.status['text'] = 'Error: Is another copy of this app already running?' # Shouldn't happen - don't bother localizing
# (Re-)install hotkey monitoring
hotkeymgr.register(self.w, config.getint('hotkey_code'), config.getint('hotkey_mods'))
# (Re-)install log monitoring
if not monitor.start(self.w):
self.status['text'] = 'Error: Check %s' % _('E:D journal file location') # Location of the new Journal file in E:D 2.2
self.cooldown()
# callback after verification code
@ -368,7 +363,7 @@ class AppWindow:
auto_update = not event
play_sound = (auto_update or int(event.type) == self.EVENT_VIRTUAL) and not config.getint('hotkey_mute')
if (monitor.cmdr and not monitor.mode) or monitor.is_beta:
if not monitor.cmdr or not monitor.mode or monitor.is_beta:
return # In CQC or Beta - do nothing
if not retrying:
@ -478,7 +473,7 @@ class AppWindow:
self.status['text'] = ''
# Update credits and ship info and send to EDSM
if config.getint('output') & config.OUT_SYS_EDSM and not monitor.is_beta:
if config.getint('output') & config.OUT_SYS_EDSM:
try:
if data['commander'].get('credits') is not None:
monitor.credits = (data['commander']['credits'], data['commander'].get('debt', 0))
@ -568,13 +563,25 @@ class AppWindow:
self.edsm.link(monitor.system)
self.w.update_idletasks()
# New Cmdr?
if entry['event'] in [None, 'NewCommander', 'LoadGame'] and monitor.cmdr and not monitor.is_beta:
prefs.migrate(monitor.cmdr) # migration from <= 2.25
if config.get('cmdrs') and monitor.cmdr in config.get('cmdrs'):
prefs.make_current(monitor.cmdr)
elif config.get('cmdrs') and entry['event'] == 'NewCommander':
cmdrs = config.get('cmdrs')
cmdrs[0] = monitor.cmdr # New Cmdr uses same credentials as old
config.set('cmdrs', cmdrs)
else:
prefs.PreferencesDialog(self.w, self.postprefs) # First run or new Cmdr
# Send interesting events to EDSM
if config.getint('output') & config.OUT_SYS_EDSM and not monitor.is_beta:
self.status['text'] = _('Sending data to EDSM...')
self.w.update_idletasks()
try:
# Update system status on startup
if monitor.mode and not entry['event']:
if monitor.mode and monitor.system and not entry['event']:
self.edsm.lookup(monitor.system)
# Send credits to EDSM on new game (but not on startup - data might be old)
@ -609,6 +616,10 @@ class AppWindow:
self.status['text'] = ''
self.edsmpoll()
# Companion login - do this after EDSM so any EDSM errors don't mask login errors
if entry['event'] in [None, 'LoadGame'] and monitor.cmdr and not monitor.is_beta:
self.login()
if not entry['event'] or not monitor.mode:
return # Startup or in CQC
@ -688,7 +699,7 @@ class AppWindow:
def shipyard_url(self, shipname=None):
if (monitor.cmdr and not monitor.mode) or monitor.is_beta:
if not monitor.cmdr or not monitor.mode or monitor.is_beta:
return False # In CQC or Beta - do nothing
self.status['text'] = _('Fetching data...')

View File

@ -144,6 +144,9 @@ If 2 this problem may or may not resolve itself in time.
This problem is tracked as [Issue #165](https://github.com/Marginal/EDMarketConnector/issues/165).
### Credentials settings are greyed out
You can't edit your Username/Password or EDSM Commander Name/API Key while Elite: Dangerous is at the Main Menu. You will be able to edit these values once you've entered the game.
### Error: Can't connect to EDDN
EDMC needs to talk to eddn-gateway.elite-markets.net on port 8080. If you consistently receive this error check that your router or VPN configuration allows port 8080 / tcp outbound.

View File

@ -1,9 +1,10 @@
import requests
from collections import defaultdict
from cookielib import LWPCookieJar
import hashlib
import numbers
import os
from os.path import dirname, join
from os.path import dirname, isfile, join
import sys
from sys import platform
import time
@ -178,6 +179,7 @@ class Session:
def __init__(self):
self.state = Session.STATE_INIT
self.credentials = None
self.session = None
# yuck suppress InsecurePlatformWarning under Python < 2.7.9 which lacks SNI support
try:
@ -189,14 +191,6 @@ class Session:
if platform=='win32' and getattr(sys, 'frozen', False):
os.environ['REQUESTS_CA_BUNDLE'] = join(dirname(sys.executable), 'cacert.pem')
self.session = requests.Session()
self.session.headers['User-Agent'] = 'Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Mobile/11D257'
self.session.cookies = LWPCookieJar(join(config.app_dir, 'cookies.txt'))
try:
self.session.cookies.load()
except IOError:
pass
def login(self, username=None, password=None):
if (not username or not password):
if not self.credentials:
@ -208,8 +202,20 @@ class Session:
if self.credentials == credentials and self.state == Session.STATE_OK:
return # already logged in
if self.credentials and self.credentials['email'] != credentials['email']: # changed account
self.session.cookies.clear()
if not self.credentials or self.credentials['email'] != credentials['email']: # changed account
self.close()
self.session = requests.Session()
self.session.headers['User-Agent'] = 'Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Mobile/11D257'
cookiefile = join(config.app_dir, 'cookies-%s.txt' % hashlib.md5(credentials['email']).hexdigest())
if not isfile(cookiefile) and isfile(join(config.app_dir, 'cookies.txt')):
os.rename(join(config.app_dir, 'cookies.txt'), cookiefile) # migration from <= 2.25
self.session.cookies = LWPCookieJar(cookiefile)
try:
self.session.cookies.load()
except IOError:
pass
self.credentials = credentials
self.state = Session.STATE_INIT
try:
@ -237,7 +243,7 @@ class Session:
r = self.session.post(URL_CONFIRM, data = {'code' : code}, timeout=timeout)
if r.status_code != requests.codes.ok or r.url == URL_CONFIRM: # would have redirected away if success
raise VerificationRequired()
self.save() # Save cookies now for use by command-line app
self.session.cookies.save() # Save cookies now for use by command-line app
self.login()
def query(self):
@ -270,16 +276,14 @@ class Session:
return data
def save(self):
self.session.cookies.save()
def close(self):
self.state = Session.STATE_NONE
try:
self.session.cookies.save()
self.session.close()
except:
pass
if self.session:
try:
self.session.cookies.save()
self.session.close()
except:
if __debug__: print_exc()
self.session = None
def dump(self, r):

View File

@ -7,6 +7,7 @@ import urllib2
import Tkinter as tk
from config import appname, applongname, appversion, config
from monitor import monitor
if __debug__:
from traceback import print_exc
@ -79,10 +80,11 @@ class EDSM:
# Call an EDSM endpoint with args (which should be quoted)
def call(self, endpoint, args, check_msgnum=True):
try:
idx = config.get('cmdrs').index(monitor.cmdr)
url = 'https://www.edsm.net/%s?commanderName=%s&apiKey=%s&fromSoftware=%s&fromSoftwareVersion=%s' % (
endpoint,
urllib2.quote(config.get('edsm_cmdrname').encode('utf-8')),
urllib2.quote(config.get('edsm_apikey')),
urllib2.quote(config.get('edsm_usernames')[idx].encode('utf-8')),
urllib2.quote(config.get('edsm_apikeys')[idx]),
urllib2.quote(applongname),
urllib2.quote(appversion),
) + args

View File

@ -106,7 +106,7 @@ class EDLogs(FileSystemEventHandler):
# Latest pre-existing logfile - e.g. if E:D is already running. Assumes logs sort alphabetically.
# Do this before setting up the observer in case the journal directory has gone away
try:
logfiles = sorted([x for x in listdir(self.currentdir) if x.startswith('Journal.')])
logfiles = sorted([x for x in listdir(self.currentdir) if x.startswith('Journal.') and x.endswith('.log')])
self.logfile = logfiles and join(self.currentdir, logfiles[-1]) or None
except:
self.logfile = None
@ -129,6 +129,8 @@ class EDLogs(FileSystemEventHandler):
print '%s "%s"' % (polling and 'Polling' or 'Monitoring', self.currentdir)
print 'Start logfile "%s"' % self.logfile
self.event_queue.append(None) # Generate null event to signal (re)start
if not self.running():
self.thread = threading.Thread(target = self.worker, name = 'Journal worker')
self.thread.daemon = True
@ -181,8 +183,6 @@ class EDLogs(FileSystemEventHandler):
except:
if __debug__:
print 'Invalid journal entry "%s"' % repr(line)
self.event_queue.append(None) # Generate null event to signal start
self.root.event_generate('<<JournalEvent>>', when="tail")
else:
loghandle = None

156
prefs.py
View File

@ -80,12 +80,13 @@ class PreferencesDialog(tk.Toplevel):
parent.call('tk::unsupported::MacWindowStyle', 'style', self, 'utility')
self.resizable(tk.FALSE, tk.FALSE)
style = ttk.Style()
self.cmdr = None # Note if Cmdr changes in the Journal
frame = ttk.Frame(self)
frame.grid(sticky=tk.NSEW)
notebook = nb.Notebook(frame)
notebook.bind('<<NotebookTabChanged>>', self.outvarchanged) # Recompute on tab change
PADX = 10
BUTTONX = 12 # indent Checkbuttons and Radiobuttons
@ -96,17 +97,23 @@ class PreferencesDialog(tk.Toplevel):
nb.Label(credframe, text=_('Credentials')).grid(padx=PADX, sticky=tk.W) # Section heading in settings
ttk.Separator(credframe, orient=tk.HORIZONTAL).grid(columnspan=2, padx=PADX, pady=PADY, sticky=tk.EW)
nb.Label(credframe, text=_('Please log in with your Elite: Dangerous account details')).grid(padx=PADX, columnspan=2, sticky=tk.W) # Use same text as E:D Launcher's login dialog
nb.Label(credframe, text=_('Username (Email)')).grid(row=10, padx=PADX, sticky=tk.W) # Use same text as E:D Launcher's login dialog
nb.Label(credframe, text=_('Password')).grid(row=11, padx=PADX, sticky=tk.W) # Use same text as E:D Launcher's login dialog
self.cred_label = nb.Label(credframe, text=_('Please log in with your Elite: Dangerous account details')) # Use same text as E:D Launcher's login dialog
self.cred_label.grid(padx=PADX, columnspan=2, sticky=tk.W)
self.cmdr_label = nb.Label(credframe, text=_('Cmdr')) # Main window
self.cmdr_label.grid(row=10, padx=PADX, sticky=tk.W)
self.username_label = nb.Label(credframe, text=_('Username (Email)')) # Use same text as E:D Launcher's login dialog
self.username_label.grid(row=11, padx=PADX, sticky=tk.W)
self.password_label = nb.Label(credframe, text=_('Password')) # Use same text as E:D Launcher's login dialog
self.password_label.grid(row=12, padx=PADX, sticky=tk.W)
self.cmdr_text = nb.Label(credframe, text=_('None')) # No hotkey/shortcut currently defined
self.cmdr_text.grid(row=10, column=1, padx=PADX, pady=PADY, sticky=tk.W)
self.username = nb.Entry(credframe)
self.username.insert(0, config.get('username') or '')
self.username.grid(row=10, column=1, padx=PADX, pady=PADY, sticky=tk.EW)
self.username.focus_set()
self.username.grid(row=11, column=1, padx=PADX, pady=PADY, sticky=tk.EW)
if not monitor.is_beta and monitor.cmdr:
self.username.focus_set()
self.password = nb.Entry(credframe, show=u'')
self.password.insert(0, config.get('password') or '')
self.password.grid(row=11, column=1, padx=PADX, pady=PADY, sticky=tk.EW)
self.password.grid(row=12, column=1, padx=PADX, pady=PADY, sticky=tk.EW)
nb.Label(credframe).grid(sticky=tk.W) # big spacer
nb.Label(credframe, text=_('Privacy')).grid(padx=PADX, sticky=tk.W) # Section heading in settings
@ -125,13 +132,17 @@ class PreferencesDialog(tk.Toplevel):
output = config.getint('output') or (config.OUT_MKT_EDDN | config.OUT_SYS_EDDN | config.OUT_SHIP) # default settings
nb.Label(outframe, text=_('Please choose what data to save')).grid(columnspan=2, padx=PADX, sticky=tk.W)
self.out_label = nb.Label(outframe, text=_('Please choose what data to save'))
self.out_label.grid(columnspan=2, padx=PADX, sticky=tk.W)
self.out_csv = tk.IntVar(value = (output & config.OUT_MKT_CSV ) and 1)
nb.Checkbutton(outframe, text=_('Market data in CSV format file'), variable=self.out_csv, command=self.outvarchanged).grid(columnspan=2, padx=BUTTONX, sticky=tk.W)
self.out_csv_button = nb.Checkbutton(outframe, text=_('Market data in CSV format file'), variable=self.out_csv, command=self.outvarchanged)
self.out_csv_button.grid(columnspan=2, padx=BUTTONX, sticky=tk.W)
self.out_td = tk.IntVar(value = (output & config.OUT_MKT_TD ) and 1)
nb.Checkbutton(outframe, text=_('Market data in Trade Dangerous format file'), variable=self.out_td, command=self.outvarchanged).grid(columnspan=2, padx=BUTTONX, sticky=tk.W)
self.out_td_button = nb.Checkbutton(outframe, text=_('Market data in Trade Dangerous format file'), variable=self.out_td, command=self.outvarchanged)
self.out_td_button.grid(columnspan=2, padx=BUTTONX, sticky=tk.W)
self.out_ship= tk.IntVar(value = (output & (config.OUT_SHIP|config.OUT_SHIP_EDS|config.OUT_SHIP_CORIOLIS) and 1))
nb.Checkbutton(outframe, text=_('Ship loadout'), variable=self.out_ship, command=self.outvarchanged).grid(columnspan=2, padx=BUTTONX, pady=(5,0), sticky=tk.W) # Output setting
self.out_ship_button = nb.Checkbutton(outframe, text=_('Ship loadout'), variable=self.out_ship, command=self.outvarchanged) # Output setting
self.out_ship_button.grid(columnspan=2, padx=BUTTONX, pady=(5,0), sticky=tk.W)
self.out_auto = tk.IntVar(value = 0 if output & config.OUT_MKT_MANUAL else 1) # inverted
self.out_auto_button = nb.Checkbutton(outframe, text=_('Automatically update on docking'), variable=self.out_auto, command=self.outvarchanged) # Output setting
self.out_auto_button.grid(columnspan=2, padx=BUTTONX, pady=(5,0), sticky=tk.W)
@ -155,7 +166,8 @@ class PreferencesDialog(tk.Toplevel):
HyperlinkLabel(eddnframe, text='Elite Dangerous Data Network', background=nb.Label().cget('background'), url='https://github.com/jamesremuscat/EDDN/wiki', underline=True).grid(padx=PADX, sticky=tk.W) # Don't translate
self.eddn_station= tk.IntVar(value = (output & config.OUT_MKT_EDDN) and 1)
nb.Checkbutton(eddnframe, text=_('Send station data to the Elite Dangerous Data Network'), variable=self.eddn_station, command=self.outvarchanged).grid(padx=BUTTONX, pady=(5,0), sticky=tk.W) # Output setting
self.eddn_station_button = nb.Checkbutton(eddnframe, text=_('Send station data to the Elite Dangerous Data Network'), variable=self.eddn_station, command=self.outvarchanged) # Output setting
self.eddn_station_button.grid(padx=BUTTONX, pady=(5,0), sticky=tk.W)
self.eddn_auto_button = nb.Checkbutton(eddnframe, text=_('Automatically update on docking'), variable=self.out_auto, command=self.outvarchanged) # Output setting
self.eddn_auto_button.grid(padx=BUTTONX, sticky=tk.W)
self.eddn_system = tk.IntVar(value = (output & config.OUT_SYS_EDDN) and 1)
@ -180,17 +192,20 @@ class PreferencesDialog(tk.Toplevel):
self.edsm_label = HyperlinkLabel(edsmframe, text=_('Elite Dangerous Star Map credentials'), background=nb.Label().cget('background'), url='https://www.edsm.net/settings/api', underline=True) # Section heading in settings
self.edsm_label.grid(columnspan=2, padx=PADX, sticky=tk.W)
self.edsm_cmdr_label = nb.Label(edsmframe, text=_('Commander Name')) # EDSM setting
self.edsm_cmdr_label = nb.Label(edsmframe, text=_('Cmdr')) # Main window
self.edsm_cmdr_label.grid(row=10, padx=PADX, sticky=tk.W)
self.edsm_cmdr = nb.Entry(edsmframe)
self.edsm_cmdr.insert(0, config.get('edsm_cmdrname') or '')
self.edsm_cmdr.grid(row=10, column=1, padx=PADX, pady=PADY, sticky=tk.EW)
self.edsm_cmdr_text = nb.Label(edsmframe, text=_('None')) # No hotkey/shortcut currently defined
self.edsm_cmdr_text.grid(row=10, column=1, padx=PADX, pady=PADY, sticky=tk.W)
self.edsm_user_label = nb.Label(edsmframe, text=_('Commander Name')) # EDSM setting
self.edsm_user_label.grid(row=11, padx=PADX, sticky=tk.W)
self.edsm_user = nb.Entry(edsmframe)
self.edsm_user.grid(row=11, column=1, padx=PADX, pady=PADY, sticky=tk.EW)
self.edsm_apikey_label = nb.Label(edsmframe, text=_('API Key')) # EDSM setting
self.edsm_apikey_label.grid(row=11, padx=PADX, sticky=tk.W)
self.edsm_apikey_label.grid(row=12, padx=PADX, sticky=tk.W)
self.edsm_apikey = nb.Entry(edsmframe)
self.edsm_apikey.insert(0, config.get('edsm_apikey') or '')
self.edsm_apikey.grid(row=11, column=1, padx=PADX, pady=PADY, sticky=tk.EW)
self.edsm_apikey.grid(row=12, column=1, padx=PADX, pady=PADY, sticky=tk.EW)
notebook.add(edsmframe, text='EDSM') # Not translated
@ -321,30 +336,57 @@ class PreferencesDialog(tk.Toplevel):
0x10000, None, position):
self.geometry("+%d+%d" % (position.left, position.top))
def outvarchanged(self):
def outvarchanged(self, event=None):
self.cmdr_text['state'] = self.edsm_cmdr_text['state'] = tk.NORMAL # must be writable to update
self.cmdr_text['text'] = self.edsm_cmdr_text['text'] = monitor.cmdr and monitor.is_beta and ('%s [Beta]' % monitor.cmdr) or monitor.cmdr or _('None') # No hotkey/shortcut currently defined
if self.cmdr != monitor.cmdr:
# Cmdr has changed - update settings
if not monitor.is_beta:
migrate(monitor.cmdr) # migration from <= 2.25
if monitor.cmdr and config.get('cmdrs') and monitor.cmdr in config.get('cmdrs'):
config_idx = config.get('cmdrs').index(monitor.cmdr)
else:
config_idx = None
self.username['state'] = tk.NORMAL
self.username.delete(0, tk.END)
self.username.insert(0, config_idx is not None and config.get('fdev_usernames')[config_idx] or '')
self.password['state'] = tk.NORMAL
self.password.delete(0, tk.END)
self.password.insert(0, config_idx is not None and config.get('fdev_passwords')[config_idx] or '')
self.edsm_user['state'] = tk.NORMAL
self.edsm_user.delete(0, tk.END)
self.edsm_user.insert(0, config_idx is not None and config.get('edsm_usernames')[config_idx] or '')
self.edsm_apikey['state'] = tk.NORMAL
self.edsm_apikey.delete(0, tk.END)
self.edsm_apikey.insert(0, config_idx is not None and config.get('edsm_apikeys')[config_idx] or '')
self.cmdr = monitor.cmdr
cmdr_state = not monitor.is_beta and monitor.cmdr and tk.NORMAL or tk.DISABLED
self.cred_label['state'] = self.cmdr_label['state'] = self.username_label['state'] = self.password_label['state'] = cmdr_state
self.cmdr_text['state'] = self.username['state'] = self.password['state'] = cmdr_state
self.displaypath(self.outdir, self.outdir_entry)
self.displaypath(self.logdir, self.logdir_entry)
logdir = self.logdir.get()
logvalid = logdir and exists(logdir)
local = self.out_td.get() or self.out_csv.get() or self.out_ship.get()
self.out_auto_button['state'] = local and logvalid and not monitor.is_beta and tk.NORMAL or tk.DISABLED
self.out_label['state'] = self.out_csv_button['state'] = self.out_td_button['state'] = self.out_ship_button['state'] = not monitor.is_beta and tk.NORMAL or tk.DISABLED
local = not monitor.is_beta and (self.out_td.get() or self.out_csv.get() or self.out_ship.get())
self.out_auto_button['state'] = local and logvalid and tk.NORMAL or tk.DISABLED
self.outdir_label['state'] = local and tk.NORMAL or tk.DISABLED
self.outbutton['state'] = local and tk.NORMAL or tk.DISABLED
self.outdir_entry['state'] = local and 'readonly' or tk.DISABLED
self.eddn_station_button['state'] = not monitor.is_beta and tk.NORMAL or tk.DISABLED
self.eddn_auto_button['state'] = self.eddn_station.get() and logvalid and not monitor.is_beta and tk.NORMAL or tk.DISABLED
self.eddn_system_button['state']= logvalid and tk.NORMAL or tk.DISABLED
self.eddn_delay_button['state'] = logvalid and eddn.replayfile and self.eddn_system.get() and tk.NORMAL or tk.DISABLED
self.edsm_log_button['state'] = logvalid and tk.NORMAL or tk.DISABLED
edsm_state = logvalid and self.edsm_log.get() and tk.NORMAL or tk.DISABLED
self.edsm_label['state'] = edsm_state
self.edsm_cmdr_label['state'] = edsm_state
self.edsm_apikey_label['state'] = edsm_state
self.edsm_cmdr['state'] = edsm_state
self.edsm_apikey['state'] = edsm_state
self.edsm_log_button['state'] = logvalid and not monitor.is_beta and tk.NORMAL or tk.DISABLED
edsm_state = logvalid and monitor.cmdr and not monitor.is_beta and self.edsm_log.get() and tk.NORMAL or tk.DISABLED
self.edsm_label['state'] = self.edsm_cmdr_label['state'] = self.edsm_user_label['state'] = self.edsm_apikey_label['state'] = edsm_state
self.edsm_cmdr_text['state'] = self.edsm_user['state'] = self.edsm_apikey['state'] = edsm_state
def filebrowse(self, title, pathvar):
if platform != 'win32':
@ -474,9 +516,20 @@ class PreferencesDialog(tk.Toplevel):
def apply(self):
credentials = (config.get('username'), config.get('password'))
config.set('username', self.username.get().strip())
config.set('password', self.password.get().strip())
if self.cmdr and not monitor.is_beta:
if not config.get('cmdrs'):
config.set('cmdrs', [self.cmdr])
config.set('fdev_usernames', [self.username.get().strip()])
config.set('fdev_passwords', [self.password.get().strip()])
config.set('edsm_usernames', [self.edsm_user.get().strip()])
config.set('edsm_apikeys', [self.edsm_apikey.get().strip()])
else:
idx = config.get('cmdrs').index(self.cmdr) if self.cmdr in config.get('cmdrs') else -1
_putfirst('cmdrs', idx, self.cmdr)
_putfirst('fdev_usernames', idx, self.username.get().strip())
_putfirst('fdev_passwords', idx, self.password.get().strip())
_putfirst('edsm_usernames', idx, self.edsm_user.get().strip())
_putfirst('edsm_apikeys', idx, self.edsm_apikey.get().strip())
config.set('output',
(self.out_td.get() and config.OUT_MKT_TD) +
@ -489,9 +542,6 @@ class PreferencesDialog(tk.Toplevel):
(self.edsm_log.get() and config.OUT_SYS_EDSM))
config.set('outdir', self.outdir.get().startswith('~') and join(config.home, self.outdir.get()[2:]) or self.outdir.get())
config.set('edsm_cmdrname', self.edsm_cmdr.get().strip())
config.set('edsm_apikey', self.edsm_apikey.get().strip())
logdir = self.logdir.get()
if config.default_journal_dir and logdir.lower() == config.default_journal_dir.lower():
config.set('journaldir', '') # default location
@ -621,3 +671,35 @@ class AuthenticationDialog(tk.Toplevel):
self.parent.wm_attributes('-topmost', config.getint('always_ontop') and 1 or 0)
self.destroy()
if self.callback: self.callback(None)
# migration from <= 2.25. Assumes current Cmdr corresponds to the saved credentials
def migrate(current_cmdr):
if current_cmdr and not config.get('cmdrs') and config.get('username') and config.get('password'):
config.set('cmdrs', [current_cmdr])
config.set('fdev_usernames', [config.get('username')])
config.set('fdev_passwords', [config.get('password')])
config.set('edsm_usernames', [config.get('edsm_cmdrname') or ''])
config.set('edsm_apikeys', [config.get('edsm_apikey') or ''])
# XXX to be done for release
# config.delete('username')
# config.delete('password')
# config.delete('edsm_cmdrname')
# config.delete('edsm_apikey')
# Put current Cmdr first in the lists
def make_current(current_cmdr):
if current_cmdr and config.get('cmdrs') and current_cmdr in config.get('cmdrs'):
idx = config.get('cmdrs').index(current_cmdr)
_putfirst('cmdrs', idx)
_putfirst('fdev_usernames', idx)
_putfirst('fdev_passwords', idx)
_putfirst('edsm_usernames', idx)
_putfirst('edsm_apikeys', idx)
def _putfirst(setting, config_idx, new_value=None):
assert config_idx>=0 or new_value is not None, (setting, config_idx, new_value)
values = config.get(setting)
values.insert(0, new_value if config_idx<0 else values.pop(config_idx))
if new_value is not None:
values[0] = new_value
config.set(setting, values)

View File

@ -11,6 +11,7 @@ import myNotebook as nb
import companion
from companion import ship_map
from monitor import monitor
import prefs
if platform=='win32':
@ -175,6 +176,9 @@ class StatsDialog():
self.showstats()
def showstats(self):
if not monitor.cmdr or monitor.is_beta:
return # In Beta - do nothing
self.status['text'] = _('Fetching data...')
self.parent.update_idletasks()