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

Add support for sending flight log to EDSM. Export existing flight log to EDSM the first time this is enabled.

This commit is contained in:
Jonathan Harris 2015-10-13 20:36:03 +01:00
parent a74a928764
commit 60caf24c8d
6 changed files with 186 additions and 56 deletions

View File

@ -179,7 +179,7 @@ class AppWindow:
self.status['text'] = ''
# Try to obtain exclusive lock on flight log ASAP
if config.getint('output') & config.OUT_LOG:
if config.getint('output') & config.OUT_LOG_FILE:
try:
flightlog.openlog()
except Exception as e:
@ -251,25 +251,29 @@ class AppWindow:
self.system['text'] = data.get('lastSystem') and data.get('lastSystem').get('name') or ''
self.station['text'] = data.get('commander') and data.get('commander').get('docked') and data.get('lastStarport') and data.get('lastStarport').get('name') or (EDDB.system(self.system['text']) and self.STATION_UNDOCKED or '')
self.edit_menu.entryconfigure(_('Copy'), state=tk.NORMAL)
self.edsm.start_lookup(self.system['text'], EDDB.system(self.system['text']))
self.system['image'] = self.edsm.result['img']
self.w.after(int(EDSM_POLL * 1000), self.edsmpoll)
# stuff we can do when not docked
if config.getint('output') & config.OUT_LOG:
flightlog.export(data)
if config.getint('output') & config.OUT_SHIP_EDS:
loadout.export(data)
if config.getint('output') & config.OUT_SHIP_CORIOLIS:
coriolis.export(data)
if config.getint('output') & config.OUT_LOG_FILE:
flightlog.export(data)
if config.getint('output') & config.OUT_LOG_EDSM:
self.status['text'] = _('Sending data to EDSM...')
self.w.update_idletasks()
edsm.export(data, lambda:self.edsm.lookup(self.system['text'], EDDB.system(self.system['text']))) # Do EDSM lookup during EDSM export
else:
self.edsm.start_lookup(self.system['text'], EDDB.system(self.system['text']))
self.edsmpoll()
if not (config.getint('output') & (config.OUT_CSV|config.OUT_TD|config.OUT_BPC|config.OUT_EDDN)):
# no further output requested
# no station data requested - we're done
self.status['text'] = strftime(_('Last updated at {HH}:{MM}:{SS}').format(HH='%H', MM='%M', SS='%S').encode('utf-8'), localtime(querytime)).decode('utf-8')
elif not data['commander'].get('docked'):
self.status['text'] = _("You're not docked at a station!")
# signal as error becuase sometimes the server hosting the Companion API hasn't caught up
# signal as error because the user might actually be docked but the server hosting the Companion API hasn't caught up
if play_sound: hotkeymgr.play_bad()
else:

View File

@ -43,7 +43,7 @@ combination that you use to log into the Elite: Dangerous launcher, and is requi
You can also choose here what data to save (refer to the next section for details), whether to set up a hotkey so you don't have to switch to the app in order to “Update”, and whether to attach your Cmdr name or a [pseudo-anonymized](http://en.wikipedia.org/wiki/Pseudonymity) ID to the data.
You are next prompted to authenticate with a “verification code”, which you will shortly receive by email from Frontier.
The first time that you hit “Update” you will be prompted to authenticate with a “verification code”, which you will shortly receive by email from Frontier.
Note that each “verification code” is one-time only - if you enter the code incorrectly or quit the app before
authenticating you will need to wait for Frontier to send you a new code.
@ -56,15 +56,16 @@ This app can save a variety of data in a variety of formats:
* Market data
* Elite Dangerous Data Network - sends commodity market, outfitting and shipyard data to “[EDDN](http://eddn-gateway.elite-markets.net/)” from where you and others can use it via online trading tools such as [eddb](http://eddb.io/), [Elite Trade Net](http://etn.io/), [Inara](http://inara.cz), [ED-TD](http://ed-td.space/), [Roguey's](http://roguey.co.uk/elite-dangerous/), etc.
* Slopey's BPC format - saves commodity market data as files that you can load into [Slopey's BPC Market Tool](https://forums.frontier.co.uk/showthread.php?t=76081).
* Trade Dangerous format - saves commodity market data as files that you can load into [Trade Dangerous](https://bitbucket.org/kfsone/tradedangerous/wiki/Home).
* CSV format - saves commodity market data as files that you can upload to [Thrudd's Trading Tools](http://www.elitetradingtool.co.uk/), [Inara](http://inara.cz) or [mEDI's Elite Tools](https://github.com/mEDI-S/mEDI_s-Elite-Tools).
* Slopey's BPC format file - saves commodity market data as files that you can load into [Slopey's BPC Market Tool](https://forums.frontier.co.uk/showthread.php?t=76081).
* Trade Dangerous format file - saves commodity market data as files that you can load into [Trade Dangerous](https://bitbucket.org/kfsone/tradedangerous/wiki/Home).
* CSV format file - saves commodity market data as files that you can upload to [Thrudd's Trading Tools](http://www.elitetradingtool.co.uk/), [Inara](http://inara.cz) or [mEDI's Elite Tools](https://github.com/mEDI-S/mEDI_s-Elite-Tools).
* Ship loadout
* After every outfitting change saves a record of your ship loadout as a file that you can open in a text editor and that you can import into [E:D Shipyard](http://www.edshipyard.com) or [Coriolis](http://coriolis.io).
* Flight log
* Adds a record of your location, ship and cargo to a file that you can open in a text editor or a spreadsheet program such as Excel. Note: Don't edit, rename or move this file - take a copy if you wish to change it.
* Elite Dangerous Star Map - sends a record of your location to “[EDSM](http://www.edsm.net/)” where you can view your logs under My account → Exploration Logs, and optionally add private comments about a system.
* CSV format file - adds a record of your location, ship and cargo to a file that you can open in a text editor or a spreadsheet program such as Excel. Note: Don't edit, rename or move this file - take a copy if you wish to change it.
By default these files will be placed in your Documents folder. Since this app will create a lot of files if you use it for a while you may wish to create a separate folder for the files and tell the app to place them there.

View File

@ -70,9 +70,10 @@ class Config:
OUT_TD = 4
OUT_CSV = 8
OUT_SHIP_EDS = 16
OUT_LOG = 32
OUT_LOG_FILE = 32
#OUT_STAT = 64 # No longer available
OUT_SHIP_CORIOLIS = 128
OUT_LOG_EDSM = 256
if platform=='darwin':

89
edsm.py
View File

@ -1,10 +1,14 @@
import requests
import threading
from sys import platform
import time
import urllib
import Tkinter as tk
from config import config
import flightlog
if __debug__:
from traceback import print_exc
@ -24,18 +28,43 @@ class EDSM:
EDSM._IMG_NEW = tk.PhotoImage(data = 'R0lGODlhEAAQAMZwANKVHtWcIteiHuiqLPCuHOS1MN22ZeW7ROG6Zuu9MOy+K/i8Kf/DAuvCVf/FAP3BNf/JCf/KAPHHSv7ESObHdv/MBv/GRv/LGP/QBPXOPvjPQfjQSvbRSP/UGPLSae7Sfv/YNvLXgPbZhP7dU//iI//mAP/jH//kFv7fU//fV//ebv/iTf/iUv/kTf/iZ/vgiP/hc/vgjv/jbfriiPriiv7ka//if//jd//sJP/oT//tHv/mZv/sLf/rRP/oYv/rUv/paP/mhv/sS//oc//lkf/mif/sUf/uPv/qcv/uTv/uUv/vUP/qhP/xP//pm//ua//sf//ubf/wXv/thv/tif/slv/tjf/smf/yYP/ulf/2R//2Sv/xkP/2av/0gP/ylf/2df/0i//0j//0lP/5cP/7a//1p//5gf/7ev/3o//2sf/5mP/6kv/2vP/3y//+jP///////////////////////////////////////////////////////////////yH5BAEKAH8ALAAAAAAQABAAAAePgH+Cg4SFhoJKPIeHYT+LhVppUTiPg2hrUkKPXWdlb2xHJk9jXoNJQDk9TVtkYCUkOy4wNjdGfy1UXGJYOksnPiwgFwwYg0NubWpmX1ArHREOFYUyWVNIVkxXQSoQhyMoNVUpRU5EixkcMzQaGy8xhwsKHiEfBQkSIg+GBAcUCIIBBDSYYGiAAUMALFR6FAgAOw==')
EDSM._IMG_ERROR = tk.PhotoImage(data = 'R0lGODlhDgAOAIABAAAAAP///yH5BAEKAAEALAAAAAAOAA4AAAIcjIGJxqHaIJPypBYvzms77X1dWHlliKYmuI5GAQA7') # BBC Mode 5 '?'
def lookup(self, system_name, known=0):
self.cancel_lookup()
if system_name in self.syscache: # Cache URLs of systems with known coordinates
self.result = { 'img': EDSM._IMG_KNOWN, 'url': self.syscache[system_name], 'done': True }
elif known:
self.result = { 'img': EDSM._IMG_KNOWN, 'url': 'http://www.edsm.net/needed-distances?systemName=%s' % urllib.quote(system_name), 'done': True } # default URL
self.thread = threading.Thread(target = self.known, name = 'EDSM worker', args = (system_name, self.result))
else:
self.result = { 'img': '', 'url': 'http://www.edsm.net/needed-distances?systemName=%s' % urllib.quote(system_name), 'done': True } # default URL
r = requests.get('http://www.edsm.net/api-v1/system?sysname=%s&coords=1' % urllib.quote(system_name), timeout=EDSM._TIMEOUT)
r.raise_for_status()
data = r.json()
if data == -1:
# System not present - but don't create it on the assumption that the caller will
result['img'] = EDSM._IMG_NEW
elif data.get('coords'):
result['img'] = EDSM._IMG_KNOWN
self.thread = threading.Thread(target = self.known, name = 'EDSM worker', args = (system_name, self.result))
else:
result['img'] = EDSM._IMG_UNKNOWN
# Asynchronous version of the above
def start_lookup(self, system_name, known=0):
self.cancel_lookup()
# Cache URLs of systems with known coordinates
if system_name in self.syscache:
if system_name in self.syscache: # Cache URLs of systems with known coordinates
self.result = { 'img': EDSM._IMG_KNOWN, 'url': self.syscache[system_name], 'done': True }
return
self.result = { 'img': '', 'url': 'http://www.edsm.net/needed-distances?systemName=%s' % urllib.quote(system_name), 'done': False } # default URL
self.thread = threading.Thread(target = known and self.known or self.worker, name = 'EDSM worker', args = (system_name, self.result))
self.thread.daemon = True
self.thread.start()
elif known:
self.result = { 'img': EDSM._IMG_KNOWN, 'url': 'http://www.edsm.net/needed-distances?systemName=%s' % urllib.quote(system_name), 'done': True } # default URL
self.thread = threading.Thread(target = self.known, name = 'EDSM worker', args = (system_name, self.result))
else:
self.result = { 'img': '', 'url': 'http://www.edsm.net/needed-distances?systemName=%s' % urllib.quote(system_name), 'done': False } # default URL
self.thread = threading.Thread(target = self.worker, name = 'EDSM worker', args = (system_name, self.result))
self.thread.daemon = True
self.thread.start()
def cancel_lookup(self):
self.thread = None # orphan any existing thread
@ -53,6 +82,8 @@ class EDSM:
result['done'] = True # give feedback immediately
requests.get('http://www.edsm.net/api-v1/url?sysname=%s' % urllib.quote(system_name), timeout=EDSM._TIMEOUT) # creates system
elif data.get('coords'):
result['img'] = EDSM._IMG_KNOWN
result['done'] = True # give feedback immediately
self.known(system_name, result)
else:
result['img'] = EDSM._IMG_UNKNOWN
@ -64,8 +95,6 @@ class EDSM:
# Worker for known known systems - saves initial EDSM API call
def known(self, system_name, result):
# Prefer to send user to "Show distances" page for systems with known coordinates
result['img'] = EDSM._IMG_KNOWN
result['done'] = True # give feedback immediately
try:
r = requests.get('http://www.edsm.net/api-v1/url?sysname=%s' % urllib.quote(system_name), timeout=EDSM._TIMEOUT)
r.raise_for_status()
@ -73,3 +102,43 @@ class EDSM:
result['url'] = self.syscache[system_name] = data['url']['show-system']
except:
if __debug__: print_exc()
# Flight log - http://www.edsm.net/api-logs
def export(data, edsmlookupfn):
querytime = config.getint('querytime') or int(time.time())
try:
# Look up the system before adding it to the log, since adding it to the log has the side-effect of creating it
edsmlookupfn()
r = requests.get('http://www.edsm.net/api-logs-v1/set-log?commanderName=%s&apiKey=%s&systemName=%s&dateVisited=%s' % (urllib.quote(config.get('edsm_cmdrname')), urllib.quote(config.get('edsm_apikey')), urllib.quote(data['lastSystem']['name']), urllib.quote(time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(querytime)))), timeout=EDSM._TIMEOUT)
r.raise_for_status()
reply = r.json()
(msgnum, msg) = reply['msgnum'], reply['msg']
except:
if __debug__: print_exc()
raise Exception(_("Error: Can't connect to EDSM"))
# Message numbers: 1xx = OK, 2xx = fatal error, 3xx = error (but not generated in practice), 4xx = ignorable errors
if msgnum // 100 not in (1,4):
raise Exception(_('Error: EDSM {MSG}').format(MSG=msg))
if not config.getint('edsm_historical'):
config.set('edsm_historical', 1)
thread = threading.Thread(target = export_historical, name = 'EDSM export')
thread.daemon = True
thread.start()
# Make best effort to export existing flight log file. Be silent on error.
def export_historical():
try:
for (timestamp, system_name) in flightlog.logs():
r = requests.get('http://www.edsm.net/api-logs-v1/set-log?commanderName=%s&apiKey=%s&systemName=%s&dateVisited=%s' % (urllib.quote(config.get('edsm_cmdrname')), urllib.quote(config.get('edsm_apikey')), urllib.quote(system_name), urllib.quote(time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(timestamp)))), timeout=EDSM._TIMEOUT)
r.raise_for_status()
if r.json()['msgnum'] // 100 == 2:
raise Exception()
except:
if __debug__: print_exc()

View File

@ -39,9 +39,6 @@ def openlog():
def export(data):
def elapsed(game_time):
return '%3d:%02d:%02d' % ((game_time // 3600) % 3600, (game_time // 60) % 60, game_time % 60)
querytime = config.getint('querytime') or int(time.time())
openlog()
@ -60,3 +57,16 @@ def export(data):
','.join([('%d %s' % (commodities[k], k)) for k in sorted(commodities)])))
logfile.flush()
# return log as list of (timestamp, system_name)
def logs():
entries = []
with open(join(config.get('outdir'), 'Flight Log.csv'), 'rU') as f:
f.readline() # Assume header
for line in f:
if not line.strip(): continue
cols = line.split(',')
assert len(cols) >= 3, cols
entries.append((time.mktime(time.strptime('%sT%s' % (cols[0], cols[1]), '%Y-%m-%dT%H:%M:%S')), cols[2])) # Convert from local time to UTC
return entries

103
prefs.py
View File

@ -1,12 +1,13 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
from os.path import dirname, isdir, sep
from os.path import dirname, expanduser, isdir, sep
from sys import platform
import Tkinter as tk
import ttk
import tkFileDialog
from ttkHyperlinkLabel import HyperlinkLabel
from config import applongname, config
from hotkey import hotkeymgr
@ -64,6 +65,8 @@ class PreferencesDialog(tk.Toplevel):
# http://wiki.tcl.tk/13428
parent.call('tk::unsupported::MacWindowStyle', 'style', self, 'utility')
style = ttk.Style()
frame = ttk.Frame(self)
frame.grid(sticky=tk.NSEW)
@ -88,34 +91,58 @@ class PreferencesDialog(tk.Toplevel):
outframe = ttk.LabelFrame(frame, text=_('Output')) # Section heading in settings
outframe.grid(padx=10, pady=10, sticky=tk.NSEW)
outframe.columnconfigure(0, weight=1)
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).grid(row=1, 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"), variable=self.out_bpc, command=self.outvarchanged).grid(row=2, 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'), variable=self.out_td, command=self.outvarchanged).grid(row=3, columnspan=2, padx=5, sticky=tk.W)
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'), variable=self.out_csv, command=self.outvarchanged).grid(row=4, columnspan=2, padx=5, sticky=tk.W)
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'), variable=self.out_ship_eds, command=self.outvarchanged).grid(row=5, columnspan=2, padx=5, sticky=tk.W)
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'), variable=self.out_ship_coriolis, command=self.outvarchanged).grid(row=6, columnspan=2, padx=5, sticky=tk.W)
self.out_log = tk.IntVar(value = (output & config.OUT_LOG ) and 1 or 0)
ttk.Checkbutton(outframe, text=_('Flight log'), variable=self.out_log, command=self.outvarchanged).grid(row=7, columnspan=2, padx=5, sticky=tk.W)
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=(platform=='darwin' and _('Where:') or # Output folder prompt on OSX
_('File location:'))).grid(row=8, padx=5, pady=(5,0), sticky=tk.NSEW) # Output folder prompt on Windows
self.outbutton = ttk.Button(outframe, text=(platform=='darwin' and _('Change...') or # Folder selection button on OSX
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.columnconfigure(0, weight=1)
self.outdir = ttk.Entry(dirframe, takefocus=False)
if config.get('outdir').startswith(expanduser('~')):
self.outdir.insert(0, '~' + config.get('outdir')[len(expanduser('~')):])
else:
self.outdir.insert(0, config.get('outdir'))
self.outdir.grid(row=0, padx=5, pady=5, sticky=tk.NSEW)
self.outbutton = ttk.Button(dirframe, text=(platform=='darwin' and _('Change...') or # Folder selection button on OSX
_('Browse...')), command=self.outbrowse) # Folder selection button on Windows
self.outbutton.grid(row=8, column=1, padx=5, pady=(5,0), sticky=tk.NSEW)
self.outdir = ttk.Entry(outframe, takefocus=False)
self.outdir.insert(0, config.get('outdir'))
self.outdir.grid(row=9, columnspan=2, padx=5, pady=5, sticky=tk.EW)
self.outvarchanged()
self.outbutton.grid(row=0, column=1, padx=5, pady=5, sticky=tk.NSEW)
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.columnconfigure(1, weight=1)
ttk.Label(edsmframe, text=_('Cmdr name')).grid(row=0, sticky=tk.W) # EDSM & privacy setting
self.edsm_cmdr = ttk.Entry(edsmframe)
self.edsm_cmdr.insert(0, config.get('edsm_cmdrname') or '')
self.edsm_cmdr.grid(row=0, column=1, sticky=tk.NSEW)
ttk.Label(edsmframe, text=_('API Key')).grid(row=1, sticky=tk.W) # EDSM setting
self.edsm_apikey = ttk.Entry(edsmframe)
self.edsm_apikey.insert(0, config.get('edsm_apikey') or '')
self.edsm_apikey.grid(row=1, column=1, sticky=tk.NSEW)
for child in edsmframe.winfo_children():
child.grid_configure(padx=5, pady=3)
if platform in ['darwin','win32']:
self.hotkey_code = config.getint('hotkey_code')
@ -145,7 +172,6 @@ class PreferencesDialog(tk.Toplevel):
privacyframe = ttk.LabelFrame(frame, text=_('Privacy')) # Section heading in settings
privacyframe.grid(padx=10, pady=10, sticky=tk.NSEW)
privacyframe.columnconfigure(0, weight=1)
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)
@ -162,6 +188,9 @@ class PreferencesDialog(tk.Toplevel):
ttk.Button(buttonframe, text=_('OK'), command=self.apply).grid(row=0, column=1, sticky=tk.E)
self.protocol("WM_DELETE_WINDOW", self._destroy)
# Selectively disable buttons depending on output settings
self.outvarchanged()
# disable hotkey for the duration
hotkeymgr.unregister()
@ -171,13 +200,19 @@ class PreferencesDialog(tk.Toplevel):
#self.wait_window(self) # causes duplicate events on OSX
def outvarchanged(self):
local = self.out_bpc.get() or self.out_td.get() or self.out_csv.get() or self.out_ship_eds.get() or self.out_ship_coriolis.get() or self.out_log.get()
self.outbutton['state'] = local and tk.NORMAL or tk.DISABLED
local = self.out_bpc.get() or self.out_td.get() or self.out_csv.get() or self.out_ship_eds.get() or self.out_ship_coriolis.get() or self.out_log_file.get()
self.dir_label['state'] = local and tk.NORMAL or tk.DISABLED
self.outbutton['state'] = local and tk.NORMAL or tk.DISABLED
self.outdir['state'] = local and 'readonly' or tk.DISABLED
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
self.edsm_apikey['state'] = edsm and tk.NORMAL or tk.DISABLED
def outbrowse(self):
if platform != 'win32':
d = tkFileDialog.askdirectory(parent=self, initialdir=self.outdir.get(), title=_('File location:'), mustexist=tk.TRUE)
d = tkFileDialog.askdirectory(parent=self, initialdir=expanduser(self.outdir.get()), title=_('File location'), mustexist=tk.TRUE)
else:
def browsecallback(hwnd, uMsg, lParam, lpData):
# set initial folder
@ -186,10 +221,10 @@ class PreferencesDialog(tk.Toplevel):
return 0
browseInfo = BROWSEINFO()
browseInfo.lpszTitle = _('File location:')
browseInfo.lpszTitle = _('File location')
browseInfo.ulFlags = BIF_RETURNONLYFSDIRS|BIF_USENEWUI
browseInfo.lpfn = BrowseCallbackProc(browsecallback)
browseInfo.lParam = self.outdir.get()
browseInfo.lParam = expanduser(self.outdir.get())
ctypes.windll.ole32.CoInitialize(None)
pidl = ctypes.windll.shell32.SHBrowseForFolderW(ctypes.byref(browseInfo))
if pidl:
@ -203,7 +238,10 @@ class PreferencesDialog(tk.Toplevel):
if d:
self.outdir['state'] = tk.NORMAL # must be writable to update
self.outdir.delete(0, tk.END)
self.outdir.insert(0, d.replace('/', sep))
if d.startswith(expanduser('~')):
self.outdir.insert(0, '~' + d[len(expanduser('~')):])
else:
self.outdir.insert(0, d)
self.outdir['state'] = 'readonly'
def hotkeystart(self, event):
@ -251,14 +289,21 @@ class PreferencesDialog(tk.Toplevel):
credentials = (config.get('username'), config.get('password'))
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.get() and config.OUT_LOG or 0) + (self.out_ship_coriolis.get() and config.OUT_SHIP_CORIOLIS or 0))
config.set('outdir', self.outdir.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('outdir', expanduser(self.outdir.get()))
config.set('edsm_cmdrname', self.edsm_cmdr.get().strip())
config.set('edsm_apikey', self.edsm_apikey.get().strip())
if platform in ['darwin','win32']:
config.set('hotkey_code', self.hotkey_code)
config.set('hotkey_mods', self.hotkey_mods)
config.set('hotkey_always', int(not self.hotkey_only.get()))
config.set('hotkey_mute', int(not self.hotkey_play.get()))
config.set('anonymous', self.out_anon.get())
self._destroy()
if credentials != (config.get('username'), config.get('password')) and self.callback:
self.callback()