Large pep8 compliance to make work for Tox
This commit is contained in:
@@ -22,7 +22,8 @@ import wx
|
||||
|
||||
class PFListPane(wx.ScrolledWindow):
|
||||
def __init__(self, parent):
|
||||
wx.ScrolledWindow.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(1, 1), style=wx.TAB_TRAVERSAL)
|
||||
wx.ScrolledWindow.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(1, 1),
|
||||
style=wx.TAB_TRAVERSAL)
|
||||
|
||||
self._wList = []
|
||||
self._wCount = 0
|
||||
|
||||
@@ -2,7 +2,6 @@ import wx
|
||||
import gui.utils.colorUtils as colorUtils
|
||||
import gui.utils.drawUtils as drawUtils
|
||||
|
||||
|
||||
SearchButton, EVT_SEARCH_BTN = wx.lib.newevent.NewEvent()
|
||||
CancelButton, EVT_CANCEL_BTN = wx.lib.newevent.NewEvent()
|
||||
TextEnter, EVT_TEXT_ENTER = wx.lib.newevent.NewEvent()
|
||||
@@ -40,7 +39,9 @@ class PFSearchBox(wx.Window):
|
||||
self._hl = False
|
||||
|
||||
w, h = size
|
||||
self.EditBox = wx.TextCtrl(self, wx.ID_ANY, "", wx.DefaultPosition, (-1, h - 2 if 'wxGTK' in wx.PlatformInfo else -1), wx.TE_PROCESS_ENTER | (wx.BORDER_NONE if 'wxGTK' in wx.PlatformInfo else 0))
|
||||
self.EditBox = wx.TextCtrl(self, wx.ID_ANY, "", wx.DefaultPosition,
|
||||
(-1, h - 2 if 'wxGTK' in wx.PlatformInfo else -1),
|
||||
wx.TE_PROCESS_ENTER | (wx.BORDER_NONE if 'wxGTK' in wx.PlatformInfo else 0))
|
||||
|
||||
self.Bind(wx.EVT_PAINT, self.OnPaint)
|
||||
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBk)
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
import config
|
||||
|
||||
|
||||
versionString = "{0} {1} - {2} {3}".format(config.version, config.tag, config.expansionName, config.expansionVersion)
|
||||
licenses = (
|
||||
"pyfa is released under GNU GPLv3 - see included LICENSE file",
|
||||
|
||||
@@ -35,7 +35,6 @@ import gui.chromeTabs
|
||||
|
||||
|
||||
class AdditionsPane(TogglePanel):
|
||||
|
||||
def __init__(self, parent):
|
||||
|
||||
TogglePanel.__init__(self, parent, forceLayout=1)
|
||||
|
||||
@@ -30,7 +30,6 @@ except ImportError:
|
||||
|
||||
|
||||
class BitmapLoader(object):
|
||||
|
||||
try:
|
||||
archive = zipfile.ZipFile(os.path.join(config.pyfaPath, 'imgs.zip'), 'r')
|
||||
except IOError:
|
||||
|
||||
@@ -27,21 +27,21 @@ from service.market import Market
|
||||
|
||||
|
||||
class CargoViewDrop(wx.PyDropTarget):
|
||||
def __init__(self, dropFn):
|
||||
wx.PyDropTarget.__init__(self)
|
||||
self.dropFn = dropFn
|
||||
# this is really transferring an EVE itemID
|
||||
self.dropData = wx.PyTextDataObject()
|
||||
self.SetDataObject(self.dropData)
|
||||
def __init__(self, dropFn):
|
||||
wx.PyDropTarget.__init__(self)
|
||||
self.dropFn = dropFn
|
||||
# this is really transferring an EVE itemID
|
||||
self.dropData = wx.PyTextDataObject()
|
||||
self.SetDataObject(self.dropData)
|
||||
|
||||
def OnData(self, x, y, t):
|
||||
if self.GetData():
|
||||
data = self.dropData.GetText().split(':')
|
||||
self.dropFn(x, y, data)
|
||||
return t
|
||||
def OnData(self, x, y, t):
|
||||
if self.GetData():
|
||||
data = self.dropData.GetText().split(':')
|
||||
self.dropFn(x, y, data)
|
||||
return t
|
||||
|
||||
|
||||
# @todo: Was copied form another class and modified. Look through entire file, refine
|
||||
# @todo: Was copied form another class and modified. Look through entire file, refine
|
||||
class CargoView(d.Display):
|
||||
DEFAULT_COLS = ["Base Icon",
|
||||
"Base Name",
|
||||
|
||||
@@ -99,14 +99,14 @@ class CharacterEntityEditor(EntityEditor):
|
||||
|
||||
class CharacterEditor(wx.Frame):
|
||||
def __init__(self, parent):
|
||||
wx.Frame.__init__ (self, parent, id=wx.ID_ANY, title=u"pyfa: Character Editor", pos=wx.DefaultPosition,
|
||||
size=wx.Size(640, 600), style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
|
||||
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title=u"pyfa: Character Editor", pos=wx.DefaultPosition,
|
||||
size=wx.Size(640, 600), style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
|
||||
|
||||
i = wx.IconFromBitmap(BitmapLoader.getBitmap("character_small", "gui"))
|
||||
self.SetIcon(i)
|
||||
|
||||
self.mainFrame = parent
|
||||
#self.disableWin = wx.WindowDisabler(self)
|
||||
# self.disableWin = wx.WindowDisabler(self)
|
||||
sFit = Fit.getInstance()
|
||||
|
||||
self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE))
|
||||
@@ -179,7 +179,7 @@ class CharacterEditor(wx.Frame):
|
||||
event.Skip()
|
||||
|
||||
def editingFinished(self, event):
|
||||
#del self.disableWin
|
||||
# del self.disableWin
|
||||
wx.PostEvent(self.mainFrame, GE.CharListUpdated())
|
||||
self.Destroy()
|
||||
|
||||
@@ -201,7 +201,7 @@ class CharacterEditor(wx.Frame):
|
||||
wx.PostEvent(self, GE.CharListUpdated())
|
||||
|
||||
def closeEvent(self, event):
|
||||
#del self.disableWin
|
||||
# del self.disableWin
|
||||
wx.PostEvent(self.mainFrame, GE.CharListUpdated())
|
||||
self.Destroy()
|
||||
|
||||
@@ -234,18 +234,20 @@ class CharacterEditor(wx.Frame):
|
||||
|
||||
wx.Frame.Destroy(self)
|
||||
|
||||
class SkillTreeView (wx.Panel):
|
||||
|
||||
class SkillTreeView(wx.Panel):
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__ (self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.TAB_TRAVERSAL)
|
||||
wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
|
||||
style=wx.TAB_TRAVERSAL)
|
||||
self.charEditor = self.Parent.Parent # first parent is Notebook, second is Character Editor
|
||||
self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
|
||||
|
||||
pmainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
tree = self.skillTreeListCtrl = wx.gizmos.TreeListCtrl(self, wx.ID_ANY, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT)
|
||||
tree = self.skillTreeListCtrl = wx.gizmos.TreeListCtrl(self, wx.ID_ANY,
|
||||
style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT)
|
||||
pmainSizer.Add(tree, 1, wx.EXPAND | wx.ALL, 5)
|
||||
|
||||
|
||||
self.imageList = wx.ImageList(16, 16)
|
||||
tree.SetImageList(self.imageList)
|
||||
self.skillBookImageId = self.imageList.Add(BitmapLoader.getBitmap("skill_small", "gui"))
|
||||
@@ -289,7 +291,6 @@ class SkillTreeView (wx.Panel):
|
||||
self.revertID = wx.NewId()
|
||||
self.levelChangeMenu.Append(self.revertID, "Revert")
|
||||
|
||||
|
||||
self.saveID = wx.NewId()
|
||||
self.levelChangeMenu.Append(self.saveID, "Save")
|
||||
|
||||
@@ -328,7 +329,7 @@ class SkillTreeView (wx.Panel):
|
||||
if tree.GetItemText(child) == "dummy":
|
||||
tree.Delete(child)
|
||||
|
||||
#Get the real intrestin' stuff
|
||||
# Get the real intrestin' stuff
|
||||
sChar = Character.getInstance()
|
||||
char = self.charEditor.entityEditor.getActiveEntity()
|
||||
for id, name in sChar.getSkills(tree.GetPyData(root)):
|
||||
@@ -391,7 +392,7 @@ class SkillTreeView (wx.Panel):
|
||||
|
||||
class ImplantEditorView(BaseImplantEditorView):
|
||||
def __init__(self, parent):
|
||||
BaseImplantEditorView.__init__ (self, parent)
|
||||
BaseImplantEditorView.__init__(self, parent)
|
||||
|
||||
self.determineEnabled()
|
||||
|
||||
@@ -445,9 +446,10 @@ class ImplantEditorView(BaseImplantEditorView):
|
||||
self.Enable()
|
||||
|
||||
|
||||
class APIView (wx.Panel):
|
||||
class APIView(wx.Panel):
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__ (self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(500, 300), style=wx.TAB_TRAVERSAL)
|
||||
wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(500, 300),
|
||||
style=wx.TAB_TRAVERSAL)
|
||||
self.charEditor = self.Parent.Parent # first parent is Notebook, second is Character Editor
|
||||
self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
|
||||
|
||||
@@ -456,17 +458,17 @@ class APIView (wx.Panel):
|
||||
|
||||
pmainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
hintSizer = wx.BoxSizer( wx.HORIZONTAL )
|
||||
hintSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
hintSizer.AddStretchSpacer()
|
||||
self.stDisabledTip = wx.StaticText( self, wx.ID_ANY, u"You cannot add API Details for All 0 and All 5 characters.\n"
|
||||
u"Please select another character or make a new one.", style=wx.ALIGN_CENTER )
|
||||
self.stDisabledTip.Wrap( -1 )
|
||||
hintSizer.Add( self.stDisabledTip, 0, wx.TOP | wx.BOTTOM, 10 )
|
||||
self.stDisabledTip = wx.StaticText(self, wx.ID_ANY,
|
||||
u"You cannot add API Details for All 0 and All 5 characters.\n"
|
||||
u"Please select another character or make a new one.", style=wx.ALIGN_CENTER)
|
||||
self.stDisabledTip.Wrap(-1)
|
||||
hintSizer.Add(self.stDisabledTip, 0, wx.TOP | wx.BOTTOM, 10)
|
||||
self.stDisabledTip.Hide()
|
||||
hintSizer.AddStretchSpacer()
|
||||
pmainSizer.Add(hintSizer, 0, wx.EXPAND, 5)
|
||||
|
||||
|
||||
fgSizerInput = wx.FlexGridSizer(3, 2, 0, 0)
|
||||
fgSizerInput.AddGrowableCol(1)
|
||||
fgSizerInput.SetFlexibleDirection(wx.BOTH)
|
||||
@@ -498,39 +500,44 @@ class APIView (wx.Panel):
|
||||
|
||||
pmainSizer.Add(fgSizerInput, 0, wx.EXPAND, 5)
|
||||
|
||||
btnSizer = wx.BoxSizer( wx.HORIZONTAL )
|
||||
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
btnSizer.AddStretchSpacer()
|
||||
|
||||
self.btnFetchCharList = wx.Button(self, wx.ID_ANY, u"Get Characters")
|
||||
btnSizer.Add(self.btnFetchCharList, 0, wx.ALL, 2)
|
||||
self.btnFetchCharList.Bind(wx.EVT_BUTTON, self.fetchCharList)
|
||||
|
||||
self.btnFetchSkills = wx.Button(self, wx.ID_ANY, u"Fetch Skills")
|
||||
btnSizer.Add(self.btnFetchSkills, 0, wx.ALL, 2)
|
||||
self.btnFetchSkills = wx.Button(self, wx.ID_ANY, u"Fetch Skills")
|
||||
btnSizer.Add(self.btnFetchSkills, 0, wx.ALL, 2)
|
||||
self.btnFetchSkills.Bind(wx.EVT_BUTTON, self.fetchSkills)
|
||||
self.btnFetchSkills.Enable(False)
|
||||
|
||||
btnSizer.AddStretchSpacer()
|
||||
pmainSizer.Add(btnSizer, 0, wx.EXPAND, 5)
|
||||
|
||||
self.stStatus = wx.StaticText(self, wx.ID_ANY, wx.EmptyString)
|
||||
self.stStatus = wx.StaticText(self, wx.ID_ANY, wx.EmptyString)
|
||||
pmainSizer.Add(self.stStatus, 0, wx.ALL, 5)
|
||||
|
||||
pmainSizer.AddStretchSpacer()
|
||||
self.stAPITip = wx.StaticText( self, wx.ID_ANY, u"You can create a pre-defined key here (only CharacterSheet is required):", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.stAPITip.Wrap( -1 )
|
||||
self.stAPITip = wx.StaticText(self, wx.ID_ANY,
|
||||
u"You can create a pre-defined key here (only CharacterSheet is required):",
|
||||
wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stAPITip.Wrap(-1)
|
||||
|
||||
pmainSizer.Add( self.stAPITip, 0, wx.ALL, 2 )
|
||||
pmainSizer.Add(self.stAPITip, 0, wx.ALL, 2)
|
||||
|
||||
self.hlEveAPI = wx.HyperlinkCtrl( self, wx.ID_ANY, self.apiUrlCreatePredefined, self.apiUrlCreatePredefined, wx.DefaultPosition, wx.DefaultSize, wx.HL_DEFAULT_STYLE )
|
||||
pmainSizer.Add( self.hlEveAPI, 0, wx.ALL, 2 )
|
||||
self.hlEveAPI = wx.HyperlinkCtrl(self, wx.ID_ANY, self.apiUrlCreatePredefined, self.apiUrlCreatePredefined,
|
||||
wx.DefaultPosition, wx.DefaultSize, wx.HL_DEFAULT_STYLE)
|
||||
pmainSizer.Add(self.hlEveAPI, 0, wx.ALL, 2)
|
||||
|
||||
self.stAPITip2 = wx.StaticText( self, wx.ID_ANY, u"Or, you can choose an existing key from:", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.stAPITip2.Wrap( -1 )
|
||||
pmainSizer.Add( self.stAPITip2, 0, wx.ALL, 2 )
|
||||
self.stAPITip2 = wx.StaticText(self, wx.ID_ANY, u"Or, you can choose an existing key from:", wx.DefaultPosition,
|
||||
wx.DefaultSize, 0)
|
||||
self.stAPITip2.Wrap(-1)
|
||||
pmainSizer.Add(self.stAPITip2, 0, wx.ALL, 2)
|
||||
|
||||
self.hlEveAPI2 = wx.HyperlinkCtrl( self, wx.ID_ANY, self.apiUrlKeyList, self.apiUrlKeyList, wx.DefaultPosition, wx.DefaultSize, wx.HL_DEFAULT_STYLE )
|
||||
pmainSizer.Add( self.hlEveAPI2, 0, wx.ALL, 2 )
|
||||
self.hlEveAPI2 = wx.HyperlinkCtrl(self, wx.ID_ANY, self.apiUrlKeyList, self.apiUrlKeyList, wx.DefaultPosition,
|
||||
wx.DefaultSize, wx.HL_DEFAULT_STYLE)
|
||||
pmainSizer.Add(self.hlEveAPI2, 0, wx.ALL, 2)
|
||||
|
||||
self.charEditor.entityEditor.Bind(wx.EVT_CHOICE, self.charChanged)
|
||||
|
||||
@@ -587,7 +594,7 @@ class APIView (wx.Panel):
|
||||
except TimeoutError, e:
|
||||
self.stStatus.SetLabel("Request timed out. Please check network connectivity and/or proxy settings.")
|
||||
except Exception, e:
|
||||
self.stStatus.SetLabel("Error:\n%s"%e.message)
|
||||
self.stStatus.SetLabel("Error:\n%s" % e.message)
|
||||
else:
|
||||
self.charChoice.Clear()
|
||||
for charName in list:
|
||||
@@ -611,8 +618,8 @@ class APIView (wx.Panel):
|
||||
except Exception, e:
|
||||
self.stStatus.SetLabel("Unable to retrieve %s\'s skills. Error message:\n%s" % (charName, e))
|
||||
|
||||
class SaveCharacterAs(wx.Dialog):
|
||||
|
||||
class SaveCharacterAs(wx.Dialog):
|
||||
def __init__(self, parent, charID):
|
||||
wx.Dialog.__init__(self, parent, title="Save Character As...", size=wx.Size(300, 60))
|
||||
self.charID = charID
|
||||
@@ -640,4 +647,3 @@ class SaveCharacterAs(wx.Dialog):
|
||||
|
||||
event.Skip()
|
||||
self.Close()
|
||||
|
||||
@@ -26,7 +26,6 @@ from gui.bitmapLoader import BitmapLoader
|
||||
|
||||
from service.fit import Fit
|
||||
|
||||
|
||||
_PageChanging, EVT_NOTEBOOK_PAGE_CHANGING = wx.lib.newevent.NewEvent()
|
||||
_PageChanged, EVT_NOTEBOOK_PAGE_CHANGED = wx.lib.newevent.NewEvent()
|
||||
_PageAdding, EVT_NOTEBOOK_PAGE_ADDING = wx.lib.newevent.NewEvent()
|
||||
@@ -527,7 +526,10 @@ class PFTabRenderer:
|
||||
"""
|
||||
self.tabRegion = wx.RegionFromBitmap(self.tabBackBitmap)
|
||||
self.closeBtnRegion = wx.RegionFromBitmap(self.ctabCloseBmp)
|
||||
self.closeBtnRegion.Offset(self.contentWidth + self.leftWidth - self.ctabCloseBmp.GetWidth() / 2, (self.tabHeight - self.ctabCloseBmp.GetHeight()) / 2)
|
||||
self.closeBtnRegion.Offset(
|
||||
self.contentWidth + self.leftWidth - self.ctabCloseBmp.GetWidth() / 2,
|
||||
(self.tabHeight - self.ctabCloseBmp.GetHeight()) / 2
|
||||
)
|
||||
|
||||
def InitColors(self):
|
||||
"""Determines colors used for tab, based on system settings"""
|
||||
@@ -1277,7 +1279,12 @@ class PFTabsContainer(wx.Panel):
|
||||
selpos = pos
|
||||
if selected is not skipTab:
|
||||
selected.SetPosition((selpos, self.containerHeight - self.height))
|
||||
self.addButton.SetPosition((round(tabsWidth) + self.inclination * 2, self.containerHeight - self.height / 2 - self.addButton.GetHeight() / 3))
|
||||
self.addButton.SetPosition(
|
||||
(
|
||||
round(tabsWidth) + self.inclination * 2,
|
||||
self.containerHeight - self.height / 2 - self.addButton.GetHeight() / 3
|
||||
)
|
||||
)
|
||||
|
||||
def OnLeaveWindow(self, event):
|
||||
|
||||
@@ -1302,7 +1309,12 @@ class PFTabsContainer(wx.Panel):
|
||||
if not self.previewTab.GetSelected():
|
||||
page = self.Parent.GetPage(self.GetTabIndex(self.previewTab))
|
||||
if page.Snapshot():
|
||||
self.previewWnd = PFNotebookPagePreview(self, (mposx + 3, mposy + 3), page.Snapshot(), self.previewTab.text)
|
||||
self.previewWnd = PFNotebookPagePreview(
|
||||
self,
|
||||
(mposx + 3, mposy + 3),
|
||||
page.Snapshot(),
|
||||
self.previewTab.text
|
||||
)
|
||||
self.previewWnd.Show()
|
||||
|
||||
event.Skip()
|
||||
@@ -1310,7 +1322,15 @@ class PFTabsContainer(wx.Panel):
|
||||
|
||||
class PFNotebookPagePreview(wx.Frame):
|
||||
def __init__(self, parent, pos, bitmap, title):
|
||||
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title=wx.EmptyString, pos=pos, size=wx.DefaultSize, style=wx.NO_BORDER | wx.FRAME_NO_TASKBAR | wx.STAY_ON_TOP)
|
||||
wx.Frame.__init__(
|
||||
self,
|
||||
parent,
|
||||
id=wx.ID_ANY,
|
||||
title=wx.EmptyString,
|
||||
pos=pos,
|
||||
size=wx.DefaultSize,
|
||||
style=wx.NO_BORDER | wx.FRAME_NO_TASKBAR | wx.STAY_ON_TOP
|
||||
)
|
||||
|
||||
self.title = title
|
||||
self.bitmap = bitmap
|
||||
|
||||
@@ -1,180 +1,179 @@
|
||||
# =============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# This file is part of pyfa.
|
||||
#
|
||||
# pyfa is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# pyfa is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
|
||||
# =============================================================================
|
||||
|
||||
import wx
|
||||
import logging
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ContextMenu(object):
|
||||
menus = []
|
||||
_ids = [] # [wx.NewId() for x in xrange(200)] # init with decent amount
|
||||
_idxid = -1
|
||||
|
||||
@classmethod
|
||||
def register(cls):
|
||||
ContextMenu.menus.append(cls)
|
||||
|
||||
@classmethod
|
||||
def getMenu(cls, selection, *fullContexts):
|
||||
"""
|
||||
getMenu returns a menu that is used with wx.PopupMenu.
|
||||
|
||||
selection: provides a list of what was selected. If only 1 item was
|
||||
selected, it's is a 1-item list or tuple. Can also be None for
|
||||
contexts without selection, such as statsPane or projected view
|
||||
fullContexts: a number of tuples of the following tuple:
|
||||
srcContext - context were menu was spawned, eg: projectedFit,
|
||||
cargoItem, etc
|
||||
itemContext - usually the name of the item's category
|
||||
|
||||
eg:
|
||||
(('fittingModule', 'Module'), ('fittingShip', 'Ship'))
|
||||
(('marketItemGroup', 'Implant'),)
|
||||
(('fittingShip', 'Ship'),)
|
||||
"""
|
||||
cls._idxid = -1
|
||||
debug_start = len(cls._ids)
|
||||
|
||||
rootMenu = wx.Menu()
|
||||
rootMenu.info = {}
|
||||
rootMenu.selection = (selection,) if not hasattr(selection, "__iter__") else selection
|
||||
empty = True
|
||||
for i, fullContext in enumerate(fullContexts):
|
||||
amount = 0
|
||||
srcContext = fullContext[0]
|
||||
try:
|
||||
itemContext = fullContext[1]
|
||||
except IndexError:
|
||||
itemContext = None
|
||||
for menuHandler in cls.menus:
|
||||
# loop through registered menus
|
||||
m = menuHandler()
|
||||
if m.display(srcContext, selection):
|
||||
amount += 1
|
||||
texts = m.getText(itemContext, selection)
|
||||
if isinstance(texts, basestring):
|
||||
texts = (texts,)
|
||||
|
||||
bitmap = m.getBitmap(srcContext, selection)
|
||||
multiple = not isinstance(bitmap, wx.Bitmap)
|
||||
for it, text in enumerate(texts):
|
||||
id = cls.nextID()
|
||||
rootItem = wx.MenuItem(rootMenu, id, text)
|
||||
rootMenu.info[id] = (m, fullContext, it)
|
||||
|
||||
sub = m.getSubMenu(srcContext, selection, rootMenu, it, rootItem)
|
||||
|
||||
if sub is None:
|
||||
# if there is no sub menu, bind the handler to the rootItem
|
||||
rootMenu.Bind(wx.EVT_MENU, cls.handler, rootItem)
|
||||
elif sub:
|
||||
# If sub exists and is not False, set submenu.
|
||||
# Sub might return False when we have a mix of
|
||||
# single menu items and submenus (see: damage profile
|
||||
# context menu)
|
||||
#
|
||||
# If there is a submenu, it is expected that the sub
|
||||
# logic take care of it's own bindings, including for
|
||||
# any single root items. No binding is done here
|
||||
#
|
||||
# It is important to remember that when binding sub
|
||||
# menu items, the menu to bind to depends on platform.
|
||||
# Windows should bind to rootMenu, and all other
|
||||
# platforms should bind to sub menu. See existing
|
||||
# implementations for examples.
|
||||
rootItem.SetSubMenu(sub)
|
||||
|
||||
if bitmap is not None:
|
||||
if multiple:
|
||||
bp = bitmap[it]
|
||||
if bp:
|
||||
rootItem.SetBitmap(bp)
|
||||
else:
|
||||
rootItem.SetBitmap(bitmap)
|
||||
|
||||
rootMenu.AppendItem(rootItem)
|
||||
|
||||
empty = False
|
||||
|
||||
if amount > 0 and i != len(fullContexts) - 1:
|
||||
rootMenu.AppendSeparator()
|
||||
|
||||
debug_end = len(cls._ids)
|
||||
if (debug_end - debug_start):
|
||||
logger.debug("%d new IDs created for this menu" % (debug_end - debug_start))
|
||||
|
||||
return rootMenu if empty is False else None
|
||||
|
||||
@classmethod
|
||||
def handler(cls, event):
|
||||
menu = event.EventObject
|
||||
stuff = menu.info.get(event.Id)
|
||||
if stuff is not None:
|
||||
menuHandler, context, i = stuff
|
||||
selection = menu.selection
|
||||
if not hasattr(selection, "__iter__"):
|
||||
selection = (selection,)
|
||||
|
||||
menuHandler.activate(context, selection, i)
|
||||
else:
|
||||
event.Skip()
|
||||
|
||||
def display(self, context, selection):
|
||||
raise NotImplementedError()
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
return None
|
||||
|
||||
def getSubMenu(self, context, selection, rootMenu, i, pitem):
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def nextID(cls):
|
||||
"""
|
||||
Fetches an ID from the pool of IDs allocated to Context Menu.
|
||||
If we don't have enough ID's to fulfill request, create new
|
||||
ID and add it to the pool.
|
||||
|
||||
See GH Issue #589
|
||||
"""
|
||||
cls._idxid += 1
|
||||
|
||||
if cls._idxid >= len(cls._ids): # We don't ahve an ID for this index, create one
|
||||
cls._ids.append(wx.NewId())
|
||||
|
||||
return cls._ids[cls._idxid]
|
||||
|
||||
def getText(self, context, selection):
|
||||
"""
|
||||
getText should be implemented in child classes, and should return either
|
||||
a string that will make up a menu item label or a list of strings which
|
||||
will make numerous menu items.
|
||||
|
||||
These menu items will be added to the root menu
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def getBitmap(self, context, selection):
|
||||
return None
|
||||
|
||||
|
||||
from gui.builtinContextMenus import * # noqa
|
||||
# =============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# This file is part of pyfa.
|
||||
#
|
||||
# pyfa is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# pyfa is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
|
||||
# =============================================================================
|
||||
|
||||
import wx
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ContextMenu(object):
|
||||
menus = []
|
||||
_ids = [] # [wx.NewId() for x in xrange(200)] # init with decent amount
|
||||
_idxid = -1
|
||||
|
||||
@classmethod
|
||||
def register(cls):
|
||||
ContextMenu.menus.append(cls)
|
||||
|
||||
@classmethod
|
||||
def getMenu(cls, selection, *fullContexts):
|
||||
"""
|
||||
getMenu returns a menu that is used with wx.PopupMenu.
|
||||
|
||||
selection: provides a list of what was selected. If only 1 item was
|
||||
selected, it's is a 1-item list or tuple. Can also be None for
|
||||
contexts without selection, such as statsPane or projected view
|
||||
fullContexts: a number of tuples of the following tuple:
|
||||
srcContext - context were menu was spawned, eg: projectedFit,
|
||||
cargoItem, etc
|
||||
itemContext - usually the name of the item's category
|
||||
|
||||
eg:
|
||||
(('fittingModule', 'Module'), ('fittingShip', 'Ship'))
|
||||
(('marketItemGroup', 'Implant'),)
|
||||
(('fittingShip', 'Ship'),)
|
||||
"""
|
||||
cls._idxid = -1
|
||||
debug_start = len(cls._ids)
|
||||
|
||||
rootMenu = wx.Menu()
|
||||
rootMenu.info = {}
|
||||
rootMenu.selection = (selection,) if not hasattr(selection, "__iter__") else selection
|
||||
empty = True
|
||||
for i, fullContext in enumerate(fullContexts):
|
||||
amount = 0
|
||||
srcContext = fullContext[0]
|
||||
try:
|
||||
itemContext = fullContext[1]
|
||||
except IndexError:
|
||||
itemContext = None
|
||||
for menuHandler in cls.menus:
|
||||
# loop through registered menus
|
||||
m = menuHandler()
|
||||
if m.display(srcContext, selection):
|
||||
amount += 1
|
||||
texts = m.getText(itemContext, selection)
|
||||
if isinstance(texts, basestring):
|
||||
texts = (texts,)
|
||||
|
||||
bitmap = m.getBitmap(srcContext, selection)
|
||||
multiple = not isinstance(bitmap, wx.Bitmap)
|
||||
for it, text in enumerate(texts):
|
||||
id = cls.nextID()
|
||||
rootItem = wx.MenuItem(rootMenu, id, text)
|
||||
rootMenu.info[id] = (m, fullContext, it)
|
||||
|
||||
sub = m.getSubMenu(srcContext, selection, rootMenu, it, rootItem)
|
||||
|
||||
if sub is None:
|
||||
# if there is no sub menu, bind the handler to the rootItem
|
||||
rootMenu.Bind(wx.EVT_MENU, cls.handler, rootItem)
|
||||
elif sub:
|
||||
# If sub exists and is not False, set submenu.
|
||||
# Sub might return False when we have a mix of
|
||||
# single menu items and submenus (see: damage profile
|
||||
# context menu)
|
||||
#
|
||||
# If there is a submenu, it is expected that the sub
|
||||
# logic take care of it's own bindings, including for
|
||||
# any single root items. No binding is done here
|
||||
#
|
||||
# It is important to remember that when binding sub
|
||||
# menu items, the menu to bind to depends on platform.
|
||||
# Windows should bind to rootMenu, and all other
|
||||
# platforms should bind to sub menu. See existing
|
||||
# implementations for examples.
|
||||
rootItem.SetSubMenu(sub)
|
||||
|
||||
if bitmap is not None:
|
||||
if multiple:
|
||||
bp = bitmap[it]
|
||||
if bp:
|
||||
rootItem.SetBitmap(bp)
|
||||
else:
|
||||
rootItem.SetBitmap(bitmap)
|
||||
|
||||
rootMenu.AppendItem(rootItem)
|
||||
|
||||
empty = False
|
||||
|
||||
if amount > 0 and i != len(fullContexts) - 1:
|
||||
rootMenu.AppendSeparator()
|
||||
|
||||
debug_end = len(cls._ids)
|
||||
if (debug_end - debug_start):
|
||||
logger.debug("%d new IDs created for this menu" % (debug_end - debug_start))
|
||||
|
||||
return rootMenu if empty is False else None
|
||||
|
||||
@classmethod
|
||||
def handler(cls, event):
|
||||
menu = event.EventObject
|
||||
stuff = menu.info.get(event.Id)
|
||||
if stuff is not None:
|
||||
menuHandler, context, i = stuff
|
||||
selection = menu.selection
|
||||
if not hasattr(selection, "__iter__"):
|
||||
selection = (selection,)
|
||||
|
||||
menuHandler.activate(context, selection, i)
|
||||
else:
|
||||
event.Skip()
|
||||
|
||||
def display(self, context, selection):
|
||||
raise NotImplementedError()
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
return None
|
||||
|
||||
def getSubMenu(self, context, selection, rootMenu, i, pitem):
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def nextID(cls):
|
||||
"""
|
||||
Fetches an ID from the pool of IDs allocated to Context Menu.
|
||||
If we don't have enough ID's to fulfill request, create new
|
||||
ID and add it to the pool.
|
||||
|
||||
See GH Issue #589
|
||||
"""
|
||||
cls._idxid += 1
|
||||
|
||||
if cls._idxid >= len(cls._ids): # We don't ahve an ID for this index, create one
|
||||
cls._ids.append(wx.NewId())
|
||||
|
||||
return cls._ids[cls._idxid]
|
||||
|
||||
def getText(self, context, selection):
|
||||
"""
|
||||
getText should be implemented in child classes, and should return either
|
||||
a string that will make up a menu item label or a list of strings which
|
||||
will make numerous menu items.
|
||||
|
||||
These menu items will be added to the root menu
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def getBitmap(self, context, selection):
|
||||
return None
|
||||
|
||||
|
||||
from gui.builtinContextMenus import * # noqa
|
||||
|
||||
@@ -30,7 +30,8 @@ class CopySelectDialog(wx.Dialog):
|
||||
copyFormatMultiBuy = 5
|
||||
|
||||
def __init__(self, parent):
|
||||
wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title=u"Select a format", size=(-1, -1), style=wx.DEFAULT_DIALOG_STYLE)
|
||||
wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title=u"Select a format", size=(-1, -1),
|
||||
style=wx.DEFAULT_DIALOG_STYLE)
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
copyFormats = [u"EFT", u"EFT (Implants)", u"XML", u"DNA", u"CREST", u"MultiBuy"]
|
||||
@@ -40,7 +41,8 @@ class CopySelectDialog(wx.Dialog):
|
||||
CopySelectDialog.copyFormatDna: u"A one-line text format",
|
||||
CopySelectDialog.copyFormatCrest: u"A JSON format used for EVE CREST",
|
||||
CopySelectDialog.copyFormatMultiBuy: u"MultiBuy text format"}
|
||||
selector = wx.RadioBox(self, wx.ID_ANY, label=u"Copy to the clipboard using:", choices=copyFormats, style=wx.RA_SPECIFY_ROWS)
|
||||
selector = wx.RadioBox(self, wx.ID_ANY, label=u"Copy to the clipboard using:", choices=copyFormats,
|
||||
style=wx.RA_SPECIFY_ROWS)
|
||||
selector.Bind(wx.EVT_RADIOBOX, self.Selected)
|
||||
for format, tooltip in copyFormatTooltips.iteritems():
|
||||
selector.SetItemToolTip(format, tooltip)
|
||||
|
||||
@@ -16,9 +16,9 @@ import gui.globalEvents as GE
|
||||
|
||||
|
||||
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)
|
||||
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))
|
||||
|
||||
@@ -26,42 +26,43 @@ class CrestFittings(wx.Frame):
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
sCrest = Crest.getInstance()
|
||||
|
||||
characterSelectSizer = wx.BoxSizer( wx.HORIZONTAL )
|
||||
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 )
|
||||
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 )
|
||||
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 )
|
||||
characterSelectSizer.Add(self.charChoice, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
|
||||
self.updateCharList()
|
||||
|
||||
self.fetchBtn = wx.Button( self, wx.ID_ANY, u"Fetch Fits", wx.DefaultPosition, wx.DefaultSize, 5 )
|
||||
characterSelectSizer.Add( self.fetchBtn, 0, wx.ALL, 5 )
|
||||
mainSizer.Add( characterSelectSizer, 0, wx.EXPAND, 5 )
|
||||
self.fetchBtn = wx.Button(self, wx.ID_ANY, u"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 )
|
||||
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 )
|
||||
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 )
|
||||
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 )
|
||||
fitSizer.Add(self.fitView, 1, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
btnSizer = wx.BoxSizer( wx.HORIZONTAL )
|
||||
self.importBtn = wx.Button( self, wx.ID_ANY, u"Import to pyfa", wx.DefaultPosition, wx.DefaultSize, 5 )
|
||||
self.deleteBtn = wx.Button( self, wx.ID_ANY, u"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 )
|
||||
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
self.importBtn = wx.Button(self, wx.ID_ANY, u"Import to pyfa", wx.DefaultPosition, wx.DefaultSize, 5)
|
||||
self.deleteBtn = wx.Button(self, wx.ID_ANY, u"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)
|
||||
@@ -104,12 +105,12 @@ class CrestFittings(wx.Frame):
|
||||
self.charChoice.SetSelection(0)
|
||||
|
||||
def updateCacheStatus(self, event):
|
||||
t = time.gmtime(self.cacheTime-time.time())
|
||||
t = time.gmtime(self.cacheTime - time.time())
|
||||
if t < 0:
|
||||
self.cacheTimer.Stop()
|
||||
else:
|
||||
sTime = time.strftime("%H:%M:%S", t)
|
||||
self.statusbar.SetStatusText("Cached for %s"%sTime, 0)
|
||||
self.statusbar.SetStatusText("Cached for %s" % sTime, 0)
|
||||
|
||||
def ssoLogout(self, event):
|
||||
if event.type == CrestModes.IMPLICIT:
|
||||
@@ -163,8 +164,8 @@ class CrestFittings(wx.Frame):
|
||||
data = json.loads(self.fitTree.fittingsTreeCtrl.GetPyData(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)
|
||||
"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:
|
||||
@@ -174,9 +175,9 @@ class CrestFittings(wx.Frame):
|
||||
|
||||
|
||||
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)
|
||||
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))
|
||||
@@ -186,20 +187,21 @@ class ExportToEve(wx.Frame):
|
||||
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 )
|
||||
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 )
|
||||
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 )
|
||||
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, u"Export Fit", wx.DefaultPosition, wx.DefaultSize, 5 )
|
||||
hSizer.Add( self.exportBtn, 0, wx.ALL, 5 )
|
||||
self.exportBtn = wx.Button(self, wx.ID_ANY, u"Export Fit", wx.DefaultPosition, wx.DefaultSize, 5)
|
||||
hSizer.Add(self.exportBtn, 0, wx.ALL, 5)
|
||||
|
||||
mainSizer.Add( hSizer, 0, wx.EXPAND, 5 )
|
||||
mainSizer.Add(hSizer, 0, wx.EXPAND, 5)
|
||||
|
||||
self.exportBtn.Bind(wx.EVT_BUTTON, self.exportFitting)
|
||||
|
||||
@@ -271,7 +273,7 @@ class ExportToEve(wx.Frame):
|
||||
data = sFit.exportCrest(fitID)
|
||||
res = sCrest.postFitting(self.getActiveCharacter(), data)
|
||||
|
||||
self.statusbar.SetStatusText("%d: %s"%(res.status_code, res.reason), 0)
|
||||
self.statusbar.SetStatusText("%d: %s" % (res.status_code, res.reason), 0)
|
||||
try:
|
||||
text = json.loads(res.text)
|
||||
self.statusbar.SetStatusText(text['message'], 1)
|
||||
@@ -282,40 +284,40 @@ class ExportToEve(wx.Frame):
|
||||
|
||||
|
||||
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 )
|
||||
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 )
|
||||
mainSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
self.lcCharacters = wx.ListCtrl( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LC_REPORT)
|
||||
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 )
|
||||
mainSizer.Add(self.lcCharacters, 1, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
btnSizer = wx.BoxSizer( wx.VERTICAL )
|
||||
btnSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
self.addBtn = wx.Button( self, wx.ID_ANY, u"Add Character", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
btnSizer.Add( self.addBtn, 0, wx.ALL | wx.EXPAND, 5 )
|
||||
self.addBtn = wx.Button(self, wx.ID_ANY, u"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, u"Revoke Character", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
btnSizer.Add( self.deleteBtn, 0, wx.ALL | wx.EXPAND, 5 )
|
||||
self.deleteBtn = wx.Button(self, wx.ID_ANY, u"Revoke Character", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
btnSizer.Add(self.deleteBtn, 0, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
mainSizer.Add( btnSizer, 0, 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.SetSizer(mainSizer)
|
||||
self.Layout()
|
||||
|
||||
self.Centre( wx.BOTH )
|
||||
self.Centre(wx.BOTH)
|
||||
|
||||
def ssoLogin(self, event):
|
||||
self.popCharList()
|
||||
|
||||
@@ -70,9 +70,8 @@ class Display(wx.ListCtrl):
|
||||
|
||||
self.imageListBase = self.imageList.ImageCount
|
||||
|
||||
|
||||
# Override native HitTestSubItem (doesn't work as it should on GTK)
|
||||
# Source: ObjectListView
|
||||
# Override native HitTestSubItem (doesn't work as it should on GTK)
|
||||
# Source: ObjectListView
|
||||
|
||||
def HitTestSubItem(self, pt):
|
||||
"""
|
||||
@@ -282,7 +281,7 @@ class Display(wx.ListCtrl):
|
||||
self.SetColumnWidth(i, headerWidth)
|
||||
else:
|
||||
self.SetColumnWidth(i, col.size)
|
||||
# self.Thaw()
|
||||
# self.Thaw()
|
||||
|
||||
def update(self, stuff):
|
||||
self.populate(stuff)
|
||||
|
||||
@@ -28,24 +28,25 @@ from eos.types import Slot
|
||||
from gui.contextMenu import ContextMenu
|
||||
from service.fit import Fit
|
||||
|
||||
class FighterViewDrop(wx.PyDropTarget):
|
||||
def __init__(self, dropFn):
|
||||
wx.PyDropTarget.__init__(self)
|
||||
self.dropFn = dropFn
|
||||
# this is really transferring an EVE itemID
|
||||
self.dropData = wx.PyTextDataObject()
|
||||
self.SetDataObject(self.dropData)
|
||||
|
||||
def OnData(self, x, y, t):
|
||||
if self.GetData():
|
||||
data = self.dropData.GetText().split(':')
|
||||
self.dropFn(x, y, data)
|
||||
return t
|
||||
class FighterViewDrop(wx.PyDropTarget):
|
||||
def __init__(self, dropFn):
|
||||
wx.PyDropTarget.__init__(self)
|
||||
self.dropFn = dropFn
|
||||
# this is really transferring an EVE itemID
|
||||
self.dropData = wx.PyTextDataObject()
|
||||
self.SetDataObject(self.dropData)
|
||||
|
||||
def OnData(self, x, y, t):
|
||||
if self.GetData():
|
||||
data = self.dropData.GetText().split(':')
|
||||
self.dropFn(x, y, data)
|
||||
return t
|
||||
|
||||
|
||||
class FighterView(wx.Panel):
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, style=wx.TAB_TRAVERSAL )
|
||||
wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, style=wx.TAB_TRAVERSAL)
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.labels = ["Light", "Heavy", "Support"]
|
||||
|
||||
@@ -55,7 +56,7 @@ class FighterView(wx.Panel):
|
||||
mainSizer.Add(self.fighterDisplay, 1, wx.EXPAND, 0)
|
||||
|
||||
textSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
textSizer.AddSpacer(( 0, 0), 1, wx.EXPAND, 5)
|
||||
textSizer.AddSpacer((0, 0), 1, wx.EXPAND, 5)
|
||||
|
||||
for x in self.labels:
|
||||
lbl = wx.StaticText(self, wx.ID_ANY, x.capitalize())
|
||||
@@ -74,10 +75,9 @@ class FighterView(wx.Panel):
|
||||
|
||||
mainSizer.Add(textSizer, 0, wx.EXPAND, 5)
|
||||
|
||||
self.SetSizer( mainSizer )
|
||||
self.SetSizer(mainSizer)
|
||||
self.SetAutoLayout(True)
|
||||
|
||||
|
||||
self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged)
|
||||
|
||||
def fitChanged(self, event):
|
||||
@@ -90,7 +90,8 @@ class FighterView(wx.Panel):
|
||||
slot = getattr(Slot, "F_{}".format(x.upper()))
|
||||
used = fit.getSlotsUsed(slot)
|
||||
total = fit.getNumSlots(slot)
|
||||
color = wx.Colour(204, 51, 51) if used > total else wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT)
|
||||
color = wx.Colour(204, 51, 51) if used > total else wx.SystemSettings_GetColour(
|
||||
wx.SYS_COLOUR_WINDOWTEXT)
|
||||
|
||||
lbl = getattr(self, "label%sUsed" % x.capitalize())
|
||||
lbl.SetLabel(str(int(used)))
|
||||
@@ -105,15 +106,15 @@ class FighterView(wx.Panel):
|
||||
|
||||
class FighterDisplay(d.Display):
|
||||
DEFAULT_COLS = ["State",
|
||||
#"Base Icon",
|
||||
# "Base Icon",
|
||||
"Base Name",
|
||||
# "prop:droneDps,droneBandwidth",
|
||||
#"Max Range",
|
||||
#"Miscellanea",
|
||||
# "Max Range",
|
||||
# "Miscellanea",
|
||||
"attr:maxVelocity",
|
||||
"Fighter Abilities"
|
||||
#"Price",
|
||||
]
|
||||
# "Price",
|
||||
]
|
||||
|
||||
def __init__(self, parent):
|
||||
d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL | wx.BORDER_NONE)
|
||||
@@ -131,12 +132,11 @@ class FighterDisplay(d.Display):
|
||||
self.Bind(wx.EVT_MOTION, self.OnMouseMove)
|
||||
self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
|
||||
|
||||
if "__WXGTK__" in wx.PlatformInfo:
|
||||
if "__WXGTK__" in wx.PlatformInfo:
|
||||
self.Bind(wx.EVT_RIGHT_UP, self.scheduleMenu)
|
||||
else:
|
||||
self.Bind(wx.EVT_RIGHT_DOWN, self.scheduleMenu)
|
||||
|
||||
|
||||
self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.startDrag)
|
||||
self.SetDropTarget(FighterViewDrop(self.handleDragDrop))
|
||||
|
||||
@@ -183,7 +183,7 @@ class FighterDisplay(d.Display):
|
||||
row = event.GetIndex()
|
||||
if row != -1:
|
||||
data = wx.PyTextDataObject()
|
||||
data.SetText("fighter:"+str(row))
|
||||
data.SetText("fighter:" + str(row))
|
||||
|
||||
dropSource = wx.DropSource(self)
|
||||
dropSource.SetData(data)
|
||||
@@ -229,7 +229,7 @@ class FighterDisplay(d.Display):
|
||||
|
||||
self.Parent.Parent.Parent.DisablePage(self.Parent, not fit)
|
||||
|
||||
#Clear list and get out if current fitId is None
|
||||
# Clear list and get out if current fitId is None
|
||||
if event.fitID is None and self.lastFitId is not None:
|
||||
self.DeleteAllItems()
|
||||
self.lastFitId = None
|
||||
@@ -257,7 +257,6 @@ class FighterDisplay(d.Display):
|
||||
self.update(stuff)
|
||||
event.Skip()
|
||||
|
||||
|
||||
def addItem(self, event):
|
||||
sFit = Fit.getInstance()
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
|
||||
@@ -1,448 +1,449 @@
|
||||
import wx
|
||||
from wx.lib.buttons import GenBitmapButton
|
||||
|
||||
import service.fleet
|
||||
import gui.mainFrame
|
||||
import gui.utils.colorUtils as colorUtils
|
||||
import gui.sfBrowserItem as SFItem
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
from gui.PFListPane import PFListPane
|
||||
from gui.utils.drawUtils import GetPartialText
|
||||
|
||||
|
||||
FleetSelected, EVT_FLEET_SELECTED = wx.lib.newevent.NewEvent()
|
||||
FleetRenamed, EVT_FLEET_RENAMED = wx.lib.newevent.NewEvent()
|
||||
FleetRemoved, EVT_FLEET_REMOVED = wx.lib.newevent.NewEvent()
|
||||
FleetItemSelect, EVT_FLEET_ITEM_SELECT = wx.lib.newevent.NewEvent()
|
||||
FleetItemDelete, EVT_FLEET_ITEM_DELETE = wx.lib.newevent.NewEvent()
|
||||
FleetItemNew, EVT_FLEET_ITEM_NEW = wx.lib.newevent.NewEvent()
|
||||
FleetItemCopy, EVT_FLEET_ITEM_COPY = wx.lib.newevent.NewEvent()
|
||||
FleetItemRename, EVT_FLEET_ITEM_RENAME = wx.lib.newevent.NewEvent()
|
||||
|
||||
|
||||
class FleetBrowser(wx.Panel):
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__(self, parent)
|
||||
|
||||
self.sFleet = service.fleet.Fleet.getInstance()
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
self.hpane = FleetBrowserHeader(self)
|
||||
mainSizer.Add(self.hpane, 0, wx.EXPAND)
|
||||
|
||||
self.m_sl2 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL)
|
||||
mainSizer.Add(self.m_sl2, 0, wx.EXPAND, 0)
|
||||
|
||||
self.fleetItemContainer = PFFleetItemContainer(self)
|
||||
|
||||
mainSizer.Add(self.fleetItemContainer, 1, wx.EXPAND)
|
||||
|
||||
self.SetSizer(mainSizer)
|
||||
self.Layout()
|
||||
|
||||
self.filter = ""
|
||||
self.fleetIDMustEditName = -1
|
||||
|
||||
self.Bind(wx.EVT_SIZE, self.SizeRefreshList)
|
||||
|
||||
self.Bind(EVT_FLEET_ITEM_NEW, self.AddNewFleetItem)
|
||||
self.Bind(EVT_FLEET_ITEM_SELECT, self.SelectFleetItem)
|
||||
self.Bind(EVT_FLEET_ITEM_DELETE, self.DeleteFleetItem)
|
||||
self.Bind(EVT_FLEET_ITEM_COPY, self.CopyFleetItem)
|
||||
self.Bind(EVT_FLEET_ITEM_RENAME, self.RenameFleetItem)
|
||||
|
||||
self.PopulateFleetList()
|
||||
|
||||
def AddNewFleetItem(self, event):
|
||||
fleetName = event.fleetName
|
||||
newFleet = self.sFleet.addFleet()
|
||||
self.sFleet.renameFleet(newFleet, fleetName)
|
||||
|
||||
self.fleetIDMustEditName = newFleet.ID
|
||||
self.AddItem(newFleet.ID, newFleet.name, newFleet.count())
|
||||
|
||||
def SelectFleetItem(self, event):
|
||||
fleetID = event.fleetID
|
||||
self.fleetItemContainer.SelectWidgetByFleetID(fleetID)
|
||||
wx.PostEvent(self.mainFrame, FleetSelected(fleetID=fleetID))
|
||||
|
||||
def CopyFleetItem(self, event):
|
||||
fleetID = event.fleetID
|
||||
fleet = self.sFleet.copyFleetByID(fleetID)
|
||||
|
||||
fleetName = fleet.name + " Copy"
|
||||
self.sFleet.renameFleet(fleet, fleetName)
|
||||
|
||||
self.fleetIDMustEditName = fleet.ID
|
||||
self.AddItem(fleet.ID, fleet.name, fleet.count())
|
||||
|
||||
self.fleetItemContainer.SelectWidgetByFleetID(fleet.ID)
|
||||
wx.PostEvent(self.mainFrame, FleetSelected(fleetID=fleet.ID))
|
||||
|
||||
def RenameFleetItem(self, event):
|
||||
fleetID = event.fleetID
|
||||
fleet = self.sFleet.getFleetByID(fleetID)
|
||||
|
||||
newFleetName = event.fleetName
|
||||
|
||||
self.sFleet.renameFleet(fleet, newFleetName)
|
||||
wx.PostEvent(self.mainFrame, FleetRenamed(fleetID=fleet.ID))
|
||||
|
||||
def DeleteFleetItem(self, event):
|
||||
self.sFleet.deleteFleetByID(event.fleetID)
|
||||
self.PopulateFleetList()
|
||||
wx.PostEvent(self.mainFrame, FleetRemoved(fleetID=event.fleetID))
|
||||
|
||||
def AddItem(self, ID, name, count):
|
||||
self.fleetItemContainer.AddWidget(FleetItem(self, ID, name, count))
|
||||
widget = self.fleetItemContainer.GetWidgetByFleetID(ID)
|
||||
self.fleetItemContainer.RefreshList(True)
|
||||
self.fleetItemContainer.ScrollChildIntoView(widget)
|
||||
wx.PostEvent(self, FleetItemSelect(fleetID=ID))
|
||||
|
||||
def PopulateFleetList(self):
|
||||
self.Freeze()
|
||||
filter_ = self.filter
|
||||
self.fleetItemContainer.RemoveAllChildren()
|
||||
fleetList = self.sFleet.getFleetList()
|
||||
for fleetID, fleetName, fleetCount in fleetList:
|
||||
if fleetName.lower().find(filter_.lower()) != -1:
|
||||
self.fleetItemContainer.AddWidget(FleetItem(self, fleetID, fleetName, fleetCount))
|
||||
self.fleetItemContainer.RefreshList()
|
||||
self.Thaw()
|
||||
|
||||
def SetFilter(self, filter):
|
||||
self.filter = filter
|
||||
|
||||
def SizeRefreshList(self, event):
|
||||
ewidth, eheight = event.GetSize()
|
||||
self.Layout()
|
||||
self.fleetItemContainer.Layout()
|
||||
self.fleetItemContainer.RefreshList(True)
|
||||
event.Skip()
|
||||
|
||||
|
||||
class FleetBrowserHeader(wx.Panel):
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(500, 24), style=wx.TAB_TRAVERSAL)
|
||||
self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE))
|
||||
|
||||
self.newBmp = BitmapLoader.getBitmap("fit_add_small", "gui")
|
||||
bmpSize = (16, 16)
|
||||
|
||||
mainSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
if 'wxMac' in wx.PlatformInfo:
|
||||
bgcolour = wx.Colour(0, 0, 0, 0)
|
||||
else:
|
||||
bgcolour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE)
|
||||
|
||||
self.fbNewFleet = PFGenBitmapButton(self, wx.ID_ANY, self.newBmp, wx.DefaultPosition, bmpSize, wx.BORDER_NONE)
|
||||
mainSizer.Add(self.fbNewFleet, 0, wx.LEFT | wx.TOP | wx.BOTTOM | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
self.fbNewFleet.SetBackgroundColour(bgcolour)
|
||||
|
||||
self.sl1 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_VERTICAL)
|
||||
mainSizer.Add(self.sl1, 0, wx.EXPAND | wx.LEFT, 5)
|
||||
|
||||
self.tcFilter = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
mainSizer.Add(self.tcFilter, 0, wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
|
||||
self.stStatus = wx.StaticText(self, wx.ID_ANY, u"", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stStatus.Wrap(-1)
|
||||
mainSizer.Add(self.stStatus, 1, wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
|
||||
self.SetSizer(mainSizer)
|
||||
self.Layout()
|
||||
|
||||
self.fbNewFleet.Bind(wx.EVT_ENTER_WINDOW, self.fbNewEnterWindow)
|
||||
self.fbNewFleet.Bind(wx.EVT_LEAVE_WINDOW, self.fbHItemLeaveWindow)
|
||||
self.fbNewFleet.Bind(wx.EVT_BUTTON, self.OnNewFleetItem)
|
||||
|
||||
self.tcFilter.Bind(wx.EVT_TEXT, self.OnFilterText)
|
||||
|
||||
self.tcFilter.Bind(wx.EVT_ENTER_WINDOW, self.fbFilterEnterWindow)
|
||||
self.tcFilter.Bind(wx.EVT_LEAVE_WINDOW, self.fbHItemLeaveWindow)
|
||||
|
||||
def OnFilterText(self, event):
|
||||
filter = self.tcFilter.GetValue()
|
||||
self.Parent.SetFilter(filter)
|
||||
self.Parent.PopulateFleetList()
|
||||
event.Skip()
|
||||
|
||||
def OnNewFleetItem(self, event):
|
||||
wx.PostEvent(self.Parent, FleetItemNew(fleetName="New Fleet"))
|
||||
|
||||
def fbNewEnterWindow(self, event):
|
||||
self.stStatus.SetLabel("New fleet")
|
||||
self.Parent.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
|
||||
event.Skip()
|
||||
|
||||
def fbHItemLeaveWindow(self, event):
|
||||
self.stStatus.SetLabel("")
|
||||
self.Parent.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
|
||||
event.Skip()
|
||||
|
||||
def fbFilterEnterWindow(self, event):
|
||||
self.stStatus.SetLabel("Filter list")
|
||||
event.Skip()
|
||||
|
||||
|
||||
class PFFleetItemContainer(PFListPane):
|
||||
def __init__(self, parent):
|
||||
PFListPane.__init__(self, parent)
|
||||
self.selectedWidget = -1
|
||||
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
|
||||
|
||||
def IsWidgetSelectedByContext(self, widget):
|
||||
if self.GetWidgetList()[widget].IsSelected():
|
||||
return True
|
||||
return False
|
||||
|
||||
def GetWidgetIndex(self, widgetWnd):
|
||||
return self.GetWidgetList().index(widgetWnd)
|
||||
|
||||
def GetWidgetByFleetID(self, fleetID):
|
||||
for widget in self.GetWidgetList():
|
||||
if widget.fleetID == fleetID:
|
||||
return widget
|
||||
return None
|
||||
|
||||
def SelectWidget(self, widgetWnd):
|
||||
wlist = self.GetWidgetList()
|
||||
if self.selectedWidget != -1:
|
||||
wlist[self.selectedWidget].SetSelected(False)
|
||||
wlist[self.selectedWidget].Refresh()
|
||||
windex = self.GetWidgetIndex(widgetWnd)
|
||||
wlist[windex].SetSelected(True)
|
||||
wlist[windex].Refresh()
|
||||
self.selectedWidget = windex
|
||||
|
||||
def SelectWidgetByFleetID(self, fleetID):
|
||||
widgetWnd = self.GetWidgetByFleetID(fleetID)
|
||||
if widgetWnd:
|
||||
self.SelectWidget(widgetWnd)
|
||||
|
||||
def RemoveWidget(self, child):
|
||||
child.Destroy()
|
||||
self.selectedWidget = -1
|
||||
self._wList.remove(child)
|
||||
|
||||
def RemoveAllChildren(self):
|
||||
for widget in self._wList:
|
||||
widget.Destroy()
|
||||
|
||||
self.selectedWidget = -1
|
||||
self._wList = []
|
||||
|
||||
def OnLeftUp(self, event):
|
||||
event.Skip()
|
||||
|
||||
|
||||
class FleetItem(SFItem.SFBrowserItem):
|
||||
def __init__(self, parent, fleetID, fleetName, fleetCount,
|
||||
id=wx.ID_ANY, pos=wx.DefaultPosition,
|
||||
size=(0, 40), style=0):
|
||||
SFItem.SFBrowserItem.__init__(self, parent, size=size)
|
||||
|
||||
self.fleetBrowser = self.Parent
|
||||
self.fleetID = fleetID
|
||||
self.fleetName = fleetName
|
||||
self.fleetCount = fleetCount
|
||||
|
||||
self.padding = 4
|
||||
|
||||
self.fontBig = wx.FontFromPixelSize((0, 15), wx.SWISS, wx.NORMAL, wx.BOLD, False)
|
||||
self.fontNormal = wx.FontFromPixelSize((0, 14), wx.SWISS, wx.NORMAL, wx.NORMAL, False)
|
||||
self.fontSmall = wx.FontFromPixelSize((0, 12), wx.SWISS, wx.NORMAL, wx.NORMAL, False)
|
||||
|
||||
self.copyBmp = BitmapLoader.getBitmap("fit_add_small", "gui")
|
||||
self.renameBmp = BitmapLoader.getBitmap("fit_rename_small", "gui")
|
||||
self.deleteBmp = BitmapLoader.getBitmap("fit_delete_small", "gui")
|
||||
self.acceptBmp = BitmapLoader.getBitmap("faccept_small", "gui")
|
||||
self.fleetBmp = BitmapLoader.getBitmap("fleet_item_big", "gui")
|
||||
|
||||
fleetImg = self.fleetBmp.ConvertToImage()
|
||||
fleetImg = fleetImg.Blur(2)
|
||||
|
||||
if not fleetImg.HasAlpha():
|
||||
fleetImg.InitAlpha()
|
||||
|
||||
fleetImg = fleetImg.AdjustChannels(1, 1, 1, 0.5)
|
||||
self.fleetEffBmp = wx.BitmapFromImage(fleetImg)
|
||||
|
||||
self.toolbar.AddButton(self.copyBmp, "Copy", self.CopyFleetCB)
|
||||
self.renameBtn = self.toolbar.AddButton(self.renameBmp, "Rename", self.RenameFleetCB)
|
||||
self.toolbar.AddButton(self.deleteBmp, "Delete", self.DeleteFleetCB)
|
||||
|
||||
self.editWidth = 150
|
||||
self.tcFleetName = wx.TextCtrl(self, wx.ID_ANY, "%s" % self.fleetName, wx.DefaultPosition, (self.editWidth, -1), wx.TE_PROCESS_ENTER)
|
||||
|
||||
if self.fleetBrowser.fleetIDMustEditName != self.fleetID:
|
||||
self.tcFleetName.Show(False)
|
||||
else:
|
||||
self.tcFleetName.SetFocus()
|
||||
self.tcFleetName.SelectAll()
|
||||
self.fleetBrowser.fleetIDMustEditName = -1
|
||||
self.renameBtn.SetBitmap(self.acceptBmp)
|
||||
self.selected = True
|
||||
|
||||
self.tcFleetName.Bind(wx.EVT_KILL_FOCUS, self.OnEditLostFocus)
|
||||
self.tcFleetName.Bind(wx.EVT_TEXT_ENTER, self.RenameFleet)
|
||||
self.tcFleetName.Bind(wx.EVT_KEY_DOWN, self.EditCheckEsc)
|
||||
|
||||
self.animCount = 0
|
||||
|
||||
def MouseLeftUp(self, event):
|
||||
if self.tcFleetName.IsShown():
|
||||
self.RestoreEditButton()
|
||||
else:
|
||||
wx.PostEvent(self.fleetBrowser, FleetItemSelect(fleetID=self.fleetID))
|
||||
|
||||
def CopyFleetCB(self):
|
||||
if self.tcFleetName.IsShown():
|
||||
self.RestoreEditButton()
|
||||
return
|
||||
|
||||
wx.PostEvent(self.fleetBrowser, FleetItemCopy(fleetID=self.fleetID))
|
||||
|
||||
def RenameFleetCB(self):
|
||||
|
||||
if self.tcFleetName.IsShown():
|
||||
|
||||
self.RenameFleet(None)
|
||||
self.RestoreEditButton()
|
||||
|
||||
else:
|
||||
self.tcFleetName.SetValue(self.fleetName)
|
||||
self.tcFleetName.Show()
|
||||
|
||||
self.renameBtn.SetBitmap(self.acceptBmp)
|
||||
self.Refresh()
|
||||
|
||||
self.tcFleetName.SetFocus()
|
||||
self.tcFleetName.SelectAll()
|
||||
|
||||
self.Refresh()
|
||||
|
||||
def RenameFleet(self, event):
|
||||
|
||||
newFleetName = self.tcFleetName.GetValue()
|
||||
self.fleetName = newFleetName
|
||||
|
||||
self.tcFleetName.Show(False)
|
||||
|
||||
wx.PostEvent(self.fleetBrowser, FleetItemRename(fleetID=self.fleetID, fleetName=self.fleetName))
|
||||
self.Refresh()
|
||||
|
||||
def DeleteFleetCB(self):
|
||||
if self.tcFleetName.IsShown():
|
||||
self.RestoreEditButton()
|
||||
return
|
||||
wx.PostEvent(self.fleetBrowser, FleetItemDelete(fleetID=self.fleetID))
|
||||
|
||||
def RestoreEditButton(self):
|
||||
self.tcFleetName.Show(False)
|
||||
self.renameBtn.SetBitmap(self.renameBmp)
|
||||
self.Refresh()
|
||||
|
||||
def OnEditLostFocus(self, event):
|
||||
self.RestoreEditButton()
|
||||
self.Refresh()
|
||||
|
||||
def EditCheckEsc(self, event):
|
||||
if event.GetKeyCode() == wx.WXK_ESCAPE:
|
||||
self.RestoreEditButton()
|
||||
else:
|
||||
event.Skip()
|
||||
|
||||
def IsSelected(self):
|
||||
return self.selected
|
||||
|
||||
def UpdateElementsPos(self, mdc):
|
||||
rect = self.GetRect()
|
||||
|
||||
self.toolbarx = rect.width - self.toolbar.GetWidth() - self.padding
|
||||
self.toolbary = (rect.height - self.toolbar.GetHeight()) / 2
|
||||
|
||||
self.toolbarx = self.toolbarx + self.animCount
|
||||
|
||||
self.fleetBmpx = self.padding + (rect.height - self.fleetBmp.GetWidth()) / 2
|
||||
self.fleetBmpy = (rect.height - self.fleetBmp.GetHeight()) / 2
|
||||
|
||||
self.fleetBmpx -= self.animCount
|
||||
|
||||
self.textStartx = self.fleetBmpx + self.fleetBmp.GetWidth() + self.padding
|
||||
|
||||
self.fleetNamey = (rect.height - self.fleetBmp.GetHeight()) / 2
|
||||
|
||||
mdc.SetFont(self.fontBig)
|
||||
wtext, htext = mdc.GetTextExtent(self.fleetName)
|
||||
|
||||
self.fleetCounty = self.fleetNamey + htext
|
||||
|
||||
mdc.SetFont(self.fontSmall)
|
||||
|
||||
wlabel, hlabel = mdc.GetTextExtent(self.toolbar.hoverLabel)
|
||||
|
||||
self.thoverx = self.toolbarx - self.padding - wlabel
|
||||
self.thovery = (rect.height - hlabel) / 2
|
||||
self.thoverw = wlabel
|
||||
|
||||
def DrawItem(self, mdc):
|
||||
# rect = self.GetRect()
|
||||
|
||||
windowColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)
|
||||
textColor = colorUtils.GetSuitableColor(windowColor, 1)
|
||||
|
||||
mdc.SetTextForeground(textColor)
|
||||
|
||||
self.UpdateElementsPos(mdc)
|
||||
|
||||
self.toolbar.SetPosition((self.toolbarx, self.toolbary))
|
||||
mdc.DrawBitmap(self.fleetEffBmp, self.fleetBmpx + 3, self.fleetBmpy + 2)
|
||||
mdc.DrawBitmap(self.fleetBmp, self.fleetBmpx, self.fleetBmpy)
|
||||
|
||||
mdc.SetFont(self.fontNormal)
|
||||
|
||||
suffix = "%d ships" % self.fleetCount if self.fleetCount > 1 else "%d ship" % self.fleetCount if self.fleetCount == 1 else "No ships"
|
||||
fleetCount = "Fleet size: %s" % suffix
|
||||
fleetCount = GetPartialText(mdc, fleetCount, self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw)
|
||||
|
||||
mdc.DrawText(fleetCount, self.textStartx, self.fleetCounty)
|
||||
|
||||
mdc.SetFont(self.fontSmall)
|
||||
mdc.DrawText(self.toolbar.hoverLabel, self.thoverx, self.thovery)
|
||||
|
||||
mdc.SetFont(self.fontBig)
|
||||
|
||||
pfname = GetPartialText(mdc, self.fleetName, self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw)
|
||||
mdc.DrawText(pfname, self.textStartx, self.fleetNamey)
|
||||
|
||||
if self.tcFleetName.IsShown():
|
||||
self.AdjustControlSizePos(self.tcFleetName, self.textStartx, self.toolbarx - self.editWidth - self.padding)
|
||||
|
||||
def AdjustControlSizePos(self, editCtl, start, end):
|
||||
fnEditSize = editCtl.GetSize()
|
||||
wSize = self.GetSize()
|
||||
fnEditPosX = end
|
||||
fnEditPosY = (wSize.height - fnEditSize.height) / 2
|
||||
if fnEditPosX < start:
|
||||
editCtl.SetSize((self.editWidth + fnEditPosX - start, -1))
|
||||
editCtl.SetPosition((start, fnEditPosY))
|
||||
else:
|
||||
editCtl.SetSize((self.editWidth, -1))
|
||||
editCtl.SetPosition((fnEditPosX, fnEditPosY))
|
||||
|
||||
|
||||
class PFGenBitmapButton(GenBitmapButton):
|
||||
def __init__(self, parent, id, bitmap, pos, size, style):
|
||||
GenBitmapButton.__init__(self, parent, id, bitmap, pos, size, style)
|
||||
self.bgcolor = wx.Brush(wx.WHITE)
|
||||
|
||||
def SetBackgroundColour(self, color):
|
||||
self.bgcolor = wx.Brush(color)
|
||||
|
||||
def GetBackgroundBrush(self, dc):
|
||||
return self.bgcolor
|
||||
import wx
|
||||
from wx.lib.buttons import GenBitmapButton
|
||||
|
||||
import service.fleet
|
||||
import gui.mainFrame
|
||||
import gui.utils.colorUtils as colorUtils
|
||||
import gui.sfBrowserItem as SFItem
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
from gui.PFListPane import PFListPane
|
||||
from gui.utils.drawUtils import GetPartialText
|
||||
|
||||
FleetSelected, EVT_FLEET_SELECTED = wx.lib.newevent.NewEvent()
|
||||
FleetRenamed, EVT_FLEET_RENAMED = wx.lib.newevent.NewEvent()
|
||||
FleetRemoved, EVT_FLEET_REMOVED = wx.lib.newevent.NewEvent()
|
||||
FleetItemSelect, EVT_FLEET_ITEM_SELECT = wx.lib.newevent.NewEvent()
|
||||
FleetItemDelete, EVT_FLEET_ITEM_DELETE = wx.lib.newevent.NewEvent()
|
||||
FleetItemNew, EVT_FLEET_ITEM_NEW = wx.lib.newevent.NewEvent()
|
||||
FleetItemCopy, EVT_FLEET_ITEM_COPY = wx.lib.newevent.NewEvent()
|
||||
FleetItemRename, EVT_FLEET_ITEM_RENAME = wx.lib.newevent.NewEvent()
|
||||
|
||||
|
||||
class FleetBrowser(wx.Panel):
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__(self, parent)
|
||||
|
||||
self.sFleet = service.fleet.Fleet.getInstance()
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
self.hpane = FleetBrowserHeader(self)
|
||||
mainSizer.Add(self.hpane, 0, wx.EXPAND)
|
||||
|
||||
self.m_sl2 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL)
|
||||
mainSizer.Add(self.m_sl2, 0, wx.EXPAND, 0)
|
||||
|
||||
self.fleetItemContainer = PFFleetItemContainer(self)
|
||||
|
||||
mainSizer.Add(self.fleetItemContainer, 1, wx.EXPAND)
|
||||
|
||||
self.SetSizer(mainSizer)
|
||||
self.Layout()
|
||||
|
||||
self.filter = ""
|
||||
self.fleetIDMustEditName = -1
|
||||
|
||||
self.Bind(wx.EVT_SIZE, self.SizeRefreshList)
|
||||
|
||||
self.Bind(EVT_FLEET_ITEM_NEW, self.AddNewFleetItem)
|
||||
self.Bind(EVT_FLEET_ITEM_SELECT, self.SelectFleetItem)
|
||||
self.Bind(EVT_FLEET_ITEM_DELETE, self.DeleteFleetItem)
|
||||
self.Bind(EVT_FLEET_ITEM_COPY, self.CopyFleetItem)
|
||||
self.Bind(EVT_FLEET_ITEM_RENAME, self.RenameFleetItem)
|
||||
|
||||
self.PopulateFleetList()
|
||||
|
||||
def AddNewFleetItem(self, event):
|
||||
fleetName = event.fleetName
|
||||
newFleet = self.sFleet.addFleet()
|
||||
self.sFleet.renameFleet(newFleet, fleetName)
|
||||
|
||||
self.fleetIDMustEditName = newFleet.ID
|
||||
self.AddItem(newFleet.ID, newFleet.name, newFleet.count())
|
||||
|
||||
def SelectFleetItem(self, event):
|
||||
fleetID = event.fleetID
|
||||
self.fleetItemContainer.SelectWidgetByFleetID(fleetID)
|
||||
wx.PostEvent(self.mainFrame, FleetSelected(fleetID=fleetID))
|
||||
|
||||
def CopyFleetItem(self, event):
|
||||
fleetID = event.fleetID
|
||||
fleet = self.sFleet.copyFleetByID(fleetID)
|
||||
|
||||
fleetName = fleet.name + " Copy"
|
||||
self.sFleet.renameFleet(fleet, fleetName)
|
||||
|
||||
self.fleetIDMustEditName = fleet.ID
|
||||
self.AddItem(fleet.ID, fleet.name, fleet.count())
|
||||
|
||||
self.fleetItemContainer.SelectWidgetByFleetID(fleet.ID)
|
||||
wx.PostEvent(self.mainFrame, FleetSelected(fleetID=fleet.ID))
|
||||
|
||||
def RenameFleetItem(self, event):
|
||||
fleetID = event.fleetID
|
||||
fleet = self.sFleet.getFleetByID(fleetID)
|
||||
|
||||
newFleetName = event.fleetName
|
||||
|
||||
self.sFleet.renameFleet(fleet, newFleetName)
|
||||
wx.PostEvent(self.mainFrame, FleetRenamed(fleetID=fleet.ID))
|
||||
|
||||
def DeleteFleetItem(self, event):
|
||||
self.sFleet.deleteFleetByID(event.fleetID)
|
||||
self.PopulateFleetList()
|
||||
wx.PostEvent(self.mainFrame, FleetRemoved(fleetID=event.fleetID))
|
||||
|
||||
def AddItem(self, ID, name, count):
|
||||
self.fleetItemContainer.AddWidget(FleetItem(self, ID, name, count))
|
||||
widget = self.fleetItemContainer.GetWidgetByFleetID(ID)
|
||||
self.fleetItemContainer.RefreshList(True)
|
||||
self.fleetItemContainer.ScrollChildIntoView(widget)
|
||||
wx.PostEvent(self, FleetItemSelect(fleetID=ID))
|
||||
|
||||
def PopulateFleetList(self):
|
||||
self.Freeze()
|
||||
filter_ = self.filter
|
||||
self.fleetItemContainer.RemoveAllChildren()
|
||||
fleetList = self.sFleet.getFleetList()
|
||||
for fleetID, fleetName, fleetCount in fleetList:
|
||||
if fleetName.lower().find(filter_.lower()) != -1:
|
||||
self.fleetItemContainer.AddWidget(FleetItem(self, fleetID, fleetName, fleetCount))
|
||||
self.fleetItemContainer.RefreshList()
|
||||
self.Thaw()
|
||||
|
||||
def SetFilter(self, filter):
|
||||
self.filter = filter
|
||||
|
||||
def SizeRefreshList(self, event):
|
||||
ewidth, eheight = event.GetSize()
|
||||
self.Layout()
|
||||
self.fleetItemContainer.Layout()
|
||||
self.fleetItemContainer.RefreshList(True)
|
||||
event.Skip()
|
||||
|
||||
|
||||
class FleetBrowserHeader(wx.Panel):
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(500, 24),
|
||||
style=wx.TAB_TRAVERSAL)
|
||||
self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE))
|
||||
|
||||
self.newBmp = BitmapLoader.getBitmap("fit_add_small", "gui")
|
||||
bmpSize = (16, 16)
|
||||
|
||||
mainSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
if 'wxMac' in wx.PlatformInfo:
|
||||
bgcolour = wx.Colour(0, 0, 0, 0)
|
||||
else:
|
||||
bgcolour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE)
|
||||
|
||||
self.fbNewFleet = PFGenBitmapButton(self, wx.ID_ANY, self.newBmp, wx.DefaultPosition, bmpSize, wx.BORDER_NONE)
|
||||
mainSizer.Add(self.fbNewFleet, 0, wx.LEFT | wx.TOP | wx.BOTTOM | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
self.fbNewFleet.SetBackgroundColour(bgcolour)
|
||||
|
||||
self.sl1 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_VERTICAL)
|
||||
mainSizer.Add(self.sl1, 0, wx.EXPAND | wx.LEFT, 5)
|
||||
|
||||
self.tcFilter = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
mainSizer.Add(self.tcFilter, 0, wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
|
||||
self.stStatus = wx.StaticText(self, wx.ID_ANY, u"", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stStatus.Wrap(-1)
|
||||
mainSizer.Add(self.stStatus, 1, wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
|
||||
self.SetSizer(mainSizer)
|
||||
self.Layout()
|
||||
|
||||
self.fbNewFleet.Bind(wx.EVT_ENTER_WINDOW, self.fbNewEnterWindow)
|
||||
self.fbNewFleet.Bind(wx.EVT_LEAVE_WINDOW, self.fbHItemLeaveWindow)
|
||||
self.fbNewFleet.Bind(wx.EVT_BUTTON, self.OnNewFleetItem)
|
||||
|
||||
self.tcFilter.Bind(wx.EVT_TEXT, self.OnFilterText)
|
||||
|
||||
self.tcFilter.Bind(wx.EVT_ENTER_WINDOW, self.fbFilterEnterWindow)
|
||||
self.tcFilter.Bind(wx.EVT_LEAVE_WINDOW, self.fbHItemLeaveWindow)
|
||||
|
||||
def OnFilterText(self, event):
|
||||
filter = self.tcFilter.GetValue()
|
||||
self.Parent.SetFilter(filter)
|
||||
self.Parent.PopulateFleetList()
|
||||
event.Skip()
|
||||
|
||||
def OnNewFleetItem(self, event):
|
||||
wx.PostEvent(self.Parent, FleetItemNew(fleetName="New Fleet"))
|
||||
|
||||
def fbNewEnterWindow(self, event):
|
||||
self.stStatus.SetLabel("New fleet")
|
||||
self.Parent.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
|
||||
event.Skip()
|
||||
|
||||
def fbHItemLeaveWindow(self, event):
|
||||
self.stStatus.SetLabel("")
|
||||
self.Parent.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
|
||||
event.Skip()
|
||||
|
||||
def fbFilterEnterWindow(self, event):
|
||||
self.stStatus.SetLabel("Filter list")
|
||||
event.Skip()
|
||||
|
||||
|
||||
class PFFleetItemContainer(PFListPane):
|
||||
def __init__(self, parent):
|
||||
PFListPane.__init__(self, parent)
|
||||
self.selectedWidget = -1
|
||||
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
|
||||
|
||||
def IsWidgetSelectedByContext(self, widget):
|
||||
if self.GetWidgetList()[widget].IsSelected():
|
||||
return True
|
||||
return False
|
||||
|
||||
def GetWidgetIndex(self, widgetWnd):
|
||||
return self.GetWidgetList().index(widgetWnd)
|
||||
|
||||
def GetWidgetByFleetID(self, fleetID):
|
||||
for widget in self.GetWidgetList():
|
||||
if widget.fleetID == fleetID:
|
||||
return widget
|
||||
return None
|
||||
|
||||
def SelectWidget(self, widgetWnd):
|
||||
wlist = self.GetWidgetList()
|
||||
if self.selectedWidget != -1:
|
||||
wlist[self.selectedWidget].SetSelected(False)
|
||||
wlist[self.selectedWidget].Refresh()
|
||||
windex = self.GetWidgetIndex(widgetWnd)
|
||||
wlist[windex].SetSelected(True)
|
||||
wlist[windex].Refresh()
|
||||
self.selectedWidget = windex
|
||||
|
||||
def SelectWidgetByFleetID(self, fleetID):
|
||||
widgetWnd = self.GetWidgetByFleetID(fleetID)
|
||||
if widgetWnd:
|
||||
self.SelectWidget(widgetWnd)
|
||||
|
||||
def RemoveWidget(self, child):
|
||||
child.Destroy()
|
||||
self.selectedWidget = -1
|
||||
self._wList.remove(child)
|
||||
|
||||
def RemoveAllChildren(self):
|
||||
for widget in self._wList:
|
||||
widget.Destroy()
|
||||
|
||||
self.selectedWidget = -1
|
||||
self._wList = []
|
||||
|
||||
def OnLeftUp(self, event):
|
||||
event.Skip()
|
||||
|
||||
|
||||
class FleetItem(SFItem.SFBrowserItem):
|
||||
def __init__(self, parent, fleetID, fleetName, fleetCount,
|
||||
id=wx.ID_ANY, pos=wx.DefaultPosition,
|
||||
size=(0, 40), style=0):
|
||||
SFItem.SFBrowserItem.__init__(self, parent, size=size)
|
||||
|
||||
self.fleetBrowser = self.Parent
|
||||
self.fleetID = fleetID
|
||||
self.fleetName = fleetName
|
||||
self.fleetCount = fleetCount
|
||||
|
||||
self.padding = 4
|
||||
|
||||
self.fontBig = wx.FontFromPixelSize((0, 15), wx.SWISS, wx.NORMAL, wx.BOLD, False)
|
||||
self.fontNormal = wx.FontFromPixelSize((0, 14), wx.SWISS, wx.NORMAL, wx.NORMAL, False)
|
||||
self.fontSmall = wx.FontFromPixelSize((0, 12), wx.SWISS, wx.NORMAL, wx.NORMAL, False)
|
||||
|
||||
self.copyBmp = BitmapLoader.getBitmap("fit_add_small", "gui")
|
||||
self.renameBmp = BitmapLoader.getBitmap("fit_rename_small", "gui")
|
||||
self.deleteBmp = BitmapLoader.getBitmap("fit_delete_small", "gui")
|
||||
self.acceptBmp = BitmapLoader.getBitmap("faccept_small", "gui")
|
||||
self.fleetBmp = BitmapLoader.getBitmap("fleet_item_big", "gui")
|
||||
|
||||
fleetImg = self.fleetBmp.ConvertToImage()
|
||||
fleetImg = fleetImg.Blur(2)
|
||||
|
||||
if not fleetImg.HasAlpha():
|
||||
fleetImg.InitAlpha()
|
||||
|
||||
fleetImg = fleetImg.AdjustChannels(1, 1, 1, 0.5)
|
||||
self.fleetEffBmp = wx.BitmapFromImage(fleetImg)
|
||||
|
||||
self.toolbar.AddButton(self.copyBmp, "Copy", self.CopyFleetCB)
|
||||
self.renameBtn = self.toolbar.AddButton(self.renameBmp, "Rename", self.RenameFleetCB)
|
||||
self.toolbar.AddButton(self.deleteBmp, "Delete", self.DeleteFleetCB)
|
||||
|
||||
self.editWidth = 150
|
||||
self.tcFleetName = wx.TextCtrl(self, wx.ID_ANY, "%s" % self.fleetName, wx.DefaultPosition, (self.editWidth, -1),
|
||||
wx.TE_PROCESS_ENTER)
|
||||
|
||||
if self.fleetBrowser.fleetIDMustEditName != self.fleetID:
|
||||
self.tcFleetName.Show(False)
|
||||
else:
|
||||
self.tcFleetName.SetFocus()
|
||||
self.tcFleetName.SelectAll()
|
||||
self.fleetBrowser.fleetIDMustEditName = -1
|
||||
self.renameBtn.SetBitmap(self.acceptBmp)
|
||||
self.selected = True
|
||||
|
||||
self.tcFleetName.Bind(wx.EVT_KILL_FOCUS, self.OnEditLostFocus)
|
||||
self.tcFleetName.Bind(wx.EVT_TEXT_ENTER, self.RenameFleet)
|
||||
self.tcFleetName.Bind(wx.EVT_KEY_DOWN, self.EditCheckEsc)
|
||||
|
||||
self.animCount = 0
|
||||
|
||||
def MouseLeftUp(self, event):
|
||||
if self.tcFleetName.IsShown():
|
||||
self.RestoreEditButton()
|
||||
else:
|
||||
wx.PostEvent(self.fleetBrowser, FleetItemSelect(fleetID=self.fleetID))
|
||||
|
||||
def CopyFleetCB(self):
|
||||
if self.tcFleetName.IsShown():
|
||||
self.RestoreEditButton()
|
||||
return
|
||||
|
||||
wx.PostEvent(self.fleetBrowser, FleetItemCopy(fleetID=self.fleetID))
|
||||
|
||||
def RenameFleetCB(self):
|
||||
|
||||
if self.tcFleetName.IsShown():
|
||||
|
||||
self.RenameFleet(None)
|
||||
self.RestoreEditButton()
|
||||
|
||||
else:
|
||||
self.tcFleetName.SetValue(self.fleetName)
|
||||
self.tcFleetName.Show()
|
||||
|
||||
self.renameBtn.SetBitmap(self.acceptBmp)
|
||||
self.Refresh()
|
||||
|
||||
self.tcFleetName.SetFocus()
|
||||
self.tcFleetName.SelectAll()
|
||||
|
||||
self.Refresh()
|
||||
|
||||
def RenameFleet(self, event):
|
||||
|
||||
newFleetName = self.tcFleetName.GetValue()
|
||||
self.fleetName = newFleetName
|
||||
|
||||
self.tcFleetName.Show(False)
|
||||
|
||||
wx.PostEvent(self.fleetBrowser, FleetItemRename(fleetID=self.fleetID, fleetName=self.fleetName))
|
||||
self.Refresh()
|
||||
|
||||
def DeleteFleetCB(self):
|
||||
if self.tcFleetName.IsShown():
|
||||
self.RestoreEditButton()
|
||||
return
|
||||
wx.PostEvent(self.fleetBrowser, FleetItemDelete(fleetID=self.fleetID))
|
||||
|
||||
def RestoreEditButton(self):
|
||||
self.tcFleetName.Show(False)
|
||||
self.renameBtn.SetBitmap(self.renameBmp)
|
||||
self.Refresh()
|
||||
|
||||
def OnEditLostFocus(self, event):
|
||||
self.RestoreEditButton()
|
||||
self.Refresh()
|
||||
|
||||
def EditCheckEsc(self, event):
|
||||
if event.GetKeyCode() == wx.WXK_ESCAPE:
|
||||
self.RestoreEditButton()
|
||||
else:
|
||||
event.Skip()
|
||||
|
||||
def IsSelected(self):
|
||||
return self.selected
|
||||
|
||||
def UpdateElementsPos(self, mdc):
|
||||
rect = self.GetRect()
|
||||
|
||||
self.toolbarx = rect.width - self.toolbar.GetWidth() - self.padding
|
||||
self.toolbary = (rect.height - self.toolbar.GetHeight()) / 2
|
||||
|
||||
self.toolbarx = self.toolbarx + self.animCount
|
||||
|
||||
self.fleetBmpx = self.padding + (rect.height - self.fleetBmp.GetWidth()) / 2
|
||||
self.fleetBmpy = (rect.height - self.fleetBmp.GetHeight()) / 2
|
||||
|
||||
self.fleetBmpx -= self.animCount
|
||||
|
||||
self.textStartx = self.fleetBmpx + self.fleetBmp.GetWidth() + self.padding
|
||||
|
||||
self.fleetNamey = (rect.height - self.fleetBmp.GetHeight()) / 2
|
||||
|
||||
mdc.SetFont(self.fontBig)
|
||||
wtext, htext = mdc.GetTextExtent(self.fleetName)
|
||||
|
||||
self.fleetCounty = self.fleetNamey + htext
|
||||
|
||||
mdc.SetFont(self.fontSmall)
|
||||
|
||||
wlabel, hlabel = mdc.GetTextExtent(self.toolbar.hoverLabel)
|
||||
|
||||
self.thoverx = self.toolbarx - self.padding - wlabel
|
||||
self.thovery = (rect.height - hlabel) / 2
|
||||
self.thoverw = wlabel
|
||||
|
||||
def DrawItem(self, mdc):
|
||||
# rect = self.GetRect()
|
||||
|
||||
windowColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)
|
||||
textColor = colorUtils.GetSuitableColor(windowColor, 1)
|
||||
|
||||
mdc.SetTextForeground(textColor)
|
||||
|
||||
self.UpdateElementsPos(mdc)
|
||||
|
||||
self.toolbar.SetPosition((self.toolbarx, self.toolbary))
|
||||
mdc.DrawBitmap(self.fleetEffBmp, self.fleetBmpx + 3, self.fleetBmpy + 2)
|
||||
mdc.DrawBitmap(self.fleetBmp, self.fleetBmpx, self.fleetBmpy)
|
||||
|
||||
mdc.SetFont(self.fontNormal)
|
||||
|
||||
suffix = "%d ships" % self.fleetCount if self.fleetCount > 1 else "%d ship" % self.fleetCount if self.fleetCount == 1 else "No ships"
|
||||
fleetCount = "Fleet size: %s" % suffix
|
||||
fleetCount = GetPartialText(mdc, fleetCount, self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw)
|
||||
|
||||
mdc.DrawText(fleetCount, self.textStartx, self.fleetCounty)
|
||||
|
||||
mdc.SetFont(self.fontSmall)
|
||||
mdc.DrawText(self.toolbar.hoverLabel, self.thoverx, self.thovery)
|
||||
|
||||
mdc.SetFont(self.fontBig)
|
||||
|
||||
pfname = GetPartialText(mdc, self.fleetName, self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw)
|
||||
mdc.DrawText(pfname, self.textStartx, self.fleetNamey)
|
||||
|
||||
if self.tcFleetName.IsShown():
|
||||
self.AdjustControlSizePos(self.tcFleetName, self.textStartx, self.toolbarx - self.editWidth - self.padding)
|
||||
|
||||
def AdjustControlSizePos(self, editCtl, start, end):
|
||||
fnEditSize = editCtl.GetSize()
|
||||
wSize = self.GetSize()
|
||||
fnEditPosX = end
|
||||
fnEditPosY = (wSize.height - fnEditSize.height) / 2
|
||||
if fnEditPosX < start:
|
||||
editCtl.SetSize((self.editWidth + fnEditPosX - start, -1))
|
||||
editCtl.SetPosition((start, fnEditPosY))
|
||||
else:
|
||||
editCtl.SetSize((self.editWidth, -1))
|
||||
editCtl.SetPosition((fnEditPosX, fnEditPosY))
|
||||
|
||||
|
||||
class PFGenBitmapButton(GenBitmapButton):
|
||||
def __init__(self, parent, id, bitmap, pos, size, style):
|
||||
GenBitmapButton.__init__(self, parent, id, bitmap, pos, size, style)
|
||||
self.bgcolor = wx.Brush(wx.WHITE)
|
||||
|
||||
def SetBackgroundColour(self, color):
|
||||
self.bgcolor = wx.Brush(color)
|
||||
|
||||
def GetBackgroundBrush(self, dc):
|
||||
return self.bgcolor
|
||||
|
||||
@@ -32,7 +32,8 @@ import gui.globalEvents as GE
|
||||
|
||||
class GangView(ScrolledPanel):
|
||||
def __init__(self, parent):
|
||||
ScrolledPanel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(100, 20), style=wx.TAB_TRAVERSAL | wx.HSCROLL | wx.VSCROLL)
|
||||
ScrolledPanel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(100, 20),
|
||||
style=wx.TAB_TRAVERSAL | wx.HSCROLL | wx.VSCROLL)
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
|
||||
@@ -49,10 +50,10 @@ class GangView(ScrolledPanel):
|
||||
|
||||
self.fleet = {}
|
||||
for id_, option in enumerate(self.options):
|
||||
|
||||
# set content for each commander
|
||||
self.fleet[id_] = {}
|
||||
self.fleet[id_]['stLabel'] = wx.StaticText(self, wx.ID_ANY, self.options[id_] + ':', wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.fleet[id_]['stLabel'] = wx.StaticText(self, wx.ID_ANY, self.options[id_] + ':', wx.DefaultPosition,
|
||||
wx.DefaultSize, 0)
|
||||
self.fleet[id_]['stText'] = wx.StaticText(self, wx.ID_ANY, 'None', wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.fleet[id_]['chFit'] = wx.Choice(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, [])
|
||||
self.fleet[id_]['chChar'] = wx.Choice(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, [])
|
||||
@@ -94,7 +95,8 @@ class GangView(ScrolledPanel):
|
||||
for id_ in self.fleet:
|
||||
# set various properties
|
||||
self.fleet[id_]['stLabel'].Wrap(-1)
|
||||
self.fleet[id_]['stLabel'].SetFont(wx.Font(wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString))
|
||||
self.fleet[id_]['stLabel'].SetFont(
|
||||
wx.Font(wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString))
|
||||
self.fleet[id_]['stText'].Wrap(-1)
|
||||
|
||||
# bind text and choice events
|
||||
@@ -107,7 +109,8 @@ class GangView(ScrolledPanel):
|
||||
|
||||
# add fit text and choice to the fit sizer
|
||||
self.fleet[id_]['fitSizer'].Add(self.fleet[id_]['stText'], 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
|
||||
self.fleet[id_]['fitSizer'].Add(self.fleet[id_]['chFit'], 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, 1)
|
||||
self.fleet[id_]['fitSizer'].Add(self.fleet[id_]['chFit'], 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND,
|
||||
1)
|
||||
|
||||
# add everything to the content sizer
|
||||
contentFGSizer.Add(self.fleet[id_]['stLabel'], 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
|
||||
@@ -271,7 +274,8 @@ class GangView(ScrolledPanel):
|
||||
raise Exception()
|
||||
|
||||
self.fleet[id_]['stText'].SetLabel(commander.ship.item.name + ": " + commander.name)
|
||||
self.fleet[id_]['chChar'].SetStringSelection(commander.character.name if commander.character is not None else "All 0")
|
||||
self.fleet[id_]['chChar'].SetStringSelection(
|
||||
commander.character.name if commander.character is not None else "All 0")
|
||||
self.fleet[id_]['chChar'].Enable()
|
||||
self.fleet[id_]['chFit'].Hide()
|
||||
self.fleet[id_]['stText'].Show()
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import wx.lib.newevent
|
||||
|
||||
|
||||
FitChanged, FIT_CHANGED = wx.lib.newevent.NewEvent()
|
||||
CharListUpdated, CHAR_LIST_UPDATED = wx.lib.newevent.NewEvent()
|
||||
CharChanged, CHAR_CHANGED = wx.lib.newevent.NewEvent()
|
||||
|
||||
@@ -1,281 +1,282 @@
|
||||
# =============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# This file is part of pyfa.
|
||||
#
|
||||
# pyfa is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# pyfa is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
|
||||
# =============================================================================
|
||||
|
||||
import os
|
||||
|
||||
import wx
|
||||
|
||||
from service.fit import Fit
|
||||
import gui.display
|
||||
import gui.mainFrame
|
||||
import gui.globalEvents as GE
|
||||
from gui.graph import Graph
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
|
||||
|
||||
enabled = True
|
||||
mplImported = False
|
||||
|
||||
|
||||
class GraphFrame(wx.Frame):
|
||||
def __init__(self, parent, style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE | wx.FRAME_FLOAT_ON_PARENT):
|
||||
|
||||
global enabled
|
||||
global mplImported
|
||||
|
||||
self.legendFix = False
|
||||
if not enabled:
|
||||
return
|
||||
|
||||
try:
|
||||
import matplotlib as mpl
|
||||
|
||||
try:
|
||||
cache_dir = mpl._get_cachedir()
|
||||
except:
|
||||
cache_dir = unicode(os.path.expanduser(os.path.join("~", ".matplotlib")))
|
||||
|
||||
cache_file = os.path.join(cache_dir, 'fontList.cache')
|
||||
if os.access(cache_dir, os.W_OK | os.X_OK) and os.path.isfile(cache_file):
|
||||
# remove matplotlib font cache, see #234
|
||||
os.remove(cache_file)
|
||||
if not mplImported:
|
||||
mpl.use('wxagg')
|
||||
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas
|
||||
from matplotlib.figure import Figure
|
||||
enabled = True
|
||||
if mpl.__version__[0] != "1":
|
||||
print("pyfa: Found matplotlib version ", mpl.__version__, " - activating OVER9000 workarounds")
|
||||
print("pyfa: Recommended minimum matplotlib version is 1.0.0")
|
||||
self.legendFix = True
|
||||
except:
|
||||
print("Problems importing matplotlib; continuing without graphs")
|
||||
enabled = False
|
||||
return
|
||||
|
||||
mplImported = True
|
||||
|
||||
wx.Frame.__init__(self, parent, title=u"pyfa: Graph Generator", style=style, size=(520, 390))
|
||||
|
||||
i = wx.IconFromBitmap(BitmapLoader.getBitmap("graphs_small", "gui"))
|
||||
self.SetIcon(i)
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.CreateStatusBar()
|
||||
|
||||
self.mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
self.SetSizer(self.mainSizer)
|
||||
|
||||
sFit = Fit.getInstance()
|
||||
fit = sFit.getFit(self.mainFrame.getActiveFit())
|
||||
self.fits = [fit] if fit is not None else []
|
||||
self.fitList = FitList(self)
|
||||
self.fitList.SetMinSize((270, -1))
|
||||
|
||||
self.fitList.fitList.update(self.fits)
|
||||
|
||||
self.graphSelection = wx.Choice(self, wx.ID_ANY, style=0)
|
||||
self.mainSizer.Add(self.graphSelection, 0, wx.EXPAND)
|
||||
|
||||
self.figure = Figure(figsize=(4, 3))
|
||||
|
||||
rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get()
|
||||
clr = [c / 255. for c in rgbtuple]
|
||||
self.figure.set_facecolor(clr)
|
||||
self.figure.set_edgecolor(clr)
|
||||
|
||||
self.canvas = Canvas(self, -1, self.figure)
|
||||
self.canvas.SetBackgroundColour(wx.Colour(*rgbtuple))
|
||||
|
||||
self.subplot = self.figure.add_subplot(111)
|
||||
self.subplot.grid(True)
|
||||
|
||||
self.mainSizer.Add(self.canvas, 1, wx.EXPAND)
|
||||
self.mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0, wx.EXPAND)
|
||||
|
||||
self.gridPanel = wx.Panel(self)
|
||||
self.mainSizer.Add(self.gridPanel, 0, wx.EXPAND)
|
||||
|
||||
dummyBox = wx.BoxSizer(wx.VERTICAL)
|
||||
self.gridPanel.SetSizer(dummyBox)
|
||||
|
||||
self.gridSizer = wx.FlexGridSizer(0, 4)
|
||||
self.gridSizer.AddGrowableCol(1)
|
||||
dummyBox.Add(self.gridSizer, 0, wx.EXPAND)
|
||||
|
||||
for view in Graph.views:
|
||||
view = view()
|
||||
self.graphSelection.Append(view.name, view)
|
||||
|
||||
self.graphSelection.SetSelection(0)
|
||||
self.fields = {}
|
||||
self.select(0)
|
||||
self.sl1 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL)
|
||||
self.mainSizer.Add(self.sl1, 0, wx.EXPAND)
|
||||
self.mainSizer.Add(self.fitList, 0, wx.EXPAND)
|
||||
|
||||
self.fitList.fitList.Bind(wx.EVT_LEFT_DCLICK, self.removeItem)
|
||||
self.mainFrame.Bind(GE.FIT_CHANGED, self.draw)
|
||||
self.Bind(wx.EVT_CLOSE, self.close)
|
||||
|
||||
self.Fit()
|
||||
self.SetMinSize(self.GetSize())
|
||||
|
||||
def handleDrag(self, type, fitID):
|
||||
if type == "fit":
|
||||
self.AppendFitToList(fitID)
|
||||
|
||||
def close(self, event):
|
||||
self.fitList.fitList.Unbind(wx.EVT_LEFT_DCLICK, handler=self.removeItem)
|
||||
self.mainFrame.Unbind(GE.FIT_CHANGED, handler=self.draw)
|
||||
event.Skip()
|
||||
|
||||
def getView(self):
|
||||
return self.graphSelection.GetClientData(self.graphSelection.GetSelection())
|
||||
|
||||
def getValues(self):
|
||||
values = {}
|
||||
for fieldName, field in self.fields.iteritems():
|
||||
values[fieldName] = field.GetValue()
|
||||
|
||||
return values
|
||||
|
||||
def select(self, index):
|
||||
view = self.getView()
|
||||
icons = view.getIcons()
|
||||
labels = view.getLabels()
|
||||
sizer = self.gridSizer
|
||||
self.gridPanel.DestroyChildren()
|
||||
self.fields.clear()
|
||||
|
||||
# Setup textboxes
|
||||
for field, defaultVal in view.getFields().iteritems():
|
||||
|
||||
textBox = wx.TextCtrl(self.gridPanel, wx.ID_ANY, style=0)
|
||||
self.fields[field] = textBox
|
||||
textBox.Bind(wx.EVT_TEXT, self.onFieldChanged)
|
||||
sizer.Add(textBox, 1, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 3)
|
||||
if defaultVal is not None:
|
||||
if not isinstance(defaultVal, basestring):
|
||||
defaultVal = ("%f" % defaultVal).rstrip("0")
|
||||
if defaultVal[-1:] == ".":
|
||||
defaultVal = defaultVal + "0"
|
||||
|
||||
textBox.ChangeValue(defaultVal)
|
||||
|
||||
imgLabelSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
if icons:
|
||||
icon = icons.get(field)
|
||||
if icon is not None:
|
||||
static = wx.StaticBitmap(self.gridPanel)
|
||||
static.SetBitmap(icon)
|
||||
imgLabelSizer.Add(static, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 1)
|
||||
|
||||
if labels:
|
||||
label = labels.get(field)
|
||||
label = label if label is not None else field
|
||||
else:
|
||||
label = field
|
||||
|
||||
imgLabelSizer.Add(wx.StaticText(self.gridPanel, wx.ID_ANY, label), 0, wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 3)
|
||||
sizer.Add(imgLabelSizer, 0, wx.ALIGN_CENTER_VERTICAL)
|
||||
self.draw()
|
||||
|
||||
def draw(self, event=None):
|
||||
values = self.getValues()
|
||||
view = self.getView()
|
||||
self.subplot.clear()
|
||||
self.subplot.grid(True)
|
||||
legend = []
|
||||
|
||||
for fit in self.fits:
|
||||
try:
|
||||
success, status = view.getPoints(fit, values)
|
||||
if not success:
|
||||
# TODO: Add a pwetty statys bar to report errors with
|
||||
self.SetStatusText(status)
|
||||
return
|
||||
|
||||
x, y = success, status
|
||||
|
||||
self.subplot.plot(x, y)
|
||||
legend.append(fit.name)
|
||||
except:
|
||||
self.SetStatusText("Invalid values in '%s'" % fit.name)
|
||||
self.canvas.draw()
|
||||
return
|
||||
|
||||
if self.legendFix and len(legend) > 0:
|
||||
leg = self.subplot.legend(tuple(legend), "upper right", shadow=False)
|
||||
for t in leg.get_texts():
|
||||
t.set_fontsize('small')
|
||||
|
||||
for l in leg.get_lines():
|
||||
l.set_linewidth(1)
|
||||
|
||||
elif not self.legendFix and len(legend) > 0:
|
||||
leg = self.subplot.legend(tuple(legend), "upper right", shadow=False, frameon=False)
|
||||
for t in leg.get_texts():
|
||||
t.set_fontsize('small')
|
||||
|
||||
for l in leg.get_lines():
|
||||
l.set_linewidth(1)
|
||||
|
||||
self.canvas.draw()
|
||||
self.SetStatusText("")
|
||||
if event is not None:
|
||||
event.Skip()
|
||||
|
||||
def onFieldChanged(self, event):
|
||||
self.draw()
|
||||
|
||||
def AppendFitToList(self, fitID):
|
||||
sFit = Fit.getInstance()
|
||||
fit = sFit.getFit(fitID)
|
||||
if fit not in self.fits:
|
||||
self.fits.append(fit)
|
||||
|
||||
self.fitList.fitList.update(self.fits)
|
||||
self.draw()
|
||||
|
||||
def removeItem(self, event):
|
||||
row, _ = self.fitList.fitList.HitTest(event.Position)
|
||||
if row != -1:
|
||||
del self.fits[row]
|
||||
self.fitList.fitList.update(self.fits)
|
||||
self.draw()
|
||||
|
||||
|
||||
class FitList(wx.Panel):
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__(self, parent)
|
||||
self.mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
self.SetSizer(self.mainSizer)
|
||||
|
||||
self.fitList = FitDisplay(self)
|
||||
self.mainSizer.Add(self.fitList, 1, wx.EXPAND)
|
||||
fitToolTip = wx.ToolTip("Drag a fit into this list to graph it")
|
||||
self.fitList.SetToolTip(fitToolTip)
|
||||
|
||||
|
||||
class FitDisplay(gui.display.Display):
|
||||
DEFAULT_COLS = ["Base Icon",
|
||||
"Base Name"]
|
||||
|
||||
def __init__(self, parent):
|
||||
gui.display.Display.__init__(self, parent)
|
||||
# =============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# This file is part of pyfa.
|
||||
#
|
||||
# pyfa is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# pyfa is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
|
||||
# =============================================================================
|
||||
|
||||
import os
|
||||
|
||||
import wx
|
||||
|
||||
from service.fit import Fit
|
||||
import gui.display
|
||||
import gui.mainFrame
|
||||
import gui.globalEvents as GE
|
||||
from gui.graph import Graph
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
|
||||
enabled = True
|
||||
mplImported = False
|
||||
|
||||
|
||||
class GraphFrame(wx.Frame):
|
||||
def __init__(self, parent, style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE | wx.FRAME_FLOAT_ON_PARENT):
|
||||
|
||||
global enabled
|
||||
global mplImported
|
||||
|
||||
self.legendFix = False
|
||||
if not enabled:
|
||||
return
|
||||
|
||||
try:
|
||||
import matplotlib as mpl
|
||||
|
||||
try:
|
||||
cache_dir = mpl._get_cachedir()
|
||||
except:
|
||||
cache_dir = unicode(os.path.expanduser(os.path.join("~", ".matplotlib")))
|
||||
|
||||
cache_file = os.path.join(cache_dir, 'fontList.cache')
|
||||
if os.access(cache_dir, os.W_OK | os.X_OK) and os.path.isfile(cache_file):
|
||||
# remove matplotlib font cache, see #234
|
||||
os.remove(cache_file)
|
||||
if not mplImported:
|
||||
mpl.use('wxagg')
|
||||
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas
|
||||
from matplotlib.figure import Figure
|
||||
enabled = True
|
||||
if mpl.__version__[0] != "1":
|
||||
print("pyfa: Found matplotlib version ", mpl.__version__, " - activating OVER9000 workarounds")
|
||||
print("pyfa: Recommended minimum matplotlib version is 1.0.0")
|
||||
self.legendFix = True
|
||||
except:
|
||||
print("Problems importing matplotlib; continuing without graphs")
|
||||
enabled = False
|
||||
return
|
||||
|
||||
mplImported = True
|
||||
|
||||
wx.Frame.__init__(self, parent, title=u"pyfa: Graph Generator", style=style, size=(520, 390))
|
||||
|
||||
i = wx.IconFromBitmap(BitmapLoader.getBitmap("graphs_small", "gui"))
|
||||
self.SetIcon(i)
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.CreateStatusBar()
|
||||
|
||||
self.mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
self.SetSizer(self.mainSizer)
|
||||
|
||||
sFit = Fit.getInstance()
|
||||
fit = sFit.getFit(self.mainFrame.getActiveFit())
|
||||
self.fits = [fit] if fit is not None else []
|
||||
self.fitList = FitList(self)
|
||||
self.fitList.SetMinSize((270, -1))
|
||||
|
||||
self.fitList.fitList.update(self.fits)
|
||||
|
||||
self.graphSelection = wx.Choice(self, wx.ID_ANY, style=0)
|
||||
self.mainSizer.Add(self.graphSelection, 0, wx.EXPAND)
|
||||
|
||||
self.figure = Figure(figsize=(4, 3))
|
||||
|
||||
rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get()
|
||||
clr = [c / 255. for c in rgbtuple]
|
||||
self.figure.set_facecolor(clr)
|
||||
self.figure.set_edgecolor(clr)
|
||||
|
||||
self.canvas = Canvas(self, -1, self.figure)
|
||||
self.canvas.SetBackgroundColour(wx.Colour(*rgbtuple))
|
||||
|
||||
self.subplot = self.figure.add_subplot(111)
|
||||
self.subplot.grid(True)
|
||||
|
||||
self.mainSizer.Add(self.canvas, 1, wx.EXPAND)
|
||||
self.mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0,
|
||||
wx.EXPAND)
|
||||
|
||||
self.gridPanel = wx.Panel(self)
|
||||
self.mainSizer.Add(self.gridPanel, 0, wx.EXPAND)
|
||||
|
||||
dummyBox = wx.BoxSizer(wx.VERTICAL)
|
||||
self.gridPanel.SetSizer(dummyBox)
|
||||
|
||||
self.gridSizer = wx.FlexGridSizer(0, 4)
|
||||
self.gridSizer.AddGrowableCol(1)
|
||||
dummyBox.Add(self.gridSizer, 0, wx.EXPAND)
|
||||
|
||||
for view in Graph.views:
|
||||
view = view()
|
||||
self.graphSelection.Append(view.name, view)
|
||||
|
||||
self.graphSelection.SetSelection(0)
|
||||
self.fields = {}
|
||||
self.select(0)
|
||||
self.sl1 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL)
|
||||
self.mainSizer.Add(self.sl1, 0, wx.EXPAND)
|
||||
self.mainSizer.Add(self.fitList, 0, wx.EXPAND)
|
||||
|
||||
self.fitList.fitList.Bind(wx.EVT_LEFT_DCLICK, self.removeItem)
|
||||
self.mainFrame.Bind(GE.FIT_CHANGED, self.draw)
|
||||
self.Bind(wx.EVT_CLOSE, self.close)
|
||||
|
||||
self.Fit()
|
||||
self.SetMinSize(self.GetSize())
|
||||
|
||||
def handleDrag(self, type, fitID):
|
||||
if type == "fit":
|
||||
self.AppendFitToList(fitID)
|
||||
|
||||
def close(self, event):
|
||||
self.fitList.fitList.Unbind(wx.EVT_LEFT_DCLICK, handler=self.removeItem)
|
||||
self.mainFrame.Unbind(GE.FIT_CHANGED, handler=self.draw)
|
||||
event.Skip()
|
||||
|
||||
def getView(self):
|
||||
return self.graphSelection.GetClientData(self.graphSelection.GetSelection())
|
||||
|
||||
def getValues(self):
|
||||
values = {}
|
||||
for fieldName, field in self.fields.iteritems():
|
||||
values[fieldName] = field.GetValue()
|
||||
|
||||
return values
|
||||
|
||||
def select(self, index):
|
||||
view = self.getView()
|
||||
icons = view.getIcons()
|
||||
labels = view.getLabels()
|
||||
sizer = self.gridSizer
|
||||
self.gridPanel.DestroyChildren()
|
||||
self.fields.clear()
|
||||
|
||||
# Setup textboxes
|
||||
for field, defaultVal in view.getFields().iteritems():
|
||||
|
||||
textBox = wx.TextCtrl(self.gridPanel, wx.ID_ANY, style=0)
|
||||
self.fields[field] = textBox
|
||||
textBox.Bind(wx.EVT_TEXT, self.onFieldChanged)
|
||||
sizer.Add(textBox, 1, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 3)
|
||||
if defaultVal is not None:
|
||||
if not isinstance(defaultVal, basestring):
|
||||
defaultVal = ("%f" % defaultVal).rstrip("0")
|
||||
if defaultVal[-1:] == ".":
|
||||
defaultVal = defaultVal + "0"
|
||||
|
||||
textBox.ChangeValue(defaultVal)
|
||||
|
||||
imgLabelSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
if icons:
|
||||
icon = icons.get(field)
|
||||
if icon is not None:
|
||||
static = wx.StaticBitmap(self.gridPanel)
|
||||
static.SetBitmap(icon)
|
||||
imgLabelSizer.Add(static, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 1)
|
||||
|
||||
if labels:
|
||||
label = labels.get(field)
|
||||
label = label if label is not None else field
|
||||
else:
|
||||
label = field
|
||||
|
||||
imgLabelSizer.Add(wx.StaticText(self.gridPanel, wx.ID_ANY, label), 0,
|
||||
wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 3)
|
||||
sizer.Add(imgLabelSizer, 0, wx.ALIGN_CENTER_VERTICAL)
|
||||
self.draw()
|
||||
|
||||
def draw(self, event=None):
|
||||
values = self.getValues()
|
||||
view = self.getView()
|
||||
self.subplot.clear()
|
||||
self.subplot.grid(True)
|
||||
legend = []
|
||||
|
||||
for fit in self.fits:
|
||||
try:
|
||||
success, status = view.getPoints(fit, values)
|
||||
if not success:
|
||||
# TODO: Add a pwetty statys bar to report errors with
|
||||
self.SetStatusText(status)
|
||||
return
|
||||
|
||||
x, y = success, status
|
||||
|
||||
self.subplot.plot(x, y)
|
||||
legend.append(fit.name)
|
||||
except:
|
||||
self.SetStatusText("Invalid values in '%s'" % fit.name)
|
||||
self.canvas.draw()
|
||||
return
|
||||
|
||||
if self.legendFix and len(legend) > 0:
|
||||
leg = self.subplot.legend(tuple(legend), "upper right", shadow=False)
|
||||
for t in leg.get_texts():
|
||||
t.set_fontsize('small')
|
||||
|
||||
for l in leg.get_lines():
|
||||
l.set_linewidth(1)
|
||||
|
||||
elif not self.legendFix and len(legend) > 0:
|
||||
leg = self.subplot.legend(tuple(legend), "upper right", shadow=False, frameon=False)
|
||||
for t in leg.get_texts():
|
||||
t.set_fontsize('small')
|
||||
|
||||
for l in leg.get_lines():
|
||||
l.set_linewidth(1)
|
||||
|
||||
self.canvas.draw()
|
||||
self.SetStatusText("")
|
||||
if event is not None:
|
||||
event.Skip()
|
||||
|
||||
def onFieldChanged(self, event):
|
||||
self.draw()
|
||||
|
||||
def AppendFitToList(self, fitID):
|
||||
sFit = Fit.getInstance()
|
||||
fit = sFit.getFit(fitID)
|
||||
if fit not in self.fits:
|
||||
self.fits.append(fit)
|
||||
|
||||
self.fitList.fitList.update(self.fits)
|
||||
self.draw()
|
||||
|
||||
def removeItem(self, event):
|
||||
row, _ = self.fitList.fitList.HitTest(event.Position)
|
||||
if row != -1:
|
||||
del self.fits[row]
|
||||
self.fitList.fitList.update(self.fits)
|
||||
self.draw()
|
||||
|
||||
|
||||
class FitList(wx.Panel):
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__(self, parent)
|
||||
self.mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
self.SetSizer(self.mainSizer)
|
||||
|
||||
self.fitList = FitDisplay(self)
|
||||
self.mainSizer.Add(self.fitList, 1, wx.EXPAND)
|
||||
fitToolTip = wx.ToolTip("Drag a fit into this list to graph it")
|
||||
self.fitList.SetToolTip(fitToolTip)
|
||||
|
||||
|
||||
class FitDisplay(gui.display.Display):
|
||||
DEFAULT_COLS = ["Base Icon",
|
||||
"Base Name"]
|
||||
|
||||
def __init__(self, parent):
|
||||
gui.display.Display.__init__(self, parent)
|
||||
|
||||
@@ -64,7 +64,8 @@ class ItemStatsDialog(wx.Dialog):
|
||||
itmContext = fullContext[1]
|
||||
except IndexError:
|
||||
itmContext = None
|
||||
item = getattr(victim, "item", None) if srcContext.lower() not in ("projectedcharge", "fittingcharge") else getattr(victim, "charge", None)
|
||||
item = getattr(victim, "item", None) if srcContext.lower() not in (
|
||||
"projectedcharge", "fittingcharge") else getattr(victim, "charge", None)
|
||||
if item is None:
|
||||
sMkt = Market.getInstance()
|
||||
item = sMkt.getItem(victim.ID)
|
||||
@@ -76,7 +77,8 @@ class ItemStatsDialog(wx.Dialog):
|
||||
itemImg = BitmapLoader.getBitmap(iconFile, "icons")
|
||||
if itemImg is not None:
|
||||
self.SetIcon(wx.IconFromBitmap(itemImg))
|
||||
self.SetTitle("%s: %s%s" % ("%s Stats" % itmContext if itmContext is not None else "Stats", item.name, " (%d)" % item.ID if config.debug else ""))
|
||||
self.SetTitle("%s: %s%s" % ("%s Stats" % itmContext if itmContext is not None else "Stats", item.name,
|
||||
" (%d)" % item.ID if config.debug else ""))
|
||||
|
||||
self.SetMinSize((300, 200))
|
||||
if "wxGTK" in wx.PlatformInfo: # GTK has huge tab widgets, give it a bit more room
|
||||
@@ -232,7 +234,8 @@ class ItemDescription(wx.Panel):
|
||||
desc = re.sub("<( *)font( *)color( *)=(.*?)>(?P<inside>.*?)<( *)/( *)font( *)>", "\g<inside>", desc)
|
||||
# Strip URLs
|
||||
desc = re.sub("<( *)a(.*?)>(?P<inside>.*?)<( *)/( *)a( *)>", "\g<inside>", desc)
|
||||
desc = "<body bgcolor='" + bgcolor.GetAsString(wx.C2S_HTML_SYNTAX) + "' text='" + fgcolor.GetAsString(wx.C2S_HTML_SYNTAX) + "' >" + desc + "</body>"
|
||||
desc = "<body bgcolor='" + bgcolor.GetAsString(wx.C2S_HTML_SYNTAX) + "' text='" + fgcolor.GetAsString(
|
||||
wx.C2S_HTML_SYNTAX) + "' >" + desc + "</body>"
|
||||
|
||||
self.description.SetPage(desc)
|
||||
|
||||
@@ -240,12 +243,13 @@ class ItemDescription(wx.Panel):
|
||||
self.Layout()
|
||||
|
||||
|
||||
class ItemParams (wx.Panel):
|
||||
class ItemParams(wx.Panel):
|
||||
def __init__(self, parent, stuff, item, context=None):
|
||||
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 = AutoListCtrl(self, wx.ID_ANY,
|
||||
style=wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES | wx.NO_BORDER)
|
||||
mainSizer.Add(self.paramList, 1, wx.ALL | wx.EXPAND, 0)
|
||||
self.SetSizer(mainSizer)
|
||||
|
||||
@@ -263,10 +267,12 @@ class ItemParams (wx.Panel):
|
||||
self.totalAttrsLabel = wx.StaticText(self, wx.ID_ANY, u" ", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
bSizer.Add(self.totalAttrsLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT)
|
||||
|
||||
self.toggleViewBtn = wx.ToggleButton(self, wx.ID_ANY, u"Toggle view mode", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.toggleViewBtn = wx.ToggleButton(self, wx.ID_ANY, u"Toggle view mode", wx.DefaultPosition, wx.DefaultSize,
|
||||
0)
|
||||
bSizer.Add(self.toggleViewBtn, 0, wx.ALIGN_CENTER_VERTICAL)
|
||||
|
||||
self.exportStatsBtn = wx.ToggleButton(self, wx.ID_ANY, u"Export Item Stats", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.exportStatsBtn = wx.ToggleButton(self, wx.ID_ANY, u"Export Item Stats", wx.DefaultPosition, wx.DefaultSize,
|
||||
0)
|
||||
bSizer.Add(self.exportStatsBtn, 0, wx.ALIGN_CENTER_VERTICAL)
|
||||
|
||||
if stuff is not None:
|
||||
@@ -470,7 +476,8 @@ class ItemParams (wx.Panel):
|
||||
|
||||
trans = {"Inverse Absolute Percent": (lambda: (1 - value) * 100, unitName),
|
||||
"Inversed Modifier Percent": (lambda: (1 - value) * 100, unitName),
|
||||
"Modifier Percent": (lambda: ("%+.2f" if ((value - 1) * 100) % 1 else "%+d") % ((value - 1) * 100), unitName),
|
||||
"Modifier Percent": (
|
||||
lambda: ("%+.2f" if ((value - 1) * 100) % 1 else "%+d") % ((value - 1) * 100), unitName),
|
||||
"Volume": (lambda: value, u"m\u00B3"),
|
||||
"Sizeclass": (lambda: value, ""),
|
||||
"Absolute Percent": (lambda: (value * 100), unitName),
|
||||
@@ -508,7 +515,8 @@ class ItemCompare(wx.Panel):
|
||||
self.currentSort = None
|
||||
self.sortReverse = False
|
||||
self.item = item
|
||||
self.items = sorted(items, key=lambda x: x.attributes['metaLevel'].value if 'metaLevel' in x.attributes else None)
|
||||
self.items = sorted(items,
|
||||
key=lambda x: x.attributes['metaLevel'].value if 'metaLevel' in x.attributes else None)
|
||||
self.attrs = {}
|
||||
|
||||
# get a dict of attrName: attrInfo of all unique attributes across all items
|
||||
@@ -661,7 +669,7 @@ class ItemCompare(wx.Panel):
|
||||
trans = {"Inverse Absolute Percent": (lambda: (1 - value) * 100, unitName),
|
||||
"Inversed Modifier Percent": (lambda: (1 - value) * 100, unitName),
|
||||
"Modifier Percent": (
|
||||
lambda: ("%+.2f" if ((value - 1) * 100) % 1 else "%+d") % ((value - 1) * 100), unitName),
|
||||
lambda: ("%+.2f" if ((value - 1) * 100) % 1 else "%+d") % ((value - 1) * 100), unitName),
|
||||
"Volume": (lambda: value, u"m\u00B3"),
|
||||
"Sizeclass": (lambda: value, ""),
|
||||
"Absolute Percent": (lambda: (value * 100), unitName),
|
||||
@@ -719,14 +727,15 @@ class ItemRequirements(wx.Panel):
|
||||
self.skillIdHistory.append(skill.ID)
|
||||
|
||||
|
||||
class ItemEffects (wx.Panel):
|
||||
class ItemEffects(wx.Panel):
|
||||
def __init__(self, parent, stuff, item):
|
||||
wx.Panel.__init__(self, parent)
|
||||
self.item = item
|
||||
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
self.effectList = AutoListCtrl(self, wx.ID_ANY, style=wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES | wx.NO_BORDER)
|
||||
self.effectList = AutoListCtrl(self, wx.ID_ANY,
|
||||
style=wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES | wx.NO_BORDER)
|
||||
mainSizer.Add(self.effectList, 1, wx.ALL | wx.EXPAND, 0)
|
||||
self.SetSizer(mainSizer)
|
||||
|
||||
@@ -1033,7 +1042,8 @@ class ItemAffectedBy(wx.Panel):
|
||||
else:
|
||||
item = afflictor.item
|
||||
|
||||
items[attrName].append((type(afflictor), afflictor, item, modifier, amount, getattr(afflictor, "projected", False)))
|
||||
items[attrName].append(
|
||||
(type(afflictor), afflictor, item, modifier, amount, getattr(afflictor, "projected", False)))
|
||||
|
||||
# Make sure projected fits are on top
|
||||
rootOrder = container.keys()
|
||||
@@ -1234,7 +1244,8 @@ class ItemAffectedBy(wx.Panel):
|
||||
else:
|
||||
penalized = ""
|
||||
|
||||
attributes.append((attrName, (displayName if displayName != "" else attrName), attrModifier, attrAmount, penalized, attrIcon))
|
||||
attributes.append((attrName, (displayName if displayName != "" else attrName), attrModifier,
|
||||
attrAmount, penalized, attrIcon))
|
||||
|
||||
attrSorted = sorted(attributes, key=lambda attribName: attribName[0])
|
||||
for attr in attrSorted:
|
||||
@@ -1242,9 +1253,11 @@ class ItemAffectedBy(wx.Panel):
|
||||
|
||||
if self.showRealNames:
|
||||
display = "%s %s %.2f %s" % (attrName, attrModifier, attrAmount, penalized)
|
||||
saved = "%s %s %.2f %s" % ((displayName if displayName != "" else attrName), attrModifier, attrAmount, penalized)
|
||||
saved = "%s %s %.2f %s" % (
|
||||
(displayName if displayName != "" else attrName), attrModifier, attrAmount, penalized)
|
||||
else:
|
||||
display = "%s %s %.2f %s" % ((displayName if displayName != "" else attrName), attrModifier, attrAmount, penalized)
|
||||
display = "%s %s %.2f %s" % (
|
||||
(displayName if displayName != "" else attrName), attrModifier, attrAmount, penalized)
|
||||
saved = "%s %s %.2f %s" % (attrName, attrModifier, attrAmount, penalized)
|
||||
|
||||
treeitem = self.affectedBy.AppendItem(child, display, attrIcon)
|
||||
|
||||
@@ -81,6 +81,7 @@ if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION
|
||||
|
||||
try:
|
||||
from gui.propertyEditor import AttributeEditor
|
||||
|
||||
disableOverrideEditor = False
|
||||
except ImportError as e:
|
||||
print("Error loading Attribute Editor: %s.\nAccess to Attribute Editor is disabled." % e.message)
|
||||
@@ -240,7 +241,8 @@ class MainFrame(wx.Frame):
|
||||
def LoadPreviousOpenFits(self):
|
||||
sFit = Fit.getInstance()
|
||||
|
||||
self.prevOpenFits = SettingsProvider.getInstance().getSettings("pyfaPrevOpenFits", {"enabled": False, "pyfaOpenFits": []})
|
||||
self.prevOpenFits = SettingsProvider.getInstance().getSettings("pyfaPrevOpenFits",
|
||||
{"enabled": False, "pyfaOpenFits": []})
|
||||
fits = self.prevOpenFits['pyfaOpenFits']
|
||||
|
||||
# Remove any fits that cause exception when fetching (non-existent fits)
|
||||
@@ -259,8 +261,10 @@ class MainFrame(wx.Frame):
|
||||
OpenFitsThread(fits, self.closeWaitDialog)
|
||||
|
||||
def LoadMainFrameAttribs(self):
|
||||
mainFrameDefaultAttribs = {"wnd_width": 1000, "wnd_height": 700, "wnd_maximized": False, "browser_width": 300, "market_height": 0, "fitting_height": -200}
|
||||
self.mainFrameAttribs = SettingsProvider.getInstance().getSettings("pyfaMainWindowAttribs", mainFrameDefaultAttribs)
|
||||
mainFrameDefaultAttribs = {"wnd_width": 1000, "wnd_height": 700, "wnd_maximized": False, "browser_width": 300,
|
||||
"market_height": 0, "fitting_height": -200}
|
||||
self.mainFrameAttribs = SettingsProvider.getInstance().getSettings("pyfaMainWindowAttribs",
|
||||
mainFrameDefaultAttribs)
|
||||
|
||||
if self.mainFrameAttribs["wnd_maximized"]:
|
||||
width = mainFrameDefaultAttribs["wnd_width"]
|
||||
@@ -623,7 +627,8 @@ class MainFrame(wx.Frame):
|
||||
ModifiedAttributeDict.OVERRIDES = not ModifiedAttributeDict.OVERRIDES
|
||||
wx.PostEvent(self, GE.FitChanged(fitID=self.getActiveFit()))
|
||||
menu = self.GetMenuBar()
|
||||
menu.SetLabel(menu.toggleOverridesId, "Turn Overrides Off" if ModifiedAttributeDict.OVERRIDES else "Turn Overrides On")
|
||||
menu.SetLabel(menu.toggleOverridesId,
|
||||
"Turn Overrides Off" if ModifiedAttributeDict.OVERRIDES else "Turn Overrides On")
|
||||
|
||||
def saveChar(self, event):
|
||||
sChr = Character.getInstance()
|
||||
|
||||
@@ -27,7 +27,6 @@ import gui.graphFrame
|
||||
import gui.globalEvents as GE
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
|
||||
|
||||
if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3, 0)):
|
||||
from service.crest import CrestModes
|
||||
|
||||
@@ -158,7 +157,8 @@ class MainMenuBar(wx.MenuBar):
|
||||
helpMenu.Append(wx.ID_ABOUT)
|
||||
|
||||
if config.debug:
|
||||
helpMenu.Append(self.mainFrame.widgetInspectMenuID, "Open Widgets Inspect tool", "Open Widgets Inspect tool")
|
||||
helpMenu.Append(self.mainFrame.widgetInspectMenuID, "Open Widgets Inspect tool",
|
||||
"Open Widgets Inspect tool")
|
||||
|
||||
self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged)
|
||||
|
||||
|
||||
@@ -1,462 +1,461 @@
|
||||
# =============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# This file is part of pyfa.
|
||||
#
|
||||
# pyfa is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# pyfa is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
|
||||
# =============================================================================
|
||||
|
||||
import wx
|
||||
from service.market import Market
|
||||
from service.attribute import Attribute
|
||||
import gui.display as d
|
||||
import gui.PFSearchBox as SBox
|
||||
from gui.cachingImageList import CachingImageList
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
|
||||
|
||||
ItemSelected, ITEM_SELECTED = wx.lib.newevent.NewEvent()
|
||||
|
||||
RECENTLY_USED_MODULES = -2
|
||||
MAX_RECENTLY_USED_MODULES = 20
|
||||
|
||||
|
||||
class MarketBrowser(wx.Panel):
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__(self, parent)
|
||||
vbox = wx.BoxSizer(wx.VERTICAL)
|
||||
self.SetSizer(vbox)
|
||||
|
||||
# Add a search box on top
|
||||
self.search = SearchBox(self)
|
||||
vbox.Add(self.search, 0, wx.EXPAND)
|
||||
|
||||
self.splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
|
||||
vbox.Add(self.splitter, 1, wx.EXPAND)
|
||||
|
||||
# Grab market service instance and create child objects
|
||||
self.sMkt = Market.getInstance()
|
||||
self.searchMode = False
|
||||
self.marketView = MarketTree(self.splitter, self)
|
||||
self.itemView = ItemView(self.splitter, self)
|
||||
|
||||
self.splitter.SplitHorizontally(self.marketView, self.itemView)
|
||||
self.splitter.SetMinimumPaneSize(250)
|
||||
|
||||
# Setup our buttons for metaGroup selection
|
||||
# Same fix as for search box on macs,
|
||||
# need some pixels of extra space or everything clips and is ugly
|
||||
p = wx.Panel(self)
|
||||
box = wx.BoxSizer(wx.HORIZONTAL)
|
||||
p.SetSizer(box)
|
||||
vbox.Add(p, 0, wx.EXPAND)
|
||||
self.metaButtons = []
|
||||
for name in self.sMkt.META_MAP.keys():
|
||||
btn = wx.ToggleButton(p, wx.ID_ANY, name.capitalize(), style=wx.BU_EXACTFIT)
|
||||
setattr(self, name, btn)
|
||||
box.Add(btn, 1, wx.ALIGN_CENTER)
|
||||
btn.Bind(wx.EVT_TOGGLEBUTTON, self.toggleMetaButton)
|
||||
btn.metaName = name
|
||||
self.metaButtons.append(btn)
|
||||
# Make itemview to set toggles according to list contents
|
||||
self.itemView.setToggles()
|
||||
|
||||
p.SetMinSize((wx.SIZE_AUTO_WIDTH, btn.GetSize()[1] + 5))
|
||||
|
||||
def toggleMetaButton(self, event):
|
||||
"""Process clicks on toggle buttons"""
|
||||
ctrl = wx.GetMouseState().CmdDown()
|
||||
ebtn = event.EventObject
|
||||
if not ctrl:
|
||||
for btn in self.metaButtons:
|
||||
if btn.Enabled:
|
||||
if btn == ebtn:
|
||||
btn.SetValue(True)
|
||||
else:
|
||||
btn.SetValue(False)
|
||||
else:
|
||||
# Note: using the 'wrong' value for clicked button might seem weird,
|
||||
# But the button is toggled by wx and we should deal with it
|
||||
activeBtns = set()
|
||||
for btn in self.metaButtons:
|
||||
if (btn.GetValue() is True and btn != ebtn) or (btn.GetValue() is False and btn == ebtn):
|
||||
activeBtns.add(btn)
|
||||
# Do 'nothing' if we're trying to turn last active button off
|
||||
if len(activeBtns) == 1 and activeBtns.pop() == ebtn:
|
||||
# Keep button in the same state
|
||||
ebtn.SetValue(True)
|
||||
return
|
||||
# Leave old unfiltered list contents, just re-filter them and show
|
||||
self.itemView.filterItemStore()
|
||||
|
||||
def jump(self, item):
|
||||
self.marketView.jump(item)
|
||||
|
||||
|
||||
class SearchBox(SBox.PFSearchBox):
|
||||
def __init__(self, parent, **kwargs):
|
||||
SBox.PFSearchBox.__init__(self, parent, **kwargs)
|
||||
cancelBitmap = BitmapLoader.getBitmap("fit_delete_small", "gui")
|
||||
searchBitmap = BitmapLoader.getBitmap("fsearch_small", "gui")
|
||||
self.SetSearchBitmap(searchBitmap)
|
||||
self.SetCancelBitmap(cancelBitmap)
|
||||
self.ShowSearchButton()
|
||||
self.ShowCancelButton()
|
||||
|
||||
|
||||
class MarketTree(wx.TreeCtrl):
|
||||
def __init__(self, parent, marketBrowser):
|
||||
wx.TreeCtrl.__init__(self, parent, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT)
|
||||
self.root = self.AddRoot("root")
|
||||
|
||||
self.imageList = CachingImageList(16, 16)
|
||||
self.SetImageList(self.imageList)
|
||||
|
||||
self.sMkt = marketBrowser.sMkt
|
||||
self.marketBrowser = marketBrowser
|
||||
|
||||
# Form market tree root
|
||||
sMkt = self.sMkt
|
||||
for mktGrp in sMkt.getMarketRoot():
|
||||
iconId = self.addImage(sMkt.getIconByMarketGroup(mktGrp))
|
||||
childId = self.AppendItem(self.root, mktGrp.name, iconId, data=wx.TreeItemData(mktGrp.ID))
|
||||
# All market groups which were never expanded are dummies, here we assume
|
||||
# that all root market groups are expandable
|
||||
self.AppendItem(childId, "dummy")
|
||||
self.SortChildren(self.root)
|
||||
|
||||
# Add recently used modules node
|
||||
rumIconId = self.addImage("market_small", "gui")
|
||||
self.AppendItem(self.root, "Recently Used Modules", rumIconId, data=wx.TreeItemData(RECENTLY_USED_MODULES))
|
||||
|
||||
# Bind our lookup method to when the tree gets expanded
|
||||
self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.expandLookup)
|
||||
|
||||
def addImage(self, iconFile, location="icons"):
|
||||
if iconFile is None:
|
||||
return -1
|
||||
return self.imageList.GetImageIndex(iconFile, location)
|
||||
|
||||
def expandLookup(self, event):
|
||||
"""Process market tree expands"""
|
||||
root = event.Item
|
||||
child = self.GetFirstChild(root)[0]
|
||||
# If child of given market group is a dummy
|
||||
if self.GetItemText(child) == "dummy":
|
||||
# Delete it
|
||||
self.Delete(child)
|
||||
# And add real market group contents
|
||||
sMkt = self.sMkt
|
||||
currentMktGrp = sMkt.getMarketGroup(self.GetPyData(root), eager="children")
|
||||
for childMktGrp in sMkt.getMarketGroupChildren(currentMktGrp):
|
||||
# If market should have items but it doesn't, do not show it
|
||||
if sMkt.marketGroupValidityCheck(childMktGrp) is False:
|
||||
continue
|
||||
iconId = self.addImage(sMkt.getIconByMarketGroup(childMktGrp))
|
||||
try:
|
||||
childId = self.AppendItem(root, childMktGrp.name, iconId, data=wx.TreeItemData(childMktGrp.ID))
|
||||
except:
|
||||
continue
|
||||
if sMkt.marketGroupHasTypesCheck(childMktGrp) is False:
|
||||
self.AppendItem(childId, "dummy")
|
||||
|
||||
self.SortChildren(root)
|
||||
|
||||
def jump(self, item):
|
||||
"""Open market group and meta tab of given item"""
|
||||
self.marketBrowser.searchMode = False
|
||||
sMkt = self.sMkt
|
||||
mg = sMkt.getMarketGroupByItem(item)
|
||||
metaId = sMkt.getMetaGroupIdByItem(item)
|
||||
|
||||
jumpList = []
|
||||
while mg is not None:
|
||||
jumpList.append(mg.ID)
|
||||
mg = mg.parent
|
||||
|
||||
for id in sMkt.ROOT_MARKET_GROUPS:
|
||||
if id in jumpList:
|
||||
jumpList = jumpList[:jumpList.index(id) + 1]
|
||||
|
||||
item = self.root
|
||||
for i in range(len(jumpList) - 1, -1, -1):
|
||||
target = jumpList[i]
|
||||
child, cookie = self.GetFirstChild(item)
|
||||
while self.GetItemPyData(child) != target:
|
||||
child, cookie = self.GetNextChild(item, cookie)
|
||||
|
||||
item = child
|
||||
self.Expand(item)
|
||||
|
||||
self.SelectItem(item)
|
||||
self.marketBrowser.itemView.selectionMade(forcedMetaSelect=metaId)
|
||||
|
||||
|
||||
class ItemView(d.Display):
|
||||
DEFAULT_COLS = ["Base Icon",
|
||||
"Base Name",
|
||||
"attr:power,,,True",
|
||||
"attr:cpu,,,True"]
|
||||
|
||||
def __init__(self, parent, marketBrowser):
|
||||
d.Display.__init__(self, parent)
|
||||
marketBrowser.Bind(wx.EVT_TREE_SEL_CHANGED, self.selectionMade)
|
||||
|
||||
self.unfilteredStore = set()
|
||||
self.filteredStore = set()
|
||||
self.recentlyUsedModules = set()
|
||||
self.sMkt = marketBrowser.sMkt
|
||||
self.searchMode = marketBrowser.searchMode
|
||||
|
||||
self.marketBrowser = marketBrowser
|
||||
self.marketView = marketBrowser.marketView
|
||||
|
||||
# Make sure our search actually does interesting stuff
|
||||
self.marketBrowser.search.Bind(SBox.EVT_TEXT_ENTER, self.scheduleSearch)
|
||||
self.marketBrowser.search.Bind(SBox.EVT_SEARCH_BTN, self.scheduleSearch)
|
||||
self.marketBrowser.search.Bind(SBox.EVT_CANCEL_BTN, self.clearSearch)
|
||||
self.marketBrowser.search.Bind(SBox.EVT_TEXT, self.scheduleSearch)
|
||||
|
||||
# Make sure WE do interesting stuff too
|
||||
self.Bind(wx.EVT_CONTEXT_MENU, self.contextMenu)
|
||||
self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.itemActivated)
|
||||
self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.startDrag)
|
||||
|
||||
# Make reverse map, used by sorter
|
||||
self.metaMap = self.makeReverseMetaMap()
|
||||
|
||||
# Fill up recently used modules set
|
||||
for itemID in self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"]:
|
||||
self.recentlyUsedModules.add(self.sMkt.getItem(itemID))
|
||||
|
||||
def startDrag(self, event):
|
||||
row = self.GetFirstSelected()
|
||||
|
||||
if row != -1:
|
||||
data = wx.PyTextDataObject()
|
||||
data.SetText("market:" + str(self.active[row].ID))
|
||||
|
||||
dropSource = wx.DropSource(self)
|
||||
dropSource.SetData(data)
|
||||
dropSource.DoDragDrop()
|
||||
|
||||
def itemActivated(self, event=None):
|
||||
# Check if something is selected, if so, spawn the menu for it
|
||||
sel = self.GetFirstSelected()
|
||||
if sel == -1:
|
||||
return
|
||||
|
||||
if self.mainFrame.getActiveFit():
|
||||
|
||||
self.storeRecentlyUsedMarketItem(self.active[sel].ID)
|
||||
self.recentlyUsedModules = set()
|
||||
for itemID in self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"]:
|
||||
self.recentlyUsedModules.add(self.sMkt.getItem(itemID))
|
||||
|
||||
wx.PostEvent(self.mainFrame, ItemSelected(itemID=self.active[sel].ID))
|
||||
|
||||
def storeRecentlyUsedMarketItem(self, itemID):
|
||||
if len(self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"]) > MAX_RECENTLY_USED_MODULES:
|
||||
self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"].pop(0)
|
||||
|
||||
self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"].append(itemID)
|
||||
|
||||
def selectionMade(self, event=None, forcedMetaSelect=None):
|
||||
self.marketBrowser.searchMode = False
|
||||
# Grab the threeview selection and check if it's fine
|
||||
sel = self.marketView.GetSelection()
|
||||
if sel.IsOk():
|
||||
# Get data field of the selected item (which is a marketGroup ID if anything was selected)
|
||||
seldata = self.marketView.GetPyData(sel)
|
||||
if seldata is not None and seldata != RECENTLY_USED_MODULES:
|
||||
# If market group treeview item doesn't have children (other market groups or dummies),
|
||||
# then it should have items in it and we want to request them
|
||||
if self.marketView.ItemHasChildren(sel) is False:
|
||||
sMkt = self.sMkt
|
||||
# Get current market group
|
||||
mg = sMkt.getMarketGroup(seldata, eager=("items", "items.metaGroup"))
|
||||
# Get all its items
|
||||
items = sMkt.getItemsByMarketGroup(mg)
|
||||
else:
|
||||
items = set()
|
||||
else:
|
||||
# If method was called but selection wasn't actually made or we have a hit on recently used modules
|
||||
if seldata == RECENTLY_USED_MODULES:
|
||||
items = self.recentlyUsedModules
|
||||
else:
|
||||
items = set()
|
||||
|
||||
# Fill store
|
||||
self.updateItemStore(items)
|
||||
|
||||
# Set toggle buttons / use search mode flag if recently used modules category is selected (in order to have all modules listed and not filtered)
|
||||
if seldata is not RECENTLY_USED_MODULES:
|
||||
self.setToggles(forcedMetaSelect=forcedMetaSelect)
|
||||
else:
|
||||
self.marketBrowser.searchMode = True
|
||||
self.setToggles()
|
||||
|
||||
# Update filtered items
|
||||
self.filterItemStore()
|
||||
|
||||
def updateItemStore(self, items):
|
||||
self.unfilteredStore = items
|
||||
|
||||
def filterItemStore(self):
|
||||
sMkt = self.sMkt
|
||||
selectedMetas = set()
|
||||
for btn in self.marketBrowser.metaButtons:
|
||||
if btn.GetValue():
|
||||
selectedMetas.update(sMkt.META_MAP[btn.metaName])
|
||||
self.filteredStore = sMkt.filterItemsByMeta(self.unfilteredStore, selectedMetas)
|
||||
self.update(list(self.filteredStore))
|
||||
|
||||
def setToggles(self, forcedMetaSelect=None):
|
||||
metaIDs = set()
|
||||
sMkt = self.sMkt
|
||||
for item in self.unfilteredStore:
|
||||
metaIDs.add(sMkt.getMetaGroupIdByItem(item))
|
||||
anySelection = False
|
||||
for btn in self.marketBrowser.metaButtons:
|
||||
btnMetas = sMkt.META_MAP[btn.metaName]
|
||||
if len(metaIDs.intersection(btnMetas)) > 0:
|
||||
btn.Enable(True)
|
||||
# Select all available buttons if we're searching
|
||||
if self.marketBrowser.searchMode is True:
|
||||
btn.SetValue(True)
|
||||
# Select explicitly requested button
|
||||
if forcedMetaSelect is not None:
|
||||
btn.SetValue(True if forcedMetaSelect in btnMetas else False)
|
||||
else:
|
||||
btn.Enable(False)
|
||||
btn.SetValue(False)
|
||||
if btn.GetValue():
|
||||
anySelection = True
|
||||
# If no buttons are pressed, press first active
|
||||
if anySelection is False:
|
||||
for btn in self.marketBrowser.metaButtons:
|
||||
if btn.Enabled:
|
||||
btn.SetValue(True)
|
||||
break
|
||||
|
||||
def scheduleSearch(self, event=None):
|
||||
search = self.marketBrowser.search.GetLineText(0)
|
||||
# Make sure we do not count wildcard as search symbol
|
||||
realsearch = search.replace("*", "")
|
||||
# Re-select market group if search query has zero length
|
||||
if len(realsearch) == 0:
|
||||
self.selectionMade()
|
||||
return
|
||||
# Show nothing if query is too short
|
||||
elif len(realsearch) < 3:
|
||||
self.clearSearch()
|
||||
return
|
||||
|
||||
self.marketBrowser.searchMode = True
|
||||
self.sMkt.searchItems(search, self.populateSearch)
|
||||
|
||||
def clearSearch(self, event=None):
|
||||
# Wipe item store and update everything to accomodate with it
|
||||
# If clearSearch was generated by SearchCtrl's Cancel button, clear the content also
|
||||
|
||||
if event:
|
||||
self.marketBrowser.search.Clear()
|
||||
|
||||
self.marketBrowser.searchMode = False
|
||||
self.updateItemStore(set())
|
||||
self.setToggles()
|
||||
self.filterItemStore()
|
||||
|
||||
def populateSearch(self, items):
|
||||
# If we're no longer searching, dump the results
|
||||
if self.marketBrowser.searchMode is False:
|
||||
return
|
||||
self.updateItemStore(items)
|
||||
self.setToggles()
|
||||
self.filterItemStore()
|
||||
|
||||
def itemSort(self, item):
|
||||
sMkt = self.sMkt
|
||||
catname = sMkt.getCategoryByItem(item).name
|
||||
try:
|
||||
mktgrpid = sMkt.getMarketGroupByItem(item).ID
|
||||
except AttributeError:
|
||||
mktgrpid = None
|
||||
print("unable to find market group for", item.name)
|
||||
parentname = sMkt.getParentItemByItem(item).name
|
||||
# Get position of market group
|
||||
metagrpid = sMkt.getMetaGroupIdByItem(item)
|
||||
metatab = self.metaMap.get(metagrpid)
|
||||
metalvl = self.metalvls.get(item.ID, 0)
|
||||
return (catname, mktgrpid, parentname, metatab, metalvl, item.name)
|
||||
|
||||
def contextMenu(self, event):
|
||||
# Check if something is selected, if so, spawn the menu for it
|
||||
sel = self.GetFirstSelected()
|
||||
if sel == -1:
|
||||
return
|
||||
|
||||
item = self.active[sel]
|
||||
|
||||
sMkt = self.sMkt
|
||||
sourceContext = "marketItemGroup" if self.marketBrowser.searchMode is False else "marketItemMisc"
|
||||
itemContext = sMkt.getCategoryByItem(item).name
|
||||
|
||||
menu = ContextMenu.getMenu((item,), (sourceContext, itemContext))
|
||||
self.PopupMenu(menu)
|
||||
|
||||
def populate(self, items):
|
||||
if len(items) > 0:
|
||||
# Get dictionary with meta level attribute
|
||||
sAttr = Attribute.getInstance()
|
||||
attrs = sAttr.getAttributeInfo("metaLevel")
|
||||
sMkt = self.sMkt
|
||||
self.metalvls = sMkt.directAttrRequest(items, attrs)
|
||||
# Clear selection
|
||||
self.deselectItems()
|
||||
# Perform sorting, using item's meta levels besides other stuff
|
||||
items.sort(key=self.itemSort)
|
||||
# Mark current item list as active
|
||||
self.active = items
|
||||
# Show them
|
||||
d.Display.populate(self, items)
|
||||
|
||||
def refresh(self, items):
|
||||
if len(items) > 1:
|
||||
# Get dictionary with meta level attribute
|
||||
sAttr = Attribute.getInstance()
|
||||
attrs = sAttr.getAttributeInfo("metaLevel")
|
||||
sMkt = self.sMkt
|
||||
self.metalvls = sMkt.directAttrRequest(items, attrs)
|
||||
# Re-sort stuff
|
||||
items.sort(key=self.itemSort)
|
||||
|
||||
for i, item in enumerate(items[:9]):
|
||||
# set shortcut info for first 9 modules
|
||||
item.marketShortcut = i + 1
|
||||
|
||||
d.Display.refresh(self, items)
|
||||
|
||||
def makeReverseMetaMap(self):
|
||||
"""
|
||||
Form map which tells in which tab items of given metagroup are located
|
||||
"""
|
||||
revmap = {}
|
||||
i = 0
|
||||
for mgids in self.sMkt.META_MAP.itervalues():
|
||||
for mgid in mgids:
|
||||
revmap[mgid] = i
|
||||
i += 1
|
||||
return revmap
|
||||
# =============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# This file is part of pyfa.
|
||||
#
|
||||
# pyfa is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# pyfa is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
|
||||
# =============================================================================
|
||||
|
||||
import wx
|
||||
from service.market import Market
|
||||
from service.attribute import Attribute
|
||||
import gui.display as d
|
||||
import gui.PFSearchBox as SBox
|
||||
from gui.cachingImageList import CachingImageList
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
|
||||
ItemSelected, ITEM_SELECTED = wx.lib.newevent.NewEvent()
|
||||
|
||||
RECENTLY_USED_MODULES = -2
|
||||
MAX_RECENTLY_USED_MODULES = 20
|
||||
|
||||
|
||||
class MarketBrowser(wx.Panel):
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__(self, parent)
|
||||
vbox = wx.BoxSizer(wx.VERTICAL)
|
||||
self.SetSizer(vbox)
|
||||
|
||||
# Add a search box on top
|
||||
self.search = SearchBox(self)
|
||||
vbox.Add(self.search, 0, wx.EXPAND)
|
||||
|
||||
self.splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
|
||||
vbox.Add(self.splitter, 1, wx.EXPAND)
|
||||
|
||||
# Grab market service instance and create child objects
|
||||
self.sMkt = Market.getInstance()
|
||||
self.searchMode = False
|
||||
self.marketView = MarketTree(self.splitter, self)
|
||||
self.itemView = ItemView(self.splitter, self)
|
||||
|
||||
self.splitter.SplitHorizontally(self.marketView, self.itemView)
|
||||
self.splitter.SetMinimumPaneSize(250)
|
||||
|
||||
# Setup our buttons for metaGroup selection
|
||||
# Same fix as for search box on macs,
|
||||
# need some pixels of extra space or everything clips and is ugly
|
||||
p = wx.Panel(self)
|
||||
box = wx.BoxSizer(wx.HORIZONTAL)
|
||||
p.SetSizer(box)
|
||||
vbox.Add(p, 0, wx.EXPAND)
|
||||
self.metaButtons = []
|
||||
for name in self.sMkt.META_MAP.keys():
|
||||
btn = wx.ToggleButton(p, wx.ID_ANY, name.capitalize(), style=wx.BU_EXACTFIT)
|
||||
setattr(self, name, btn)
|
||||
box.Add(btn, 1, wx.ALIGN_CENTER)
|
||||
btn.Bind(wx.EVT_TOGGLEBUTTON, self.toggleMetaButton)
|
||||
btn.metaName = name
|
||||
self.metaButtons.append(btn)
|
||||
# Make itemview to set toggles according to list contents
|
||||
self.itemView.setToggles()
|
||||
|
||||
p.SetMinSize((wx.SIZE_AUTO_WIDTH, btn.GetSize()[1] + 5))
|
||||
|
||||
def toggleMetaButton(self, event):
|
||||
"""Process clicks on toggle buttons"""
|
||||
ctrl = wx.GetMouseState().CmdDown()
|
||||
ebtn = event.EventObject
|
||||
if not ctrl:
|
||||
for btn in self.metaButtons:
|
||||
if btn.Enabled:
|
||||
if btn == ebtn:
|
||||
btn.SetValue(True)
|
||||
else:
|
||||
btn.SetValue(False)
|
||||
else:
|
||||
# Note: using the 'wrong' value for clicked button might seem weird,
|
||||
# But the button is toggled by wx and we should deal with it
|
||||
activeBtns = set()
|
||||
for btn in self.metaButtons:
|
||||
if (btn.GetValue() is True and btn != ebtn) or (btn.GetValue() is False and btn == ebtn):
|
||||
activeBtns.add(btn)
|
||||
# Do 'nothing' if we're trying to turn last active button off
|
||||
if len(activeBtns) == 1 and activeBtns.pop() == ebtn:
|
||||
# Keep button in the same state
|
||||
ebtn.SetValue(True)
|
||||
return
|
||||
# Leave old unfiltered list contents, just re-filter them and show
|
||||
self.itemView.filterItemStore()
|
||||
|
||||
def jump(self, item):
|
||||
self.marketView.jump(item)
|
||||
|
||||
|
||||
class SearchBox(SBox.PFSearchBox):
|
||||
def __init__(self, parent, **kwargs):
|
||||
SBox.PFSearchBox.__init__(self, parent, **kwargs)
|
||||
cancelBitmap = BitmapLoader.getBitmap("fit_delete_small", "gui")
|
||||
searchBitmap = BitmapLoader.getBitmap("fsearch_small", "gui")
|
||||
self.SetSearchBitmap(searchBitmap)
|
||||
self.SetCancelBitmap(cancelBitmap)
|
||||
self.ShowSearchButton()
|
||||
self.ShowCancelButton()
|
||||
|
||||
|
||||
class MarketTree(wx.TreeCtrl):
|
||||
def __init__(self, parent, marketBrowser):
|
||||
wx.TreeCtrl.__init__(self, parent, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT)
|
||||
self.root = self.AddRoot("root")
|
||||
|
||||
self.imageList = CachingImageList(16, 16)
|
||||
self.SetImageList(self.imageList)
|
||||
|
||||
self.sMkt = marketBrowser.sMkt
|
||||
self.marketBrowser = marketBrowser
|
||||
|
||||
# Form market tree root
|
||||
sMkt = self.sMkt
|
||||
for mktGrp in sMkt.getMarketRoot():
|
||||
iconId = self.addImage(sMkt.getIconByMarketGroup(mktGrp))
|
||||
childId = self.AppendItem(self.root, mktGrp.name, iconId, data=wx.TreeItemData(mktGrp.ID))
|
||||
# All market groups which were never expanded are dummies, here we assume
|
||||
# that all root market groups are expandable
|
||||
self.AppendItem(childId, "dummy")
|
||||
self.SortChildren(self.root)
|
||||
|
||||
# Add recently used modules node
|
||||
rumIconId = self.addImage("market_small", "gui")
|
||||
self.AppendItem(self.root, "Recently Used Modules", rumIconId, data=wx.TreeItemData(RECENTLY_USED_MODULES))
|
||||
|
||||
# Bind our lookup method to when the tree gets expanded
|
||||
self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.expandLookup)
|
||||
|
||||
def addImage(self, iconFile, location="icons"):
|
||||
if iconFile is None:
|
||||
return -1
|
||||
return self.imageList.GetImageIndex(iconFile, location)
|
||||
|
||||
def expandLookup(self, event):
|
||||
"""Process market tree expands"""
|
||||
root = event.Item
|
||||
child = self.GetFirstChild(root)[0]
|
||||
# If child of given market group is a dummy
|
||||
if self.GetItemText(child) == "dummy":
|
||||
# Delete it
|
||||
self.Delete(child)
|
||||
# And add real market group contents
|
||||
sMkt = self.sMkt
|
||||
currentMktGrp = sMkt.getMarketGroup(self.GetPyData(root), eager="children")
|
||||
for childMktGrp in sMkt.getMarketGroupChildren(currentMktGrp):
|
||||
# If market should have items but it doesn't, do not show it
|
||||
if sMkt.marketGroupValidityCheck(childMktGrp) is False:
|
||||
continue
|
||||
iconId = self.addImage(sMkt.getIconByMarketGroup(childMktGrp))
|
||||
try:
|
||||
childId = self.AppendItem(root, childMktGrp.name, iconId, data=wx.TreeItemData(childMktGrp.ID))
|
||||
except:
|
||||
continue
|
||||
if sMkt.marketGroupHasTypesCheck(childMktGrp) is False:
|
||||
self.AppendItem(childId, "dummy")
|
||||
|
||||
self.SortChildren(root)
|
||||
|
||||
def jump(self, item):
|
||||
"""Open market group and meta tab of given item"""
|
||||
self.marketBrowser.searchMode = False
|
||||
sMkt = self.sMkt
|
||||
mg = sMkt.getMarketGroupByItem(item)
|
||||
metaId = sMkt.getMetaGroupIdByItem(item)
|
||||
|
||||
jumpList = []
|
||||
while mg is not None:
|
||||
jumpList.append(mg.ID)
|
||||
mg = mg.parent
|
||||
|
||||
for id in sMkt.ROOT_MARKET_GROUPS:
|
||||
if id in jumpList:
|
||||
jumpList = jumpList[:jumpList.index(id) + 1]
|
||||
|
||||
item = self.root
|
||||
for i in range(len(jumpList) - 1, -1, -1):
|
||||
target = jumpList[i]
|
||||
child, cookie = self.GetFirstChild(item)
|
||||
while self.GetItemPyData(child) != target:
|
||||
child, cookie = self.GetNextChild(item, cookie)
|
||||
|
||||
item = child
|
||||
self.Expand(item)
|
||||
|
||||
self.SelectItem(item)
|
||||
self.marketBrowser.itemView.selectionMade(forcedMetaSelect=metaId)
|
||||
|
||||
|
||||
class ItemView(d.Display):
|
||||
DEFAULT_COLS = ["Base Icon",
|
||||
"Base Name",
|
||||
"attr:power,,,True",
|
||||
"attr:cpu,,,True"]
|
||||
|
||||
def __init__(self, parent, marketBrowser):
|
||||
d.Display.__init__(self, parent)
|
||||
marketBrowser.Bind(wx.EVT_TREE_SEL_CHANGED, self.selectionMade)
|
||||
|
||||
self.unfilteredStore = set()
|
||||
self.filteredStore = set()
|
||||
self.recentlyUsedModules = set()
|
||||
self.sMkt = marketBrowser.sMkt
|
||||
self.searchMode = marketBrowser.searchMode
|
||||
|
||||
self.marketBrowser = marketBrowser
|
||||
self.marketView = marketBrowser.marketView
|
||||
|
||||
# Make sure our search actually does interesting stuff
|
||||
self.marketBrowser.search.Bind(SBox.EVT_TEXT_ENTER, self.scheduleSearch)
|
||||
self.marketBrowser.search.Bind(SBox.EVT_SEARCH_BTN, self.scheduleSearch)
|
||||
self.marketBrowser.search.Bind(SBox.EVT_CANCEL_BTN, self.clearSearch)
|
||||
self.marketBrowser.search.Bind(SBox.EVT_TEXT, self.scheduleSearch)
|
||||
|
||||
# Make sure WE do interesting stuff too
|
||||
self.Bind(wx.EVT_CONTEXT_MENU, self.contextMenu)
|
||||
self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.itemActivated)
|
||||
self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.startDrag)
|
||||
|
||||
# Make reverse map, used by sorter
|
||||
self.metaMap = self.makeReverseMetaMap()
|
||||
|
||||
# Fill up recently used modules set
|
||||
for itemID in self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"]:
|
||||
self.recentlyUsedModules.add(self.sMkt.getItem(itemID))
|
||||
|
||||
def startDrag(self, event):
|
||||
row = self.GetFirstSelected()
|
||||
|
||||
if row != -1:
|
||||
data = wx.PyTextDataObject()
|
||||
data.SetText("market:" + str(self.active[row].ID))
|
||||
|
||||
dropSource = wx.DropSource(self)
|
||||
dropSource.SetData(data)
|
||||
dropSource.DoDragDrop()
|
||||
|
||||
def itemActivated(self, event=None):
|
||||
# Check if something is selected, if so, spawn the menu for it
|
||||
sel = self.GetFirstSelected()
|
||||
if sel == -1:
|
||||
return
|
||||
|
||||
if self.mainFrame.getActiveFit():
|
||||
|
||||
self.storeRecentlyUsedMarketItem(self.active[sel].ID)
|
||||
self.recentlyUsedModules = set()
|
||||
for itemID in self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"]:
|
||||
self.recentlyUsedModules.add(self.sMkt.getItem(itemID))
|
||||
|
||||
wx.PostEvent(self.mainFrame, ItemSelected(itemID=self.active[sel].ID))
|
||||
|
||||
def storeRecentlyUsedMarketItem(self, itemID):
|
||||
if len(self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"]) > MAX_RECENTLY_USED_MODULES:
|
||||
self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"].pop(0)
|
||||
|
||||
self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"].append(itemID)
|
||||
|
||||
def selectionMade(self, event=None, forcedMetaSelect=None):
|
||||
self.marketBrowser.searchMode = False
|
||||
# Grab the threeview selection and check if it's fine
|
||||
sel = self.marketView.GetSelection()
|
||||
if sel.IsOk():
|
||||
# Get data field of the selected item (which is a marketGroup ID if anything was selected)
|
||||
seldata = self.marketView.GetPyData(sel)
|
||||
if seldata is not None and seldata != RECENTLY_USED_MODULES:
|
||||
# If market group treeview item doesn't have children (other market groups or dummies),
|
||||
# then it should have items in it and we want to request them
|
||||
if self.marketView.ItemHasChildren(sel) is False:
|
||||
sMkt = self.sMkt
|
||||
# Get current market group
|
||||
mg = sMkt.getMarketGroup(seldata, eager=("items", "items.metaGroup"))
|
||||
# Get all its items
|
||||
items = sMkt.getItemsByMarketGroup(mg)
|
||||
else:
|
||||
items = set()
|
||||
else:
|
||||
# If method was called but selection wasn't actually made or we have a hit on recently used modules
|
||||
if seldata == RECENTLY_USED_MODULES:
|
||||
items = self.recentlyUsedModules
|
||||
else:
|
||||
items = set()
|
||||
|
||||
# Fill store
|
||||
self.updateItemStore(items)
|
||||
|
||||
# Set toggle buttons / use search mode flag if recently used modules category is selected (in order to have all modules listed and not filtered)
|
||||
if seldata is not RECENTLY_USED_MODULES:
|
||||
self.setToggles(forcedMetaSelect=forcedMetaSelect)
|
||||
else:
|
||||
self.marketBrowser.searchMode = True
|
||||
self.setToggles()
|
||||
|
||||
# Update filtered items
|
||||
self.filterItemStore()
|
||||
|
||||
def updateItemStore(self, items):
|
||||
self.unfilteredStore = items
|
||||
|
||||
def filterItemStore(self):
|
||||
sMkt = self.sMkt
|
||||
selectedMetas = set()
|
||||
for btn in self.marketBrowser.metaButtons:
|
||||
if btn.GetValue():
|
||||
selectedMetas.update(sMkt.META_MAP[btn.metaName])
|
||||
self.filteredStore = sMkt.filterItemsByMeta(self.unfilteredStore, selectedMetas)
|
||||
self.update(list(self.filteredStore))
|
||||
|
||||
def setToggles(self, forcedMetaSelect=None):
|
||||
metaIDs = set()
|
||||
sMkt = self.sMkt
|
||||
for item in self.unfilteredStore:
|
||||
metaIDs.add(sMkt.getMetaGroupIdByItem(item))
|
||||
anySelection = False
|
||||
for btn in self.marketBrowser.metaButtons:
|
||||
btnMetas = sMkt.META_MAP[btn.metaName]
|
||||
if len(metaIDs.intersection(btnMetas)) > 0:
|
||||
btn.Enable(True)
|
||||
# Select all available buttons if we're searching
|
||||
if self.marketBrowser.searchMode is True:
|
||||
btn.SetValue(True)
|
||||
# Select explicitly requested button
|
||||
if forcedMetaSelect is not None:
|
||||
btn.SetValue(True if forcedMetaSelect in btnMetas else False)
|
||||
else:
|
||||
btn.Enable(False)
|
||||
btn.SetValue(False)
|
||||
if btn.GetValue():
|
||||
anySelection = True
|
||||
# If no buttons are pressed, press first active
|
||||
if anySelection is False:
|
||||
for btn in self.marketBrowser.metaButtons:
|
||||
if btn.Enabled:
|
||||
btn.SetValue(True)
|
||||
break
|
||||
|
||||
def scheduleSearch(self, event=None):
|
||||
search = self.marketBrowser.search.GetLineText(0)
|
||||
# Make sure we do not count wildcard as search symbol
|
||||
realsearch = search.replace("*", "")
|
||||
# Re-select market group if search query has zero length
|
||||
if len(realsearch) == 0:
|
||||
self.selectionMade()
|
||||
return
|
||||
# Show nothing if query is too short
|
||||
elif len(realsearch) < 3:
|
||||
self.clearSearch()
|
||||
return
|
||||
|
||||
self.marketBrowser.searchMode = True
|
||||
self.sMkt.searchItems(search, self.populateSearch)
|
||||
|
||||
def clearSearch(self, event=None):
|
||||
# Wipe item store and update everything to accomodate with it
|
||||
# If clearSearch was generated by SearchCtrl's Cancel button, clear the content also
|
||||
|
||||
if event:
|
||||
self.marketBrowser.search.Clear()
|
||||
|
||||
self.marketBrowser.searchMode = False
|
||||
self.updateItemStore(set())
|
||||
self.setToggles()
|
||||
self.filterItemStore()
|
||||
|
||||
def populateSearch(self, items):
|
||||
# If we're no longer searching, dump the results
|
||||
if self.marketBrowser.searchMode is False:
|
||||
return
|
||||
self.updateItemStore(items)
|
||||
self.setToggles()
|
||||
self.filterItemStore()
|
||||
|
||||
def itemSort(self, item):
|
||||
sMkt = self.sMkt
|
||||
catname = sMkt.getCategoryByItem(item).name
|
||||
try:
|
||||
mktgrpid = sMkt.getMarketGroupByItem(item).ID
|
||||
except AttributeError:
|
||||
mktgrpid = None
|
||||
print("unable to find market group for", item.name)
|
||||
parentname = sMkt.getParentItemByItem(item).name
|
||||
# Get position of market group
|
||||
metagrpid = sMkt.getMetaGroupIdByItem(item)
|
||||
metatab = self.metaMap.get(metagrpid)
|
||||
metalvl = self.metalvls.get(item.ID, 0)
|
||||
return (catname, mktgrpid, parentname, metatab, metalvl, item.name)
|
||||
|
||||
def contextMenu(self, event):
|
||||
# Check if something is selected, if so, spawn the menu for it
|
||||
sel = self.GetFirstSelected()
|
||||
if sel == -1:
|
||||
return
|
||||
|
||||
item = self.active[sel]
|
||||
|
||||
sMkt = self.sMkt
|
||||
sourceContext = "marketItemGroup" if self.marketBrowser.searchMode is False else "marketItemMisc"
|
||||
itemContext = sMkt.getCategoryByItem(item).name
|
||||
|
||||
menu = ContextMenu.getMenu((item,), (sourceContext, itemContext))
|
||||
self.PopupMenu(menu)
|
||||
|
||||
def populate(self, items):
|
||||
if len(items) > 0:
|
||||
# Get dictionary with meta level attribute
|
||||
sAttr = Attribute.getInstance()
|
||||
attrs = sAttr.getAttributeInfo("metaLevel")
|
||||
sMkt = self.sMkt
|
||||
self.metalvls = sMkt.directAttrRequest(items, attrs)
|
||||
# Clear selection
|
||||
self.deselectItems()
|
||||
# Perform sorting, using item's meta levels besides other stuff
|
||||
items.sort(key=self.itemSort)
|
||||
# Mark current item list as active
|
||||
self.active = items
|
||||
# Show them
|
||||
d.Display.populate(self, items)
|
||||
|
||||
def refresh(self, items):
|
||||
if len(items) > 1:
|
||||
# Get dictionary with meta level attribute
|
||||
sAttr = Attribute.getInstance()
|
||||
attrs = sAttr.getAttributeInfo("metaLevel")
|
||||
sMkt = self.sMkt
|
||||
self.metalvls = sMkt.directAttrRequest(items, attrs)
|
||||
# Re-sort stuff
|
||||
items.sort(key=self.itemSort)
|
||||
|
||||
for i, item in enumerate(items[:9]):
|
||||
# set shortcut info for first 9 modules
|
||||
item.marketShortcut = i + 1
|
||||
|
||||
d.Display.refresh(self, items)
|
||||
|
||||
def makeReverseMetaMap(self):
|
||||
"""
|
||||
Form map which tells in which tab items of given metagroup are located
|
||||
"""
|
||||
revmap = {}
|
||||
i = 0
|
||||
for mgids in self.sMkt.META_MAP.itervalues():
|
||||
for mgid in mgids:
|
||||
revmap[mgid] = i
|
||||
i += 1
|
||||
return revmap
|
||||
|
||||
@@ -164,18 +164,18 @@ class DmgPatternEditorDlg(wx.Dialog):
|
||||
("Export", wx.ART_FILE_SAVE_AS, "to"))
|
||||
|
||||
for name, art, direction in importExport:
|
||||
bitmap = wx.ArtProvider.GetBitmap(art, wx.ART_BUTTON)
|
||||
btn = wx.BitmapButton(self, wx.ID_ANY, bitmap)
|
||||
bitmap = wx.ArtProvider.GetBitmap(art, wx.ART_BUTTON)
|
||||
btn = wx.BitmapButton(self, wx.ID_ANY, bitmap)
|
||||
|
||||
btn.SetMinSize(btn.GetSize())
|
||||
btn.SetMaxSize(btn.GetSize())
|
||||
btn.SetMinSize(btn.GetSize())
|
||||
btn.SetMaxSize(btn.GetSize())
|
||||
|
||||
btn.Layout()
|
||||
setattr(self, name, btn)
|
||||
btn.Enable(True)
|
||||
btn.SetToolTipString("%s patterns %s clipboard" % (name, direction))
|
||||
footerSizer.Add(btn, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_RIGHT)
|
||||
btn.Bind(wx.EVT_BUTTON, getattr(self, "{}Patterns".format(name.lower())))
|
||||
btn.Layout()
|
||||
setattr(self, name, btn)
|
||||
btn.Enable(True)
|
||||
btn.SetToolTipString("%s patterns %s clipboard" % (name, direction))
|
||||
footerSizer.Add(btn, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_RIGHT)
|
||||
btn.Bind(wx.EVT_BUTTON, getattr(self, "{}Patterns".format(name.lower())))
|
||||
|
||||
self.Layout()
|
||||
bsize = self.GetBestSize()
|
||||
@@ -196,10 +196,10 @@ class DmgPatternEditorDlg(wx.Dialog):
|
||||
p = self.entityEditor.getActiveEntity()
|
||||
total = sum(map(lambda attr: getattr(self, "%sEdit" % attr).GetValue(), self.DAMAGE_TYPES))
|
||||
for type_ in self.DAMAGE_TYPES:
|
||||
editObj = getattr(self, "%sEdit" % type_)
|
||||
percObj = getattr(self, "%sPerc" % type_)
|
||||
setattr(p, "%sAmount" % type_, editObj.GetValue())
|
||||
percObj.SetLabel("%.1f%%" % (float(editObj.GetValue()) * 100 / total if total > 0 else 0))
|
||||
editObj = getattr(self, "%sEdit" % type_)
|
||||
percObj = getattr(self, "%sPerc" % type_)
|
||||
setattr(p, "%sAmount" % type_, editObj.GetValue())
|
||||
percObj.SetLabel("%.1f%%" % (float(editObj.GetValue()) * 100 / total if total > 0 else 0))
|
||||
|
||||
self.totSizer.Layout()
|
||||
|
||||
|
||||
@@ -25,7 +25,8 @@ logger = logging.getLogger(__name__)
|
||||
class AttributeEditor(wx.Frame):
|
||||
def __init__(self, parent):
|
||||
wx.Frame.__init__(self, parent, wx.ID_ANY, title="Attribute Editor", pos=wx.DefaultPosition,
|
||||
size=wx.Size(650, 600), style=wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT | wx.TAB_TRAVERSAL)
|
||||
size=wx.Size(650, 600),
|
||||
style=wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT | wx.TAB_TRAVERSAL)
|
||||
|
||||
i = wx.IconFromBitmap(BitmapLoader.getBitmap("fit_rename_small", "gui"))
|
||||
self.SetIcon(i)
|
||||
@@ -54,7 +55,8 @@ class AttributeEditor(wx.Frame):
|
||||
mainSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
leftSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
leftPanel = wx.Panel(panel, wx.ID_ANY, style=wx.DOUBLE_BORDER if 'wxMSW' in wx.PlatformInfo else wx.SIMPLE_BORDER)
|
||||
leftPanel = wx.Panel(panel, wx.ID_ANY,
|
||||
style=wx.DOUBLE_BORDER if 'wxMSW' in wx.PlatformInfo else wx.SIMPLE_BORDER)
|
||||
|
||||
self.searchBox = SearchBox(leftPanel)
|
||||
self.itemView = ItemView(leftPanel)
|
||||
@@ -66,7 +68,8 @@ class AttributeEditor(wx.Frame):
|
||||
mainSizer.Add(leftPanel, 1, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
rightSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
self.btnRemoveOverrides = wx.Button(panel, wx.ID_ANY, u"Remove Overides for Item", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.btnRemoveOverrides = wx.Button(panel, wx.ID_ANY, u"Remove Overides for Item", wx.DefaultPosition,
|
||||
wx.DefaultSize, 0)
|
||||
self.pg = AttributeGrid(panel)
|
||||
rightSizer.Add(self.pg, 1, wx.ALL | wx.EXPAND, 5)
|
||||
rightSizer.Add(self.btnRemoveOverrides, 0, wx.ALL | wx.EXPAND, 5)
|
||||
@@ -202,7 +205,8 @@ class ItemView(d.Display):
|
||||
|
||||
class AttributeGrid(wxpg.PropertyGrid):
|
||||
def __init__(self, parent):
|
||||
wxpg.PropertyGrid.__init__(self, parent, style=wxpg.PG_HIDE_MARGIN | wxpg.PG_HIDE_CATEGORIES | wxpg.PG_BOLD_MODIFIED | wxpg.PG_TOOLTIPS)
|
||||
wxpg.PropertyGrid.__init__(self, parent,
|
||||
style=wxpg.PG_HIDE_MARGIN | wxpg.PG_HIDE_CATEGORIES | wxpg.PG_BOLD_MODIFIED | wxpg.PG_TOOLTIPS)
|
||||
self.SetExtraStyle(wxpg.PG_EX_HELP_AS_TOOLTIPS)
|
||||
|
||||
self.item = None
|
||||
|
||||
@@ -27,7 +27,8 @@ from gui.bitmapLoader import BitmapLoader
|
||||
|
||||
class TogglePanel(wx.Panel):
|
||||
def __init__(self, parent, forceLayout=-1):
|
||||
wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL)
|
||||
wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(-1, -1),
|
||||
style=wx.TAB_TRAVERSAL)
|
||||
|
||||
self._toggle = 1
|
||||
self.parent = parent
|
||||
|
||||
@@ -79,7 +79,6 @@ class TargetResistsEntityEditor(EntityEditor):
|
||||
|
||||
|
||||
class ResistsEditorDlg(wx.Dialog):
|
||||
|
||||
DAMAGE_TYPES = ("em", "thermal", "kinetic", "explosive")
|
||||
|
||||
def __init__(self, parent):
|
||||
@@ -120,7 +119,8 @@ class ResistsEditorDlg(wx.Dialog):
|
||||
setattr(self, "%sEdit" % type_, wx.TextCtrl(self, wx.ID_ANY, "", wx.DefaultPosition, defSize))
|
||||
editObj = getattr(self, "%sEdit" % type_)
|
||||
resistEditSizer.Add(editObj, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
resistEditSizer.Add(wx.StaticText(self, wx.ID_ANY, u"%", wx.DefaultPosition, wx.DefaultSize, 0), 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
resistEditSizer.Add(wx.StaticText(self, wx.ID_ANY, u"%", wx.DefaultPosition, wx.DefaultSize, 0), 0,
|
||||
wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
editObj.Bind(wx.EVT_TEXT, self.ValuesUpdated)
|
||||
|
||||
# Color we use to reset invalid value color
|
||||
|
||||
@@ -146,17 +146,17 @@ class ImplantSetEditorDlg(wx.Dialog):
|
||||
("Export", wx.ART_FILE_SAVE_AS, "to"))
|
||||
|
||||
for name, art, direction in importExport:
|
||||
bitmap = wx.ArtProvider.GetBitmap(art, wx.ART_BUTTON)
|
||||
btn = wx.BitmapButton(self, wx.ID_ANY, bitmap)
|
||||
bitmap = wx.ArtProvider.GetBitmap(art, wx.ART_BUTTON)
|
||||
btn = wx.BitmapButton(self, wx.ID_ANY, bitmap)
|
||||
|
||||
btn.SetMinSize(btn.GetSize())
|
||||
btn.SetMaxSize(btn.GetSize())
|
||||
btn.SetMinSize(btn.GetSize())
|
||||
btn.SetMaxSize(btn.GetSize())
|
||||
|
||||
btn.Layout()
|
||||
setattr(self, name, btn)
|
||||
btn.Enable(True)
|
||||
btn.SetToolTipString("%s implant sets %s clipboard" % (name, direction))
|
||||
footerSizer.Add(btn, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_RIGHT)
|
||||
btn.Layout()
|
||||
setattr(self, name, btn)
|
||||
btn.Enable(True)
|
||||
btn.SetToolTipString("%s implant sets %s clipboard" % (name, direction))
|
||||
footerSizer.Add(btn, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_RIGHT)
|
||||
|
||||
mainSizer.Add(footerSizer, 0, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
|
||||
@@ -13,7 +13,8 @@ BTN_DISABLED = 8
|
||||
|
||||
|
||||
class PFBaseButton(object):
|
||||
def __init__(self, normalBitmap=wx.NullBitmap, label="", callback=None, hoverBitmap=None, disabledBitmap=None, show=True):
|
||||
def __init__(self, normalBitmap=wx.NullBitmap, label="", callback=None, hoverBitmap=None, disabledBitmap=None,
|
||||
show=True):
|
||||
|
||||
self.normalBmp = normalBitmap
|
||||
self.dropShadowOpacity = 0.2
|
||||
|
||||
@@ -20,7 +20,6 @@ from gui.PFListPane import PFListPane
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
|
||||
|
||||
FitRenamed, EVT_FIT_RENAMED = wx.lib.newevent.NewEvent()
|
||||
FitSelected, EVT_FIT_SELECTED = wx.lib.newevent.NewEvent()
|
||||
FitRemoved, EVT_FIT_REMOVED = wx.lib.newevent.NewEvent()
|
||||
@@ -67,7 +66,8 @@ class PFWidgetsContainer(PFListPane):
|
||||
|
||||
|
||||
class RaceSelector(wx.Window):
|
||||
def __init__(self, parent, id=wx.ID_ANY, label="", pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, layout=wx.VERTICAL, animate=False):
|
||||
def __init__(self, parent, id=wx.ID_ANY, label="", pos=wx.DefaultPosition, size=wx.DefaultSize, style=0,
|
||||
layout=wx.VERTICAL, animate=False):
|
||||
wx.Window.__init__(self, parent, id, pos=pos, size=size, style=style)
|
||||
|
||||
self.animTimerID = wx.NewId()
|
||||
@@ -344,11 +344,16 @@ class NavigationPanel(SFItem.SFBrowserItem):
|
||||
self.switchBmp = self.AdjustChannels(self.switchBmpH)
|
||||
self.newBmp = self.AdjustChannels(self.newBmpH)
|
||||
|
||||
self.toolbar.AddButton(self.resetBmp, "Ship groups", clickCallback=self.OnHistoryReset, hoverBitmap=self.resetBmpH)
|
||||
self.toolbar.AddButton(self.resetBmp, "Ship groups", clickCallback=self.OnHistoryReset,
|
||||
hoverBitmap=self.resetBmpH)
|
||||
self.toolbar.AddButton(self.rewBmp, "Back", clickCallback=self.OnHistoryBack, hoverBitmap=self.rewBmpH)
|
||||
self.btnNew = self.toolbar.AddButton(self.newBmp, "New fitting", clickCallback=self.OnNewFitting, hoverBitmap=self.newBmpH, show=False)
|
||||
self.btnSwitch = self.toolbar.AddButton(self.switchBmpD, "Hide empty ship groups", clickCallback=self.ToggleEmptyGroupsView, hoverBitmap=self.switchBmpH, show=False)
|
||||
self.toolbar.AddButton(self.searchBmp, "Search fittings", clickCallback=self.ToggleSearchBox, hoverBitmap=self.searchBmpH)
|
||||
self.btnNew = self.toolbar.AddButton(self.newBmp, "New fitting", clickCallback=self.OnNewFitting,
|
||||
hoverBitmap=self.newBmpH, show=False)
|
||||
self.btnSwitch = self.toolbar.AddButton(self.switchBmpD, "Hide empty ship groups",
|
||||
clickCallback=self.ToggleEmptyGroupsView, hoverBitmap=self.switchBmpH,
|
||||
show=False)
|
||||
self.toolbar.AddButton(self.searchBmp, "Search fittings", clickCallback=self.ToggleSearchBox,
|
||||
hoverBitmap=self.searchBmpH)
|
||||
|
||||
self.padding = 4
|
||||
self.lastSearch = ""
|
||||
@@ -357,7 +362,9 @@ class NavigationPanel(SFItem.SFBrowserItem):
|
||||
|
||||
self.fontSmall = wx.Font(fonts.SMALL, wx.SWISS, wx.NORMAL, wx.NORMAL)
|
||||
w, h = size
|
||||
self.BrowserSearchBox = wx.TextCtrl(self, wx.ID_ANY, "", wx.DefaultPosition, (-1, h - 2 if 'wxGTK' in wx.PlatformInfo else -1), wx.TE_PROCESS_ENTER | (wx.BORDER_NONE if 'wxGTK' in wx.PlatformInfo else 0))
|
||||
self.BrowserSearchBox = wx.TextCtrl(self, wx.ID_ANY, "", wx.DefaultPosition,
|
||||
(-1, h - 2 if 'wxGTK' in wx.PlatformInfo else -1),
|
||||
wx.TE_PROCESS_ENTER | (wx.BORDER_NONE if 'wxGTK' in wx.PlatformInfo else 0))
|
||||
self.BrowserSearchBox.Show(False)
|
||||
|
||||
self.BrowserSearchBox.Bind(wx.EVT_TEXT_ENTER, self.OnBrowserSearchBoxEnter)
|
||||
@@ -882,7 +889,9 @@ class ShipBrowser(wx.Panel):
|
||||
for ship in ships:
|
||||
shipTrait = ship.traits.traitText if (ship.traits is not None) else "" # empty string if no traits
|
||||
|
||||
self.lpane.AddWidget(ShipItem(self.lpane, ship.ID, (ship.name, shipTrait, len(sFit.getFitsWithShip(ship.ID))), ship.race))
|
||||
self.lpane.AddWidget(
|
||||
ShipItem(self.lpane, ship.ID, (ship.name, shipTrait, len(sFit.getFitsWithShip(ship.ID))),
|
||||
ship.race))
|
||||
|
||||
for ID, name, shipID, shipName, booster, timestamp in fitList:
|
||||
ship = sMkt.getItem(shipID)
|
||||
@@ -923,7 +932,8 @@ class ShipBrowser(wx.Panel):
|
||||
|
||||
if fits:
|
||||
for fit in fits:
|
||||
shipTrait = fit.ship.traits.traitText if (fit.ship.traits is not None) else "" # empty string if no traits
|
||||
shipTrait = fit.ship.traits.traitText if (
|
||||
fit.ship.traits is not None) else "" # empty string if no traits
|
||||
|
||||
self.lpane.AddWidget(FitItem(
|
||||
self.lpane,
|
||||
@@ -1067,6 +1077,7 @@ class CategoryItem(SFItem.SFBrowserItem):
|
||||
|
||||
mdc.DrawText(categoryName, self.catx, self.caty)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Waiting for total #fits impl in eos/service
|
||||
#
|
||||
@@ -1140,7 +1151,8 @@ class ShipItem(SFItem.SFBrowserItem):
|
||||
self.editWidth = 150
|
||||
self.padding = 4
|
||||
|
||||
self.tcFitName = wx.TextCtrl(self, wx.ID_ANY, "%s fit" % self.shipName, wx.DefaultPosition, (120, -1), wx.TE_PROCESS_ENTER)
|
||||
self.tcFitName = wx.TextCtrl(self, wx.ID_ANY, "%s fit" % self.shipName, wx.DefaultPosition, (120, -1),
|
||||
wx.TE_PROCESS_ENTER)
|
||||
self.tcFitName.Show(False)
|
||||
|
||||
self.newBtn = self.toolbar.AddButton(self.newBmp, "New", self.newBtnCB)
|
||||
@@ -1331,7 +1343,8 @@ class ShipItem(SFItem.SFBrowserItem):
|
||||
|
||||
mdc.SetFont(self.fontBig)
|
||||
|
||||
psname = drawUtils.GetPartialText(mdc, shipName, self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw)
|
||||
psname = drawUtils.GetPartialText(mdc, shipName,
|
||||
self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw)
|
||||
|
||||
mdc.DrawText(psname, self.textStartx, self.shipNamey)
|
||||
|
||||
@@ -1353,7 +1366,8 @@ class ShipItem(SFItem.SFBrowserItem):
|
||||
|
||||
class PFBitmapFrame(wx.Frame):
|
||||
def __init__(self, parent, pos, bitmap):
|
||||
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title=wx.EmptyString, pos=pos, size=wx.DefaultSize, style=wx.NO_BORDER | wx.FRAME_NO_TASKBAR | wx.STAY_ON_TOP)
|
||||
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title=wx.EmptyString, pos=pos, size=wx.DefaultSize,
|
||||
style=wx.NO_BORDER | wx.FRAME_NO_TASKBAR | wx.STAY_ON_TOP)
|
||||
img = bitmap.ConvertToImage()
|
||||
img = img.ConvertToGreyscale()
|
||||
bitmap = wx.BitmapFromImage(img)
|
||||
@@ -1409,7 +1423,8 @@ class PFBitmapFrame(wx.Frame):
|
||||
|
||||
|
||||
class FitItem(SFItem.SFBrowserItem):
|
||||
def __init__(self, parent, fitID=None, shipFittingInfo=("Test", "TestTrait", "cnc's avatar", 0, 0), shipID=None, itemData=None,
|
||||
def __init__(self, parent, fitID=None, shipFittingInfo=("Test", "TestTrait", "cnc's avatar", 0, 0), shipID=None,
|
||||
itemData=None,
|
||||
id=wx.ID_ANY, pos=wx.DefaultPosition,
|
||||
size=(0, 40), style=0):
|
||||
|
||||
@@ -1487,7 +1502,8 @@ class FitItem(SFItem.SFBrowserItem):
|
||||
self.renameBtn = self.toolbar.AddButton(self.renameBmp, "Rename", self.renameBtnCB)
|
||||
self.toolbar.AddButton(self.deleteBmp, "Delete", self.deleteBtnCB)
|
||||
|
||||
self.tcFitName = wx.TextCtrl(self, wx.ID_ANY, "%s" % self.fitName, wx.DefaultPosition, (self.editWidth, -1), wx.TE_PROCESS_ENTER)
|
||||
self.tcFitName = wx.TextCtrl(self, wx.ID_ANY, "%s" % self.fitName, wx.DefaultPosition, (self.editWidth, -1),
|
||||
wx.TE_PROCESS_ENTER)
|
||||
|
||||
if self.shipBrowser.fitIDMustEditName != self.fitID:
|
||||
self.tcFitName.Show(False)
|
||||
@@ -1852,7 +1868,8 @@ class FitItem(SFItem.SFBrowserItem):
|
||||
|
||||
fitDate = time.localtime(self.timestamp)
|
||||
fitLocalDate = "%d/%02d/%02d %02d:%02d" % (fitDate[0], fitDate[1], fitDate[2], fitDate[3], fitDate[4])
|
||||
pfdate = drawUtils.GetPartialText(mdc, fitLocalDate, self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw)
|
||||
pfdate = drawUtils.GetPartialText(mdc, fitLocalDate,
|
||||
self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw)
|
||||
|
||||
mdc.DrawText(pfdate, self.textStartx, self.timestampy)
|
||||
|
||||
@@ -1861,7 +1878,8 @@ class FitItem(SFItem.SFBrowserItem):
|
||||
|
||||
mdc.SetFont(self.fontBig)
|
||||
|
||||
psname = drawUtils.GetPartialText(mdc, self.fitName, self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw)
|
||||
psname = drawUtils.GetPartialText(mdc, self.fitName,
|
||||
self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw)
|
||||
|
||||
mdc.DrawText(psname, self.textStartx, self.fitNamey)
|
||||
|
||||
|
||||
@@ -81,7 +81,8 @@ class StatsPane(wx.Panel):
|
||||
|
||||
mainSizer.Add(tp, 0, wx.EXPAND | wx.LEFT, 3)
|
||||
if i < maxviews - 1:
|
||||
mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, style=wx.HORIZONTAL), 0, wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, 2)
|
||||
mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, style=wx.HORIZONTAL), 0,
|
||||
wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, 2)
|
||||
i += 1
|
||||
tp.OnStateChange(tp.GetBestSize())
|
||||
|
||||
|
||||
@@ -23,79 +23,89 @@ import config
|
||||
import dateutil.parser
|
||||
from service import settings
|
||||
|
||||
class UpdateDialog(wx.Dialog):
|
||||
|
||||
class UpdateDialog(wx.Dialog):
|
||||
def __init__(self, parent, release):
|
||||
wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = "Pyfa Update", pos = wx.DefaultPosition, size = wx.Size( 400,300 ), style = wx.DEFAULT_DIALOG_STYLE )
|
||||
wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title="Pyfa Update", pos=wx.DefaultPosition,
|
||||
size=wx.Size(400, 300), style=wx.DEFAULT_DIALOG_STYLE)
|
||||
|
||||
self.UpdateSettings = settings.UpdateSettings.getInstance()
|
||||
self.releaseInfo = release
|
||||
self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
|
||||
self.SetSizeHintsSz(wx.DefaultSize, wx.DefaultSize)
|
||||
|
||||
mainSizer = wx.BoxSizer( wx.VERTICAL )
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
headSizer = wx.BoxSizer( wx.HORIZONTAL )
|
||||
headSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
self.headingText = wx.StaticText( self, wx.ID_ANY, "Pyfa Update Available!", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE )
|
||||
self.headingText.Wrap( -1 )
|
||||
self.headingText.SetFont( wx.Font( 14, 74, 90, 92, False) )
|
||||
self.headingText = wx.StaticText(self, wx.ID_ANY, "Pyfa Update Available!", wx.DefaultPosition, wx.DefaultSize,
|
||||
wx.ALIGN_CENTRE)
|
||||
self.headingText.Wrap(-1)
|
||||
self.headingText.SetFont(wx.Font(14, 74, 90, 92, False))
|
||||
|
||||
headSizer.Add( self.headingText, 1, wx.ALL, 5 )
|
||||
mainSizer.Add( headSizer, 0, wx.EXPAND, 5 )
|
||||
headSizer.Add(self.headingText, 1, wx.ALL, 5)
|
||||
mainSizer.Add(headSizer, 0, wx.EXPAND, 5)
|
||||
|
||||
mainSizer.Add( wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ), 0, wx.EXPAND |wx.ALL, 5 )
|
||||
mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0,
|
||||
wx.EXPAND | wx.ALL, 5)
|
||||
|
||||
versionSizer = wx.BoxSizer( wx.HORIZONTAL )
|
||||
versionSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
if(self.releaseInfo['prerelease']):
|
||||
self.releaseText = wx.StaticText( self, wx.ID_ANY, "Pre-release", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_RIGHT )
|
||||
self.releaseText.SetFont( wx.Font( 12, 74, 90, 92, False) )
|
||||
self.releaseText.SetForegroundColour( wx.Colour( 230, 0, 0 ) )
|
||||
if (self.releaseInfo['prerelease']):
|
||||
self.releaseText = wx.StaticText(self, wx.ID_ANY, "Pre-release", wx.DefaultPosition, wx.DefaultSize,
|
||||
wx.ALIGN_RIGHT)
|
||||
self.releaseText.SetFont(wx.Font(12, 74, 90, 92, False))
|
||||
self.releaseText.SetForegroundColour(wx.Colour(230, 0, 0))
|
||||
else:
|
||||
self.releaseText = wx.StaticText( self, wx.ID_ANY, "Stable", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_RIGHT )
|
||||
self.releaseText.SetFont( wx.Font( 12, 74, 90, 90, False) )
|
||||
self.releaseText = wx.StaticText(self, wx.ID_ANY, "Stable", wx.DefaultPosition, wx.DefaultSize,
|
||||
wx.ALIGN_RIGHT)
|
||||
self.releaseText.SetFont(wx.Font(12, 74, 90, 90, False))
|
||||
|
||||
self.releaseText.Wrap( -1 )
|
||||
self.releaseText.Wrap(-1)
|
||||
|
||||
versionSizer.Add( self.releaseText, 1, wx.ALL, 5 )
|
||||
versionSizer.Add(self.releaseText, 1, wx.ALL, 5)
|
||||
|
||||
self.versionText = wx.StaticText( self, wx.ID_ANY, self.releaseInfo['tag_name'], wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_LEFT )
|
||||
self.versionText.Wrap( -1 )
|
||||
self.versionText.SetFont( wx.Font( 12, 74, 90, 90, False) )
|
||||
self.versionText = wx.StaticText(self, wx.ID_ANY, self.releaseInfo['tag_name'], wx.DefaultPosition,
|
||||
wx.DefaultSize, wx.ALIGN_LEFT)
|
||||
self.versionText.Wrap(-1)
|
||||
self.versionText.SetFont(wx.Font(12, 74, 90, 90, False))
|
||||
|
||||
versionSizer.Add( self.versionText, 1, wx.ALL, 5 )
|
||||
versionSizer.AddSpacer( ( 15, 5), 0, wx.EXPAND, 5 )
|
||||
versionSizer.Add(self.versionText, 1, wx.ALL, 5)
|
||||
versionSizer.AddSpacer((15, 5), 0, wx.EXPAND, 5)
|
||||
|
||||
mainSizer.Add( versionSizer, 0, wx.EXPAND, 5 )
|
||||
mainSizer.AddSpacer( ( 0, 5), 0, wx.EXPAND, 5 )
|
||||
mainSizer.Add(versionSizer, 0, wx.EXPAND, 5)
|
||||
mainSizer.AddSpacer((0, 5), 0, wx.EXPAND, 5)
|
||||
|
||||
releaseDate = dateutil.parser.parse(self.releaseInfo['published_at'])
|
||||
notesSizer = wx.BoxSizer( wx.HORIZONTAL )
|
||||
self.notesTextCtrl = wx.TextCtrl( self, wx.ID_ANY, str(releaseDate.date())+":\n\n"+self.releaseInfo['body'], wx.DefaultPosition, wx.DefaultSize, wx.TE_AUTO_URL|wx.TE_MULTILINE|wx.TE_READONLY|wx.DOUBLE_BORDER|wx.TRANSPARENT_WINDOW )
|
||||
notesSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
self.notesTextCtrl = wx.TextCtrl(self, wx.ID_ANY, str(releaseDate.date()) + ":\n\n" + self.releaseInfo['body'],
|
||||
wx.DefaultPosition, wx.DefaultSize,
|
||||
wx.TE_AUTO_URL | wx.TE_MULTILINE | wx.TE_READONLY | wx.DOUBLE_BORDER | wx.TRANSPARENT_WINDOW)
|
||||
|
||||
notesSizer.Add( self.notesTextCtrl, 1, wx.EXPAND|wx.LEFT|wx.RIGHT, 5 )
|
||||
mainSizer.Add( notesSizer, 1, wx.EXPAND, 5 )
|
||||
notesSizer.Add(self.notesTextCtrl, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 5)
|
||||
mainSizer.Add(notesSizer, 1, wx.EXPAND, 5)
|
||||
|
||||
self.supressCheckbox = wx.CheckBox( self, wx.ID_ANY, "Don't remind me again for this release", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.supressCheckbox = wx.CheckBox(self, wx.ID_ANY, "Don't remind me again for this release",
|
||||
wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.supressCheckbox.Bind(wx.EVT_CHECKBOX, self.SuppressChange)
|
||||
|
||||
mainSizer.Add( self.supressCheckbox, 0, wx.ALL, 5 )
|
||||
mainSizer.Add( wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ), 0, wx.EXPAND |wx.ALL, 5 )
|
||||
mainSizer.Add(self.supressCheckbox, 0, wx.ALL, 5)
|
||||
mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0,
|
||||
wx.EXPAND | wx.ALL, 5)
|
||||
|
||||
actionSizer = wx.BoxSizer( wx.HORIZONTAL )
|
||||
actionSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
goSizer = wx.BoxSizer( wx.VERTICAL )
|
||||
self.downloadButton = wx.Button( self, wx.ID_ANY, "Download", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
goSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
self.downloadButton = wx.Button(self, wx.ID_ANY, "Download", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.downloadButton.Bind(wx.EVT_BUTTON, self.OnDownload)
|
||||
goSizer.Add( self.downloadButton, 0, wx.ALL, 5 )
|
||||
actionSizer.Add( goSizer, 1, wx.EXPAND, 5 )
|
||||
goSizer.Add(self.downloadButton, 0, wx.ALL, 5)
|
||||
actionSizer.Add(goSizer, 1, wx.EXPAND, 5)
|
||||
|
||||
self.closeButton = wx.Button(self, wx.ID_CLOSE)
|
||||
self.closeButton.Bind(wx.EVT_BUTTON, self.OnClose)
|
||||
actionSizer.Add( self.closeButton, 0, wx.ALL, 5 )
|
||||
mainSizer.Add( actionSizer, 0, wx.EXPAND, 5 )
|
||||
actionSizer.Add(self.closeButton, 0, wx.ALL, 5)
|
||||
mainSizer.Add(actionSizer, 0, wx.EXPAND, 5)
|
||||
|
||||
self.SetSizer( mainSizer )
|
||||
self.SetSizer(mainSizer)
|
||||
self.Layout()
|
||||
|
||||
# Handle use-case of suppressing a release, then a new version becoming available.
|
||||
@@ -104,7 +114,7 @@ class UpdateDialog(wx.Dialog):
|
||||
# safely reset this setting
|
||||
self.UpdateSettings.set('version', None)
|
||||
|
||||
self.Centre( wx.BOTH )
|
||||
self.Centre(wx.BOTH)
|
||||
|
||||
def OnClose(self, e):
|
||||
self.Close()
|
||||
@@ -116,5 +126,5 @@ class UpdateDialog(wx.Dialog):
|
||||
self.UpdateSettings.set('version', None)
|
||||
|
||||
def OnDownload(self, e):
|
||||
wx.LaunchDefaultBrowser('https://github.com/pyfa-org/Pyfa/releases/tag/'+self.releaseInfo['tag_name'])
|
||||
wx.LaunchDefaultBrowser('https://github.com/pyfa-org/Pyfa/releases/tag/' + self.releaseInfo['tag_name'])
|
||||
self.OnClose(e)
|
||||
|
||||
@@ -5,11 +5,9 @@ different wxPython versions
|
||||
|
||||
import wx
|
||||
|
||||
|
||||
if 'wxMac' in wx.PlatformInfo:
|
||||
sizes = (10, 11, 12)
|
||||
else:
|
||||
sizes = (7, 8, 9)
|
||||
|
||||
|
||||
SMALL, NORMAL, BIG = sizes
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
|
||||
import eos.db
|
||||
|
||||
|
||||
class Attribute():
|
||||
instance = None
|
||||
|
||||
@classmethod
|
||||
def getInstance(cls):
|
||||
if cls.instance is None:
|
||||
|
||||
@@ -40,6 +40,7 @@ from eos.saveddata.fighter import Fighter as es_Fighter
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CharacterImportThread(threading.Thread):
|
||||
def __init__(self, paths, callback):
|
||||
threading.Thread.__init__(self)
|
||||
@@ -80,6 +81,7 @@ class CharacterImportThread(threading.Thread):
|
||||
|
||||
wx.CallAfter(self.callback)
|
||||
|
||||
|
||||
class SkillBackupThread(threading.Thread):
|
||||
def __init__(self, path, saveFmt, activeFit, callback):
|
||||
threading.Thread.__init__(self)
|
||||
@@ -100,11 +102,12 @@ class SkillBackupThread(threading.Thread):
|
||||
with gzip.open(path, mode='wb') as backupFile:
|
||||
backupFile.write(backupData)
|
||||
else:
|
||||
with open(path, mode='w',encoding='utf-8') as backupFile:
|
||||
with open(path, mode='w', encoding='utf-8') as backupFile:
|
||||
backupFile.write(backupData)
|
||||
|
||||
wx.CallAfter(self.callback)
|
||||
|
||||
|
||||
class Character(object):
|
||||
instance = None
|
||||
skillReqsDict = {}
|
||||
@@ -151,7 +154,7 @@ class Character(object):
|
||||
for s in self.skillReqsDict['skills']:
|
||||
skillKey = str(s["skillID"]) + "::" + s["skill"] + "::" + str(int(s["level"]))
|
||||
if skillKey in skillsSeen:
|
||||
pass # Duplicate skills confuse EVEMon
|
||||
pass # Duplicate skills confuse EVEMon
|
||||
else:
|
||||
skillsSeen.add(skillKey)
|
||||
entry = ElementTree.SubElement(root, "entry")
|
||||
@@ -230,7 +233,7 @@ class Character(object):
|
||||
group = eos.db.getGroup(groupID)
|
||||
skills = []
|
||||
for skill in group.items:
|
||||
if skill.published == True:
|
||||
if skill.published is True:
|
||||
skills.append((skill.ID, skill.name))
|
||||
return skills
|
||||
|
||||
@@ -305,7 +308,7 @@ class Character(object):
|
||||
if char.name == charName:
|
||||
charID = char.characterID
|
||||
|
||||
if charID == None:
|
||||
if charID is None:
|
||||
return
|
||||
|
||||
sheet = auth.character(charID).CharacterSheet()
|
||||
|
||||
@@ -16,16 +16,18 @@ from service.pycrest.eve import EVE
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Servers(Enum):
|
||||
TQ = 0
|
||||
SISI = 1
|
||||
|
||||
|
||||
class CrestModes(Enum):
|
||||
IMPLICIT = 0
|
||||
USER = 1
|
||||
|
||||
class Crest():
|
||||
|
||||
class Crest():
|
||||
clientIDs = {
|
||||
Servers.TQ: 'f9be379951c046339dc13a00e6be7704',
|
||||
Servers.SISI: 'af87365240d644f7950af563b8418bad'
|
||||
@@ -36,9 +38,10 @@ class Crest():
|
||||
clientTest = True
|
||||
|
||||
_instance = None
|
||||
|
||||
@classmethod
|
||||
def getInstance(cls):
|
||||
if cls._instance == None:
|
||||
if cls._instance is None:
|
||||
cls._instance = Crest()
|
||||
|
||||
return cls._instance
|
||||
@@ -74,7 +77,8 @@ class Crest():
|
||||
|
||||
# Base EVE connection that is copied to all characters
|
||||
self.eve = EVE(
|
||||
client_id=self.settings.get('clientID') if self.settings.get('mode') == CrestModes.USER else self.clientIDs.get(self.settings.get('server')),
|
||||
client_id=self.settings.get('clientID') if self.settings.get(
|
||||
'mode') == CrestModes.USER else self.clientIDs.get(self.settings.get('server')),
|
||||
api_key=self.settings.get('clientSecret') if self.settings.get('mode') == CrestModes.USER else None,
|
||||
redirect_uri=self.clientCallback,
|
||||
testing=self.isTestServer
|
||||
@@ -134,16 +138,16 @@ class Crest():
|
||||
|
||||
def getFittings(self, charID):
|
||||
char = self.getCrestCharacter(charID)
|
||||
return char.eve.get('%scharacters/%d/fittings/'%(char.eve._authed_endpoint,char.ID))
|
||||
return char.eve.get('%scharacters/%d/fittings/' % (char.eve._authed_endpoint, char.ID))
|
||||
|
||||
def postFitting(self, charID, json):
|
||||
#@todo: new fitting ID can be recovered from Location header, ie: Location -> https://api-sisi.testeveonline.com/characters/1611853631/fittings/37486494/
|
||||
# @todo: new fitting ID can be recovered from Location header, ie: Location -> https://api-sisi.testeveonline.com/characters/1611853631/fittings/37486494/
|
||||
char = self.getCrestCharacter(charID)
|
||||
return char.eve.post('%scharacters/%d/fittings/'%(char.eve._authed_endpoint,char.ID), data=json)
|
||||
return char.eve.post('%scharacters/%d/fittings/' % (char.eve._authed_endpoint, char.ID), data=json)
|
||||
|
||||
def delFitting(self, charID, fittingID):
|
||||
char = self.getCrestCharacter(charID)
|
||||
return char.eve.delete('%scharacters/%d/fittings/%d/'%(char.eve._authed_endpoint, char.ID, fittingID))
|
||||
return char.eve.delete('%scharacters/%d/fittings/%d/' % (char.eve._authed_endpoint, char.ID, fittingID))
|
||||
|
||||
def logout(self):
|
||||
"""Logout of implicit character"""
|
||||
@@ -160,7 +164,8 @@ class Crest():
|
||||
logging.debug("Starting server")
|
||||
if self.httpd:
|
||||
self.stopServer()
|
||||
time.sleep(1) # we need this to ensure that the previous get_request finishes, and then the socket will close
|
||||
time.sleep(1)
|
||||
# we need this to ensure that the previous get_request finishes, and then the socket will close
|
||||
self.httpd = StoppableHTTPServer(('', 6461), AuthHandler)
|
||||
thread.start_new_thread(self.httpd.serve, (self.handleLogin,))
|
||||
|
||||
@@ -175,7 +180,7 @@ class Crest():
|
||||
logger.warn("OAUTH state mismatch")
|
||||
return
|
||||
|
||||
logger.debug("Handling CREST login with: %s"%message)
|
||||
logger.debug("Handling CREST login with: %s" % message)
|
||||
|
||||
if 'access_token' in message: # implicit
|
||||
eve = copy.deepcopy(self.eve)
|
||||
@@ -193,7 +198,7 @@ class Crest():
|
||||
|
||||
self.implicitCharacter = CrestChar(info['CharacterID'], info['CharacterName'])
|
||||
self.implicitCharacter.eve = eve
|
||||
#self.implicitCharacter.fetchImage()
|
||||
# self.implicitCharacter.fetchImage()
|
||||
|
||||
wx.PostEvent(self.mainFrame, GE.SsoLogin(type=CrestModes.IMPLICIT))
|
||||
elif 'code' in message:
|
||||
|
||||
@@ -22,12 +22,14 @@ import copy
|
||||
import eos.db
|
||||
from eos.saveddata.damagePattern import DamagePattern as es_DamagePattern
|
||||
|
||||
|
||||
class ImportError(Exception):
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
class DamagePattern():
|
||||
instance = None
|
||||
|
||||
@classmethod
|
||||
def getInstance(cls):
|
||||
if cls.instance is None:
|
||||
|
||||
@@ -174,6 +174,7 @@ proxySSL = False
|
||||
_default_useragent = "eveapi.py/1.3"
|
||||
_useragent = None # use set_user_agent() to set this.
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -309,6 +310,7 @@ def _ParseXML(response, fromContext, storeFunc):
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# API Classes
|
||||
# -----------------------------------------------------------------------------
|
||||
@@ -414,7 +416,8 @@ class _RootContext(_Context):
|
||||
if retrieve_fallback:
|
||||
# implementor is handling fallbacks...
|
||||
try:
|
||||
return _ParseXML(response, True, store and (lambda obj: cache.store(self._host, path, kw, response, obj)))
|
||||
return _ParseXML(response, True,
|
||||
store and (lambda obj: cache.store(self._host, path, kw, response, obj)))
|
||||
except Error as e:
|
||||
response = retrieve_fallback(self._host, path, kw, reason=e)
|
||||
if response is not None:
|
||||
@@ -563,7 +566,9 @@ class _Parser(object):
|
||||
if not self.container._cols or (numAttr > numCols):
|
||||
# the row data contains more attributes than were defined.
|
||||
self.container._cols = attributes[0::2]
|
||||
self.container.append([_castfunc(attributes[i], attributes[i + 1]) for i in xrange(0, len(attributes), 2)])
|
||||
self.container.append(
|
||||
[_castfunc(attributes[i], attributes[i + 1]) for i in xrange(0, len(attributes), 2)]
|
||||
)
|
||||
# </hack>
|
||||
|
||||
this._isrow = True
|
||||
@@ -675,9 +680,11 @@ class _Parser(object):
|
||||
# into a Rowset, adding the sibling element and this one.
|
||||
rs = Rowset()
|
||||
rs.__catch = rs._name = this._name
|
||||
row = [_castfunc(attributes[i], attributes[i + 1]) for i in xrange(0, len(attributes), 2)] + [getattr(this, col) for col in attributes2]
|
||||
row = [_castfunc(attributes[i], attributes[i + 1]) for i in xrange(0, len(attributes), 2)] + \
|
||||
[getattr(this, col) for col in attributes2]
|
||||
rs.append(row)
|
||||
row = [getattr(sibling, attributes[i]) for i in xrange(0, len(attributes), 2)] + [getattr(sibling, col) for col in attributes2]
|
||||
row = [getattr(sibling, attributes[i]) for i in xrange(0, len(attributes), 2)] + \
|
||||
[getattr(sibling, col) for col in attributes2]
|
||||
rs.append(row)
|
||||
rs._cols = [attributes[i] for i in xrange(0, len(attributes), 2)] + [col for col in attributes2]
|
||||
setattr(self.container, this._name, rs)
|
||||
|
||||
@@ -17,39 +17,30 @@
|
||||
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
import locale
|
||||
import copy
|
||||
import threading
|
||||
import logging
|
||||
import wx
|
||||
from codecs import open
|
||||
|
||||
import xml.parsers.expat
|
||||
|
||||
import eos.db
|
||||
from eos.types import State, Slot, Module, Drone, Fighter, Fit as FitType
|
||||
|
||||
from eos.saveddata.ship import Ship as es_Ship
|
||||
from eos.saveddata.citadel import Citadel as es_Citadel
|
||||
from eos.saveddata.implant import Implant as es_Implant
|
||||
from eos.saveddata.booster import Booster as es_Booster
|
||||
from eos.saveddata.module import Module as es_Module
|
||||
from eos.saveddata.fighter import Fighter as es_Fighter
|
||||
from eos.saveddata.drone import Drone as es_Drone
|
||||
from eos.saveddata.cargo import Cargo as es_Cargo
|
||||
from eos.saveddata.damagePattern import DamagePattern as es_DamagePattern
|
||||
|
||||
from service.market import Market
|
||||
from service.damagePattern import DamagePattern
|
||||
from service.character import Character
|
||||
from eos.saveddata.character import Character as saveddata_Character
|
||||
from eos.saveddata.citadel import Citadel as es_Citadel
|
||||
from eos.saveddata.damagePattern import DamagePattern as es_DamagePattern
|
||||
from eos.saveddata.drone import Drone as es_Drone
|
||||
from eos.saveddata.fighter import Fighter as es_Fighter
|
||||
from eos.saveddata.implant import Implant as es_Implant
|
||||
from eos.saveddata.module import Module as es_Module
|
||||
from eos.saveddata.ship import Ship as es_Ship
|
||||
from eos.types import State, Slot, Fit as FitType
|
||||
from service.character import Character
|
||||
from service.damagePattern import DamagePattern
|
||||
from service.fleet import Fleet
|
||||
from service.market import Market
|
||||
from service.settings import SettingsProvider
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
class Fit(object):
|
||||
instance = None
|
||||
|
||||
|
||||
435
service/fleet.py
435
service/fleet.py
@@ -1,217 +1,218 @@
|
||||
# =============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# This file is part of pyfa.
|
||||
#
|
||||
# pyfa is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# pyfa is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
|
||||
# =============================================================================
|
||||
|
||||
import copy
|
||||
import eos.db
|
||||
from eos.saveddata.fleet import Fleet as Fleet_
|
||||
from eos.saveddata.fleet import Fleet as Wing
|
||||
from eos.saveddata.fleet import Fleet as Squad
|
||||
|
||||
class Fleet(object):
|
||||
instance = None
|
||||
@classmethod
|
||||
def getInstance(cls):
|
||||
if cls.instance is None:
|
||||
cls.instance = Fleet()
|
||||
|
||||
return cls.instance
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def getFleetList(self):
|
||||
fleetList = []
|
||||
fleets = eos.db.getFleetList()
|
||||
for fleet in fleets:
|
||||
fleetList.append((fleet.ID, fleet.name, fleet.count()))
|
||||
|
||||
return fleetList
|
||||
|
||||
def getFleetByID(self, ID):
|
||||
f = eos.db.getFleet(ID)
|
||||
return f
|
||||
|
||||
def addFleet(self):
|
||||
f = Fleet_()
|
||||
eos.db.save(f)
|
||||
return f
|
||||
|
||||
def renameFleet(self, fleet, newName):
|
||||
fleet.name = newName
|
||||
eos.db.commit()
|
||||
|
||||
def copyFleet(self, fleet):
|
||||
newFleet = copy.deepcopy(fleet)
|
||||
eos.db.save(newFleet)
|
||||
return newFleet
|
||||
|
||||
def copyFleetByID(self, ID):
|
||||
fleet = self.getFleetByID(ID)
|
||||
return self.copyFleet(fleet)
|
||||
|
||||
def deleteFleet(self, fleet):
|
||||
eos.db.remove(fleet)
|
||||
|
||||
def deleteFleetByID(self, ID):
|
||||
fleet = self.getFleetByID(ID)
|
||||
self.deleteFleet(fleet)
|
||||
|
||||
def makeLinearFleet(self, fit):
|
||||
f = Fleet_()
|
||||
w = Wing()
|
||||
f.wings.append(w)
|
||||
s = Squad()
|
||||
w.squads.append(s)
|
||||
s.members.append(fit)
|
||||
fit.fleet = f
|
||||
eos.db.save(f)
|
||||
|
||||
def setLinearFleetCom(self, boostee, booster):
|
||||
#if boostee == booster:
|
||||
# return
|
||||
if self.getLinearFleet(boostee) is None:
|
||||
self.removeAssociatedFleetData(boostee)
|
||||
self.makeLinearFleet(boostee)
|
||||
squadIDs = set(eos.db.getSquadsIDsWithFitID(boostee.ID))
|
||||
squad = eos.db.getSquad(squadIDs.pop())
|
||||
if squad.wing.gang.leader is not None and booster is None:
|
||||
try:
|
||||
squad.wing.gang.leader.boostsFits.remove(boostee.ID)
|
||||
except KeyError:
|
||||
pass
|
||||
squad.wing.gang.leader = booster
|
||||
if self.anyBoosters(squad) is False:
|
||||
self.removeAssociatedFleetData(boostee)
|
||||
from service.fit import Fit
|
||||
sFit = Fit.getInstance()
|
||||
sFit.recalc(boostee, withBoosters=True)
|
||||
|
||||
def setLinearWingCom(self, boostee, booster):
|
||||
#if boostee == booster:
|
||||
# return
|
||||
if self.getLinearFleet(boostee) is None:
|
||||
self.removeAssociatedFleetData(boostee)
|
||||
self.makeLinearFleet(boostee)
|
||||
squadIDs = set(eos.db.getSquadsIDsWithFitID(boostee.ID))
|
||||
squad = eos.db.getSquad(squadIDs.pop())
|
||||
if squad.wing.leader is not None and booster is None:
|
||||
try:
|
||||
squad.wing.leader.boostsFits.remove(boostee.ID)
|
||||
except KeyError:
|
||||
pass
|
||||
squad.wing.leader = booster
|
||||
if self.anyBoosters(squad) is False:
|
||||
self.removeAssociatedFleetData(boostee)
|
||||
from service.fit import Fit
|
||||
sFit = Fit.getInstance()
|
||||
sFit.recalc(boostee, withBoosters=True)
|
||||
|
||||
def setLinearSquadCom(self, boostee, booster):
|
||||
#if boostee == booster:
|
||||
# return
|
||||
if self.getLinearFleet(boostee) is None:
|
||||
self.removeAssociatedFleetData(boostee)
|
||||
self.makeLinearFleet(boostee)
|
||||
squadIDs = set(eos.db.getSquadsIDsWithFitID(boostee.ID))
|
||||
squad = eos.db.getSquad(squadIDs.pop())
|
||||
if squad.leader is not None and booster is None:
|
||||
try:
|
||||
squad.leader.boostsFits.remove(boostee.ID)
|
||||
except KeyError:
|
||||
pass
|
||||
squad.leader = booster
|
||||
if self.anyBoosters(squad) is False:
|
||||
self.removeAssociatedFleetData(boostee)
|
||||
from service.fit import Fit
|
||||
sFit = Fit.getInstance()
|
||||
sFit.recalc(boostee, withBoosters=True)
|
||||
|
||||
|
||||
def getLinearFleet(self, fit):
|
||||
sqIDs = eos.db.getSquadsIDsWithFitID(fit.ID)
|
||||
if len(sqIDs) != 1:
|
||||
return None
|
||||
s = eos.db.getSquad(sqIDs[0])
|
||||
if len(s.members) != 1:
|
||||
return None
|
||||
w = s.wing
|
||||
if len(w.squads) != 1:
|
||||
return None
|
||||
f = w.gang
|
||||
if len(f.wings) != 1:
|
||||
return None
|
||||
return f
|
||||
|
||||
def removeAssociatedFleetData(self, fit):
|
||||
squadIDs = set(eos.db.getSquadsIDsWithFitID(fit.ID))
|
||||
if len(squadIDs) == 0:
|
||||
return
|
||||
squads = list(eos.db.getSquad(sqID) for sqID in squadIDs)
|
||||
wingIDs = set(squad.wing.ID for squad in squads)
|
||||
fleetIDs = set(squad.wing.gang.ID for squad in squads)
|
||||
for fleetID in fleetIDs:
|
||||
fleet = eos.db.getFleet(fleetID)
|
||||
for wing in fleet.wings:
|
||||
wingIDs.add(wing.ID)
|
||||
for wingID in wingIDs:
|
||||
wing = eos.db.getWing(wingID)
|
||||
for squad in wing.squads:
|
||||
squadIDs.add(squad.ID)
|
||||
for squadID in squadIDs:
|
||||
squad = eos.db.getSquad(squadID)
|
||||
if squad.leader is not None:
|
||||
try:
|
||||
squad.leader.boostsFits.remove(fit.ID)
|
||||
except KeyError:
|
||||
pass
|
||||
eos.db.remove(squad)
|
||||
for wingID in wingIDs:
|
||||
wing = eos.db.getWing(wingID)
|
||||
if wing.leader is not None:
|
||||
try:
|
||||
wing.leader.boostsFits.remove(fit.ID)
|
||||
except KeyError:
|
||||
pass
|
||||
eos.db.remove(wing)
|
||||
for fleetID in fleetIDs:
|
||||
fleet = eos.db.getFleet(fleetID)
|
||||
if fleet.leader is not None:
|
||||
try:
|
||||
fleet.leader.boostsFits.remove(fit.ID)
|
||||
except KeyError:
|
||||
pass
|
||||
eos.db.remove(fleet)
|
||||
fit.fleet = None
|
||||
return
|
||||
|
||||
def anyBoosters(self, squad):
|
||||
wing = squad.wing
|
||||
fleet = wing.gang
|
||||
if squad.leader is None and wing.leader is None and fleet.leader is None:
|
||||
return False
|
||||
return True
|
||||
|
||||
def loadLinearFleet(self, fit):
|
||||
if self.getLinearFleet(fit) is None:
|
||||
return None
|
||||
squadID = eos.db.getSquadsIDsWithFitID(fit.ID)[0]
|
||||
s = eos.db.getSquad(squadID)
|
||||
w = s.wing
|
||||
f = w.gang
|
||||
return (f.leader, w.leader, s.leader)
|
||||
# =============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# This file is part of pyfa.
|
||||
#
|
||||
# pyfa is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# pyfa is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
|
||||
# =============================================================================
|
||||
|
||||
import copy
|
||||
import eos.db
|
||||
from eos.saveddata.fleet import Fleet as Fleet_
|
||||
from eos.saveddata.fleet import Fleet as Wing
|
||||
from eos.saveddata.fleet import Fleet as Squad
|
||||
|
||||
|
||||
class Fleet(object):
|
||||
instance = None
|
||||
|
||||
@classmethod
|
||||
def getInstance(cls):
|
||||
if cls.instance is None:
|
||||
cls.instance = Fleet()
|
||||
|
||||
return cls.instance
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def getFleetList(self):
|
||||
fleetList = []
|
||||
fleets = eos.db.getFleetList()
|
||||
for fleet in fleets:
|
||||
fleetList.append((fleet.ID, fleet.name, fleet.count()))
|
||||
|
||||
return fleetList
|
||||
|
||||
def getFleetByID(self, ID):
|
||||
f = eos.db.getFleet(ID)
|
||||
return f
|
||||
|
||||
def addFleet(self):
|
||||
f = Fleet_()
|
||||
eos.db.save(f)
|
||||
return f
|
||||
|
||||
def renameFleet(self, fleet, newName):
|
||||
fleet.name = newName
|
||||
eos.db.commit()
|
||||
|
||||
def copyFleet(self, fleet):
|
||||
newFleet = copy.deepcopy(fleet)
|
||||
eos.db.save(newFleet)
|
||||
return newFleet
|
||||
|
||||
def copyFleetByID(self, ID):
|
||||
fleet = self.getFleetByID(ID)
|
||||
return self.copyFleet(fleet)
|
||||
|
||||
def deleteFleet(self, fleet):
|
||||
eos.db.remove(fleet)
|
||||
|
||||
def deleteFleetByID(self, ID):
|
||||
fleet = self.getFleetByID(ID)
|
||||
self.deleteFleet(fleet)
|
||||
|
||||
def makeLinearFleet(self, fit):
|
||||
f = Fleet_()
|
||||
w = Wing()
|
||||
f.wings.append(w)
|
||||
s = Squad()
|
||||
w.squads.append(s)
|
||||
s.members.append(fit)
|
||||
fit.fleet = f
|
||||
eos.db.save(f)
|
||||
|
||||
def setLinearFleetCom(self, boostee, booster):
|
||||
# if boostee == booster:
|
||||
# return
|
||||
if self.getLinearFleet(boostee) is None:
|
||||
self.removeAssociatedFleetData(boostee)
|
||||
self.makeLinearFleet(boostee)
|
||||
squadIDs = set(eos.db.getSquadsIDsWithFitID(boostee.ID))
|
||||
squad = eos.db.getSquad(squadIDs.pop())
|
||||
if squad.wing.gang.leader is not None and booster is None:
|
||||
try:
|
||||
squad.wing.gang.leader.boostsFits.remove(boostee.ID)
|
||||
except KeyError:
|
||||
pass
|
||||
squad.wing.gang.leader = booster
|
||||
if self.anyBoosters(squad) is False:
|
||||
self.removeAssociatedFleetData(boostee)
|
||||
from service.fit import Fit
|
||||
sFit = Fit.getInstance()
|
||||
sFit.recalc(boostee, withBoosters=True)
|
||||
|
||||
def setLinearWingCom(self, boostee, booster):
|
||||
# if boostee == booster:
|
||||
# return
|
||||
if self.getLinearFleet(boostee) is None:
|
||||
self.removeAssociatedFleetData(boostee)
|
||||
self.makeLinearFleet(boostee)
|
||||
squadIDs = set(eos.db.getSquadsIDsWithFitID(boostee.ID))
|
||||
squad = eos.db.getSquad(squadIDs.pop())
|
||||
if squad.wing.leader is not None and booster is None:
|
||||
try:
|
||||
squad.wing.leader.boostsFits.remove(boostee.ID)
|
||||
except KeyError:
|
||||
pass
|
||||
squad.wing.leader = booster
|
||||
if self.anyBoosters(squad) is False:
|
||||
self.removeAssociatedFleetData(boostee)
|
||||
from service.fit import Fit
|
||||
sFit = Fit.getInstance()
|
||||
sFit.recalc(boostee, withBoosters=True)
|
||||
|
||||
def setLinearSquadCom(self, boostee, booster):
|
||||
# if boostee == booster:
|
||||
# return
|
||||
if self.getLinearFleet(boostee) is None:
|
||||
self.removeAssociatedFleetData(boostee)
|
||||
self.makeLinearFleet(boostee)
|
||||
squadIDs = set(eos.db.getSquadsIDsWithFitID(boostee.ID))
|
||||
squad = eos.db.getSquad(squadIDs.pop())
|
||||
if squad.leader is not None and booster is None:
|
||||
try:
|
||||
squad.leader.boostsFits.remove(boostee.ID)
|
||||
except KeyError:
|
||||
pass
|
||||
squad.leader = booster
|
||||
if self.anyBoosters(squad) is False:
|
||||
self.removeAssociatedFleetData(boostee)
|
||||
from service.fit import Fit
|
||||
sFit = Fit.getInstance()
|
||||
sFit.recalc(boostee, withBoosters=True)
|
||||
|
||||
def getLinearFleet(self, fit):
|
||||
sqIDs = eos.db.getSquadsIDsWithFitID(fit.ID)
|
||||
if len(sqIDs) != 1:
|
||||
return None
|
||||
s = eos.db.getSquad(sqIDs[0])
|
||||
if len(s.members) != 1:
|
||||
return None
|
||||
w = s.wing
|
||||
if len(w.squads) != 1:
|
||||
return None
|
||||
f = w.gang
|
||||
if len(f.wings) != 1:
|
||||
return None
|
||||
return f
|
||||
|
||||
def removeAssociatedFleetData(self, fit):
|
||||
squadIDs = set(eos.db.getSquadsIDsWithFitID(fit.ID))
|
||||
if len(squadIDs) == 0:
|
||||
return
|
||||
squads = list(eos.db.getSquad(sqID) for sqID in squadIDs)
|
||||
wingIDs = set(squad.wing.ID for squad in squads)
|
||||
fleetIDs = set(squad.wing.gang.ID for squad in squads)
|
||||
for fleetID in fleetIDs:
|
||||
fleet = eos.db.getFleet(fleetID)
|
||||
for wing in fleet.wings:
|
||||
wingIDs.add(wing.ID)
|
||||
for wingID in wingIDs:
|
||||
wing = eos.db.getWing(wingID)
|
||||
for squad in wing.squads:
|
||||
squadIDs.add(squad.ID)
|
||||
for squadID in squadIDs:
|
||||
squad = eos.db.getSquad(squadID)
|
||||
if squad.leader is not None:
|
||||
try:
|
||||
squad.leader.boostsFits.remove(fit.ID)
|
||||
except KeyError:
|
||||
pass
|
||||
eos.db.remove(squad)
|
||||
for wingID in wingIDs:
|
||||
wing = eos.db.getWing(wingID)
|
||||
if wing.leader is not None:
|
||||
try:
|
||||
wing.leader.boostsFits.remove(fit.ID)
|
||||
except KeyError:
|
||||
pass
|
||||
eos.db.remove(wing)
|
||||
for fleetID in fleetIDs:
|
||||
fleet = eos.db.getFleet(fleetID)
|
||||
if fleet.leader is not None:
|
||||
try:
|
||||
fleet.leader.boostsFits.remove(fit.ID)
|
||||
except KeyError:
|
||||
pass
|
||||
eos.db.remove(fleet)
|
||||
fit.fleet = None
|
||||
return
|
||||
|
||||
def anyBoosters(self, squad):
|
||||
wing = squad.wing
|
||||
fleet = wing.gang
|
||||
if squad.leader is None and wing.leader is None and fleet.leader is None:
|
||||
return False
|
||||
return True
|
||||
|
||||
def loadLinearFleet(self, fit):
|
||||
if self.getLinearFleet(fit) is None:
|
||||
return None
|
||||
squadID = eos.db.getSquadsIDsWithFitID(fit.ID)[0]
|
||||
s = eos.db.getSquad(squadID)
|
||||
w = s.wing
|
||||
f = w.gang
|
||||
return (f.leader, w.leader, s.leader)
|
||||
|
||||
@@ -24,9 +24,11 @@ from service.market import Market
|
||||
from eos.saveddata.implant import Implant as es_Implant
|
||||
from eos.saveddata.implantSet import ImplantSet as es_ImplantSet
|
||||
|
||||
|
||||
class ImportError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ImplantSets(object):
|
||||
instance = None
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#===============================================================================
|
||||
# ===============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# This file is part of pyfa.
|
||||
@@ -15,7 +15,7 @@
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
|
||||
#===============================================================================
|
||||
# ===============================================================================
|
||||
|
||||
import re
|
||||
import threading
|
||||
@@ -43,6 +43,7 @@ logger = logging.getLogger(__name__)
|
||||
# Event which tells threads dependent on Market that it's initialized
|
||||
mktRdy = threading.Event()
|
||||
|
||||
|
||||
class ShipBrowserWorkerThread(threading.Thread):
|
||||
def run(self):
|
||||
self.queue = Queue.Queue()
|
||||
@@ -73,6 +74,7 @@ class ShipBrowserWorkerThread(threading.Thread):
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
class PriceWorkerThread(threading.Thread):
|
||||
def run(self):
|
||||
self.queue = Queue.Queue()
|
||||
@@ -107,6 +109,7 @@ class PriceWorkerThread(threading.Thread):
|
||||
self.wait[itemID] = []
|
||||
self.wait[itemID].append(callback)
|
||||
|
||||
|
||||
class SearchWorkerThread(threading.Thread):
|
||||
def run(self):
|
||||
self.cv = threading.Condition()
|
||||
@@ -131,7 +134,7 @@ class SearchWorkerThread(threading.Thread):
|
||||
elif filterOn: # filter by selected categories
|
||||
filter = e_Category.name.in_(filterOn)
|
||||
else:
|
||||
filter=None
|
||||
filter = None
|
||||
|
||||
results = eos.db.searchItems(request, where=filter,
|
||||
join=(e_Item.group, e_Group.category),
|
||||
@@ -150,15 +153,18 @@ class SearchWorkerThread(threading.Thread):
|
||||
self.cv.notify()
|
||||
self.cv.release()
|
||||
|
||||
|
||||
class Market():
|
||||
instance = None
|
||||
|
||||
def __init__(self):
|
||||
self.priceCache = {}
|
||||
|
||||
#Init recently used module storage
|
||||
# Init recently used module storage
|
||||
serviceMarketRecentlyUsedModules = {"pyfaMarketRecentlyUsedModules": []}
|
||||
|
||||
self.serviceMarketRecentlyUsedModules = SettingsProvider.getInstance().getSettings("pyfaMarketRecentlyUsedModules", serviceMarketRecentlyUsedModules)
|
||||
self.serviceMarketRecentlyUsedModules = SettingsProvider.getInstance().getSettings(
|
||||
"pyfaMarketRecentlyUsedModules", serviceMarketRecentlyUsedModules)
|
||||
|
||||
# Start price fetcher
|
||||
self.priceWorkerThread = PriceWorkerThread()
|
||||
@@ -188,36 +194,37 @@ class Market():
|
||||
self.les_grp.description = ""
|
||||
self.les_grp.icon = None
|
||||
self.ITEMS_FORCEGROUP = {
|
||||
"Opux Luxury Yacht": self.les_grp, # One of those is wedding present at CCP fanfest, another was hijacked from ISD guy during an event
|
||||
"Opux Luxury Yacht": self.les_grp,
|
||||
# One of those is wedding present at CCP fanfest, another was hijacked from ISD guy during an event
|
||||
"Silver Magnate": self.les_grp, # Amarr Championship prize
|
||||
"Gold Magnate": self.les_grp, # Amarr Championship prize
|
||||
"Armageddon Imperial Issue": self.les_grp, # Amarr Championship prize
|
||||
"Apocalypse Imperial Issue": self.les_grp, # Amarr Championship prize
|
||||
"Guardian-Vexor": self.les_grp, # Illegal rewards for the Gallente Frontier Tour Lines event arc
|
||||
"Megathron Federate Issue": self.les_grp, # Reward during Crielere event
|
||||
"Apocalypse Imperial Issue": self.les_grp, # Amarr Championship prize
|
||||
"Guardian-Vexor": self.les_grp, # Illegal rewards for the Gallente Frontier Tour Lines event arc
|
||||
"Megathron Federate Issue": self.les_grp, # Reward during Crielere event
|
||||
"Raven State Issue": self.les_grp, # AT4 prize
|
||||
"Tempest Tribal Issue": self.les_grp, # AT4 prize
|
||||
"Apotheosis": self.les_grp, # 5th EVE anniversary present
|
||||
"Zephyr": self.les_grp, # 2010 new year gift
|
||||
"Primae": self.les_grp, # Promotion of planetary interaction
|
||||
"Freki": self.les_grp, # AT7 prize
|
||||
"Mimir": self.les_grp, # AT7 prize
|
||||
"Utu": self.les_grp, # AT8 prize
|
||||
"Adrestia": self.les_grp, # AT8 prize
|
||||
"Echelon": self.les_grp, # 2011 new year gift
|
||||
"Malice": self.les_grp, # AT9 prize
|
||||
"Vangel": self.les_grp, # AT9 prize
|
||||
"Cambion": self.les_grp, # AT10 prize
|
||||
"Etana": self.les_grp, # AT10 prize
|
||||
"Chremoas": self.les_grp, # AT11 prize :(
|
||||
"Moracha": self.les_grp, # AT11 prize
|
||||
"Stratios Emergency Responder": self.les_grp, # Issued for Somer Blink lottery
|
||||
"Miasmos Quafe Ultra Edition": self.les_grp, # Gift to people who purchased FF HD stream
|
||||
"Tempest Tribal Issue": self.les_grp, # AT4 prize
|
||||
"Apotheosis": self.les_grp, # 5th EVE anniversary present
|
||||
"Zephyr": self.les_grp, # 2010 new year gift
|
||||
"Primae": self.les_grp, # Promotion of planetary interaction
|
||||
"Freki": self.les_grp, # AT7 prize
|
||||
"Mimir": self.les_grp, # AT7 prize
|
||||
"Utu": self.les_grp, # AT8 prize
|
||||
"Adrestia": self.les_grp, # AT8 prize
|
||||
"Echelon": self.les_grp, # 2011 new year gift
|
||||
"Malice": self.les_grp, # AT9 prize
|
||||
"Vangel": self.les_grp, # AT9 prize
|
||||
"Cambion": self.les_grp, # AT10 prize
|
||||
"Etana": self.les_grp, # AT10 prize
|
||||
"Chremoas": self.les_grp, # AT11 prize :(
|
||||
"Moracha": self.les_grp, # AT11 prize
|
||||
"Stratios Emergency Responder": self.les_grp, # Issued for Somer Blink lottery
|
||||
"Miasmos Quafe Ultra Edition": self.les_grp, # Gift to people who purchased FF HD stream
|
||||
"InterBus Shuttle": self.les_grp,
|
||||
"Leopard": self.les_grp, # 2013 new year gift
|
||||
"Whiptail": self.les_grp, # AT12 prize
|
||||
"Chameleon": self.les_grp, # AT12 prize
|
||||
"Victorieux Luxury Yacht": self.les_grp, # Worlds Collide prize \o/ chinese getting owned
|
||||
"Leopard": self.les_grp, # 2013 new year gift
|
||||
"Whiptail": self.les_grp, # AT12 prize
|
||||
"Chameleon": self.les_grp, # AT12 prize
|
||||
"Victorieux Luxury Yacht": self.les_grp, # Worlds Collide prize \o/ chinese getting owned
|
||||
"Imp": self.les_grp, # AT13 prize
|
||||
"Fiend": self.les_grp, # AT13 prize
|
||||
}
|
||||
@@ -228,8 +235,8 @@ class Market():
|
||||
|
||||
# List of items which are forcibly published or hidden
|
||||
self.ITEMS_FORCEPUBLISHED = {
|
||||
"Data Subverter I": False, # Not used in EVE, probably will appear with Dust link
|
||||
"QA Cross Protocol Analyzer": False, # QA modules used by CCP internally
|
||||
"Data Subverter I": False, # Not used in EVE, probably will appear with Dust link
|
||||
"QA Cross Protocol Analyzer": False, # QA modules used by CCP internally
|
||||
"QA Damage Module": False,
|
||||
"QA ECCM": False,
|
||||
"QA Immunity Module": False,
|
||||
@@ -265,7 +272,7 @@ class Market():
|
||||
|
||||
# List of groups which are forcibly published
|
||||
self.GROUPS_FORCEPUBLISHED = {
|
||||
"Prototype Exploration Ship": False } # We moved the only ship from this group to other group anyway
|
||||
"Prototype Exploration Ship": False} # We moved the only ship from this group to other group anyway
|
||||
|
||||
# Dictionary of items with forced meta groups, uses following format:
|
||||
# Item name: (metagroup name, parent type name)
|
||||
@@ -274,75 +281,96 @@ class Market():
|
||||
"'Wild' Miner I": ("Storyline", "Miner I"),
|
||||
"Medium Nano Armor Repair Unit I": ("Tech I", "Medium Armor Repairer I"),
|
||||
"Large 'Reprieve' Vestment Reconstructer I": ("Storyline", "Large Armor Repairer I"),
|
||||
"Khanid Navy Torpedo Launcher": ("Faction", "Torpedo Launcher I"),}
|
||||
"Khanid Navy Torpedo Launcher": ("Faction", "Torpedo Launcher I"), }
|
||||
# Parent type name: set(item names)
|
||||
self.ITEMS_FORCEDMETAGROUP_R = {}
|
||||
for item, value in self.ITEMS_FORCEDMETAGROUP.items():
|
||||
parent = value[1]
|
||||
if not parent in self.ITEMS_FORCEDMETAGROUP_R:
|
||||
if parent not in self.ITEMS_FORCEDMETAGROUP_R:
|
||||
self.ITEMS_FORCEDMETAGROUP_R[parent] = set()
|
||||
self.ITEMS_FORCEDMETAGROUP_R[parent].add(item)
|
||||
# Dictionary of items with forced market group (service assumes they have no
|
||||
# market group assigned in db, otherwise they'll appear in both original and forced groups)
|
||||
self.ITEMS_FORCEDMARKETGROUP = {
|
||||
"'Alpha' Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
|
||||
"'Codex' Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
|
||||
"'Daemon' Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
|
||||
"'Libram' Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
|
||||
"Advanced Cerebral Accelerator": 977, # Implants & Boosters > Booster
|
||||
"Civilian Damage Control": 615, # Ship Equipment > Hull & Armor > Damage Controls
|
||||
"Civilian EM Ward Field": 1695, # Ship Equipment > Shield > Shield Hardeners > EM Shield Hardeners
|
||||
"Civilian Explosive Deflection Field": 1694, # Ship Equipment > Shield > Shield Hardeners > Explosive Shield Hardeners
|
||||
"Civilian Hobgoblin": 837, # Drones > Combat Drones > Light Scout Drones
|
||||
"Civilian Kinetic Deflection Field": 1693, # Ship Equipment > Shield > Shield Hardeners > Kinetic Shield Hardeners
|
||||
"Civilian Light Missile Launcher": 640, # Ship Equipment > Turrets & Bays > Missile Launchers > Light Missile Launchers
|
||||
"Civilian Scourge Light Missile": 920, # Ammunition & Charges > Missiles > Light Missiles > Standard Light Missiles
|
||||
"Civilian Small Remote Armor Repairer": 1059, # Ship Equipment > Hull & Armor > Remote Armor Repairers > Small
|
||||
"Civilian Small Remote Shield Booster": 603, # Ship Equipment > Shield > Remote Shield Boosters > Small
|
||||
"Civilian Stasis Webifier": 683, # Ship Equipment > Electronic Warfare > Stasis Webifiers
|
||||
"Civilian Thermic Dissipation Field": 1692, # Ship Equipment > Shield > Shield Hardeners > Thermal Shield Hardeners
|
||||
"Civilian Warp Disruptor": 1935, # Ship Equipment > Electronic Warfare > Warp Disruptors
|
||||
"Hardwiring - Zainou 'Sharpshooter' ZMX10": 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
|
||||
"Hardwiring - Zainou 'Sharpshooter' ZMX100": 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
|
||||
"Hardwiring - Zainou 'Sharpshooter' ZMX1000": 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
|
||||
"Hardwiring - Zainou 'Sharpshooter' ZMX11": 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
|
||||
"Hardwiring - Zainou 'Sharpshooter' ZMX110": 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
|
||||
"Hardwiring - Zainou 'Sharpshooter' ZMX1100": 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
|
||||
"Nugoehuvi Synth Blue Pill Booster": 977, # Implants & Boosters > Booster
|
||||
"Prototype Cerebral Accelerator": 977, # Implants & Boosters > Booster
|
||||
"Prototype Iris Probe Launcher": 712, # Ship Equipment > Turrets & Bays > Scan Probe Launchers
|
||||
"Shadow": 1310, # Drones > Combat Drones > Fighter Bombers
|
||||
"Sleeper Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
|
||||
"Standard Cerebral Accelerator": 977, # Implants & Boosters > Booster
|
||||
"Talocan Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
|
||||
"Terran Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
|
||||
"Tetrimon Data Analyzer I": 714 # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
|
||||
"'Alpha' Data Analyzer I": 714,
|
||||
# Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
|
||||
"'Codex' Data Analyzer I": 714,
|
||||
# Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
|
||||
"'Daemon' Data Analyzer I": 714,
|
||||
# Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
|
||||
"'Libram' Data Analyzer I": 714,
|
||||
# Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
|
||||
"Advanced Cerebral Accelerator": 977, # Implants & Boosters > Booster
|
||||
"Civilian Damage Control": 615, # Ship Equipment > Hull & Armor > Damage Controls
|
||||
"Civilian EM Ward Field": 1695, # Ship Equipment > Shield > Shield Hardeners > EM Shield Hardeners
|
||||
"Civilian Explosive Deflection Field": 1694,
|
||||
# Ship Equipment > Shield > Shield Hardeners > Explosive Shield Hardeners
|
||||
"Civilian Hobgoblin": 837, # Drones > Combat Drones > Light Scout Drones
|
||||
"Civilian Kinetic Deflection Field": 1693,
|
||||
# Ship Equipment > Shield > Shield Hardeners > Kinetic Shield Hardeners
|
||||
"Civilian Light Missile Launcher": 640,
|
||||
# Ship Equipment > Turrets & Bays > Missile Launchers > Light Missile Launchers
|
||||
"Civilian Scourge Light Missile": 920,
|
||||
# Ammunition & Charges > Missiles > Light Missiles > Standard Light Missiles
|
||||
"Civilian Small Remote Armor Repairer": 1059,
|
||||
# Ship Equipment > Hull & Armor > Remote Armor Repairers > Small
|
||||
"Civilian Small Remote Shield Booster": 603, # Ship Equipment > Shield > Remote Shield Boosters > Small
|
||||
"Civilian Stasis Webifier": 683, # Ship Equipment > Electronic Warfare > Stasis Webifiers
|
||||
"Civilian Thermic Dissipation Field": 1692,
|
||||
# Ship Equipment > Shield > Shield Hardeners > Thermal Shield Hardeners
|
||||
"Civilian Warp Disruptor": 1935, # Ship Equipment > Electronic Warfare > Warp Disruptors
|
||||
"Hardwiring - Zainou 'Sharpshooter' ZMX10": 1493,
|
||||
# Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
|
||||
"Hardwiring - Zainou 'Sharpshooter' ZMX100": 1493,
|
||||
# Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
|
||||
"Hardwiring - Zainou 'Sharpshooter' ZMX1000": 1493,
|
||||
# Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
|
||||
"Hardwiring - Zainou 'Sharpshooter' ZMX11": 1493,
|
||||
# Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
|
||||
"Hardwiring - Zainou 'Sharpshooter' ZMX110": 1493,
|
||||
# Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
|
||||
"Hardwiring - Zainou 'Sharpshooter' ZMX1100": 1493,
|
||||
# Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
|
||||
"Nugoehuvi Synth Blue Pill Booster": 977, # Implants & Boosters > Booster
|
||||
"Prototype Cerebral Accelerator": 977, # Implants & Boosters > Booster
|
||||
"Prototype Iris Probe Launcher": 712, # Ship Equipment > Turrets & Bays > Scan Probe Launchers
|
||||
"Shadow": 1310, # Drones > Combat Drones > Fighter Bombers
|
||||
"Sleeper Data Analyzer I": 714,
|
||||
# Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
|
||||
"Standard Cerebral Accelerator": 977, # Implants & Boosters > Booster
|
||||
"Talocan Data Analyzer I": 714,
|
||||
# Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
|
||||
"Terran Data Analyzer I": 714,
|
||||
# Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
|
||||
"Tetrimon Data Analyzer I": 714
|
||||
# Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
|
||||
}
|
||||
|
||||
self.ITEMS_FORCEDMARKETGROUP_R = self.__makeRevDict(self.ITEMS_FORCEDMARKETGROUP)
|
||||
|
||||
self.FORCEDMARKETGROUP = {
|
||||
685: False, # Ship Equipment > Electronic Warfare > ECCM
|
||||
681: False, # Ship Equipment > Electronic Warfare > Sensor Backup Arrays
|
||||
685: False, # Ship Equipment > Electronic Warfare > ECCM
|
||||
681: False, # Ship Equipment > Electronic Warfare > Sensor Backup Arrays
|
||||
}
|
||||
|
||||
# Misc definitions
|
||||
# 0 is for items w/o meta group
|
||||
self.META_MAP = OrderedDict([("normal", frozenset((0, 1, 2, 14))),
|
||||
self.META_MAP = OrderedDict([("normal", frozenset((0, 1, 2, 14))),
|
||||
("faction", frozenset((4, 3))),
|
||||
("complex", frozenset((6,))),
|
||||
("officer", frozenset((5,)))])
|
||||
self.SEARCH_CATEGORIES = ("Drone", "Module", "Subsystem", "Charge", "Implant", "Deployable", "Fighter", "Structure", "Structure Module")
|
||||
self.SEARCH_CATEGORIES = (
|
||||
"Drone", "Module", "Subsystem", "Charge", "Implant", "Deployable", "Fighter", "Structure", "Structure Module")
|
||||
self.SEARCH_GROUPS = ("Ice Product",)
|
||||
self.ROOT_MARKET_GROUPS = (9, # Modules
|
||||
self.ROOT_MARKET_GROUPS = (9, # Modules
|
||||
1111, # Rigs
|
||||
157, # Drones
|
||||
11, # Ammo
|
||||
157, # Drones
|
||||
11, # Ammo
|
||||
1112, # Subsystems
|
||||
24, # Implants & Boosters
|
||||
404, # Deployables
|
||||
24, # Implants & Boosters
|
||||
404, # Deployables
|
||||
2202, # Structure Equipment
|
||||
2203 # Structure Modifications
|
||||
2203 # Structure Modifications
|
||||
)
|
||||
# Tell other threads that Market is at their service
|
||||
mktRdy.set()
|
||||
@@ -560,7 +588,8 @@ class Market():
|
||||
groupItems = set(group.items)
|
||||
if hasattr(group, 'addItems'):
|
||||
groupItems.update(group.addItems)
|
||||
items = set(filter(lambda item: self.getPublicityByItem(item) and self.getGroupByItem(item) == group, groupItems))
|
||||
items = set(
|
||||
filter(lambda item: self.getPublicityByItem(item) and self.getGroupByItem(item) == group, groupItems))
|
||||
return items
|
||||
|
||||
def getItemsByMarketGroup(self, mg, vars=True):
|
||||
|
||||
@@ -29,21 +29,27 @@ from service.settings import NetworkSettings
|
||||
timeout = 3
|
||||
socket.setdefaulttimeout(timeout)
|
||||
|
||||
|
||||
class Error(StandardError):
|
||||
def __init__(self, msg=None):
|
||||
self.message = msg
|
||||
|
||||
|
||||
class RequestError(StandardError):
|
||||
pass
|
||||
|
||||
|
||||
class AuthenticationError(StandardError):
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
class ServerError(StandardError):
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
class TimeoutError(StandardError):
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
class Network():
|
||||
# Request constants - every request must supply this, as it is checked if
|
||||
@@ -73,7 +79,8 @@ class Network():
|
||||
raise Error("Access not enabled - please enable in Preferences > Network")
|
||||
|
||||
# Set up some things for the request
|
||||
versionString = "{0} {1} - {2} {3}".format(config.version, config.tag, config.expansionName, config.expansionVersion)
|
||||
versionString = "{0} {1} - {2} {3}".format(config.version, config.tag, config.expansionName,
|
||||
config.expansionVersion)
|
||||
headers = {"User-Agent": "pyfa {0} (Python-urllib2)".format(versionString)}
|
||||
|
||||
proxy = NetworkSettings.getInstance().getProxySettings()
|
||||
|
||||
@@ -171,6 +171,7 @@ class Port(object):
|
||||
return fits
|
||||
|
||||
"""Service which houses all import/export format functions"""
|
||||
|
||||
@classmethod
|
||||
def exportCrest(cls, ofit, callback=None):
|
||||
# A few notes:
|
||||
@@ -379,6 +380,7 @@ class Port(object):
|
||||
if len(s) > 10:
|
||||
return s[:10] + "..."
|
||||
return s
|
||||
|
||||
logger.exception("Couldn't import ship data %r", [logtransform(s) for s in info])
|
||||
return None
|
||||
|
||||
@@ -821,7 +823,8 @@ class Port(object):
|
||||
slot = module.slot
|
||||
if slot not in stuff:
|
||||
stuff[slot] = []
|
||||
curr = module.item.name if module.item else ("[Empty %s slot]" % Slot.getName(slot).capitalize() if slot is not None else "")
|
||||
curr = module.item.name if module.item else (
|
||||
"[Empty %s slot]" % Slot.getName(slot).capitalize() if slot is not None else "")
|
||||
if module.charge and sFit.serviceFittingOptions["exportCharges"]:
|
||||
curr += ", %s" % module.charge.name
|
||||
if module.state == State.OFFLINE:
|
||||
@@ -1075,6 +1078,7 @@ class FitBackupThread(threading.Thread):
|
||||
# Send done signal to GUI
|
||||
wx.CallAfter(self.callback, -1)
|
||||
|
||||
|
||||
class FitImportThread(threading.Thread):
|
||||
def __init__(self, paths, callback):
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
@@ -1,70 +1,72 @@
|
||||
# =============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# This file is part of pyfa.
|
||||
#
|
||||
# pyfa is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# pyfa is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
|
||||
# =============================================================================
|
||||
|
||||
import threading
|
||||
import os
|
||||
|
||||
import config
|
||||
from eos import db
|
||||
from eos.db import migration
|
||||
from eos.db.saveddata.loadDefaultDatabaseValues import DefaultDatabaseValues
|
||||
from eos.saveddata.character import Character as es_Character
|
||||
|
||||
class PrefetchThread(threading.Thread):
|
||||
def run(self):
|
||||
# We're a daemon thread, as such, interpreter might get shut down while we do stuff
|
||||
# Make sure we don't throw tracebacks to console
|
||||
try:
|
||||
es_Character.setSkillList(db.getItemsByCategory("Skill", eager=("effects", "attributes", "attributes.info.icon", "attributes.info.unit", "icon")))
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
prefetch = PrefetchThread()
|
||||
prefetch.daemon = True
|
||||
prefetch.start()
|
||||
|
||||
# The following code does not belong here, however until we rebuild skeletons
|
||||
# to include modified pyfa.py, this is the best place to put it. See GH issue
|
||||
# #176
|
||||
# @ todo: move this to pyfa.py
|
||||
|
||||
# Make sure the saveddata db exists
|
||||
if config.savePath and not os.path.exists(config.savePath):
|
||||
os.mkdir(config.savePath)
|
||||
|
||||
if config.saveDB and os.path.isfile(config.saveDB):
|
||||
# If database exists, run migration after init'd database
|
||||
db.saveddata_meta.create_all()
|
||||
migration.update(db.saveddata_engine)
|
||||
# Import default database values
|
||||
# Import values that must exist otherwise Pyfa breaks
|
||||
DefaultDatabaseValues.importRequiredDefaults()
|
||||
elif config.saveDB:
|
||||
# If database does not exist, do not worry about migration. Simply
|
||||
# create and set version
|
||||
db.saveddata_meta.create_all()
|
||||
db.saveddata_engine.execute('PRAGMA user_version = {}'.format(migration.getAppVersion()))
|
||||
# Import default database values
|
||||
# Import values that must exist otherwise Pyfa breaks
|
||||
DefaultDatabaseValues.importRequiredDefaults()
|
||||
# Import default values for damage profiles
|
||||
DefaultDatabaseValues.importDamageProfileDefaults()
|
||||
# Import default values for target resist profiles
|
||||
DefaultDatabaseValues.importResistProfileDefaults()
|
||||
# =============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# This file is part of pyfa.
|
||||
#
|
||||
# pyfa is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# pyfa is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
|
||||
# =============================================================================
|
||||
|
||||
import threading
|
||||
import os
|
||||
|
||||
import config
|
||||
from eos import db
|
||||
from eos.db import migration
|
||||
from eos.db.saveddata.loadDefaultDatabaseValues import DefaultDatabaseValues
|
||||
from eos.saveddata.character import Character as es_Character
|
||||
|
||||
|
||||
class PrefetchThread(threading.Thread):
|
||||
def run(self):
|
||||
# We're a daemon thread, as such, interpreter might get shut down while we do stuff
|
||||
# Make sure we don't throw tracebacks to console
|
||||
try:
|
||||
es_Character.setSkillList(db.getItemsByCategory("Skill", eager=(
|
||||
"effects", "attributes", "attributes.info.icon", "attributes.info.unit", "icon")))
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
prefetch = PrefetchThread()
|
||||
prefetch.daemon = True
|
||||
prefetch.start()
|
||||
|
||||
# The following code does not belong here, however until we rebuild skeletons
|
||||
# to include modified pyfa.py, this is the best place to put it. See GH issue
|
||||
# #176
|
||||
# @ todo: move this to pyfa.py
|
||||
|
||||
# Make sure the saveddata db exists
|
||||
if config.savePath and not os.path.exists(config.savePath):
|
||||
os.mkdir(config.savePath)
|
||||
|
||||
if config.saveDB and os.path.isfile(config.saveDB):
|
||||
# If database exists, run migration after init'd database
|
||||
db.saveddata_meta.create_all()
|
||||
migration.update(db.saveddata_engine)
|
||||
# Import default database values
|
||||
# Import values that must exist otherwise Pyfa breaks
|
||||
DefaultDatabaseValues.importRequiredDefaults()
|
||||
elif config.saveDB:
|
||||
# If database does not exist, do not worry about migration. Simply
|
||||
# create and set version
|
||||
db.saveddata_meta.create_all()
|
||||
db.saveddata_engine.execute('PRAGMA user_version = {}'.format(migration.getAppVersion()))
|
||||
# Import default database values
|
||||
# Import values that must exist otherwise Pyfa breaks
|
||||
DefaultDatabaseValues.importRequiredDefaults()
|
||||
# Import default values for damage profiles
|
||||
DefaultDatabaseValues.importDamageProfileDefaults()
|
||||
# Import default values for target resist profiles
|
||||
DefaultDatabaseValues.importResistProfileDefaults()
|
||||
|
||||
@@ -22,7 +22,6 @@ try:
|
||||
except ImportError: # pragma: no cover
|
||||
import cPickle as pickle
|
||||
|
||||
|
||||
logger = logging.getLogger("pycrest.eve")
|
||||
cache_re = re.compile(r'max-age=([0-9]+)')
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ class WeakCiphersHTTPSConnection(urllib3.connection.VerifiedHTTPSConnection): #
|
||||
warnings.warn((
|
||||
'System time is way off (before {0}). This will probably '
|
||||
'lead to SSL verification errors').format(
|
||||
urllib3.connection.RECENT_DATE),
|
||||
urllib3.connection.RECENT_DATE),
|
||||
SystemTimeWarning
|
||||
)
|
||||
|
||||
@@ -103,13 +103,11 @@ class WeakCiphersHTTPSConnection(urllib3.connection.VerifiedHTTPSConnection): #
|
||||
|
||||
|
||||
class WeakCiphersHTTPSConnectionPool(
|
||||
urllib3.connectionpool.HTTPSConnectionPool):
|
||||
|
||||
urllib3.connectionpool.HTTPSConnectionPool):
|
||||
ConnectionCls = WeakCiphersHTTPSConnection
|
||||
|
||||
|
||||
class WeakCiphersPoolManager(urllib3.poolmanager.PoolManager):
|
||||
|
||||
def _new_pool(self, scheme, host, port):
|
||||
if scheme == 'https':
|
||||
return WeakCiphersHTTPSConnectionPool(host, port, **(self.connection_pool_kw))
|
||||
|
||||
@@ -77,7 +77,6 @@ class AuthHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
|
||||
# http://code.activestate.com/recipes/425210-simple-stoppable-server-using-socket-timeout/
|
||||
class StoppableHTTPServer(BaseHTTPServer.HTTPServer):
|
||||
|
||||
def server_bind(self):
|
||||
BaseHTTPServer.HTTPServer.server_bind(self)
|
||||
self.settings = CRESTSettings.getInstance()
|
||||
|
||||
@@ -119,9 +119,9 @@ class NetworkSettings(object):
|
||||
_instance = None
|
||||
|
||||
# constants for serviceNetworkDefaultSettings["mode"] parameter
|
||||
PROXY_MODE_NONE = 0 # 0 - No proxy
|
||||
PROXY_MODE_NONE = 0 # 0 - No proxy
|
||||
PROXY_MODE_AUTODETECT = 1 # 1 - Auto-detected proxy settings
|
||||
PROXY_MODE_MANUAL = 2 # 2 - Manual proxy settings
|
||||
PROXY_MODE_MANUAL = 2 # 2 - Manual proxy settings
|
||||
|
||||
@classmethod
|
||||
def getInstance(cls):
|
||||
@@ -254,8 +254,15 @@ class HTMLExportSettings(object):
|
||||
return cls._instance
|
||||
|
||||
def __init__(self):
|
||||
serviceHTMLExportDefaultSettings = {"enabled": False, "path": config.pyfaPath + os.sep + 'pyfaFits.html', "minimal": False}
|
||||
self.serviceHTMLExportSettings = SettingsProvider.getInstance().getSettings("pyfaServiceHTMLExportSettings", serviceHTMLExportDefaultSettings)
|
||||
serviceHTMLExportDefaultSettings = {
|
||||
"enabled": False,
|
||||
"path": config.pyfaPath + os.sep + 'pyfaFits.html',
|
||||
"minimal": False
|
||||
}
|
||||
self.serviceHTMLExportSettings = SettingsProvider.getInstance().getSettings(
|
||||
"pyfaServiceHTMLExportSettings",
|
||||
serviceHTMLExportDefaultSettings
|
||||
)
|
||||
|
||||
def getEnabled(self):
|
||||
return self.serviceHTMLExportSettings["enabled"]
|
||||
@@ -295,7 +302,10 @@ class UpdateSettings(object):
|
||||
# prerelease - If True, suppress prerelease notifications
|
||||
# version - Set to release tag that user does not want notifications for
|
||||
serviceUpdateDefaultSettings = {"prerelease": True, 'version': None}
|
||||
self.serviceUpdateSettings = SettingsProvider.getInstance().getSettings("pyfaServiceUpdateSettings", serviceUpdateDefaultSettings)
|
||||
self.serviceUpdateSettings = SettingsProvider.getInstance().getSettings(
|
||||
"pyfaServiceUpdateSettings",
|
||||
serviceUpdateDefaultSettings
|
||||
)
|
||||
|
||||
def get(self, type):
|
||||
return self.serviceUpdateSettings[type]
|
||||
@@ -315,13 +325,15 @@ class CRESTSettings(object):
|
||||
return cls._instance
|
||||
|
||||
def __init__(self):
|
||||
|
||||
# mode
|
||||
# 0 - Implicit authentication
|
||||
# 1 - User-supplied client details
|
||||
serviceCRESTDefaultSettings = {"mode": 0, "server": 0, "clientID": "", "clientSecret": "", "timeout": 60}
|
||||
|
||||
self.serviceCRESTSettings = SettingsProvider.getInstance().getSettings("pyfaServiceCRESTSettings", serviceCRESTDefaultSettings)
|
||||
self.serviceCRESTSettings = SettingsProvider.getInstance().getSettings(
|
||||
"pyfaServiceCRESTSettings",
|
||||
serviceCRESTDefaultSettings
|
||||
)
|
||||
|
||||
def get(self, type):
|
||||
return self.serviceCRESTSettings[type]
|
||||
@@ -329,5 +341,4 @@ class CRESTSettings(object):
|
||||
def set(self, type, value):
|
||||
self.serviceCRESTSettings[type] = value
|
||||
|
||||
|
||||
# @todo: migrate fit settings (from fit service) here?
|
||||
|
||||
@@ -24,10 +24,12 @@ from eos.saveddata.targetResists import TargetResists as es_TargetResists
|
||||
|
||||
|
||||
class ImportError(Exception):
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
class TargetResists(object):
|
||||
instance = None
|
||||
|
||||
@classmethod
|
||||
def getInstance(cls):
|
||||
if cls.instance is None:
|
||||
|
||||
@@ -42,7 +42,10 @@ class CheckUpdateThread(threading.Thread):
|
||||
try:
|
||||
response = network.request('https://api.github.com/repos/pyfa-org/Pyfa/releases', network.UPDATE)
|
||||
jsonResponse = json.loads(response.read())
|
||||
jsonResponse.sort(key=lambda x: calendar.timegm(dateutil.parser.parse(x['published_at']).utctimetuple()), reverse=True)
|
||||
jsonResponse.sort(
|
||||
key=lambda x: calendar.timegm(dateutil.parser.parse(x['published_at']).utctimetuple()),
|
||||
reverse=True
|
||||
)
|
||||
|
||||
for release in jsonResponse:
|
||||
# Suppress pre releases
|
||||
@@ -63,7 +66,9 @@ class CheckUpdateThread(threading.Thread):
|
||||
else:
|
||||
rVersion = release['tag_name'].replace('v', '', 1)
|
||||
|
||||
if config.tag is 'git' and not release['prerelease'] and self.versiontuple(rVersion) >= self.versiontuple(config.version):
|
||||
if config.tag is 'git' and \
|
||||
not release['prerelease'] and \
|
||||
self.versiontuple(rVersion) >= self.versiontuple(config.version):
|
||||
wx.CallAfter(self.callback, release) # git (dev/Singularity) -> Stable
|
||||
elif config.expansionName is not "Singularity":
|
||||
if release['prerelease']:
|
||||
|
||||
2
tox.ini
2
tox.ini
@@ -12,4 +12,4 @@ commands = py.test -vv --cov Pyfa tests/
|
||||
|
||||
[testenv:pep8]
|
||||
deps = flake8
|
||||
commands = flake8 --exclude=.svn,CVS,.bzr,.hg,.git,__pycache__,venv,tests,.tox,build,dist,__init__.py --ignore=E501,E731 gui_service gui eos utils config.py pyfa.py
|
||||
commands = flake8 --exclude=.svn,CVS,.bzr,.hg,.git,__pycache__,venv,tests,.tox,build,dist,__init__.py --ignore=E501,E731 service gui eos utils config.py pyfa.py
|
||||
|
||||
Reference in New Issue
Block a user