Merge branch 'master' into colour-item-list

This commit is contained in:
Ryan Holmes
2019-03-02 15:27:54 -05:00
committed by GitHub
16 changed files with 543 additions and 125 deletions

View File

@@ -110,7 +110,7 @@ def defPaths(customSavePath=None):
# Version data
with open(os.path.join(pyfaPath, "version.yml"), 'r') as file:
data = yaml.load(file)
data = yaml.load(file, Loader=yaml.FullLoader)
version = data['version']
# Where we store the saved fits etc, default is the current users home directory

View File

@@ -8,7 +8,7 @@ import yaml
with open("version.yml", 'r') as file:
data = yaml.load(file)
data = yaml.load(file, Loader=yaml.FullLoader)
version = data['version']
os.environ["PYFA_DIST_DIR"] = os.path.join(os.getcwd(), 'dist')

View File

@@ -39,6 +39,8 @@ attributes_table = Table("dgmattribs", gamedata_meta,
Column("displayName", String),
Column("highIsGood", Boolean),
Column("iconID", Integer),
Column("attributeCategory", Integer),
Column("tooltipDescription", Integer),
Column("unitID", Integer, ForeignKey("dgmunits.unitID")))
mapper(Attribute, typeattributes_table,

View File

@@ -577,6 +577,15 @@ class Unit(EqBase):
self.name = None
self.displayName = None
@property
def rigSizes(self):
return {
1: "Small",
2: "Medium",
3: "Large",
4: "X-Large"
}
@property
def translations(self):
""" This is a mapping of various tweaks that we have to do between the internal representation of an attribute
@@ -609,10 +618,10 @@ class Unit(EqBase):
lambda u: "",
lambda d: d),
"Sizeclass": (
lambda v: v,
lambda v: v,
lambda u: "",
lambda d: d),
lambda v: self.rigSizes[v],
lambda v: self.rigSizes[v],
lambda d: next(i for i in self.rigSizes.keys() if self.rigSizes[i] == 'Medium'),
lambda u: ""),
"Absolute Percent": (
lambda v: v * 100,
lambda v: v * 100,

BIN
eve.db

Binary file not shown.

View File

@@ -82,9 +82,7 @@ class BitmapLoader(object):
@classmethod
def loadBitmap(cls, name, location):
if cls.scaling_factor is None:
import gui.mainFrame
cls.scaling_factor = int(gui.mainFrame.MainFrame.getInstance().GetContentScaleFactor())
cls.scaling_factor = int(wx.GetApp().GetTopWindow().GetContentScaleFactor())
scale = cls.scaling_factor
filename, img = cls.loadScaledBitmap(name, location, scale)

View File

@@ -0,0 +1,254 @@
from enum import Enum, auto
# Define the various groups of attributes
class AttrGroup(Enum):
FITTING = auto()
STRUCTURE = auto()
SHIELD = auto()
ARMOR = auto()
TARGETING = auto()
EWAR_RESISTS = auto()
CAPACITOR = auto()
SHARED_FACILITIES = auto()
FIGHTER_FACILITIES = auto()
ON_DEATH = auto()
JUMP_SYSTEMS = auto()
PROPULSIONS = auto()
FIGHTERS = auto()
RequiredSkillAttrs = sum((["requiredSkill{}".format(x), "requiredSkill{}Level".format(x)] for x in range(1, 7)), [])
#todo: maybe moved some of these basic definitions into eos proper? Can really be useful with effect writing as a lot of these are used over and over
damage_types = ["em", "thermal", "kinetic", "explosive"]
scan_types = ["radar", "magnetometric", "gravimetric", "ladar"]
DamageAttrs = ["{}Damage".format(x) for x in damage_types]
HullResistsAttrs = ["{}DamageResonance".format(x) for x in damage_types]
ArmorResistsAttrs = ["armor{}DamageResonance".format(x.capitalize()) for x in damage_types]
ShieldResistsAttrs = ["shield{}DamageResonance".format(x.capitalize()) for x in damage_types]
ScanStrAttrs = ["scan{}Strength".format(x.capitalize()) for x in scan_types]
# todo: convert to named tuples?
AttrGroups = [
(DamageAttrs, "Damage"),
(HullResistsAttrs, "Resistances"),
(ArmorResistsAttrs, "Resistances"),
(ShieldResistsAttrs, "Resistances"),
(ScanStrAttrs, "Sensor Strengths")
]
GroupedAttributes = []
for x in AttrGroups:
GroupedAttributes += x[0]
# Start defining all the known attribute groups
AttrGroupDict = {
AttrGroup.FITTING : {
"label" : "Fitting",
"attributes": [
# parent-level attributes
"cpuOutput",
"powerOutput",
"upgradeCapacity",
"hiSlots",
"medSlots",
"lowSlots",
"serviceSlots",
"turretSlotsLeft",
"launcherSlotsLeft",
"upgradeSlotsLeft",
# child-level attributes
"cpu",
"power",
"rigSize",
"upgradeCost",
# "mass",
]
},
AttrGroup.STRUCTURE : {
"label" : "Structure",
"attributes": [
"hp",
"capacity",
"mass",
"volume",
"agility",
"droneCapacity",
"droneBandwidth",
"specialOreHoldCapacity",
"specialGasHoldCapacity",
"specialMineralHoldCapacity",
"specialSalvageHoldCapacity",
"specialShipHoldCapacity",
"specialSmallShipHoldCapacity",
"specialMediumShipHoldCapacity",
"specialLargeShipHoldCapacity",
"specialIndustrialShipHoldCapacity",
"specialAmmoHoldCapacity",
"specialCommandCenterHoldCapacity",
"specialPlanetaryCommoditiesHoldCapacity",
"structureDamageLimit",
"specialSubsystemHoldCapacity",
"emDamageResonance",
"thermalDamageResonance",
"kineticDamageResonance",
"explosiveDamageResonance"
]
},
AttrGroup.ARMOR : {
"label": "Armor",
"attributes":[
"armorHP",
"armorDamageLimit",
"armorEmDamageResonance",
"armorThermalDamageResonance",
"armorKineticDamageResonance",
"armorExplosiveDamageResonance",
]
},
AttrGroup.SHIELD : {
"label": "Shield",
"attributes": [
"shieldCapacity",
"shieldRechargeRate",
"shieldDamageLimit",
"shieldEmDamageResonance",
"shieldExplosiveDamageResonance",
"shieldKineticDamageResonance",
"shieldThermalDamageResonance",
]
},
AttrGroup.EWAR_RESISTS : {
"label": "Electronic Warfare",
"attributes": [
"ECMResistance",
"remoteAssistanceImpedance",
"remoteRepairImpedance",
"energyWarfareResistance",
"sensorDampenerResistance",
"stasisWebifierResistance",
"targetPainterResistance",
"weaponDisruptionResistance",
]
},
AttrGroup.CAPACITOR : {
"label": "Capacitor",
"attributes": [
"capacitorCapacity",
"rechargeRate",
]
},
AttrGroup.TARGETING : {
"label": "Targeting",
"attributes": [
"maxTargetRange",
"maxRange",
"maxLockedTargets",
"signatureRadius",
"optimalSigRadius",
"scanResolution",
"proximityRange",
"falloff",
"trackingSpeed",
"scanRadarStrength",
"scanMagnetometricStrength",
"scanGravimetricStrength",
"scanLadarStrength",
]
},
AttrGroup.SHARED_FACILITIES : {
"label" : "Shared Facilities",
"attributes": [
"fleetHangarCapacity",
"shipMaintenanceBayCapacity",
"maxJumpClones",
]
},
AttrGroup.FIGHTER_FACILITIES: {
"label": "Fighter Squadron Facilities",
"attributes": [
"fighterCapacity",
"fighterTubes",
"fighterLightSlots",
"fighterSupportSlots",
"fighterHeavySlots",
"fighterStandupLightSlots",
"fighterStandupSupportSlots",
"fighterStandupHeavySlots",
]
},
AttrGroup.ON_DEATH : {
"label": "On Death",
"attributes": [
"onDeathDamageEM",
"onDeathDamageTherm",
"onDeathDamageKin",
"onDeathDamageExp",
"onDeathAOERadius",
"onDeathSignatureRadius",
]
},
AttrGroup.JUMP_SYSTEMS : {
"label": "Jump Drive Systems",
"attributes": [
"jumpDriveCapacitorNeed",
"jumpDriveRange",
"jumpDriveConsumptionType",
"jumpDriveConsumptionAmount",
"jumpPortalCapacitorNeed",
"jumpDriveDuration",
"specialFuelBayCapacity",
"jumpPortalConsumptionMassFactor",
"jumpPortalDuration",
]
},
AttrGroup.PROPULSIONS : {
"label": "Propulsion",
"attributes": [
"maxVelocity"
]
},
AttrGroup.FIGHTERS : {
"label": "Fighter",
"attributes": [
"mass",
"maxVelocity",
"agility",
"volume",
"signatureRadius",
"fighterSquadronMaxSize",
"fighterRefuelingTime",
"fighterSquadronOrbitRange",
]
},
}
Group1 = [
AttrGroup.FITTING,
AttrGroup.STRUCTURE,
AttrGroup.ARMOR,
AttrGroup.SHIELD,
AttrGroup.EWAR_RESISTS,
AttrGroup.CAPACITOR,
AttrGroup.TARGETING,
AttrGroup.SHARED_FACILITIES,
AttrGroup.FIGHTER_FACILITIES,
AttrGroup.ON_DEATH,
AttrGroup.JUMP_SYSTEMS,
AttrGroup.PROPULSIONS,
]
CategoryGroups = {
"Fighter" : [
AttrGroup.FIGHTERS,
AttrGroup.SHIELD,
AttrGroup.TARGETING,
],
"Ship" : Group1,
"Drone" : Group1,
"Structure": Group1
}

View File

@@ -3,11 +3,18 @@ import config
# noinspection PyPackageRequirements
import wx
from .helpers import AutoListCtrl
import wx.lib.agw.hypertreelist
from gui.builtinItemStatsViews.helpers import AutoListCtrl
from gui.bitmap_loader import BitmapLoader
from gui.utils.numberFormatter import formatAmount, roundDec
from enum import IntEnum
from gui.builtinItemStatsViews.attributeGrouping import *
class AttributeView(IntEnum):
NORMAL = 1
RAW = -1
class ItemParams(wx.Panel):
@@ -15,8 +22,9 @@ class ItemParams(wx.Panel):
wx.Panel.__init__(self, parent)
mainSizer = wx.BoxSizer(wx.VERTICAL)
self.paramList = AutoListCtrl(self, wx.ID_ANY,
style=wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES | wx.NO_BORDER)
self.paramList = wx.lib.agw.hypertreelist.HyperTreeList(self, wx.ID_ANY, agwStyle=wx.TR_HIDE_ROOT | wx.TR_NO_LINES | wx.TR_FULL_ROW_HIGHLIGHT | wx.TR_HAS_BUTTONS)
self.paramList.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW))
mainSizer.Add(self.paramList, 1, wx.ALL | wx.EXPAND, 0)
self.SetSizer(mainSizer)
@@ -27,14 +35,19 @@ class ItemParams(wx.Panel):
self.attrValues = {}
self._fetchValues()
self.paramList.AddColumn("Attribute")
self.paramList.AddColumn("Current Value")
if self.stuff is not None:
self.paramList.AddColumn("Base Value")
self.paramList.SetMainColumn(0) # the one with the tree in it...
self.paramList.SetColumnWidth(0, 300)
self.m_staticline = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL)
mainSizer.Add(self.m_staticline, 0, wx.EXPAND)
bSizer = wx.BoxSizer(wx.HORIZONTAL)
self.totalAttrsLabel = wx.StaticText(self, wx.ID_ANY, " ", wx.DefaultPosition, wx.DefaultSize, 0)
bSizer.Add(self.totalAttrsLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT)
self.toggleViewBtn = wx.ToggleButton(self, wx.ID_ANY, "Toggle view mode", wx.DefaultPosition, wx.DefaultSize,
self.toggleViewBtn = wx.ToggleButton(self, wx.ID_ANY, "Veiw Raw Data", wx.DefaultPosition, wx.DefaultSize,
0)
bSizer.Add(self.toggleViewBtn, 0, wx.ALIGN_CENTER_VERTICAL)
@@ -76,10 +89,10 @@ class ItemParams(wx.Panel):
def UpdateList(self):
self.Freeze()
self.paramList.ClearAll()
self.paramList.DeleteRoot()
self.PopulateList()
self.Thaw()
self.paramList.resizeLastColumn(100)
# self.paramList.resizeLastColumn(100)
def RefreshValues(self, event):
self._fetchValues()
@@ -151,89 +164,154 @@ class ItemParams(wx.Panel):
]
)
def AddAttribute(self, parent, attr):
if attr in self.attrValues and attr not in self.processed_attribs:
data = self.GetData(attr)
if data is None:
return
attrIcon, attrName, currentVal, baseVal = data
attr_item = self.paramList.AppendItem(parent, attrName)
self.paramList.SetItemText(attr_item, currentVal, 1)
if self.stuff is not None:
self.paramList.SetItemText(attr_item, baseVal, 2)
self.paramList.SetItemImage(attr_item, attrIcon, which=wx.TreeItemIcon_Normal)
self.processed_attribs.add(attr)
def ExpandOrDelete(self, item):
if self.paramList.GetChildrenCount(item) == 0:
self.paramList.Delete(item)
else:
self.paramList.Expand(item)
def PopulateList(self):
self.paramList.InsertColumn(0, "Attribute")
self.paramList.InsertColumn(1, "Current Value")
if self.stuff is not None:
self.paramList.InsertColumn(2, "Base Value")
self.paramList.SetColumnWidth(0, 110)
self.paramList.SetColumnWidth(1, 90)
if self.stuff is not None:
self.paramList.SetColumnWidth(2, 90)
self.paramList.setResizeColumn(0)
# self.paramList.setResizeColumn(0)
self.imageList = wx.ImageList(16, 16)
self.paramList.SetImageList(self.imageList, wx.IMAGE_LIST_SMALL)
self.processed_attribs = set()
root = self.paramList.AddRoot("The Root Item")
misc_parent = root
# We must first deet4ermine if it's categorey already has defined groupings set for it. Otherwise, we default to just using the fitting group
order = CategoryGroups.get(self.item.category.categoryName, [AttrGroup.FITTING])
# start building out the tree
for data in [AttrGroupDict[o] for o in order]:
heading = data.get("label")
header_item = self.paramList.AppendItem(root, heading)
for attr in data.get("attributes", []):
# Attribute is a "grouped" attr (eg: damage, sensor strengths, etc). Automatically group these into a child item
if attr in GroupedAttributes:
# find which group it's in
for grouping in AttrGroups:
if attr in grouping[0]:
break
# create a child item with the groups label
item = self.paramList.AppendItem(header_item, grouping[1])
for attr2 in grouping[0]:
# add each attribute in the group
self.AddAttribute(item, attr2)
self.ExpandOrDelete(item)
continue
self.AddAttribute(header_item, attr)
self.ExpandOrDelete(header_item)
names = list(self.attrValues.keys())
names.sort()
idNameMap = {}
idCount = 0
# this will take care of any attributes that weren't collected withe the defined grouping (or all attributes if the item ddidn't have anything defined)
for name in names:
info = self.attrInfo.get(name)
att = self.attrValues[name]
if name in GroupedAttributes:
# find which group it's in
for grouping in AttrGroups:
if name in grouping[0]:
break
# If we're working with a stuff object, we should get the original value from our getBaseAttrValue function,
# which will return the value with respect to the effective base (with mutators / overrides in place)
valDefault = getattr(info, "value", None) # Get default value from attribute
if self.stuff is not None:
# if it's a stuff, overwrite default (with fallback to current value)
valDefault = self.stuff.getBaseAttrValue(name, valDefault)
valueDefault = valDefault if valDefault is not None else att
# get all attributes in group
item = self.paramList.AppendItem(root, grouping[1])
for attr2 in grouping[0]:
self.AddAttribute(item, attr2)
val = getattr(att, "value", None)
value = val if val is not None else att
self.ExpandOrDelete(item)
continue
if info and info.displayName and self.toggleView == 1:
attrName = info.displayName
else:
attrName = name
self.AddAttribute(root, name)
if info and config.debug:
attrName += " ({})".format(info.ID)
self.paramList.AssignImageList(self.imageList)
self.Layout()
if info:
if info.iconID is not None:
iconFile = info.iconID
icon = BitmapLoader.getBitmap(iconFile, "icons")
def GetData(self, attr):
info = self.attrInfo.get(attr)
att = self.attrValues[attr]
if icon is None:
icon = BitmapLoader.getBitmap("transparent16x16", "gui")
# If we're working with a stuff object, we should get the original value from our getBaseAttrValue function,
# which will return the value with respect to the effective base (with mutators / overrides in place)
valDefault = getattr(info, "value", None) # Get default value from attribute
if self.stuff is not None:
# if it's a stuff, overwrite default (with fallback to current value)
valDefault = self.stuff.getBaseAttrValue(attr, valDefault)
valueDefault = valDefault if valDefault is not None else att
attrIcon = self.imageList.Add(icon)
else:
attrIcon = self.imageList.Add(BitmapLoader.getBitmap("0", "icons"))
val = getattr(att, "value", None)
value = val if val is not None else att
if self.toggleView == AttributeView.NORMAL and ((attr not in GroupedAttributes and not value) or info is None or not info.published or attr in RequiredSkillAttrs):
return None
if info and info.displayName and self.toggleView == 1:
attrName = info.displayName
else:
attrName = attr
if info and config.debug:
attrName += " ({})".format(info.ID)
if info:
if info.iconID is not None:
iconFile = info.iconID
icon = BitmapLoader.getBitmap(iconFile, "icons")
if icon is None:
icon = BitmapLoader.getBitmap("transparent16x16", "gui")
attrIcon = self.imageList.Add(icon)
else:
attrIcon = self.imageList.Add(BitmapLoader.getBitmap("0", "icons"))
else:
attrIcon = self.imageList.Add(BitmapLoader.getBitmap("0", "icons"))
index = self.paramList.InsertItem(self.paramList.GetItemCount(), attrName, attrIcon)
idNameMap[idCount] = attrName
self.paramList.SetItemData(index, idCount)
idCount += 1
# index = self.paramList.AppendItem(root, attrName)
# idNameMap[idCount] = attrName
# self.paramList.SetPyData(index, idCount)
# idCount += 1
if self.toggleView != 1:
valueUnit = str(value)
elif info and info.unit:
valueUnit = self.FormatValue(*info.unit.PreformatValue(value))
else:
valueUnit = formatAmount(value, 3, 0, 0)
if self.toggleView != 1:
valueUnit = str(value)
elif info and info.unit:
valueUnit = self.FormatValue(*info.unit.PreformatValue(value))
else:
valueUnit = formatAmount(value, 3, 0, 0)
if self.toggleView != 1:
valueUnitDefault = str(valueDefault)
elif info and info.unit:
valueUnitDefault = self.FormatValue(*info.unit.PreformatValue(valueDefault))
else:
valueUnitDefault = formatAmount(valueDefault, 3, 0, 0)
if self.toggleView != 1:
valueUnitDefault = str(valueDefault)
elif info and info.unit:
valueUnitDefault = self.FormatValue(*info.unit.PreformatValue(valueDefault))
else:
valueUnitDefault = formatAmount(valueDefault, 3, 0, 0)
self.paramList.SetItem(index, 1, valueUnit)
if self.stuff is not None:
self.paramList.SetItem(index, 2, valueUnitDefault)
# @todo: pheonix, this lamda used cmp() which no longer exists in py3. Probably a better way to do this in the
# long run, take a look
self.paramList.SortItems(lambda id1, id2: (idNameMap[id1] > idNameMap[id2]) - (idNameMap[id1] < idNameMap[id2]))
self.paramList.RefreshRows()
self.totalAttrsLabel.SetLabel("%d attributes. " % idCount)
self.Layout()
# todo: attribute that point to another item should load that item's icon.
return (attrIcon, attrName, valueUnit, valueUnitDefault)
# self.paramList.SetItemText(index, valueUnit, 1)
# if self.stuff is not None:
# self.paramList.SetItemText(index, valueUnitDefault, 2)
# self.paramList.SetItemImage(index, attrIcon, which=wx.TreeItemIcon_Normal)
@staticmethod
def FormatValue(value, unit, rounding='prec', digits=3):
@@ -246,3 +324,43 @@ class ItemParams(wx.Panel):
else:
fvalue = value
return "%s %s" % (fvalue, unit)
if __name__ == "__main__":
import eos.db
# need to set up some paths, since bitmap loader requires config to have things
# Should probably change that so that it's not dependant on config
import os
os.chdir('..')
import config
config.defPaths(None)
config.debug = True
class Frame(wx.Frame):
def __init__(self, ):
# item = eos.db.getItem(23773) # Ragnarok
item = eos.db.getItem(23061) # Einherji I
#item = eos.db.getItem(24483) # Nidhoggur
#item = eos.db.getItem(587) # Rifter
#item = eos.db.getItem(2486) # Warrior I
#item = eos.db.getItem(526) # Stasis Webifier I
item = eos.db.getItem(486) # 200mm AutoCannon I
#item = eos.db.getItem(200) # Phased Plasma L
super().__init__(None, title="Test Attribute Window | {} - {}".format(item.ID, item.name), size=(1000, 500))
if 'wxMSW' in wx.PlatformInfo:
color = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE)
self.SetBackgroundColour(color)
main_sizer = wx.BoxSizer(wx.HORIZONTAL)
panel = ItemParams(self, None, item)
main_sizer.Add(panel, 1, wx.EXPAND | wx.ALL, 2)
self.SetSizer(main_sizer)
app = wx.App(redirect=False) # Error messages go to popup window
top = Frame()
top.Show()
app.MainLoop()

View File

@@ -62,13 +62,11 @@ from gui.preferenceDialog import PreferenceDialog
from gui.resistsEditor import ResistsEditorDlg
from gui.setEditor import ImplantSetEditorDlg
from gui.shipBrowser import ShipBrowser
from gui.ssoLogin import SsoLogin
from gui.statsPane import StatsPane
from gui.updateDialog import UpdateDialog
from gui.utils.clipboard import fromClipboard, toClipboard
from service.character import Character
from service.esi import Esi, LoginMethod
from service.esiAccess import SsoMode
from service.esi import Esi
from service.fit import Fit
from service.port import EfsPort, IPortUser, Port
from service.settings import HTMLExportSettings, SettingsProvider
@@ -230,20 +228,11 @@ class MainFrame(wx.Frame):
self.sUpdate.CheckUpdate(self.ShowUpdateBox)
self.Bind(GE.EVT_SSO_LOGIN, self.onSSOLogin)
self.Bind(GE.EVT_SSO_LOGGING_IN, self.ShowSsoLogin)
@property
def command(self) -> wx.CommandProcessor:
return Fit.getCommandProcessor(self.getActiveFit())
def ShowSsoLogin(self, event):
if getattr(event, "login_mode", LoginMethod.SERVER) == LoginMethod.MANUAL and getattr(event, "sso_mode", SsoMode.AUTO) == SsoMode.AUTO:
dlg = SsoLogin(self)
if dlg.ShowModal() == wx.ID_OK:
sEsi = Esi.getInstance()
# todo: verify that this is a correct SSO Info block
sEsi.handleLogin({'SSOInfo': [dlg.ssoInfoCtrl.Value.strip()]})
def ShowUpdateBox(self, release, version):
dlg = UpdateDialog(self, release, version)
dlg.ShowModal()

View File

@@ -1,9 +1,14 @@
import wx
import gui.mainFrame
import webbrowser
import gui.globalEvents as GE
class SsoLogin(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title="SSO Login", size=wx.Size(400, 240))
def __init__(self):
mainFrame = gui.mainFrame.MainFrame.getInstance()
wx.Dialog.__init__(self, mainFrame, id=wx.ID_ANY, title="SSO Login", size=wx.Size(400, 240))
bSizer1 = wx.BoxSizer(wx.VERTICAL)
@@ -24,3 +29,55 @@ class SsoLogin(wx.Dialog):
self.SetSizer(bSizer1)
self.Center()
mainFrame.Bind(GE.EVT_SSO_LOGIN, self.OnLogin)
from service.esi import Esi
self.sEsi = Esi.getInstance()
uri = self.sEsi.getLoginURI(None)
webbrowser.open(uri)
def OnLogin(self, event):
self.Close()
event.Skip()
class SsoLoginServer(wx.Dialog):
def __init__(self, port):
mainFrame = gui.mainFrame.MainFrame.getInstance()
wx.Dialog.__init__(self, mainFrame, id=wx.ID_ANY, title="SSO Login", size=(-1, -1))
from service.esi import Esi
self.sEsi = Esi.getInstance()
serverAddr = self.sEsi.startServer(port)
uri = self.sEsi.getLoginURI(serverAddr)
bSizer1 = wx.BoxSizer(wx.VERTICAL)
mainFrame.Bind(GE.EVT_SSO_LOGIN, self.OnLogin)
self.Bind(wx.EVT_CLOSE, self.OnClose)
text = wx.StaticText(self, wx.ID_ANY, "Waiting for character login through EVE Single Sign-On.")
bSizer1.Add(text, 0, wx.ALL | wx.EXPAND, 10)
bSizer3 = wx.BoxSizer(wx.VERTICAL)
bSizer3.Add(wx.StaticLine(self, wx.ID_ANY), 0, wx.BOTTOM | wx.EXPAND, 10)
bSizer3.Add(self.CreateStdDialogButtonSizer(wx.CANCEL), 0, wx.EXPAND)
bSizer1.Add(bSizer3, 0, wx.BOTTOM | wx.RIGHT | wx.LEFT | wx.EXPAND, 10)
self.SetSizer(bSizer1)
self.Fit()
self.Center()
webbrowser.open(uri)
def OnLogin(self, event):
self.Close()
event.Skip()
def OnClose(self, event):
self.sEsi.stopServer()
event.Skip()

View File

@@ -1,13 +1,13 @@
wxPython == 4.0.0b2
wxPython == 4.0.4
logbook >= 1.0.0
matplotlib >= 2.0.0
python-dateutil
requests >= 2.0.0
sqlalchemy == 1.0.5
cryptography ==2.2.2
cryptography>=2.3
markdown2==2.3.5
packaging==16.8
roman==2.0.0
beautifulsoup4==4.6.0
PyYAML==3.12
pyyaml>=5.1b1
PyInstaller == 3.3

View File

@@ -10,7 +10,7 @@ import os
with open("version.yml", 'r+') as file:
data = yaml.load(file)
data = yaml.load(file, Loader=yaml.FullLoader)
file.seek(0)
file.truncate()
# todo: run Version() on the tag to ensure that it's of proper formatting - fail a test if not and prevent building

View File

@@ -10,7 +10,7 @@ import json
iconDict = {}
stream = open('iconIDs.yaml', 'r')
docs = yaml.load_all(stream)
docs = yaml.load_all(stream, Loader=yaml.FullLoader)
for doc in docs:
for k,v in list(doc.items()):

View File

@@ -13,9 +13,11 @@ from eos.enum import Enum
from eos.saveddata.ssocharacter import SsoCharacter
from service.esiAccess import APIException, SsoMode
import gui.globalEvents as GE
from gui.ssoLogin import SsoLogin, SsoLoginServer
from service.server import StoppableHTTPServer, AuthHandler
from service.settings import EsiSettings
from service.esiAccess import EsiAccess
import gui.mainFrame
from requests import Session
@@ -104,19 +106,21 @@ class Esi(EsiAccess):
self.fittings_deleted.add(fittingID)
def login(self):
serverAddr = None
# always start the local server if user is using client details. Otherwise, start only if they choose to do so.
if self.settings.get('ssoMode') == SsoMode.CUSTOM or self.settings.get('loginMode') == LoginMethod.SERVER:
# random port, or if it's custom application, use a defined port
serverAddr = self.startServer(6461 if self.settings.get('ssoMode') == SsoMode.CUSTOM else 0)
uri = self.getLoginURI(serverAddr)
webbrowser.open(uri)
wx.PostEvent(self.mainFrame, GE.SsoLoggingIn(sso_mode=self.settings.get('ssoMode'), login_mode=self.settings.get('loginMode')))
dlg = gui.ssoLogin.SsoLoginServer(6461 if self.settings.get('ssoMode') == SsoMode.CUSTOM else 0)
dlg.ShowModal()
else:
dlg = gui.ssoLogin.SsoLogin()
if dlg.ShowModal() == wx.ID_OK:
self.handleLogin({'SSOInfo': [dlg.ssoInfoCtrl.Value.strip()]})
def stopServer(self):
pyfalog.debug("Stopping Server")
self.httpd.stop()
self.httpd = None
if self.httpd:
self.httpd.stop()
self.httpd = None
def startServer(self, port): # todo: break this out into two functions: starting the server, and getting the URI
pyfalog.debug("Starting server")

View File

@@ -43,9 +43,9 @@ class JargonLoader(object):
self.jargon_mtime != self._get_jargon_file_mtime())
def _load_jargon(self):
jargondata = yaml.load(DEFAULT_DATA)
jargondata = yaml.load(DEFAULT_DATA, Loader=yaml.FullLoader)
with open(JARGON_PATH) as f:
userdata = yaml.load(f)
userdata = yaml.load(f, Loader=yaml.FullLoader)
jargondata.update(userdata)
self.jargon_mtime = self._get_jargon_file_mtime()
self._jargon = Jargon(jargondata)
@@ -57,7 +57,7 @@ class JargonLoader(object):
@staticmethod
def init_user_jargon(jargon_path):
values = yaml.load(DEFAULT_DATA)
values = yaml.load(DEFAULT_DATA, Loader=yaml.FullLoader)
# Disabled for issue/1533; do not overwrite existing user config
# if os.path.exists(jargon_path):

View File

@@ -117,13 +117,7 @@ class StoppableHTTPServer(socketserver.TCPServer):
# self.settings = CRESTSettings.getInstance()
# Allow listening for x seconds
sec = 120
pyfalog.debug("Running server for {0} seconds", sec)
self.socket.settimeout(1)
self.max_tries = sec / self.socket.gettimeout()
self.tries = 0
self.run = True
def get_request(self):
@@ -140,13 +134,6 @@ class StoppableHTTPServer(socketserver.TCPServer):
pyfalog.warning("Setting pyfa server to stop.")
self.run = False
def handle_timeout(self):
pyfalog.debug("Number of tries: {0}", self.tries)
self.tries += 1
if self.tries == self.max_tries:
pyfalog.debug("Server timed out waiting for connection")
self.stop()
def serve(self, callback=None):
self.callback = callback
while self.run: