Start refactoring the refactor that was started with command pattern refactoring.

Instead of attempting to keep all the Fit service functionality, move these into specific "Fitting Commands" that are designed to define a unit of work and it's undo. Then, we will have "GUI Commands" which are defined as actions taken by the user themselves - these will usually use one or more "Fitting Commands".
This commit is contained in:
blitzmann
2018-07-24 01:29:57 -04:00
parent 2ccad2a358
commit d5aeb0913d
15 changed files with 272 additions and 57 deletions

View File

@@ -36,10 +36,10 @@ class ItemRemove(ContextMenu):
if srcContext == "fittingModule":
modules = [module for module in selection if module is not None]
self.mainFrame.command.Submit(cmd.FitModuleRemoveCommand(fitID, modules))
self.mainFrame.command.Submit(cmd.GuiModuleRemoveCommand(fitID, modules))
return # the command takes care of the PostEvent
elif srcContext in ("fittingCharge", "projectedCharge"):
self.mainFrame.command.Submit(cmd.FitModuleAddChargeCommand(fitID, None, selection))
self.mainFrame.command.Submit(cmd.GuiModuleAddChargeCommand(fitID, None, selection))
elif srcContext == "droneItem":
sFit.removeDrone(fitID, fit.drones.index(selection[0]))
elif srcContext == "fighterItem":

View File

@@ -229,7 +229,7 @@ class ModuleAmmoPicker(ContextMenu):
return
fitID = self.mainFrame.getActiveFit()
self.mainFrame.command.Submit(cmd.FitModuleAddChargeCommand(fitID, charge.ID if charge is not None else None, self.modules))
self.mainFrame.command.Submit(cmd.GuiModuleAddChargeCommand(fitID, charge.ID if charge is not None else None, self.modules))
ModuleAmmoPicker.register()

View File

@@ -40,7 +40,7 @@ class ModuleGlobalAmmoPicker(ModuleAmmoPicker):
if mod.itemID == selectedModule.itemID:
allModules.append(mod)
self.mainFrame.command.Submit(cmd.FitModuleAddChargeCommand(fitID, charge.ID if charge is not None else None, allModules))
self.mainFrame.command.Submit(cmd.GuiModuleAddChargeCommand(fitID, charge.ID if charge is not None else None, allModules))
def display(self, srcContext, selection):
if not self.settings.get('moduleGlobalAmmoPicker'):

View File

@@ -383,9 +383,9 @@ class FittingView(d.Display):
sel = self.GetNextSelected(sel)
if len(modules) > 0:
self.mainFrame.command.Submit(cmd.FitModuleAddChargeCommand(fitID, itemID, modules))
self.mainFrame.command.Submit(cmd.GuiModuleAddChargeCommand(fitID, itemID, modules))
else:
self.mainFrame.command.Submit(cmd.FitModuleAddCommand(fitID, itemID))
self.mainFrame.command.Submit(cmd.GuiModuleAddCommand(fitID, itemID))
event.Skip()
@@ -407,7 +407,7 @@ class FittingView(d.Display):
if not isinstance(modules, list):
modules = [modules]
self.mainFrame.command.Submit(cmd.FitModuleRemoveCommand(self.activeFitID, modules))
self.mainFrame.command.Submit(cmd.GuiModuleRemoveCommand(self.activeFitID, modules))
def addModule(self, x, y, itemID):
"""Add a module from the market browser (from dragging it)"""
@@ -419,7 +419,7 @@ class FittingView(d.Display):
if not isinstance(mod, Module): # make sure we're not adding something to a T3D Mode
return
self.mainFrame.command.Submit(cmd.FitModuleAddCommand(fitID, itemID, self.mods[dstRow].modPosition))
self.mainFrame.command.Submit(cmd.GuiModuleAddCommand(fitID, itemID, self.mods[dstRow].modPosition))
def swapCargo(self, x, y, srcIdx):
"""Swap a module from cargo to fitting window"""
@@ -465,7 +465,7 @@ class FittingView(d.Display):
fitID = self.mainFrame.getActiveFit()
if getattr(mod2, "modPosition") is not None:
self.mainFrame.command.Submit(cmd.FitModuleSwapOrCloneCommand(fitID, srcIdx, mod2.modPosition, clone))
self.mainFrame.command.Submit(cmd.GuiModuleSwapOrCloneCommand(fitID, srcIdx, mod2.modPosition, clone))
else:
pyfalog.error("Missing module position for: {0}", str(getattr(mod2, "ID", "Unknown")))
@@ -625,7 +625,7 @@ class FittingView(d.Display):
ctrl = event.cmdDown or event.middleIsDown
click = "ctrl" if ctrl is True else "right" if event.GetButton() == 3 else "left"
self.mainFrame.command.Submit(cmd.FitModuleStateChangeCommand(fitID, self.mods[self.GetItemData(row)], mods, click))
self.mainFrame.command.Submit(cmd.GuiModuleStateChangeCommand(fitID, self.mods[self.GetItemData(row)], mods, click))
# update state tooltip
tooltip = self.activeColumns[col].getToolTip(self.mods[self.GetItemData(row)])

View File

@@ -1,5 +1,5 @@
from .moduleStateChange import FitModuleStateChangeCommand
from .moduleAdd import FitModuleAddCommand
from .moduleRemove import FitModuleRemoveCommand
from .moduleAddCharge import FitModuleAddChargeCommand
from .moduleSwapOrClone import FitModuleSwapOrCloneCommand
from .moduleStateChange import GuiModuleStateChangeCommand
from .moduleAdd import GuiModuleAddCommand
from .moduleRemove import GuiModuleRemoveCommand
from .moduleAddCharge import GuiModuleAddChargeCommand
from .moduleSwapOrClone import GuiModuleSwapOrCloneCommand

View File

@@ -0,0 +1,70 @@
import wx
from service.fit import Fit
import gui.mainFrame
from gui import globalEvents as GE
#from .helpers import ModuleInfoCache
from eos.saveddata.module import Module, State
import eos.db
from logbook import Logger
pyfalog = Logger(__name__)
class FitAddModuleCommand(wx.Command):
""""
Fitting command that appends a module to a fit using the first available slot.
from sFit.appendModule
"""
def __init__(self, fitID, itemID):
wx.Command.__init__(self, True, "Module Add")
self.fitID = fitID
self.itemID = itemID
self.new_position = None
self.change = None
def Do(self):
fitID = self.fitID
itemID = self.itemID
pyfalog.debug("Appending module for fit ({0}) using item: {1}", fitID, itemID)
fit = eos.db.getFit(fitID)
item = eos.db.getItem(itemID, eager=("attributes", "group.category"))
try:
self.module = Module(item)
except ValueError:
pyfalog.warning("Invalid item: {0}", itemID)
return False
if self.module.item.category.name == "Subsystem":
fit.modules.freeSlot(self.module.getModifiedItemAttr("subSystemSlot"))
if self.module.fits(fit):
self.module.owner = fit
numSlots = len(fit.modules)
fit.modules.append(self.module)
if self.module.isValidState(State.ACTIVE):
self.module.state = State.ACTIVE
# todo: fix these
# As some items may affect state-limiting attributes of the ship, calculate new attributes first
# self.recalc(fit)
# Then, check states of all modules and change where needed. This will recalc if needed
# self.checkStates(fit, m)
fit.fill()
eos.db.commit()
self.change = numSlots != len(fit.modules)
self.new_position = self.module.modPosition
else:
return False
return True
def Undo(self):
from .fitRemoveModule import FitRemoveModuleCommand # Avoid circular import
if self.new_position:
cmd = FitRemoveModuleCommand(self.fitID, [self.new_position])
cmd.Do()
return True

View File

@@ -0,0 +1,57 @@
import wx
from service.fit import Fit
import gui.mainFrame
from gui import globalEvents as GE
from .helpers import ModuleInfoCache
from eos.saveddata.module import Module, State
import eos.db
from logbook import Logger
pyfalog = Logger(__name__)
class FitRemoveModuleCommand(wx.Command):
""""
Fitting command that removes a module at a specified positions
from sFit.removeModule
"""
def __init__(self, fitID: int, positions: list = None):
wx.Command.__init__(self, True, "Module Remove")
self.fitID = fitID
self.positions = positions
self.modCache = []
self.change = None
def Do(self):
fitID = self.fitID
pyfalog.debug("Removing module from position ({0}) for fit ID: {1}", self.positions, fitID)
fit = eos.db.getFit(fitID)
for x in self.positions:
mod = fit.modules[x]
if not mod.isEmpty:
self.modCache.append(ModuleInfoCache(mod.modPosition, mod.item.ID, mod.state, mod.charge))
fit.modules.toDummy(x)
# if no modules have changes, report back None
if not len(self.modCache) > 0:
return False
numSlots = len(fit.modules)
# todo: determine if we need to do this still
# self.recalc(fit)
# self.checkStates(fit, None)
fit.fill()
eos.db.commit()
self.slotsChanged = numSlots != len(fit.modules)
return True
def Undo(self):
from .fitAddModule import FitAddModuleCommand # avoids circular import
for mod in self.modCache:
cmd = FitAddModuleCommand(self.fitID, mod.itemID)
cmd.Do()
cmd.module.state = mod.state
cmd.module.charge = mod.charge
return True

View File

@@ -0,0 +1,77 @@
import wx
from service.fit import Fit
import gui.mainFrame
from gui import globalEvents as GE
from .helpers import ModuleInfoCache
from eos.saveddata.module import Module, State
import eos.db
from logbook import Logger
pyfalog = Logger(__name__)
class FitReplaceModuleCommand(wx.Command):
""""
Fitting command that changes an existing module into another.
from sFit.changeModule
"""
def __init__(self, fitID, position, itemID):
wx.Command.__init__(self, True, "Change Module")
self.fitID = fitID
self.itemID = itemID
self.position = position
self.module = None # the module version of itemID
self.old_module = None
def Do(self):
return self.change_module(self.fitID, self.position, self.itemID)
def Undo(self):
self.change_module(self.fitID, self.position, self.itemID)
self.module.state = self.old_module.state
self.module.charge = self.old_module.charge
return True
def change_module(self, fitID, position, itemID):
fit = eos.db.getFit(fitID)
# We're trying to add a charge to a slot, which won't work. Instead, try to add the charge to the module in that slot.
# todo: evaluate if this is still a thing
# actually, this seems like it should be handled higher up...
#
# if self.isAmmo(itemID):
# module = fit.modules[self.position]
# if not module.isEmpty:
# self.setAmmo(fitID, itemID, [module])
# return True
pyfalog.debug("Changing position of module from position ({0}) for fit ID: {1}", self.position, fitID)
item = eos.db.getItem(itemID, eager=("attributes", "group.category"))
mod = fit.modules[self.position]
self.old_module.append(ModuleInfoCache(mod.modPosition, mod.item.ID, mod.state, mod.charge))
# Dummy it out in case the next bit fails
fit.modules.toDummy(self.position)
try:
self.module = Module(item)
except ValueError:
pyfalog.warning("Invalid item: {0}", itemID)
return False
if self.module.fits(fit):
self.module.owner = fit
fit.modules.toModule(self.position, self.module)
if self.module.isValidState(State.ACTIVE):
self.module.state = State.ACTIVE
# Then, check states of all modules and change where needed. This will recalc if needed
# self.checkStates(fit, m)
fit.fill()
eos.db.commit()
return True
return False

View File

@@ -4,9 +4,10 @@ from service.fit import Fit
import gui.mainFrame
from gui import globalEvents as GE
from .helpers import ModuleInfoCache
from .fitAddModule import FitAddModuleCommand
from .fitReplaceModule import FitReplaceModuleCommand
class FitModuleAddCommand(wx.Command):
class GuiModuleAddCommand(wx.Command):
def __init__(self, fitID, itemID, position=None):
wx.Command.__init__(self, True, "Module Add")
# todo: evaluate mutaplasmid modules
@@ -14,45 +15,37 @@ class FitModuleAddCommand(wx.Command):
self.sFit = Fit.getInstance()
self.fitID = fitID
self.itemID = itemID
self.internal_history = wx.CommandProcessor()
self.new_position = position
self.old_mod = None
def Do(self):
change = None
success = False
# if we have a position set, try to apply the module to that position
if self.new_position:
fit = self.sFit.getFit(self.fitID)
old_mod = fit.modules[self.new_position]
cache = ModuleInfoCache(old_mod.modPosition, old_mod.itemID, old_mod.state, old_mod.charge)
change = self.sFit.changeModule(self.fitID, self.new_position, self.itemID)
if change is None:
# the new module doesn't fit in specified slot, remove the position
success = self.internal_history.Submit(FitReplaceModuleCommand(self.fitID, self.new_position, self.itemID))
if not success:
# something went wrong with trying to fit the module into specific location, attemp to append it
self.new_position = None
elif not old_mod.isEmpty:
self.old_mod = cache
# if we're not trying to set module to a position, simply append
if not self.new_position:
change, self.new_position = self.sFit.appendModule(self.fitID, self.itemID)
success = self.internal_history.Submit(FitAddModuleCommand(self.fitID, self.itemID))
if change is not None:
print('new position: ',self.new_position )
# self.slotsChanged() # unsure how to handle this right now? Perhaps move this to the event itself?
if success:
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="modadd", typeID=self.itemID))
return True
return False
#
# if change is not None:
# print('new position: ',self.new_position )
# # self.slotsChanged() # unsure how to handle this right now? Perhaps move this to the event itself?
# return True
# return False
def Undo(self):
if self.new_position:
if self.old_mod:
# we added a module on top of another one
m = self.sFit.changeModule(self.fitID, self.old_mod.modPosition, self.old_mod.itemID, False)
m.state = self.old_mod.state
m.charge = self.old_mod.charge
else:
# todo: self.slotsChanged()
# we simply added a module, so simply remove
result = self.sFit.removeModule(self.fitID, [self.new_position])
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="moddel", typeID=self.itemID))
for _ in self.internal_history.Commands:
self.internal_history.Undo()
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="moddel", typeID=self.itemID))
return True

View File

@@ -5,7 +5,7 @@ import gui.mainFrame
from gui import globalEvents as GE
class FitModuleAddChargeCommand(wx.Command):
class GuiModuleAddChargeCommand(wx.Command):
def __init__(self, fitID, itemID, modules):
wx.Command.__init__(self, True, "Module Charge Add")
# todo: evaluate mutaplasmid modules

View File

@@ -6,8 +6,10 @@ from gui import globalEvents as GE
from collections import namedtuple
from .helpers import ModuleInfoCache
from .fitRemoveModule import FitRemoveModuleCommand
class FitModuleRemoveCommand(wx.Command):
class GuiModuleRemoveCommand(wx.Command):
def __init__(self, fitID, modules):
# todo: evaluate mutaplasmid modules
wx.Command.__init__(self, True, "Module Remove")
@@ -15,22 +17,19 @@ class FitModuleRemoveCommand(wx.Command):
self.sFit = Fit.getInstance()
self.fitID = fitID
self.modCache = [ModuleInfoCache(mod.modPosition, mod.item.ID, mod.state, mod.charge) for mod in modules]
self.internal_history = wx.CommandProcessor()
def Do(self):
self.sFit.getFit(self.fitID)
result = self.sFit.removeModule(self.fitID, [mod.modPosition for mod in self.modCache])
# todo: what happens when one remove in an array of removes fucks up? (it really shouldn't it's easy peasy)
success = self.internal_history.Submit(FitRemoveModuleCommand(self.fitID, [mod.modPosition for mod in self.modCache]))
if result is not None:
if success is not None:
# self.slotsChanged() # todo: fix
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="moddel", typeID=set([mod.itemID for mod in self.modCache])))
return True
return True
def Undo(self):
for mod in self.modCache:
m = self.sFit.changeModule(self.fitID, mod.modPosition, mod.itemID, False)
m.state = mod.state
m.charge = mod.charge
self.sFit.recalc(self.fitID)
for x in self.internal_history.Commands:
self.internal_history.Undo()
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="modadd", typeID=set([mod.itemID for mod in self.modCache])))
return True

View File

@@ -5,7 +5,7 @@ import gui.mainFrame
from gui import globalEvents as GE
class FitModuleStateChangeCommand(wx.Command):
class GuiModuleStateChangeCommand(wx.Command):
def __init__(self, fitID, baseMod, modules, click):
# todo: instead of modules, needs to be positions. Dead objects are a thing
wx.Command.__init__(self, True, "Module State Change")

View File

@@ -5,7 +5,7 @@ import gui.mainFrame
from gui import globalEvents as GE
class FitModuleSwapOrCloneCommand(wx.Command):
class GuiModuleSwapOrCloneCommand(wx.Command):
def __init__(self, fitID, srcPosition, dstPosition, clone=False):
# todo: instead of modules, needs to be positions. Dead objects are a thing
wx.Command.__init__(self, True, "Module State Change")

View File

@@ -37,7 +37,7 @@ from eos.saveddata.fit import Fit as FitType, ImplantLocation
from service.character import Character
from service.damagePattern import DamagePattern
from service.settings import SettingsProvider
from utils.deprecated import deprecated
pyfalog = Logger(__name__)
@@ -538,6 +538,7 @@ class Fit(object):
eos.db.commit()
return mutator.value
@deprecated
def appendModule(self, fitID, itemID):
pyfalog.debug("Appending module for fit ({0}) using item: {1}", fitID, itemID)
fit = eos.db.getFit(fitID)
@@ -570,6 +571,7 @@ class Fit(object):
else:
return None, None
@deprecated
def removeModule(self, fitID, positions):
"""Removes modules based on a number of positions."""
pyfalog.debug("Removing module from position ({0}) for fit ID: {1}", positions, fitID)
@@ -627,6 +629,7 @@ class Fit(object):
else:
return None
@deprecated
def changeModule(self, fitID, position, newItemID, recalc=True):
fit = eos.db.getFit(fitID)

16
utils/deprecated.py Normal file
View File

@@ -0,0 +1,16 @@
import warnings
import functools
def deprecated(func):
"""This is a decorator which can be used to mark functions
as deprecated. It will result in a warning being emitted
when the function is used."""
@functools.wraps(func)
def new_func(*args, **kwargs):
warnings.simplefilter('always', DeprecationWarning) # turn off filter
warnings.warn("Call to deprecated function {}.".format(func.__name__),
category=DeprecationWarning,
stacklevel=2)
warnings.simplefilter('default', DeprecationWarning) # reset filter
return func(*args, **kwargs)
return new_func