diff --git a/eos/db/saveddata/booster.py b/eos/db/saveddata/booster.py index e40762cd9..fa29c70b2 100644 --- a/eos/db/saveddata/booster.py +++ b/eos/db/saveddata/booster.py @@ -24,6 +24,8 @@ import datetime from eos.db import saveddata_meta from eos.saveddata.booster import Booster +from eos.saveddata.boosterSideEffect import BoosterSideEffect +from eos.saveddata.fit import Fit boosters_table = Table("boosters", saveddata_meta, Column("ID", Integer, primary_key=True), @@ -34,19 +36,21 @@ boosters_table = Table("boosters", saveddata_meta, Column("modified", DateTime, nullable=True, onupdate=datetime.datetime.now), ) -# Legacy booster side effect code, should disable but a mapper relies on it. -activeSideEffects_table = Table("boostersActiveSideEffects", saveddata_meta, - Column("boosterID", ForeignKey("boosters.ID"), primary_key=True), - Column("effectID", Integer, primary_key=True)) + +booster_side_effect_table = Table("boosterSideEffects", saveddata_meta, + Column("boosterID", Integer, ForeignKey("boosters.ID"), primary_key=True, index=True), + Column("effectID", Integer, nullable=False, primary_key=True), + Column("active", Boolean, default=False)) -class ActiveSideEffectsDummy(object): - def __init__(self, effectID): - self.effectID = effectID - - -mapper(ActiveSideEffectsDummy, activeSideEffects_table) mapper(Booster, boosters_table, - properties={"_Booster__activeSideEffectDummies": relation(ActiveSideEffectsDummy)}) + properties={ + "_Booster__sideEffects": relation( + BoosterSideEffect, + backref="booster", + cascade='all, delete, delete-orphan'), + } +) -Booster._Booster__activeSideEffectIDs = association_proxy("_Booster__activeSideEffectDummies", "effectID") + +mapper(BoosterSideEffect, booster_side_effect_table) diff --git a/eos/saveddata/booster.py b/eos/saveddata/booster.py index 62eb4d88f..aa5d6bfcb 100644 --- a/eos/saveddata/booster.py +++ b/eos/saveddata/booster.py @@ -24,6 +24,7 @@ from sqlalchemy.orm import reconstructor, validates import eos.db from eos.effectHandlerHelpers import HandledItem from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut +from eos.saveddata.boosterSideEffect import BoosterSideEffect pyfalog = Logger(__name__) @@ -37,6 +38,9 @@ class Booster(HandledItem, ItemAttrShortcut): self.itemID = item.ID if item is not None else None self.active = True + + self.__sideEffects = self.__getSideEffects() + self.build() @reconstructor @@ -58,34 +62,23 @@ class Booster(HandledItem, ItemAttrShortcut): def build(self): """ Build object. Assumes proper and valid item already set """ - self.__sideEffects = [] self.__itemModifiedAttributes = ModifiedAttributeDict() self.__itemModifiedAttributes.original = self.__item.attributes self.__itemModifiedAttributes.overrides = self.__item.overrides self.__slot = self.__calculateSlot(self.__item) - # Legacy booster side effect code, disabling as not currently implemented - ''' - for effect in self.__item.effects.itervalues(): - if effect.isType("boosterSideEffect"): - s = SideEffect(self) - s.effect = effect - s.active = effect.ID in self.__activeSideEffectIDs - self.__sideEffects.append(s) - ''' + if len(self.sideEffects) != len(self.__getSideEffects()): + self.__sideEffects = [] + for ability in self.__getSideEffects(): + self.__sideEffects.append(ability) - # Legacy booster side effect code, disabling as not currently implemented - ''' - def iterSideEffects(self): - return self.__sideEffects.__iter__() + @property + def sideEffects(self): + return self.__sideEffects or [] - def getSideEffect(self, name): - for sideEffect in self.iterSideEffects(): - if sideEffect.effect.name == name: - return sideEffect - - raise KeyError("SideEffect with %s as name not found" % name) - ''' + def __getSideEffects(self): + """Returns list of BoosterSideEffect that are loaded with data""" + return [BoosterSideEffect(effect) for effect in self.item.effects.values() if effect.type and 'boosterSideEffect' in effect.type] @property def itemModifiedAttributes(self): @@ -161,41 +154,3 @@ class Booster(HandledItem, ItemAttrShortcut): ''' return copy - - -# Legacy booster side effect code, disabling as not currently implemented -''' - class SideEffect(object): - def __init__(self, owner): - self.__owner = owner - self.__active = False - self.__effect = None - - @property - def active(self): - return self.__active - - @active.setter - def active(self, active): - if not isinstance(active, bool): - raise TypeError("Expecting a bool, not a " + type(active)) - - if active != self.__active: - if active: - self.__owner._Booster__activeSideEffectIDs.append(self.effect.ID) - else: - self.__owner._Booster__activeSideEffectIDs.remove(self.effect.ID) - - self.__active = active - - @property - def effect(self): - return self.__effect - - @effect.setter - def effect(self, effect): - if not hasattr(effect, "handler"): - raise TypeError("Need an effect with a handler") - - self.__effect = effect -''' diff --git a/eos/saveddata/boosterSideEffect.py b/eos/saveddata/boosterSideEffect.py new file mode 100644 index 000000000..71014c3a7 --- /dev/null +++ b/eos/saveddata/boosterSideEffect.py @@ -0,0 +1,63 @@ +# =============================================================================== +# 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 . +# =============================================================================== + +from logbook import Logger + +from sqlalchemy.orm import reconstructor + +pyfalog = Logger(__name__) + + +class BoosterSideEffect(object): + + def __init__(self, effect): + """Initialize from the program""" + self.__effect = effect + self.effectID = effect.ID if effect is not None else None + self.active = False + self.build() + + @reconstructor + def init(self): + """Initialize from the database""" + self.__effect = None + + if self.effectID: + self.__effect = next((x for x in self.booster.item.effects.itervalues() if x.ID == self.effectID), None) + if self.__effect is None: + pyfalog.error("Effect (id: {0}) does not exist", self.effectID) + return + + self.build() + + def build(self): + pass + + @property + def effect(self): + return self.__effect + + @property + def name(self): + return self.__effect.getattr('displayName') or self.__effect.handlerName + + @property + def attrPrefix(self): + return self.__effect.getattr('prefix') + diff --git a/gui/boosterView.py b/gui/boosterView.py index 5f43aca04..549c5fd4c 100644 --- a/gui/boosterView.py +++ b/gui/boosterView.py @@ -49,6 +49,7 @@ class BoosterView(d.Display): "State", "attr:boosterness", "Base Name", + "Side Effects", "Price", ] diff --git a/gui/builtinContextMenus/boosterSideEffects.py b/gui/builtinContextMenus/boosterSideEffects.py new file mode 100644 index 000000000..68cfed1b2 --- /dev/null +++ b/gui/builtinContextMenus/boosterSideEffects.py @@ -0,0 +1,64 @@ +# noinspection PyPackageRequirements +import wx +from gui.contextMenu import ContextMenu +import gui.mainFrame +import gui.globalEvents as GE +from service.fit import Fit +from service.settings import ContextMenuSettings + + +class BoosterSideEffect(ContextMenu): + def __init__(self): + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.settings = ContextMenuSettings.getInstance() + + def display(self, srcContext, selection): + # if not self.settings.get('fighterAbilities'): + # return False + + if self.mainFrame.getActiveFit() is None or srcContext not in ("boosterItem"): + return False + + self.booster = selection[0] + return True + + def getText(self, itmContext, selection): + return "Side Effects" + + def addEffect(self, menu, ability): + label = ability.name + id = ContextMenu.nextID() + self.effectIds[id] = ability + menuItem = wx.MenuItem(menu, id, label, kind=wx.ITEM_CHECK) + menu.Bind(wx.EVT_MENU, self.handleMode, menuItem) + return menuItem + + def getSubMenu(self, context, selection, rootMenu, i, pitem): + msw = True if "wxMSW" in wx.PlatformInfo else False + self.context = context + self.effectIds = {} + + sub = wx.Menu() + + for effect in self.booster.sideEffects: + if not effect.effect.isImplemented: + continue + menuItem = self.addEffect(rootMenu if msw else sub, effect) + sub.AppendItem(menuItem) + menuItem.Check(effect.active) + + return sub + + def handleMode(self, event): + effect = self.effectIds[event.Id] + if effect is False or effect not in self.booster.sideEffects: + event.Skip() + return + + sFit = Fit.getInstance() + fitID = self.mainFrame.getActiveFit() + sFit.toggleBoosterSideEffect(fitID, effect) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + + +BoosterSideEffect.register() diff --git a/gui/builtinViewColumns/__init__.py b/gui/builtinViewColumns/__init__.py index cff8bc614..2a089e176 100644 --- a/gui/builtinViewColumns/__init__.py +++ b/gui/builtinViewColumns/__init__.py @@ -1,2 +1,2 @@ __all__ = ["ammo", "ammoIcon", "attributeDisplay", "baseIcon", "baseName", - "capacitorUse", "maxRange", "price", "propertyDisplay", "state", "misc", "abilities"] + "capacitorUse", "maxRange", "price", "propertyDisplay", "state", "misc", "abilities", "sideEffects"] diff --git a/gui/builtinViewColumns/sideEffects.py b/gui/builtinViewColumns/sideEffects.py new file mode 100644 index 000000000..25adb3769 --- /dev/null +++ b/gui/builtinViewColumns/sideEffects.py @@ -0,0 +1,46 @@ +# ============================================================================= +# 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 . +# ============================================================================= + + +# noinspection PyPackageRequirements +import wx +from eos.saveddata.booster import Booster +from gui.viewColumn import ViewColumn +import gui.mainFrame + + +class SideEffects(ViewColumn): + name = "Side Effects" + + def __init__(self, fittingView, params): + ViewColumn.__init__(self, fittingView) + + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.columnText = "Active Side Effects" + self.mask = wx.LIST_MASK_TEXT + + def getText(self, stuff): + if isinstance(stuff, Booster): + active = [x.name for x in stuff.sideEffects if x.active] + if len(active) == 0: + return "None" + return ", ".join(active) + + +SideEffects.register() diff --git a/gui/contextMenu.py b/gui/contextMenu.py index b56661217..043140db3 100644 --- a/gui/contextMenu.py +++ b/gui/contextMenu.py @@ -206,6 +206,7 @@ from gui.builtinContextMenus import ( # noqa: E402,F401 metaSwap, implantSets, fighterAbilities, + boosterSideEffects, commandFits, tabbedFits ) diff --git a/gui/viewColumn.py b/gui/viewColumn.py index 34c3c89ce..08f9ca2bb 100644 --- a/gui/viewColumn.py +++ b/gui/viewColumn.py @@ -79,5 +79,6 @@ from gui.builtinViewColumns import ( # noqa: E402, F401 misc, price, propertyDisplay, - state + state, + sideEffects ) diff --git a/service/fit.py b/service/fit.py index 896ca689d..da1b2fe0f 100644 --- a/service/fit.py +++ b/service/fit.py @@ -991,6 +991,13 @@ class Fit(object): eos.db.commit() self.recalc(fit) + def toggleBoosterSideEffect(self, fitID, sideEffect): + pyfalog.debug("Toggling booster side effect for fit ID: {0}", fitID) + fit = eos.db.getFit(fitID) + sideEffect.active = not sideEffect.active + eos.db.commit() + self.recalc(fit) + def changeChar(self, fitID, charID): pyfalog.debug("Changing character ({0}) for fit ID: {1}", charID, fitID) if fitID is None or charID is None: