Cargo works, but needs a more TLC

This commit is contained in:
blitzmann
2014-03-26 22:41:51 -04:00
parent e87ac96c6c
commit 5df7e193e7
14 changed files with 442 additions and 7 deletions

32
eos/db/saveddata/cargo.py Normal file
View File

@@ -0,0 +1,32 @@
#===============================================================================
# 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, ForeignKey, Boolean
from sqlalchemy.orm import mapper
from eos.db import saveddata_meta
from eos.types import Cargo
cargo_table = Table("cargo", saveddata_meta,
Column("ID", Integer, primary_key=True),
Column("fitID", Integer, ForeignKey("fits.ID"), nullable = False, index = True),
Column("itemID", Integer, nullable = False),
Column("amount", Integer, nullable = False))
mapper(Cargo, cargo_table)

View File

@@ -24,11 +24,12 @@ from sqlalchemy.sql import and_
from eos.db import saveddata_meta
from eos.db.saveddata.module import modules_table
from eos.db.saveddata.drone import drones_table
from eos.db.saveddata.cargo import cargo_table
from eos.db.saveddata.implant import fitImplants_table
from eos.types import Fit, Module, User, Booster, Drone, Implant, Character, DamagePattern
from eos.types import Fit, Module, User, Booster, Drone, Cargo, Implant, Character, DamagePattern
from eos.effectHandlerHelpers import HandledModuleList, HandledDroneList, \
HandledImplantBoosterList, HandledProjectedModList, HandledProjectedDroneList, \
HandledProjectedFitList
HandledProjectedFitList, HandledCargoList
fits_table = Table("fits", saveddata_meta,
Column("ID", Integer, primary_key = True),
Column("ownerID", ForeignKey("users.ID"), nullable = True, index = True),
@@ -53,6 +54,8 @@ mapper(Fit, fits_table,
"_Fit__boosters" : relation(Booster, collection_class = HandledImplantBoosterList, cascade='all, delete, delete-orphan', single_parent=True),
"_Fit__drones" : relation(Drone, collection_class = HandledDroneList, cascade='all, delete, delete-orphan', single_parent=True,
primaryjoin = and_(drones_table.c.fitID == fits_table.c.ID, drones_table.c.projected == False)),
"_Fit__cargo" : relation(Cargo, collection_class = HandledCargoList, cascade='all, delete, delete-orphan', single_parent=True,
primaryjoin = and_(cargo_table.c.fitID == fits_table.c.ID)),
"_Fit__projectedDrones" : relation(Drone, collection_class = HandledProjectedDroneList, cascade='all, delete, delete-orphan', single_parent=True,
primaryjoin = and_(drones_table.c.fitID == fits_table.c.ID, drones_table.c.projected == True)),
"_Fit__implants" : relation(Implant, collection_class = HandledImplantBoosterList, cascade='all, delete, delete-orphan', single_parent=True,

View File

@@ -187,6 +187,46 @@ class HandledDroneList(HandledList):
return d
class HandledCargoList(HandledList):
# shameless copy of HandledDroneList
# I have no idea what this does, but I needed it
# @todo: investigate this
def find(self, item):
for d in self:
if d.item == item:
yield d
def findFirst(self, item):
for d in self.find(item):
return d
def append(self, cargo):
list.append(self, cargo)
def remove(self, cargo):
HandledList.remove(self, cargo)
def appendItem(self, item, qty = 1):
if qty < 1: ValueError("Amount of cargo to add should be >= 1")
d = self.findFirst(item)
if d is None:
d = eos.types.Cargo(item)
self.append(d)
d.qty += qty
return d
def removeItem(self, item, qty):
if qty < 1: ValueError("Amount of cargo to remove should be >= 1")
d = self.findFirst(item)
if d is None: return
d.qty -= qty
if d.qty <= 0:
self.remove(d)
return None
return d
class HandledImplantBoosterList(HandledList):
def __init__(self):

78
eos/saveddata/cargo.py Normal file
View File

@@ -0,0 +1,78 @@
#===============================================================================
# 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 eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut, ChargeAttrShortcut
from eos.effectHandlerHelpers import HandledItem, HandledCharge
from sqlalchemy.orm import validates, reconstructor
# Cargo class copied from Implant class and hacked to make work. \o/
# @todo: clean me up, Scotty
class Cargo(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
def __init__(self, item):
if item.category.name != "Charge":
raise ValueError("Passed item is not a charge")
self.__item = item
self.itemID = item.ID
self.active = True
self.amount = 0
self.__itemModifiedAttributes = ModifiedAttributeDict()
self.__itemModifiedAttributes.original = self.item.attributes
@reconstructor
def init(self):
self.__item = None
def __fetchItemInfo(self):
import eos.db
self.__item = eos.db.getItem(self.itemID)
self.__itemModifiedAttributes = ModifiedAttributeDict()
self.__itemModifiedAttributes.original = self.__item.attributes
@property
def itemModifiedAttributes(self):
if self.__item is None:
self.__fetchItemInfo()
return self.__itemModifiedAttributes
@property
def item(self):
if self.__item is None:
self.__fetchItemInfo()
return self.__item
def clear(self):
self.itemModifiedAttributes.clear()
@validates("fitID", "itemID", "active")
def validator(self, key, val):
map = {"fitID": lambda val: isinstance(val, int),
"itemID" : lambda val: isinstance(val, int),
"active": lambda val: isinstance(val, bool)}
if map[key](val) == False: raise ValueError(str(val) + " is not a valid value for " + key)
else: return val
def __deepcopy__(self, memo):
copy = Cargo(self.item)
copy.active = self.active
return copy

View File

@@ -18,14 +18,14 @@
#===============================================================================
from eos.effectHandlerHelpers import HandledList, HandledModuleList, HandledDroneList, HandledImplantBoosterList, \
HandledProjectedFitList, HandledProjectedModList, HandledProjectedDroneList
HandledProjectedFitList, HandledProjectedModList, HandledProjectedDroneList, HandledCargoList
from eos.modifiedAttributeDict import ModifiedAttributeDict
from sqlalchemy.orm import validates, reconstructor
from itertools import chain
from eos import capSim
from copy import deepcopy
from math import sqrt, log, asinh
from eos.types import Drone, Ship, Character, State, Slot, Module, Implant, Booster, Skill
from eos.types import Drone, Cargo, Ship, Character, State, Slot, Module, Implant, Booster, Skill
from eos.saveddata.module import State
import re
import xml.dom
@@ -52,6 +52,7 @@ class Fit(object):
def __init__(self):
self.__modules = HandledModuleList()
self.__drones = HandledDroneList()
self.__cargo = HandledCargoList()
self.__implants = HandledImplantBoosterList()
self.__boosters = HandledImplantBoosterList()
self.__projectedFits = HandledProjectedFitList()
@@ -425,6 +426,10 @@ class Fit(object):
d = Drone(item)
d.amount = int(hardware.getAttribute("qty"))
f.drones.append(d)
elif item.category.name == "Charge":
c = Cargo(item)
c.amount = int(hardware.getAttribute("qty"))
f.cargo.append(c)
else:
try:
m = Module(item)
@@ -545,6 +550,13 @@ class Fit(object):
hardware.setAttribute("type", drone.item.name)
fitting.appendChild(hardware)
for cargo in fit.cargo:
hardware = doc.createElement("hardware")
hardware.setAttribute("qty", "%d" % cargo.amount)
hardware.setAttribute("slot", "cargo")
hardware.setAttribute("type", cargo.item.name)
fitting.appendChild(hardware)
return doc.toprettyxml()
@reconstructor
@@ -606,6 +618,10 @@ class Fit(object):
def drones(self):
return self.__drones
@property
def cargo(self):
return self.__cargo
@property
def modules(self):
return self.__modules

View File

@@ -25,6 +25,7 @@ from eos.saveddata.damagePattern import DamagePattern
from eos.saveddata.character import Character, Skill
from eos.saveddata.module import Module, State, Slot, Hardpoint, Rack
from eos.saveddata.drone import Drone
from eos.saveddata.cargo import Cargo
from eos.saveddata.implant import Implant
from eos.saveddata.booster import SideEffect
from eos.saveddata.booster import Booster

View File

@@ -21,6 +21,7 @@ import wx
import gui.mainFrame
from gui.boosterView import BoosterView
from gui.droneView import DroneView
from gui.cargoView import CargoView
from gui.implantView import ImplantView
from gui.projectedView import ProjectedView
from gui.pyfatogglepanel import TogglePanel
@@ -55,8 +56,10 @@ class AdditionsPane(TogglePanel):
boosterImg = bitmapLoader.getImage("booster_small", "icons")
projectedImg = bitmapLoader.getImage("projected_small", "icons")
gangImg = bitmapLoader.getImage("fleet_fc_small", "icons")
cargoImg = bitmapLoader.getImage("cargo_small", "icons")
self.notebook.AddPage(DroneView(self.notebook), "Drones", tabImage = droneImg, showClose = False)
self.notebook.AddPage(CargoView(self.notebook), "Cargo", tabImage = cargoImg, showClose = False)
self.notebook.AddPage(ImplantView(self.notebook), "Implants", tabImage = implantImg, showClose = False)
self.notebook.AddPage(BoosterView(self.notebook), "Boosters", tabImage = boosterImg, showClose = False)
@@ -68,6 +71,6 @@ class AdditionsPane(TogglePanel):
self.notebook.SetSelection(0)
PANES = ["Drones", "Implants", "Boosters", "Projected", "Fleet"]
PANES = ["Drones", "Cargo", "Implants", "Boosters", "Projected", "Fleet"]
def select(self, name):
self.notebook.SetSelection(self.PANES.index(name))

View File

@@ -1,2 +1,2 @@
__all__ = ["moduleAmmoPicker", "itemStats", "damagePattern", "marketJump", "droneSplit", "itemRemove",
"droneRemoveStack", "ammoPattern", "project", "factorReload", "whProjector"]
"droneRemoveStack", "ammoPattern", "project", "factorReload", "whProjector", "cargo"]

View File

@@ -0,0 +1,101 @@
from gui.contextMenu import ContextMenu
from gui.itemStats import ItemStatsDialog
import eos.types
import gui.mainFrame
import service
import gui.globalEvents as GE
import wx
class Cargo(ContextMenu):
def __init__(self):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
def display(self, srcContext, selection):
# Make sure context menu registers in the correct view
if srcContext not in ("marketItemGroup", "marketItemMisc") or self.mainFrame.getActiveFit() is None:
return False
item = selection[0]
sFit = service.Fit.getInstance()
return sFit.isAmmo(item.ID)
def getText(self, itmContext, selection):
return "Add {0} to Cargo".format(itmContext)
def activate(self, fullContext, selection, i):
sFit = service.Fit.getInstance()
fitID = self.mainFrame.getActiveFit()
cargo = eos.types.Cargo(selection[0])
dlg = CargoChanger(self.mainFrame, cargo, fullContext)
dlg.ShowModal()
dlg.Destroy()
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
Cargo.register()
class CargoAmount(ContextMenu):
def __init__(self):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
def display(self, srcContext, selection):
return srcContext in ("cargoItem",) and selection[0].amount >= 0
def getText(self, itmContext, selection):
return "Change {0} Quantity".format(itmContext)
def activate(self, fullContext, selection, i):
srcContext = fullContext[0]
dlg = CargoChanger(self.mainFrame, selection[0], srcContext)
dlg.ShowModal()
dlg.Destroy()
CargoAmount.register()
class CargoChanger(wx.Dialog):
def __init__(self, parent, cargo, context):
wx.Dialog.__init__(self, parent, title="Select Amount", size=wx.Size(220, 60))
self.cargo = cargo
self.context = context
bSizer1 = wx.BoxSizer(wx.HORIZONTAL)
self.input = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0)
bSizer1.Add(self.input, 0, wx.ALL, 5)
self.input.Bind(wx.EVT_CHAR, self.onChar)
self.button = wx.Button(self, wx.ID_OK, u"Change")
bSizer1.Add(self.button, 0, wx.ALL, 5)
self.SetSizer(bSizer1)
self.Layout()
self.Centre(wx.BOTH)
self.button.Bind(wx.EVT_BUTTON, self.change)
def change(self, event):
sFit = service.Fit.getInstance()
mainFrame = gui.mainFrame.MainFrame.getInstance()
fitID = mainFrame.getActiveFit()
sFit.addChangeCargo(fitID, self.cargo, int(self.input.GetLineText(0)))
wx.PostEvent(mainFrame, GE.FitChanged(fitID=fitID))
event.Skip()
## checks to make sure it's valid number
def onChar(self, event):
key = event.GetKeyCode()
acceptable_characters = "1234567890"
acceptable_keycode = [3, 22, 13, 8, 127] # modifiers like delete, copy, paste
if key in acceptable_keycode or key >= 255 or (key < 255 and chr(key) in acceptable_characters):
event.Skip()
return
else:
return False

View File

@@ -102,6 +102,9 @@ class PriceViewFull(StatsView):
for drone in fit.drones:
for _ in xrange(drone.amount):
typeIDs.append(drone.itemID)
for cargo in fit.cargo:
for _ in xrange(cargo.amount):
typeIDs.append(cargo.itemID)
if self._timer:
if self._timer.IsRunning():
self._timer.Stop()

View File

@@ -22,7 +22,7 @@ from gui import builtinViewColumns
from gui.viewColumn import ViewColumn
from gui import bitmapLoader
import wx
from eos.types import Drone, Fit, Module, Slot, Rack
from eos.types import Drone, Cargo, Fit, Module, Slot, Rack
import service
class BaseName(ViewColumn):
@@ -36,6 +36,8 @@ class BaseName(ViewColumn):
def getText(self, stuff):
if isinstance(stuff, Drone):
return "%dx %s" % (stuff.amount, stuff.item.name)
elif isinstance(stuff, Cargo):
return "%dx %s" % (stuff.amount, stuff.item.name)
elif isinstance(stuff, Fit):
return "%s (%s)" % (stuff.name, stuff.ship.item.name)
elif isinstance(stuff, Rack):

115
gui/cargoView.py Normal file
View File

@@ -0,0 +1,115 @@
#===============================================================================
# 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 service
import gui.display as d
import gui.marketBrowser as mb
from gui.builtinViewColumns.state import State
from gui.contextMenu import ContextMenu
import globalEvents as GE
# @todo: Was copied form another class and modified. Look through entire file, refine
class CargoView(d.Display):
DEFAULT_COLS = ["Base Name"]
def __init__(self, parent):
d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL | wx.BORDER_NONE)
self.lastFitId = None
self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged)
#self.mainFrame.Bind(mb.ITEM_SELECTED, self.addItem)
self.Bind(wx.EVT_LEFT_DCLICK, self.removeItem)
self.Bind(wx.EVT_KEY_UP, self.kbEvent)
if "__WXGTK__" in wx.PlatformInfo:
self.Bind(wx.EVT_RIGHT_UP, self.scheduleMenu)
else:
self.Bind(wx.EVT_RIGHT_DOWN, self.scheduleMenu)
def kbEvent(self,event):
keycode = event.GetKeyCode()
if keycode == wx.WXK_DELETE or keycode == wx.WXK_NUMPAD_DELETE:
fitID = self.mainFrame.getActiveFit()
cFit = service.Fit.getInstance()
row = self.GetFirstSelected()
if row != -1:
cFit.removeCargo(fitID, self.GetItemData(row))
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
event.Skip()
def fitChanged(self, event):
#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
event.Skip()
return
cFit = service.Fit.getInstance()
fit = cFit.getFit(event.fitID)
self.original = fit.cargo if fit is not None else None
self.cargo = stuff = fit.cargo if fit is not None else None
if stuff is not None: stuff.sort(key=lambda cargo: cargo.itemID)
if event.fitID != self.lastFitId:
self.lastFitId = event.fitID
item = self.GetNextItem(-1, wx.LIST_NEXT_ALL, wx.LIST_STATE_DONTCARE)
if item != -1:
self.EnsureVisible(item)
self.deselectItems()
self.populate(stuff)
self.refresh(stuff)
event.Skip()
def removeItem(self, event):
row, _ = self.HitTest(event.Position)
if row != -1:
col = self.getColumn(event.Position)
if col != self.getColIndex(State):
fitID = self.mainFrame.getActiveFit()
cFit = service.Fit.getInstance()
cargo = self.cargo[self.GetItemData(row)]
cFit.removeCargo(fitID, self.original.index(cargo))
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
def scheduleMenu(self, event):
event.Skip()
if self.getColumn(event.Position) != self.getColIndex(State):
wx.CallAfter(self.spawnMenu)
def spawnMenu(self):
sel = self.GetFirstSelected()
if sel != -1:
cFit = service.Fit.getInstance()
fit = cFit.getFit(self.mainFrame.getActiveFit())
cargo = fit.cargo[sel]
sMkt = service.Market.getInstance()
sourceContext = "cargoItem"
itemContext = sMkt.getCategoryByItem(cargo.item).name
menu = ContextMenu.getMenu((cargo,), (sourceContext, itemContext))
self.PopupMenu(menu)

BIN
icons/cargo_small.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 669 B

View File

@@ -416,6 +416,47 @@ class Fit(object):
fit.modules.insert(dst, new)
eos.db.commit()
def addChangeCargo(self, fitID, c, amount):
if fitID == None:
return False
fit = eos.db.getFit(fitID)
cargo = None
if c not in fit.cargo:
# adding from market
for x in fit.cargo.find(c.item):
if x is not None:
# found item already in cargo, use previous value and remove old
cargo = x
fit.cargo.remove(x)
break
if cargo is None:
# if we don't have the item already in cargo, use default values
cargo = c
else:
# changing existing
cargo = eos.types.Cargo(c.item)
fit.cargo.remove(c) # remove old
fit.cargo.append(cargo)
cargo.amount += amount
self.recalc(fit)
eos.db.commit()
return True
def removeCargo(self, fitID, position):
if fitID is None:
return False
fit = eos.db.getFit(fitID)
charge = fit.cargo[position]
fit.cargo.remove(charge)
self.recalc(fit)
return True
def addDrone(self, fitID, itemID):
if fitID == None: