Merge branch 'overrides' into singularity

Conflicts:
	eos/db/__init__.py
	eos/db/saveddata/__init__.py
	eos/db/saveddata/queries.py
	gui/mainFrame.py
	gui/mainMenuBar.py
This commit is contained in:
blitzmann
2015-11-02 19:01:12 -05:00
22 changed files with 505 additions and 27 deletions

View File

@@ -68,14 +68,8 @@ from eos.db.gamedata import *
from eos.db.saveddata import *
#Import queries
from eos.db.gamedata.queries import getItem, searchItems, getVariations, getItemsByCategory, directAttributeRequest, \
getMarketGroup, getGroup, getCategory, getAttributeInfo, getMetaData, getMetaGroup
from eos.db.saveddata.queries import getUser, getCharacter, getFit, getFitsWithShip, countFitsWithShip, searchFits, \
getCharacterList, getPrice, getDamagePatternList, getDamagePattern, \
getFitList, getFleetList, getFleet, save, remove, commit, add, \
getCharactersForUser, getMiscData, getSquadsIDsWithFitID, getWing, \
getSquad, getBoosterFits, getProjectedFits, getTargetResistsList, getTargetResists,\
clearPrices, countAllFits, getCrestCharacters, getCrestCharacter
from eos.db.gamedata.queries import *
from eos.db.saveddata.queries import *
#If using in memory saveddata, you'll want to reflect it so the data structure is good.
if config.saveddata_connectionstring == "sqlite:///:memory:":

View File

@@ -1,3 +1,18 @@
__all__ = ["character", "fit", "module", "user", "crest", "skill", "price",
"booster", "drone", "implant", "fleet", "damagePattern",
"miscData", "targetResists"]
__all__ = [
"character",
"fit",
"module",
"user",
"skill",
"price",
"booster",
"drone",
"implant",
"fleet",
"damagePattern",
"miscData",
"targetResists",
"override",
"crest"
]

View File

@@ -0,0 +1,31 @@
#===============================================================================
# Copyright (C) 2010 Diego Duclos
#
# This file is part of eos.
#
# eos is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# eos 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with eos. If not, see <http://www.gnu.org/licenses/>.
#===============================================================================
from sqlalchemy import Table, Column, Integer, Float
from sqlalchemy.orm import mapper
from eos.db import saveddata_meta
from eos.types import Override
overrides_table = Table("overrides", saveddata_meta,
Column("itemID", Integer, primary_key=True, index = True),
Column("attrID", Integer, primary_key=True, index = True),
Column("value", Float, nullable = False))
mapper(Override, overrides_table)

View File

@@ -19,7 +19,8 @@
from eos.db.util import processEager, processWhere
from eos.db import saveddata_session, sd_lock
from eos.types import User, Character, Fit, Price, DamagePattern, Fleet, MiscData, Wing, Squad, TargetResists, CrestChar
from eos.types import User, Character, Fit, Price, DamagePattern, Fleet, MiscData, Wing, Squad, TargetResists, Override, CrestChar
from eos.db.saveddata.fleet import squadmembers_table
from eos.db.saveddata.fit import projectedFits_table
from sqlalchemy.sql import and_
@@ -182,7 +183,7 @@ def getFit(lookfor, eager=None):
else:
eager = processEager(eager)
with sd_lock:
fit = saveddata_session.query(Fit).options(*eager).filter(Fit.ID == fitID).first()
fit = saveddata_session.query(Fit).options(*eager).filter(Fit.ID == lookfor).first()
else:
raise TypeError("Need integer as argument")
@@ -440,6 +441,21 @@ def getCrestCharacter(lookfor, eager=None):
raise TypeError("Need integer or string as argument")
return character
def getOverrides(itemID, eager=None):
if isinstance(itemID, int):
return saveddata_session.query(Override).filter(Override.itemID == itemID).all()
else:
raise TypeError("Need integer as argument")
def clearOverrides():
with sd_lock:
deleted_rows = saveddata_session.query(Override).delete()
commit()
return deleted_rows
def getAllOverrides(eager=None):
return saveddata_session.query(Override).all()
def removeInvalid(fits):
invalids = [f for f in fits if f.isInvalid]

View File

@@ -24,6 +24,7 @@ from sqlalchemy.orm import reconstructor
from eqBase import EqBase
import traceback
import eos.db
try:
from collections import OrderedDict
@@ -168,7 +169,6 @@ class Item(EqBase):
info = getattr(cls, "MOVE_ATTR_INFO", None)
if info is None:
cls.MOVE_ATTR_INFO = info = []
import eos.db
for id in cls.MOVE_ATTRS:
info.append(eos.db.getAttributeInfo(id))
@@ -191,6 +191,7 @@ class Item(EqBase):
self.__moved = False
self.__offensive = None
self.__assistive = None
self.__overrides = None
@property
def attributes(self):
@@ -210,6 +211,32 @@ class Item(EqBase):
return False
@property
def overrides(self):
if self.__overrides is None:
self.__overrides = {}
overrides = eos.db.getOverrides(self.ID)
for x in overrides:
if x.attr.name in self.__attributes:
self.__overrides[x.attr.name] = x
return self.__overrides
def setOverride(self, attr, value):
from eos.saveddata.override import Override
if attr.name in self.__overrides:
override = self.__overrides.get(attr.name)
override.value = value
else:
override = Override(self, attr, value)
self.__overrides[attr.name] = override
eos.db.save(override)
def deleteOverride(self, attr):
override = self.__overrides.pop(attr.name, None)
eos.db.saveddata_session.delete(override)
eos.db.commit()
@property
def requiredSkills(self):
if self.__requiredSkills is None:
@@ -345,6 +372,12 @@ class Item(EqBase):
return False
def __repr__(self):
return "Item(ID={}, name={}) at {}".format(
self.ID, self.name, hex(id(self))
)
class MetaData(EqBase):
pass

View File

@@ -38,6 +38,9 @@ class ChargeAttrShortcut(object):
return None
class ModifiedAttributeDict(collections.MutableMapping):
OVERRIDES = False
class CalculationPlaceholder():
pass
@@ -51,6 +54,8 @@ class ModifiedAttributeDict(collections.MutableMapping):
self.__modified = {}
# Affected by entities
self.__affectedBy = {}
# Overrides
self.__overrides = {}
# Dictionaries for various value modification types
self.__forced = {}
self.__preAssigns = {}
@@ -79,6 +84,14 @@ class ModifiedAttributeDict(collections.MutableMapping):
self.__original = val
self.__modified.clear()
@property
def overrides(self):
return self.__overrides
@overrides.setter
def overrides(self, val):
self.__overrides = val
def __getitem__(self, key):
# Check if we have final calculated value
if key in self.__modified:
@@ -99,6 +112,8 @@ class ModifiedAttributeDict(collections.MutableMapping):
del self.__intermediary[key]
def getOriginal(self, key):
if self.OVERRIDES and key in self.__overrides:
return self.__overrides.get(key).value
val = self.__original.get(key)
if val is None:
return None

View File

@@ -58,6 +58,7 @@ class Booster(HandledItem, ItemAttrShortcut):
self.__sideEffects = []
self.__itemModifiedAttributes = ModifiedAttributeDict()
self.__itemModifiedAttributes.original = self.__item.attributes
self.__itemModifiedAttributes.overrides = self.__item.overrides
self.__slot = self.__calculateSlot(self.__item)
for effect in self.__item.effects.itervalues():

View File

@@ -34,6 +34,7 @@ class Cargo(HandledItem, ItemAttrShortcut):
self.amount = 0
self.__itemModifiedAttributes = ModifiedAttributeDict()
self.__itemModifiedAttributes.original = item.attributes
self.__itemModifiedAttributes.overrides = item.overrides
@reconstructor
def init(self):
@@ -48,6 +49,7 @@ class Cargo(HandledItem, ItemAttrShortcut):
self.__itemModifiedAttributes = ModifiedAttributeDict()
self.__itemModifiedAttributes.original = self.__item.attributes
self.__itemModifiedAttributes.overrides = self.__item.overrides
@property
def itemModifiedAttributes(self):

View File

@@ -67,6 +67,7 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
self.__miningyield = None
self.__itemModifiedAttributes = ModifiedAttributeDict()
self.__itemModifiedAttributes.original = self.__item.attributes
self.__itemModifiedAttributes.overrides = self.__item.overrides
self.__chargeModifiedAttributes = ModifiedAttributeDict()
chargeID = self.getModifiedItemAttr("entityMissileTypeID")
@@ -74,6 +75,7 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
charge = eos.db.getItem(int(chargeID))
self.__charge = charge
self.__chargeModifiedAttributes.original = charge.attributes
self.__chargeModifiedAttributes.overrides = charge.overrides
@property
def itemModifiedAttributes(self):

View File

@@ -56,6 +56,7 @@ class Implant(HandledItem, ItemAttrShortcut):
""" Build object. Assumes proper and valid item already set """
self.__itemModifiedAttributes = ModifiedAttributeDict()
self.__itemModifiedAttributes.original = self.__item.attributes
self.__itemModifiedAttributes.overrides = self.__item.overrides
self.__slot = self.__calculateSlot(self.__item)
@property

View File

@@ -30,6 +30,7 @@ class Mode(ItemAttrShortcut, HandledItem):
self.__item = item
self.__itemModifiedAttributes = ModifiedAttributeDict()
self.__itemModifiedAttributes.original = self.item.attributes
self.__itemModifiedAttributes.overrides = self.item.overrides
@property
def item(self):

View File

@@ -113,10 +113,13 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
if self.__item:
self.__itemModifiedAttributes.original = self.__item.attributes
self.__itemModifiedAttributes.overrides = self.__item.overrides
self.__hardpoint = self.__calculateHardpoint(self.__item)
self.__slot = self.__calculateSlot(self.__item)
if self.__charge:
self.__chargeModifiedAttributes.original = self.__charge.attributes
self.__chargeModifiedAttributes.overrides = self.__charge.overrides
@classmethod
def buildEmpty(cls, slot):
@@ -283,9 +286,11 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
if charge is not None:
self.chargeID = charge.ID
self.__chargeModifiedAttributes.original = charge.attributes
self.__chargeModifiedAttributes.overrides = charge.overrides
else:
self.chargeID = None
self.__chargeModifiedAttributes.original = None
self.__chargeModifiedAttributes.overrides = {}
self.__itemModifiedAttributes.clear()

59
eos/saveddata/override.py Normal file
View File

@@ -0,0 +1,59 @@
#===============================================================================
# Copyright (C) 2015 Ryan Holmes
#
# This file is part of eos.
#
# eos is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# eos 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with eos. If not, see <http://www.gnu.org/licenses/>.
#===============================================================================
from eos.eqBase import EqBase
from sqlalchemy.orm import validates, reconstructor
import eos.db
import logging
logger = logging.getLogger(__name__)
class Override(EqBase):
def __init__(self, item, attr, value):
self.itemID = item.ID
self.__item = item
self.attrID = attr.ID
self.__attr = attr
self.value = value
@reconstructor
def init(self):
self.__attr = None
self.__item = None
if self.attrID:
self.__attr = eos.db.getAttributeInfo(self.attrID)
if self.__attr is None:
logger.error("Attribute (id: %d) does not exist", self.attrID)
return
if self.itemID:
self.__item = eos.db.getItem(self.itemID)
if self.__item is None:
logger.error("Item (id: %d) does not exist", self.itemID)
return
@property
def attr(self):
return self.__attr
@property
def item(self):
return self.__item

View File

@@ -51,6 +51,7 @@ class Ship(ItemAttrShortcut, HandledItem):
self.__itemModifiedAttributes = ModifiedAttributeDict()
self.__itemModifiedAttributes.original = dict(self.item.attributes)
self.__itemModifiedAttributes.original.update(self.EXTRA_ATTRIBUTES)
self.__itemModifiedAttributes.overrides = self.item.overrides
self.commandBonus = 0

View File

@@ -36,4 +36,5 @@ from eos.saveddata.fit import Fit
from eos.saveddata.mode import Mode
from eos.saveddata.fleet import Fleet, Wing, Squad
from eos.saveddata.miscData import MiscData
from eos.saveddata.override import Override
import eos.db

View File

@@ -11,7 +11,7 @@ TextTyped, EVT_TEXT = wx.lib.newevent.NewEvent()
class PFSearchBox(wx.Window):
def __init__(self, parent, id = wx.ID_ANY, value = "", pos = wx.DefaultPosition, size = wx.Size(-1,24), style = 0):
wx.Window.__init__(self, parent, id, pos, size, style = 0)
wx.Window.__init__(self, parent, id, pos, size, style = style)
self.isSearchButtonVisible = False
self.isCancelButtonVisible = False

View File

@@ -35,9 +35,6 @@ class CharacterEditor(wx.Frame):
size=wx.Size(641, 600), style=wx.DEFAULT_FRAME_STYLE|wx.FRAME_FLOAT_ON_PARENT|wx.TAB_TRAVERSAL)
i = wx.IconFromBitmap(BitmapLoader.getBitmap("character_small", "gui"))
self.mainFrame = parent
self.SetIcon(i)
self.disableWin= wx.WindowDisabler(self)

View File

@@ -55,7 +55,12 @@ from gui.copySelectDialog import CopySelectDialog
from gui.utils.clipboard import toClipboard, fromClipboard
from gui.fleetBrowser import FleetBrowser
from gui.updateDialog import UpdateDialog
from gui.propertyEditor import AttributeEditor
from gui.builtinViews import *
# import this to access override setting
from eos.modifiedAttributeDict import ModifiedAttributeDict
from time import gmtime, strftime
from service.crest import CrestModes
@@ -340,6 +345,10 @@ class MainFrame(wx.Frame):
dlg=CharacterEditor(self)
dlg.Show()
def showAttrEditor(self, event):
dlg=AttributeEditor(self)
dlg.Show()
def showTargetResistsEditor(self, event):
dlg=ResistsEditorDlg(self)
dlg.ShowModal()
@@ -427,6 +436,7 @@ class MainFrame(wx.Frame):
self.Bind(wx.EVT_MENU, self.saveCharAs, id = menuBar.saveCharAsId)
# Save current character
self.Bind(wx.EVT_MENU, self.revertChar, id = menuBar.revertCharId)
# Browse fittings
self.Bind(wx.EVT_MENU, self.eveFittings, id = menuBar.eveFittingsId)
# Export to EVE
@@ -434,6 +444,11 @@ class MainFrame(wx.Frame):
# Login to EVE
self.Bind(wx.EVT_MENU, self.ssoLogin, id = menuBar.ssoLoginId)
# Open attribute editor
self.Bind(wx.EVT_MENU, self.showAttrEditor, id = menuBar.attrEditorId)
# Toggle Overrides
self.Bind(wx.EVT_MENU, self.toggleOverrides, id = menuBar.toggleOverridesId)
#Clipboard exports
self.Bind(wx.EVT_MENU, self.exportToClipboard, id=wx.ID_COPY)
@@ -534,6 +549,12 @@ class MainFrame(wx.Frame):
dlg=ExportToEve(self)
dlg.Show()
def toggleOverrides(self, event):
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")
def saveChar(self, event):
sChr = service.Character.getInstance()
charID = self.charSelection.getActiveCharacter()

View File

@@ -47,6 +47,8 @@ class MainMenuBar(wx.MenuBar):
self.eveFittingsId = wx.NewId()
self.exportToEveId = wx.NewId()
self.ssoLoginId = wx.NewId()
self.attrEditorId = wx.NewId()
self.toggleOverridesId = wx.NewId()
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
@@ -87,6 +89,9 @@ class MainMenuBar(wx.MenuBar):
editMenu.Append(self.saveCharId, "Save Character")
editMenu.Append(self.saveCharAsId, "Save Character As...")
editMenu.Append(self.revertCharId, "Revert Character")
editMenu.AppendSeparator()
editMenu.Append(self.toggleOverridesId, "Turn Overrides On")
# Character menu
windowMenu = wx.Menu()
self.Append(windowMenu, "&Window")
@@ -125,6 +130,10 @@ class MainMenuBar(wx.MenuBar):
self.Enable(self.eveFittingsId, False)
self.Enable(self.exportToEveId, False)
attrItem = wx.MenuItem(windowMenu, self.attrEditorId, "Attribute Overrides\tCTRL+A")
attrItem.SetBitmap(BitmapLoader.getBitmap("fit_rename_small", "gui"))
windowMenu.AppendItem(attrItem)
# Help menu
helpMenu = wx.Menu()
self.Append(helpMenu, "&Help")

View File

@@ -103,8 +103,8 @@ class MarketBrowser(wx.Panel):
self.marketView.jump(item)
class SearchBox(SBox.PFSearchBox):
def __init__(self, parent):
SBox.PFSearchBox.__init__(self, parent)
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)

264
gui/propertyEditor.py Normal file
View File

