441 lines
15 KiB
Python
441 lines
15 KiB
Python
import time
|
|
import webbrowser
|
|
import json
|
|
# noinspection PyPackageRequirements
|
|
import wx
|
|
import requests
|
|
|
|
from service.port import Port
|
|
from service.fit import Fit
|
|
|
|
from eos.saveddata.cargo import Cargo
|
|
from eos.db import getItem
|
|
|
|
from gui.display import Display
|
|
import gui.globalEvents as GE
|
|
|
|
from logbook import Logger
|
|
import calendar
|
|
pyfalog = Logger(__name__)
|
|
|
|
if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3, 0)):
|
|
from service.crest import Crest, CrestModes
|
|
|
|
|
|
class CrestFittings(wx.Frame):
|
|
def __init__(self, parent):
|
|
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title="Browse EVE Fittings", pos=wx.DefaultPosition,
|
|
size=wx.Size(550, 450), style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL)
|
|
|
|
self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE))
|
|
|
|
self.mainFrame = parent
|
|
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
|
sCrest = Crest.getInstance()
|
|
|
|
characterSelectSizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
|
|
if sCrest.settings.get('mode') == CrestModes.IMPLICIT:
|
|
self.stLogged = wx.StaticText(self, wx.ID_ANY, "Currently logged in as %s" % sCrest.implicitCharacter.name,
|
|
wx.DefaultPosition, wx.DefaultSize)
|
|
self.stLogged.Wrap(-1)
|
|
|
|
characterSelectSizer.Add(self.stLogged, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
|
|
else:
|
|
self.charChoice = wx.Choice(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, [])
|
|
characterSelectSizer.Add(self.charChoice, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
|
|
self.updateCharList()
|
|
|
|
self.fetchBtn = wx.Button(self, wx.ID_ANY, "Fetch Fits", wx.DefaultPosition, wx.DefaultSize, 5)
|
|
characterSelectSizer.Add(self.fetchBtn, 0, wx.ALL, 5)
|
|
mainSizer.Add(characterSelectSizer, 0, wx.EXPAND, 5)
|
|
|
|
self.sl = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL)
|
|
mainSizer.Add(self.sl, 0, wx.EXPAND | wx.ALL, 5)
|
|
|
|
contentSizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
browserSizer = wx.BoxSizer(wx.VERTICAL)
|
|
|
|
self.fitTree = FittingsTreeView(self)
|
|
browserSizer.Add(self.fitTree, 1, wx.ALL | wx.EXPAND, 5)
|
|
contentSizer.Add(browserSizer, 1, wx.EXPAND, 0)
|
|
fitSizer = wx.BoxSizer(wx.VERTICAL)
|
|
|
|
self.fitView = FitView(self)
|
|
fitSizer.Add(self.fitView, 1, wx.ALL | wx.EXPAND, 5)
|
|
|
|
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
self.importBtn = wx.Button(self, wx.ID_ANY, "Import to pyfa", wx.DefaultPosition, wx.DefaultSize, 5)
|
|
self.deleteBtn = wx.Button(self, wx.ID_ANY, "Delete from EVE", wx.DefaultPosition, wx.DefaultSize, 5)
|
|
btnSizer.Add(self.importBtn, 1, wx.ALL, 5)
|
|
btnSizer.Add(self.deleteBtn, 1, wx.ALL, 5)
|
|
fitSizer.Add(btnSizer, 0, wx.EXPAND)
|
|
|
|
contentSizer.Add(fitSizer, 1, wx.EXPAND, 0)
|
|
mainSizer.Add(contentSizer, 1, wx.EXPAND, 5)
|
|
|
|
self.fetchBtn.Bind(wx.EVT_BUTTON, self.fetchFittings)
|
|
self.importBtn.Bind(wx.EVT_BUTTON, self.importFitting)
|
|
self.deleteBtn.Bind(wx.EVT_BUTTON, self.deleteFitting)
|
|
|
|
self.mainFrame.Bind(GE.EVT_SSO_LOGOUT, self.ssoLogout)
|
|
self.mainFrame.Bind(GE.EVT_SSO_LOGIN, self.ssoLogin)
|
|
self.Bind(wx.EVT_CLOSE, self.OnClose)
|
|
|
|
self.statusbar = wx.StatusBar(self)
|
|
self.statusbar.SetFieldsCount()
|
|
self.SetStatusBar(self.statusbar)
|
|
|
|
self.cacheTimer = wx.Timer(self)
|
|
self.Bind(wx.EVT_TIMER, self.updateCacheStatus, self.cacheTimer)
|
|
|
|
self.SetSizer(mainSizer)
|
|
self.Layout()
|
|
|
|
self.Centre(wx.BOTH)
|
|
|
|
def ssoLogin(self, event):
|
|
self.updateCharList()
|
|
event.Skip()
|
|
|
|
def updateCharList(self):
|
|
sCrest = Crest.getInstance()
|
|
chars = sCrest.getCrestCharacters()
|
|
|
|
if len(chars) == 0:
|
|
self.Close()
|
|
|
|
self.charChoice.Clear()
|
|
for char in chars:
|
|
self.charChoice.Append(char.name, char.ID)
|
|
|
|
self.charChoice.SetSelection(0)
|
|
|
|
def updateCacheStatus(self, event):
|
|
t = time.gmtime(self.cacheTime - time.time())
|
|
|
|
if calendar.timegm(t) < 0: # calendar.timegm gets seconds until time given
|
|
self.cacheTimer.Stop()
|
|
else:
|
|
sTime = time.strftime("%H:%M:%S", t)
|
|
self.statusbar.SetStatusText("Cached for %s" % sTime, 0)
|
|
|
|
def ssoLogout(self, event):
|
|
if event.type == CrestModes.IMPLICIT:
|
|
self.Close()
|
|
else:
|
|
self.updateCharList()
|
|
event.Skip() # continue event
|
|
|
|
def OnClose(self, event):
|
|
self.mainFrame.Unbind(GE.EVT_SSO_LOGOUT, handler=self.ssoLogout)
|
|
self.mainFrame.Unbind(GE.EVT_SSO_LOGIN, handler=self.ssoLogin)
|
|
event.Skip()
|
|
|
|
def getActiveCharacter(self):
|
|
sCrest = Crest.getInstance()
|
|
|
|
if sCrest.settings.get('mode') == CrestModes.IMPLICIT:
|
|
return sCrest.implicitCharacter.ID
|
|
|
|
selection = self.charChoice.GetCurrentSelection()
|
|
return self.charChoice.GetClientData(selection) if selection is not None else None
|
|
|
|
def fetchFittings(self, event):
|
|
sCrest = Crest.getInstance()
|
|
try:
|
|
waitDialog = wx.BusyInfo("Fetching fits, please wait...", parent=self)
|
|
fittings = sCrest.getFittings(self.getActiveCharacter())
|
|
self.cacheTime = fittings.get('cached_until')
|
|
self.updateCacheStatus(None)
|
|
self.cacheTimer.Start(1000)
|
|
self.fitTree.populateSkillTree(fittings)
|
|
del waitDialog
|
|
except requests.exceptions.ConnectionError:
|
|
msg = "Connection error, please check your internet connection"
|
|
pyfalog.error(msg)
|
|
self.statusbar.SetStatusText(msg)
|
|
|
|
def importFitting(self, event):
|
|
selection = self.fitView.fitSelection
|
|
if not selection:
|
|
return
|
|
data = self.fitTree.fittingsTreeCtrl.GetItemData(selection)
|
|
sPort = Port.getInstance()
|
|
fits = sPort.importFitFromBuffer(data)
|
|
self.mainFrame._openAfterImport(fits)
|
|
|
|
def deleteFitting(self, event):
|
|
sCrest = Crest.getInstance()
|
|
selection = self.fitView.fitSelection
|
|
if not selection:
|
|
return
|
|
data = json.loads(self.fitTree.fittingsTreeCtrl.GetItemData(selection))
|
|
|
|
dlg = wx.MessageDialog(self,
|
|
"Do you really want to delete %s (%s) from EVE?" % (data['name'], data['ship']['name']),
|
|
"Confirm Delete", wx.YES | wx.NO | wx.ICON_QUESTION)
|
|
|
|
if dlg.ShowModal() == wx.ID_YES:
|
|
try:
|
|
sCrest.delFitting(self.getActiveCharacter(), data['fittingID'])
|
|
except requests.exceptions.ConnectionError:
|
|
msg = "Connection error, please check your internet connection"
|
|
pyfalog.error(msg)
|
|
self.statusbar.SetStatusText(msg)
|
|
|
|
|
|
class ExportToEve(wx.Frame):
|
|
def __init__(self, parent):
|
|
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title="Export fit to EVE", pos=wx.DefaultPosition,
|
|
size=(wx.Size(350, 100)), style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL)
|
|
|
|
self.mainFrame = parent
|
|
self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE))
|
|
|
|
sCrest = Crest.getInstance()
|
|
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
|
hSizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
|
|
if sCrest.settings.get('mode') == CrestModes.IMPLICIT:
|
|
self.stLogged = wx.StaticText(self, wx.ID_ANY, "Currently logged in as %s" % sCrest.implicitCharacter.name,
|
|
wx.DefaultPosition, wx.DefaultSize)
|
|
self.stLogged.Wrap(-1)
|
|
|
|
hSizer.Add(self.stLogged, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
|
|
else:
|
|
self.charChoice = wx.Choice(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, [])
|
|
hSizer.Add(self.charChoice, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
|
|
self.updateCharList()
|
|
self.charChoice.SetSelection(0)
|
|
|
|
self.exportBtn = wx.Button(self, wx.ID_ANY, "Export Fit", wx.DefaultPosition, wx.DefaultSize, 5)
|
|
hSizer.Add(self.exportBtn, 0, wx.ALL, 5)
|
|
|
|
mainSizer.Add(hSizer, 0, wx.EXPAND, 5)
|
|
|
|
self.exportBtn.Bind(wx.EVT_BUTTON, self.exportFitting)
|
|
|
|
self.statusbar = wx.StatusBar(self)
|
|
self.statusbar.SetFieldsCount(2)
|
|
self.statusbar.SetStatusWidths([100, -1])
|
|
|
|
self.mainFrame.Bind(GE.EVT_SSO_LOGOUT, self.ssoLogout)
|
|
self.mainFrame.Bind(GE.EVT_SSO_LOGIN, self.ssoLogin)
|
|
self.Bind(wx.EVT_CLOSE, self.OnClose)
|
|
|
|
self.SetSizer(mainSizer)
|
|
self.SetStatusBar(self.statusbar)
|
|
self.Layout()
|
|
|
|
self.Centre(wx.BOTH)
|
|
|
|
def updateCharList(self):
|
|
sCrest = Crest.getInstance()
|
|
chars = sCrest.getCrestCharacters()
|
|
|
|
if len(chars) == 0:
|
|
self.Close()
|
|
|
|
self.charChoice.Clear()
|
|
for char in chars:
|
|
self.charChoice.Append(char.name, char.ID)
|
|
|
|
self.charChoice.SetSelection(0)
|
|
|
|
def ssoLogin(self, event):
|
|
self.updateCharList()
|
|
event.Skip()
|
|
|
|
def ssoLogout(self, event):
|
|
if event.type == CrestModes.IMPLICIT:
|
|
self.Close()
|
|
else:
|
|
self.updateCharList()
|
|
event.Skip() # continue event
|
|
|
|
def OnClose(self, event):
|
|
self.mainFrame.Unbind(GE.EVT_SSO_LOGOUT, handler=self.ssoLogout)
|
|
event.Skip()
|
|
|
|
def getActiveCharacter(self):
|
|
sCrest = Crest.getInstance()
|
|
|
|
if sCrest.settings.get('mode') == CrestModes.IMPLICIT:
|
|
return sCrest.implicitCharacter.ID
|
|
|
|
selection = self.charChoice.GetCurrentSelection()
|
|
return self.charChoice.GetClientData(selection) if selection is not None else None
|
|
|
|
def exportFitting(self, event):
|
|
sPort = Port.getInstance()
|
|
fitID = self.mainFrame.getActiveFit()
|
|
|
|
self.statusbar.SetStatusText("", 0)
|
|
|
|
if fitID is None:
|
|
self.statusbar.SetStatusText("Please select an active fitting in the main window", 1)
|
|
return
|
|
|
|
self.statusbar.SetStatusText("Sending request and awaiting response", 1)
|
|
sCrest = Crest.getInstance()
|
|
|
|
try:
|
|
sFit = Fit.getInstance()
|
|
data = sPort.exportCrest(sFit.getFit(fitID))
|
|
res = sCrest.postFitting(self.getActiveCharacter(), data)
|
|
|
|
self.statusbar.SetStatusText("%d: %s" % (res.status_code, res.reason), 0)
|
|
try:
|
|
text = json.loads(res.text)
|
|
self.statusbar.SetStatusText(text['message'], 1)
|
|
except ValueError:
|
|
pyfalog.warning("Value error on loading JSON.")
|
|
self.statusbar.SetStatusText("", 1)
|
|
except requests.exceptions.ConnectionError:
|
|
msg = "Connection error, please check your internet connection"
|
|
pyfalog.error(msg)
|
|
self.statusbar.SetStatusText(msg)
|
|
|
|
|
|
class CrestMgmt(wx.Dialog):
|
|
def __init__(self, parent):
|
|
wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title="CREST Character Management", pos=wx.DefaultPosition,
|
|
size=wx.Size(550, 250), style=wx.DEFAULT_DIALOG_STYLE)
|
|
self.mainFrame = parent
|
|
mainSizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
|
|
self.lcCharacters = wx.ListCtrl(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LC_REPORT)
|
|
|
|
self.lcCharacters.InsertColumn(0, heading='Character')
|
|
self.lcCharacters.InsertColumn(1, heading='Refresh Token')
|
|
|
|
self.popCharList()
|
|
|
|
mainSizer.Add(self.lcCharacters, 1, wx.ALL | wx.EXPAND, 5)
|
|
|
|
btnSizer = wx.BoxSizer(wx.VERTICAL)
|
|
|
|
self.addBtn = wx.Button(self, wx.ID_ANY, "Add Character", wx.DefaultPosition, wx.DefaultSize, 0)
|
|
btnSizer.Add(self.addBtn, 0, wx.ALL | wx.EXPAND, 5)
|
|
|
|
self.deleteBtn = wx.Button(self, wx.ID_ANY, "Revoke Character", wx.DefaultPosition, wx.DefaultSize, 0)
|
|
btnSizer.Add(self.deleteBtn, 0, wx.ALL | wx.EXPAND, 5)
|
|
|
|
mainSizer.Add(btnSizer, 0, wx.EXPAND, 5)
|
|
|
|
self.addBtn.Bind(wx.EVT_BUTTON, self.addChar)
|
|
self.deleteBtn.Bind(wx.EVT_BUTTON, self.delChar)
|
|
|
|
self.mainFrame.Bind(GE.EVT_SSO_LOGIN, self.ssoLogin)
|
|
|
|
self.SetSizer(mainSizer)
|
|
self.Layout()
|
|
|
|
self.Centre(wx.BOTH)
|
|
|
|
def ssoLogin(self, event):
|
|
self.popCharList()
|
|
event.Skip()
|
|
|
|
def popCharList(self):
|
|
sCrest = Crest.getInstance()
|
|
chars = sCrest.getCrestCharacters()
|
|
|
|
self.lcCharacters.DeleteAllItems()
|
|
|
|
for index, char in enumerate(chars):
|
|
self.lcCharacters.InsertItem(index, char.name)
|
|
self.lcCharacters.SetStringItem(index, 1, char.refresh_token)
|
|
self.lcCharacters.SetItemData(index, char.ID)
|
|
|
|
self.lcCharacters.SetColumnWidth(0, wx.LIST_AUTOSIZE)
|
|
self.lcCharacters.SetColumnWidth(1, wx.LIST_AUTOSIZE)
|
|
|
|
@staticmethod
|
|
def addChar(event):
|
|
sCrest = Crest.getInstance()
|
|
uri = sCrest.startServer()
|
|
webbrowser.open(uri)
|
|
|
|
def delChar(self, event):
|
|
item = self.lcCharacters.GetFirstSelected()
|
|
if item > -1:
|
|
charID = self.lcCharacters.GetItemData(item)
|
|
sCrest = Crest.getInstance()
|
|
sCrest.delCrestCharacter(charID)
|
|
self.popCharList()
|
|
|
|
|
|
class FittingsTreeView(wx.Panel):
|
|
def __init__(self, parent):
|
|
wx.Panel.__init__(self, parent, id=wx.ID_ANY)
|
|
self.parent = parent
|
|
pmainSizer = wx.BoxSizer(wx.VERTICAL)
|
|
|
|
tree = self.fittingsTreeCtrl = wx.TreeCtrl(self, wx.ID_ANY, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT)
|
|
pmainSizer.Add(tree, 1, wx.EXPAND | wx.ALL, 0)
|
|
|
|
self.root = tree.AddRoot("Fits")
|
|
self.populateSkillTree(None)
|
|
|
|
self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.displayFit)
|
|
|
|
self.SetSizer(pmainSizer)
|
|
|
|
self.Layout()
|
|
|
|
def populateSkillTree(self, data):
|
|
if data is None:
|
|
return
|
|
root = self.root
|
|
tree = self.fittingsTreeCtrl
|
|
tree.DeleteChildren(root)
|
|
|
|
dict = {}
|
|
fits = data['items']
|
|
for fit in fits:
|
|
if fit['ship']['name'] not in dict:
|
|
dict[fit['ship']['name']] = []
|
|
dict[fit['ship']['name']].append(fit)
|
|
|
|
for name, fits in dict.items():
|
|
shipID = tree.AppendItem(root, name)
|
|
for fit in fits:
|
|
fitId = tree.AppendItem(shipID, fit['name'])
|
|
tree.SetPyData(fitId, json.dumps(fit))
|
|
|
|
tree.SortChildren(root)
|
|
|
|
def displayFit(self, event):
|
|
selection = self.fittingsTreeCtrl.GetSelection()
|
|
data = self.fittingsTreeCtrl.GetItemData(selection)
|
|
|
|
if data is None:
|
|
event.Skip()
|
|
return
|
|
|
|
fit = json.loads(data)
|
|
list = []
|
|
|
|
for item in fit['items']:
|
|
try:
|
|
cargo = Cargo(getItem(item['type']['id']))
|
|
cargo.amount = item['quantity']
|
|
list.append(cargo)
|
|
except Exception as e:
|
|
pyfalog.critical("Exception caught in displayFit")
|
|
pyfalog.critical(e)
|
|
|
|
self.parent.fitView.fitSelection = selection
|
|
self.parent.fitView.update(list)
|
|
|
|
|
|
class FitView(Display):
|
|
DEFAULT_COLS = ["Base Icon",
|
|
"Base Name"]
|
|
|
|
def __init__(self, parent):
|
|
Display.__init__(self, parent, style=wx.LC_SINGLE_SEL)
|
|
self.fitSelection = None
|