# =============================================================================== # 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 eos.exception import HandledListActionError from utils.deprecated import deprecated pyfalog = Logger(__name__) class HandledList(list): def filteredItemPreAssign(self, filter, *args, **kwargs): for element in self: try: if filter(element): element.preAssignItemAttr(*args, **kwargs) except AttributeError: pass def filteredItemIncrease(self, filter, *args, **kwargs): for element in self: try: if filter(element): element.increaseItemAttr(*args, **kwargs) except AttributeError: pass def filteredItemMultiply(self, filter, *args, **kwargs): for element in self: try: if filter(element): element.multiplyItemAttr(*args, **kwargs) except AttributeError: pass def filteredItemBoost(self, filter, *args, **kwargs): for element in self: try: if filter(element): element.boostItemAttr(*args, **kwargs) except AttributeError: pass def filteredItemForce(self, filter, *args, **kwargs): for element in self: try: if filter(element): element.forceItemAttr(*args, **kwargs) except AttributeError: pass def filteredChargePreAssign(self, filter, *args, **kwargs): for element in self: try: if filter(element): element.preAssignChargeAttr(*args, **kwargs) except AttributeError: pass def filteredChargeIncrease(self, filter, *args, **kwargs): for element in self: try: if filter(element): element.increaseChargeAttr(*args, **kwargs) except AttributeError: pass def filteredChargeMultiply(self, filter, *args, **kwargs): for element in self: try: if filter(element): element.multiplyChargeAttr(*args, **kwargs) except AttributeError: pass def filteredChargeBoost(self, filter, *args, **kwargs): for element in self: try: if filter(element): element.boostChargeAttr(*args, **kwargs) except AttributeError: pass def filteredChargeForce(self, filter, *args, **kwargs): for element in self: try: if filter(element): element.forceChargeAttr(*args, **kwargs) except AttributeError: pass def remove(self, thing): # We must flag it as modified, otherwise it not be removed from the database # @todo: flag_modified isn't in os x skel. need to rebuild to include # flag_modified(thing, "itemID") if thing.isInvalid: # see GH issue #324 thing.itemID = 0 list.remove(self, thing) def sort(self, *args, **kwargs): # We need it here to prevent external users from accidentally sorting the list as alot of # external logic relies on keeping modules at their places raise NotImplementedError class HandledModuleList(HandledList): def append(self, mod): emptyPosition = float("Inf") for i in range(len(self)): currMod = self[i] if currMod.isEmpty and not mod.isEmpty and currMod.slot == mod.slot: currPos = mod.position or i if currPos < emptyPosition: emptyPosition = currPos if emptyPosition < len(self): mod.position = emptyPosition self.__toModule(emptyPosition, mod) if mod.isInvalid: self.__toDummy(mod.position) raise HandledListActionError(mod) return self.appendIgnoreEmpty(mod) def appendIgnoreEmpty(self, mod): mod.position = len(self) HandledList.append(self, mod) if mod.isInvalid: self.remove(mod) raise HandledListActionError(mod) def replace(self, idx, mod): try: oldMod = self[idx] except IndexError: raise HandledListActionError(mod) self.__toModule(idx, mod) if mod.isInvalid: self.__toModule(idx, oldMod) raise HandledListActionError(mod) def replaceRackPosition(self, rackPosition, mod): listPositions = [] for currPos in range(len(self)): currMod = self[currPos] if currMod.slot == mod.slot: listPositions.append(currPos) listPositions.sort() try: modListPosition = listPositions[rackPosition] except IndexError: self.appendIgnoreEmpty(mod) else: oldMod = self[modListPosition] if mod.isEmpty: self.__toDummy(modListPosition) else: self.__toModule(modListPosition, mod) # If new module cannot be appended, restore old state if mod.isInvalid: if oldMod.isEmpty: self.__toDummy(modListPosition) else: self.__toModule(modListPosition, oldMod) raise HandledListActionError(mod) def insert(self, idx, mod): mod.position = idx i = idx while i < len(self): self[i].position += 1 i += 1 HandledList.insert(self, idx, mod) if mod.isInvalid: self.remove(mod) raise HandledListActionError(mod) def remove(self, mod): HandledList.remove(self, mod) oldPos = mod.position mod.position = None for i in range(oldPos, len(self)): self[i].position -= 1 def free(self, idx): self.__toDummy(idx) def __toDummy(self, index): mod = self[index] if not mod.isEmpty: dummy = mod.buildEmpty(mod.slot) dummy.position = index self[index] = dummy mod.position = None def __toModule(self, index, mod): oldMod = self[index] mod.position = index self[index] = mod oldMod.position = None class HandledDroneCargoList(HandledList): def find(self, item): for o in self: if o.item == item: yield o def findFirst(self, item): for o in self.find(item): return o def append(self, thing): HandledList.append(self, thing) if thing.isInvalid: self.remove(thing) raise HandledListActionError(thing) def insert(self, idx, thing): HandledList.insert(self, idx, thing) if thing.isInvalid: self.remove(thing) raise HandledListActionError(thing) class HandledImplantList(HandledList): def append(self, implant): if implant.isInvalid: HandledList.append(self, implant) self.remove(implant) raise HandledListActionError(implant) if self.__slotCheck(implant): HandledList.append(self, implant) self.remove(implant) raise HandledListActionError(implant) HandledList.append(self, implant) def insert(self, idx, implant): if implant.isInvalid: HandledList.insert(self, idx, implant) self.remove(implant) raise HandledListActionError(implant) if self.__slotCheck(implant): HandledList.insert(self, idx, implant) self.remove(implant) raise HandledListActionError(implant) HandledList.insert(self, idx, implant) def makeRoom(self, implant): # if needed, remove booster that was occupying slot oldObj = next((i for i in self if i.slot == implant.slot), None) if oldObj is not None: pyfalog.info("Slot {0} occupied with {1}, replacing with {2}", implant.slot, oldObj.item.name, implant.item.name) position = self.index(oldObj) from gui.fitCommands.helpers import ImplantInfo implantInfo = ImplantInfo.fromImplant(oldObj) oldObj.itemID = 0 # hack to remove from DB. See GH issue #324 self.remove(oldObj) return position, implantInfo return None, None def __slotCheck(self, implant): return any(i.slot == implant.slot for i in self) class HandledBoosterList(HandledList): def append(self, booster): if booster.isInvalid: HandledList.append(self, booster) self.remove(booster) raise HandledListActionError(booster) if self.__slotCheck(booster): HandledList.append(self, booster) self.remove(booster) raise HandledListActionError(booster) HandledList.append(self, booster) def insert(self, idx, booster): if booster.isInvalid: HandledList.insert(self, idx, booster) self.remove(booster) raise HandledListActionError(booster) if self.__slotCheck(booster): HandledList.insert(self, idx, booster) self.remove(booster) raise HandledListActionError(booster) HandledList.insert(self, idx, booster) def makeRoom(self, booster): # if needed, remove booster that was occupying slot oldObj = next((b for b in self if b.slot == booster.slot), None) if oldObj is not None: pyfalog.info("Slot {0} occupied with {1}, replacing with {2}", booster.slot, oldObj.item.name, booster.item.name) position = self.index(oldObj) from gui.fitCommands.helpers import BoosterInfo boosterInfo = BoosterInfo.fromBooster(oldObj) oldObj.itemID = 0 # hack to remove from DB. See GH issue #324 self.remove(oldObj) return position, boosterInfo return None, None def __slotCheck(self, booster): return any(b.slot == booster.slot for b in self) class HandledSsoCharacterList(list): def append(self, character): old = next((x for x in self if x.client == character.client), None) if old is not None: pyfalog.warning("Removing SSO Character with same hash: {}".format(repr(old))) list.remove(self, old) list.append(self, character) class HandledProjectedModList(HandledList): def append(self, proj): if proj.isInvalid: # we must include it before we remove it. doing it this way ensures # rows and relationships in database are removed as well HandledList.append(self, proj) self.remove(proj) raise HandledListActionError(proj) proj.projected = True HandledList.append(self, proj) # Remove non-projectable modules if not proj.item.isType("projected") and not proj.isExclusiveSystemEffect: self.remove(proj) raise HandledListActionError(proj) def insert(self, idx, proj): if proj.isInvalid: # we must include it before we remove it. doing it this way ensures # rows and relationships in database are removed as well HandledList.insert(self, idx, proj) self.remove(proj) raise HandledListActionError(proj) proj.projected = True HandledList.insert(self, idx, proj) # Remove non-projectable modules if not proj.item.isType("projected") and not proj.isExclusiveSystemEffect: self.remove(proj) raise HandledListActionError(proj) @property def currentSystemEffect(self): return next((m for m in self if m.isExclusiveSystemEffect), None) def makeRoom(self, proj): if proj.isExclusiveSystemEffect: # remove other system effects - only 1 per fit plz mod = self.currentSystemEffect if mod: pyfalog.info("System effect occupied with {0}, removing it to make space for {1}".format(mod.item.name, proj.item.name)) position = self.index(mod) # We need to pack up this info, so whatever... from gui.fitCommands.helpers import ModuleInfo modInfo = ModuleInfo.fromModule(mod) self.remove(mod) return position, modInfo return None, None class HandledProjectedDroneList(HandledDroneCargoList): def append(self, proj): proj.projected = True HandledList.append(self, proj) # Remove invalid or non-projectable drones if proj.isInvalid or not proj.item.isType("projected"): self.remove(proj) proj.projected = False raise HandledListActionError(proj) return True def insert(self, idx, proj): proj.projected = True HandledList.insert(self, idx, proj) # Remove invalid or non-projectable drones if proj.isInvalid or not proj.item.isType("projected"): self.remove(proj) proj.projected = False raise HandledListActionError(proj) return True class HandledItem(object): def preAssignItemAttr(self, *args, **kwargs): self.itemModifiedAttributes.preAssign(*args, **kwargs) def increaseItemAttr(self, *args, **kwargs): self.itemModifiedAttributes.increase(*args, **kwargs) def multiplyItemAttr(self, *args, **kwargs): self.itemModifiedAttributes.multiply(*args, **kwargs) def boostItemAttr(self, *args, **kwargs): self.itemModifiedAttributes.boost(*args, **kwargs) def forceItemAttr(self, *args, **kwargs): self.itemModifiedAttributes.force(*args, **kwargs) class HandledCharge(object): def preAssignChargeAttr(self, *args, **kwargs): self.chargeModifiedAttributes.preAssign(*args, **kwargs) def increaseChargeAttr(self, *args, **kwargs): self.chargeModifiedAttributes.increase(*args, **kwargs) def multiplyChargeAttr(self, *args, **kwargs): self.chargeModifiedAttributes.multiply(*args, **kwargs) def boostChargeAttr(self, *args, **kwargs): self.chargeModifiedAttributes.boost(*args, **kwargs) def forceChargeAttr(self, *args, **kwargs): self.chargeModifiedAttributes.force(*args, **kwargs)