@@ -0,0 +1,264 @@
import wx
import wx.propgrid as wxpg
import gui.PFSearchBox as SBox
from gui.marketBrowser import SearchBox
import gui.display as d
import gui.globalEvents as GE
from gui.bitmapLoader import BitmapLoader
import service
import csv
import eos.db
import logging
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)
i = wx.IconFromBitmap(BitmapLoader.getBitmap("fit_rename_small", "gui"))
self.SetIcon(i)
self.mainFrame = parent
menubar = wx.MenuBar()
fileMenu = wx.Menu()
fileImport = fileMenu.Append(wx.ID_ANY, 'Import', 'Import overrides')
fileExport = fileMenu.Append(wx.ID_ANY, 'Export', 'Import overrides')
fileClear = fileMenu.Append(wx.ID_ANY, 'Clear All', 'Clear all overrides')
menubar.Append(fileMenu, '&File')
self.SetMenuBar(menubar)
self.Bind(wx.EVT_MENU, self.OnImport, fileImport)
self.Bind(wx.EVT_MENU, self.OnExport, fileExport)
self.Bind(wx.EVT_MENU, self.OnClear, fileClear)
i = wx.IconFromBitmap(BitmapLoader.getBitmap("fit_rename_small", "gui"))
self.SetIcon(i)
self.mainFrame = parent
self.panel = panel = wx.Panel(self, wx.ID_ANY)
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)
self.searchBox = SearchBox(leftPanel)
self.itemView = ItemView(leftPanel)
leftSizer.Add(self.searchBox, 0, wx.EXPAND)
leftSizer.Add(self.itemView, 1, wx.EXPAND)
leftPanel.SetSizer(leftSizer)
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.pg = AttributeGrid(panel)
rightSizer.Add(self.pg, 1, wx.ALL|wx.EXPAND, 5)
rightSizer.Add(self.btnRemoveOverrides, 0, wx.ALL | wx.EXPAND, 5 )
self.btnRemoveOverrides.Bind(wx.EVT_BUTTON, self.pg.removeOverrides)
self.btnRemoveOverrides.Enable(False)
mainSizer.Add(rightSizer, 1, wx.EXPAND)
panel.SetSizer(mainSizer)
mainSizer.SetSizeHints(panel)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(panel, 1, wx.EXPAND)
self.SetSizer(sizer)
self.SetAutoLayout(True)
self.Bind(wx.EVT_CLOSE, self.OnClose)
def OnClose(self, event):
fitID = self.mainFrame.getActiveFit()
if fitID is not None:
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
self.Destroy()
def OnImport(self, event):
dlg = wx.FileDialog(self, "Import pyfa override file",
wildcard = "pyfa override file (*.csv)|*.csv",
style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
if (dlg.ShowModal() == wx.ID_OK):
path = dlg.GetPath()
with open(path, 'rb') as csvfile:
spamreader = csv.reader(csvfile)
for row in spamreader:
itemID, attrID, value = row
item = eos.db.getItem(int(itemID))
attr = eos.db.getAttributeInfo(int(attrID))
item.setOverride(attr, float(value))
self.itemView.updateItems(True)
def OnExport(self, event):
sMkt = service.Market.getInstance()
items = sMkt.getItemsWithOverrides()
defaultFile = "pyfa_overrides.csv"
dlg = wx.FileDialog(self, "Save Overrides As...",
wildcard = "pyfa overrides (*.csv)|*.csv",
style = wx.FD_SAVE,
defaultFile=defaultFile)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
with open(path, 'wb') as csvfile:
writer = csv.writer(csvfile)
for item in items:
for key, override in item.overrides.iteritems():
writer.writerow([item.ID, override.attrID, override.value])
def OnClear(self, event):
dlg = wx.MessageDialog(self,
"Are you sure you want to delete all overrides?",
"Confirm Delete", wx.YES | wx.NO | wx.ICON_EXCLAMATION)
if dlg.ShowModal() == wx.ID_YES:
sMkt = service.Market.getInstance()
items = sMkt.getItemsWithOverrides()
# We can't just delete overrides, as loaded items will still have
# them assigned. Deleting them from the database won't propagate
# them due to the eve/user database disconnect. We must loop through
# all items that have overrides and remove them
for item in items:
for _, x in item.overrides.items():
item.deleteOverride(x.attr)
self.itemView.updateItems(True)
self.pg.Clear()
# This is literally a stripped down version of the market.
class ItemView(d.Display):
DEFAULT_COLS = ["Base Icon",
"Base Name",
"attr:power,,,True",
"attr:cpu,,,True"]
def __init__(self, parent):
d.Display.__init__(self, parent)
sMkt = service.Market.getInstance()
self.things = sMkt.getItemsWithOverrides()
self.items = self.things
self.searchBox = parent.Parent.Parent.searchBox
# Bind search actions
self.searchBox.Bind(SBox.EVT_TEXT_ENTER, self.scheduleSearch)
self.searchBox.Bind(SBox.EVT_SEARCH_BTN, self.scheduleSearch)
self.searchBox.Bind(SBox.EVT_CANCEL_BTN, self.clearSearch)
self.searchBox.Bind(SBox.EVT_TEXT, self.scheduleSearch)
self.update(self.items)
def clearSearch(self, event=None):
if event:
self.searchBox.Clear()
self.items = self.things
self.update(self.items)
def updateItems(self, updateDisplay=False):
sMkt = service.Market.getInstance()
self.things = sMkt.getItemsWithOverrides()
self.items = self.things
if updateDisplay:
self.update(self.things)
def scheduleSearch(self, event=None):
sMkt = service.Market.getInstance()
search = self.searchBox.GetLineText(0)
# Make sure we do not count wildcard as search symbol
realsearch = search.replace("*", "")
# Show nothing if query is too short
if len(realsearch) < 3:
self.clearSearch()
return
sMkt.searchItems(search, self.populateSearch, False)
def populateSearch(self, items):
self.items = list(items)
self.update(items)
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)
self.SetExtraStyle(wxpg.PG_EX_HELP_AS_TOOLTIPS)
self.item = None
self.itemView = parent.Parent.itemView
self.btn = parent.Parent.btnRemoveOverrides
self.Bind( wxpg.EVT_PG_CHANGED, self.OnPropGridChange )
self.Bind( wxpg.EVT_PG_SELECTED, self.OnPropGridSelect )
self.Bind( wxpg.EVT_PG_RIGHT_CLICK, self.OnPropGridRightClick )
self.itemView.Bind(wx.EVT_LIST_ITEM_SELECTED, self.itemActivated)
self.itemView.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.itemActivated)
def itemActivated(self, event):
self.Clear()
self.btn.Enable(True)
sel = event.EventObject.GetFirstSelected()
self.item = item = self.itemView.items[sel]
for key in sorted(item.attributes.keys()):
override = item.overrides.get(key, None)
default = item.attributes[key].value
if override and override.value != default:
prop = wxpg.FloatProperty(key, value=override.value)
prop.SetModifiedStatus(True)
else:
prop = wxpg.FloatProperty(key, value=default)
prop.SetClientData(item.attributes[key]) # set this so that we may access it later
prop.SetHelpString("%s\n%s"%(item.attributes[key].displayName or key, "Default Value: %0.3f"%default))
self.Append(prop)
def removeOverrides(self, event):
if self.item is None:
return
for _, x in self.item.overrides.items():
self.item.deleteOverride(x.attr)
self.itemView.updateItems(True)
self.ClearModifiedStatus()
self.itemView.Select(self.itemView.GetFirstSelected(), on=False)
self.Clear()
def Clear(self):
self.item = None
self.btn.Enable(False)
wxpg.PropertyGrid.Clear(self)
def OnPropGridChange(self, event):
p = event.GetProperty()
attr = p.GetClientData()
if p.GetValue() == attr.value:
self.item.deleteOverride(attr)
p.SetModifiedStatus(False)
else:
self.item.setOverride(attr, p.GetValue())
self.itemView.updateItems()
logger.debug('%s changed to "%s"' % (p.GetName(), p.GetValueAsString()))
def OnPropGridSelect(self, event):
pass
def OnPropGridRightClick(self, event):
pass

