588 lines
22 KiB
Python
588 lines
22 KiB
Python
import json
|
|
|
|
import requests
|
|
# noinspection PyPackageRequirements
|
|
import wx
|
|
from logbook import Logger
|
|
|
|
import config
|
|
import gui.globalEvents as GE
|
|
from eos.db import getItem
|
|
from eos.saveddata.cargo import Cargo
|
|
import gui.mainFrame
|
|
from gui.auxWindow import AuxiliaryFrame
|
|
from gui.display import Display
|
|
from gui.characterEditor import APIView
|
|
from service.character import Character
|
|
from service.esi import Esi
|
|
from service.esiAccess import APIException
|
|
from service.fit import Fit
|
|
from service.port import Port
|
|
from service.port.esi import ESIExportException
|
|
from service.settings import EsiSettings
|
|
|
|
|
|
_t = wx.GetTranslation
|
|
pyfalog = Logger(__name__)
|
|
|
|
|
|
class EveFittings(AuxiliaryFrame):
|
|
|
|
def __init__(self, parent):
|
|
super().__init__(
|
|
parent, id=wx.ID_ANY, title=_t("Browse EVE Fittings"), pos=wx.DefaultPosition,
|
|
size=wx.Size(750, 450), resizeable=True)
|
|
|
|
self.mainFrame = parent
|
|
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
|
|
|
characterSelectSizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
|
|
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, _t("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)
|
|
browserSizer.SetItemMinSize(0, 200, 0)
|
|
contentSizer.Add(browserSizer, 0, 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, _t("Import to pyfa"), wx.DefaultPosition, wx.DefaultSize, 5)
|
|
self.deleteBtn = wx.Button(self, wx.ID_ANY, _t("Delete from EVE"), wx.DefaultPosition, wx.DefaultSize, 5)
|
|
self.deleteAllBtn = wx.Button(self, wx.ID_ANY, _t("Delete all from Eve"), wx.DefaultPosition, wx.DefaultSize, 5)
|
|
btnSizer.Add(self.importBtn, 1, wx.ALL, 5)
|
|
btnSizer.Add(self.deleteBtn, 1, wx.ALL, 5)
|
|
btnSizer.Add(self.deleteAllBtn, 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.deleteAllBtn.Bind(wx.EVT_BUTTON, self.deleteAllFittings)
|
|
|
|
self.Bind(wx.EVT_CHAR_HOOK, self.kbEvent)
|
|
|
|
self.statusbar = wx.StatusBar(self)
|
|
self.statusbar.SetFieldsCount()
|
|
self.SetStatusBar(self.statusbar)
|
|
|
|
self.SetSizer(mainSizer)
|
|
self.Layout()
|
|
self.SetMinSize(self.GetSize())
|
|
|
|
self.Centre(wx.BOTH)
|
|
|
|
def updateCharList(self):
|
|
sEsi = Esi.getInstance()
|
|
chars = sEsi.getSsoCharacters()
|
|
|
|
self.charChoice.Clear()
|
|
for char in chars:
|
|
self.charChoice.Append(char.characterDisplay, char.ID)
|
|
if len(chars) > 0:
|
|
self.charChoice.SetSelection(0)
|
|
|
|
def kbEvent(self, event):
|
|
if event.GetKeyCode() == wx.WXK_ESCAPE and event.GetModifiers() == wx.MOD_NONE:
|
|
self.Close()
|
|
return
|
|
event.Skip()
|
|
|
|
def getActiveCharacter(self):
|
|
selection = self.charChoice.GetCurrentSelection()
|
|
return self.charChoice.GetClientData(selection) if selection not in (None, -1) else None
|
|
|
|
def fetchFittings(self, event):
|
|
sEsi = Esi.getInstance()
|
|
waitDialog = wx.BusyInfo(_t("Fetching fits, please wait..."), parent=self)
|
|
activeChar = self.getActiveCharacter()
|
|
if activeChar is None:
|
|
msg = _t("Need at least one ESI character to fetch")
|
|
pyfalog.warning(msg)
|
|
self.statusbar.SetStatusText(msg)
|
|
return
|
|
try:
|
|
self.fittings = sEsi.getFittings(activeChar)
|
|
# self.cacheTime = fittings.get('cached_until')
|
|
# self.updateCacheStatus(None)
|
|
# self.cacheTimer.Start(1000)
|
|
self.fitTree.populateSkillTree(self.fittings)
|
|
del waitDialog
|
|
except requests.exceptions.ConnectionError:
|
|
msg = _t("Connection error, please check your internet connection")
|
|
pyfalog.error(msg)
|
|
self.statusbar.SetStatusText(msg)
|
|
except APIException as ex:
|
|
# Can't do this in a finally because then it obscures the message dialog
|
|
del waitDialog # noqa: F821
|
|
ESIExceptionHandler(ex)
|
|
except (KeyboardInterrupt, SystemExit):
|
|
raise
|
|
except Exception as ex:
|
|
del waitDialog # noqa: F821
|
|
raise ex
|
|
|
|
def importFitting(self, event):
|
|
selection = self.fitView.fitSelection
|
|
if not selection:
|
|
return
|
|
data = self.fitTree.fittingsTreeCtrl.GetItemData(selection)
|
|
sPort = Port.getInstance()
|
|
import_type, fits = sPort.importFitFromBuffer(data)
|
|
self.mainFrame._openAfterImport(fits)
|
|
|
|
def deleteFitting(self, event):
|
|
self.statusbar.SetStatusText("")
|
|
sEsi = Esi.getInstance()
|
|
selection = self.fitView.fitSelection
|
|
if not selection:
|
|
return
|
|
data = json.loads(self.fitTree.fittingsTreeCtrl.GetItemData(selection))
|
|
|
|
with wx.MessageDialog(
|
|
self, _t("Do you really want to delete {} ({}) from EVE?").format(data['name'], getItem(data['ship_type_id']).name),
|
|
_t("Confirm Delete"), wx.YES | wx.NO | wx.ICON_QUESTION
|
|
) as dlg:
|
|
if dlg.ShowModal() == wx.ID_YES:
|
|
activeChar = self.getActiveCharacter()
|
|
if activeChar is None:
|
|
return
|
|
try:
|
|
try:
|
|
sEsi.delFitting(activeChar, data['fitting_id'])
|
|
# repopulate the fitting list
|
|
self.fitTree.populateSkillTree(self.fittings)
|
|
self.fitView.update([])
|
|
except APIException as ex:
|
|
pyfalog.error(ex)
|
|
self.statusbar.SetStatusText("Failed to delete fit: ESI error {} received - {}".format(ex.status_code, ex.response["error"]))
|
|
try:
|
|
ESIExceptionHandler(ex)
|
|
except:
|
|
# don't need to do anything - we should already have error code in the status
|
|
pass
|
|
except requests.exceptions.ConnectionError:
|
|
msg = _t("Connection error, please check your internet connection")
|
|
pyfalog.error(msg)
|
|
self.statusbar.SetStatusText(msg)
|
|
|
|
def deleteAllFittings(self, event):
|
|
self.statusbar.SetStatusText("")
|
|
sEsi = Esi.getInstance()
|
|
activeChar = self.getActiveCharacter()
|
|
if activeChar is None:
|
|
return
|
|
charName = sEsi.getSsoCharacter(activeChar).characterName
|
|
anyDeleted = False
|
|
with wx.MessageDialog(
|
|
self, "Do you really want to delete all fits from %s in EVE?"%(charName),
|
|
"Confirm Delete", wx.YES | wx.NO | wx.ICON_QUESTION
|
|
) as dlg:
|
|
if dlg.ShowModal() == wx.ID_YES:
|
|
try:
|
|
try:
|
|
for fit in self.fittings:
|
|
sEsi.delFitting(activeChar, fit['fitting_id'])
|
|
anyDeleted = True
|
|
except APIException as ex:
|
|
pyfalog.error(ex)
|
|
if anyDeleted:
|
|
msg = "Some fits were not deleted: ESI error {} received - {}".format(ex.status_code,
|
|
ex.response["error"])
|
|
else:
|
|
msg = "Failed to delete fits: ESI error {} received - {}".format(ex.status_code,
|
|
ex.response["error"])
|
|
pyfalog.error(msg)
|
|
self.statusbar.SetStatusText(msg)
|
|
try:
|
|
ESIExceptionHandler(ex)
|
|
except:
|
|
# don't need to do anything - we should already have error code in the status
|
|
pass
|
|
except requests.exceptions.ConnectionError:
|
|
msg = "Connection error, please check your internet connection"
|
|
pyfalog.error(msg)
|
|
self.statusbar.SetStatusText(msg)
|
|
|
|
# repopulate the fitting list
|
|
self.fitTree.populateSkillTree(self.fittings)
|
|
self.fitView.update([])
|
|
|
|
|
|
class ESIExceptionHandler:
|
|
# todo: make this a generate excetpion handler for all calls
|
|
def __init__(self, ex):
|
|
# raise ex
|
|
if ex.response['error'].startswith('Token is not valid') \
|
|
or ex.response['error'] == 'invalid_token' \
|
|
or ex.response['error'] == 'invalid_grant': # todo: this seems messy, figure out a better response
|
|
pyfalog.error(ex)
|
|
with wx.MessageDialog(
|
|
gui.mainFrame.MainFrame.getInstance(),
|
|
_t("There was an error validating characters' SSO token. Please try "
|
|
"logging into the character again to reset the token."),
|
|
_t("Invalid Token"),
|
|
wx.OK | wx.ICON_ERROR | wx.CANCEL
|
|
) as dlg:
|
|
dlg.SetOKLabel("Manage ESI Characters")
|
|
ret = dlg.ShowModal()
|
|
if ret == wx.ID_OK:
|
|
SsoCharacterMgmt.openOne(parent=gui.mainFrame.MainFrame.getInstance())
|
|
# todo: spawn manage esi characters
|
|
pass
|
|
elif ex.response['error'].startswith('Timeout contacting'):
|
|
pyfalog.error(ex)
|
|
with wx.MessageDialog(
|
|
gui.mainFrame.MainFrame.getInstance(),
|
|
"HTTP %s: %s\n\n" % (ex.status_code, ex.response['error'])
|
|
+ _t("The server took too long to response. Please try again in a moment."),
|
|
_t("Timeout"),
|
|
wx.OK | wx.ICON_ERROR
|
|
) as dlg:
|
|
dlg.ShowModal()
|
|
else:
|
|
# We don't know how to handle the error, raise it for the global error handler to pick it up
|
|
raise ex
|
|
|
|
|
|
class ExportToEve(AuxiliaryFrame):
|
|
|
|
def __init__(self, parent):
|
|
super().__init__(
|
|
parent, id=wx.ID_ANY, title=_t("Export fit to EVE"), pos=wx.DefaultPosition,
|
|
size=wx.Size(400, 175) if "wxGTK" in wx.PlatformInfo else wx.Size(350, 145), resizeable=True)
|
|
|
|
self.mainFrame = parent
|
|
|
|
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
|
hSizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
|
|
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, _t("Export Fit"), wx.DefaultPosition, wx.DefaultSize, 5)
|
|
hSizer.Add(self.exportBtn, 0, wx.ALL, 5)
|
|
|
|
mainSizer.Add(hSizer, 0, wx.EXPAND, 5)
|
|
|
|
self.exportChargesCb = wx.CheckBox(self, wx.ID_ANY, _t('Export Loaded Charges'), wx.DefaultPosition, wx.DefaultSize, 0)
|
|
self.exportChargesCb.SetValue(EsiSettings.getInstance().get('exportCharges'))
|
|
self.exportChargesCb.Bind(wx.EVT_CHECKBOX, self.OnChargeExportChange)
|
|
mainSizer.Add(self.exportChargesCb, 0, 0, 5)
|
|
|
|
self.exportImplantsCb = wx.CheckBox(self, wx.ID_ANY, _t('Export Implants'), wx.DefaultPosition, wx.DefaultSize, 0)
|
|
self.exportImplantsCb.SetValue(EsiSettings.getInstance().get('exportImplants'))
|
|
self.exportImplantsCb.Bind(wx.EVT_CHECKBOX, self.OnImplantsExportChange)
|
|
mainSizer.Add(self.exportImplantsCb, 0, 0, 5)
|
|
|
|
self.exportBoostersCb = wx.CheckBox(self, wx.ID_ANY, _t('Export Boosters'), wx.DefaultPosition, wx.DefaultSize, 0)
|
|
self.exportBoostersCb.SetValue(EsiSettings.getInstance().get('exportBoosters'))
|
|
self.exportBoostersCb.Bind(wx.EVT_CHECKBOX, self.OnBoostersExportChange)
|
|
mainSizer.Add(self.exportBoostersCb, 0, 0, 5)
|
|
|
|
self.exportBtn.Bind(wx.EVT_BUTTON, self.exportFitting)
|
|
|
|
self.statusbar = wx.StatusBar(self)
|
|
self.statusbar.SetFieldsCount(2)
|
|
self.statusbar.SetStatusWidths([100, -1])
|
|
|
|
self.Bind(wx.EVT_CHAR_HOOK, self.kbEvent)
|
|
|
|
self.SetSizer(mainSizer)
|
|
self.SetStatusBar(self.statusbar)
|
|
self.Layout()
|
|
self.SetMinSize(self.GetSize())
|
|
|
|
self.Center(wx.BOTH)
|
|
|
|
def OnChargeExportChange(self, event):
|
|
EsiSettings.getInstance().set('exportCharges', self.exportChargesCb.GetValue())
|
|
event.Skip()
|
|
|
|
def OnImplantsExportChange(self, event):
|
|
EsiSettings.getInstance().set('exportImplants', self.exportImplantsCb.GetValue())
|
|
event.Skip()
|
|
|
|
def OnBoostersExportChange(self, event):
|
|
EsiSettings.getInstance().set('exportBoosters', self.exportBoostersCb.GetValue())
|
|
event.Skip()
|
|
|
|
def updateCharList(self):
|
|
sEsi = Esi.getInstance()
|
|
chars = sEsi.getSsoCharacters()
|
|
|
|
self.charChoice.Clear()
|
|
for char in chars:
|
|
self.charChoice.Append(char.characterDisplay, char.ID)
|
|
|
|
if len(chars) > 0:
|
|
self.charChoice.SetSelection(0)
|
|
|
|
def kbEvent(self, event):
|
|
if event.GetKeyCode() == wx.WXK_ESCAPE and event.GetModifiers() == wx.MOD_NONE:
|
|
self.Close()
|
|
return
|
|
event.Skip()
|
|
|
|
def getActiveCharacter(self):
|
|
selection = self.charChoice.GetCurrentSelection()
|
|
return self.charChoice.GetClientData(selection) if selection not in (None, -1) else None
|
|
|
|
def exportFitting(self, event):
|
|
sPort = Port.getInstance()
|
|
fitID = self.mainFrame.getActiveFit()
|
|
|
|
self.statusbar.SetStatusText("", 0)
|
|
|
|
if fitID is None:
|
|
self.statusbar.SetStatusText(_t("Please select an active fitting in the main window"), 1)
|
|
return
|
|
|
|
self.statusbar.SetStatusText(_t("Sending request and awaiting response"), 1)
|
|
sEsi = Esi.getInstance()
|
|
|
|
sFit = Fit.getInstance()
|
|
exportCharges = self.exportChargesCb.GetValue()
|
|
exportImplants = self.exportImplantsCb.GetValue()
|
|
exportBoosters = self.exportBoostersCb.GetValue()
|
|
try:
|
|
data = sPort.exportESI(sFit.getFit(fitID), exportCharges, exportImplants, exportBoosters)
|
|
except ESIExportException as e:
|
|
msg = str(e)
|
|
if not msg:
|
|
msg = _t("Failed to generate export data")
|
|
pyfalog.warning(msg)
|
|
self.statusbar.SetStatusText(msg, 1)
|
|
return
|
|
activeChar = self.getActiveCharacter()
|
|
if activeChar is None:
|
|
msg = _t("Need at least one ESI character to export")
|
|
pyfalog.warning(msg)
|
|
self.statusbar.SetStatusText(msg, 1)
|
|
return
|
|
|
|
try:
|
|
res = sEsi.postFitting(activeChar, data)
|
|
res.raise_for_status()
|
|
self.statusbar.SetStatusText("", 0)
|
|
self.statusbar.SetStatusText(res.reason, 1)
|
|
except requests.exceptions.ConnectionError:
|
|
msg = _t("Connection error, please check your internet connection")
|
|
pyfalog.error(msg)
|
|
self.statusbar.SetStatusText(_t("ERROR"), 0)
|
|
self.statusbar.SetStatusText(msg, 1)
|
|
except APIException as ex:
|
|
pyfalog.error(ex)
|
|
self.statusbar.SetStatusText(_t("ERROR"), 0)
|
|
self.statusbar.SetStatusText("HTTP {} - {}".format(ex.status_code, ex.response["error"]), 1)
|
|
try:
|
|
ESIExceptionHandler(ex)
|
|
except:
|
|
# don't need to do anything - we should already get the error in ex.response
|
|
pass
|
|
except Exception as ex:
|
|
self.statusbar.SetStatusText(_t("ERROR"), 0)
|
|
self.statusbar.SetStatusText("Unknown error", 1)
|
|
pyfalog.error(ex)
|
|
|
|
|
|
class SsoCharacterMgmt(AuxiliaryFrame):
|
|
|
|
def __init__(self, parent):
|
|
super().__init__(
|
|
parent, id=wx.ID_ANY, title=_t("SSO Character Management"), pos=wx.DefaultPosition,
|
|
size=wx.Size(550, 250), resizeable=True)
|
|
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=_t('Character'))
|
|
self.lcCharacters.InsertColumn(1, heading=_t('Character ID'))
|
|
self.lcCharacters.InsertColumn(2, heading=_t('Server'))
|
|
|
|
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, _t("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, _t("Remove 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.Bind(wx.EVT_CLOSE, self.OnClose)
|
|
self.Bind(wx.EVT_CHAR_HOOK, self.kbEvent)
|
|
|
|
self.SetSizer(mainSizer)
|
|
self.Layout()
|
|
self.SetMinSize(self.GetSize())
|
|
|
|
self.Centre(wx.BOTH)
|
|
|
|
def ssoLogin(self, event):
|
|
self.popCharList()
|
|
sChar = Character.getInstance()
|
|
# Update existing pyfa character, if it doesn't exist - create new
|
|
char = sChar.getCharacter(event.character.characterName)
|
|
newChar = False
|
|
if char is None:
|
|
char = sChar.new(event.character.characterName)
|
|
newChar = True
|
|
char.setSsoCharacter(event.character, config.getClientSecret())
|
|
sChar.apiFetch(char.ID, APIView.fetchCallback)
|
|
wx.PostEvent(self.mainFrame, GE.CharListUpdated())
|
|
event.Skip()
|
|
|
|
def kbEvent(self, event):
|
|
if event.GetKeyCode() == wx.WXK_ESCAPE and event.GetModifiers() == wx.MOD_NONE:
|
|
self.Close()
|
|
return
|
|
event.Skip()
|
|
|
|
def OnClose(self, event):
|
|
self.mainFrame.Unbind(GE.EVT_SSO_LOGIN, handler=self.ssoLogin)
|
|
event.Skip()
|
|
|
|
def popCharList(self):
|
|
sEsi = Esi.getInstance()
|
|
chars = sEsi.getSsoCharacters()
|
|
|
|
self.lcCharacters.DeleteAllItems()
|
|
|
|
for index, char in enumerate(chars):
|
|
self.lcCharacters.InsertItem(index, char.characterName)
|
|
self.lcCharacters.SetItem(index, 1, str(char.characterID))
|
|
self.lcCharacters.SetItemData(index, char.ID)
|
|
self.lcCharacters.SetItem(index, 2, char.server or "<unknown>")
|
|
|
|
self.lcCharacters.SetColumnWidth(0, wx.LIST_AUTOSIZE)
|
|
self.lcCharacters.SetColumnWidth(1, wx.LIST_AUTOSIZE)
|
|
self.lcCharacters.SetColumnWidth(2, wx.LIST_AUTOSIZE)
|
|
|
|
def addChar(self, event):
|
|
try:
|
|
sEsi = Esi.getInstance()
|
|
sEsi.login()
|
|
except (KeyboardInterrupt, SystemExit):
|
|
raise
|
|
|
|
def delChar(self, event):
|
|
item = self.lcCharacters.GetFirstSelected()
|
|
if item > -1:
|
|
charID = self.lcCharacters.GetItemData(item)
|
|
sEsi = Esi.getInstance()
|
|
sEsi.delSsoCharacter(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_SEL_CHANGED, 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)
|
|
|
|
sEsi = Esi.getInstance()
|
|
|
|
dict = {}
|
|
fits = data
|
|
for fit in fits:
|
|
if fit['fitting_id'] in sEsi.fittings_deleted:
|
|
continue
|
|
ship = getItem(fit['ship_type_id'])
|
|
if ship is None:
|
|
pyfalog.debug('Cannot find ship type id: {}'.format(fit['ship_type_id']))
|
|
continue
|
|
if ship.name not in dict:
|
|
dict[ship.name] = []
|
|
dict[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.SetItemData(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 (KeyboardInterrupt, SystemExit):
|
|
raise
|
|
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
|