View File

@@ -116,12 +116,15 @@ class SearchWorkerThread(threading.Thread):
while self.searchRequest is None:
cv.wait()
request, callback = self.searchRequest
request, callback, filterOn = self.searchRequest
self.searchRequest = None
cv.release()
sMkt = Market.getInstance()
# Rely on category data provided by eos as we don't hardcode them much in service
filter = eos.types.Category.name.in_(sMkt.SEARCH_CATEGORIES)
if filterOn:
# Rely on category data provided by eos as we don't hardcode them much in service
filter = eos.types.Category.name.in_(sMkt.SEARCH_CATEGORIES)
else:
filter=None
results = eos.db.searchItems(request, where=filter,
join=(eos.types.Item.group, eos.types.Group.category),
eager=("icon", "group.category", "metaGroup", "metaGroup.parent"))
@@ -133,9 +136,9 @@ class SearchWorkerThread(threading.Thread):
items.add(item)
wx.CallAfter(callback, items)
def scheduleSearch(self, text, callback):
def scheduleSearch(self, text, callback, filterOn=True):
self.cv.acquire()
self.searchRequest = (text, callback)
self.searchRequest = (text, callback, filterOn)
self.cv.notify()
self.cv.release()
@@ -665,9 +668,16 @@ class Market():
ships.add(item)
return ships
def searchItems(self, name, callback):
def searchItems(self, name, callback, filterOn=True):
"""Find items according to given text pattern"""
self.searchWorkerThread.scheduleSearch(name, callback)
self.searchWorkerThread.scheduleSearch(name, callback, filterOn)
def getItemsWithOverrides(self):
overrides = eos.db.getAllOverrides()
items = set()
for x in overrides:
items.add(x.item)
return list(items)
def directAttrRequest(self, items, attribs):
try: