From 926e0a903526a20effca0164729e5dccf169e78b Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 21 Jul 2018 00:12:28 -0400 Subject: [PATCH 01/95] Start working on some undo / redo functionality. this is just the start, only module state changes and fit rename is implemented, and probably not very well x_x --- gui/builtinShipBrowser/fitItem.py | 23 ++++++++++++++--- gui/builtinViews/fittingView.py | 7 +++-- gui/fitCommands/__init__.py | 1 + gui/fitCommands/moduleStateChange.py | 38 ++++++++++++++++++++++++++++ gui/mainFrame.py | 6 +++++ gui/mainMenuBar.py | 4 +-- service/fit.py | 3 +++ 7 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 gui/fitCommands/__init__.py create mode 100644 gui/fitCommands/moduleStateChange.py diff --git a/gui/builtinShipBrowser/fitItem.py b/gui/builtinShipBrowser/fitItem.py index 2f05229d0..99cb9e0bb 100644 --- a/gui/builtinShipBrowser/fitItem.py +++ b/gui/builtinShipBrowser/fitItem.py @@ -21,6 +21,25 @@ from service.fit import Fit pyfalog = Logger(__name__) +class FitRenameCommand(wx.Command): + def __init__(self, fitID, newName): + wx.Command.__init__(self, True, "FitRename") + self.fitID = fitID + self.newName = newName + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.oldName = None + self.sFit = Fit.getInstance() + + def Do(self): + self.oldName, _ = self.sFit.renameFit(self.fitID, self.newName) + wx.PostEvent(self.mainFrame, FitRenamed(fitID=self.fitID)) + return True + + def Undo(self): + self.sFit.renameFit(self.fitID, self.oldName) + wx.PostEvent(self.mainFrame, FitRenamed(fitID=self.fitID)) + return True + class FitItem(SFItem.SFBrowserItem): def __init__(self, parent, fitID=None, shipFittingInfo=("Test", "TestTrait", "cnc's avatar", 0, 0, None), shipID=None, itemData=None, graphicID=None, @@ -325,14 +344,12 @@ class FitItem(SFItem.SFBrowserItem): self.Refresh() def renameFit(self, event=None): - sFit = Fit.getInstance() self.tcFitName.Show(False) self.editWasShown = 0 fitName = self.tcFitName.GetValue() if fitName: self.fitName = fitName - sFit.renameFit(self.fitID, self.fitName) - wx.PostEvent(self.mainFrame, FitRenamed(fitID=self.fitID)) + self.mainFrame.command.Submit(FitRenameCommand(self.fitID, self.fitName)) else: self.tcFitName.SetValue(self.fitName) diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index d6bf4ae0c..6ccc00c33 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -34,6 +34,7 @@ from gui.bitmap_loader import BitmapLoader import gui.builtinViews.emptyView from logbook import Logger from gui.chrome_tabs import EVT_NOTEBOOK_PAGE_CHANGED +import gui.fitCommands as cmd from service.fit import Fit from service.market import Market @@ -127,6 +128,8 @@ class FittingViewDrop(wx.DropTarget): return t + + class FittingView(d.Display): DEFAULT_COLS = ["State", "Ammo Icon", @@ -642,14 +645,14 @@ class FittingView(d.Display): fitID = self.mainFrame.getActiveFit() ctrl = event.cmdDown or event.middleIsDown click = "ctrl" if ctrl is True else "right" if event.GetButton() == 3 else "left" - sFit.toggleModulesState(fitID, self.mods[self.GetItemData(row)], mods, click) + + self.mainFrame.command.Submit(cmd.FitModuleStateChangeCommand(fitID, self.mods[self.GetItemData(row)], mods, click)) # update state tooltip tooltip = self.activeColumns[col].getToolTip(self.mods[self.GetItemData(row)]) if tooltip: self.SetToolTip(tooltip) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit())) else: event.Skip() diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py new file mode 100644 index 000000000..19100381e --- /dev/null +++ b/gui/fitCommands/__init__.py @@ -0,0 +1 @@ +from .moduleStateChange import FitModuleStateChangeCommand \ No newline at end of file diff --git a/gui/fitCommands/moduleStateChange.py b/gui/fitCommands/moduleStateChange.py new file mode 100644 index 000000000..c490115e2 --- /dev/null +++ b/gui/fitCommands/moduleStateChange.py @@ -0,0 +1,38 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE + + +class FitModuleStateChangeCommand(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") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.fitID = fitID + self.baseMod = baseMod + self.modules = modules + self.click = click + + self.old_states = {} + for mod in modules: + # we don't use the actual module as the key, because it may have been deleted in subsequent calls (even if + # we undo a deletion, wouldn't be the same obj). So, we store the position + self.old_states[mod.modPosition] = mod.state + + def Do(self): + # todo: determine if we've changed state (recalc). If not, store that so we don't attempt to recalc on undo + self.sFit.toggleModulesState(self.fitID, self.baseMod, self.modules, self.click) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + + def Undo(self): + # todo: some sanity checking to make sure that we are applying state back to the same modules? + fit = self.sFit.getFit(self.fitID) + for k, v in self.old_states.items(): + fit.modules[k].state = v + self.sFit.recalc(fit) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True diff --git a/gui/mainFrame.py b/gui/mainFrame.py index 9b237663c..2a94f1b2c 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -170,6 +170,8 @@ class MainFrame(wx.Frame): i = wx.Icon(BitmapLoader.getBitmap("pyfa", "gui")) self.SetIcon(i) + self.command = wx.CommandProcessor() + # Create the layout and windows mainSizer = wx.BoxSizer(wx.HORIZONTAL) @@ -514,6 +516,10 @@ class MainFrame(wx.Frame): self.Bind(wx.EVT_MENU, self.showPreferenceDialog, id=wx.ID_PREFERENCES) # User guide self.Bind(wx.EVT_MENU, self.goWiki, id=menuBar.wikiId) + + self.Bind(wx.EVT_MENU, lambda evt: MainFrame.getInstance().command.Undo(), id=wx.ID_UNDO) + + self.Bind(wx.EVT_MENU, lambda evt: MainFrame.getInstance().command.Redo(), id=wx.ID_REDO) # EVE Forums self.Bind(wx.EVT_MENU, self.goForums, id=menuBar.forumId) # Save current character diff --git a/gui/mainMenuBar.py b/gui/mainMenuBar.py index 9c421f779..c0a28f1dc 100644 --- a/gui/mainMenuBar.py +++ b/gui/mainMenuBar.py @@ -90,8 +90,8 @@ class MainMenuBar(wx.MenuBar): editMenu = wx.Menu() self.Append(editMenu, "&Edit") - # editMenu.Append(wx.ID_UNDO) - # editMenu.Append(wx.ID_REDO) + editMenu.Append(wx.ID_UNDO) + editMenu.Append(wx.ID_REDO) editMenu.Append(wx.ID_COPY, "To Clipboard\tCTRL+C", "Export a fit to the clipboard") editMenu.Append(wx.ID_PASTE, "From Clipboard\tCTRL+V", "Import a fit from the clipboard") diff --git a/service/fit.py b/service/fit.py index 122de2fa6..3a4d044eb 100644 --- a/service/fit.py +++ b/service/fit.py @@ -170,8 +170,11 @@ class Fit(object): def renameFit(fitID, newName): pyfalog.debug("Renaming fit ({0}) to: {1}", fitID, newName) fit = eos.db.getFit(fitID) + old_name = fit.name fit.name = newName eos.db.commit() + return old_name, newName + @staticmethod def deleteFit(fitID): From 0c3fa53bcf3bae8b885ccc115bc15ebee980106f Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 21 Jul 2018 14:46:25 -0400 Subject: [PATCH 02/95] Support undo/redo module add --- gui/builtinViews/fittingView.py | 6 ++---- gui/fitCommands/__init__.py | 3 ++- gui/fitCommands/moduleAdd.py | 29 +++++++++++++++++++++++++++++ service/fit.py | 2 +- 4 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 gui/fitCommands/moduleAdd.py diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index 6ccc00c33..d25f2f097 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -382,14 +382,12 @@ class FittingView(d.Display): sFit.setAmmo(fitID, itemID, modules) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) else: - populate = sFit.appendModule(fitID, itemID) - if populate is not None: - self.slotsChanged() - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID, action="modadd", typeID=itemID)) + self.mainFrame.command.Submit(cmd.FitModuleAddCommand(fitID, itemID)) event.Skip() def removeItem(self, event): + '''Double Left Click - remove module''' if event.CmdDown(): return row, _ = self.HitTest(event.Position) diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index 19100381e..fcb59fc63 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -1 +1,2 @@ -from .moduleStateChange import FitModuleStateChangeCommand \ No newline at end of file +from .moduleStateChange import FitModuleStateChangeCommand +from.moduleAdd import FitModuleAddCommand \ No newline at end of file diff --git a/gui/fitCommands/moduleAdd.py b/gui/fitCommands/moduleAdd.py new file mode 100644 index 000000000..c7f4e21f7 --- /dev/null +++ b/gui/fitCommands/moduleAdd.py @@ -0,0 +1,29 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE + + +class FitModuleAddCommand(wx.Command): + def __init__(self, fitID, itemID): + # todo: instead of modules, needs to be positions. Dead objects are a thing + wx.Command.__init__(self, True, "Module Add") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.fitID = fitID + self.itemID = itemID + self.new_position = None + + def Do(self): + populate, self.new_position = self.sFit.appendModule(self.fitID, self.itemID) + if populate is not None: + # self.slotsChanged() # unsure how to handle this right now? Perhaps move this to the event itself? + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="modadd", typeID=self.itemID)) + return True + + def Undo(self): + # todo: self.slotsChanged() + result = self.sFit.removeModule(self.fitID, [self.new_position]) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="moddel", typeID=self.itemID)) + return True diff --git a/service/fit.py b/service/fit.py index 3a4d044eb..245007dda 100644 --- a/service/fit.py +++ b/service/fit.py @@ -566,7 +566,7 @@ class Fit(object): fit.fill() eos.db.commit() - return numSlots != len(fit.modules) + return numSlots != len(fit.modules), m.modPosition else: return None From 9309ddff07321572c70a2e12faaf0937f312c8c3 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 21 Jul 2018 15:34:58 -0400 Subject: [PATCH 03/95] Created undo/redo command for module remove, along with reapplying some module-specific attributes (state, charge). Fixed a bug when trying to add a module that doesn't fit --- gui/builtinViews/fittingView.py | 10 +-------- gui/fitCommands/__init__.py | 3 ++- gui/fitCommands/moduleAdd.py | 10 +++++---- gui/fitCommands/moduleRemove.py | 37 +++++++++++++++++++++++++++++++++ service/fit.py | 18 +++++++++------- 5 files changed, 57 insertions(+), 21 deletions(-) create mode 100644 gui/fitCommands/moduleRemove.py diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index d25f2f097..47255542f 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -401,18 +401,10 @@ class FittingView(d.Display): def removeModule(self, modules): """Removes a list of modules from the fit""" - sFit = Fit.getInstance() - if not isinstance(modules, list): modules = [modules] - positions = [mod.modPosition for mod in modules] - result = sFit.removeModule(self.activeFitID, positions) - - if result is not None: - self.slotsChanged() - ids = {mod.item.ID for mod in modules} - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.activeFitID, action="moddel", typeID=ids)) + self.mainFrame.command.Submit(cmd.FitModuleRemoveCommand(self.activeFitID, modules)) def addModule(self, x, y, srcIdx): """Add a module from the market browser""" diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index fcb59fc63..3aaaf1409 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -1,2 +1,3 @@ from .moduleStateChange import FitModuleStateChangeCommand -from.moduleAdd import FitModuleAddCommand \ No newline at end of file +from .moduleAdd import FitModuleAddCommand +from .moduleRemove import FitModuleRemoveCommand \ No newline at end of file diff --git a/gui/fitCommands/moduleAdd.py b/gui/fitCommands/moduleAdd.py index c7f4e21f7..e5b038317 100644 --- a/gui/fitCommands/moduleAdd.py +++ b/gui/fitCommands/moduleAdd.py @@ -7,8 +7,8 @@ from gui import globalEvents as GE class FitModuleAddCommand(wx.Command): def __init__(self, fitID, itemID): - # todo: instead of modules, needs to be positions. Dead objects are a thing wx.Command.__init__(self, True, "Module Add") + # todo: evaluate mutaplasmid modules self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.sFit = Fit.getInstance() self.fitID = fitID @@ -16,6 +16,7 @@ class FitModuleAddCommand(wx.Command): self.new_position = None def Do(self): + # todo: figure how not to add this command to stack if module doesn't fit correctly. populate, self.new_position = self.sFit.appendModule(self.fitID, self.itemID) if populate is not None: # self.slotsChanged() # unsure how to handle this right now? Perhaps move this to the event itself? @@ -23,7 +24,8 @@ class FitModuleAddCommand(wx.Command): return True def Undo(self): - # todo: self.slotsChanged() - result = self.sFit.removeModule(self.fitID, [self.new_position]) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="moddel", typeID=self.itemID)) + if (self.new_position): + # todo: self.slotsChanged() + result = self.sFit.removeModule(self.fitID, [self.new_position]) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="moddel", typeID=self.itemID)) return True diff --git a/gui/fitCommands/moduleRemove.py b/gui/fitCommands/moduleRemove.py new file mode 100644 index 000000000..df1bda3a6 --- /dev/null +++ b/gui/fitCommands/moduleRemove.py @@ -0,0 +1,37 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from collections import namedtuple + + +ModuleInfoCache = namedtuple('ModuleInfoCache', ['modPosition', 'itemID', 'state', 'charge']) + +class FitModuleRemoveCommand(wx.Command): + def __init__(self, fitID, modules): + # todo: evaluate mutaplasmid modules + wx.Command.__init__(self, True, "Module Remove") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.fitID = fitID + self.modCache = [ModuleInfoCache(mod.modPosition, mod.item.ID, mod.state, mod.charge) for mod in modules] + + def Do(self): + self.sFit.getFit(self.fitID) + result = self.sFit.removeModule(self.fitID, [mod.modPosition for mod in self.modCache]) + + if result 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 + + 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) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="modadd", typeID=set([mod.itemID for mod in self.modCache]))) + + return True diff --git a/service/fit.py b/service/fit.py index 245007dda..1172cd2fb 100644 --- a/service/fit.py +++ b/service/fit.py @@ -568,7 +568,7 @@ class Fit(object): return numSlots != len(fit.modules), m.modPosition else: - return None + return None, None def removeModule(self, fitID, positions): """Removes modules based on a number of positions.""" @@ -627,7 +627,7 @@ class Fit(object): else: return None - def changeModule(self, fitID, position, newItemID): + def changeModule(self, fitID, position, newItemID, recalc=True): 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. @@ -656,15 +656,16 @@ class Fit(object): if m.isValidState(State.ACTIVE): m.state = State.ACTIVE - # As some items may affect state-limiting attributes of the ship, calculate new attributes first - self.recalc(fit) + if (recalc): + # 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() - return True + return m else: return None @@ -1073,7 +1074,7 @@ class Fit(object): def isAmmo(itemID): return eos.db.getItem(itemID).category.name == "Charge" - def setAmmo(self, fitID, ammoID, modules): + def setAmmo(self, fitID, ammoID, modules, recalc=True): pyfalog.debug("Set ammo for fit ID: {0}", fitID) if fitID is None: return @@ -1085,7 +1086,8 @@ class Fit(object): if mod.isValidCharge(ammo): mod.charge = ammo - self.recalc(fit) + if recalc: + self.recalc(fit) @staticmethod def getTargetResists(fitID): @@ -1259,6 +1261,8 @@ class Fit(object): self.recalc(fit) def recalc(self, fit): + if isinstance(fit, int): + fit = self.getFit(fit) start_time = time() pyfalog.info("=" * 10 + "recalc: {0}" + "=" * 10, fit.name) From ec3cd75f4c763ac369e7dbe7e6f58b7727de8b0e Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 21 Jul 2018 16:00:02 -0400 Subject: [PATCH 04/95] Convert the context > Remove Module to command pattern --- gui/builtinContextMenus/itemRemove.py | 8 ++++---- gui/fitCommands/moduleRemove.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gui/builtinContextMenus/itemRemove.py b/gui/builtinContextMenus/itemRemove.py index 8e9ede5c6..dca400c5d 100644 --- a/gui/builtinContextMenus/itemRemove.py +++ b/gui/builtinContextMenus/itemRemove.py @@ -5,7 +5,7 @@ import wx import gui.globalEvents as GE from service.fit import Fit from service.settings import ContextMenuSettings - +import gui.fitCommands as cmd class ItemRemove(ContextMenu): def __init__(self): @@ -35,9 +35,9 @@ class ItemRemove(ContextMenu): fit = sFit.getFit(fitID) if srcContext == "fittingModule": - for module in selection: - if module is not None: - sFit.removeModule(fitID, fit.modules.index(module)) + modules = [module for module in selection if module is not None] + self.mainFrame.command.Submit(cmd.FitModuleRemoveCommand(fitID, modules)) + return # the command takes care of the PostEvent elif srcContext in ("fittingCharge", "projectedCharge"): sFit.setAmmo(fitID, None, selection) elif srcContext == "droneItem": diff --git a/gui/fitCommands/moduleRemove.py b/gui/fitCommands/moduleRemove.py index df1bda3a6..bc055cde6 100644 --- a/gui/fitCommands/moduleRemove.py +++ b/gui/fitCommands/moduleRemove.py @@ -5,9 +5,9 @@ import gui.mainFrame from gui import globalEvents as GE from collections import namedtuple - ModuleInfoCache = namedtuple('ModuleInfoCache', ['modPosition', 'itemID', 'state', 'charge']) + class FitModuleRemoveCommand(wx.Command): def __init__(self, fitID, modules): # todo: evaluate mutaplasmid modules From 5d0342ee2d0bd0287e9d6dd36939104e83f56ec4 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 21 Jul 2018 18:04:07 -0400 Subject: [PATCH 05/95] Convert module charge handling to command pattern (adding charges and removing charges) --- gui/builtinContextMenus/itemRemove.py | 2 +- gui/builtinContextMenus/moduleAmmoPicker.py | 7 ++--- .../moduleGlobalAmmoPicker.py | 5 ++-- gui/builtinViews/fittingView.py | 3 +- gui/fitCommands/__init__.py | 3 +- gui/fitCommands/moduleAddCharge.py | 30 +++++++++++++++++++ 6 files changed, 38 insertions(+), 12 deletions(-) create mode 100644 gui/fitCommands/moduleAddCharge.py diff --git a/gui/builtinContextMenus/itemRemove.py b/gui/builtinContextMenus/itemRemove.py index dca400c5d..d6b8f79f1 100644 --- a/gui/builtinContextMenus/itemRemove.py +++ b/gui/builtinContextMenus/itemRemove.py @@ -39,7 +39,7 @@ class ItemRemove(ContextMenu): self.mainFrame.command.Submit(cmd.FitModuleRemoveCommand(fitID, modules)) return # the command takes care of the PostEvent elif srcContext in ("fittingCharge", "projectedCharge"): - sFit.setAmmo(fitID, None, selection) + self.mainFrame.command.Submit(cmd.FitModuleAddChargeCommand(fitID, None, selection)) elif srcContext == "droneItem": sFit.removeDrone(fitID, fit.drones.index(selection[0])) elif srcContext == "fighterItem": diff --git a/gui/builtinContextMenus/moduleAmmoPicker.py b/gui/builtinContextMenus/moduleAmmoPicker.py index 93ff48754..59f6c3391 100644 --- a/gui/builtinContextMenus/moduleAmmoPicker.py +++ b/gui/builtinContextMenus/moduleAmmoPicker.py @@ -11,7 +11,7 @@ import gui.globalEvents as GE from gui.contextMenu import ContextMenu from gui.bitmap_loader import BitmapLoader from service.settings import ContextMenuSettings - +import gui.fitCommands as cmd class ModuleAmmoPicker(ContextMenu): DAMAGE_TYPES = ("em", "explosive", "kinetic", "thermal") @@ -228,11 +228,8 @@ class ModuleAmmoPicker(ContextMenu): event.Skip() return - sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() - - sFit.setAmmo(fitID, charge.ID if charge is not None else None, self.modules) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.FitModuleAddChargeCommand(fitID, charge.ID if charge is not None else None, self.modules)) ModuleAmmoPicker.register() diff --git a/gui/builtinContextMenus/moduleGlobalAmmoPicker.py b/gui/builtinContextMenus/moduleGlobalAmmoPicker.py index 5e516e68f..81bce6649 100644 --- a/gui/builtinContextMenus/moduleGlobalAmmoPicker.py +++ b/gui/builtinContextMenus/moduleGlobalAmmoPicker.py @@ -7,7 +7,7 @@ from gui.builtinContextMenus.moduleAmmoPicker import ModuleAmmoPicker from eos.db.saveddata.queries import getFit as db_getFit from service.fit import Fit from service.settings import ContextMenuSettings - +import gui.fitCommands as cmd class ModuleGlobalAmmoPicker(ModuleAmmoPicker): def __init__(self): @@ -40,8 +40,7 @@ class ModuleGlobalAmmoPicker(ModuleAmmoPicker): if mod.itemID == selectedModule.itemID: allModules.append(mod) - sFit.setAmmo(fitID, charge.ID if charge is not None else None, allModules) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.FitModuleAddChargeCommand(fitID, charge.ID if charge is not None else None, allModules)) def display(self, srcContext, selection): if not self.settings.get('moduleGlobalAmmoPicker'): diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index 47255542f..84678bb8f 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -379,8 +379,7 @@ class FittingView(d.Display): sel = self.GetNextSelected(sel) if len(modules) > 0: - sFit.setAmmo(fitID, itemID, modules) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.FitModuleAddChargeCommand(fitID, itemID, modules)) else: self.mainFrame.command.Submit(cmd.FitModuleAddCommand(fitID, itemID)) diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index 3aaaf1409..9ed595da5 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -1,3 +1,4 @@ from .moduleStateChange import FitModuleStateChangeCommand from .moduleAdd import FitModuleAddCommand -from .moduleRemove import FitModuleRemoveCommand \ No newline at end of file +from .moduleRemove import FitModuleRemoveCommand +from .moduleAddCharge import FitModuleAddChargeCommand \ No newline at end of file diff --git a/gui/fitCommands/moduleAddCharge.py b/gui/fitCommands/moduleAddCharge.py new file mode 100644 index 000000000..c125230b9 --- /dev/null +++ b/gui/fitCommands/moduleAddCharge.py @@ -0,0 +1,30 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE + + +class FitModuleAddChargeCommand(wx.Command): + def __init__(self, fitID, itemID, modules): + wx.Command.__init__(self, True, "Module Charge Add") + # todo: evaluate mutaplasmid modules + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.fitID = fitID + self.itemID = itemID + self.positions = {mod.modPosition: mod.chargeID for mod in modules} + + def Do(self): + fit = self.sFit.getFit(self.fitID) + self.sFit.setAmmo(self.fitID, self.itemID, [fit.modules[i] for i in self.positions.keys()]) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + + def Undo(self): + fit = self.sFit.getFit(self.fitID) + for position, chargeID in self.positions.items(): + self.sFit.setAmmo(self.fitID, chargeID, [fit.modules[position]], False) + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True From a66eb059e293bc2fe9b7aa2dbdd5222a22fe665e Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 21 Jul 2018 18:20:24 -0400 Subject: [PATCH 06/95] Convert module swap to command pattern --- gui/builtinViews/fittingView.py | 8 ++----- gui/fitCommands/__init__.py | 3 ++- gui/fitCommands/moduleSwapOrClone.py | 34 ++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 gui/fitCommands/moduleSwapOrClone.py diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index 84678bb8f..fab09726b 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -468,13 +468,9 @@ class FittingView(d.Display): if mod1.slot != mod2.slot: return + fitID = self.mainFrame.getActiveFit() if getattr(mod2, "modPosition") is not None: - if clone and mod2.isEmpty: - sFit.cloneModule(self.mainFrame.getActiveFit(), srcIdx, mod2.modPosition) - else: - sFit.swapModules(self.mainFrame.getActiveFit(), srcIdx, mod2.modPosition) - - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit())) + self.mainFrame.command.Submit(cmd.FitModuleSwapOrCloneCommand(fitID, srcIdx, mod2.modPosition, clone and mod2.isEmpty)) else: pyfalog.error("Missing module position for: {0}", str(getattr(mod2, "ID", "Unknown"))) diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index 9ed595da5..c9bbf25da 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -1,4 +1,5 @@ from .moduleStateChange import FitModuleStateChangeCommand from .moduleAdd import FitModuleAddCommand from .moduleRemove import FitModuleRemoveCommand -from .moduleAddCharge import FitModuleAddChargeCommand \ No newline at end of file +from .moduleAddCharge import FitModuleAddChargeCommand +from .moduleSwapOrClone import FitModuleSwapOrCloneCommand \ No newline at end of file diff --git a/gui/fitCommands/moduleSwapOrClone.py b/gui/fitCommands/moduleSwapOrClone.py new file mode 100644 index 000000000..65b6a10dc --- /dev/null +++ b/gui/fitCommands/moduleSwapOrClone.py @@ -0,0 +1,34 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE + + +class FitModuleSwapOrCloneCommand(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") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.fitID = fitID + self.srcPosition = srcPosition + self.dstPosition = dstPosition + self.clone = clone + + def Do(self): + if self.clone: + self.sFit.cloneModule(self.fitID, self.srcPosition, self.dstPosition) + else: + self.sFit.swapModules(self.fitID, self.srcPosition, self.dstPosition) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + + def Undo(self): + if self.clone: + # if we had cloned, the destinations was originally an empty slot, hence we can just remove the module + self.sFit.removeModule(self.fitID, [self.dstPosition]) + else: + self.sFit.swapModules(self.fitID, self.dstPosition, self.srcPosition) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True From 2ccad2a3588545351dc398d6e253ab930e4390f7 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 21 Jul 2018 19:52:28 -0400 Subject: [PATCH 07/95] Handle use case of moving a module from market to fitting view --- gui/builtinViews/fittingView.py | 28 ++++++++------------ gui/fitCommands/helpers.py | 3 +++ gui/fitCommands/moduleAdd.py | 45 ++++++++++++++++++++++++++------- gui/fitCommands/moduleRemove.py | 3 +-- 4 files changed, 51 insertions(+), 28 deletions(-) create mode 100644 gui/fitCommands/helpers.py diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index fab09726b..d74474bbd 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -361,6 +361,9 @@ class FittingView(d.Display): self.parent.SetPageTextIcon(pageIndex, text, bitmap) def appendItem(self, event): + ''' + Adds items that are double clicks from the market browser. We handle both modules and ammo + ''' if not self: event.Skip() return @@ -370,6 +373,7 @@ class FittingView(d.Display): if fitID is not None: sFit = Fit.getInstance() if sFit.isAmmo(itemID): + # If we've selected ammo, then apply to the selected module(s) modules = [] sel = self.GetFirstSelected() while sel != -1 and sel not in self.blanks: @@ -405,23 +409,17 @@ class FittingView(d.Display): self.mainFrame.command.Submit(cmd.FitModuleRemoveCommand(self.activeFitID, modules)) - def addModule(self, x, y, srcIdx): - """Add a module from the market browser""" + def addModule(self, x, y, itemID): + """Add a module from the market browser (from dragging it)""" dstRow, _ = self.HitTest((x, y)) if dstRow != -1 and dstRow not in self.blanks: - sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() mod = self.mods[dstRow] if not isinstance(mod, Module): # make sure we're not adding something to a T3D Mode return - moduleChanged = sFit.changeModule(fitID, self.mods[dstRow].modPosition, srcIdx) - if moduleChanged is None: - # the new module doesn't fit in specified slot, try to simply append it - wx.PostEvent(self.mainFrame, ItemSelected(itemID=srcIdx)) - - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit(), action="modadd", typeID=srcIdx)) + self.mainFrame.command.Submit(cmd.FitModuleAddCommand(fitID, itemID, self.mods[dstRow].modPosition)) def swapCargo(self, x, y, srcIdx): """Swap a module from cargo to fitting window""" @@ -449,18 +447,13 @@ class FittingView(d.Display): sFit = Fit.getInstance() fit = sFit.getFit(self.activeFitID) - if mstate.CmdDown(): - clone = True - else: - clone = False - dstRow, _ = self.HitTest((x, y)) if dstRow != -1 and dstRow not in self.blanks: - mod1 = fit.modules[srcIdx] mod2 = self.mods[dstRow] + if not isinstance(mod2, Module): return @@ -468,9 +461,11 @@ class FittingView(d.Display): if mod1.slot != mod2.slot: return + clone = mstate.CmdDown() and mod2.isEmpty + fitID = self.mainFrame.getActiveFit() if getattr(mod2, "modPosition") is not None: - self.mainFrame.command.Submit(cmd.FitModuleSwapOrCloneCommand(fitID, srcIdx, mod2.modPosition, clone and mod2.isEmpty)) + self.mainFrame.command.Submit(cmd.FitModuleSwapOrCloneCommand(fitID, srcIdx, mod2.modPosition, clone)) else: pyfalog.error("Missing module position for: {0}", str(getattr(mod2, "ID", "Unknown"))) @@ -626,7 +621,6 @@ class FittingView(d.Display): else: mods = self.getSelectedMods() - sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() ctrl = event.cmdDown or event.middleIsDown click = "ctrl" if ctrl is True else "right" if event.GetButton() == 3 else "left" diff --git a/gui/fitCommands/helpers.py b/gui/fitCommands/helpers.py new file mode 100644 index 000000000..81c862193 --- /dev/null +++ b/gui/fitCommands/helpers.py @@ -0,0 +1,3 @@ +from collections import namedtuple + +ModuleInfoCache = namedtuple('ModuleInfoCache', ['modPosition', 'itemID', 'state', 'charge']) diff --git a/gui/fitCommands/moduleAdd.py b/gui/fitCommands/moduleAdd.py index e5b038317..ee631cc65 100644 --- a/gui/fitCommands/moduleAdd.py +++ b/gui/fitCommands/moduleAdd.py @@ -3,29 +3,56 @@ from service.fit import Fit import gui.mainFrame from gui import globalEvents as GE +from .helpers import ModuleInfoCache class FitModuleAddCommand(wx.Command): - def __init__(self, fitID, itemID): + def __init__(self, fitID, itemID, position=None): wx.Command.__init__(self, True, "Module Add") # todo: evaluate mutaplasmid modules self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.sFit = Fit.getInstance() self.fitID = fitID self.itemID = itemID - self.new_position = None + self.new_position = position + self.old_mod = None def Do(self): - # todo: figure how not to add this command to stack if module doesn't fit correctly. - populate, self.new_position = self.sFit.appendModule(self.fitID, self.itemID) - if populate is not None: + change = None + + # 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 + 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) + + 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? wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="modadd", typeID=self.itemID)) - return True + return True + return False def Undo(self): - if (self.new_position): - # todo: self.slotsChanged() - result = self.sFit.removeModule(self.fitID, [self.new_position]) + 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)) return True diff --git a/gui/fitCommands/moduleRemove.py b/gui/fitCommands/moduleRemove.py index bc055cde6..b70423beb 100644 --- a/gui/fitCommands/moduleRemove.py +++ b/gui/fitCommands/moduleRemove.py @@ -5,8 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from collections import namedtuple -ModuleInfoCache = namedtuple('ModuleInfoCache', ['modPosition', 'itemID', 'state', 'charge']) - +from .helpers import ModuleInfoCache class FitModuleRemoveCommand(wx.Command): def __init__(self, fitID, modules): From d5aeb0913dac8f38ef56602da6cbd09275461679 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Tue, 24 Jul 2018 01:29:57 -0400 Subject: [PATCH 08/95] 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". --- gui/builtinContextMenus/itemRemove.py | 4 +- gui/builtinContextMenus/moduleAmmoPicker.py | 2 +- .../moduleGlobalAmmoPicker.py | 2 +- gui/builtinViews/fittingView.py | 12 +-- gui/fitCommands/__init__.py | 10 +-- gui/fitCommands/fitAddModule.py | 70 +++++++++++++++++ gui/fitCommands/fitRemoveModule.py | 57 ++++++++++++++ gui/fitCommands/fitReplaceModule.py | 77 +++++++++++++++++++ gui/fitCommands/moduleAdd.py | 47 +++++------ gui/fitCommands/moduleAddCharge.py | 2 +- gui/fitCommands/moduleRemove.py | 21 +++-- gui/fitCommands/moduleStateChange.py | 2 +- gui/fitCommands/moduleSwapOrClone.py | 2 +- service/fit.py | 5 +- utils/deprecated.py | 16 ++++ 15 files changed, 272 insertions(+), 57 deletions(-) create mode 100644 gui/fitCommands/fitAddModule.py create mode 100644 gui/fitCommands/fitRemoveModule.py create mode 100644 gui/fitCommands/fitReplaceModule.py create mode 100644 utils/deprecated.py diff --git a/gui/builtinContextMenus/itemRemove.py b/gui/builtinContextMenus/itemRemove.py index d6b8f79f1..c1c11fde5 100644 --- a/gui/builtinContextMenus/itemRemove.py +++ b/gui/builtinContextMenus/itemRemove.py @@ -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": diff --git a/gui/builtinContextMenus/moduleAmmoPicker.py b/gui/builtinContextMenus/moduleAmmoPicker.py index 59f6c3391..9b9a3a308 100644 --- a/gui/builtinContextMenus/moduleAmmoPicker.py +++ b/gui/builtinContextMenus/moduleAmmoPicker.py @@ -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() diff --git a/gui/builtinContextMenus/moduleGlobalAmmoPicker.py b/gui/builtinContextMenus/moduleGlobalAmmoPicker.py index 81bce6649..6f19aec96 100644 --- a/gui/builtinContextMenus/moduleGlobalAmmoPicker.py +++ b/gui/builtinContextMenus/moduleGlobalAmmoPicker.py @@ -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'): diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index d74474bbd..f57d54adc 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -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)]) diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index c9bbf25da..b3cb622fc 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -1,5 +1,5 @@ -from .moduleStateChange import FitModuleStateChangeCommand -from .moduleAdd import FitModuleAddCommand -from .moduleRemove import FitModuleRemoveCommand -from .moduleAddCharge import FitModuleAddChargeCommand -from .moduleSwapOrClone import FitModuleSwapOrCloneCommand \ No newline at end of file +from .moduleStateChange import GuiModuleStateChangeCommand +from .moduleAdd import GuiModuleAddCommand +from .moduleRemove import GuiModuleRemoveCommand +from .moduleAddCharge import GuiModuleAddChargeCommand +from .moduleSwapOrClone import GuiModuleSwapOrCloneCommand \ No newline at end of file diff --git a/gui/fitCommands/fitAddModule.py b/gui/fitCommands/fitAddModule.py new file mode 100644 index 000000000..8ff72ab74 --- /dev/null +++ b/gui/fitCommands/fitAddModule.py @@ -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 diff --git a/gui/fitCommands/fitRemoveModule.py b/gui/fitCommands/fitRemoveModule.py new file mode 100644 index 000000000..02d4c193b --- /dev/null +++ b/gui/fitCommands/fitRemoveModule.py @@ -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 diff --git a/gui/fitCommands/fitReplaceModule.py b/gui/fitCommands/fitReplaceModule.py new file mode 100644 index 000000000..0d9900b0e --- /dev/null +++ b/gui/fitCommands/fitReplaceModule.py @@ -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 diff --git a/gui/fitCommands/moduleAdd.py b/gui/fitCommands/moduleAdd.py index ee631cc65..a783c241d 100644 --- a/gui/fitCommands/moduleAdd.py +++ b/gui/fitCommands/moduleAdd.py @@ -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 diff --git a/gui/fitCommands/moduleAddCharge.py b/gui/fitCommands/moduleAddCharge.py index c125230b9..c696b51c5 100644 --- a/gui/fitCommands/moduleAddCharge.py +++ b/gui/fitCommands/moduleAddCharge.py @@ -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 diff --git a/gui/fitCommands/moduleRemove.py b/gui/fitCommands/moduleRemove.py index b70423beb..25ce96658 100644 --- a/gui/fitCommands/moduleRemove.py +++ b/gui/fitCommands/moduleRemove.py @@ -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 diff --git a/gui/fitCommands/moduleStateChange.py b/gui/fitCommands/moduleStateChange.py index c490115e2..340526972 100644 --- a/gui/fitCommands/moduleStateChange.py +++ b/gui/fitCommands/moduleStateChange.py @@ -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") diff --git a/gui/fitCommands/moduleSwapOrClone.py b/gui/fitCommands/moduleSwapOrClone.py index 65b6a10dc..58a3c00c5 100644 --- a/gui/fitCommands/moduleSwapOrClone.py +++ b/gui/fitCommands/moduleSwapOrClone.py @@ -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") diff --git a/service/fit.py b/service/fit.py index 1172cd2fb..c4c0c15e6 100644 --- a/service/fit.py +++ b/service/fit.py @@ -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) diff --git a/utils/deprecated.py b/utils/deprecated.py new file mode 100644 index 000000000..e7eeb9fad --- /dev/null +++ b/utils/deprecated.py @@ -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 From 9ccdb51063d1ea5aaee00687d931c03ffd6bc243 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Wed, 25 Jul 2018 00:58:11 -0400 Subject: [PATCH 09/95] remove some logging tweaks --- config.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/config.py b/config.py index fa073ad9d..750888659 100644 --- a/config.py +++ b/config.py @@ -229,19 +229,6 @@ def defLogging(): ) ]) - with logging_setup.threadbound(): - - # Output all stdout (print) messages as warnings - try: - sys.stdout = LoggerWriter(pyfalog.warning) - except: - pyfalog.critical("Cannot redirect. Continuing without writing stdout to log.") - - # Output all stderr (stacktrace) messages as critical - try: - sys.stderr = LoggerWriter(pyfalog.critical) - except: - pyfalog.critical("Cannot redirect. Continuing without writing stderr to log.") class LoggerWriter(object): From 65c568bd95778582fec2eaf7c6e9041a842c2b12 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Wed, 25 Jul 2018 22:02:44 -0400 Subject: [PATCH 10/95] Move some module state mapping definitions to the module file and add deprecation flags some sFit functions (will be moving to module / commands) --- eos/saveddata/module.py | 24 ++++++++++++++++++++++++ service/fit.py | 23 +++++------------------ 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/eos/saveddata/module.py b/eos/saveddata/module.py index d95afc5c6..d5a68bae3 100644 --- a/eos/saveddata/module.py +++ b/eos/saveddata/module.py @@ -64,6 +64,30 @@ class Slot(Enum): FS_HEAVY = 15 +ProjectedMap = { + State.OVERHEATED: State.ACTIVE, + State.ACTIVE: State.OFFLINE, + State.OFFLINE: State.ACTIVE, + State.ONLINE: State.ACTIVE # Just in case +} + + +# Old state : New State +LocalMap = { + State.OVERHEATED: State.ACTIVE, + State.ACTIVE: State.ONLINE, + State.OFFLINE: State.ONLINE, + State.ONLINE: State.ACTIVE +} + + +# For system effects. They should only ever be online or offline +ProjectedSystem = { + State.OFFLINE: State.ONLINE, + State.ONLINE: State.OFFLINE +} + + class Hardpoint(Enum): NONE = 0 MISSILE = 1 diff --git a/service/fit.py b/service/fit.py index c4c0c15e6..0f775b458 100644 --- a/service/fit.py +++ b/service/fit.py @@ -32,7 +32,7 @@ from eos.saveddata.drone import Drone as es_Drone from eos.saveddata.fighter import Fighter as es_Fighter from eos.saveddata.implant import Implant as es_Implant from eos.saveddata.ship import Ship as es_Ship -from eos.saveddata.module import Module as es_Module, State, Slot +from eos.saveddata.module import Module as es_Module, State, Slot, ProjectedMap, ProjectedSystem, LocalMap from eos.saveddata.fit import Fit as FitType, ImplantLocation from service.character import Character from service.damagePattern import DamagePattern @@ -1186,6 +1186,7 @@ class Fit(object): if changed: self.recalc(fit) + @deprecated def toggleModulesState(self, fitID, base, modules, click): pyfalog.debug("Toggle module state for fit ID: {0}", fitID) changed = False @@ -1210,31 +1211,17 @@ class Fit(object): # Then, check states of all modules and change where needed. This will recalc if needed self.checkStates(fit, base) - # Old state : New State - localMap = { - State.OVERHEATED: State.ACTIVE, - State.ACTIVE: State.ONLINE, - State.OFFLINE: State.ONLINE, - State.ONLINE: State.ACTIVE} - projectedMap = { - State.OVERHEATED: State.ACTIVE, - State.ACTIVE: State.OFFLINE, - State.OFFLINE: State.ACTIVE, - State.ONLINE: State.ACTIVE} # Just in case - # For system effects. They should only ever be online or offline - projectedSystem = { - State.OFFLINE: State.ONLINE, - State.ONLINE: State.OFFLINE} + @deprecated def __getProposedState(self, mod, click, proposedState=None): pyfalog.debug("Get proposed state for module.") if mod.slot == Slot.SUBSYSTEM or mod.isEmpty: return State.ONLINE if mod.slot == Slot.SYSTEM: - transitionMap = self.projectedSystem + transitionMap = ProjectedSystem else: - transitionMap = self.projectedMap if mod.projected else self.localMap + transitionMap = ProjectedMap if mod.projected else LocalMap currState = mod.state From 1f9024a740fe00c1586c9c6c7069e08bcd10815f Mon Sep 17 00:00:00 2001 From: blitzmann Date: Wed, 25 Jul 2018 22:06:53 -0400 Subject: [PATCH 11/95] Move `getProposedState`from fit service to module class --- eos/saveddata/module.py | 31 +++++++++++++++++++++++++++++++ service/fit.py | 33 +++------------------------------ 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/eos/saveddata/module.py b/eos/saveddata/module.py index d5a68bae3..a675b0fb0 100644 --- a/eos/saveddata/module.py +++ b/eos/saveddata/module.py @@ -29,6 +29,7 @@ from eos.enum import Enum from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut, ChargeAttrShortcut from eos.saveddata.citadel import Citadel from eos.saveddata.mutator import Mutator +from utils.deprecated import deprecated pyfalog = Logger(__name__) @@ -856,6 +857,36 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): else: return 0 + @staticmethod + def getProposedState(mod, click, proposedState=None): + # todo: instead of passing in module, make this a instanced function. + pyfalog.debug("Get proposed state for module.") + if mod.slot == Slot.SUBSYSTEM or mod.isEmpty: + return State.ONLINE + + if mod.slot == Slot.SYSTEM: + transitionMap = ProjectedSystem + else: + transitionMap = ProjectedMap if mod.projected else LocalMap + + currState = mod.state + + if proposedState is not None: + state = proposedState + elif click == "right": + state = State.OVERHEATED + elif click == "ctrl": + state = State.OFFLINE + else: + state = transitionMap[currState] + if not mod.isValidState(state): + state = -1 + + if mod.isValidState(state): + return state + else: + return currState + def __deepcopy__(self, memo): item = self.item if item is None: diff --git a/service/fit.py b/service/fit.py index 0f775b458..3b5513e5b 100644 --- a/service/fit.py +++ b/service/fit.py @@ -466,7 +466,7 @@ class Fit(object): elif isinstance(thing, es_Fighter): thing.active = not thing.active elif isinstance(thing, es_Module): - thing.state = self.__getProposedState(thing, click) + thing.state = es_Module.getProposedState(thing, click) if not thing.canHaveState(thing.state, fit): thing.state = State.OFFLINE elif isinstance(thing, FitType): @@ -1190,14 +1190,14 @@ class Fit(object): def toggleModulesState(self, fitID, base, modules, click): pyfalog.debug("Toggle module state for fit ID: {0}", fitID) changed = False - proposedState = self.__getProposedState(base, click) + proposedState = es_Module.getProposedState(base, click) if proposedState != base.state: changed = True base.state = proposedState for mod in modules: if mod != base: - p = self.__getProposedState(mod, click, proposedState) + p = es_Module.getProposedState(mod, click, proposedState) mod.state = p if p != mod.state: changed = True @@ -1212,34 +1212,7 @@ class Fit(object): self.checkStates(fit, base) - @deprecated - def __getProposedState(self, mod, click, proposedState=None): - pyfalog.debug("Get proposed state for module.") - if mod.slot == Slot.SUBSYSTEM or mod.isEmpty: - return State.ONLINE - if mod.slot == Slot.SYSTEM: - transitionMap = ProjectedSystem - else: - transitionMap = ProjectedMap if mod.projected else LocalMap - - currState = mod.state - - if proposedState is not None: - state = proposedState - elif click == "right": - state = State.OVERHEATED - elif click == "ctrl": - state = State.OFFLINE - else: - state = transitionMap[currState] - if not mod.isValidState(state): - state = -1 - - if mod.isValidState(state): - return state - else: - return currState def refreshFit(self, fitID): pyfalog.debug("Refresh fit for fit ID: {0}", fitID) From dd6fe01df5cc41d6cc1ac49f3da90bf277511795 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Wed, 25 Jul 2018 22:24:57 -0400 Subject: [PATCH 12/95] Migrate module state change to gui/fit command pattern --- gui/fitCommands/fitChangeState.py | 61 ++++++++++++++++++++++++++++ gui/fitCommands/moduleRemove.py | 1 - gui/fitCommands/moduleStateChange.py | 21 ++++------ 3 files changed, 68 insertions(+), 15 deletions(-) create mode 100644 gui/fitCommands/fitChangeState.py diff --git a/gui/fitCommands/fitChangeState.py b/gui/fitCommands/fitChangeState.py new file mode 100644 index 000000000..c800e030e --- /dev/null +++ b/gui/fitCommands/fitChangeState.py @@ -0,0 +1,61 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from logbook import Logger +from eos.saveddata.module import Module +pyfalog = Logger(__name__) +import eos.db + +class FitChangeStatesCommand(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") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.fitID = fitID + self.baseMod = baseMod + self.modules = modules + self.click = click + self.changed = None + self.old_states = {} + for mod in modules: + # we don't use the actual module as the key, because it may have been deleted in subsequent calls (even if + # we undo a deletion, wouldn't be the same obj). So, we store the position + self.old_states[mod.modPosition] = mod.state + + def Do(self): + # todo: determine if we've changed state (recalc). If not, store that so we don't attempt to recalc on undo + # self.sFit.toggleModulesState(self.fitID, self.baseMod, self.modules, self.click) + + pyfalog.debug("Toggle module state for fit ID: {0}", self.fitID) + changed = False + proposedState = Module.getProposedState(self.baseMod, self.click) + + if proposedState != self.baseMod.state: + changed = True + self.baseMod.state = proposedState + for mod in self.modules: + if mod != self.baseMod: + p = Module.getProposedState(mod, self.click, proposedState) + mod.state = p + if p != mod.state: + changed = True + + if changed: + self.changed = changed + eos.db.commit() + # 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, base) + return True + return False + + def Undo(self): + # todo: some sanity checking to make sure that we are applying state back to the same modules? + fit = self.sFit.getFit(self.fitID) + for k, v in self.old_states.items(): + fit.modules[k].state = v + return True diff --git a/gui/fitCommands/moduleRemove.py b/gui/fitCommands/moduleRemove.py index 25ce96658..bcf2cf139 100644 --- a/gui/fitCommands/moduleRemove.py +++ b/gui/fitCommands/moduleRemove.py @@ -3,7 +3,6 @@ from service.fit import Fit import gui.mainFrame from gui import globalEvents as GE -from collections import namedtuple from .helpers import ModuleInfoCache from .fitRemoveModule import FitRemoveModuleCommand diff --git a/gui/fitCommands/moduleStateChange.py b/gui/fitCommands/moduleStateChange.py index 340526972..167777bd1 100644 --- a/gui/fitCommands/moduleStateChange.py +++ b/gui/fitCommands/moduleStateChange.py @@ -3,7 +3,7 @@ from service.fit import Fit import gui.mainFrame from gui import globalEvents as GE - +from .fitChangeState import FitChangeStatesCommand class GuiModuleStateChangeCommand(wx.Command): def __init__(self, fitID, baseMod, modules, click): @@ -15,24 +15,17 @@ class GuiModuleStateChangeCommand(wx.Command): self.baseMod = baseMod self.modules = modules self.click = click - - self.old_states = {} - for mod in modules: - # we don't use the actual module as the key, because it may have been deleted in subsequent calls (even if - # we undo a deletion, wouldn't be the same obj). So, we store the position - self.old_states[mod.modPosition] = mod.state + self.internal_history = wx.CommandProcessor() def Do(self): # todo: determine if we've changed state (recalc). If not, store that so we don't attempt to recalc on undo - self.sFit.toggleModulesState(self.fitID, self.baseMod, self.modules, self.click) + self.internal_history.Submit(FitChangeStatesCommand(self.fitID, self.baseMod, self.modules, self.click)) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True def Undo(self): - # todo: some sanity checking to make sure that we are applying state back to the same modules? - fit = self.sFit.getFit(self.fitID) - for k, v in self.old_states.items(): - fit.modules[k].state = v - self.sFit.recalc(fit) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + for x in self.internal_history.Commands: + self.internal_history.Undo() + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True + From 53f6d431094fd2f49c3538048e953badac5b3cd2 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Wed, 25 Jul 2018 22:49:09 -0400 Subject: [PATCH 13/95] Migrate over the ammo setting stuff to fit/gui commands --- gui/fitCommands/fitSetCharge.py | 44 ++++++++++++++++++++++++++++++ gui/fitCommands/moduleAddCharge.py | 25 ++++++++--------- service/fit.py | 1 + 3 files changed, 57 insertions(+), 13 deletions(-) create mode 100644 gui/fitCommands/fitSetCharge.py diff --git a/gui/fitCommands/fitSetCharge.py b/gui/fitCommands/fitSetCharge.py new file mode 100644 index 000000000..0ae8a80fd --- /dev/null +++ b/gui/fitCommands/fitSetCharge.py @@ -0,0 +1,44 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from eos.saveddata.module import Module +from logbook import Logger +pyfalog = Logger(__name__) +import eos.db + +class FitSetChargeCommand(wx.Command): + def __init__(self, fitID, modules, chargeID=None): + # todo: determine if this command really should be used with a group of modules, or a simple per module basis + wx.Command.__init__(self, True, "Module Charge Add") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.fitID = fitID + self.chargeID = chargeID + self.modules = modules + self.positions = {mod.modPosition: mod.chargeID for mod in modules} + + def Do(self): + pyfalog.debug("Set ammo for fit ID: {0}", self.fitID) + if self.fitID is None: + return False + return self.__setAmmo(self.modules, self.chargeID) + + def Undo(self): + fit = eos.db.getFit(self.fitID) + for position, chargeID in self.positions.items(): + self.__setAmmo([fit.modules[position]], chargeID) + return True + + @staticmethod + def __setAmmo(modules, chargeID): + ammo = eos.db.getItem(chargeID) if chargeID else None + result = False + + for mod in modules: + if mod.isValidCharge(ammo): + result = True + mod.charge = ammo + eos.db.commit() + return result \ No newline at end of file diff --git a/gui/fitCommands/moduleAddCharge.py b/gui/fitCommands/moduleAddCharge.py index c696b51c5..7dd4ba6ec 100644 --- a/gui/fitCommands/moduleAddCharge.py +++ b/gui/fitCommands/moduleAddCharge.py @@ -3,28 +3,27 @@ from service.fit import Fit import gui.mainFrame from gui import globalEvents as GE - +from .fitSetCharge import FitSetChargeCommand class GuiModuleAddChargeCommand(wx.Command): def __init__(self, fitID, itemID, modules): wx.Command.__init__(self, True, "Module Charge Add") - # todo: evaluate mutaplasmid modules self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() self.fitID = fitID - self.itemID = itemID - self.positions = {mod.modPosition: mod.chargeID for mod in modules} + # can set his up no to not have to set variables on our object + self.cmd = FitSetChargeCommand(fitID, modules, itemID) def Do(self): - fit = self.sFit.getFit(self.fitID) - self.sFit.setAmmo(self.fitID, self.itemID, [fit.modules[i] for i in self.positions.keys()]) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) - return True + if self.internal_history.Submit(self.cmd): + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False def Undo(self): - fit = self.sFit.getFit(self.fitID) - for position, chargeID in self.positions.items(): - self.sFit.setAmmo(self.fitID, chargeID, [fit.modules[position]], False) - self.sFit.recalc(self.fitID) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + for x in self.internal_history.Commands: + self.internal_history.Undo() + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True + diff --git a/service/fit.py b/service/fit.py index 3b5513e5b..b0bf81df0 100644 --- a/service/fit.py +++ b/service/fit.py @@ -1077,6 +1077,7 @@ class Fit(object): def isAmmo(itemID): return eos.db.getItem(itemID).category.name == "Charge" + @deprecated def setAmmo(self, fitID, ammoID, modules, recalc=True): pyfalog.debug("Set ammo for fit ID: {0}", fitID) if fitID is None: From 0d32b60f7eb757a760bd39f4da231ef78dbb2e56 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Thu, 26 Jul 2018 00:31:38 -0400 Subject: [PATCH 14/95] Convert module swap / clone to fit / gui commands --- gui/fitCommands/fitCloneModule.py | 49 ++++++++++++++++++++++++++++ gui/fitCommands/fitSwapModule.py | 44 +++++++++++++++++++++++++ gui/fitCommands/moduleSwapOrClone.py | 22 +++++++------ service/fit.py | 2 ++ 4 files changed, 107 insertions(+), 10 deletions(-) create mode 100644 gui/fitCommands/fitCloneModule.py create mode 100644 gui/fitCommands/fitSwapModule.py diff --git a/gui/fitCommands/fitCloneModule.py b/gui/fitCommands/fitCloneModule.py new file mode 100644 index 000000000..b126c5063 --- /dev/null +++ b/gui/fitCommands/fitCloneModule.py @@ -0,0 +1,49 @@ +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__) +import copy + +class FitCloneModduleCommand(wx.Command): + """ + Clone a module from src to dst + This will overwrite dst! Checking for empty module must be + done at a higher level + + from sFit.cloneModule + """ + def __init__(self, fitID, src, dst): + wx.Command.__init__(self, True, "Module Clone") + self.fitID = fitID + self.src = src + self.dst = dst + + def Do(self): + pyfalog.debug("Cloning modules from source ({0}) to destination ({1}) for fit ID: {1}", self.src, self.dst, self.fitID) + fit = eos.db.getFit(self.fitID) + # Gather modules + srcMod = fit.modules[self.src] + dstMod = fit.modules[self.dst] # should be a placeholder module + + new = copy.deepcopy(srcMod) + new.owner = fit + if new.fits(fit): + # insert copy if module meets hardpoint restrictions + fit.modules.remove(dstMod) + fit.modules.insert(self.dst, new) + + eos.db.commit() + return True + return False + + def Undo(self): + from .fitRemoveModule import FitRemoveModuleCommand # Avoid circular import + cmd = FitRemoveModuleCommand(self.fitID, [self.dst]) + cmd.Do() + return True diff --git a/gui/fitCommands/fitSwapModule.py b/gui/fitCommands/fitSwapModule.py new file mode 100644 index 000000000..8f5ff4212 --- /dev/null +++ b/gui/fitCommands/fitSwapModule.py @@ -0,0 +1,44 @@ +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 FitSwapModuleCommand(wx.Command): + """" + from sFit.swapModules + """ + def __init__(self, fitID, src, dst): + wx.Command.__init__(self, True, "Module Swap") + self.fitID = fitID + self.src = src + self.dst = dst + + def Do(self): + self.__swap(self.fitID, self.src, self.dst) + return True + + def Undo(self): + self.__swap(self.fitID, self.dst, self.src) + return True + + def __swap(self, fitID, src, dst): + pyfalog.debug("Swapping modules from source ({0}) to destination ({1}) for fit ID: {1}", src, dst, fitID) + fit = eos.db.getFit(fitID) + # Gather modules + srcMod = fit.modules[src] + dstMod = fit.modules[dst] + + # To swap, we simply remove mod and insert at destination. + fit.modules.remove(srcMod) + fit.modules.insert(dst, srcMod) + fit.modules.remove(dstMod) + fit.modules.insert(src, dstMod) + + eos.db.commit() diff --git a/gui/fitCommands/moduleSwapOrClone.py b/gui/fitCommands/moduleSwapOrClone.py index 58a3c00c5..799b7a915 100644 --- a/gui/fitCommands/moduleSwapOrClone.py +++ b/gui/fitCommands/moduleSwapOrClone.py @@ -3,7 +3,8 @@ from service.fit import Fit import gui.mainFrame from gui import globalEvents as GE - +from .fitSwapModule import FitSwapModuleCommand +from .fitCloneModule import FitCloneModduleCommand class GuiModuleSwapOrCloneCommand(wx.Command): def __init__(self, fitID, srcPosition, dstPosition, clone=False): @@ -15,20 +16,21 @@ class GuiModuleSwapOrCloneCommand(wx.Command): self.srcPosition = srcPosition self.dstPosition = dstPosition self.clone = clone + self.internal_history = wx.CommandProcessor() def Do(self): + result = None if self.clone: - self.sFit.cloneModule(self.fitID, self.srcPosition, self.dstPosition) + result = self.internal_history.Submit(FitCloneModduleCommand(self.fitID, self.srcPosition, self.dstPosition)) else: - self.sFit.swapModules(self.fitID, self.srcPosition, self.dstPosition) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) - return True + result = self.internal_history.Submit(FitSwapModuleCommand(self.fitID, self.srcPosition, self.dstPosition)) + + if result: + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return result def Undo(self): - if self.clone: - # if we had cloned, the destinations was originally an empty slot, hence we can just remove the module - self.sFit.removeModule(self.fitID, [self.dstPosition]) - else: - self.sFit.swapModules(self.fitID, self.dstPosition, self.srcPosition) + for _ in self.internal_history.Commands: + self.internal_history.Undo() wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True diff --git a/service/fit.py b/service/fit.py index b0bf81df0..d4bd396dc 100644 --- a/service/fit.py +++ b/service/fit.py @@ -736,6 +736,7 @@ class Fit(object): self.recalc(fit) @staticmethod + @deprecated def swapModules(fitID, src, dst): pyfalog.debug("Swapping modules from source ({0}) to destination ({1}) for fit ID: {1}", src, dst, fitID) fit = eos.db.getFit(fitID) @@ -751,6 +752,7 @@ class Fit(object): eos.db.commit() + @deprecated def cloneModule(self, fitID, src, dst): """ Clone a module from src to dst From 7f8ad3885d3ef80a7df9966927db2829a5c141be Mon Sep 17 00:00:00 2001 From: blitzmann Date: Thu, 26 Jul 2018 01:16:29 -0400 Subject: [PATCH 15/95] Create isCharge property --- eos/gamedata.py | 4 ++++ gui/fitCommands/moduleAdd.py | 2 ++ service/fit.py | 3 ++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/eos/gamedata.py b/eos/gamedata.py index 7c7f85b8f..0fc9482e2 100644 --- a/eos/gamedata.py +++ b/eos/gamedata.py @@ -476,6 +476,10 @@ class Item(EqBase): def getAbyssalYypes(cls): cls.ABYSSAL_TYPES = eos.db.getAbyssalTypes() + @property + def isCharge(self): + return self.category.name == "Charge" + def __repr__(self): return "Item(ID={}, name={}) at {}".format( self.ID, self.name, hex(id(self)) diff --git a/gui/fitCommands/moduleAdd.py b/gui/fitCommands/moduleAdd.py index a783c241d..e035dbfd0 100644 --- a/gui/fitCommands/moduleAdd.py +++ b/gui/fitCommands/moduleAdd.py @@ -22,6 +22,8 @@ class GuiModuleAddCommand(wx.Command): def Do(self): success = False # if we have a position set, try to apply the module to that position + + # todo: check to see if item is a charge. if it is, dont try to add module, but instead set amm if self.new_position: success = self.internal_history.Submit(FitReplaceModuleCommand(self.fitID, self.new_position, self.itemID)) if not success: diff --git a/service/fit.py b/service/fit.py index d4bd396dc..175292666 100644 --- a/service/fit.py +++ b/service/fit.py @@ -1077,7 +1077,8 @@ class Fit(object): @staticmethod def isAmmo(itemID): - return eos.db.getItem(itemID).category.name == "Charge" + # todo: get rid of this form the service, use directly from item + return eos.db.getItem(itemID).isCharge @deprecated def setAmmo(self, fitID, ammoID, modules, recalc=True): From b724e5bec1b835e721067f7f6a84c91610dc83b9 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Fri, 27 Jul 2018 00:43:47 -0400 Subject: [PATCH 16/95] Set up commands for adding/removing cargo --- gui/builtinContextMenus/cargo.py | 6 +-- gui/builtinContextMenus/itemRemove.py | 3 +- gui/fitCommands/__init__.py | 6 ++- gui/fitCommands/fitAddCargo.py | 48 ++++++++++++++++++++++++ gui/fitCommands/fitRemoveCargo.py | 53 +++++++++++++++++++++++++++ gui/fitCommands/fitSetCharge.py | 2 +- gui/fitCommands/guiAddCargo.py | 29 +++++++++++++++ gui/fitCommands/guiRemoveCargo.py | 29 +++++++++++++++ service/fit.py | 3 ++ 9 files changed, 173 insertions(+), 6 deletions(-) create mode 100644 gui/fitCommands/fitAddCargo.py create mode 100644 gui/fitCommands/fitRemoveCargo.py create mode 100644 gui/fitCommands/guiAddCargo.py create mode 100644 gui/fitCommands/guiRemoveCargo.py diff --git a/gui/builtinContextMenus/cargo.py b/gui/builtinContextMenus/cargo.py index 32d6370cf..a0b1c6e80 100644 --- a/gui/builtinContextMenus/cargo.py +++ b/gui/builtinContextMenus/cargo.py @@ -5,6 +5,7 @@ import gui.globalEvents as GE import wx from service.fit import Fit from service.settings import ContextMenuSettings +import gui.fitCommands as cmd class Cargo(ContextMenu): @@ -32,13 +33,12 @@ class Cargo(ContextMenu): return "Add {0} to Cargo".format(itmContext) def activate(self, fullContext, selection, i): - sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() typeID = int(selection[0].ID) - sFit.addCargo(fitID, typeID) + + self.mainFrame.command.Submit(cmd.GuiAddCargoCommand(fitID, typeID)) self.mainFrame.additionsPane.select("Cargo") - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) Cargo.register() diff --git a/gui/builtinContextMenus/itemRemove.py b/gui/builtinContextMenus/itemRemove.py index c1c11fde5..9eb741dda 100644 --- a/gui/builtinContextMenus/itemRemove.py +++ b/gui/builtinContextMenus/itemRemove.py @@ -49,7 +49,8 @@ class ItemRemove(ContextMenu): elif srcContext == "boosterItem": sFit.removeBooster(fitID, fit.boosters.index(selection[0])) elif srcContext == "cargoItem": - sFit.removeCargo(fitID, fit.cargo.index(selection[0])) + self.mainFrame.command.Submit(cmd.GuiRemoveCargoCommand(fitID, selection[0].itemID)) + return # the command takes care of the PostEvent elif srcContext in ("projectedFit", "projectedModule", "projectedDrone", "projectedFighter"): sFit.removeProjected(fitID, selection[0]) elif srcContext == "commandFit": diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index b3cb622fc..7e74e568e 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -2,4 +2,8 @@ from .moduleStateChange import GuiModuleStateChangeCommand from .moduleAdd import GuiModuleAddCommand from .moduleRemove import GuiModuleRemoveCommand from .moduleAddCharge import GuiModuleAddChargeCommand -from .moduleSwapOrClone import GuiModuleSwapOrCloneCommand \ No newline at end of file +from .moduleSwapOrClone import GuiModuleSwapOrCloneCommand +from .guiRemoveCargo import GuiRemoveCargoCommand +from .guiAddCargo import GuiAddCargoCommand +from .fitAddCargo import FitAddCargoCommand +from .fitRemoveCargo import FitRemoveCargoCommand \ No newline at end of file diff --git a/gui/fitCommands/fitAddCargo.py b/gui/fitCommands/fitAddCargo.py new file mode 100644 index 000000000..85bfae3eb --- /dev/null +++ b/gui/fitCommands/fitAddCargo.py @@ -0,0 +1,48 @@ +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__) +from eos.saveddata.cargo import Cargo + +class FitAddCargoCommand(wx.Command): + """" + from sFit.addCargo + """ + def __init__(self, fitID, itemID, amount=1, replace=False): + wx.Command.__init__(self, True, "Cargo add") + self.fitID = fitID + self.itemID = itemID + self.amount = amount # add x amount. If this goes over amount, removes stack + self.replace = replace # if this is false, we increment. + + def Do(self): + pyfalog.debug("Adding cargo {0} (x{1}) for fit {2}", self.itemID, self.amount, self.fitID) + + fit = eos.db.getFit(self.fitID) + item = eos.db.getItem(self.itemID) + + cargo = next((x for x in fit.cargo if x.itemID == self.itemID), None) + + if cargo is None: + cargo = Cargo(item) + fit.cargo.append(cargo) + + if self.replace: + cargo.amount = self.amount + else: + cargo.amount += self.amount + + eos.db.commit() + return True + + def Undo(self): + from .fitRemoveCargo import FitRemoveCargoCommand # Avoid circular import + cmd = FitRemoveCargoCommand(self.fitID, self.itemID, self.amount) + cmd.Do() + return True diff --git a/gui/fitCommands/fitRemoveCargo.py b/gui/fitCommands/fitRemoveCargo.py new file mode 100644 index 000000000..41fb57b9e --- /dev/null +++ b/gui/fitCommands/fitRemoveCargo.py @@ -0,0 +1,53 @@ +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 FitRemoveCargoCommand(wx.Command): + """" + Fitting command that sets the amount for an item within the cargo. + + from sFit.removeCargo + """ + def __init__(self, fitID, itemID, amount=1, stack=False): + wx.Command.__init__(self, True, "Cargo remove") + self.fitID = fitID + self.itemID = itemID + self.stack = stack # remove entire stack + self.amount = amount # remove x amount. If this goes over amount, removes stack + self.old_amount = None + + def Do(self): + pyfalog.debug("Removing cargo {0} (x{1}) for fit {2}", self.itemID, self.amount, self.fitID) + fit = eos.db.getFit(self.fitID) + cargo = next((x for x in fit.cargo if x.itemID == self.itemID), None) + + if cargo is None: + return False + + self.old_amount = cargo.amount + + if self.amount >= cargo.amount: + self.stack = True # set to full stack, this allows easier logic in the Undo function + + if self.stack or self.amount >= cargo.amount: + fit.cargo.remove(cargo) + eos.db.commit() + return True + + cargo.amount -= self.amount + eos.db.commit() + return True + + def Undo(self): + from .fitAddCargo import FitAddCargoCommand # Avoid circular import + cmd = FitAddCargoCommand(self.fitID, self.itemID, self.old_amount, True) + cmd.Do() + return True diff --git a/gui/fitCommands/fitSetCharge.py b/gui/fitCommands/fitSetCharge.py index 0ae8a80fd..111959a18 100644 --- a/gui/fitCommands/fitSetCharge.py +++ b/gui/fitCommands/fitSetCharge.py @@ -37,7 +37,7 @@ class FitSetChargeCommand(wx.Command): result = False for mod in modules: - if mod.isValidCharge(ammo): + if not mod.isEmpty and mod.isValidCharge(ammo): result = True mod.charge = ammo eos.db.commit() diff --git a/gui/fitCommands/guiAddCargo.py b/gui/fitCommands/guiAddCargo.py new file mode 100644 index 000000000..98491505c --- /dev/null +++ b/gui/fitCommands/guiAddCargo.py @@ -0,0 +1,29 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from .fitAddCargo import FitAddCargoCommand + +class GuiAddCargoCommand(wx.Command): + def __init__(self, fitID, itemID): + wx.Command.__init__(self, True, "Cargo Add") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() + self.fitID = fitID + # can set his up no to not have to set variables on our object + self.cmd = FitAddCargoCommand(fitID, itemID) + + def Do(self): + if self.internal_history.Submit(self.cmd): + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for x in self.internal_history.Commands: + self.internal_history.Undo() + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + diff --git a/gui/fitCommands/guiRemoveCargo.py b/gui/fitCommands/guiRemoveCargo.py new file mode 100644 index 000000000..f86b607d2 --- /dev/null +++ b/gui/fitCommands/guiRemoveCargo.py @@ -0,0 +1,29 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from .fitRemoveCargo import FitRemoveCargoCommand + +class GuiRemoveCargoCommand(wx.Command): + def __init__(self, fitID, itemID): + wx.Command.__init__(self, True, "Module Charge Add") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() + self.fitID = fitID + # can set his up no to not have to set variables on our object + self.cmd = FitRemoveCargoCommand(fitID, itemID, stack=True) + + def Do(self): + if self.internal_history.Submit(self.cmd): + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for x in self.internal_history.Commands: + self.internal_history.Undo() + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + diff --git a/service/fit.py b/service/fit.py index 175292666..746990daf 100644 --- a/service/fit.py +++ b/service/fit.py @@ -672,6 +672,7 @@ class Fit(object): else: return None + @deprecated def moveCargoToModule(self, fitID, moduleIdx, cargoIdx, copyMod=False): """ Moves cargo to fitting window. Can either do a copy, move, or swap with current module @@ -775,6 +776,7 @@ class Fit(object): eos.db.commit() self.recalc(fit) + @deprecated def addCargo(self, fitID, itemID, amount=1, replace=False): """ Adds cargo via typeID of item. If replace = True, we replace amount with @@ -812,6 +814,7 @@ class Fit(object): return True + @deprecated def removeCargo(self, fitID, position): pyfalog.debug("Removing cargo from position ({0}) fit ID: {1}", position, fitID) if fitID is None: From dd430bc9bbe39290a1010ba152a2e3b4dd235ee3 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Fri, 27 Jul 2018 23:54:41 -0400 Subject: [PATCH 17/95] Implant and cargo conversions --- gui/builtinAdditionPanes/cargoView.py | 5 ++- gui/builtinAdditionPanes/implantView.py | 11 ++----- gui/builtinContextMenus/amount.py | 5 +-- gui/builtinContextMenus/cargoAmmo.py | 7 ++--- gui/builtinContextMenus/itemRemove.py | 3 +- gui/builtinContextMenus/metaSwap.py | 14 +++++---- gui/fitCommands/__init__.py | 4 ++- gui/fitCommands/fitAddImplant.py | 41 +++++++++++++++++++++++++ gui/fitCommands/fitRemoveImplant.py | 38 +++++++++++++++++++++++ gui/fitCommands/guiAddCargo.py | 4 +-- gui/fitCommands/guiAddImplant.py | 29 +++++++++++++++++ gui/fitCommands/guiRemoveImplant.py | 29 +++++++++++++++++ service/fit.py | 2 ++ 13 files changed, 164 insertions(+), 28 deletions(-) create mode 100644 gui/fitCommands/fitAddImplant.py create mode 100644 gui/fitCommands/fitRemoveImplant.py create mode 100644 gui/fitCommands/guiAddImplant.py create mode 100644 gui/fitCommands/guiRemoveImplant.py diff --git a/gui/builtinAdditionPanes/cargoView.py b/gui/builtinAdditionPanes/cargoView.py index a5b94f31b..2b385c72a 100644 --- a/gui/builtinAdditionPanes/cargoView.py +++ b/gui/builtinAdditionPanes/cargoView.py @@ -26,6 +26,7 @@ import gui.globalEvents as GE from gui.utils.staticHelpers import DragDropHelper from service.fit import Fit from service.market import Market +import gui.fitCommands as cmd class CargoViewDrop(wx.DropTarget): @@ -80,9 +81,7 @@ class CargoView(d.Display): if data[0] == "fitting": self.swapModule(x, y, int(data[1])) elif data[0] == "market": - sFit = Fit.getInstance() - sFit.addCargo(self.mainFrame.getActiveFit(), int(data[1]), 1) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit())) + self.mainFrame.command.Submit(cmd.GuiAddCargoCommand(self.mainFrame.getActiveFit(), int(data[1]))) def startDrag(self, event): row = event.GetIndex() diff --git a/gui/builtinAdditionPanes/implantView.py b/gui/builtinAdditionPanes/implantView.py index b1d7bbe66..7144d6cb5 100644 --- a/gui/builtinAdditionPanes/implantView.py +++ b/gui/builtinAdditionPanes/implantView.py @@ -28,7 +28,7 @@ import gui.globalEvents as GE from eos.saveddata.fit import ImplantLocation from service.fit import Fit from service.market import Market - +import gui.fitCommands as cmd class ImplantView(wx.Panel): def __init__(self, parent): @@ -155,9 +155,7 @@ class ImplantDisplay(d.Display): event.Skip() return - trigger = sFit.addImplant(fitID, event.itemID) - if trigger: - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + if self.mainFrame.command.Submit(cmd.GuiAddImplantCommand(fitID, event.itemID)): self.mainFrame.additionsPane.select("Implants") event.Skip() @@ -175,10 +173,7 @@ class ImplantDisplay(d.Display): def removeImplant(self, implant): fitID = self.mainFrame.getActiveFit() - sFit = Fit.getInstance() - - sFit.removeImplant(fitID, self.original.index(implant)) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.GuiRemoveImplantCommand(fitID, self.original.index(implant))) def click(self, event): event.Skip() diff --git a/gui/builtinContextMenus/amount.py b/gui/builtinContextMenus/amount.py index ed23e606a..eec575f29 100644 --- a/gui/builtinContextMenus/amount.py +++ b/gui/builtinContextMenus/amount.py @@ -9,7 +9,7 @@ from service.fit import Fit from eos.saveddata.cargo import Cargo as es_Cargo from eos.saveddata.fighter import Fighter as es_Fighter from service.settings import ContextMenuSettings - +import gui.fitCommands as cmd class ChangeAmount(ContextMenu): def __init__(self): @@ -45,7 +45,8 @@ class ChangeAmount(ContextMenu): cleanInput = re.sub(r'[^0-9.]', '', dlg.input.GetLineText(0).strip()) if isinstance(thing, es_Cargo): - sFit.addCargo(fitID, thing.item.ID, int(float(cleanInput)), replace=True) + self.mainFrame.command.Submit(cmd.GuiAddCargoCommand(fitID, thing.item.ID, int(float(cleanInput)), replace=True)) + return # no need for post event here elif isinstance(thing, es_Fit): sFit.changeAmount(fitID, thing, int(float(cleanInput))) elif isinstance(thing, es_Fighter): diff --git a/gui/builtinContextMenus/cargoAmmo.py b/gui/builtinContextMenus/cargoAmmo.py index 12ebe552f..e80801975 100644 --- a/gui/builtinContextMenus/cargoAmmo.py +++ b/gui/builtinContextMenus/cargoAmmo.py @@ -4,7 +4,7 @@ import gui.globalEvents as GE import wx from service.settings import ContextMenuSettings from service.fit import Fit - +import gui.fitCommands as cmd class CargoAmmo(ContextMenu): def __init__(self): @@ -28,13 +28,10 @@ class CargoAmmo(ContextMenu): return "Add {0} to Cargo (x1000)".format(itmContext) def activate(self, fullContext, selection, i): - sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() - typeID = int(selection[0].ID) - sFit.addCargo(fitID, typeID, 1000) + self.mainFrame.command.Submit(cmd.GuiAddCargoCommand(fitID, typeID, 1000)) self.mainFrame.additionsPane.select("Cargo") - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) CargoAmmo.register() diff --git a/gui/builtinContextMenus/itemRemove.py b/gui/builtinContextMenus/itemRemove.py index 9eb741dda..b3cb414b5 100644 --- a/gui/builtinContextMenus/itemRemove.py +++ b/gui/builtinContextMenus/itemRemove.py @@ -45,7 +45,8 @@ class ItemRemove(ContextMenu): elif srcContext == "fighterItem": sFit.removeFighter(fitID, fit.fighters.index(selection[0])) elif srcContext == "implantItem": - sFit.removeImplant(fitID, fit.implants.index(selection[0])) + self.mainFrame.command.Submit(cmd.GuiRemoveImplantCommand(fitID, fit.implants.index(selection[0]))) + return # the command takes care of the PostEvent elif srcContext == "boosterItem": sFit.removeBooster(fitID, fit.boosters.index(selection[0])) elif srcContext == "cargoItem": diff --git a/gui/builtinContextMenus/metaSwap.py b/gui/builtinContextMenus/metaSwap.py index a5f6371e3..7956848f8 100644 --- a/gui/builtinContextMenus/metaSwap.py +++ b/gui/builtinContextMenus/metaSwap.py @@ -15,7 +15,7 @@ from eos.saveddata.drone import Drone from eos.saveddata.fighter import Fighter from eos.saveddata.implant import Implant from eos.saveddata.cargo import Cargo - +import gui.fitCommands as cmd class MetaSwap(ContextMenu): def __init__(self): @@ -183,16 +183,18 @@ class MetaSwap(ContextMenu): elif isinstance(selected_item, Implant): for idx, implant_stack in enumerate(fit.implants): if implant_stack is selected_item: - sFit.removeImplant(fitID, idx, False) - sFit.addImplant(fitID, item.ID, True) - break + self.mainFrame.command.Submit(cmd.GuiRemoveImplantCommand(fitID, idx)) + self.mainFrame.command.Submit(cmd.GuiAddImplantCommand(fitID, item.ID)) + return elif isinstance(selected_item, Cargo): for idx, cargo_stack in enumerate(fit.cargo): if cargo_stack is selected_item: + # todo: make a command to change varieance of all items, or maybe per item type, which would + # utilize the two fitting commands that we need to remove then add? sFit.removeCargo(fitID, idx) - sFit.addCargo(fitID, item.ID, cargo_stack.amount, True) - break + self.mainFrame.command.Submit(cmd.GuiAddCargoCommand(fitID, item.ID, cargo_stack.amount, True)) + return # don't need the post event wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index 7e74e568e..c3507a7e6 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -6,4 +6,6 @@ from .moduleSwapOrClone import GuiModuleSwapOrCloneCommand from .guiRemoveCargo import GuiRemoveCargoCommand from .guiAddCargo import GuiAddCargoCommand from .fitAddCargo import FitAddCargoCommand -from .fitRemoveCargo import FitRemoveCargoCommand \ No newline at end of file +from .fitRemoveCargo import FitRemoveCargoCommand +from .guiRemoveImplant import GuiRemoveImplantCommand +from .guiAddImplant import GuiAddImplantCommand \ No newline at end of file diff --git a/gui/fitCommands/fitAddImplant.py b/gui/fitCommands/fitAddImplant.py new file mode 100644 index 000000000..91bc5be61 --- /dev/null +++ b/gui/fitCommands/fitAddImplant.py @@ -0,0 +1,41 @@ +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__) +from eos.saveddata.implant import Implant + +class FitAddImplantCommand(wx.Command): + """" + from sFit.addImplant + """ + def __init__(self, fitID, itemID): + wx.Command.__init__(self, True, "Cargo add") + self.fitID = fitID + self.itemID = itemID + + def Do(self): + pyfalog.debug("Adding implant to fit ({0}) for item ID: {1}", self.fitID, self.itemID) + + fit = eos.db.getFit(self.fitID) + item = eos.db.getItem(self.itemID, eager="attributes") + try: + implant = Implant(item) + except ValueError: + pyfalog.warning("Invalid item: {0}", self.itemID) + return False + + fit.implants.append(implant) + self.new_index = fit.implants.index(implant) + return True + + def Undo(self): + from .fitRemoveImplant import FitRemoveImplantCommand # Avoid circular import + cmd = FitRemoveImplantCommand(self.fitID, self.new_index) + cmd.Do() + return True diff --git a/gui/fitCommands/fitRemoveImplant.py b/gui/fitCommands/fitRemoveImplant.py new file mode 100644 index 000000000..509bbd40d --- /dev/null +++ b/gui/fitCommands/fitRemoveImplant.py @@ -0,0 +1,38 @@ +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 FitRemoveImplantCommand(wx.Command): + """" + Fitting command that sets the amount for an item within the cargo. + + from sFit.removeImplant + """ + def __init__(self, fitID, position): + wx.Command.__init__(self, True, "Implant remove") + self.fitID = fitID + self.position = position + self.old_implant = None + + def Do(self): + pyfalog.debug("Removing implant from position ({0}) for fit ID: {1}", self.position, self.fitID) + + fit = eos.db.getFit(self.fitID) + implant = fit.implants[self.position] + self.old_implant = implant.itemID + fit.implants.remove(implant) + return True + + def Undo(self): + from .fitAddImplant import FitAddImplantCommand # Avoid circular import + cmd = FitAddImplantCommand(self.fitID, self.old_implant) + cmd.Do() + return True diff --git a/gui/fitCommands/guiAddCargo.py b/gui/fitCommands/guiAddCargo.py index 98491505c..dbff1360c 100644 --- a/gui/fitCommands/guiAddCargo.py +++ b/gui/fitCommands/guiAddCargo.py @@ -6,14 +6,14 @@ from gui import globalEvents as GE from .fitAddCargo import FitAddCargoCommand class GuiAddCargoCommand(wx.Command): - def __init__(self, fitID, itemID): + def __init__(self, fitID, itemID, amount=1, replace=False): wx.Command.__init__(self, True, "Cargo Add") self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.sFit = Fit.getInstance() self.internal_history = wx.CommandProcessor() self.fitID = fitID # can set his up no to not have to set variables on our object - self.cmd = FitAddCargoCommand(fitID, itemID) + self.cmd = FitAddCargoCommand(fitID, itemID, amount, replace) def Do(self): if self.internal_history.Submit(self.cmd): diff --git a/gui/fitCommands/guiAddImplant.py b/gui/fitCommands/guiAddImplant.py new file mode 100644 index 000000000..b01023aa3 --- /dev/null +++ b/gui/fitCommands/guiAddImplant.py @@ -0,0 +1,29 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from .fitAddImplant import FitAddImplantCommand + +class GuiAddImplantCommand(wx.Command): + def __init__(self, fitID, itemID): + wx.Command.__init__(self, True, "Implant Add") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() + self.fitID = fitID + # can set his up no to not have to set variables on our object + self.cmd = FitAddImplantCommand(fitID, itemID) + + def Do(self): + if self.internal_history.Submit(self.cmd): + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for x in self.internal_history.Commands: + self.internal_history.Undo() + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + diff --git a/gui/fitCommands/guiRemoveImplant.py b/gui/fitCommands/guiRemoveImplant.py new file mode 100644 index 000000000..ebe906a35 --- /dev/null +++ b/gui/fitCommands/guiRemoveImplant.py @@ -0,0 +1,29 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from .fitRemoveImplant import FitRemoveImplantCommand + +class GuiRemoveImplantCommand(wx.Command): + def __init__(self, fitID, position): + wx.Command.__init__(self, True, "") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() + self.fitID = fitID + # can set his up no to not have to set variables on our object + self.cmd = FitRemoveImplantCommand(fitID, position) + + def Do(self): + if self.internal_history.Submit(self.cmd): + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for x in self.internal_history.Commands: + self.internal_history.Undo() + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + diff --git a/service/fit.py b/service/fit.py index 746990daf..c63ce4205 100644 --- a/service/fit.py +++ b/service/fit.py @@ -319,6 +319,7 @@ class Fit(object): fit.notes)) return fits + @deprecated def addImplant(self, fitID, itemID, recalc=True): pyfalog.debug("Adding implant to fit ({0}) for item ID: {1}", fitID, itemID) if fitID is None: @@ -337,6 +338,7 @@ class Fit(object): self.recalc(fit) return True + @deprecated def removeImplant(self, fitID, position, recalc=True): pyfalog.debug("Removing implant from position ({0}) for fit ID: {1}", position, fitID) if fitID is None: From 984978a80d577b7b945f02fc400d85da87613739 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 28 Jul 2018 00:06:44 -0400 Subject: [PATCH 18/95] move some files around and create a context manager for fit recalclation --- gui/builtinViews/fittingView.py | 10 +- gui/fitCommands/__init__.py | 14 ++- gui/fitCommands/calc/__init__.py | 0 gui/fitCommands/{ => calc}/fitAddCargo.py | 0 gui/fitCommands/{ => calc}/fitAddImplant.py | 0 gui/fitCommands/{ => calc}/fitAddModule.py | 0 gui/fitCommands/{ => calc}/fitChangeState.py | 0 gui/fitCommands/{ => calc}/fitCloneModule.py | 0 gui/fitCommands/{ => calc}/fitRemoveCargo.py | 6 +- .../{ => calc}/fitRemoveImplant.py | 6 +- gui/fitCommands/{ => calc}/fitRemoveModule.py | 8 +- .../{ => calc}/fitReplaceModule.py | 2 +- gui/fitCommands/{ => calc}/fitSetCharge.py | 0 gui/fitCommands/{ => calc}/fitSwapModule.py | 0 gui/fitCommands/cargoToModule.py | 100 ++++++++++++++++++ gui/fitCommands/guiAddCargo.py | 2 +- .../{moduleAddCharge.py => guiAddCharge.py} | 2 +- gui/fitCommands/guiAddImplant.py | 2 +- .../{moduleAdd.py => guiAddModule.py} | 5 +- gui/fitCommands/guiRemoveCargo.py | 2 +- gui/fitCommands/guiRemoveImplant.py | 2 +- .../{moduleRemove.py => guiRemoveModule.py} | 2 +- ...leSwapOrClone.py => guiSwapCloneModule.py} | 4 +- ...StateChange.py => guiToggleModuleState.py} | 2 +- service/fit.py | 14 +++ 25 files changed, 143 insertions(+), 40 deletions(-) create mode 100644 gui/fitCommands/calc/__init__.py rename gui/fitCommands/{ => calc}/fitAddCargo.py (100%) rename gui/fitCommands/{ => calc}/fitAddImplant.py (100%) rename gui/fitCommands/{ => calc}/fitAddModule.py (100%) rename gui/fitCommands/{ => calc}/fitChangeState.py (100%) rename gui/fitCommands/{ => calc}/fitCloneModule.py (100%) rename gui/fitCommands/{ => calc}/fitRemoveCargo.py (87%) rename gui/fitCommands/{ => calc}/fitRemoveImplant.py (81%) rename gui/fitCommands/{ => calc}/fitRemoveModule.py (86%) rename gui/fitCommands/{ => calc}/fitReplaceModule.py (98%) rename gui/fitCommands/{ => calc}/fitSetCharge.py (100%) rename gui/fitCommands/{ => calc}/fitSwapModule.py (100%) create mode 100644 gui/fitCommands/cargoToModule.py rename gui/fitCommands/{moduleAddCharge.py => guiAddCharge.py} (94%) rename gui/fitCommands/{moduleAdd.py => guiAddModule.py} (93%) rename gui/fitCommands/{moduleRemove.py => guiRemoveModule.py} (96%) rename gui/fitCommands/{moduleSwapOrClone.py => guiSwapCloneModule.py} (91%) rename gui/fitCommands/{moduleStateChange.py => guiToggleModuleState.py} (95%) diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index f57d54adc..247003b55 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -436,10 +436,14 @@ class FittingView(d.Display): fit = sFit.getFit(self.activeFitID) typeID = fit.cargo[srcIdx].item.ID - sFit.moveCargoToModule(self.mainFrame.getActiveFit(), module.modPosition, srcIdx, - mstate.CmdDown() and module.isEmpty) + self.mainFrame.command.Submit(cmd.GuiCargoToModuleCommand( + self.mainFrame.getActiveFit(), + module.modPosition, + srcIdx, + mstate.CmdDown() and module.isEmpty)) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit(), action="modadd", typeID=typeID)) + + # wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit(), action="modadd", typeID=typeID)) def swapItems(self, x, y, srcIdx): """Swap two modules in fitting window""" diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index c3507a7e6..89a74b369 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -1,11 +1,9 @@ -from .moduleStateChange import GuiModuleStateChangeCommand -from .moduleAdd import GuiModuleAddCommand -from .moduleRemove import GuiModuleRemoveCommand -from .moduleAddCharge import GuiModuleAddChargeCommand -from .moduleSwapOrClone import GuiModuleSwapOrCloneCommand +from .guiToggleModuleState import GuiModuleStateChangeCommand +from .guiAddModule import GuiModuleAddCommand +from .guiRemoveModule import GuiModuleRemoveCommand +from .guiAddCharge import GuiModuleAddChargeCommand +from .guiSwapCloneModule import GuiModuleSwapOrCloneCommand from .guiRemoveCargo import GuiRemoveCargoCommand from .guiAddCargo import GuiAddCargoCommand -from .fitAddCargo import FitAddCargoCommand -from .fitRemoveCargo import FitRemoveCargoCommand from .guiRemoveImplant import GuiRemoveImplantCommand -from .guiAddImplant import GuiAddImplantCommand \ No newline at end of file +from .guiAddImplant import GuiAddImplantCommand diff --git a/gui/fitCommands/calc/__init__.py b/gui/fitCommands/calc/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/gui/fitCommands/fitAddCargo.py b/gui/fitCommands/calc/fitAddCargo.py similarity index 100% rename from gui/fitCommands/fitAddCargo.py rename to gui/fitCommands/calc/fitAddCargo.py diff --git a/gui/fitCommands/fitAddImplant.py b/gui/fitCommands/calc/fitAddImplant.py similarity index 100% rename from gui/fitCommands/fitAddImplant.py rename to gui/fitCommands/calc/fitAddImplant.py diff --git a/gui/fitCommands/fitAddModule.py b/gui/fitCommands/calc/fitAddModule.py similarity index 100% rename from gui/fitCommands/fitAddModule.py rename to gui/fitCommands/calc/fitAddModule.py diff --git a/gui/fitCommands/fitChangeState.py b/gui/fitCommands/calc/fitChangeState.py similarity index 100% rename from gui/fitCommands/fitChangeState.py rename to gui/fitCommands/calc/fitChangeState.py diff --git a/gui/fitCommands/fitCloneModule.py b/gui/fitCommands/calc/fitCloneModule.py similarity index 100% rename from gui/fitCommands/fitCloneModule.py rename to gui/fitCommands/calc/fitCloneModule.py diff --git a/gui/fitCommands/fitRemoveCargo.py b/gui/fitCommands/calc/fitRemoveCargo.py similarity index 87% rename from gui/fitCommands/fitRemoveCargo.py rename to gui/fitCommands/calc/fitRemoveCargo.py index 41fb57b9e..6b92278b3 100644 --- a/gui/fitCommands/fitRemoveCargo.py +++ b/gui/fitCommands/calc/fitRemoveCargo.py @@ -1,10 +1,6 @@ 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__) @@ -47,7 +43,7 @@ class FitRemoveCargoCommand(wx.Command): return True def Undo(self): - from .fitAddCargo import FitAddCargoCommand # Avoid circular import + from gui.fitCommands.calc.fitAddCargo import FitAddCargoCommand # Avoid circular import cmd = FitAddCargoCommand(self.fitID, self.itemID, self.old_amount, True) cmd.Do() return True diff --git a/gui/fitCommands/fitRemoveImplant.py b/gui/fitCommands/calc/fitRemoveImplant.py similarity index 81% rename from gui/fitCommands/fitRemoveImplant.py rename to gui/fitCommands/calc/fitRemoveImplant.py index 509bbd40d..2a834878a 100644 --- a/gui/fitCommands/fitRemoveImplant.py +++ b/gui/fitCommands/calc/fitRemoveImplant.py @@ -1,10 +1,6 @@ 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__) @@ -32,7 +28,7 @@ class FitRemoveImplantCommand(wx.Command): return True def Undo(self): - from .fitAddImplant import FitAddImplantCommand # Avoid circular import + from gui.fitCommands.calc.fitAddImplant import FitAddImplantCommand # Avoid circular import cmd = FitAddImplantCommand(self.fitID, self.old_implant) cmd.Do() return True diff --git a/gui/fitCommands/fitRemoveModule.py b/gui/fitCommands/calc/fitRemoveModule.py similarity index 86% rename from gui/fitCommands/fitRemoveModule.py rename to gui/fitCommands/calc/fitRemoveModule.py index 02d4c193b..876545718 100644 --- a/gui/fitCommands/fitRemoveModule.py +++ b/gui/fitCommands/calc/fitRemoveModule.py @@ -1,10 +1,6 @@ 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 +from gui.fitCommands.helpers import ModuleInfoCache import eos.db from logbook import Logger pyfalog = Logger(__name__) @@ -48,7 +44,7 @@ class FitRemoveModuleCommand(wx.Command): return True def Undo(self): - from .fitAddModule import FitAddModuleCommand # avoids circular import + from gui.fitCommands.calc.fitAddModule import FitAddModuleCommand # avoids circular import for mod in self.modCache: cmd = FitAddModuleCommand(self.fitID, mod.itemID) cmd.Do() diff --git a/gui/fitCommands/fitReplaceModule.py b/gui/fitCommands/calc/fitReplaceModule.py similarity index 98% rename from gui/fitCommands/fitReplaceModule.py rename to gui/fitCommands/calc/fitReplaceModule.py index 0d9900b0e..9b1ecf2e3 100644 --- a/gui/fitCommands/fitReplaceModule.py +++ b/gui/fitCommands/calc/fitReplaceModule.py @@ -3,7 +3,7 @@ from service.fit import Fit import gui.mainFrame from gui import globalEvents as GE -from .helpers import ModuleInfoCache +from gui.fitCommands.helpers import ModuleInfoCache from eos.saveddata.module import Module, State import eos.db from logbook import Logger diff --git a/gui/fitCommands/fitSetCharge.py b/gui/fitCommands/calc/fitSetCharge.py similarity index 100% rename from gui/fitCommands/fitSetCharge.py rename to gui/fitCommands/calc/fitSetCharge.py diff --git a/gui/fitCommands/fitSwapModule.py b/gui/fitCommands/calc/fitSwapModule.py similarity index 100% rename from gui/fitCommands/fitSwapModule.py rename to gui/fitCommands/calc/fitSwapModule.py diff --git a/gui/fitCommands/cargoToModule.py b/gui/fitCommands/cargoToModule.py new file mode 100644 index 000000000..df47cac03 --- /dev/null +++ b/gui/fitCommands/cargoToModule.py @@ -0,0 +1,100 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from gui.fitCommands.calc.fitSetCharge import FitSetChargeCommand +from logbook import Logger +pyfalog = Logger(__name__) + +class GuiCargoToModuleCommand(wx.Command): + """ + Moves cargo to fitting window. Can either do a copy, move, or swap with current module + If we try to copy/move into a spot with a non-empty module, we swap instead. + To avoid redundancy in converting Cargo item, this function does the + sanity checks as opposed to the GUI View. This is different than how the + normal .swapModules() does things, which is mostly a blind swap. + """ + + def __init__(self, fitID, moduleIdx, cargoIdx, copy=False): + # todo: instead of modules, needs to be positions. Dead objects are a thing + wx.Command.__init__(self, True, "Module State Change") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.fitID = fitID + self.moduleIdx = moduleIdx + self.cargoIdx = cargoIdx + self.copy = copy + self.internal_history = wx.CommandProcessor() + + def Do(self): + sFit = Fit.getInstance() + fit = sFit.getFit(self.fitID) + module = fit.modules[self.moduleIdx] + cargo = fit.cargo[self.cargoIdx] + result = None + + # We're trying to move a charge from cargo to a slot. Use SetCharge command (don't respect move vs copy) + if sFit.isAmmo(cargo.item.ID): + result = self.internal_history.Submit(FitSetChargeCommand(self.fitID, [module], cargo.item.ID)) + # else: + # + # pyfalog.debug("Moving cargo item to module for fit ID: {0}", self.fitID) + # + # # Gather modules and convert Cargo item to Module, silently return if not a module + # try: + # cargoP = es_Module(cargo.item) + # cargoP.owner = fit + # if cargoP.isValidState(State.ACTIVE): + # cargoP.state = State.ACTIVE + # except: + # pyfalog.warning("Invalid item: {0}", cargo.item) + # return + # + # if cargoP.slot != module.slot: # can't swap modules to different racks + # return + # + # # remove module that we are trying to move cargo to + # fit.modules.remove(module) + # + # if not cargoP.fits(fit): # if cargo doesn't fit, rollback and return + # fit.modules.insert(moduleIdx, module) + # return + # + # fit.modules.insert(moduleIdx, cargoP) + # + # if not copyMod: # remove existing cargo if not cloning + # if cargo.amount == 1: + # fit.cargo.remove(cargo) + # else: + # cargo.amount -= 1 + # + # if not module.isEmpty: # if module is placeholder, we don't want to convert/add it + # moduleItem = module.item if not module.item.isAbyssal else module.baseItem + # for x in fit.cargo.find(moduleItem): + # x.amount += 1 + # break + # else: + # moduleP = es_Cargo(moduleItem) + # moduleP.amount = 1 + # fit.cargo.insert(cargoIdx, moduleP) + # + # eos.db.commit() + # self.recalc(fit) + # # + # # + # # + # # if self.clone: + # # result = self.internal_history.Submit(FitCloneModduleCommand(self.fitID, self.srcPosition, self.dstPosition)) + # # else: + # # result = self.internal_history.Submit(FitSwapModuleCommand(self.fitID, self.srcPosition, self.dstPosition)) + + if result: + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return result + + def Undo(self): + for _ in self.internal_history.Commands: + self.internal_history.Undo() + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True diff --git a/gui/fitCommands/guiAddCargo.py b/gui/fitCommands/guiAddCargo.py index dbff1360c..db923c7d1 100644 --- a/gui/fitCommands/guiAddCargo.py +++ b/gui/fitCommands/guiAddCargo.py @@ -3,7 +3,7 @@ from service.fit import Fit import gui.mainFrame from gui import globalEvents as GE -from .fitAddCargo import FitAddCargoCommand +from .calc.fitAddCargo import FitAddCargoCommand class GuiAddCargoCommand(wx.Command): def __init__(self, fitID, itemID, amount=1, replace=False): diff --git a/gui/fitCommands/moduleAddCharge.py b/gui/fitCommands/guiAddCharge.py similarity index 94% rename from gui/fitCommands/moduleAddCharge.py rename to gui/fitCommands/guiAddCharge.py index 7dd4ba6ec..49b2a1680 100644 --- a/gui/fitCommands/moduleAddCharge.py +++ b/gui/fitCommands/guiAddCharge.py @@ -3,7 +3,7 @@ from service.fit import Fit import gui.mainFrame from gui import globalEvents as GE -from .fitSetCharge import FitSetChargeCommand +from .calc.fitSetCharge import FitSetChargeCommand class GuiModuleAddChargeCommand(wx.Command): def __init__(self, fitID, itemID, modules): diff --git a/gui/fitCommands/guiAddImplant.py b/gui/fitCommands/guiAddImplant.py index b01023aa3..33495398d 100644 --- a/gui/fitCommands/guiAddImplant.py +++ b/gui/fitCommands/guiAddImplant.py @@ -3,7 +3,7 @@ from service.fit import Fit import gui.mainFrame from gui import globalEvents as GE -from .fitAddImplant import FitAddImplantCommand +from .calc.fitAddImplant import FitAddImplantCommand class GuiAddImplantCommand(wx.Command): def __init__(self, fitID, itemID): diff --git a/gui/fitCommands/moduleAdd.py b/gui/fitCommands/guiAddModule.py similarity index 93% rename from gui/fitCommands/moduleAdd.py rename to gui/fitCommands/guiAddModule.py index e035dbfd0..20a27e23d 100644 --- a/gui/fitCommands/moduleAdd.py +++ b/gui/fitCommands/guiAddModule.py @@ -3,9 +3,8 @@ 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 +from .calc.fitAddModule import FitAddModuleCommand +from .calc.fitReplaceModule import FitReplaceModuleCommand class GuiModuleAddCommand(wx.Command): def __init__(self, fitID, itemID, position=None): diff --git a/gui/fitCommands/guiRemoveCargo.py b/gui/fitCommands/guiRemoveCargo.py index f86b607d2..210252418 100644 --- a/gui/fitCommands/guiRemoveCargo.py +++ b/gui/fitCommands/guiRemoveCargo.py @@ -3,7 +3,7 @@ from service.fit import Fit import gui.mainFrame from gui import globalEvents as GE -from .fitRemoveCargo import FitRemoveCargoCommand +from .calc.fitRemoveCargo import FitRemoveCargoCommand class GuiRemoveCargoCommand(wx.Command): def __init__(self, fitID, itemID): diff --git a/gui/fitCommands/guiRemoveImplant.py b/gui/fitCommands/guiRemoveImplant.py index ebe906a35..af96355a4 100644 --- a/gui/fitCommands/guiRemoveImplant.py +++ b/gui/fitCommands/guiRemoveImplant.py @@ -3,7 +3,7 @@ from service.fit import Fit import gui.mainFrame from gui import globalEvents as GE -from .fitRemoveImplant import FitRemoveImplantCommand +from .calc.fitRemoveImplant import FitRemoveImplantCommand class GuiRemoveImplantCommand(wx.Command): def __init__(self, fitID, position): diff --git a/gui/fitCommands/moduleRemove.py b/gui/fitCommands/guiRemoveModule.py similarity index 96% rename from gui/fitCommands/moduleRemove.py rename to gui/fitCommands/guiRemoveModule.py index bcf2cf139..32dc8cedc 100644 --- a/gui/fitCommands/moduleRemove.py +++ b/gui/fitCommands/guiRemoveModule.py @@ -5,7 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .helpers import ModuleInfoCache -from .fitRemoveModule import FitRemoveModuleCommand +from .calc.fitRemoveModule import FitRemoveModuleCommand class GuiModuleRemoveCommand(wx.Command): diff --git a/gui/fitCommands/moduleSwapOrClone.py b/gui/fitCommands/guiSwapCloneModule.py similarity index 91% rename from gui/fitCommands/moduleSwapOrClone.py rename to gui/fitCommands/guiSwapCloneModule.py index 799b7a915..bc283943c 100644 --- a/gui/fitCommands/moduleSwapOrClone.py +++ b/gui/fitCommands/guiSwapCloneModule.py @@ -3,8 +3,8 @@ from service.fit import Fit import gui.mainFrame from gui import globalEvents as GE -from .fitSwapModule import FitSwapModuleCommand -from .fitCloneModule import FitCloneModduleCommand +from gui.fitCommands.calc.fitSwapModule import FitSwapModuleCommand +from .calc.fitCloneModule import FitCloneModduleCommand class GuiModuleSwapOrCloneCommand(wx.Command): def __init__(self, fitID, srcPosition, dstPosition, clone=False): diff --git a/gui/fitCommands/moduleStateChange.py b/gui/fitCommands/guiToggleModuleState.py similarity index 95% rename from gui/fitCommands/moduleStateChange.py rename to gui/fitCommands/guiToggleModuleState.py index 167777bd1..0f2344e64 100644 --- a/gui/fitCommands/moduleStateChange.py +++ b/gui/fitCommands/guiToggleModuleState.py @@ -3,7 +3,7 @@ from service.fit import Fit import gui.mainFrame from gui import globalEvents as GE -from .fitChangeState import FitChangeStatesCommand +from .calc.fitChangeState import FitChangeStatesCommand class GuiModuleStateChangeCommand(wx.Command): def __init__(self, fitID, baseMod, modules, click): diff --git a/service/fit.py b/service/fit.py index c63ce4205..016f5989a 100644 --- a/service/fit.py +++ b/service/fit.py @@ -41,6 +41,20 @@ from utils.deprecated import deprecated pyfalog = Logger(__name__) +class DeferRecalc(): + def __init__(self, fitID): + self.fitID = fitID + self.sFit = Fit.getInstance() + + def __enter__(self): + self._recalc = self.sFit.recalc + self.sFit.recalc = lambda x: print('Deferred Recalc') + + def __exit__(self, *args): + self.sFit.recalc = self._recalc + self.sFit.recalc(self.fitID) + + class Fit(object): instance = None From cfb7a70da565c669617f9f74a0b585cdc0179e24 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Mon, 30 Jul 2018 00:05:00 -0400 Subject: [PATCH 19/95] Add recalcs to Add and remove module --- gui/fitCommands/guiAddModule.py | 5 +++-- gui/fitCommands/guiRemoveModule.py | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/gui/fitCommands/guiAddModule.py b/gui/fitCommands/guiAddModule.py index 20a27e23d..5abf52651 100644 --- a/gui/fitCommands/guiAddModule.py +++ b/gui/fitCommands/guiAddModule.py @@ -1,5 +1,4 @@ import wx -from service.fit import Fit import gui.mainFrame from gui import globalEvents as GE @@ -22,7 +21,7 @@ class GuiModuleAddCommand(wx.Command): success = False # if we have a position set, try to apply the module to that position - # todo: check to see if item is a charge. if it is, dont try to add module, but instead set amm + # todo: check to see if item is a charge. if it is, dont try to add module, but instead set ammo if self.new_position: success = self.internal_history.Submit(FitReplaceModuleCommand(self.fitID, self.new_position, self.itemID)) if not success: @@ -34,6 +33,7 @@ class GuiModuleAddCommand(wx.Command): success = self.internal_history.Submit(FitAddModuleCommand(self.fitID, self.itemID)) if success: + self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="modadd", typeID=self.itemID)) return True return False @@ -48,5 +48,6 @@ class GuiModuleAddCommand(wx.Command): def Undo(self): for _ in self.internal_history.Commands: self.internal_history.Undo() + self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="moddel", typeID=self.itemID)) return True diff --git a/gui/fitCommands/guiRemoveModule.py b/gui/fitCommands/guiRemoveModule.py index 32dc8cedc..9c7c5eef6 100644 --- a/gui/fitCommands/guiRemoveModule.py +++ b/gui/fitCommands/guiRemoveModule.py @@ -24,11 +24,13 @@ class GuiModuleRemoveCommand(wx.Command): if success is not None: # self.slotsChanged() # todo: fix + self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="moddel", typeID=set([mod.itemID for mod in self.modCache]))) return True def Undo(self): for x in self.internal_history.Commands: self.internal_history.Undo() + self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="modadd", typeID=set([mod.itemID for mod in self.modCache]))) return True From 098f0f92ee7d3d96eb69074c6353d63752dc0e82 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Tue, 31 Jul 2018 21:29:59 -0400 Subject: [PATCH 20/95] Fix issue with layout-modifying modules (need to build fill() into the recalc itself at some point) --- eos/saveddata/fit.py | 4 +++- gui/fitCommands/guiAddModule.py | 1 + service/fit.py | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index 8f5cc2b36..62eaa2bb1 100644 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -35,7 +35,6 @@ from eos.saveddata.character import Character from eos.saveddata.citadel import Citadel from eos.saveddata.module import Module, State, Slot, Hardpoint from logbook import Logger - pyfalog = Logger(__name__) @@ -913,6 +912,9 @@ class Fit(object): Fill this fit's module slots with enough dummy slots so that all slots are used. This is mostly for making the life of gui's easier. GUI's can call fill() and then stop caring about empty slots completely. + + todo: want to get rid of using this from the gui/commands, and instead make it a more built-in feature within + recalc. Figure out a way to keep track of any changes to slot layout and call this automatically """ if self.ship is None: return diff --git a/gui/fitCommands/guiAddModule.py b/gui/fitCommands/guiAddModule.py index 5abf52651..dad2780e1 100644 --- a/gui/fitCommands/guiAddModule.py +++ b/gui/fitCommands/guiAddModule.py @@ -4,6 +4,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitAddModule import FitAddModuleCommand from .calc.fitReplaceModule import FitReplaceModuleCommand +from service.fit import Fit class GuiModuleAddCommand(wx.Command): def __init__(self, fitID, itemID, position=None): diff --git a/service/fit.py b/service/fit.py index 016f5989a..d3ed7d9c7 100644 --- a/service/fit.py +++ b/service/fit.py @@ -1256,5 +1256,5 @@ class Fit(object): fit.clear() fit.calculateModifiedAttributes() - + fit.fill() pyfalog.info("=" * 10 + "recalc time: " + str(time() - start_time) + "=" * 10) From fc153915b6adb64302a6acfacfbe80d25f98e879 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Thu, 2 Aug 2018 02:06:03 -0400 Subject: [PATCH 21/95] More work on commands, this time focusing on details with module add / remove functionalities. --- gui/fitCommands/calc/fitAddModule.py | 11 +++++-- gui/fitCommands/calc/fitRemoveModule.py | 9 ++--- gui/fitCommands/calc/fitReplaceModule.py | 21 ++++++++---- gui/fitCommands/calc/fitSetCharge.py | 26 ++++++++------- gui/fitCommands/guiAddCharge.py | 6 ++-- gui/fitCommands/guiAddModule.py | 42 ++++++++++++++---------- gui/fitCommands/guiRemoveModule.py | 15 +++++---- gui/fitCommands/helpers.py | 2 +- 8 files changed, 80 insertions(+), 52 deletions(-) diff --git a/gui/fitCommands/calc/fitAddModule.py b/gui/fitCommands/calc/fitAddModule.py index 8ff72ab74..39dabf7e1 100644 --- a/gui/fitCommands/calc/fitAddModule.py +++ b/gui/fitCommands/calc/fitAddModule.py @@ -16,10 +16,12 @@ class FitAddModuleCommand(wx.Command): from sFit.appendModule """ - def __init__(self, fitID, itemID): + def __init__(self, fitID, itemID, mutaplasmidID=None, baseID=None): wx.Command.__init__(self, True, "Module Add") self.fitID = fitID self.itemID = itemID + self.mutaplasmidID = mutaplasmidID + self.baseID = baseID self.new_position = None self.change = None @@ -30,8 +32,11 @@ class FitAddModuleCommand(wx.Command): fit = eos.db.getFit(fitID) item = eos.db.getItem(itemID, eager=("attributes", "group.category")) + bItem = eos.db.getItem(self.baseID) if self.baseID else None + mItem = next((x for x in bItem.mutaplasmids if x.ID == self.mutaplasmidID)) if self.mutaplasmidID else None + try: - self.module = Module(item) + self.module = Module(item, bItem, mItem) except ValueError: pyfalog.warning("Invalid item: {0}", itemID) return False @@ -52,7 +57,7 @@ class FitAddModuleCommand(wx.Command): # Then, check states of all modules and change where needed. This will recalc if needed # self.checkStates(fit, m) - fit.fill() + #fit.fill() eos.db.commit() self.change = numSlots != len(fit.modules) diff --git a/gui/fitCommands/calc/fitRemoveModule.py b/gui/fitCommands/calc/fitRemoveModule.py index 876545718..9eb2e013a 100644 --- a/gui/fitCommands/calc/fitRemoveModule.py +++ b/gui/fitCommands/calc/fitRemoveModule.py @@ -27,10 +27,10 @@ class FitRemoveModuleCommand(wx.Command): 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)) + self.modCache.append(ModuleInfoCache(mod.modPosition, mod.item.ID, mod.state, mod.charge, mod.baseItemID, mod.mutaplasmidID)) fit.modules.toDummy(x) - # if no modules have changes, report back None + # if no modules have changes, skip command if not len(self.modCache) > 0: return False @@ -38,7 +38,7 @@ class FitRemoveModuleCommand(wx.Command): # todo: determine if we need to do this still # self.recalc(fit) # self.checkStates(fit, None) - fit.fill() + # fit.fill() eos.db.commit() self.slotsChanged = numSlots != len(fit.modules) return True @@ -46,7 +46,8 @@ class FitRemoveModuleCommand(wx.Command): def Undo(self): from gui.fitCommands.calc.fitAddModule import FitAddModuleCommand # avoids circular import for mod in self.modCache: - cmd = FitAddModuleCommand(self.fitID, mod.itemID) + # todo, send the state and charge? + cmd = FitAddModuleCommand(self.fitID, mod.itemID, mod.mutaplasmidID, mod.baseID) cmd.Do() cmd.module.state = mod.state cmd.module.charge = mod.charge diff --git a/gui/fitCommands/calc/fitReplaceModule.py b/gui/fitCommands/calc/fitReplaceModule.py index 9b1ecf2e3..ddfd2c770 100644 --- a/gui/fitCommands/calc/fitReplaceModule.py +++ b/gui/fitCommands/calc/fitReplaceModule.py @@ -28,7 +28,12 @@ class FitReplaceModuleCommand(wx.Command): return self.change_module(self.fitID, self.position, self.itemID) def Undo(self): - self.change_module(self.fitID, self.position, self.itemID) + if self.old_module is None: + fit = eos.db.getFit(self.fitID) + fit.modules.toDummy(self.position) + return True + + self.change_module(self.fitID, self.position, self.old_module.itemID) self.module.state = self.old_module.state self.module.charge = self.old_module.charge return True @@ -51,10 +56,8 @@ class FitReplaceModuleCommand(wx.Command): 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) + if not mod.isEmpty: + self.old_module = ModuleInfoCache(mod.modPosition, mod.item.ID, mod.state, mod.charge, mod.baseItemID, mod.mutaplasmidID) try: self.module = Module(item) @@ -62,6 +65,12 @@ class FitReplaceModuleCommand(wx.Command): pyfalog.warning("Invalid item: {0}", itemID) return False + if self.module.slot != mod.slot: + return False + + # Dummy it out in case the next bit fails + fit.modules.toDummy(self.position) + if self.module.fits(fit): self.module.owner = fit fit.modules.toModule(self.position, self.module) @@ -71,7 +80,7 @@ class FitReplaceModuleCommand(wx.Command): # Then, check states of all modules and change where needed. This will recalc if needed # self.checkStates(fit, m) - fit.fill() + # fit.fill() eos.db.commit() return True return False diff --git a/gui/fitCommands/calc/fitSetCharge.py b/gui/fitCommands/calc/fitSetCharge.py index 111959a18..e97d55adb 100644 --- a/gui/fitCommands/calc/fitSetCharge.py +++ b/gui/fitCommands/calc/fitSetCharge.py @@ -9,34 +9,36 @@ pyfalog = Logger(__name__) import eos.db class FitSetChargeCommand(wx.Command): - def __init__(self, fitID, modules, chargeID=None): + def __init__(self, fitID, positions, chargeID=None): # todo: determine if this command really should be used with a group of modules, or a simple per module basis wx.Command.__init__(self, True, "Module Charge Add") self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.sFit = Fit.getInstance() self.fitID = fitID self.chargeID = chargeID - self.modules = modules - self.positions = {mod.modPosition: mod.chargeID for mod in modules} + self.positions = positions + self.cache = None def Do(self): pyfalog.debug("Set ammo for fit ID: {0}", self.fitID) - if self.fitID is None: - return False - return self.__setAmmo(self.modules, self.chargeID) + return self.__setAmmo(self.positions, self.chargeID) def Undo(self): - fit = eos.db.getFit(self.fitID) - for position, chargeID in self.positions.items(): - self.__setAmmo([fit.modules[position]], chargeID) + for position, chargeID in self.cache.items(): + self.__setAmmo([position], chargeID) return True - @staticmethod - def __setAmmo(modules, chargeID): + def __setAmmo(self, positions, chargeID): + fit = eos.db.getFit(self.fitID) + self.cache = {fit.modules[i].modPosition: fit.modules[i].chargeID for i in positions} ammo = eos.db.getItem(chargeID) if chargeID else None + + if not ammo.isCharge: + return False result = False - for mod in modules: + for pos in positions: + mod = fit.modules[pos] if not mod.isEmpty and mod.isValidCharge(ammo): result = True mod.charge = ammo diff --git a/gui/fitCommands/guiAddCharge.py b/gui/fitCommands/guiAddCharge.py index 49b2a1680..94d7d4249 100644 --- a/gui/fitCommands/guiAddCharge.py +++ b/gui/fitCommands/guiAddCharge.py @@ -13,10 +13,11 @@ class GuiModuleAddChargeCommand(wx.Command): self.internal_history = wx.CommandProcessor() self.fitID = fitID # can set his up no to not have to set variables on our object - self.cmd = FitSetChargeCommand(fitID, modules, itemID) + self.cmd = FitSetChargeCommand(fitID, [mod.modPosition for mod in modules], itemID) def Do(self): if self.internal_history.Submit(self.cmd): + self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True return False @@ -24,6 +25,7 @@ class GuiModuleAddChargeCommand(wx.Command): def Undo(self): for x in self.internal_history.Commands: self.internal_history.Undo() - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True diff --git a/gui/fitCommands/guiAddModule.py b/gui/fitCommands/guiAddModule.py index dad2780e1..06267919f 100644 --- a/gui/fitCommands/guiAddModule.py +++ b/gui/fitCommands/guiAddModule.py @@ -1,36 +1,48 @@ import wx - +import eos.db import gui.mainFrame from gui import globalEvents as GE from .calc.fitAddModule import FitAddModuleCommand from .calc.fitReplaceModule import FitReplaceModuleCommand +from .calc.fitSetCharge import FitSetChargeCommand from service.fit import Fit + class GuiModuleAddCommand(wx.Command): def __init__(self, fitID, itemID, position=None): - wx.Command.__init__(self, True, "Module Add") - # todo: evaluate mutaplasmid modules + """ + Handles adding an item, usually a module, to the Fitting Window. + + :param fitID: The fit ID that we are modifying + :param itemID: The item that is to be added to the Fitting View. If this turns out to be a charge, we attempt to + set the charge on the underlying module (requires position) + :param position: Optional. The position in fit.modules that we are attempting to set the item to + """ + wx.Command.__init__(self, True, "Module Add: {}".format(itemID)) self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.sFit = Fit.getInstance() self.fitID = fitID self.itemID = itemID self.internal_history = wx.CommandProcessor() - self.new_position = position + self.position = position self.old_mod = None def Do(self): success = False - # if we have a position set, try to apply the module to that position - - # todo: check to see if item is a charge. if it is, dont try to add module, but instead set ammo - if self.new_position: - success = self.internal_history.Submit(FitReplaceModuleCommand(self.fitID, self.new_position, self.itemID)) + item = eos.db.getItem(self.itemID) + if item.isCharge and self.position is not None: + success = self.internal_history.Submit(FitSetChargeCommand(self.fitID, [self.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 + return False # if it's a charge item and this failed, nothing more we can try. + # if we have a position set, try to apply the module to that position + elif self.position is not None: + success = self.internal_history.Submit(FitReplaceModuleCommand(self.fitID, self.position, self.itemID)) + if not success: + # something went wrong with trying to fit the module into specific location, attempt to append it + self.position = None # if we're not trying to set module to a position, simply append - if not self.new_position: + if self.position is None: success = self.internal_history.Submit(FitAddModuleCommand(self.fitID, self.itemID)) if success: @@ -39,12 +51,6 @@ class GuiModuleAddCommand(wx.Command): 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): for _ in self.internal_history.Commands: diff --git a/gui/fitCommands/guiRemoveModule.py b/gui/fitCommands/guiRemoveModule.py index 9c7c5eef6..508c7178b 100644 --- a/gui/fitCommands/guiRemoveModule.py +++ b/gui/fitCommands/guiRemoveModule.py @@ -10,26 +10,29 @@ from .calc.fitRemoveModule import FitRemoveModuleCommand class GuiModuleRemoveCommand(wx.Command): def __init__(self, fitID, modules): - # todo: evaluate mutaplasmid modules + """ + + :param fitID: The fit ID that we are modifying + :param modules: A list of Module objects that we are attempting to remove. + """ wx.Command.__init__(self, True, "Module Remove") self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.sFit = Fit.getInstance() self.fitID = fitID - self.modCache = [ModuleInfoCache(mod.modPosition, mod.item.ID, mod.state, mod.charge) for mod in modules] + self.modCache = [ModuleInfoCache(mod.modPosition, mod.item.ID, mod.state, mod.charge, mod.baseItemID, mod.mutaplasmidID) for mod in modules if not mod.isEmpty] self.internal_history = wx.CommandProcessor() def Do(self): - # 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 success is not None: - # self.slotsChanged() # todo: fix + if success: self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="moddel", typeID=set([mod.itemID for mod in self.modCache]))) return True + return False def Undo(self): - for x in self.internal_history.Commands: + for _ in self.internal_history.Commands: self.internal_history.Undo() self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="modadd", typeID=set([mod.itemID for mod in self.modCache]))) diff --git a/gui/fitCommands/helpers.py b/gui/fitCommands/helpers.py index 81c862193..63aaf4b76 100644 --- a/gui/fitCommands/helpers.py +++ b/gui/fitCommands/helpers.py @@ -1,3 +1,3 @@ from collections import namedtuple -ModuleInfoCache = namedtuple('ModuleInfoCache', ['modPosition', 'itemID', 'state', 'charge']) +ModuleInfoCache = namedtuple('ModuleInfoCache', ['modPosition', 'itemID', 'state', 'charge', 'baseID', 'mutaplasmidID']) From 36b158637c9e015c019db027dc8e85f448fa147d Mon Sep 17 00:00:00 2001 From: blitzmann Date: Thu, 2 Aug 2018 23:23:52 -0400 Subject: [PATCH 22/95] Some documentation --- eos/effectHandlerHelpers.py | 2 ++ gui/fitCommands/calc/fitAddModule.py | 21 ++++++++++++++++----- gui/fitCommands/calc/fitRemoveModule.py | 9 +++++++-- gui/fitCommands/calc/fitSetCharge.py | 2 +- gui/fitCommands/guiAddModule.py | 9 +++++++++ gui/fitCommands/guiRemoveModule.py | 1 + 6 files changed, 36 insertions(+), 8 deletions(-) diff --git a/eos/effectHandlerHelpers.py b/eos/effectHandlerHelpers.py index f890ae0ed..446273a45 100644 --- a/eos/effectHandlerHelpers.py +++ b/eos/effectHandlerHelpers.py @@ -18,6 +18,7 @@ # =============================================================================== from logbook import Logger +from utils.deprecated import deprecated pyfalog = Logger(__name__) @@ -163,6 +164,7 @@ class HandledModuleList(HandledList): mod.position = index self[index] = mod + @deprecated def freeSlot(self, slot): for i in range(len(self)): mod = self[i] diff --git a/gui/fitCommands/calc/fitAddModule.py b/gui/fitCommands/calc/fitAddModule.py index 39dabf7e1..5d1a2c35c 100644 --- a/gui/fitCommands/calc/fitAddModule.py +++ b/gui/fitCommands/calc/fitAddModule.py @@ -12,23 +12,24 @@ pyfalog = Logger(__name__) class FitAddModuleCommand(wx.Command): """" - Fitting command that appends a module to a fit using the first available slot. + Fitting command that appends a module to a fit using the first available slot. In the case of a Subsystem, it checks + if there is already a subsystem with the same slot, and runs the replace command instead. from sFit.appendModule """ def __init__(self, fitID, itemID, mutaplasmidID=None, baseID=None): - wx.Command.__init__(self, True, "Module Add") + wx.Command.__init__(self, True) self.fitID = fitID self.itemID = itemID self.mutaplasmidID = mutaplasmidID self.baseID = baseID self.new_position = None self.change = None + self.replace_cmd = 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")) @@ -38,13 +39,19 @@ class FitAddModuleCommand(wx.Command): try: self.module = Module(item, bItem, mItem) except ValueError: - pyfalog.warning("Invalid item: {0}", itemID) + pyfalog.warning("Invalid module: {}", item) return False + # If subsystem and we need to replace, run the replace command instead and bypass the rest of this command if self.module.item.category.name == "Subsystem": - fit.modules.freeSlot(self.module.getModifiedItemAttr("subSystemSlot")) + for mod in fit.modules: + if mod.getModifiedItemAttr("subSystemSlot") == self.module.getModifiedItemAttr("subSystemSlot"): + from .fitReplaceModule import FitReplaceModuleCommand + self.replace_cmd = FitReplaceModuleCommand(self.fitID, mod.modPosition, itemID) + return self.replace_cmd.Do() if self.module.fits(fit): + pyfalog.debug("Adding {} as module for fit {}", self.module, fit) self.module.owner = fit numSlots = len(fit.modules) fit.modules.append(self.module) @@ -68,6 +75,10 @@ class FitAddModuleCommand(wx.Command): return True def Undo(self): + # We added a subsystem module, which actually ran the replace command. Run the undo for that guy instead + if self.replace_cmd: + return self.replace_cmd.Undo() + from .fitRemoveModule import FitRemoveModuleCommand # Avoid circular import if self.new_position: cmd = FitRemoveModuleCommand(self.fitID, [self.new_position]) diff --git a/gui/fitCommands/calc/fitRemoveModule.py b/gui/fitCommands/calc/fitRemoveModule.py index 9eb2e013a..79ae52198 100644 --- a/gui/fitCommands/calc/fitRemoveModule.py +++ b/gui/fitCommands/calc/fitRemoveModule.py @@ -13,7 +13,7 @@ class FitRemoveModuleCommand(wx.Command): from sFit.removeModule """ def __init__(self, fitID: int, positions: list = None): - wx.Command.__init__(self, True, "Module Remove") + wx.Command.__init__(self, True) self.fitID = fitID self.positions = positions self.modCache = [] @@ -21,12 +21,14 @@ class FitRemoveModuleCommand(wx.Command): 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) + pyfalog.debug("Removing module from position ({0}) for fit ID: {1}", self.positions, fitID) + for x in self.positions: mod = fit.modules[x] if not mod.isEmpty: + pyfalog.debug(" -- Removing {}", mod) self.modCache.append(ModuleInfoCache(mod.modPosition, mod.item.ID, mod.state, mod.charge, mod.baseItemID, mod.mutaplasmidID)) fit.modules.toDummy(x) @@ -44,8 +46,11 @@ class FitRemoveModuleCommand(wx.Command): return True def Undo(self): + pyfalog.debug("Reapplying {} removed module(s) for {}", len(self.modCache), self.fitID) + from gui.fitCommands.calc.fitAddModule import FitAddModuleCommand # avoids circular import for mod in self.modCache: + pyfalog.debug(" -- {}", mod) # todo, send the state and charge? cmd = FitAddModuleCommand(self.fitID, mod.itemID, mod.mutaplasmidID, mod.baseID) cmd.Do() diff --git a/gui/fitCommands/calc/fitSetCharge.py b/gui/fitCommands/calc/fitSetCharge.py index e97d55adb..d06258924 100644 --- a/gui/fitCommands/calc/fitSetCharge.py +++ b/gui/fitCommands/calc/fitSetCharge.py @@ -20,7 +20,6 @@ class FitSetChargeCommand(wx.Command): self.cache = None def Do(self): - pyfalog.debug("Set ammo for fit ID: {0}", self.fitID) return self.__setAmmo(self.positions, self.chargeID) def Undo(self): @@ -40,6 +39,7 @@ class FitSetChargeCommand(wx.Command): for pos in positions: mod = fit.modules[pos] if not mod.isEmpty and mod.isValidCharge(ammo): + pyfalog.debug("Set ammo {} for {} on fit {}", ammo, mod, self.fitID) result = True mod.charge = ammo eos.db.commit() diff --git a/gui/fitCommands/guiAddModule.py b/gui/fitCommands/guiAddModule.py index 06267919f..ae279d506 100644 --- a/gui/fitCommands/guiAddModule.py +++ b/gui/fitCommands/guiAddModule.py @@ -6,6 +6,8 @@ from .calc.fitAddModule import FitAddModuleCommand from .calc.fitReplaceModule import FitReplaceModuleCommand from .calc.fitSetCharge import FitSetChargeCommand from service.fit import Fit +from logbook import Logger +pyfalog = Logger(__name__) class GuiModuleAddCommand(wx.Command): @@ -28,21 +30,27 @@ class GuiModuleAddCommand(wx.Command): self.old_mod = None def Do(self): + pyfalog.debug("{} Do()".format(self)) success = False item = eos.db.getItem(self.itemID) if item.isCharge and self.position is not None: + pyfalog.debug("Trying to add a charge") success = self.internal_history.Submit(FitSetChargeCommand(self.fitID, [self.position], self.itemID)) if not success: + pyfalog.debug(" Failed") return False # if it's a charge item and this failed, nothing more we can try. # if we have a position set, try to apply the module to that position elif self.position is not None: + pyfalog.debug("Trying to add a module to a specific position") success = self.internal_history.Submit(FitReplaceModuleCommand(self.fitID, self.position, self.itemID)) if not success: + pyfalog.debug(" Failed") # something went wrong with trying to fit the module into specific location, attempt to append it self.position = None # if we're not trying to set module to a position, simply append if self.position is None: + pyfalog.debug("Trying to append a module") success = self.internal_history.Submit(FitAddModuleCommand(self.fitID, self.itemID)) if success: @@ -53,6 +61,7 @@ class GuiModuleAddCommand(wx.Command): def Undo(self): + pyfalog.debug("{} Undo()".format(self)) for _ in self.internal_history.Commands: self.internal_history.Undo() self.sFit.recalc(self.fitID) diff --git a/gui/fitCommands/guiRemoveModule.py b/gui/fitCommands/guiRemoveModule.py index 508c7178b..169dbe593 100644 --- a/gui/fitCommands/guiRemoveModule.py +++ b/gui/fitCommands/guiRemoveModule.py @@ -11,6 +11,7 @@ from .calc.fitRemoveModule import FitRemoveModuleCommand class GuiModuleRemoveCommand(wx.Command): def __init__(self, fitID, modules): """ + Handles removing modules from fit.modules, :param fitID: The fit ID that we are modifying :param modules: A list of Module objects that we are attempting to remove. From c84c79c9171395cf39be50d024a45d9d05d46679 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Fri, 3 Aug 2018 01:08:33 -0400 Subject: [PATCH 23/95] More tweaks to existing commands --- gui/fitCommands/calc/fitChangeState.py | 4 +--- gui/fitCommands/calc/fitCloneModule.py | 4 ++-- gui/fitCommands/guiAddCharge.py | 2 +- gui/fitCommands/guiSwapCloneModule.py | 30 ++++++++++++++++--------- gui/fitCommands/guiToggleModuleState.py | 20 ++++++++++------- 5 files changed, 36 insertions(+), 24 deletions(-) diff --git a/gui/fitCommands/calc/fitChangeState.py b/gui/fitCommands/calc/fitChangeState.py index c800e030e..06ad7bfbd 100644 --- a/gui/fitCommands/calc/fitChangeState.py +++ b/gui/fitCommands/calc/fitChangeState.py @@ -26,9 +26,6 @@ class FitChangeStatesCommand(wx.Command): self.old_states[mod.modPosition] = mod.state def Do(self): - # todo: determine if we've changed state (recalc). If not, store that so we don't attempt to recalc on undo - # self.sFit.toggleModulesState(self.fitID, self.baseMod, self.modules, self.click) - pyfalog.debug("Toggle module state for fit ID: {0}", self.fitID) changed = False proposedState = Module.getProposedState(self.baseMod, self.click) @@ -43,6 +40,7 @@ class FitChangeStatesCommand(wx.Command): if p != mod.state: changed = True + # if we haven't change the state (eg, overheat -> overheat), simply fail the command if changed: self.changed = changed eos.db.commit() diff --git a/gui/fitCommands/calc/fitCloneModule.py b/gui/fitCommands/calc/fitCloneModule.py index b126c5063..14c24ddc6 100644 --- a/gui/fitCommands/calc/fitCloneModule.py +++ b/gui/fitCommands/calc/fitCloneModule.py @@ -10,7 +10,7 @@ from logbook import Logger pyfalog = Logger(__name__) import copy -class FitCloneModduleCommand(wx.Command): +class FitCloneModuleCommand(wx.Command): """ Clone a module from src to dst This will overwrite dst! Checking for empty module must be @@ -25,7 +25,6 @@ class FitCloneModduleCommand(wx.Command): self.dst = dst def Do(self): - pyfalog.debug("Cloning modules from source ({0}) to destination ({1}) for fit ID: {1}", self.src, self.dst, self.fitID) fit = eos.db.getFit(self.fitID) # Gather modules srcMod = fit.modules[self.src] @@ -34,6 +33,7 @@ class FitCloneModduleCommand(wx.Command): new = copy.deepcopy(srcMod) new.owner = fit if new.fits(fit): + pyfalog.debug("Cloning {} from source {} to destination {} for fit ID {}", srcMod, self.src, self.dst, self.fitID) # insert copy if module meets hardpoint restrictions fit.modules.remove(dstMod) fit.modules.insert(self.dst, new) diff --git a/gui/fitCommands/guiAddCharge.py b/gui/fitCommands/guiAddCharge.py index 94d7d4249..6d1e5e70a 100644 --- a/gui/fitCommands/guiAddCharge.py +++ b/gui/fitCommands/guiAddCharge.py @@ -23,7 +23,7 @@ class GuiModuleAddChargeCommand(wx.Command): return False def Undo(self): - for x in self.internal_history.Commands: + for _ in self.internal_history.Commands: self.internal_history.Undo() self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) diff --git a/gui/fitCommands/guiSwapCloneModule.py b/gui/fitCommands/guiSwapCloneModule.py index bc283943c..65ddea591 100644 --- a/gui/fitCommands/guiSwapCloneModule.py +++ b/gui/fitCommands/guiSwapCloneModule.py @@ -4,11 +4,14 @@ from service.fit import Fit import gui.mainFrame from gui import globalEvents as GE from gui.fitCommands.calc.fitSwapModule import FitSwapModuleCommand -from .calc.fitCloneModule import FitCloneModduleCommand +from .calc.fitCloneModule import FitCloneModuleCommand +from logbook import Logger +pyfalog = Logger(__name__) + 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") self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.sFit = Fit.getInstance() @@ -19,17 +22,24 @@ class GuiModuleSwapOrCloneCommand(wx.Command): self.internal_history = wx.CommandProcessor() def Do(self): - result = None - if self.clone: - result = self.internal_history.Submit(FitCloneModduleCommand(self.fitID, self.srcPosition, self.dstPosition)) - else: - result = self.internal_history.Submit(FitSwapModuleCommand(self.fitID, self.srcPosition, self.dstPosition)) + pyfalog.debug("{} Do()".format(self)) - if result: - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) - return result + if self.clone: + pyfalog.debug("Trying to clone module") + if self.internal_history.Submit(FitCloneModuleCommand(self.fitID, self.srcPosition, self.dstPosition)): + self.sFit.recalc(self.fitID) # clone needs a recalc + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + else: + pyfalog.debug("Trying to Swap module") + if self.internal_history.Submit(FitSwapModuleCommand(self.fitID, self.srcPosition, self.dstPosition)): + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + + return False def Undo(self): + pyfalog.debug("{} Undo()".format(self)) for _ in self.internal_history.Commands: self.internal_history.Undo() wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) diff --git a/gui/fitCommands/guiToggleModuleState.py b/gui/fitCommands/guiToggleModuleState.py index 0f2344e64..7fcd824b1 100644 --- a/gui/fitCommands/guiToggleModuleState.py +++ b/gui/fitCommands/guiToggleModuleState.py @@ -5,6 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitChangeState import FitChangeStatesCommand + class GuiModuleStateChangeCommand(wx.Command): def __init__(self, fitID, baseMod, modules, click): # todo: instead of modules, needs to be positions. Dead objects are a thing @@ -16,16 +17,19 @@ class GuiModuleStateChangeCommand(wx.Command): self.modules = modules self.click = click self.internal_history = wx.CommandProcessor() + self.cmd = FitChangeStatesCommand(self.fitID, self.baseMod, self.modules, self.click) def Do(self): - # todo: determine if we've changed state (recalc). If not, store that so we don't attempt to recalc on undo - self.internal_history.Submit(FitChangeStatesCommand(self.fitID, self.baseMod, self.modules, self.click)) + if self.internal_history.Submit(self.cmd): + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for _ in self.internal_history.Commands: + self.internal_history.Undo() + self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - def Undo(self): - for x in self.internal_history.Commands: - self.internal_history.Undo() - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) - return True - From 168622052316f8f840a538ad37dd338f1fd69119 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Fri, 3 Aug 2018 01:42:06 -0400 Subject: [PATCH 24/95] Fix the state change command to not store the modules themselves, but the positions --- gui/builtinViews/fittingView.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index 247003b55..74d02295c 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -268,7 +268,9 @@ class FittingView(d.Display): sel = [] row = self.GetFirstSelected() while row != -1: - sel.append(self.mods[self.GetItemData(row)]) + mod = self.mods[self.GetItemData(row)] + if mod and not isinstance(mod, Rack): + sel.append(mod) row = self.GetNextSelected(row) return sel @@ -629,7 +631,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.GuiModuleStateChangeCommand(fitID, self.mods[self.GetItemData(row)], mods, click)) + self.mainFrame.command.Submit(cmd.GuiModuleStateChangeCommand(fitID, self.mods[self.GetItemData(row)].modPosition, [mod.modPosition for mod in mods], click)) # update state tooltip tooltip = self.activeColumns[col].getToolTip(self.mods[self.GetItemData(row)]) From aa282990a5a3a08d85fb90e1edc90b308a3bafe5 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Fri, 3 Aug 2018 01:42:06 -0400 Subject: [PATCH 25/95] Fix the state change command to not store the modules themselves, but the positions --- gui/builtinViews/fittingView.py | 6 ++- gui/fitCommands/calc/fitChangeState.py | 59 ++++++++++++++++---------- 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index 247003b55..74d02295c 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -268,7 +268,9 @@ class FittingView(d.Display): sel = [] row = self.GetFirstSelected() while row != -1: - sel.append(self.mods[self.GetItemData(row)]) + mod = self.mods[self.GetItemData(row)] + if mod and not isinstance(mod, Rack): + sel.append(mod) row = self.GetNextSelected(row) return sel @@ -629,7 +631,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.GuiModuleStateChangeCommand(fitID, self.mods[self.GetItemData(row)], mods, click)) + self.mainFrame.command.Submit(cmd.GuiModuleStateChangeCommand(fitID, self.mods[self.GetItemData(row)].modPosition, [mod.modPosition for mod in mods], click)) # update state tooltip tooltip = self.activeColumns[col].getToolTip(self.mods[self.GetItemData(row)]) diff --git a/gui/fitCommands/calc/fitChangeState.py b/gui/fitCommands/calc/fitChangeState.py index 06ad7bfbd..a6a1548cd 100644 --- a/gui/fitCommands/calc/fitChangeState.py +++ b/gui/fitCommands/calc/fitChangeState.py @@ -9,40 +9,53 @@ pyfalog = Logger(__name__) import eos.db class FitChangeStatesCommand(wx.Command): - def __init__(self, fitID, baseMod, modules, click): + """ + Fitting command that trys to change the state of modules in [positions]. We use the base module to determine the + state that we will try to apply for all modules. + + + """ + def __init__(self, fitID, baseModPos, positions, click): # todo: instead of modules, needs to be positions. Dead objects are a thing wx.Command.__init__(self, True, "Module State Change") self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.sFit = Fit.getInstance() self.fitID = fitID - self.baseMod = baseMod - self.modules = modules + self.baseModPos = baseModPos + self.positions = positions self.click = click self.changed = None self.old_states = {} - for mod in modules: - # we don't use the actual module as the key, because it may have been deleted in subsequent calls (even if - # we undo a deletion, wouldn't be the same obj). So, we store the position - self.old_states[mod.modPosition] = mod.state def Do(self): - pyfalog.debug("Toggle module state for fit ID: {0}", self.fitID) - changed = False - proposedState = Module.getProposedState(self.baseMod, self.click) + fit = eos.db.getFit(self.fitID) - if proposedState != self.baseMod.state: - changed = True - self.baseMod.state = proposedState - for mod in self.modules: - if mod != self.baseMod: - p = Module.getProposedState(mod, self.click, proposedState) - mod.state = p - if p != mod.state: - changed = True + baseMod = fit.modules[self.baseModPos] + + # make sure positions only include non-empty positions + self.positions = [x for x in self.positions if not fit.modules[x].isEmpty] + + for x in self.positions: + self.old_states[x] = fit.modules[x].state + + proposedState = Module.getProposedState(baseMod, self.click) + pyfalog.debug("Attempting to change modules to {}", proposedState) + + if proposedState != baseMod.state: + pyfalog.debug("Toggle {} state: {} for fit ID: {}", baseMod, proposedState, self.fitID) + + self.changed = True + baseMod.state = proposedState + for i in [x for x in self.positions if x != self.baseModPos]: # dont consider base module position + mod = fit.modules[i] + p = Module.getProposedState(mod, self.click, proposedState) + mod.state = p + if p != mod.state: + pyfalog.debug("Toggle {} state: {} for fit ID: {}", mod, p, self.fitID) + self.changed = True # if we haven't change the state (eg, overheat -> overheat), simply fail the command - if changed: - self.changed = changed + if self.changed: eos.db.commit() # As some items may affect state-limiting attributes of the ship, calculate new attributes first # self.recalc(fit) @@ -55,5 +68,7 @@ class FitChangeStatesCommand(wx.Command): # todo: some sanity checking to make sure that we are applying state back to the same modules? fit = self.sFit.getFit(self.fitID) for k, v in self.old_states.items(): - fit.modules[k].state = v + mod = fit.modules[k] + pyfalog.debug("Reverting {} to state {} for fit ID", mod, v, self.fitID) + mod.state = v return True From 6057a1a7d99018fdf09e6990590d2d447b992ded Mon Sep 17 00:00:00 2001 From: blitzmann Date: Fri, 3 Aug 2018 02:01:26 -0400 Subject: [PATCH 26/95] Fix issue with setting None charge --- gui/fitCommands/calc/fitSetCharge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/fitCommands/calc/fitSetCharge.py b/gui/fitCommands/calc/fitSetCharge.py index d06258924..eeb4df407 100644 --- a/gui/fitCommands/calc/fitSetCharge.py +++ b/gui/fitCommands/calc/fitSetCharge.py @@ -32,7 +32,7 @@ class FitSetChargeCommand(wx.Command): self.cache = {fit.modules[i].modPosition: fit.modules[i].chargeID for i in positions} ammo = eos.db.getItem(chargeID) if chargeID else None - if not ammo.isCharge: + if ammo is not None and not ammo.isCharge: return False result = False From 15ba5c8ace1b1fcb2a22e48d0af87838a06ca37e Mon Sep 17 00:00:00 2001 From: blitzmann Date: Fri, 3 Aug 2018 02:01:42 -0400 Subject: [PATCH 27/95] Convert tactical mode switching --- gui/builtinContextMenus/tacticalMode.py | 6 ++--- gui/fitCommands/__init__.py | 1 + gui/fitCommands/calc/fitSetMode.py | 34 +++++++++++++++++++++++++ gui/fitCommands/guiSetMode.py | 31 ++++++++++++++++++++++ service/fit.py | 1 + 5 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 gui/fitCommands/calc/fitSetMode.py create mode 100644 gui/fitCommands/guiSetMode.py diff --git a/gui/builtinContextMenus/tacticalMode.py b/gui/builtinContextMenus/tacticalMode.py index e09b26940..04c82574f 100644 --- a/gui/builtinContextMenus/tacticalMode.py +++ b/gui/builtinContextMenus/tacticalMode.py @@ -6,7 +6,7 @@ import gui.mainFrame import gui.globalEvents as GE from service.fit import Fit from service.settings import ContextMenuSettings - +import gui.fitCommands as cmd class TacticalMode(ContextMenu): def __init__(self): @@ -60,10 +60,8 @@ class TacticalMode(ContextMenu): event.Skip() return - sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() - sFit.setMode(fitID, self.modeIds[event.Id]) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.GuiSetModeCommand(fitID, self.modeIds[event.Id])) TacticalMode.register() diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index 89a74b369..c7a37439f 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -7,3 +7,4 @@ from .guiRemoveCargo import GuiRemoveCargoCommand from .guiAddCargo import GuiAddCargoCommand from .guiRemoveImplant import GuiRemoveImplantCommand from .guiAddImplant import GuiAddImplantCommand +from .guiSetMode import GuiSetModeCommand \ No newline at end of file diff --git a/gui/fitCommands/calc/fitSetMode.py b/gui/fitCommands/calc/fitSetMode.py new file mode 100644 index 000000000..183c292aa --- /dev/null +++ b/gui/fitCommands/calc/fitSetMode.py @@ -0,0 +1,34 @@ +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 FitSetModeCommand(wx.Command): + """" + from sFit.setMode + """ + def __init__(self, fitID, mode): + wx.Command.__init__(self, True, "Cargo add") + self.fitID = fitID + self.mode = mode + self.old_mode = None + + def Do(self): + pyfalog.debug("Set mode for fit ID: {0}", self.fitID) + fit = eos.db.getFit(self.fitID) + self.old_mode = fit.mode + fit.mode = self.mode + eos.db.commit() + return True + + def Undo(self): + cmd = FitSetModeCommand(self.fitID, self.old_mode) + cmd.Do() + return True diff --git a/gui/fitCommands/guiSetMode.py b/gui/fitCommands/guiSetMode.py new file mode 100644 index 000000000..2c1e4864c --- /dev/null +++ b/gui/fitCommands/guiSetMode.py @@ -0,0 +1,31 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from .calc.fitSetMode import FitSetModeCommand + +class GuiSetModeCommand(wx.Command): + def __init__(self, fitID, mode): + wx.Command.__init__(self, True, "Cargo Add") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() + self.fitID = fitID + # can set his up no to not have to set variables on our object + self.cmd = FitSetModeCommand(fitID, mode) + + def Do(self): + if self.internal_history.Submit(self.cmd): + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for _ in self.internal_history.Commands: + self.internal_history.Undo() + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + diff --git a/service/fit.py b/service/fit.py index d3ed7d9c7..47c9c2960 100644 --- a/service/fit.py +++ b/service/fit.py @@ -1155,6 +1155,7 @@ class Fit(object): self.recalc(fit) + @deprecated def setMode(self, fitID, mode): pyfalog.debug("Set mode for fit ID: {0}", fitID) if fitID is None: From fcc53d3f214c74f8fd2c00c4fee2cfe220568288 Mon Sep 17 00:00:00 2001 From: Ryan Holmes Date: Fri, 3 Aug 2018 16:10:27 -0400 Subject: [PATCH 28/95] Add commands for booster and command fits --- eos/db/saveddata/fit.py | 2 +- eos/saveddata/fit.py | 4 +- gui/builtinAdditionPanes/boosterView.py | 10 ++--- gui/builtinAdditionPanes/commandView.py | 11 ++--- gui/builtinContextMenus/itemRemove.py | 3 +- gui/builtinContextMenus/metaSwap.py | 12 +++--- gui/fitCommands/__init__.py | 4 ++ gui/fitCommands/calc/fitAddBooster.py | 42 +++++++++++++++++++ gui/fitCommands/calc/fitAddCommand.py | 53 ++++++++++++++++++++++++ gui/fitCommands/calc/fitRemoveBooster.py | 32 ++++++++++++++ gui/fitCommands/calc/fitRemoveCommand.py | 43 +++++++++++++++++++ gui/fitCommands/guiAddBooster.py | 29 +++++++++++++ gui/fitCommands/guiAddCommand.py | 29 +++++++++++++ gui/fitCommands/guiAddModule.py | 1 + gui/fitCommands/guiRemoveBooster.py | 29 +++++++++++++ gui/fitCommands/guiRemoveCommand.py | 29 +++++++++++++ service/fit.py | 8 +++- 17 files changed, 318 insertions(+), 23 deletions(-) create mode 100644 gui/fitCommands/calc/fitAddBooster.py create mode 100644 gui/fitCommands/calc/fitAddCommand.py create mode 100644 gui/fitCommands/calc/fitRemoveBooster.py create mode 100644 gui/fitCommands/calc/fitRemoveCommand.py create mode 100644 gui/fitCommands/guiAddBooster.py create mode 100644 gui/fitCommands/guiAddCommand.py create mode 100644 gui/fitCommands/guiRemoveBooster.py create mode 100644 gui/fitCommands/guiRemoveCommand.py diff --git a/eos/db/saveddata/fit.py b/eos/db/saveddata/fit.py index 0ae4509e2..9701d5d6b 100644 --- a/eos/db/saveddata/fit.py +++ b/eos/db/saveddata/fit.py @@ -138,7 +138,7 @@ es_Fit._Fit__projectedFits = association_proxy( creator=lambda sourceID, source_fit: ProjectedFit(sourceID, source_fit) ) -es_Fit._Fit__commandFits = association_proxy( +es_Fit.commandFitDict = association_proxy( "boostedOf", # look at the boostedOf association... "booster_fit", # .. and return the booster fit creator=lambda boosterID, booster_fit: CommandFit(boosterID, booster_fit) diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index 8f5cc2b36..7b9e79e6c 100644 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -262,7 +262,7 @@ class Fit(object): @property def commandFits(self): - return [fit for fit in list(self.__commandFits.values()) if not fit.isInvalid] + return [fit for fit in list(self.commandFitDict.values()) if not fit.isInvalid] def getProjectionInfo(self, fitID): return self.projectedOnto.get(fitID, None) @@ -1605,7 +1605,7 @@ class Fit(object): eos.db.saveddata_session.refresh(fit) for fit in self.commandFits: - copy_ship.__commandFits[fit.ID] = fit + copy_ship.commandFitDict[fit.ID] = fit forceUpdateSavedata(fit) copyCommandInfo = fit.getCommandInfo(copy_ship.ID) originalCommandInfo = fit.getCommandInfo(self.ID) diff --git a/gui/builtinAdditionPanes/boosterView.py b/gui/builtinAdditionPanes/boosterView.py index 8923f83de..ef9c88f2d 100644 --- a/gui/builtinAdditionPanes/boosterView.py +++ b/gui/builtinAdditionPanes/boosterView.py @@ -26,7 +26,7 @@ from gui.builtinViewColumns.state import State from gui.contextMenu import ContextMenu from gui.utils.staticHelpers import DragDropHelper from service.fit import Fit - +import gui.fitCommands as cmd class BoosterViewDrop(wx.DropTarget): def __init__(self, dropFn, *args, **kwargs): @@ -134,9 +134,7 @@ class BoosterView(d.Display): event.Skip() return - trigger = sFit.addBooster(fitID, event.itemID) - if trigger: - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + if self.mainFrame.command.Submit(cmd.GuiAddBoosterCommand(fitID, event.itemID)): self.mainFrame.additionsPane.select("Boosters") event.Skip() @@ -150,9 +148,7 @@ class BoosterView(d.Display): def removeBooster(self, booster): fitID = self.mainFrame.getActiveFit() - sFit = Fit.getInstance() - sFit.removeBooster(fitID, self.origional.index(booster)) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.GuiRemoveImplantCommand(fitID, self.origional.index(booster))) def click(self, event): event.Skip() diff --git a/gui/builtinAdditionPanes/commandView.py b/gui/builtinAdditionPanes/commandView.py index 2bfa700c9..52cda66cb 100644 --- a/gui/builtinAdditionPanes/commandView.py +++ b/gui/builtinAdditionPanes/commandView.py @@ -30,7 +30,7 @@ from gui.builtinViewColumns.state import State from gui.contextMenu import ContextMenu from gui.utils.staticHelpers import DragDropHelper from service.fit import Fit - +import gui.fitCommands as cmd class DummyItem(object): def __init__(self, txt): @@ -111,10 +111,11 @@ class CommandView(d.Display): if type == "fit": activeFit = self.mainFrame.getActiveFit() if activeFit: - sFit = Fit.getInstance() - draggedFit = sFit.getFit(fitID) - sFit.addCommandFit(activeFit, draggedFit) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFit)) + # sFit = Fit.getInstance() + # draggedFit = sFit.getFit(fitID) + # sFit.addCommandFit(activeFit, draggedFit) + # wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFit)) + self.mainFrame.command.Submit(cmd.GuiAddCommandCommand(activeFit, fitID)) def startDrag(self, event): row = event.GetIndex() diff --git a/gui/builtinContextMenus/itemRemove.py b/gui/builtinContextMenus/itemRemove.py index b3cb414b5..60a0d36d1 100644 --- a/gui/builtinContextMenus/itemRemove.py +++ b/gui/builtinContextMenus/itemRemove.py @@ -48,7 +48,8 @@ class ItemRemove(ContextMenu): self.mainFrame.command.Submit(cmd.GuiRemoveImplantCommand(fitID, fit.implants.index(selection[0]))) return # the command takes care of the PostEvent elif srcContext == "boosterItem": - sFit.removeBooster(fitID, fit.boosters.index(selection[0])) + self.mainFrame.command.Submit(cmd.GuiRemoveBoosterCommand(fitID, fit.boosters.index(selection[0]))) + return # the command takes care of the PostEvent elif srcContext == "cargoItem": self.mainFrame.command.Submit(cmd.GuiRemoveCargoCommand(fitID, selection[0].itemID)) return # the command takes care of the PostEvent diff --git a/gui/builtinContextMenus/metaSwap.py b/gui/builtinContextMenus/metaSwap.py index 7956848f8..871ebad68 100644 --- a/gui/builtinContextMenus/metaSwap.py +++ b/gui/builtinContextMenus/metaSwap.py @@ -140,6 +140,7 @@ class MetaSwap(ContextMenu): if isinstance(selected_item, Module): pos = fit.modules.index(selected_item) sFit.changeModule(fitID, pos, item.ID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) elif isinstance(selected_item, Drone): drone_count = None @@ -152,6 +153,7 @@ class MetaSwap(ContextMenu): if drone_count: sFit.addDrone(fitID, item.ID, drone_count, True) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) elif isinstance(selected_item, Fighter): fighter_count = None @@ -172,12 +174,13 @@ class MetaSwap(ContextMenu): break sFit.addFighter(fitID, item.ID, True) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) elif isinstance(selected_item, Booster): for idx, booster_stack in enumerate(fit.boosters): if booster_stack is selected_item: - sFit.removeBooster(fitID, idx, False) - sFit.addBooster(fitID, item.ID, True) + self.mainFrame.command.Submit(cmd.GuiRemoveBoosterCommand(fitID, idx)) + self.mainFrame.command.Submit(cmd.GuiAddBoosterCommand(fitID, item.ID)) break elif isinstance(selected_item, Implant): @@ -185,7 +188,7 @@ class MetaSwap(ContextMenu): if implant_stack is selected_item: self.mainFrame.command.Submit(cmd.GuiRemoveImplantCommand(fitID, idx)) self.mainFrame.command.Submit(cmd.GuiAddImplantCommand(fitID, item.ID)) - return + break elif isinstance(selected_item, Cargo): for idx, cargo_stack in enumerate(fit.cargo): @@ -194,9 +197,8 @@ class MetaSwap(ContextMenu): # utilize the two fitting commands that we need to remove then add? sFit.removeCargo(fitID, idx) self.mainFrame.command.Submit(cmd.GuiAddCargoCommand(fitID, item.ID, cargo_stack.amount, True)) - return # don't need the post event + break - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) MetaSwap.register() diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index 89a74b369..1102eaf08 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -7,3 +7,7 @@ from .guiRemoveCargo import GuiRemoveCargoCommand from .guiAddCargo import GuiAddCargoCommand from .guiRemoveImplant import GuiRemoveImplantCommand from .guiAddImplant import GuiAddImplantCommand +from .guiAddBooster import GuiAddBoosterCommand +from .guiRemoveBooster import GuiRemoveBoosterCommand +from .guiAddCommand import GuiAddCommandCommand +from .guiRemoveCommand import GuiRemoveCommandCommand \ No newline at end of file diff --git a/gui/fitCommands/calc/fitAddBooster.py b/gui/fitCommands/calc/fitAddBooster.py new file mode 100644 index 000000000..356a742da --- /dev/null +++ b/gui/fitCommands/calc/fitAddBooster.py @@ -0,0 +1,42 @@ +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__) +from eos.saveddata.booster import Booster + +class FitAddBoosterCommand(wx.Command): + """" + from sFit.addBooster + """ + def __init__(self, fitID, itemID): + wx.Command.__init__(self, True) + self.fitID = fitID + self.itemID = itemID + self.new_index = None + + def Do(self): + pyfalog.debug("Adding booster ({0}) to fit ID: {1}", self.itemID, self.fitID) + + fit = eos.db.getFit(self.fitID) + item = eos.db.getItem(self.itemID, eager="attributes") + try: + booster = Booster(item) + except ValueError: + pyfalog.warning("Invalid item: {0}", self.itemID) + return False + + fit.boosters.append(booster) + self.new_index = fit.boosters.index(booster) + return True + + def Undo(self): + from .fitRemoveBooster import FitRemoveBoosterCommand # Avoid circular import + cmd = FitRemoveBoosterCommand(self.fitID, self.new_index) + cmd.Do() + return True diff --git a/gui/fitCommands/calc/fitAddCommand.py b/gui/fitCommands/calc/fitAddCommand.py new file mode 100644 index 000000000..61dbc68b7 --- /dev/null +++ b/gui/fitCommands/calc/fitAddCommand.py @@ -0,0 +1,53 @@ +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 FitAddCommandCommand(wx.Command): # well that's an unfrtunate name + """" + from sFit.addCommand + """ + def __init__(self, fitID, commandFitID): + wx.Command.__init__(self, True) + self.fitID = fitID + self.commandFitID = commandFitID + + def Do(self): + pyfalog.debug("Projecting command fit ({0}) onto: {1}", self.fitID, self.commandFitID) + fit = eos.db.getFit(self.fitID) + command = eos.db.getFit(self.commandFitID) + + if not command: + # if redoing when the command fit has been deleted, simply fail this command + return False + + if command in fit.commandFits: + return + + fit.commandFitDict[command.ID] = command + + # this bit is required -- see GH issue # 83 + eos.db.saveddata_session.flush() + eos.db.saveddata_session.refresh(command) + + eos.db.commit() + return True + + def Undo(self): + command = eos.db.getFit(self.commandFitID) + + if not command: + # can't find the command fit, it must have been deleted. Just skip this undo + return True + + from .fitRemoveCommand import FitRemoveCommandCommand + cmd = FitRemoveCommandCommand(self.fitID, self.commandFitID) + cmd.Do() + return True diff --git a/gui/fitCommands/calc/fitRemoveBooster.py b/gui/fitCommands/calc/fitRemoveBooster.py new file mode 100644 index 000000000..f22b6fb8e --- /dev/null +++ b/gui/fitCommands/calc/fitRemoveBooster.py @@ -0,0 +1,32 @@ +import wx + +#from .helpers import ModuleInfoCache +import eos.db +from logbook import Logger +pyfalog = Logger(__name__) + + +class FitRemoveBoosterCommand(wx.Command): + """" + from sFit.removeBooster + """ + def __init__(self, fitID, position): + wx.Command.__init__(self, True, "Implant remove") + self.fitID = fitID + self.position = position + self.old = None + + def Do(self): + pyfalog.debug("Removing booster from position ({0}) for fit ID: {1}", self.position, self.fitID) + + fit = eos.db.getFit(self.fitID) + booster = fit.boosters[self.position] + self.old = booster.itemID + fit.boosters.remove(booster) + return True + + def Undo(self): + from .fitAddBooster import FitAddBoosterCommand # Avoid circular import + cmd = FitAddBoosterCommand(self.fitID, self.old) + cmd.Do() + return True diff --git a/gui/fitCommands/calc/fitRemoveCommand.py b/gui/fitCommands/calc/fitRemoveCommand.py new file mode 100644 index 000000000..57052aa1e --- /dev/null +++ b/gui/fitCommands/calc/fitRemoveCommand.py @@ -0,0 +1,43 @@ +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 FitRemoveCommandCommand(wx.Command): # well that's an unfrtunate name + """" + from sFit.removeCommand + """ + def __init__(self, fitID, commandFitID): + wx.Command.__init__(self, True) + self.fitID = fitID + self.commandFitID = commandFitID + + def Do(self): + pyfalog.debug("Removing command projection from fit ({0}) for: {1}", self.fitID, self.commandFitID) + fit = eos.db.getFit(self.fitID) + command = eos.db.getFit(self.commandFitID) + if not command: + return False + del fit.commandFitDict[command.ID] + + eos.db.commit() + return True + + def Undo(self): + command = eos.db.getFit(self.commandFitID) + + if not command: + # can't find the command fit, it must have been deleted. Just skip this undo + return True + + from .fitAddCommand import FitAddCommandCommand + cmd = FitAddCommandCommand(self.fitID, self.commandFitID) + cmd.Do() + return True diff --git a/gui/fitCommands/guiAddBooster.py b/gui/fitCommands/guiAddBooster.py new file mode 100644 index 000000000..392ce3034 --- /dev/null +++ b/gui/fitCommands/guiAddBooster.py @@ -0,0 +1,29 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from .calc.fitAddBooster import FitAddBoosterCommand + +class GuiAddBoosterCommand(wx.Command): + def __init__(self, fitID, itemID): + wx.Command.__init__(self, True, "Booster Add") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() + self.fitID = fitID + # can set his up no to not have to set variables on our object + self.cmd = FitAddBoosterCommand(fitID, itemID) + + def Do(self): + if self.internal_history.Submit(self.cmd): + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for x in self.internal_history.Commands: + self.internal_history.Undo() + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + diff --git a/gui/fitCommands/guiAddCommand.py b/gui/fitCommands/guiAddCommand.py new file mode 100644 index 000000000..995bc545a --- /dev/null +++ b/gui/fitCommands/guiAddCommand.py @@ -0,0 +1,29 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from .calc.fitAddCommand import FitAddCommandCommand + +class GuiAddCommandCommand(wx.Command): + def __init__(self, fitID, commandFitID): + wx.Command.__init__(self, True, "") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() + self.fitID = fitID + # can set his up no to not have to set variables on our object + self.cmd = FitAddCommandCommand(fitID, commandFitID) + + def Do(self): + if self.internal_history.Submit(self.cmd): + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for x in self.internal_history.Commands: + self.internal_history.Undo() + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + diff --git a/gui/fitCommands/guiAddModule.py b/gui/fitCommands/guiAddModule.py index 5abf52651..12d26d6ac 100644 --- a/gui/fitCommands/guiAddModule.py +++ b/gui/fitCommands/guiAddModule.py @@ -1,6 +1,7 @@ import wx import gui.mainFrame +from service.fit import Fit from gui import globalEvents as GE from .calc.fitAddModule import FitAddModuleCommand from .calc.fitReplaceModule import FitReplaceModuleCommand diff --git a/gui/fitCommands/guiRemoveBooster.py b/gui/fitCommands/guiRemoveBooster.py new file mode 100644 index 000000000..92578b0b8 --- /dev/null +++ b/gui/fitCommands/guiRemoveBooster.py @@ -0,0 +1,29 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from .calc.fitRemoveBooster import FitRemoveBoosterCommand + +class GuiRemoveBoosterCommand(wx.Command): + def __init__(self, fitID, position): + wx.Command.__init__(self, True, "") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() + self.fitID = fitID + # can set his up no to not have to set variables on our object + self.cmd = FitRemoveBoosterCommand(fitID, position) + + def Do(self): + if self.internal_history.Submit(self.cmd): + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for x in self.internal_history.Commands: + self.internal_history.Undo() + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + diff --git a/gui/fitCommands/guiRemoveCommand.py b/gui/fitCommands/guiRemoveCommand.py new file mode 100644 index 000000000..d2c13c749 --- /dev/null +++ b/gui/fitCommands/guiRemoveCommand.py @@ -0,0 +1,29 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from .calc.fitRemoveCommand import FitRemoveCommandCommand + +class GuiRemoveCommandCommand(wx.Command): + def __init__(self, fitID, commandFitID): + wx.Command.__init__(self, True, "") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() + self.fitID = fitID + # can set his up no to not have to set variables on our object + self.cmd = FitRemoveCommandCommand(fitID, commandFitID) + + def Do(self): + if self.internal_history.Submit(self.cmd): + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for x in self.internal_history.Commands: + self.internal_history.Undo() + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + diff --git a/service/fit.py b/service/fit.py index 016f5989a..e5ff9b21c 100644 --- a/service/fit.py +++ b/service/fit.py @@ -365,6 +365,7 @@ class Fit(object): self.recalc(fit) return True + @deprecated def addBooster(self, fitID, itemID, recalc=True): pyfalog.debug("Adding booster ({0}) to fit ID: {1}", itemID, fitID) if fitID is None: @@ -383,6 +384,7 @@ class Fit(object): self.recalc(fit) return True + @deprecated def removeBooster(self, fitID, position, recalc=True): pyfalog.debug("Removing booster from position ({0}) for fit ID: {1}", position, fitID) if fitID is None: @@ -451,6 +453,7 @@ class Fit(object): self.recalc(fit) return True + @deprecated def addCommandFit(self, fitID, thing): pyfalog.debug("Projecting command fit ({0}) onto: {1}", fitID, thing) if fitID is None: @@ -461,7 +464,7 @@ class Fit(object): if thing in fit.commandFits: return - fit.__commandFits[thing.ID] = thing + fit.commandFitDict[thing.ID] = thing # this bit is required -- see GH issue # 83 eos.db.saveddata_session.flush() @@ -539,10 +542,11 @@ class Fit(object): eos.db.commit() self.recalc(fit) + @deprecated def removeCommand(self, fitID, thing): pyfalog.debug("Removing command projection from fit ({0}) for: {1}", fitID, thing) fit = eos.db.getFit(fitID) - del fit.__commandFits[thing.ID] + del fit.commandFitDict[thing.ID] eos.db.commit() self.recalc(fit) From 3c7f0258dfc5d1212c15b8b63bb4641a885301bb Mon Sep 17 00:00:00 2001 From: blitzmann Date: Fri, 3 Aug 2018 21:19:51 -0400 Subject: [PATCH 29/95] More converting for command fits --- gui/builtinAdditionPanes/commandView.py | 10 ++-------- gui/builtinContextMenus/commandFits.py | 6 ++---- gui/builtinContextMenus/itemRemove.py | 4 ++-- gui/builtinContextMenus/tabbedFits.py | 7 +++---- gui/builtinShipBrowser/fitItem.py | 9 +++------ gui/fitCommands/guiAddCommand.py | 4 +++- gui/fitCommands/guiRemoveCommand.py | 4 +++- 7 files changed, 18 insertions(+), 26 deletions(-) diff --git a/gui/builtinAdditionPanes/commandView.py b/gui/builtinAdditionPanes/commandView.py index 52cda66cb..7a35ac74b 100644 --- a/gui/builtinAdditionPanes/commandView.py +++ b/gui/builtinAdditionPanes/commandView.py @@ -103,18 +103,13 @@ class CommandView(d.Display): sFit = Fit.getInstance() row = self.GetFirstSelected() if row != -1: - sFit.removeCommand(fitID, self.get(row)) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.GuiRemoveCommandCommand(fitID, self.get(row).ID)) def handleDrag(self, type, fitID): # Those are drags coming from pyfa sources, NOT builtin wx drags if type == "fit": activeFit = self.mainFrame.getActiveFit() if activeFit: - # sFit = Fit.getInstance() - # draggedFit = sFit.getFit(fitID) - # sFit.addCommandFit(activeFit, draggedFit) - # wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFit)) self.mainFrame.command.Submit(cmd.GuiAddCommandCommand(activeFit, fitID)) def startDrag(self, event): @@ -228,5 +223,4 @@ class CommandView(d.Display): sFit = Fit.getInstance() thing = self.get(row) if thing: # thing doesn't exist if it's the dummy value - sFit.removeCommand(fitID, thing) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.GuiRemoveCommandCommand(fitID, thing.ID)) diff --git a/gui/builtinContextMenus/commandFits.py b/gui/builtinContextMenus/commandFits.py index 936dd0cc0..d2dd7ec94 100644 --- a/gui/builtinContextMenus/commandFits.py +++ b/gui/builtinContextMenus/commandFits.py @@ -7,7 +7,7 @@ import gui.mainFrame import gui.globalEvents as GE from gui.contextMenu import ContextMenu from service.settings import ContextMenuSettings - +import gui.fitCommands as cmd class CommandFits(ContextMenu): # Get list of items that define a command fit @@ -99,9 +99,7 @@ class CommandFits(ContextMenu): sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() - - sFit.addCommandFit(fitID, fit) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.GuiAddCommandCommand(fitID, fit.ID)) CommandFits.populateFits(None) diff --git a/gui/builtinContextMenus/itemRemove.py b/gui/builtinContextMenus/itemRemove.py index 60a0d36d1..d075eba2e 100644 --- a/gui/builtinContextMenus/itemRemove.py +++ b/gui/builtinContextMenus/itemRemove.py @@ -56,8 +56,8 @@ class ItemRemove(ContextMenu): elif srcContext in ("projectedFit", "projectedModule", "projectedDrone", "projectedFighter"): sFit.removeProjected(fitID, selection[0]) elif srcContext == "commandFit": - sFit.removeCommand(fitID, selection[0]) - + self.mainFrame.command.Submit(cmd.GuiRemoveCommandCommand(fitID, selection[0].ID)) + return wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) diff --git a/gui/builtinContextMenus/tabbedFits.py b/gui/builtinContextMenus/tabbedFits.py index c55a90b35..d8b516027 100644 --- a/gui/builtinContextMenus/tabbedFits.py +++ b/gui/builtinContextMenus/tabbedFits.py @@ -8,7 +8,7 @@ import gui.mainFrame import gui.globalEvents as GE from gui.contextMenu import ContextMenu from gui.builtinViews.emptyView import BlankPage - +import gui.fitCommands as cmd class TabbedFits(ContextMenu): def __init__(self): @@ -57,11 +57,10 @@ class TabbedFits(ContextMenu): fit = self.fitLookup[event.Id] if self.context == 'commandView': - sFit.addCommandFit(fitID, fit) + self.mainFrame.command.Submit(cmd.GuiAddCommandCommand(fitID, fit.ID)) elif self.context == 'projected': sFit.project(fitID, fit) - - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) TabbedFits.register() diff --git a/gui/builtinShipBrowser/fitItem.py b/gui/builtinShipBrowser/fitItem.py index 99cb9e0bb..73617a458 100644 --- a/gui/builtinShipBrowser/fitItem.py +++ b/gui/builtinShipBrowser/fitItem.py @@ -17,7 +17,7 @@ from .events import ImportSelected, SearchSelected, FitSelected, BoosterListUpda from gui.bitmap_loader import BitmapLoader from gui.builtinShipBrowser.pfBitmapFrame import PFBitmapFrame from service.fit import Fit - +import gui.fitCommands as cmd pyfalog = Logger(__name__) @@ -209,11 +209,8 @@ class FitItem(SFItem.SFBrowserItem): def OnAddCommandFit(self, event): activeFit = self.mainFrame.getActiveFit() if activeFit: - sFit = Fit.getInstance() - commandFit = sFit.getFit(self.fitID) - sFit.addCommandFit(activeFit, commandFit) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFit)) - self.mainFrame.additionsPane.select("Command") + if self.mainFrame.command.Submit(cmd.GuiAddCommandCommand(activeFit, self.fitID)): + self.mainFrame.additionsPane.select("Command") def OnMouseCaptureLost(self, event): """ Destroy drag information (GH issue #479)""" diff --git a/gui/fitCommands/guiAddCommand.py b/gui/fitCommands/guiAddCommand.py index 995bc545a..a46da244e 100644 --- a/gui/fitCommands/guiAddCommand.py +++ b/gui/fitCommands/guiAddCommand.py @@ -18,12 +18,14 @@ class GuiAddCommandCommand(wx.Command): def Do(self): if self.internal_history.Submit(self.cmd): wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + self.sFit.recalc(self.fitID) return True return False def Undo(self): - for x in self.internal_history.Commands: + for _ in self.internal_history.Commands: self.internal_history.Undo() + self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True diff --git a/gui/fitCommands/guiRemoveCommand.py b/gui/fitCommands/guiRemoveCommand.py index d2c13c749..d01abce08 100644 --- a/gui/fitCommands/guiRemoveCommand.py +++ b/gui/fitCommands/guiRemoveCommand.py @@ -17,13 +17,15 @@ class GuiRemoveCommandCommand(wx.Command): def Do(self): if self.internal_history.Submit(self.cmd): + self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True return False def Undo(self): - for x in self.internal_history.Commands: + for _ in self.internal_history.Commands: self.internal_history.Undo() + self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True From 425c7f657c6fa4acdd3946ece8909553aa69d47f Mon Sep 17 00:00:00 2001 From: blitzmann Date: Fri, 3 Aug 2018 22:30:09 -0400 Subject: [PATCH 30/95] Do command fit toggle. Still need to settle on the logic for how to handle deleted fits - seems there's an issue with the queue. --- gui/builtinAdditionPanes/commandView.py | 4 +-- gui/fitCommands/__init__.py | 1 + gui/fitCommands/calc/fitToggleCommand.py | 42 ++++++++++++++++++++++++ gui/fitCommands/guiToggleCommand.py | 31 +++++++++++++++++ service/fit.py | 1 + 5 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 gui/fitCommands/calc/fitToggleCommand.py create mode 100644 gui/fitCommands/guiToggleCommand.py diff --git a/gui/builtinAdditionPanes/commandView.py b/gui/builtinAdditionPanes/commandView.py index 7a35ac74b..d05e4fe8c 100644 --- a/gui/builtinAdditionPanes/commandView.py +++ b/gui/builtinAdditionPanes/commandView.py @@ -186,9 +186,7 @@ class CommandView(d.Display): col = self.getColumn(event.Position) if col == self.getColIndex(State): fitID = self.mainFrame.getActiveFit() - sFit = Fit.getInstance() - sFit.toggleCommandFit(fitID, item) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.GuiToggleCommandCommand(fitID, item.ID)) def scheduleMenu(self, event): event.Skip() diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index 7e16fecbb..7abbd4141 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -12,3 +12,4 @@ from .guiRemoveBooster import GuiRemoveBoosterCommand from .guiAddCommand import GuiAddCommandCommand from .guiRemoveCommand import GuiRemoveCommandCommand from .guiSetMode import GuiSetModeCommand +from .guiToggleCommand import GuiToggleCommandCommand \ No newline at end of file diff --git a/gui/fitCommands/calc/fitToggleCommand.py b/gui/fitCommands/calc/fitToggleCommand.py new file mode 100644 index 000000000..c8adc87ac --- /dev/null +++ b/gui/fitCommands/calc/fitToggleCommand.py @@ -0,0 +1,42 @@ +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__) +from eos.saveddata.implant import Implant + +class FitToggleCommandCommand(wx.Command): + """" + from sFit.toggleCommandFit + """ + def __init__(self, fitID, commandFitId): + wx.Command.__init__(self, True, "Cargo add") + self.fitID = fitID + self.commandFitID = commandFitId + + def Do(self): + pyfalog.debug("Toggle command fit ({0}) for: {1}", self.commandFitID, self.fitID) + commandFit = eos.db.getFit(self.commandFitID) + + if not commandFit: + pyfalog.debug(" -- Command fit not found, deleted?") + return False + + commandInfo = commandFit.getCommandInfo(self.fitID) + + if not commandInfo: + pyfalog.debug(" -- Command fit info not found, deleted?") + return False + + commandInfo.active = not commandInfo.active + eos.db.commit() + return True + + def Undo(self): + cmd = FitToggleCommandCommand(self.fitID, self.commandFitID) + return cmd.Do() diff --git a/gui/fitCommands/guiToggleCommand.py b/gui/fitCommands/guiToggleCommand.py new file mode 100644 index 000000000..b7f07ed78 --- /dev/null +++ b/gui/fitCommands/guiToggleCommand.py @@ -0,0 +1,31 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from .calc.fitToggleCommand import FitToggleCommandCommand + +class GuiToggleCommandCommand(wx.Command): + def __init__(self, fitID, commandFitID): + wx.Command.__init__(self, True, "") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() + self.fitID = fitID + # can set his up no to not have to set variables on our object + self.cmd = FitToggleCommandCommand(fitID, commandFitID) + + def Do(self): + if self.internal_history.Submit(self.cmd): + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for _ in self.internal_history.Commands: + self.internal_history.Undo() + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + diff --git a/service/fit.py b/service/fit.py index d581ff07f..238c5c58b 100644 --- a/service/fit.py +++ b/service/fit.py @@ -496,6 +496,7 @@ class Fit(object): eos.db.commit() self.recalc(fit) + @deprecated def toggleCommandFit(self, fitID, thing): pyfalog.debug("Toggle command fit ({0}) for: {1}", fitID, thing) fit = eos.db.getFit(fitID) From 0f4f8c636d72085b7d14c77e46e88d1ec72ced37 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 4 Aug 2018 22:10:14 -0400 Subject: [PATCH 31/95] Start working on projections --- gui/builtinAdditionPanes/projectedView.py | 19 ++--- gui/builtinContextMenus/project.py | 12 ++-- gui/builtinContextMenus/tabbedFits.py | 4 +- gui/builtinContextMenus/whProjector.py | 6 +- gui/builtinShipBrowser/fitItem.py | 5 +- gui/fitCommands/__init__.py | 3 +- gui/fitCommands/calc/fitAddProjectedModule.py | 49 +++++++++++++ .../calc/fitRemoveProjectedModule.py | 39 ++++++++++ gui/fitCommands/guiAddProjected.py | 71 +++++++++++++++++++ service/fit.py | 1 + 10 files changed, 184 insertions(+), 25 deletions(-) create mode 100644 gui/fitCommands/calc/fitAddProjectedModule.py create mode 100644 gui/fitCommands/calc/fitRemoveProjectedModule.py create mode 100644 gui/fitCommands/guiAddProjected.py diff --git a/gui/builtinAdditionPanes/projectedView.py b/gui/builtinAdditionPanes/projectedView.py index 24ca11f3a..4cb18abd8 100644 --- a/gui/builtinAdditionPanes/projectedView.py +++ b/gui/builtinAdditionPanes/projectedView.py @@ -32,6 +32,7 @@ from gui.contextMenu import ContextMenu from gui.utils.staticHelpers import DragDropHelper from service.fit import Fit from service.market import Market +import gui.fitCommands as cmd pyfalog = Logger(__name__) @@ -100,6 +101,7 @@ class ProjectedView(d.Display): data[1] is typeID or index of data we want to manipulate """ sFit = Fit.getInstance() + fitID = self.mainFrame.getActiveFit() fit = sFit.getFit(self.mainFrame.getActiveFit()) if data[0] == "projected": @@ -109,12 +111,14 @@ class ProjectedView(d.Display): dstRow, _ = self.HitTest((x, y)) # Gather module information to get position module = fit.modules[int(data[1])] - sFit.project(fit.ID, module) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fit.ID)) + self.mainFrame.command.Submit(cmd.GuiAddProjectedCommand(fitID, module.itemID, 'item')) + # sFit.project(fit.ID, module) + # wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fit.ID)) elif data[0] == "market": - sFit = Fit.getInstance() - sFit.project(fit.ID, int(data[1])) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fit.ID)) + # sFit = Fit.getInstance() + self.mainFrame.command.Submit(cmd.GuiAddProjectedCommand(fitID, int(data[1]), 'item')) + # sFit.project(fit.ID, int(data[1])) + # wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fit.ID)) def kbEvent(self, event): keycode = event.GetKeyCode() @@ -131,10 +135,7 @@ class ProjectedView(d.Display): if type == "fit": activeFit = self.mainFrame.getActiveFit() if activeFit: - sFit = Fit.getInstance() - draggedFit = sFit.getFit(fitID) - sFit.project(activeFit, draggedFit) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFit)) + self.mainFrame.command.Submit(cmd.GuiAddProjectedCommand(activeFit, fitID, 'fit')) def startDrag(self, event): row = event.GetIndex() diff --git a/gui/builtinContextMenus/project.py b/gui/builtinContextMenus/project.py index f06c29152..dbfa16724 100644 --- a/gui/builtinContextMenus/project.py +++ b/gui/builtinContextMenus/project.py @@ -5,7 +5,7 @@ import gui.globalEvents as GE import wx from service.fit import Fit from service.settings import ContextMenuSettings - +import gui.fitCommands as cmd class Project(ContextMenu): def __init__(self): @@ -35,10 +35,12 @@ class Project(ContextMenu): def activate(self, fullContext, selection, i): sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() - trigger = sFit.project(fitID, selection[0]) - if trigger: - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) - self.mainFrame.additionsPane.select("Projected") + self.mainFrame.command.Submit(cmd.GuiAddProjectedCommand(fitID, selection[0].ID, 'item')) + + # trigger = sFit.project(fitID, selection[0]) + # if trigger: + # wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + # self.mainFrame.additionsPane.select("Projected") Project.register() diff --git a/gui/builtinContextMenus/tabbedFits.py b/gui/builtinContextMenus/tabbedFits.py index d8b516027..689622c3b 100644 --- a/gui/builtinContextMenus/tabbedFits.py +++ b/gui/builtinContextMenus/tabbedFits.py @@ -51,7 +51,6 @@ class TabbedFits(ContextMenu): return m def handleSelection(self, event): - sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() fit = self.fitLookup[event.Id] @@ -59,8 +58,7 @@ class TabbedFits(ContextMenu): if self.context == 'commandView': self.mainFrame.command.Submit(cmd.GuiAddCommandCommand(fitID, fit.ID)) elif self.context == 'projected': - sFit.project(fitID, fit) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.GuiAddProjectedCommand(fitID, fit.ID, 'fit')) TabbedFits.register() diff --git a/gui/builtinContextMenus/whProjector.py b/gui/builtinContextMenus/whProjector.py index ac0bd5c1b..1ec8252e8 100644 --- a/gui/builtinContextMenus/whProjector.py +++ b/gui/builtinContextMenus/whProjector.py @@ -8,7 +8,7 @@ from service.fit import Fit from service.settings import ContextMenuSettings from itertools import chain import re - +import gui.fitCommands as cmd class WhProjector(ContextMenu): @@ -87,10 +87,8 @@ class WhProjector(ContextMenu): event.Skip() return - sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() - sFit.project(fitID, swObj) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.GuiAddProjectedCommand(fitID, swObj.ID, 'item')) def buildMenu(self, data, local_menu, rootMenu, msw): for swType in sorted(data): diff --git a/gui/builtinShipBrowser/fitItem.py b/gui/builtinShipBrowser/fitItem.py index 73617a458..58aa0f553 100644 --- a/gui/builtinShipBrowser/fitItem.py +++ b/gui/builtinShipBrowser/fitItem.py @@ -202,9 +202,8 @@ class FitItem(SFItem.SFBrowserItem): if activeFit: sFit = Fit.getInstance() projectedFit = sFit.getFit(self.fitID) - sFit.project(activeFit, projectedFit) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFit)) - self.mainFrame.additionsPane.select("Projected") + if self.mainFrame.command.Submit(cmd.GuiAddProjectedCommand(activeFit, projectedFit.ID, 'fit')): + self.mainFrame.additionsPane.select("Projected") def OnAddCommandFit(self, event): activeFit = self.mainFrame.getActiveFit() diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index 7abbd4141..f253af60c 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -12,4 +12,5 @@ from .guiRemoveBooster import GuiRemoveBoosterCommand from .guiAddCommand import GuiAddCommandCommand from .guiRemoveCommand import GuiRemoveCommandCommand from .guiSetMode import GuiSetModeCommand -from .guiToggleCommand import GuiToggleCommandCommand \ No newline at end of file +from .guiToggleCommand import GuiToggleCommandCommand +from .guiAddProjected import GuiAddProjectedCommand \ No newline at end of file diff --git a/gui/fitCommands/calc/fitAddProjectedModule.py b/gui/fitCommands/calc/fitAddProjectedModule.py new file mode 100644 index 000000000..bf9ebf6c2 --- /dev/null +++ b/gui/fitCommands/calc/fitAddProjectedModule.py @@ -0,0 +1,49 @@ +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 +from eos.saveddata.module import Module +from eos.saveddata.drone import Drone +from eos.saveddata.fighter import Fighter +pyfalog = Logger(__name__) + + +class FitAddProjectedModuleCommand(wx.Command): + """" + from sFit.project + """ + def __init__(self, fitID, itemID): + wx.Command.__init__(self, True) + self.fitID = fitID + self.itemID = itemID + self.new_index = None + + def Do(self): + pyfalog.debug("Projecting fit ({0}) onto: {1}", self.fitID, self.itemID) + fit = eos.db.getFit(self.fitID) + item = eos.db.getItem(self.itemID, eager=("attributes", "group.category")) + + try: + module = Module(item) + except ValueError: + return False + + module.state = State.ACTIVE + if not module.canHaveState(module.state, fit): + module.state = State.OFFLINE + fit.projectedModules.append(module) + + eos.db.commit() + self.new_index = fit.projectedModules.index(module) + return True + + def Undo(self): + from gui.fitCommands.calc.fitRemoveProjectedModule import FitRemoveProjectedModuleCommand # avoids circular import + cmd = FitRemoveProjectedModuleCommand(self.fitID, self.new_index) + cmd.Do() + return True diff --git a/gui/fitCommands/calc/fitRemoveProjectedModule.py b/gui/fitCommands/calc/fitRemoveProjectedModule.py new file mode 100644 index 000000000..ffb398006 --- /dev/null +++ b/gui/fitCommands/calc/fitRemoveProjectedModule.py @@ -0,0 +1,39 @@ +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 +from eos.saveddata.module import Module +from eos.saveddata.drone import Drone +from eos.saveddata.fighter import Fighter +pyfalog = Logger(__name__) + + +class FitRemoveProjectedModuleCommand(wx.Command): + """" + from sFit.project + """ + def __init__(self, fitID, position): + wx.Command.__init__(self, True) + self.fitID = fitID + self.position = position + self.removed_item = None + + def Do(self): + pyfalog.debug("Removing ({0}) onto: {1}", self.fitID, self.position) + fit = eos.db.getFit(self.fitID) + self.removed_item = fit.projectedModules[self.position].itemID + del fit.projectedModules[self.position] + + eos.db.commit() + return True + + def Undo(self): + from gui.fitCommands.calc.fitAddProjectedModule import FitAddProjectedModuleCommand + cmd = FitAddProjectedModuleCommand(self.fitID, self.removed_item) + cmd.Do() + return True diff --git a/gui/fitCommands/guiAddProjected.py b/gui/fitCommands/guiAddProjected.py new file mode 100644 index 000000000..e483fb84f --- /dev/null +++ b/gui/fitCommands/guiAddProjected.py @@ -0,0 +1,71 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from eos.saveddata.module import Module +from .calc.fitAddProjectedModule import FitAddProjectedModuleCommand +from logbook import Logger +import eos.db +pyfalog = Logger(__name__) + + +class GuiAddProjectedCommand(wx.Command): + def __init__(self, fitID, id, type='item'): + wx.Command.__init__(self, True, "Projected Add") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() + self.fitID = fitID + self.id = id + self.type = type + + def Do(self): + result = False + # since we can project various types, we need to switch of the fit command. We can't do this switch easily in + # the fit command since each type might have a different kind of undo, easier to split it out + if self.type == 'item': + item = eos.db.getItem(self.id, eager=("attributes", "group.category")) + + if item.category.name == "Drone": + # @todo: this may need to be reworked once we visit drone commands + pyfalog.warn("DRONE PROJECTION NOT IMPLEMENTED") + # drone = None + # for d in fit.projectedDrones.find(item): + # if d is None or d.amountActive == d.amount or d.amount >= 5: + # drone = d + # break + # + # if drone is None: + # drone = Drone(item) + # fit.projectedDrones.append(drone) + # + # drone.amount += 1 + elif item.category.name == "Fighter": + pyfalog.warn("FIGHTER PROJECTION NOT IMPLEMENTED") + # fighter = Fighter(item) + # fit.projectedFighters.append(fighter) + elif item.group.name in Module.SYSTEM_GROUPS: + pyfalog.warn("WH PROJECTION NOT IMPLEMENTED") + # module = Module(item) + # module.state = State.ONLINE + # fit.projectedModules.append(module) + else: + # attempt a regular module projection + result = self.internal_history.Submit(FitAddProjectedModuleCommand(self.fitID, self.id)) + elif self.type == 'fit': + pyfalog.warn("FIT PROJECTION NOT IMPLEMENTED") + + if result: + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for _ in self.internal_history.Commands: + self.internal_history.Undo() + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + diff --git a/service/fit.py b/service/fit.py index 238c5c58b..4916df143 100644 --- a/service/fit.py +++ b/service/fit.py @@ -397,6 +397,7 @@ class Fit(object): self.recalc(fit) return True + @deprecated def project(self, fitID, thing): pyfalog.debug("Projecting fit ({0}) onto: {1}", fitID, thing) if fitID is None: From 326e1e04c296e75911b6027a8a61d33a60996be3 Mon Sep 17 00:00:00 2001 From: Ryan Holmes Date: Sun, 5 Aug 2018 08:14:12 -0400 Subject: [PATCH 32/95] Reworked slot-copying logic so that we can call it explicitly outside the append. Needed for the fitting commands to know what the previous item ID was that it's replacing. --- eos/effectHandlerHelpers.py | 12 +++++++++--- gui/builtinAdditionPanes/boosterView.py | 2 +- gui/fitCommands/calc/fitAddBooster.py | 10 +++++++++- gui/fitCommands/calc/fitAddImplant.py | 8 ++++++++ gui/fitCommands/guiAddBooster.py | 2 ++ gui/fitCommands/guiRemoveBooster.py | 2 ++ 6 files changed, 31 insertions(+), 5 deletions(-) diff --git a/eos/effectHandlerHelpers.py b/eos/effectHandlerHelpers.py index 446273a45..3cba3e40f 100644 --- a/eos/effectHandlerHelpers.py +++ b/eos/effectHandlerHelpers.py @@ -197,14 +197,20 @@ class HandledImplantBoosterList(HandledList): self.remove(thing) return + self.makeRoom(thing) + HandledList.append(self, thing) + + def makeRoom(self, thing): # if needed, remove booster that was occupying slot oldObj = next((m for m in self if m.slot == thing.slot), None) if oldObj: - pyfalog.info("Slot {0} occupied with {1}, replacing with {2}", thing.slot, oldObj.item.name, thing.item.name) + pyfalog.info("Slot {0} occupied with {1}, replacing with {2}", thing.slot, oldObj.item.name, + thing.item.name) + itemID = oldObj.itemID oldObj.itemID = 0 # hack to remove from DB. See GH issue #324 self.remove(oldObj) - - HandledList.append(self, thing) + return itemID + return None class HandledSsoCharacterList(list): diff --git a/gui/builtinAdditionPanes/boosterView.py b/gui/builtinAdditionPanes/boosterView.py index ef9c88f2d..48b3ed36d 100644 --- a/gui/builtinAdditionPanes/boosterView.py +++ b/gui/builtinAdditionPanes/boosterView.py @@ -148,7 +148,7 @@ class BoosterView(d.Display): def removeBooster(self, booster): fitID = self.mainFrame.getActiveFit() - self.mainFrame.command.Submit(cmd.GuiRemoveImplantCommand(fitID, self.origional.index(booster))) + self.mainFrame.command.Submit(cmd.GuiRemoveBoosterCommand(fitID, self.origional.index(booster))) def click(self, event): event.Skip() diff --git a/gui/fitCommands/calc/fitAddBooster.py b/gui/fitCommands/calc/fitAddBooster.py index 356a742da..61f4f5b49 100644 --- a/gui/fitCommands/calc/fitAddBooster.py +++ b/gui/fitCommands/calc/fitAddBooster.py @@ -19,7 +19,7 @@ class FitAddBoosterCommand(wx.Command): self.fitID = fitID self.itemID = itemID self.new_index = None - + self.old_item = None def Do(self): pyfalog.debug("Adding booster ({0}) to fit ID: {1}", self.itemID, self.fitID) @@ -31,11 +31,19 @@ class FitAddBoosterCommand(wx.Command): pyfalog.warning("Invalid item: {0}", self.itemID) return False + self.old_item = fit.boosters.makeRoom(booster) + fit.boosters.append(booster) self.new_index = fit.boosters.index(booster) return True def Undo(self): + if self.old_item: + # If we had an item in the slot previously, add it back. + cmd = FitAddBoosterCommand(self.fitID, self.old_item) + cmd.Do() + return True + from .fitRemoveBooster import FitRemoveBoosterCommand # Avoid circular import cmd = FitRemoveBoosterCommand(self.fitID, self.new_index) cmd.Do() diff --git a/gui/fitCommands/calc/fitAddImplant.py b/gui/fitCommands/calc/fitAddImplant.py index 91bc5be61..b65b53e69 100644 --- a/gui/fitCommands/calc/fitAddImplant.py +++ b/gui/fitCommands/calc/fitAddImplant.py @@ -18,6 +18,7 @@ class FitAddImplantCommand(wx.Command): wx.Command.__init__(self, True, "Cargo add") self.fitID = fitID self.itemID = itemID + self.old_item = None def Do(self): pyfalog.debug("Adding implant to fit ({0}) for item ID: {1}", self.fitID, self.itemID) @@ -30,11 +31,18 @@ class FitAddImplantCommand(wx.Command): pyfalog.warning("Invalid item: {0}", self.itemID) return False + self.old_item = fit.implants.makeRoom(implant) fit.implants.append(implant) self.new_index = fit.implants.index(implant) return True def Undo(self): + if self.old_item: + # If we had an item in the slot previously, add it back. + cmd = FitAddImplantCommand(self.fitID, self.old_item) + cmd.Do() + return True + from .fitRemoveImplant import FitRemoveImplantCommand # Avoid circular import cmd = FitRemoveImplantCommand(self.fitID, self.new_index) cmd.Do() diff --git a/gui/fitCommands/guiAddBooster.py b/gui/fitCommands/guiAddBooster.py index 392ce3034..3dc423cf6 100644 --- a/gui/fitCommands/guiAddBooster.py +++ b/gui/fitCommands/guiAddBooster.py @@ -17,6 +17,7 @@ class GuiAddBoosterCommand(wx.Command): def Do(self): if self.internal_history.Submit(self.cmd): + self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True return False @@ -24,6 +25,7 @@ class GuiAddBoosterCommand(wx.Command): def Undo(self): for x in self.internal_history.Commands: self.internal_history.Undo() + self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True diff --git a/gui/fitCommands/guiRemoveBooster.py b/gui/fitCommands/guiRemoveBooster.py index 92578b0b8..2155ab120 100644 --- a/gui/fitCommands/guiRemoveBooster.py +++ b/gui/fitCommands/guiRemoveBooster.py @@ -17,6 +17,7 @@ class GuiRemoveBoosterCommand(wx.Command): def Do(self): if self.internal_history.Submit(self.cmd): + self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True return False @@ -24,6 +25,7 @@ class GuiRemoveBoosterCommand(wx.Command): def Undo(self): for x in self.internal_history.Commands: self.internal_history.Undo() + self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True From 804d90c50cf3029c5cde90eaf988e3a40353b6eb Mon Sep 17 00:00:00 2001 From: Ryan Holmes Date: Sun, 5 Aug 2018 08:17:24 -0400 Subject: [PATCH 33/95] Don't run adding command on implants and boosters if item is already item --- gui/fitCommands/calc/fitAddBooster.py | 6 +++++- gui/fitCommands/calc/fitAddImplant.py | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/gui/fitCommands/calc/fitAddBooster.py b/gui/fitCommands/calc/fitAddBooster.py index 61f4f5b49..d030c4026 100644 --- a/gui/fitCommands/calc/fitAddBooster.py +++ b/gui/fitCommands/calc/fitAddBooster.py @@ -20,11 +20,16 @@ class FitAddBoosterCommand(wx.Command): self.itemID = itemID self.new_index = None self.old_item = None + def Do(self): pyfalog.debug("Adding booster ({0}) to fit ID: {1}", self.itemID, self.fitID) fit = eos.db.getFit(self.fitID) item = eos.db.getItem(self.itemID, eager="attributes") + + if next((x for x in fit.boosters if x.itemID == self.itemID), None): + return False # already have item in list of boosters + try: booster = Booster(item) except ValueError: @@ -32,7 +37,6 @@ class FitAddBoosterCommand(wx.Command): return False self.old_item = fit.boosters.makeRoom(booster) - fit.boosters.append(booster) self.new_index = fit.boosters.index(booster) return True diff --git a/gui/fitCommands/calc/fitAddImplant.py b/gui/fitCommands/calc/fitAddImplant.py index b65b53e69..ae8ea848b 100644 --- a/gui/fitCommands/calc/fitAddImplant.py +++ b/gui/fitCommands/calc/fitAddImplant.py @@ -25,6 +25,10 @@ class FitAddImplantCommand(wx.Command): fit = eos.db.getFit(self.fitID) item = eos.db.getItem(self.itemID, eager="attributes") + + if next((x for x in fit.implants if x.itemID == self.itemID), None): + return False # already have item in list of implants + try: implant = Implant(item) except ValueError: From d6b280d3ccb92453a72575ce7846e3475de99276 Mon Sep 17 00:00:00 2001 From: Ryan Holmes Date: Thu, 9 Aug 2018 15:52:34 -0400 Subject: [PATCH 34/95] Working commit for adding / removing projected modules / environments --- eos/effectHandlerHelpers.py | 16 ++++++++++------ gui/builtinAdditionPanes/projectedView.py | 3 +-- gui/builtinContextMenus/itemRemove.py | 5 +++-- gui/fitCommands/__init__.py | 3 ++- gui/fitCommands/guiAddProjected.py | 6 ++---- service/fit.py | 1 + 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/eos/effectHandlerHelpers.py b/eos/effectHandlerHelpers.py index 3cba3e40f..194429d31 100644 --- a/eos/effectHandlerHelpers.py +++ b/eos/effectHandlerHelpers.py @@ -236,12 +236,7 @@ class HandledProjectedModList(HandledList): isSystemEffect = proj.item.group.name == "Effect Beacon" if isSystemEffect: - # remove other system effects - only 1 per fit plz - oldEffect = next((m for m in self if m.item.group.name == "Effect Beacon"), None) - - if oldEffect: - pyfalog.info("System effect occupied with {0}, replacing with {1}", oldEffect.item.name, proj.item.name) - self.remove(oldEffect) + self.makeRoom(proj) HandledList.append(self, proj) @@ -249,6 +244,15 @@ class HandledProjectedModList(HandledList): if not proj.item.isType("projected") and not isSystemEffect: self.remove(proj) + def makeRoom(self, proj): + # remove other system effects - only 1 per fit plz + oldEffect = next((m for m in self if m.item.group.name == "Effect Beacon"), None) + + if oldEffect: + pyfalog.info("System effect occupied with {0}, replacing with {1}", oldEffect.item.name, proj.item.name) + self.remove(oldEffect) + return oldEffect.itemID + return None class HandledProjectedDroneList(HandledDroneCargoList): def append(self, proj): diff --git a/gui/builtinAdditionPanes/projectedView.py b/gui/builtinAdditionPanes/projectedView.py index 4cb18abd8..293f34cf2 100644 --- a/gui/builtinAdditionPanes/projectedView.py +++ b/gui/builtinAdditionPanes/projectedView.py @@ -323,5 +323,4 @@ class ProjectedView(d.Display): sFit = Fit.getInstance() thing = self.get(row) if thing: # thing doesn't exist if it's the dummy value - sFit.removeProjected(fitID, thing) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.GuiRemoveProjectedCommand(fitID, thing)) diff --git a/gui/builtinContextMenus/itemRemove.py b/gui/builtinContextMenus/itemRemove.py index d075eba2e..0d464461d 100644 --- a/gui/builtinContextMenus/itemRemove.py +++ b/gui/builtinContextMenus/itemRemove.py @@ -54,10 +54,11 @@ class ItemRemove(ContextMenu): self.mainFrame.command.Submit(cmd.GuiRemoveCargoCommand(fitID, selection[0].itemID)) return # the command takes care of the PostEvent elif srcContext in ("projectedFit", "projectedModule", "projectedDrone", "projectedFighter"): - sFit.removeProjected(fitID, selection[0]) + self.mainFrame.command.Submit(cmd.GuiRemoveProjectedCommand(fitID, selection[0])) + return # the command takes care of the PostEvent elif srcContext == "commandFit": self.mainFrame.command.Submit(cmd.GuiRemoveCommandCommand(fitID, selection[0].ID)) - return + return # the command takes care of the PostEvent wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index f253af60c..692aa6589 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -13,4 +13,5 @@ from .guiAddCommand import GuiAddCommandCommand from .guiRemoveCommand import GuiRemoveCommandCommand from .guiSetMode import GuiSetModeCommand from .guiToggleCommand import GuiToggleCommandCommand -from .guiAddProjected import GuiAddProjectedCommand \ No newline at end of file +from .guiAddProjected import GuiAddProjectedCommand +from .guiRemoveProjected import GuiRemoveProjectedCommand \ No newline at end of file diff --git a/gui/fitCommands/guiAddProjected.py b/gui/fitCommands/guiAddProjected.py index e483fb84f..cc556f32c 100644 --- a/gui/fitCommands/guiAddProjected.py +++ b/gui/fitCommands/guiAddProjected.py @@ -5,6 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from eos.saveddata.module import Module from .calc.fitAddProjectedModule import FitAddProjectedModuleCommand +from .calc.fitAddProjectedEnv import FitAddProjectedEnvCommand from logbook import Logger import eos.db pyfalog = Logger(__name__) @@ -46,10 +47,7 @@ class GuiAddProjectedCommand(wx.Command): # fighter = Fighter(item) # fit.projectedFighters.append(fighter) elif item.group.name in Module.SYSTEM_GROUPS: - pyfalog.warn("WH PROJECTION NOT IMPLEMENTED") - # module = Module(item) - # module.state = State.ONLINE - # fit.projectedModules.append(module) + result = self.internal_history.Submit(FitAddProjectedEnvCommand(self.fitID, self.id)) else: # attempt a regular module projection result = self.internal_history.Submit(FitAddProjectedModuleCommand(self.fitID, self.id)) diff --git a/service/fit.py b/service/fit.py index 4916df143..d1fab9dbe 100644 --- a/service/fit.py +++ b/service/fit.py @@ -528,6 +528,7 @@ class Fit(object): eos.db.commit() self.recalc(fit) + @deprecated def removeProjected(self, fitID, thing): pyfalog.debug("Removing projection on fit ({0}) from: {1}", fitID, thing) fit = eos.db.getFit(fitID) From bd975becf165ea433bca491ccf0bc9d80c38def3 Mon Sep 17 00:00:00 2001 From: Ryan Holmes Date: Fri, 10 Aug 2018 12:47:51 -0400 Subject: [PATCH 35/95] Continue work on projections (adding/removing projected environment and fit) --- eos/db/saveddata/fit.py | 2 +- eos/saveddata/fit.py | 4 +- gui/fitCommands/calc/fitAddProjectedEnv.py | 59 +++++++++++++ gui/fitCommands/calc/fitAddProjectedFit.py | 49 +++++++++++ gui/fitCommands/calc/fitRemoveProjectedEnv.py | 44 ++++++++++ gui/fitCommands/calc/fitRemoveProjectedFit.py | 46 +++++++++++ gui/fitCommands/guiAddProjected.py | 3 +- gui/fitCommands/guiRemoveProjected.py | 82 +++++++++++++++++++ service/fit.py | 4 +- 9 files changed, 287 insertions(+), 6 deletions(-) create mode 100644 gui/fitCommands/calc/fitAddProjectedEnv.py create mode 100644 gui/fitCommands/calc/fitAddProjectedFit.py create mode 100644 gui/fitCommands/calc/fitRemoveProjectedEnv.py create mode 100644 gui/fitCommands/calc/fitRemoveProjectedFit.py create mode 100644 gui/fitCommands/guiRemoveProjected.py diff --git a/eos/db/saveddata/fit.py b/eos/db/saveddata/fit.py index 9701d5d6b..7e3c76f5f 100644 --- a/eos/db/saveddata/fit.py +++ b/eos/db/saveddata/fit.py @@ -132,7 +132,7 @@ class CommandFit(object): ) -es_Fit._Fit__projectedFits = association_proxy( +es_Fit.projectedFitDict = association_proxy( "victimOf", # look at the victimOf association... "source_fit", # .. and return the source fits creator=lambda sourceID, source_fit: ProjectedFit(sourceID, source_fit) diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index 56c4df1a2..ad4a48ebf 100644 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -257,7 +257,7 @@ class Fit(object): def projectedFits(self): # only in extreme edge cases will the fit be invalid, but to be sure do # not return them. - return [fit for fit in list(self.__projectedFits.values()) if not fit.isInvalid] + return [fit for fit in list(self.projectedFitDict.values()) if not fit.isInvalid] @property def commandFits(self): @@ -1615,7 +1615,7 @@ class Fit(object): forceUpdateSavedata(fit) for fit in self.projectedFits: - copy_ship.__projectedFits[fit.ID] = fit + copy_ship.projectedFitDict[fit.ID] = fit forceUpdateSavedata(fit) copyProjectionInfo = fit.getProjectionInfo(copy_ship.ID) originalProjectionInfo = fit.getProjectionInfo(self.ID) diff --git a/gui/fitCommands/calc/fitAddProjectedEnv.py b/gui/fitCommands/calc/fitAddProjectedEnv.py new file mode 100644 index 000000000..974f8efa5 --- /dev/null +++ b/gui/fitCommands/calc/fitAddProjectedEnv.py @@ -0,0 +1,59 @@ +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 +from eos.saveddata.module import Module +from eos.saveddata.drone import Drone +from eos.saveddata.fighter import Fighter +from .fitRemoveProjectedModule import FitRemoveProjectedModuleCommand +pyfalog = Logger(__name__) + + +class FitAddProjectedEnvCommand(wx.Command): + """" + from sFit.project + """ + def __init__(self, fitID, itemID): + wx.Command.__init__(self, True) + self.fitID = fitID + self.itemID = itemID + self.new_index = None + self.old_item = None + + def Do(self): + pyfalog.debug("Projecting fit ({0}) onto: {1}", self.fitID, self.itemID) + fit = eos.db.getFit(self.fitID) + item = eos.db.getItem(self.itemID, eager=("attributes", "group.category")) + + try: + module = Module(item) + except ValueError: + return False + + # todo: thing to check for existing environmental effects + + self.old_item = fit.projectedModules.makeRoom(module) + + module.state = State.ONLINE + fit.projectedModules.append(module) + + eos.db.commit() + self.new_index = fit.projectedModules.index(module) + return True + + def Undo(self): + if self.old_item: + # If we had an item in the slot previously, add it back. + cmd = FitAddProjectedEnvCommand(self.fitID, self.old_item) + cmd.Do() + return True + from gui.fitCommands.calc.fitRemoveProjectedEnv import FitRemoveProjectedEnvCommand # avoids circular import + cmd = FitRemoveProjectedEnvCommand(self.fitID, self.itemID) + cmd.Do() + + return True diff --git a/gui/fitCommands/calc/fitAddProjectedFit.py b/gui/fitCommands/calc/fitAddProjectedFit.py new file mode 100644 index 000000000..70fdece0a --- /dev/null +++ b/gui/fitCommands/calc/fitAddProjectedFit.py @@ -0,0 +1,49 @@ +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 +from eos.saveddata.module import Module +from eos.saveddata.drone import Drone +from eos.saveddata.fighter import Fighter +from .fitRemoveProjectedModule import FitRemoveProjectedModuleCommand +pyfalog = Logger(__name__) + + +class FitAddProjectedFitCommand(wx.Command): + """" + from sFit.project + """ + def __init__(self, fitID, projectedFitID): + wx.Command.__init__(self, True) + self.fitID = fitID + self.projectedFitID = projectedFitID + self.new_index = None + self.old_item = None + + def Do(self): + pyfalog.debug("Projecting fit ({0}) onto: {1}", self.fitID, self.projectedFitID) + fit = eos.db.getFit(self.fitID) + projectedFit = eos.db.getFit(self.projectedFitID) + + if projectedFit is None or projectedFit in fit.projectedFits: + return False + + fit.projectedFitDict[projectedFit.ID] = projectedFit + + # this bit is required -- see GH issue # 83 + eos.db.saveddata_session.flush() + eos.db.saveddata_session.refresh(projectedFit) + + eos.db.commit() + return True + + def Undo(self): + from gui.fitCommands.calc.fitRemoveProjectedFit import FitRemoveProjectedFitCommand # avoids circular import + cmd = FitRemoveProjectedFitCommand(self.fitID, self.projectedFitID) + cmd.Do() + return True diff --git a/gui/fitCommands/calc/fitRemoveProjectedEnv.py b/gui/fitCommands/calc/fitRemoveProjectedEnv.py new file mode 100644 index 000000000..b53f40ab0 --- /dev/null +++ b/gui/fitCommands/calc/fitRemoveProjectedEnv.py @@ -0,0 +1,44 @@ +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 +from eos.saveddata.module import Module +from eos.saveddata.drone import Drone +from eos.saveddata.fighter import Fighter +from .fitRemoveProjectedModule import FitRemoveProjectedModuleCommand +pyfalog = Logger(__name__) + + +# this has the same exact definition that regular rpojected modules, besides the undo +class FitRemoveProjectedEnvCommand(FitRemoveProjectedModuleCommand): + """" + from sFit.project + """ + + def __init__(self, fitID, itemID): + wx.Command.__init__(self, True) + self.fitID = fitID + self.itemID = itemID + self.removed_item = None + + def Do(self): + pyfalog.debug("Removing ({0}) onto: {1}", self.fitID, self.itemID) + fit = eos.db.getFit(self.fitID) + + item = next((x for x in fit.projectedModules if x.itemID == self.itemID), None) + self.removed_item = item.itemID + fit.projectedModules.remove(item) + + eos.db.commit() + return True + + def Undo(self): + from gui.fitCommands.calc.fitAddProjectedEnv import FitAddProjectedEnvCommand + cmd = FitAddProjectedEnvCommand(self.fitID, self.removed_item) + cmd.Do() + return True diff --git a/gui/fitCommands/calc/fitRemoveProjectedFit.py b/gui/fitCommands/calc/fitRemoveProjectedFit.py new file mode 100644 index 000000000..829c7d3ea --- /dev/null +++ b/gui/fitCommands/calc/fitRemoveProjectedFit.py @@ -0,0 +1,46 @@ +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 +from eos.saveddata.module import Module +from eos.saveddata.drone import Drone +from eos.saveddata.fighter import Fighter +from .fitRemoveProjectedModule import FitRemoveProjectedModuleCommand +pyfalog = Logger(__name__) + + +# this has the same exact definition that regular rpojected modules, besides the undo +class FitRemoveProjectedFitCommand(FitRemoveProjectedModuleCommand): + """" + from sFit.project + """ + + def __init__(self, fitID, projectedFitID): + wx.Command.__init__(self, True) + self.fitID = fitID + self.projectedFitID = projectedFitID + + def Do(self): + pyfalog.debug("Removing ({0}) onto: {1}", self.fitID, self.projectedFitID) + fit = eos.db.getFit(self.fitID) + projectedFit = eos.db.getFit(self.projectedFitID) + + if projectedFit is None: + return False + + del fit.projectedFitDict[projectedFit.ID] + + eos.db.commit() + return True + + def Undo(self): + # todo: figure out if I need to return false here if the fit doesn't return true (means it was deleted) + from gui.fitCommands.calc.fitAddProjectedFit import FitAddProjectedFitCommand + cmd = FitAddProjectedFitCommand(self.fitID, self.projectedFitID) + cmd.Do() + return True diff --git a/gui/fitCommands/guiAddProjected.py b/gui/fitCommands/guiAddProjected.py index cc556f32c..ac6c65c23 100644 --- a/gui/fitCommands/guiAddProjected.py +++ b/gui/fitCommands/guiAddProjected.py @@ -6,6 +6,7 @@ from gui import globalEvents as GE from eos.saveddata.module import Module from .calc.fitAddProjectedModule import FitAddProjectedModuleCommand from .calc.fitAddProjectedEnv import FitAddProjectedEnvCommand +from .calc.fitAddProjectedFit import FitAddProjectedFitCommand from logbook import Logger import eos.db pyfalog = Logger(__name__) @@ -52,7 +53,7 @@ class GuiAddProjectedCommand(wx.Command): # attempt a regular module projection result = self.internal_history.Submit(FitAddProjectedModuleCommand(self.fitID, self.id)) elif self.type == 'fit': - pyfalog.warn("FIT PROJECTION NOT IMPLEMENTED") + result = self.internal_history.Submit(FitAddProjectedFitCommand(self.fitID, self.id)) if result: self.sFit.recalc(self.fitID) diff --git a/gui/fitCommands/guiRemoveProjected.py b/gui/fitCommands/guiRemoveProjected.py new file mode 100644 index 000000000..f3b36478c --- /dev/null +++ b/gui/fitCommands/guiRemoveProjected.py @@ -0,0 +1,82 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from eos.saveddata.module import Module +from .calc.fitRemoveProjectedModule import FitRemoveProjectedModuleCommand +from .calc.fitRemoveProjectedEnv import FitRemoveProjectedEnvCommand +from .calc.fitRemoveProjectedFit import FitRemoveProjectedFitCommand +from logbook import Logger +import eos.db +pyfalog = Logger(__name__) + +from eos.saveddata.drone import Drone +from eos.saveddata.module import Module +from eos.saveddata.fighter import Fighter + + +class GuiRemoveProjectedCommand(wx.Command): + def __init__(self, fitID, thing): + wx.Command.__init__(self, True, "Projected Add") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() + self.fitID = fitID + fit = self.sFit.getFit(fitID) + + if isinstance(thing, Drone): + self.data = fit.projectedDrones.index(thing) + self.type = 'drone' + elif isinstance(thing, Module): + # todo: projected stuff should be wrapped in a projected class wrapper for easier maintainence + if thing.item.group.name in Module.SYSTEM_GROUPS: + self.type = 'env' + self.data = thing.itemID + else: + self.type = 'module' + self.data = fit.projectedModules.index(thing) + elif isinstance(thing, Fighter): + self.data = fit.projectedFighters.index(thing) + self.type = 'fighter' + else: + # todo: fix! + self.data = thing.ID + self.type = 'fit' + + def Do(self): + result = False + # since we can project various types, we need to switch of the fit command. We can't do this switch easily in + # the fit command since each type might have a different kind of undo, easier to split it out + if self.type == 'module': + result = self.internal_history.Submit(FitRemoveProjectedModuleCommand(self.fitID, self.data)) + elif self.type == 'env': + result = self.internal_history.Submit(FitRemoveProjectedEnvCommand(self.fitID, self.data)) + elif self.type == 'fit': + result = self.internal_history.Submit(FitRemoveProjectedFitCommand(self.fitID, self.data)) + + # if item.category.name == "Drone": + # pyfalog.warn("DRONE REMOVE PROJECTION NOT IMPLEMENTED") + # elif item.category.name == "Fighter": + # pyfalog.warn("FIGHTER REMOVE PROJECTION NOT IMPLEMENTED") + # elif item.group.name in Module.SYSTEM_GROUPS: + # result = self.internal_history.Submit(FitRemoveProjectedEnvCommand(self.fitID, self.id)) + # else: + # # attempt a regular module projection + # + # elif self.type == 'fit': + # pyfalog.warn("FIT REMOVE PROJECTION NOT IMPLEMENTED") + + if result: + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for _ in self.internal_history.Commands: + self.internal_history.Undo() + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + diff --git a/service/fit.py b/service/fit.py index d1fab9dbe..c19513dd0 100644 --- a/service/fit.py +++ b/service/fit.py @@ -416,7 +416,7 @@ class Fit(object): if thing in fit.projectedFits: return - fit.__projectedFits[thing.ID] = thing + fit.projectedFitDict[thing.ID] = thing # this bit is required -- see GH issue # 83 eos.db.saveddata_session.flush() @@ -539,7 +539,7 @@ class Fit(object): elif isinstance(thing, es_Fighter): fit.projectedFighters.remove(thing) else: - del fit.__projectedFits[thing.ID] + del fit.projectedFitDict[thing.ID] # fit.projectedFits.remove(thing) eos.db.commit() From 391c3a32a6385e6fa11023bee7c00f78c4d2a4b3 Mon Sep 17 00:00:00 2001 From: Ryan Holmes Date: Fri, 10 Aug 2018 13:29:26 -0400 Subject: [PATCH 36/95] commands for add / remove projected fighters --- .../calc/fitAddProjectedFighter.py | 47 +++++++++++++++++++ .../calc/fitRemoveProjectedFighter.py | 44 +++++++++++++++++ gui/fitCommands/guiAddProjected.py | 6 +-- gui/fitCommands/guiRemoveProjected.py | 3 ++ 4 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 gui/fitCommands/calc/fitAddProjectedFighter.py create mode 100644 gui/fitCommands/calc/fitRemoveProjectedFighter.py diff --git a/gui/fitCommands/calc/fitAddProjectedFighter.py b/gui/fitCommands/calc/fitAddProjectedFighter.py new file mode 100644 index 000000000..df0163c01 --- /dev/null +++ b/gui/fitCommands/calc/fitAddProjectedFighter.py @@ -0,0 +1,47 @@ +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 +from eos.saveddata.fighter import Fighter +from eos.saveddata.drone import Drone +pyfalog = Logger(__name__) + + +class FitAddProjectedFighterCommand(wx.Command): + """" + from sFit.project + """ + def __init__(self, fitID, itemID): + wx.Command.__init__(self, True) + self.fitID = fitID + self.itemID = itemID + self.new_index = None + + def Do(self): + pyfalog.debug("Projecting fit ({0}) onto: {1}", self.fitID, self.itemID) + fit = eos.db.getFit(self.fitID) + item = eos.db.getItem(self.itemID, eager=("attributes", "group.category")) + + try: + fighter = Fighter(item) + except ValueError: + return False + + fit.projectedFighters.append(fighter) + # sometimes fighters aren't added because they aren't valid projectionable ones. todo: move that logic into here + if fighter in fit.projectedFighters: + eos.db.commit() + self.new_index = fit.projectedFighters.index(fighter) + return True + return False + + def Undo(self): + from gui.fitCommands.calc.fitRemoveProjectedFighter import FitRemoveProjectedFighterCommand # avoids circular import + cmd = FitRemoveProjectedFighterCommand(self.fitID, self.new_index) + cmd.Do() + return True diff --git a/gui/fitCommands/calc/fitRemoveProjectedFighter.py b/gui/fitCommands/calc/fitRemoveProjectedFighter.py new file mode 100644 index 000000000..47ae53603 --- /dev/null +++ b/gui/fitCommands/calc/fitRemoveProjectedFighter.py @@ -0,0 +1,44 @@ +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 +from eos.saveddata.module import Module +from eos.saveddata.drone import Drone +from eos.saveddata.fighter import Fighter +from .fitRemoveProjectedModule import FitRemoveProjectedModuleCommand +pyfalog = Logger(__name__) + + +# this has the same exact definition that regular rpojected modules, besides the undo +class FitRemoveProjectedFighterCommand(FitRemoveProjectedModuleCommand): + """" + from sFit.project + """ + + def __init__(self, fitID, position): + wx.Command.__init__(self, True) + self.fitID = fitID + self.position = position + self.removed_item = None + + def Do(self): + pyfalog.debug("Removing ({0}) onto: {1}", self.fitID, self.position) + fit = eos.db.getFit(self.fitID) + + fighter = fit.projectedFighters[self.position] + fit.projectedFighters.remove(fighter) + self.removed_item = fighter.itemID + + eos.db.commit() + return True + + def Undo(self): + from gui.fitCommands.calc.fitAddProjectedFighter import FitAddProjectedFighterCommand + cmd = FitAddProjectedFighterCommand(self.fitID, self.removed_item) + cmd.Do() + return True diff --git a/gui/fitCommands/guiAddProjected.py b/gui/fitCommands/guiAddProjected.py index ac6c65c23..895678e1b 100644 --- a/gui/fitCommands/guiAddProjected.py +++ b/gui/fitCommands/guiAddProjected.py @@ -7,6 +7,7 @@ from eos.saveddata.module import Module from .calc.fitAddProjectedModule import FitAddProjectedModuleCommand from .calc.fitAddProjectedEnv import FitAddProjectedEnvCommand from .calc.fitAddProjectedFit import FitAddProjectedFitCommand +from .calc.fitAddProjectedFighter import FitAddProjectedFighterCommand from logbook import Logger import eos.db pyfalog = Logger(__name__) @@ -44,13 +45,10 @@ class GuiAddProjectedCommand(wx.Command): # # drone.amount += 1 elif item.category.name == "Fighter": - pyfalog.warn("FIGHTER PROJECTION NOT IMPLEMENTED") - # fighter = Fighter(item) - # fit.projectedFighters.append(fighter) + result = self.internal_history.Submit(FitAddProjectedFighterCommand(self.fitID, self.id)) elif item.group.name in Module.SYSTEM_GROUPS: result = self.internal_history.Submit(FitAddProjectedEnvCommand(self.fitID, self.id)) else: - # attempt a regular module projection result = self.internal_history.Submit(FitAddProjectedModuleCommand(self.fitID, self.id)) elif self.type == 'fit': result = self.internal_history.Submit(FitAddProjectedFitCommand(self.fitID, self.id)) diff --git a/gui/fitCommands/guiRemoveProjected.py b/gui/fitCommands/guiRemoveProjected.py index f3b36478c..e9e2d6c7b 100644 --- a/gui/fitCommands/guiRemoveProjected.py +++ b/gui/fitCommands/guiRemoveProjected.py @@ -7,6 +7,7 @@ from eos.saveddata.module import Module from .calc.fitRemoveProjectedModule import FitRemoveProjectedModuleCommand from .calc.fitRemoveProjectedEnv import FitRemoveProjectedEnvCommand from .calc.fitRemoveProjectedFit import FitRemoveProjectedFitCommand +from .calc.fitRemoveProjectedFighter import FitRemoveProjectedFighterCommand from logbook import Logger import eos.db pyfalog = Logger(__name__) @@ -54,6 +55,8 @@ class GuiRemoveProjectedCommand(wx.Command): result = self.internal_history.Submit(FitRemoveProjectedEnvCommand(self.fitID, self.data)) elif self.type == 'fit': result = self.internal_history.Submit(FitRemoveProjectedFitCommand(self.fitID, self.data)) + elif self.type == 'fighter': + result = self.internal_history.Submit(FitRemoveProjectedFighterCommand(self.fitID, self.data)) # if item.category.name == "Drone": # pyfalog.warn("DRONE REMOVE PROJECTION NOT IMPLEMENTED") From 2164588329da47693733c842150ec895c01393b2 Mon Sep 17 00:00:00 2001 From: Ryan Holmes Date: Sun, 12 Aug 2018 17:49:58 -0400 Subject: [PATCH 37/95] projected drone commands --- gui/fitCommands/calc/fitAddProjectedDrone.py | 52 +++++++++++++++++++ .../calc/fitRemoveProjectedDrone.py | 51 ++++++++++++++++++ .../calc/fitRemoveProjectedFighter.py | 2 +- gui/fitCommands/guiAddProjected.py | 15 +----- gui/fitCommands/guiRemoveProjected.py | 24 +++++---- 5 files changed, 121 insertions(+), 23 deletions(-) create mode 100644 gui/fitCommands/calc/fitAddProjectedDrone.py create mode 100644 gui/fitCommands/calc/fitRemoveProjectedDrone.py diff --git a/gui/fitCommands/calc/fitAddProjectedDrone.py b/gui/fitCommands/calc/fitAddProjectedDrone.py new file mode 100644 index 000000000..9109c4b7b --- /dev/null +++ b/gui/fitCommands/calc/fitAddProjectedDrone.py @@ -0,0 +1,52 @@ +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 +from eos.saveddata.module import Module +from eos.saveddata.drone import Drone +from eos.saveddata.fighter import Fighter +from .fitRemoveProjectedModule import FitRemoveProjectedModuleCommand +pyfalog = Logger(__name__) + + +class FitAddProjectedDroneCommand(wx.Command): + """" + from sFit.project + """ + def __init__(self, fitID, itemID): + wx.Command.__init__(self, True) + self.fitID = fitID + self.itemID = itemID + self.index = None + + def Do(self): + pyfalog.debug("Projecting fit ({0}) onto: {1}", self.fitID, self.itemID) + fit = eos.db.getFit(self.fitID) + item = eos.db.getItem(self.itemID) + + drone = None + for d in fit.projectedDrones.find(item): + if d is None or d.amountActive == d.amount or d.amount >= 5: + drone = d + break + + if drone is None: + drone = Drone(item) + fit.projectedDrones.append(drone) + + self.index = fit.projectedDrones.index(drone) + drone.amount += 1 + + eos.db.commit() + return True + + def Undo(self): + from gui.fitCommands.calc.fitRemoveProjectedDrone import FitRemoveProjectedDroneCommand # avoids circular import + cmd = FitRemoveProjectedDroneCommand(self.fitID, self.index) + cmd.Do() + return True diff --git a/gui/fitCommands/calc/fitRemoveProjectedDrone.py b/gui/fitCommands/calc/fitRemoveProjectedDrone.py new file mode 100644 index 000000000..3742dc9eb --- /dev/null +++ b/gui/fitCommands/calc/fitRemoveProjectedDrone.py @@ -0,0 +1,51 @@ +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 +from eos.saveddata.module import Module +from eos.saveddata.drone import Drone +from eos.saveddata.fighter import Fighter +pyfalog = Logger(__name__) + + +# this has the same exact definition that regular projected modules, besides the undo +class FitRemoveProjectedDroneCommand(wx.Command): + """" + from sFit.project + """ + + def __init__(self, fitID, position, stack=False): + wx.Command.__init__(self, True) + self.fitID = fitID + self.position = position + self.removed_item = None + self.stack = stack + + def Do(self): + pyfalog.debug("Removing ({0}) onto: {1}", self.fitID, self.position) + fit = eos.db.getFit(self.fitID) + + drone = fit.projectedDrones[self.position] + if self.stack: + fit.projectedDrones.remove(drone) + else: + if drone.amount > 1: + drone.amount -= 1 + else: + fit.projectedDrones.remove(drone) + + self.drone_item = drone.itemID + + eos.db.commit() + return True + + def Undo(self): + from gui.fitCommands.calc.fitAddProjectedDrone import FitAddProjectedDroneCommand + cmd = FitAddProjectedDroneCommand(self.fitID, self.drone_item) + cmd.Do() + return True diff --git a/gui/fitCommands/calc/fitRemoveProjectedFighter.py b/gui/fitCommands/calc/fitRemoveProjectedFighter.py index 47ae53603..186ee0b43 100644 --- a/gui/fitCommands/calc/fitRemoveProjectedFighter.py +++ b/gui/fitCommands/calc/fitRemoveProjectedFighter.py @@ -15,7 +15,7 @@ pyfalog = Logger(__name__) # this has the same exact definition that regular rpojected modules, besides the undo -class FitRemoveProjectedFighterCommand(FitRemoveProjectedModuleCommand): +class FitRemoveProjectedFighterCommand(wx.Command): """" from sFit.project """ diff --git a/gui/fitCommands/guiAddProjected.py b/gui/fitCommands/guiAddProjected.py index 895678e1b..7bc81bb76 100644 --- a/gui/fitCommands/guiAddProjected.py +++ b/gui/fitCommands/guiAddProjected.py @@ -8,6 +8,7 @@ from .calc.fitAddProjectedModule import FitAddProjectedModuleCommand from .calc.fitAddProjectedEnv import FitAddProjectedEnvCommand from .calc.fitAddProjectedFit import FitAddProjectedFitCommand from .calc.fitAddProjectedFighter import FitAddProjectedFighterCommand +from .calc.fitAddProjectedDrone import FitAddProjectedDroneCommand from logbook import Logger import eos.db pyfalog = Logger(__name__) @@ -31,19 +32,7 @@ class GuiAddProjectedCommand(wx.Command): item = eos.db.getItem(self.id, eager=("attributes", "group.category")) if item.category.name == "Drone": - # @todo: this may need to be reworked once we visit drone commands - pyfalog.warn("DRONE PROJECTION NOT IMPLEMENTED") - # drone = None - # for d in fit.projectedDrones.find(item): - # if d is None or d.amountActive == d.amount or d.amount >= 5: - # drone = d - # break - # - # if drone is None: - # drone = Drone(item) - # fit.projectedDrones.append(drone) - # - # drone.amount += 1 + result = self.internal_history.Submit(FitAddProjectedDroneCommand(self.fitID, self.id)) elif item.category.name == "Fighter": result = self.internal_history.Submit(FitAddProjectedFighterCommand(self.fitID, self.id)) elif item.group.name in Module.SYSTEM_GROUPS: diff --git a/gui/fitCommands/guiRemoveProjected.py b/gui/fitCommands/guiRemoveProjected.py index e9e2d6c7b..2bf91b876 100644 --- a/gui/fitCommands/guiRemoveProjected.py +++ b/gui/fitCommands/guiRemoveProjected.py @@ -9,8 +9,9 @@ from .calc.fitRemoveProjectedEnv import FitRemoveProjectedEnvCommand from .calc.fitRemoveProjectedFit import FitRemoveProjectedFitCommand from .calc.fitRemoveProjectedFighter import FitRemoveProjectedFighterCommand from logbook import Logger -import eos.db +from .calc.fitRemoveProjectedDrone import FitRemoveProjectedDroneCommand pyfalog = Logger(__name__) +import eos.db from eos.saveddata.drone import Drone from eos.saveddata.module import Module @@ -18,6 +19,14 @@ from eos.saveddata.fighter import Fighter class GuiRemoveProjectedCommand(wx.Command): + mapping = { + 'fit': FitRemoveProjectedFitCommand, + 'module': FitRemoveProjectedModuleCommand, + 'fighter': FitRemoveProjectedFighterCommand, + 'env': FitRemoveProjectedEnvCommand, + 'drone': FitRemoveProjectedDroneCommand + } + def __init__(self, fitID, thing): wx.Command.__init__(self, True, "Projected Add") self.mainFrame = gui.mainFrame.MainFrame.getInstance() @@ -49,14 +58,11 @@ class GuiRemoveProjectedCommand(wx.Command): result = False # since we can project various types, we need to switch of the fit command. We can't do this switch easily in # the fit command since each type might have a different kind of undo, easier to split it out - if self.type == 'module': - result = self.internal_history.Submit(FitRemoveProjectedModuleCommand(self.fitID, self.data)) - elif self.type == 'env': - result = self.internal_history.Submit(FitRemoveProjectedEnvCommand(self.fitID, self.data)) - elif self.type == 'fit': - result = self.internal_history.Submit(FitRemoveProjectedFitCommand(self.fitID, self.data)) - elif self.type == 'fighter': - result = self.internal_history.Submit(FitRemoveProjectedFighterCommand(self.fitID, self.data)) + + cls = self.mapping.get(self.type, None) + if cls: + cmd = cls(self.fitID, self.data) + result = self.internal_history.Submit(cmd) # if item.category.name == "Drone": # pyfalog.warn("DRONE REMOVE PROJECTION NOT IMPLEMENTED") From 008d73e60557edf9227f12088eb111c298548e36 Mon Sep 17 00:00:00 2001 From: Ryan Holmes Date: Mon, 13 Aug 2018 02:01:16 -0400 Subject: [PATCH 38/95] Finish off commands for cargo to module action --- gui/fitCommands/__init__.py | 3 +- gui/fitCommands/calc/fitCargoToModule.py | 54 ++++++++++++ gui/fitCommands/cargoToModule.py | 100 ----------------------- gui/fitCommands/guiCargoToModule.py | 63 ++++++++++++++ 4 files changed, 119 insertions(+), 101 deletions(-) create mode 100644 gui/fitCommands/calc/fitCargoToModule.py delete mode 100644 gui/fitCommands/cargoToModule.py create mode 100644 gui/fitCommands/guiCargoToModule.py diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index 692aa6589..75889255f 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -14,4 +14,5 @@ from .guiRemoveCommand import GuiRemoveCommandCommand from .guiSetMode import GuiSetModeCommand from .guiToggleCommand import GuiToggleCommandCommand from .guiAddProjected import GuiAddProjectedCommand -from .guiRemoveProjected import GuiRemoveProjectedCommand \ No newline at end of file +from .guiRemoveProjected import GuiRemoveProjectedCommand +from .guiCargoToModule import GuiCargoToModuleCommand \ No newline at end of file diff --git a/gui/fitCommands/calc/fitCargoToModule.py b/gui/fitCommands/calc/fitCargoToModule.py new file mode 100644 index 000000000..d030c4026 --- /dev/null +++ b/gui/fitCommands/calc/fitCargoToModule.py @@ -0,0 +1,54 @@ +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__) +from eos.saveddata.booster import Booster + +class FitAddBoosterCommand(wx.Command): + """" + from sFit.addBooster + """ + def __init__(self, fitID, itemID): + wx.Command.__init__(self, True) + self.fitID = fitID + self.itemID = itemID + self.new_index = None + self.old_item = None + + def Do(self): + pyfalog.debug("Adding booster ({0}) to fit ID: {1}", self.itemID, self.fitID) + + fit = eos.db.getFit(self.fitID) + item = eos.db.getItem(self.itemID, eager="attributes") + + if next((x for x in fit.boosters if x.itemID == self.itemID), None): + return False # already have item in list of boosters + + try: + booster = Booster(item) + except ValueError: + pyfalog.warning("Invalid item: {0}", self.itemID) + return False + + self.old_item = fit.boosters.makeRoom(booster) + fit.boosters.append(booster) + self.new_index = fit.boosters.index(booster) + return True + + def Undo(self): + if self.old_item: + # If we had an item in the slot previously, add it back. + cmd = FitAddBoosterCommand(self.fitID, self.old_item) + cmd.Do() + return True + + from .fitRemoveBooster import FitRemoveBoosterCommand # Avoid circular import + cmd = FitRemoveBoosterCommand(self.fitID, self.new_index) + cmd.Do() + return True diff --git a/gui/fitCommands/cargoToModule.py b/gui/fitCommands/cargoToModule.py deleted file mode 100644 index df47cac03..000000000 --- a/gui/fitCommands/cargoToModule.py +++ /dev/null @@ -1,100 +0,0 @@ -import wx -from service.fit import Fit - -import gui.mainFrame -from gui import globalEvents as GE -from gui.fitCommands.calc.fitSetCharge import FitSetChargeCommand -from logbook import Logger -pyfalog = Logger(__name__) - -class GuiCargoToModuleCommand(wx.Command): - """ - Moves cargo to fitting window. Can either do a copy, move, or swap with current module - If we try to copy/move into a spot with a non-empty module, we swap instead. - To avoid redundancy in converting Cargo item, this function does the - sanity checks as opposed to the GUI View. This is different than how the - normal .swapModules() does things, which is mostly a blind swap. - """ - - def __init__(self, fitID, moduleIdx, cargoIdx, copy=False): - # todo: instead of modules, needs to be positions. Dead objects are a thing - wx.Command.__init__(self, True, "Module State Change") - self.mainFrame = gui.mainFrame.MainFrame.getInstance() - self.sFit = Fit.getInstance() - self.fitID = fitID - self.moduleIdx = moduleIdx - self.cargoIdx = cargoIdx - self.copy = copy - self.internal_history = wx.CommandProcessor() - - def Do(self): - sFit = Fit.getInstance() - fit = sFit.getFit(self.fitID) - module = fit.modules[self.moduleIdx] - cargo = fit.cargo[self.cargoIdx] - result = None - - # We're trying to move a charge from cargo to a slot. Use SetCharge command (don't respect move vs copy) - if sFit.isAmmo(cargo.item.ID): - result = self.internal_history.Submit(FitSetChargeCommand(self.fitID, [module], cargo.item.ID)) - # else: - # - # pyfalog.debug("Moving cargo item to module for fit ID: {0}", self.fitID) - # - # # Gather modules and convert Cargo item to Module, silently return if not a module - # try: - # cargoP = es_Module(cargo.item) - # cargoP.owner = fit - # if cargoP.isValidState(State.ACTIVE): - # cargoP.state = State.ACTIVE - # except: - # pyfalog.warning("Invalid item: {0}", cargo.item) - # return - # - # if cargoP.slot != module.slot: # can't swap modules to different racks - # return - # - # # remove module that we are trying to move cargo to - # fit.modules.remove(module) - # - # if not cargoP.fits(fit): # if cargo doesn't fit, rollback and return - # fit.modules.insert(moduleIdx, module) - # return - # - # fit.modules.insert(moduleIdx, cargoP) - # - # if not copyMod: # remove existing cargo if not cloning - # if cargo.amount == 1: - # fit.cargo.remove(cargo) - # else: - # cargo.amount -= 1 - # - # if not module.isEmpty: # if module is placeholder, we don't want to convert/add it - # moduleItem = module.item if not module.item.isAbyssal else module.baseItem - # for x in fit.cargo.find(moduleItem): - # x.amount += 1 - # break - # else: - # moduleP = es_Cargo(moduleItem) - # moduleP.amount = 1 - # fit.cargo.insert(cargoIdx, moduleP) - # - # eos.db.commit() - # self.recalc(fit) - # # - # # - # # - # # if self.clone: - # # result = self.internal_history.Submit(FitCloneModduleCommand(self.fitID, self.srcPosition, self.dstPosition)) - # # else: - # # result = self.internal_history.Submit(FitSwapModuleCommand(self.fitID, self.srcPosition, self.dstPosition)) - - if result: - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) - return result - - def Undo(self): - for _ in self.internal_history.Commands: - self.internal_history.Undo() - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) - return True diff --git a/gui/fitCommands/guiCargoToModule.py b/gui/fitCommands/guiCargoToModule.py new file mode 100644 index 000000000..63f595788 --- /dev/null +++ b/gui/fitCommands/guiCargoToModule.py @@ -0,0 +1,63 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from gui.fitCommands.calc.fitSetCharge import FitSetChargeCommand +from gui.fitCommands.calc.fitReplaceModule import FitReplaceModuleCommand +from gui.fitCommands.calc.fitRemoveCargo import FitRemoveCargoCommand +from logbook import Logger +pyfalog = Logger(__name__) + +class GuiCargoToModuleCommand(wx.Command): + """ + Moves cargo to fitting window. Can either do a copy, move, or swap with current module + If we try to copy/move into a spot with a non-empty module, we swap instead. + To avoid redundancy in converting Cargo item, this function does the + sanity checks as opposed to the GUI View. This is different than how the + normal .swapModules() does things, which is mostly a blind swap. + """ + + def __init__(self, fitID, moduleIdx, cargoIdx, copy=False): + wx.Command.__init__(self, True, "Module State Change") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.fitID = fitID + self.moduleIdx = moduleIdx + self.cargoIdx = cargoIdx + self.copy = copy + self.internal_history = wx.CommandProcessor() + + def Do(self): + sFit = Fit.getInstance() + fit = sFit.getFit(self.fitID) + module = fit.modules[self.moduleIdx] + cargo = fit.cargo[self.cargoIdx] + result = None + + # We're trying to move a charge from cargo to a slot. Use SetCharge command (don't respect move vs copy) + if sFit.isAmmo(cargo.item.ID): + result = self.internal_history.Submit(FitSetChargeCommand(self.fitID, [module], cargo.item.ID)) + else: + + pyfalog.debug("Moving cargo item to module for fit ID: {0}", self.fitID) + + self.addCmd = FitReplaceModuleCommand(self.fitID, module.modPosition, cargo.itemID) + result = self.internal_history.Submit(self.addCmd) + if not result: + # module failed + return False + + if not self.copy: + self.removeCmd = FitRemoveCargoCommand(self.fitID, cargo.itemID) + result = self.internal_history.Submit(self.removeCmd) + + if result: + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return result + + def Undo(self): + for _ in self.internal_history.Commands: + self.internal_history.Undo() + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True From 9977866eb02b2418ad28376f12e29cf2ed58e79b Mon Sep 17 00:00:00 2001 From: Ryan Holmes Date: Mon, 13 Aug 2018 15:03:19 -0400 Subject: [PATCH 39/95] work on moving from cargo to modules (including swapping modules) --- gui/builtinAdditionPanes/cargoView.py | 4 ++ gui/fitCommands/calc/fitCargoToModule.py | 54 ------------------------ gui/fitCommands/guiCargoToModule.py | 15 ++++++- 3 files changed, 17 insertions(+), 56 deletions(-) delete mode 100644 gui/fitCommands/calc/fitCargoToModule.py diff --git a/gui/builtinAdditionPanes/cargoView.py b/gui/builtinAdditionPanes/cargoView.py index 2b385c72a..dbc722eac 100644 --- a/gui/builtinAdditionPanes/cargoView.py +++ b/gui/builtinAdditionPanes/cargoView.py @@ -130,6 +130,10 @@ class CargoView(d.Display): if mstate.cmdDown: # if copying, append to cargo sFit.addCargo(self.mainFrame.getActiveFit(), module.item.ID if not module.item.isAbyssal else module.baseItemID) else: # else, move / swap + # self.mainFrame.command.Submit(cmd.GuiCargoToModuleCommand( + # self.mainFrame.getActiveFit(), + # module.modPosition, + # dstRow)) sFit.moveCargoToModule(self.mainFrame.getActiveFit(), module.position, dstRow) else: # dragging to blank spot, append sFit.addCargo(self.mainFrame.getActiveFit(), module.item.ID if not module.item.isAbyssal else module.baseItemID) diff --git a/gui/fitCommands/calc/fitCargoToModule.py b/gui/fitCommands/calc/fitCargoToModule.py deleted file mode 100644 index d030c4026..000000000 --- a/gui/fitCommands/calc/fitCargoToModule.py +++ /dev/null @@ -1,54 +0,0 @@ -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__) -from eos.saveddata.booster import Booster - -class FitAddBoosterCommand(wx.Command): - """" - from sFit.addBooster - """ - def __init__(self, fitID, itemID): - wx.Command.__init__(self, True) - self.fitID = fitID - self.itemID = itemID - self.new_index = None - self.old_item = None - - def Do(self): - pyfalog.debug("Adding booster ({0}) to fit ID: {1}", self.itemID, self.fitID) - - fit = eos.db.getFit(self.fitID) - item = eos.db.getItem(self.itemID, eager="attributes") - - if next((x for x in fit.boosters if x.itemID == self.itemID), None): - return False # already have item in list of boosters - - try: - booster = Booster(item) - except ValueError: - pyfalog.warning("Invalid item: {0}", self.itemID) - return False - - self.old_item = fit.boosters.makeRoom(booster) - fit.boosters.append(booster) - self.new_index = fit.boosters.index(booster) - return True - - def Undo(self): - if self.old_item: - # If we had an item in the slot previously, add it back. - cmd = FitAddBoosterCommand(self.fitID, self.old_item) - cmd.Do() - return True - - from .fitRemoveBooster import FitRemoveBoosterCommand # Avoid circular import - cmd = FitRemoveBoosterCommand(self.fitID, self.new_index) - cmd.Do() - return True diff --git a/gui/fitCommands/guiCargoToModule.py b/gui/fitCommands/guiCargoToModule.py index 63f595788..784cfba88 100644 --- a/gui/fitCommands/guiCargoToModule.py +++ b/gui/fitCommands/guiCargoToModule.py @@ -6,6 +6,7 @@ from gui import globalEvents as GE from gui.fitCommands.calc.fitSetCharge import FitSetChargeCommand from gui.fitCommands.calc.fitReplaceModule import FitReplaceModuleCommand from gui.fitCommands.calc.fitRemoveCargo import FitRemoveCargoCommand +from .calc.fitAddCargo import FitAddCargoCommand from logbook import Logger pyfalog = Logger(__name__) @@ -43,12 +44,22 @@ class GuiCargoToModuleCommand(wx.Command): pyfalog.debug("Moving cargo item to module for fit ID: {0}", self.fitID) self.addCmd = FitReplaceModuleCommand(self.fitID, module.modPosition, cargo.itemID) + result = self.internal_history.Submit(self.addCmd) + if not result: - # module failed + # creating module failed for whatever reason return False - if not self.copy: + if self.addCmd.old_module is not None: + # we're swapping with an existing module, so remove cargo and add module + self.removeCmd = FitRemoveCargoCommand(self.fitID, cargo.itemID) + result = self.internal_history.Submit(self.removeCmd) + + self.addCargoCmd = FitAddCargoCommand(self.fitID, self.addCmd.old_module.itemID) + result = self.internal_history.Submit(self.addCargoCmd) + elif not self.copy: + # move, not copying, so remove cargo self.removeCmd = FitRemoveCargoCommand(self.fitID, cargo.itemID) result = self.internal_history.Submit(self.removeCmd) From d74f2b2e422dcc2de83c71a9c9174f08629781dd Mon Sep 17 00:00:00 2001 From: Ryan Holmes Date: Mon, 13 Aug 2018 17:01:16 -0400 Subject: [PATCH 40/95] Rework the logic of dragging module to cargo --- gui/builtinAdditionPanes/cargoView.py | 22 +++------ gui/fitCommands/__init__.py | 3 +- gui/fitCommands/guiModuleToCargo.py | 70 +++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 16 deletions(-) create mode 100644 gui/fitCommands/guiModuleToCargo.py diff --git a/gui/builtinAdditionPanes/cargoView.py b/gui/builtinAdditionPanes/cargoView.py index dbc722eac..8eb54875f 100644 --- a/gui/builtinAdditionPanes/cargoView.py +++ b/gui/builtinAdditionPanes/cargoView.py @@ -126,22 +126,14 @@ class CargoView(d.Display): if not result: return - if dstRow != -1: # we're swapping with cargo - if mstate.cmdDown: # if copying, append to cargo - sFit.addCargo(self.mainFrame.getActiveFit(), module.item.ID if not module.item.isAbyssal else module.baseItemID) - else: # else, move / swap - # self.mainFrame.command.Submit(cmd.GuiCargoToModuleCommand( - # self.mainFrame.getActiveFit(), - # module.modPosition, - # dstRow)) - sFit.moveCargoToModule(self.mainFrame.getActiveFit(), module.position, dstRow) - else: # dragging to blank spot, append - sFit.addCargo(self.mainFrame.getActiveFit(), module.item.ID if not module.item.isAbyssal else module.baseItemID) + cargoPos = dstRow if dstRow > -1 else None - if not mstate.cmdDown: # if not copying, remove module - sFit.removeModule(self.mainFrame.getActiveFit(), module.position) - - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit(), action="moddel", typeID=module.item.ID)) + self.mainFrame.command.Submit(cmd.GuiModuleToCargoCommand( + self.mainFrame.getActiveFit(), + module.modPosition, + cargoPos, + mstate.cmdDown + )) def fitChanged(self, event): sFit = Fit.getInstance() diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index 75889255f..966295b7e 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -15,4 +15,5 @@ from .guiSetMode import GuiSetModeCommand from .guiToggleCommand import GuiToggleCommandCommand from .guiAddProjected import GuiAddProjectedCommand from .guiRemoveProjected import GuiRemoveProjectedCommand -from .guiCargoToModule import GuiCargoToModuleCommand \ No newline at end of file +from .guiCargoToModule import GuiCargoToModuleCommand +from .guiModuleToCargo import GuiModuleToCargoCommand \ No newline at end of file diff --git a/gui/fitCommands/guiModuleToCargo.py b/gui/fitCommands/guiModuleToCargo.py new file mode 100644 index 000000000..ef8e84b7a --- /dev/null +++ b/gui/fitCommands/guiModuleToCargo.py @@ -0,0 +1,70 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from gui.fitCommands.calc.fitSetCharge import FitSetChargeCommand +from gui.fitCommands.calc.fitReplaceModule import FitReplaceModuleCommand +from gui.fitCommands.calc.fitRemoveCargo import FitRemoveCargoCommand +from gui.fitCommands.calc.fitRemoveModule import FitRemoveModuleCommand + +from .calc.fitAddCargo import FitAddCargoCommand +from logbook import Logger +pyfalog = Logger(__name__) + +class GuiModuleToCargoCommand(wx.Command): + def __init__(self, fitID, moduleIdx, cargoIdx, copy=False): + wx.Command.__init__(self, True, "Module State Change") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.fitID = fitID + self.moduleIdx = moduleIdx + self.cargoIdx = cargoIdx + self.copy = copy + self.internal_history = wx.CommandProcessor() + + def Do(self): + sFit = Fit.getInstance() + fit = sFit.getFit(self.fitID) + module = fit.modules[self.moduleIdx] + result = False + + if self.cargoIdx: # we're swapping with cargo + if self.copy: # if copying, simply add item to cargo + result = self.internal_history.Submit(FitAddCargoCommand(self.mainFrame.getActiveFit(), module.item.ID if not module.item.isAbyssal else module.baseItemID)) + else: # otherwise, try to swap by replacing module with cargo item. If successful, remove old cargo and add new cargo + + cargo = fit.cargo[self.cargoIdx] + self.modReplaceCmd = FitReplaceModuleCommand(self.fitID, module.modPosition, cargo.itemID) + + result = self.internal_history.Submit(self.modReplaceCmd) + + if not result: + # creating module failed for whatever reason + return False + + if self.modReplaceCmd.old_module is not None: + # we're swapping with an existing module, so remove cargo and add module + self.removeCmd = FitRemoveCargoCommand(self.fitID, cargo.itemID) + result = self.internal_history.Submit(self.removeCmd) + + self.addCargoCmd = FitAddCargoCommand(self.fitID, self.modReplaceCmd.old_module.itemID) + result = self.internal_history.Submit(self.addCargoCmd) + + else: # dragging to blank spot, append + result = self.internal_history.Submit(FitAddCargoCommand(self.mainFrame.getActiveFit(), + module.item.ID if not module.item.isAbyssal else module.baseItemID)) + + if not self.copy: # if not copying, remove module + self.internal_history.Submit(FitRemoveModuleCommand(self.mainFrame.getActiveFit(), [self.moduleIdx])) + + + if result: + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="moddel", typeID=module.item.ID)) + return result + + def Undo(self): + for _ in self.internal_history.Commands: + self.internal_history.Undo() + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True From 646a903f1850ef55ea6f7ba2f294e2c0e0218f7b Mon Sep 17 00:00:00 2001 From: Ryan Holmes Date: Mon, 13 Aug 2018 17:16:00 -0400 Subject: [PATCH 41/95] differentiate command processors based on fitID --- gui/mainFrame.py | 6 ++++-- service/fit.py | 12 ++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/gui/mainFrame.py b/gui/mainFrame.py index 2a94f1b2c..3f35ff7ae 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -170,8 +170,6 @@ class MainFrame(wx.Frame): i = wx.Icon(BitmapLoader.getBitmap("pyfa", "gui")) self.SetIcon(i) - self.command = wx.CommandProcessor() - # Create the layout and windows mainSizer = wx.BoxSizer(wx.HORIZONTAL) @@ -246,6 +244,10 @@ class MainFrame(wx.Frame): self.Bind(GE.EVT_SSO_LOGIN, self.onSSOLogin) self.Bind(GE.EVT_SSO_LOGGING_IN, self.ShowSsoLogin) + @property + def command(self): + return Fit.getCommandProcessor(self.getActiveFit()) + def ShowSsoLogin(self, event): if getattr(event, "login_mode", LoginMethod.SERVER) == LoginMethod.MANUAL and getattr(event, "sso_mode", SsoMode.AUTO) == SsoMode.AUTO: dlg = SsoLogin(self) diff --git a/service/fit.py b/service/fit.py index c19513dd0..a4624692a 100644 --- a/service/fit.py +++ b/service/fit.py @@ -38,6 +38,8 @@ from service.character import Character from service.damagePattern import DamagePattern from service.settings import SettingsProvider from utils.deprecated import deprecated +import wx + pyfalog = Logger(__name__) @@ -57,6 +59,7 @@ class DeferRecalc(): class Fit(object): instance = None + processors = {} @classmethod def getInstance(cls): @@ -213,12 +216,21 @@ class Fit(object): eos.db.remove(fit) + if fitID in Fit.__class__.processors: + del Fit.__class__.processors[fitID] + pyfalog.debug(" Need to refresh {} fits: {}", len(refreshFits), refreshFits) for fit in refreshFits: eos.db.saveddata_session.refresh(fit) eos.db.saveddata_session.commit() + @classmethod + def getCommandProcessor(cls, fitID): + if fitID not in cls.processors: + cls.processors[fitID] = wx.CommandProcessor() + return cls.processors[fitID] + @staticmethod def copyFit(fitID): pyfalog.debug("Creating copy of fit ID: {0}", fitID) From efbf2e743289062a8b71de6e0d5e0578390e4dbc Mon Sep 17 00:00:00 2001 From: Ryan Holmes Date: Mon, 13 Aug 2018 18:50:00 -0400 Subject: [PATCH 42/95] Make sure we recalc during swaps from cargo to module --- gui/builtinViews/fittingView.py | 7 ------- gui/fitCommands/guiCargoToModule.py | 3 ++- gui/fitCommands/guiModuleToCargo.py | 3 ++- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index 74d02295c..a1c2b62e0 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -434,19 +434,12 @@ class FittingView(d.Display): if not isinstance(module, Module): return - sFit = Fit.getInstance() - fit = sFit.getFit(self.activeFitID) - typeID = fit.cargo[srcIdx].item.ID - self.mainFrame.command.Submit(cmd.GuiCargoToModuleCommand( self.mainFrame.getActiveFit(), module.modPosition, srcIdx, mstate.CmdDown() and module.isEmpty)) - - # wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit(), action="modadd", typeID=typeID)) - def swapItems(self, x, y, srcIdx): """Swap two modules in fitting window""" mstate = wx.GetMouseState() diff --git a/gui/fitCommands/guiCargoToModule.py b/gui/fitCommands/guiCargoToModule.py index 784cfba88..3ce9cc4b0 100644 --- a/gui/fitCommands/guiCargoToModule.py +++ b/gui/fitCommands/guiCargoToModule.py @@ -34,7 +34,7 @@ class GuiCargoToModuleCommand(wx.Command): fit = sFit.getFit(self.fitID) module = fit.modules[self.moduleIdx] cargo = fit.cargo[self.cargoIdx] - result = None + result = False # We're trying to move a charge from cargo to a slot. Use SetCharge command (don't respect move vs copy) if sFit.isAmmo(cargo.item.ID): @@ -64,6 +64,7 @@ class GuiCargoToModuleCommand(wx.Command): result = self.internal_history.Submit(self.removeCmd) if result: + sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return result diff --git a/gui/fitCommands/guiModuleToCargo.py b/gui/fitCommands/guiModuleToCargo.py index ef8e84b7a..d59680408 100644 --- a/gui/fitCommands/guiModuleToCargo.py +++ b/gui/fitCommands/guiModuleToCargo.py @@ -58,9 +58,10 @@ class GuiModuleToCargoCommand(wx.Command): if not self.copy: # if not copying, remove module self.internal_history.Submit(FitRemoveModuleCommand(self.mainFrame.getActiveFit(), [self.moduleIdx])) - if result: + sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="moddel", typeID=module.item.ID)) + return result def Undo(self): From 513e9d14d89926cf66227e8619d23ccafcebd06b Mon Sep 17 00:00:00 2001 From: Ryan Holmes Date: Mon, 13 Aug 2018 18:53:30 -0400 Subject: [PATCH 43/95] Moved the default fighter ability to the __init__() --- eos/saveddata/fighter.py | 14 ++++++++++++++ gui/builtinViews/fittingView.py | 2 -- service/fit.py | 14 +------------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/eos/saveddata/fighter.py b/eos/saveddata/fighter.py index 694970343..8c515b945 100644 --- a/eos/saveddata/fighter.py +++ b/eos/saveddata/fighter.py @@ -53,6 +53,20 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): self.build() + standardAttackActive = False + for ability in self.abilities: + if ability.effect.isImplemented and ability.effect.handlerName == 'fighterabilityattackm': + # Activate "standard attack" if available + ability.active = True + standardAttackActive = True + else: + # Activate all other abilities (Neut, Web, etc) except propmods if no standard attack is active + if ability.effect.isImplemented and \ + standardAttackActive is False and \ + ability.effect.handlerName != 'fighterabilitymicrowarpdrive' and \ + ability.effect.handlerName != 'fighterabilityevasivemaneuvers': + ability.active = True + @reconstructor def init(self): """Initialize a fighter from the database and validate""" diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index a1c2b62e0..eab0b9fa0 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -128,8 +128,6 @@ class FittingViewDrop(wx.DropTarget): return t - - class FittingView(d.Display): DEFAULT_COLS = ["State", "Ammo Icon", diff --git a/service/fit.py b/service/fit.py index a4624692a..87b8f02a9 100644 --- a/service/fit.py +++ b/service/fit.py @@ -861,6 +861,7 @@ class Fit(object): self.recalc(fit) return True + @deprecated def addFighter(self, fitID, itemID, recalc=True): pyfalog.debug("Adding fighters ({0}) to fit ID: {1}", itemID, fitID) if fitID is None: @@ -880,19 +881,6 @@ class Fit(object): fighter = es_Fighter(item) used = fit.getSlotsUsed(fighter.slot) total = fit.getNumSlots(fighter.slot) - standardAttackActive = False - for ability in fighter.abilities: - if ability.effect.isImplemented and ability.effect.handlerName == 'fighterabilityattackm': - # Activate "standard attack" if available - ability.active = True - standardAttackActive = True - else: - # Activate all other abilities (Neut, Web, etc) except propmods if no standard attack is active - if ability.effect.isImplemented and \ - standardAttackActive is False and \ - ability.effect.handlerName != 'fighterabilitymicrowarpdrive' and \ - ability.effect.handlerName != 'fighterabilityevasivemaneuvers': - ability.active = True if used >= total: fighter.active = False From f0983c14683f1c5268c1307efd9395ed7a1555c4 Mon Sep 17 00:00:00 2001 From: Ryan Holmes Date: Mon, 13 Aug 2018 19:35:32 -0400 Subject: [PATCH 44/95] Implement fighter add/remove commands --- gui/builtinAdditionPanes/fighterView.py | 11 ++--- gui/builtinContextMenus/itemRemove.py | 3 +- gui/fitCommands/__init__.py | 4 +- gui/fitCommands/calc/fitAddFighter.py | 53 ++++++++++++++++++++++++ gui/fitCommands/calc/fitRemoveFighter.py | 34 +++++++++++++++ gui/fitCommands/guiAddFighter.py | 30 ++++++++++++++ gui/fitCommands/guiRemoveFighter.py | 32 ++++++++++++++ gui/mainFrame.py | 2 +- service/fit.py | 1 + 9 files changed, 160 insertions(+), 10 deletions(-) create mode 100644 gui/fitCommands/calc/fitAddFighter.py create mode 100644 gui/fitCommands/calc/fitRemoveFighter.py create mode 100644 gui/fitCommands/guiAddFighter.py create mode 100644 gui/fitCommands/guiRemoveFighter.py diff --git a/gui/builtinAdditionPanes/fighterView.py b/gui/builtinAdditionPanes/fighterView.py index 3292583fd..916bcf585 100644 --- a/gui/builtinAdditionPanes/fighterView.py +++ b/gui/builtinAdditionPanes/fighterView.py @@ -30,6 +30,7 @@ from gui.contextMenu import ContextMenu from gui.utils.staticHelpers import DragDropHelper from service.fit import Fit from service.market import Market +import gui.fitCommands as cmd class FighterViewDrop(wx.DropTarget): @@ -269,11 +270,9 @@ class FighterDisplay(d.Display): event.Skip() def addItem(self, event): - sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() - trigger = sFit.addFighter(fitID, event.itemID) - if trigger: - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + + if self.mainFrame.command.Submit(cmd.GuiAddFighterCommand(fitID, event.itemID)): self.mainFrame.additionsPane.select("Fighters") event.Skip() @@ -288,9 +287,7 @@ class FighterDisplay(d.Display): def removeFighter(self, fighter): fitID = self.mainFrame.getActiveFit() - sFit = Fit.getInstance() - sFit.removeFighter(fitID, self.original.index(fighter)) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.GuiRemoveFighterCommand(fitID, self.original.index(fighter))) def click(self, event): event.Skip() diff --git a/gui/builtinContextMenus/itemRemove.py b/gui/builtinContextMenus/itemRemove.py index 0d464461d..65094c7a4 100644 --- a/gui/builtinContextMenus/itemRemove.py +++ b/gui/builtinContextMenus/itemRemove.py @@ -43,7 +43,8 @@ class ItemRemove(ContextMenu): elif srcContext == "droneItem": sFit.removeDrone(fitID, fit.drones.index(selection[0])) elif srcContext == "fighterItem": - sFit.removeFighter(fitID, fit.fighters.index(selection[0])) + self.mainFrame.command.Submit(cmd.GuiRemoveFighterCommand(fitID, fit.fighters.index(selection[0]))) + return # the command takes care of the PostEvent elif srcContext == "implantItem": self.mainFrame.command.Submit(cmd.GuiRemoveImplantCommand(fitID, fit.implants.index(selection[0]))) return # the command takes care of the PostEvent diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index 966295b7e..5acf62ffd 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -16,4 +16,6 @@ from .guiToggleCommand import GuiToggleCommandCommand from .guiAddProjected import GuiAddProjectedCommand from .guiRemoveProjected import GuiRemoveProjectedCommand from .guiCargoToModule import GuiCargoToModuleCommand -from .guiModuleToCargo import GuiModuleToCargoCommand \ No newline at end of file +from .guiModuleToCargo import GuiModuleToCargoCommand +from .guiAddFighter import GuiAddFighterCommand +from .guiRemoveFighter import GuiRemoveFighterCommand \ No newline at end of file diff --git a/gui/fitCommands/calc/fitAddFighter.py b/gui/fitCommands/calc/fitAddFighter.py new file mode 100644 index 000000000..9ceda53a1 --- /dev/null +++ b/gui/fitCommands/calc/fitAddFighter.py @@ -0,0 +1,53 @@ +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__) +from eos.saveddata.fighter import Fighter + +class FitAddFighterCommand(wx.Command): + """" + from sFit.addFighter + """ + def __init__(self, fitID, itemID, amount=1, replace=False): + wx.Command.__init__(self, True, "Cargo add") + self.fitID = fitID + self.itemID = itemID + self.new_index = None + + def Do(self): + fit = eos.db.getFit(self.fitID) + item = eos.db.getItem(self.itemID, eager=("attributes", "group.category")) + + try: + fighter = Fighter(item) + except ValueError: + pyfalog.warning("Invalid fighter: {}", item) + return False + + if not fighter.fits(fit): + return False + + used = fit.getSlotsUsed(fighter.slot) + total = fit.getNumSlots(fighter.slot) + + if used >= total: + fighter.active = False + + fit.fighters.append(fighter) + self.new_index = fit.fighters.index(fighter) + + eos.db.commit() + + return True + + def Undo(self): + from .fitRemoveFighter import FitRemoveFighterCommand # Avoid circular import + cmd = FitRemoveFighterCommand(self.fitID, self.new_index) + cmd.Do() + return True diff --git a/gui/fitCommands/calc/fitRemoveFighter.py b/gui/fitCommands/calc/fitRemoveFighter.py new file mode 100644 index 000000000..58b1f7c6a --- /dev/null +++ b/gui/fitCommands/calc/fitRemoveFighter.py @@ -0,0 +1,34 @@ +import wx + +from gui.fitCommands.helpers import ModuleInfoCache +import eos.db +from logbook import Logger +pyfalog = Logger(__name__) + + +class FitRemoveFighterCommand(wx.Command): + """" + Fitting command that removes a module at a specified positions + + from sFit.removeFighter + """ + def __init__(self, fitID: int, position: int): + wx.Command.__init__(self, True) + self.fitID = fitID + self.position = position + self.change = None + self.removed_item = None + + def Do(self): + fitID = self.fitID + fit = eos.db.getFit(fitID) + f = fit.fighters[self.position] + fit.fighters.remove(f) + self.removed_item = f.itemID + eos.db.commit() + return True + + def Undo(self): + from gui.fitCommands.calc.fitAddFighter import FitAddFighterCommand # avoids circular import + cmd = FitAddFighterCommand(self.fitID, self.removed_item) + return cmd.Do() diff --git a/gui/fitCommands/guiAddFighter.py b/gui/fitCommands/guiAddFighter.py new file mode 100644 index 000000000..095688142 --- /dev/null +++ b/gui/fitCommands/guiAddFighter.py @@ -0,0 +1,30 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from .calc.fitAddFighter import FitAddFighterCommand + +class GuiAddFighterCommand(wx.Command): + def __init__(self, fitID, itemID): + wx.Command.__init__(self, True, "Cargo Add") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() + self.fitID = fitID + self.itemID = itemID + + def Do(self): + cmd = FitAddFighterCommand(self.fitID, self.itemID) + if self.internal_history.Submit(cmd): + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for _ in self.internal_history.Commands: + self.internal_history.Undo() + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + diff --git a/gui/fitCommands/guiRemoveFighter.py b/gui/fitCommands/guiRemoveFighter.py new file mode 100644 index 000000000..f1b983ec5 --- /dev/null +++ b/gui/fitCommands/guiRemoveFighter.py @@ -0,0 +1,32 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from .calc.fitRemoveFighter import FitRemoveFighterCommand + + +class GuiRemoveFighterCommand(wx.Command): + def __init__(self, fitID, position): + wx.Command.__init__(self, True, "Module Remove") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.fitID = fitID + self.position = position + self.internal_history = wx.CommandProcessor() + + def Do(self): + success = self.internal_history.Submit(FitRemoveFighterCommand(self.fitID, self.position)) + + if success: + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for _ in self.internal_history.Commands: + self.internal_history.Undo() + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True diff --git a/gui/mainFrame.py b/gui/mainFrame.py index 3f35ff7ae..5dd119db0 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -245,7 +245,7 @@ class MainFrame(wx.Frame): self.Bind(GE.EVT_SSO_LOGGING_IN, self.ShowSsoLogin) @property - def command(self): + def command(self) -> wx.CommandProcessor: return Fit.getCommandProcessor(self.getActiveFit()) def ShowSsoLogin(self, event): diff --git a/service/fit.py b/service/fit.py index 87b8f02a9..c7cb70fd1 100644 --- a/service/fit.py +++ b/service/fit.py @@ -897,6 +897,7 @@ class Fit(object): else: return False + @deprecated def removeFighter(self, fitID, i, recalc=True): pyfalog.debug("Removing fighters from fit ID: {0}", fitID) fit = eos.db.getFit(fitID) From a5a152d3956d2100b5d7c3cffbcd0daaa3529bc7 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Tue, 14 Aug 2018 00:58:50 -0400 Subject: [PATCH 45/95] Move meta swap functionality to command process --- gui/builtinContextMenus/metaSwap.py | 134 +++++++++++++------------- gui/fitCommands/__init__.py | 3 +- gui/fitCommands/calc/fitAddFighter.py | 2 +- gui/fitCommands/guiMetaSwap.py | 64 ++++++++++++ 4 files changed, 136 insertions(+), 67 deletions(-) create mode 100644 gui/fitCommands/guiMetaSwap.py diff --git a/gui/builtinContextMenus/metaSwap.py b/gui/builtinContextMenus/metaSwap.py index 871ebad68..bd98c6bfa 100644 --- a/gui/builtinContextMenus/metaSwap.py +++ b/gui/builtinContextMenus/metaSwap.py @@ -122,82 +122,86 @@ class MetaSwap(ContextMenu): id = ContextMenu.nextID() mitem = wx.MenuItem(rootMenu, id, item.name) bindmenu.Bind(wx.EVT_MENU, self.handleModule, mitem) - self.moduleLookup[id] = item + print(context) + self.moduleLookup[id] = item, context m.Append(mitem) return m def handleModule(self, event): - item = self.moduleLookup.get(event.Id, None) + item, context = self.moduleLookup.get(event.Id, None) if item is None: event.Skip() return - sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() - fit = sFit.getFit(fitID) - for selected_item in self.selection: - if isinstance(selected_item, Module): - pos = fit.modules.index(selected_item) - sFit.changeModule(fitID, pos, item.ID) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.GuiMetaSwapCommand(fitID, context, item.ID, self.selection)) - elif isinstance(selected_item, Drone): - drone_count = None - - for idx, drone_stack in enumerate(fit.drones): - if drone_stack is selected_item: - drone_count = drone_stack.amount - sFit.removeDrone(fitID, idx, drone_count, False) - break - - if drone_count: - sFit.addDrone(fitID, item.ID, drone_count, True) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) - - elif isinstance(selected_item, Fighter): - fighter_count = None - - for idx, fighter_stack in enumerate(fit.fighters): - # Right now fighters always will have max stack size. - # Including this for future improvement, so if adjustable - # fighter stacks get added we're ready for it. - if fighter_stack is selected_item: - if fighter_stack.amount > 0: - fighter_count = fighter_stack.amount - elif fighter_stack.amount == -1: - fighter_count = fighter_stack.amountActive - else: - fighter_count.amount = 0 - - sFit.removeFighter(fitID, idx, False) - break - - sFit.addFighter(fitID, item.ID, True) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) - - elif isinstance(selected_item, Booster): - for idx, booster_stack in enumerate(fit.boosters): - if booster_stack is selected_item: - self.mainFrame.command.Submit(cmd.GuiRemoveBoosterCommand(fitID, idx)) - self.mainFrame.command.Submit(cmd.GuiAddBoosterCommand(fitID, item.ID)) - break - - elif isinstance(selected_item, Implant): - for idx, implant_stack in enumerate(fit.implants): - if implant_stack is selected_item: - self.mainFrame.command.Submit(cmd.GuiRemoveImplantCommand(fitID, idx)) - self.mainFrame.command.Submit(cmd.GuiAddImplantCommand(fitID, item.ID)) - break - - elif isinstance(selected_item, Cargo): - for idx, cargo_stack in enumerate(fit.cargo): - if cargo_stack is selected_item: - # todo: make a command to change varieance of all items, or maybe per item type, which would - # utilize the two fitting commands that we need to remove then add? - sFit.removeCargo(fitID, idx) - self.mainFrame.command.Submit(cmd.GuiAddCargoCommand(fitID, item.ID, cargo_stack.amount, True)) - break + # for selected_item in self.selection: + # if isinstance(selected_item, Module): + # pos = fit.modules.index(selected_item) + # self.mainFrame.command.Submit(cmd.GuiModuleAddCommand(fitID, item.ID, pos)) + # + # + # sFit.changeModule(fitID, pos, item.ID) + # wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + # + # elif isinstance(selected_item, Drone): + # drone_count = None + # + # for idx, drone_stack in enumerate(fit.drones): + # if drone_stack is selected_item: + # drone_count = drone_stack.amount + # sFit.removeDrone(fitID, idx, drone_count, False) + # break + # + # if drone_count: + # sFit.addDrone(fitID, item.ID, drone_count, True) + # wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + # + # elif isinstance(selected_item, Fighter): + # fighter_count = None + # + # for idx, fighter_stack in enumerate(fit.fighters): + # # Right now fighters always will have max stack size. + # # Including this for future improvement, so if adjustable + # # fighter stacks get added we're ready for it. + # if fighter_stack is selected_item: + # if fighter_stack.amount > 0: + # fighter_count = fighter_stack.amount + # elif fighter_stack.amount == -1: + # fighter_count = fighter_stack.amountActive + # else: + # fighter_count.amount = 0 + # + # sFit.removeFighter(fitID, idx, False) + # break + # + # sFit.addFighter(fitID, item.ID, True) + # wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + # + # elif isinstance(selected_item, Booster): + # for idx, booster_stack in enumerate(fit.boosters): + # if booster_stack is selected_item: + # self.mainFrame.command.Submit(cmd.GuiRemoveBoosterCommand(fitID, idx)) + # self.mainFrame.command.Submit(cmd.GuiAddBoosterCommand(fitID, item.ID)) + # break + # + # elif isinstance(selected_item, Implant): + # for idx, implant_stack in enumerate(fit.implants): + # if implant_stack is selected_item: + # self.mainFrame.command.Submit(cmd.GuiRemoveImplantCommand(fitID, idx)) + # self.mainFrame.command.Submit(cmd.GuiAddImplantCommand(fitID, item.ID)) + # break + # + # elif isinstance(selected_item, Cargo): + # for idx, cargo_stack in enumerate(fit.cargo): + # if cargo_stack is selected_item: + # # todo: make a command to change varieance of all items, or maybe per item type, which would + # # utilize the two fitting commands that we need to remove then add? + # sFit.removeCargo(fitID, idx) + # self.mainFrame.command.Submit(cmd.GuiAddCargoCommand(fitID, item.ID, cargo_stack.amount, True)) + # break diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index 5acf62ffd..6515b5e27 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -18,4 +18,5 @@ from .guiRemoveProjected import GuiRemoveProjectedCommand from .guiCargoToModule import GuiCargoToModuleCommand from .guiModuleToCargo import GuiModuleToCargoCommand from .guiAddFighter import GuiAddFighterCommand -from .guiRemoveFighter import GuiRemoveFighterCommand \ No newline at end of file +from .guiRemoveFighter import GuiRemoveFighterCommand +from .guiMetaSwap import GuiMetaSwapCommand \ No newline at end of file diff --git a/gui/fitCommands/calc/fitAddFighter.py b/gui/fitCommands/calc/fitAddFighter.py index 9ceda53a1..dfaccbf3d 100644 --- a/gui/fitCommands/calc/fitAddFighter.py +++ b/gui/fitCommands/calc/fitAddFighter.py @@ -14,7 +14,7 @@ class FitAddFighterCommand(wx.Command): """" from sFit.addFighter """ - def __init__(self, fitID, itemID, amount=1, replace=False): + def __init__(self, fitID, itemID): wx.Command.__init__(self, True, "Cargo add") self.fitID = fitID self.itemID = itemID diff --git a/gui/fitCommands/guiMetaSwap.py b/gui/fitCommands/guiMetaSwap.py new file mode 100644 index 000000000..e40906070 --- /dev/null +++ b/gui/fitCommands/guiMetaSwap.py @@ -0,0 +1,64 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from .calc.fitRemoveImplant import FitRemoveImplantCommand +from .calc.fitAddImplant import FitAddImplantCommand +from .calc.fitRemoveBooster import FitRemoveBoosterCommand +from .calc.fitAddBooster import FitAddBoosterCommand +from .calc.fitRemoveCargo import FitRemoveCargoCommand +from .calc.fitAddCargo import FitAddCargoCommand +from .calc.fitReplaceModule import FitReplaceModuleCommand +from .calc.fitAddFighter import FitAddFighterCommand +from .calc.fitRemoveFighter import FitRemoveFighterCommand + +class GuiMetaSwapCommand(wx.Command): + def __init__(self, fitID, context, itemID, selection: list): + wx.Command.__init__(self, True, "Meta Swap") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() + self.fitID = fitID + self.itemID = itemID + self.context = context + self.data = [] + fit = self.sFit.getFit(fitID) + + if context == 'fittingModule': + for x in selection: + self.data.append(((FitReplaceModuleCommand, fitID, fit.modules.index(x), itemID),),) + elif context == 'implantItem': + for x in selection: + idx = fit.implants.index(x) + self.data.append(((FitRemoveImplantCommand, fitID, idx), (FitAddImplantCommand, fitID, itemID))) + elif context == 'boosterItem': + for x in selection: + idx = fit.boosters.index(x) + self.data.append(((FitRemoveBoosterCommand, fitID, idx), (FitAddBoosterCommand, fitID, itemID))) + elif context == 'cargoItem': + for x in selection: + self.data.append(((FitRemoveCargoCommand, fitID, x.itemID, 1, True), (FitAddCargoCommand, fitID, itemID, x.amount))) + elif context == 'fighterItem': + for x in selection: + self.data.append(((FitRemoveFighterCommand, fitID, fit.fighters.index(x)), (FitAddFighterCommand, fitID, itemID))) + elif context == 'droneItem': + raise NotImplementedError() + + + def Do(self): + for cmds in self.data: + for cmd in cmds: + self.internal_history.Submit(cmd[0](*cmd[1:])) + + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + + def Undo(self): + for x in self.internal_history.Commands: + self.internal_history.Undo() + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + From 71257b5265bc3cf1b02e4082040dae2d6ebd6564 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Tue, 14 Aug 2018 01:25:36 -0400 Subject: [PATCH 46/95] Implement some various toggles as commands --- gui/builtinAdditionPanes/boosterView.py | 4 +-- gui/builtinAdditionPanes/fighterView.py | 4 +-- gui/builtinAdditionPanes/implantView.py | 4 +-- gui/fitCommands/__init__.py | 5 +++- gui/fitCommands/calc/fitToggleBooster.py | 32 +++++++++++++++++++++++ gui/fitCommands/calc/fitToggleFighter.py | 33 ++++++++++++++++++++++++ gui/fitCommands/calc/fitToggleImplant.py | 33 ++++++++++++++++++++++++ gui/fitCommands/guiMetaSwap.py | 1 + gui/fitCommands/guiToggleBooster.py | 30 +++++++++++++++++++++ gui/fitCommands/guiToggleFighter.py | 30 +++++++++++++++++++++ gui/fitCommands/guiToggleImplant.py | 30 +++++++++++++++++++++ service/fit.py | 3 +++ 12 files changed, 199 insertions(+), 10 deletions(-) create mode 100644 gui/fitCommands/calc/fitToggleBooster.py create mode 100644 gui/fitCommands/calc/fitToggleFighter.py create mode 100644 gui/fitCommands/calc/fitToggleImplant.py create mode 100644 gui/fitCommands/guiToggleBooster.py create mode 100644 gui/fitCommands/guiToggleFighter.py create mode 100644 gui/fitCommands/guiToggleImplant.py diff --git a/gui/builtinAdditionPanes/boosterView.py b/gui/builtinAdditionPanes/boosterView.py index 48b3ed36d..a68e4ff3a 100644 --- a/gui/builtinAdditionPanes/boosterView.py +++ b/gui/builtinAdditionPanes/boosterView.py @@ -157,9 +157,7 @@ class BoosterView(d.Display): col = self.getColumn(event.Position) if col == self.getColIndex(State): fitID = self.mainFrame.getActiveFit() - sFit = Fit.getInstance() - sFit.toggleBooster(fitID, row) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.GuiToggleImplantCommand(fitID, row)) def scheduleMenu(self, event): event.Skip() diff --git a/gui/builtinAdditionPanes/fighterView.py b/gui/builtinAdditionPanes/fighterView.py index 916bcf585..bf797ae15 100644 --- a/gui/builtinAdditionPanes/fighterView.py +++ b/gui/builtinAdditionPanes/fighterView.py @@ -296,10 +296,8 @@ class FighterDisplay(d.Display): col = self.getColumn(event.Position) if col == self.getColIndex(State): fitID = self.mainFrame.getActiveFit() - sFit = Fit.getInstance() fighter = self.fighters[row] - sFit.toggleFighter(fitID, self.original.index(fighter)) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.GuiToggleFighterCommand(fitID, self.original.index(fighter))) def scheduleMenu(self, event): event.Skip() diff --git a/gui/builtinAdditionPanes/implantView.py b/gui/builtinAdditionPanes/implantView.py index 7144d6cb5..0e2188e6f 100644 --- a/gui/builtinAdditionPanes/implantView.py +++ b/gui/builtinAdditionPanes/implantView.py @@ -187,9 +187,7 @@ class ImplantDisplay(d.Display): col = self.getColumn(event.Position) if col == self.getColIndex(State): fitID = self.mainFrame.getActiveFit() - sFit = Fit.getInstance() - sFit.toggleImplant(fitID, row) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.GuiToggleImplantCommand(fitID, row)) def scheduleMenu(self, event): event.Skip() diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index 6515b5e27..8b053bf82 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -19,4 +19,7 @@ from .guiCargoToModule import GuiCargoToModuleCommand from .guiModuleToCargo import GuiModuleToCargoCommand from .guiAddFighter import GuiAddFighterCommand from .guiRemoveFighter import GuiRemoveFighterCommand -from .guiMetaSwap import GuiMetaSwapCommand \ No newline at end of file +from .guiMetaSwap import GuiMetaSwapCommand +from .guiToggleFighter import GuiToggleFighterCommand +from .guiToggleImplant import GuiToggleImplantCommand +from .guiToggleBooster import GuiToggleImplantCommand \ No newline at end of file diff --git a/gui/fitCommands/calc/fitToggleBooster.py b/gui/fitCommands/calc/fitToggleBooster.py new file mode 100644 index 000000000..504ab114a --- /dev/null +++ b/gui/fitCommands/calc/fitToggleBooster.py @@ -0,0 +1,32 @@ +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 FitToggleBoosterCommand(wx.Command): + """" + from sFit.toggleBooster + """ + def __init__(self, fitID, position): + wx.Command.__init__(self, True, "Cargo add") + self.fitID = fitID + self.position = position + + def Do(self): + pyfalog.debug("Toggling booster for fit ID: {0}", self.fitID) + fit = eos.db.getFit(self.fitID) + booster = fit.boosters[self.position] + booster.active = not booster.active + + eos.db.commit() + return True + + def Undo(self): + cmd = FitToggleBoosterCommand(self.fitID, self.position) + return cmd.Do() diff --git a/gui/fitCommands/calc/fitToggleFighter.py b/gui/fitCommands/calc/fitToggleFighter.py new file mode 100644 index 000000000..d0e2a325c --- /dev/null +++ b/gui/fitCommands/calc/fitToggleFighter.py @@ -0,0 +1,33 @@ +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__) +from eos.saveddata.implant import Implant + +class FitToggleFighterCommand(wx.Command): + """" + from sFit.toggleFighter + """ + def __init__(self, fitID, position): + wx.Command.__init__(self, True, "Cargo add") + self.fitID = fitID + self.position = position + + def Do(self): + pyfalog.debug("Toggling fighters for fit ID: {0}", self.fitID) + fit = eos.db.getFit(self.fitID) + f = fit.fighters[self.position] + f.active = not f.active + + eos.db.commit() + return True + + def Undo(self): + cmd = FitToggleFighterCommand(self.fitID, self.position) + return cmd.Do() diff --git a/gui/fitCommands/calc/fitToggleImplant.py b/gui/fitCommands/calc/fitToggleImplant.py new file mode 100644 index 000000000..a44b5f293 --- /dev/null +++ b/gui/fitCommands/calc/fitToggleImplant.py @@ -0,0 +1,33 @@ +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__) +from eos.saveddata.implant import Implant + +class FitToggleImplantCommand(wx.Command): + """" + from sFit.toggleImplant + """ + def __init__(self, fitID, position): + wx.Command.__init__(self, True, "Cargo add") + self.fitID = fitID + self.position = position + + def Do(self): + pyfalog.debug("Toggling implant for fit ID: {0}", self.fitID) + fit = eos.db.getFit(self.fitID) + implant = fit.implants[self.position] + implant.active = not implant.active + + eos.db.commit() + return True + + def Undo(self): + cmd = FitToggleImplantCommand(self.fitID, self.position) + return cmd.Do() diff --git a/gui/fitCommands/guiMetaSwap.py b/gui/fitCommands/guiMetaSwap.py index e40906070..e5f3848a5 100644 --- a/gui/fitCommands/guiMetaSwap.py +++ b/gui/fitCommands/guiMetaSwap.py @@ -13,6 +13,7 @@ from .calc.fitReplaceModule import FitReplaceModuleCommand from .calc.fitAddFighter import FitAddFighterCommand from .calc.fitRemoveFighter import FitRemoveFighterCommand + class GuiMetaSwapCommand(wx.Command): def __init__(self, fitID, context, itemID, selection: list): wx.Command.__init__(self, True, "Meta Swap") diff --git a/gui/fitCommands/guiToggleBooster.py b/gui/fitCommands/guiToggleBooster.py new file mode 100644 index 000000000..7d5016dc5 --- /dev/null +++ b/gui/fitCommands/guiToggleBooster.py @@ -0,0 +1,30 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from .calc.fitToggleBooster import FitToggleBoosterCommand + +class GuiToggleImplantCommand(wx.Command): + def __init__(self, fitID, position): + wx.Command.__init__(self, True, "") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() + self.fitID = fitID + self.position = position + + def Do(self): + if self.internal_history.Submit(FitToggleBoosterCommand(self.fitID, self.position)): + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for _ in self.internal_history.Commands: + self.internal_history.Undo() + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + diff --git a/gui/fitCommands/guiToggleFighter.py b/gui/fitCommands/guiToggleFighter.py new file mode 100644 index 000000000..eee3c945e --- /dev/null +++ b/gui/fitCommands/guiToggleFighter.py @@ -0,0 +1,30 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from .calc.fitToggleFighter import FitToggleFighterCommand + +class GuiToggleFighterCommand(wx.Command): + def __init__(self, fitID, position): + wx.Command.__init__(self, True, "") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() + self.fitID = fitID + self.position = position + + def Do(self): + if self.internal_history.Submit(FitToggleFighterCommand(self.fitID, self.position)): + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for _ in self.internal_history.Commands: + self.internal_history.Undo() + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + diff --git a/gui/fitCommands/guiToggleImplant.py b/gui/fitCommands/guiToggleImplant.py new file mode 100644 index 000000000..e7ae24669 --- /dev/null +++ b/gui/fitCommands/guiToggleImplant.py @@ -0,0 +1,30 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from .calc.fitToggleImplant import FitToggleImplantCommand + +class GuiToggleImplantCommand(wx.Command): + def __init__(self, fitID, position): + wx.Command.__init__(self, True, "") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() + self.fitID = fitID + self.position = position + + def Do(self): + if self.internal_history.Submit(FitToggleImplantCommand(self.fitID, self.position)): + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for _ in self.internal_history.Commands: + self.internal_history.Undo() + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + diff --git a/service/fit.py b/service/fit.py index c7cb70fd1..7dbda941b 100644 --- a/service/fit.py +++ b/service/fit.py @@ -1022,6 +1022,7 @@ class Fit(object): self.recalc(fit) return True + @deprecated def toggleFighter(self, fitID, i): pyfalog.debug("Toggling fighters for fit ID: {0}", fitID) fit = eos.db.getFit(fitID) @@ -1032,6 +1033,7 @@ class Fit(object): self.recalc(fit) return True + @deprecated def toggleImplant(self, fitID, i): pyfalog.debug("Toggling implant for fit ID: {0}", fitID) fit = eos.db.getFit(fitID) @@ -1066,6 +1068,7 @@ class Fit(object): self.recalc(fit) return True + @deprecated def toggleBooster(self, fitID, i): pyfalog.debug("Toggling booster for fit ID: {0}", fitID) fit = eos.db.getFit(fitID) From eeb2b019c0b07f7ed369b01c66adc423f9bbe8e0 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Tue, 14 Aug 2018 01:26:17 -0400 Subject: [PATCH 47/95] Remove the crap from meta swap that was already reimplemented, leaving only drones as a reminder on what needs to be done --- gui/builtinContextMenus/metaSwap.py | 53 +---------------------------- 1 file changed, 1 insertion(+), 52 deletions(-) diff --git a/gui/builtinContextMenus/metaSwap.py b/gui/builtinContextMenus/metaSwap.py index bd98c6bfa..1c4be8017 100644 --- a/gui/builtinContextMenus/metaSwap.py +++ b/gui/builtinContextMenus/metaSwap.py @@ -138,13 +138,7 @@ class MetaSwap(ContextMenu): self.mainFrame.command.Submit(cmd.GuiMetaSwapCommand(fitID, context, item.ID, self.selection)) # for selected_item in self.selection: - # if isinstance(selected_item, Module): - # pos = fit.modules.index(selected_item) - # self.mainFrame.command.Submit(cmd.GuiModuleAddCommand(fitID, item.ID, pos)) - # - # - # sFit.changeModule(fitID, pos, item.ID) - # wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + # # elif isinstance(selected_item, Drone): # drone_count = None @@ -157,51 +151,6 @@ class MetaSwap(ContextMenu): # # if drone_count: # sFit.addDrone(fitID, item.ID, drone_count, True) - # wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) - # - # elif isinstance(selected_item, Fighter): - # fighter_count = None - # - # for idx, fighter_stack in enumerate(fit.fighters): - # # Right now fighters always will have max stack size. - # # Including this for future improvement, so if adjustable - # # fighter stacks get added we're ready for it. - # if fighter_stack is selected_item: - # if fighter_stack.amount > 0: - # fighter_count = fighter_stack.amount - # elif fighter_stack.amount == -1: - # fighter_count = fighter_stack.amountActive - # else: - # fighter_count.amount = 0 - # - # sFit.removeFighter(fitID, idx, False) - # break - # - # sFit.addFighter(fitID, item.ID, True) - # wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) - # - # elif isinstance(selected_item, Booster): - # for idx, booster_stack in enumerate(fit.boosters): - # if booster_stack is selected_item: - # self.mainFrame.command.Submit(cmd.GuiRemoveBoosterCommand(fitID, idx)) - # self.mainFrame.command.Submit(cmd.GuiAddBoosterCommand(fitID, item.ID)) - # break - # - # elif isinstance(selected_item, Implant): - # for idx, implant_stack in enumerate(fit.implants): - # if implant_stack is selected_item: - # self.mainFrame.command.Submit(cmd.GuiRemoveImplantCommand(fitID, idx)) - # self.mainFrame.command.Submit(cmd.GuiAddImplantCommand(fitID, item.ID)) - # break - # - # elif isinstance(selected_item, Cargo): - # for idx, cargo_stack in enumerate(fit.cargo): - # if cargo_stack is selected_item: - # # todo: make a command to change varieance of all items, or maybe per item type, which would - # # utilize the two fitting commands that we need to remove then add? - # sFit.removeCargo(fitID, idx) - # self.mainFrame.command.Submit(cmd.GuiAddCargoCommand(fitID, item.ID, cargo_stack.amount, True)) - # break From 3d4b41d1351eabb4b9a479ebec5ef97fc8009d00 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Tue, 14 Aug 2018 01:31:59 -0400 Subject: [PATCH 48/95] Move deprecated methods to a base class - will remove this eventually, want to keep Fit clean --- service/fit.py | 577 +------------------------------------ service/fitDeprecated.py | 607 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 610 insertions(+), 574 deletions(-) create mode 100644 service/fitDeprecated.py diff --git a/service/fit.py b/service/fit.py index 7dbda941b..0807ba8a8 100644 --- a/service/fit.py +++ b/service/fit.py @@ -37,11 +37,11 @@ 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 import wx pyfalog = Logger(__name__) +from service.fitDeprecated import FitDeprecated class DeferRecalc(): def __init__(self, fitID): @@ -57,7 +57,8 @@ class DeferRecalc(): self.sFit.recalc(self.fitID) -class Fit(object): +# inherits from FitDeprecated so that I can move all the dead shit, but not affect functionality +class Fit(FitDeprecated): instance = None processors = {} @@ -192,7 +193,6 @@ class Fit(object): eos.db.commit() return old_name, newName - @staticmethod def deleteFit(fitID): fit = eos.db.getFit(fitID) @@ -345,148 +345,6 @@ class Fit(object): fit.notes)) return fits - @deprecated - def addImplant(self, fitID, itemID, recalc=True): - pyfalog.debug("Adding implant to fit ({0}) for item ID: {1}", fitID, itemID) - if fitID is None: - return False - - fit = eos.db.getFit(fitID) - item = eos.db.getItem(itemID, eager="attributes") - try: - implant = es_Implant(item) - except ValueError: - pyfalog.warning("Invalid item: {0}", itemID) - return False - - fit.implants.append(implant) - if recalc: - self.recalc(fit) - return True - - @deprecated - def removeImplant(self, fitID, position, recalc=True): - pyfalog.debug("Removing implant from position ({0}) for fit ID: {1}", position, fitID) - if fitID is None: - return False - - fit = eos.db.getFit(fitID) - implant = fit.implants[position] - fit.implants.remove(implant) - if recalc: - self.recalc(fit) - return True - - @deprecated - def addBooster(self, fitID, itemID, recalc=True): - pyfalog.debug("Adding booster ({0}) to fit ID: {1}", itemID, fitID) - if fitID is None: - return False - - fit = eos.db.getFit(fitID) - item = eos.db.getItem(itemID, eager="attributes") - try: - booster = es_Booster(item) - except ValueError: - pyfalog.warning("Invalid item: {0}", itemID) - return False - - fit.boosters.append(booster) - if recalc: - self.recalc(fit) - return True - - @deprecated - def removeBooster(self, fitID, position, recalc=True): - pyfalog.debug("Removing booster from position ({0}) for fit ID: {1}", position, fitID) - if fitID is None: - return False - - fit = eos.db.getFit(fitID) - booster = fit.boosters[position] - fit.boosters.remove(booster) - if recalc: - self.recalc(fit) - return True - - @deprecated - def project(self, fitID, thing): - pyfalog.debug("Projecting fit ({0}) onto: {1}", fitID, thing) - if fitID is None: - return - - fit = eos.db.getFit(fitID) - - if isinstance(thing, int): - thing = eos.db.getItem(thing, - eager=("attributes", "group.category")) - - if isinstance(thing, es_Module): - thing = copy.deepcopy(thing) - fit.projectedModules.append(thing) - elif isinstance(thing, FitType): - if thing in fit.projectedFits: - return - - fit.projectedFitDict[thing.ID] = thing - - # this bit is required -- see GH issue # 83 - eos.db.saveddata_session.flush() - eos.db.saveddata_session.refresh(thing) - elif thing.category.name == "Drone": - drone = None - for d in fit.projectedDrones.find(thing): - if d is None or d.amountActive == d.amount or d.amount >= 5: - drone = d - break - - if drone is None: - drone = es_Drone(thing) - fit.projectedDrones.append(drone) - - drone.amount += 1 - elif thing.category.name == "Fighter": - fighter = es_Fighter(thing) - fit.projectedFighters.append(fighter) - elif thing.group.name in es_Module.SYSTEM_GROUPS: - module = es_Module(thing) - module.state = State.ONLINE - fit.projectedModules.append(module) - else: - try: - module = es_Module(thing) - except ValueError: - return False - module.state = State.ACTIVE - if not module.canHaveState(module.state, fit): - module.state = State.OFFLINE - fit.projectedModules.append(module) - - eos.db.commit() - self.recalc(fit) - return True - - @deprecated - def addCommandFit(self, fitID, thing): - pyfalog.debug("Projecting command fit ({0}) onto: {1}", fitID, thing) - if fitID is None: - return - - fit = eos.db.getFit(fitID) - - if thing in fit.commandFits: - return - - fit.commandFitDict[thing.ID] = thing - - # this bit is required -- see GH issue # 83 - eos.db.saveddata_session.flush() - eos.db.saveddata_session.refresh(thing) - - eos.db.commit() - self.recalc(fit) - return True - def toggleProjected(self, fitID, thing, click): pyfalog.debug("Toggling projected on fit ({0}) for: {1}", fitID, thing) fit = eos.db.getFit(fitID) @@ -509,16 +367,6 @@ class Fit(object): eos.db.commit() self.recalc(fit) - @deprecated - def toggleCommandFit(self, fitID, thing): - pyfalog.debug("Toggle command fit ({0}) for: {1}", fitID, thing) - fit = eos.db.getFit(fitID) - commandInfo = thing.getCommandInfo(fitID) - if commandInfo: - commandInfo.active = not commandInfo.active - - eos.db.commit() - self.recalc(fit) def changeAmount(self, fitID, projected_fit, amount): """Change amount of projected fits""" @@ -540,31 +388,6 @@ class Fit(object): eos.db.commit() self.recalc(fit) - @deprecated - def removeProjected(self, fitID, thing): - pyfalog.debug("Removing projection on fit ({0}) from: {1}", fitID, thing) - fit = eos.db.getFit(fitID) - if isinstance(thing, es_Drone): - fit.projectedDrones.remove(thing) - elif isinstance(thing, es_Module): - fit.projectedModules.remove(thing) - elif isinstance(thing, es_Fighter): - fit.projectedFighters.remove(thing) - else: - del fit.projectedFitDict[thing.ID] - # fit.projectedFits.remove(thing) - - eos.db.commit() - self.recalc(fit) - - @deprecated - def removeCommand(self, fitID, thing): - pyfalog.debug("Removing command projection from fit ({0}) for: {1}", fitID, thing) - fit = eos.db.getFit(fitID) - del fit.commandFitDict[thing.ID] - - eos.db.commit() - self.recalc(fit) def changeMutatedValue(self, mutator, value): pyfalog.debug("Changing mutated value for {} / {}: {} => {}".format(mutator.module, mutator.module.mutaplasmid, mutator.value, value)) @@ -573,66 +396,6 @@ 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) - item = eos.db.getItem(itemID, eager=("attributes", "group.category")) - try: - m = es_Module(item) - except ValueError: - pyfalog.warning("Invalid item: {0}", itemID) - return False - - if m.item.category.name == "Subsystem": - fit.modules.freeSlot(m.getModifiedItemAttr("subSystemSlot")) - - if m.fits(fit): - m.owner = fit - numSlots = len(fit.modules) - fit.modules.append(m) - if m.isValidState(State.ACTIVE): - m.state = State.ACTIVE - - # 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() - - return numSlots != len(fit.modules), m.modPosition - 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) - fit = eos.db.getFit(fitID) - - # Convert scalar value to list - if not isinstance(positions, list): - positions = [positions] - - modulesChanged = False - for x in positions: - if not fit.modules[x].isEmpty: - fit.modules.toDummy(x) - modulesChanged = True - - # if no modules have changes, report back None - if not modulesChanged: - return None - - numSlots = len(fit.modules) - self.recalc(fit) - self.checkStates(fit, None) - fit.fill() - eos.db.commit() - return numSlots != len(fit.modules) - def convertMutaplasmid(self, fitID, position, mutaplasmid): # this is mostly the same thing as the self.changeModule method, however it initializes an abyssal module with # the old module as it's base, and then replaces it @@ -664,251 +427,6 @@ class Fit(object): else: return None - @deprecated - def changeModule(self, fitID, position, newItemID, recalc=True): - 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. - if self.isAmmo(newItemID): - module = fit.modules[position] - if not module.isEmpty: - self.setAmmo(fitID, newItemID, [module]) - return True - - pyfalog.debug("Changing position of module from position ({0}) for fit ID: {1}", position, fitID) - - item = eos.db.getItem(newItemID, eager=("attributes", "group.category")) - - # Dummy it out in case the next bit fails - fit.modules.toDummy(position) - - try: - m = es_Module(item) - except ValueError: - pyfalog.warning("Invalid item: {0}", newItemID) - return False - - if m.fits(fit): - m.owner = fit - fit.modules.toModule(position, m) - if m.isValidState(State.ACTIVE): - m.state = State.ACTIVE - - if (recalc): - # 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() - - return m - else: - return None - - @deprecated - def moveCargoToModule(self, fitID, moduleIdx, cargoIdx, copyMod=False): - """ - Moves cargo to fitting window. Can either do a copy, move, or swap with current module - If we try to copy/move into a spot with a non-empty module, we swap instead. - To avoid redundancy in converting Cargo item, this function does the - sanity checks as opposed to the GUI View. This is different than how the - normal .swapModules() does things, which is mostly a blind swap. - """ - - fit = eos.db.getFit(fitID) - module = fit.modules[moduleIdx] - cargo = fit.cargo[cargoIdx] - - # We're trying to move a charge from cargo to a slot - try to add charge to dst module. Don't do anything with - # the charge in the cargo (don't respect move vs copy) - if self.isAmmo(cargo.item.ID): - if not module.isEmpty: - self.setAmmo(fitID, cargo.item.ID, [module]) - return - - pyfalog.debug("Moving cargo item to module for fit ID: {0}", fitID) - - # Gather modules and convert Cargo item to Module, silently return if not a module - try: - cargoP = es_Module(cargo.item) - cargoP.owner = fit - if cargoP.isValidState(State.ACTIVE): - cargoP.state = State.ACTIVE - except: - pyfalog.warning("Invalid item: {0}", cargo.item) - return - - if cargoP.slot != module.slot: # can't swap modules to different racks - return - - # remove module that we are trying to move cargo to - fit.modules.remove(module) - - if not cargoP.fits(fit): # if cargo doesn't fit, rollback and return - fit.modules.insert(moduleIdx, module) - return - - fit.modules.insert(moduleIdx, cargoP) - - if not copyMod: # remove existing cargo if not cloning - if cargo.amount == 1: - fit.cargo.remove(cargo) - else: - cargo.amount -= 1 - - if not module.isEmpty: # if module is placeholder, we don't want to convert/add it - moduleItem = module.item if not module.item.isAbyssal else module.baseItem - for x in fit.cargo.find(moduleItem): - x.amount += 1 - break - else: - moduleP = es_Cargo(moduleItem) - moduleP.amount = 1 - fit.cargo.insert(cargoIdx, moduleP) - - eos.db.commit() - self.recalc(fit) - - @staticmethod - @deprecated - def swapModules(fitID, src, dst): - pyfalog.debug("Swapping modules from source ({0}) to destination ({1}) for fit ID: {1}", src, dst, fitID) - fit = eos.db.getFit(fitID) - # Gather modules - srcMod = fit.modules[src] - dstMod = fit.modules[dst] - - # To swap, we simply remove mod and insert at destination. - fit.modules.remove(srcMod) - fit.modules.insert(dst, srcMod) - fit.modules.remove(dstMod) - fit.modules.insert(src, dstMod) - - eos.db.commit() - - @deprecated - def cloneModule(self, fitID, src, dst): - """ - Clone a module from src to dst - This will overwrite dst! Checking for empty module must be - done at a higher level - """ - pyfalog.debug("Cloning modules from source ({0}) to destination ({1}) for fit ID: {1}", src, dst, fitID) - fit = eos.db.getFit(fitID) - # Gather modules - srcMod = fit.modules[src] - dstMod = fit.modules[dst] # should be a placeholder module - - new = copy.deepcopy(srcMod) - new.owner = fit - if new.fits(fit): - # insert copy if module meets hardpoint restrictions - fit.modules.remove(dstMod) - fit.modules.insert(dst, new) - - eos.db.commit() - self.recalc(fit) - - @deprecated - def addCargo(self, fitID, itemID, amount=1, replace=False): - """ - Adds cargo via typeID of item. If replace = True, we replace amount with - given parameter, otherwise we increment - """ - pyfalog.debug("Adding cargo ({0}) fit ID: {1}", itemID, fitID) - - if fitID is None: - return False - - fit = eos.db.getFit(fitID) - item = eos.db.getItem(itemID) - cargo = None - - # adding from market - for x in fit.cargo.find(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 = es_Cargo(item) - - fit.cargo.append(cargo) - if replace: - cargo.amount = amount - else: - cargo.amount += amount - - self.recalc(fit) - eos.db.commit() - - return True - - @deprecated - def removeCargo(self, fitID, position): - pyfalog.debug("Removing cargo from position ({0}) fit ID: {1}", position, fitID) - if fitID is None: - return False - - fit = eos.db.getFit(fitID) - charge = fit.cargo[position] - fit.cargo.remove(charge) - self.recalc(fit) - return True - - @deprecated - def addFighter(self, fitID, itemID, recalc=True): - pyfalog.debug("Adding fighters ({0}) to fit ID: {1}", itemID, fitID) - if fitID is None: - return False - - fit = eos.db.getFit(fitID) - item = eos.db.getItem(itemID, eager=("attributes", "group.category")) - if item.category.name == "Fighter": - fighter = None - ''' - for d in fit.fighters.find(item): - if d is not None and d.amountActive == 0 and d.amount < max(5, fit.extraAttributes["maxActiveDrones"]): - drone = d - break - ''' - if fighter is None: - fighter = es_Fighter(item) - used = fit.getSlotsUsed(fighter.slot) - total = fit.getNumSlots(fighter.slot) - - if used >= total: - fighter.active = False - - if fighter.fits(fit) is True: - fit.fighters.append(fighter) - else: - return False - - eos.db.commit() - if recalc: - self.recalc(fit) - return True - else: - return False - - @deprecated - def removeFighter(self, fitID, i, recalc=True): - pyfalog.debug("Removing fighters from fit ID: {0}", fitID) - fit = eos.db.getFit(fitID) - f = fit.fighters[i] - fit.fighters.remove(f) - - eos.db.commit() - if recalc: - self.recalc(fit) - return True - def addDrone(self, fitID, itemID, numDronesToAdd=1, recalc=True): pyfalog.debug("Adding {0} drones ({1}) to fit ID: {2}", numDronesToAdd, itemID, fitID) if fitID is None: @@ -1022,28 +540,6 @@ class Fit(object): self.recalc(fit) return True - @deprecated - def toggleFighter(self, fitID, i): - pyfalog.debug("Toggling fighters for fit ID: {0}", fitID) - fit = eos.db.getFit(fitID) - f = fit.fighters[i] - f.active = not f.active - - eos.db.commit() - self.recalc(fit) - return True - - @deprecated - def toggleImplant(self, fitID, i): - pyfalog.debug("Toggling implant for fit ID: {0}", fitID) - fit = eos.db.getFit(fitID) - implant = fit.implants[i] - implant.active = not implant.active - - eos.db.commit() - self.recalc(fit) - return True - def toggleImplantSource(self, fitID, source): pyfalog.debug("Toggling implant source for fit ID: {0}", fitID) fit = eos.db.getFit(fitID) @@ -1068,17 +564,6 @@ class Fit(object): self.recalc(fit) return True - @deprecated - def toggleBooster(self, fitID, i): - pyfalog.debug("Toggling booster for fit ID: {0}", fitID) - fit = eos.db.getFit(fitID) - booster = fit.boosters[i] - booster.active = not booster.active - - eos.db.commit() - self.recalc(fit) - return True - def toggleFighterAbility(self, fitID, ability): pyfalog.debug("Toggling fighter ability for fit ID: {0}", fitID) fit = eos.db.getFit(fitID) @@ -1110,22 +595,6 @@ class Fit(object): # todo: get rid of this form the service, use directly from item return eos.db.getItem(itemID).isCharge - @deprecated - def setAmmo(self, fitID, ammoID, modules, recalc=True): - pyfalog.debug("Set ammo for fit ID: {0}", fitID) - if fitID is None: - return - - fit = eos.db.getFit(fitID) - ammo = eos.db.getItem(ammoID) if ammoID else None - - for mod in modules: - if mod.isValidCharge(ammo): - mod.charge = ammo - - if recalc: - self.recalc(fit) - @staticmethod def getTargetResists(fitID): pyfalog.debug("Get target resists for fit ID: {0}", fitID) @@ -1166,18 +635,6 @@ class Fit(object): self.recalc(fit) - @deprecated - def setMode(self, fitID, mode): - pyfalog.debug("Set mode for fit ID: {0}", fitID) - if fitID is None: - return - - fit = eos.db.getFit(fitID) - fit.mode = mode - eos.db.commit() - - self.recalc(fit) - def setAsPattern(self, fitID, ammo): pyfalog.debug("Set as pattern for fit ID: {0}", fitID) if fitID is None: @@ -1221,34 +678,6 @@ class Fit(object): if changed: self.recalc(fit) - @deprecated - def toggleModulesState(self, fitID, base, modules, click): - pyfalog.debug("Toggle module state for fit ID: {0}", fitID) - changed = False - proposedState = es_Module.getProposedState(base, click) - - if proposedState != base.state: - changed = True - base.state = proposedState - for mod in modules: - if mod != base: - p = es_Module.getProposedState(mod, click, proposedState) - mod.state = p - if p != mod.state: - changed = True - - if changed: - eos.db.commit() - fit = eos.db.getFit(fitID) - - # 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, base) - - - - def refreshFit(self, fitID): pyfalog.debug("Refresh fit for fit ID: {0}", fitID) if fitID is None: diff --git a/service/fitDeprecated.py b/service/fitDeprecated.py new file mode 100644 index 000000000..8bc522217 --- /dev/null +++ b/service/fitDeprecated.py @@ -0,0 +1,607 @@ +# =============================================================================== +# 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 . +# =============================================================================== + +import copy +from logbook import Logger + +import eos.db +from eos.saveddata.booster import Booster as es_Booster +from eos.saveddata.cargo import Cargo as es_Cargo + +from eos.saveddata.drone import Drone as es_Drone +from eos.saveddata.fighter import Fighter as es_Fighter +from eos.saveddata.implant import Implant as es_Implant +from eos.saveddata.module import Module as es_Module, State +from eos.saveddata.fit import Fit as FitType +from utils.deprecated import deprecated + +pyfalog = Logger(__name__) + + +class FitDeprecated(object): + + @deprecated + def addImplant(self, fitID, itemID, recalc=True): + pyfalog.debug("Adding implant to fit ({0}) for item ID: {1}", fitID, itemID) + if fitID is None: + return False + + fit = eos.db.getFit(fitID) + item = eos.db.getItem(itemID, eager="attributes") + try: + implant = es_Implant(item) + except ValueError: + pyfalog.warning("Invalid item: {0}", itemID) + return False + + fit.implants.append(implant) + if recalc: + self.recalc(fit) + return True + + @deprecated + def removeImplant(self, fitID, position, recalc=True): + pyfalog.debug("Removing implant from position ({0}) for fit ID: {1}", position, fitID) + if fitID is None: + return False + + fit = eos.db.getFit(fitID) + implant = fit.implants[position] + fit.implants.remove(implant) + if recalc: + self.recalc(fit) + return True + + @deprecated + def addBooster(self, fitID, itemID, recalc=True): + pyfalog.debug("Adding booster ({0}) to fit ID: {1}", itemID, fitID) + if fitID is None: + return False + + fit = eos.db.getFit(fitID) + item = eos.db.getItem(itemID, eager="attributes") + try: + booster = es_Booster(item) + except ValueError: + pyfalog.warning("Invalid item: {0}", itemID) + return False + + fit.boosters.append(booster) + if recalc: + self.recalc(fit) + return True + + @deprecated + def removeBooster(self, fitID, position, recalc=True): + pyfalog.debug("Removing booster from position ({0}) for fit ID: {1}", position, fitID) + if fitID is None: + return False + + fit = eos.db.getFit(fitID) + booster = fit.boosters[position] + fit.boosters.remove(booster) + if recalc: + self.recalc(fit) + return True + + @deprecated + def project(self, fitID, thing): + pyfalog.debug("Projecting fit ({0}) onto: {1}", fitID, thing) + if fitID is None: + return + + fit = eos.db.getFit(fitID) + + if isinstance(thing, int): + thing = eos.db.getItem(thing, + eager=("attributes", "group.category")) + + if isinstance(thing, es_Module): + thing = copy.deepcopy(thing) + fit.projectedModules.append(thing) + elif isinstance(thing, FitType): + if thing in fit.projectedFits: + return + + fit.projectedFitDict[thing.ID] = thing + + # this bit is required -- see GH issue # 83 + eos.db.saveddata_session.flush() + eos.db.saveddata_session.refresh(thing) + elif thing.category.name == "Drone": + drone = None + for d in fit.projectedDrones.find(thing): + if d is None or d.amountActive == d.amount or d.amount >= 5: + drone = d + break + + if drone is None: + drone = es_Drone(thing) + fit.projectedDrones.append(drone) + + drone.amount += 1 + elif thing.category.name == "Fighter": + fighter = es_Fighter(thing) + fit.projectedFighters.append(fighter) + elif thing.group.name in es_Module.SYSTEM_GROUPS: + module = es_Module(thing) + module.state = State.ONLINE + fit.projectedModules.append(module) + else: + try: + module = es_Module(thing) + except ValueError: + return False + module.state = State.ACTIVE + if not module.canHaveState(module.state, fit): + module.state = State.OFFLINE + fit.projectedModules.append(module) + + eos.db.commit() + self.recalc(fit) + return True + + @deprecated + def addCommandFit(self, fitID, thing): + pyfalog.debug("Projecting command fit ({0}) onto: {1}", fitID, thing) + if fitID is None: + return + + fit = eos.db.getFit(fitID) + + if thing in fit.commandFits: + return + + fit.commandFitDict[thing.ID] = thing + + # this bit is required -- see GH issue # 83 + eos.db.saveddata_session.flush() + eos.db.saveddata_session.refresh(thing) + + eos.db.commit() + self.recalc(fit) + return True + + @deprecated + def toggleCommandFit(self, fitID, thing): + pyfalog.debug("Toggle command fit ({0}) for: {1}", fitID, thing) + fit = eos.db.getFit(fitID) + commandInfo = thing.getCommandInfo(fitID) + if commandInfo: + commandInfo.active = not commandInfo.active + + eos.db.commit() + self.recalc(fit) + + @deprecated + def removeProjected(self, fitID, thing): + pyfalog.debug("Removing projection on fit ({0}) from: {1}", fitID, thing) + fit = eos.db.getFit(fitID) + if isinstance(thing, es_Drone): + fit.projectedDrones.remove(thing) + elif isinstance(thing, es_Module): + fit.projectedModules.remove(thing) + elif isinstance(thing, es_Fighter): + fit.projectedFighters.remove(thing) + else: + del fit.projectedFitDict[thing.ID] + # fit.projectedFits.remove(thing) + + eos.db.commit() + self.recalc(fit) + + @deprecated + def removeCommand(self, fitID, thing): + pyfalog.debug("Removing command projection from fit ({0}) for: {1}", fitID, thing) + fit = eos.db.getFit(fitID) + del fit.commandFitDict[thing.ID] + + eos.db.commit() + self.recalc(fit) + + @deprecated + def appendModule(self, fitID, 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: + m = es_Module(item) + except ValueError: + pyfalog.warning("Invalid item: {0}", itemID) + return False + + if m.item.category.name == "Subsystem": + fit.modules.freeSlot(m.getModifiedItemAttr("subSystemSlot")) + + if m.fits(fit): + m.owner = fit + numSlots = len(fit.modules) + fit.modules.append(m) + if m.isValidState(State.ACTIVE): + m.state = State.ACTIVE + + # 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() + + return numSlots != len(fit.modules), m.modPosition + 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) + fit = eos.db.getFit(fitID) + + # Convert scalar value to list + if not isinstance(positions, list): + positions = [positions] + + modulesChanged = False + for x in positions: + if not fit.modules[x].isEmpty: + fit.modules.toDummy(x) + modulesChanged = True + + # if no modules have changes, report back None + if not modulesChanged: + return None + + numSlots = len(fit.modules) + self.recalc(fit) + self.checkStates(fit, None) + fit.fill() + eos.db.commit() + return numSlots != len(fit.modules) + + @deprecated + def changeModule(self, fitID, position, newItemID, recalc=True): + 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. + if self.isAmmo(newItemID): + module = fit.modules[position] + if not module.isEmpty: + self.setAmmo(fitID, newItemID, [module]) + return True + + pyfalog.debug("Changing position of module from position ({0}) for fit ID: {1}", position, fitID) + + item = eos.db.getItem(newItemID, eager=("attributes", "group.category")) + + # Dummy it out in case the next bit fails + fit.modules.toDummy(position) + + try: + m = es_Module(item) + except ValueError: + pyfalog.warning("Invalid item: {0}", newItemID) + return False + + if m.fits(fit): + m.owner = fit + fit.modules.toModule(position, m) + if m.isValidState(State.ACTIVE): + m.state = State.ACTIVE + + if (recalc): + # 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() + + return m + else: + return None + + @deprecated + def moveCargoToModule(self, fitID, moduleIdx, cargoIdx, copyMod=False): + """ + Moves cargo to fitting window. Can either do a copy, move, or swap with current module + If we try to copy/move into a spot with a non-empty module, we swap instead. + To avoid redundancy in converting Cargo item, this function does the + sanity checks as opposed to the GUI View. This is different than how the + normal .swapModules() does things, which is mostly a blind swap. + """ + + fit = eos.db.getFit(fitID) + module = fit.modules[moduleIdx] + cargo = fit.cargo[cargoIdx] + + # We're trying to move a charge from cargo to a slot - try to add charge to dst module. Don't do anything with + # the charge in the cargo (don't respect move vs copy) + if self.isAmmo(cargo.item.ID): + if not module.isEmpty: + self.setAmmo(fitID, cargo.item.ID, [module]) + return + + pyfalog.debug("Moving cargo item to module for fit ID: {0}", fitID) + + # Gather modules and convert Cargo item to Module, silently return if not a module + try: + cargoP = es_Module(cargo.item) + cargoP.owner = fit + if cargoP.isValidState(State.ACTIVE): + cargoP.state = State.ACTIVE + except: + pyfalog.warning("Invalid item: {0}", cargo.item) + return + + if cargoP.slot != module.slot: # can't swap modules to different racks + return + + # remove module that we are trying to move cargo to + fit.modules.remove(module) + + if not cargoP.fits(fit): # if cargo doesn't fit, rollback and return + fit.modules.insert(moduleIdx, module) + return + + fit.modules.insert(moduleIdx, cargoP) + + if not copyMod: # remove existing cargo if not cloning + if cargo.amount == 1: + fit.cargo.remove(cargo) + else: + cargo.amount -= 1 + + if not module.isEmpty: # if module is placeholder, we don't want to convert/add it + moduleItem = module.item if not module.item.isAbyssal else module.baseItem + for x in fit.cargo.find(moduleItem): + x.amount += 1 + break + else: + moduleP = es_Cargo(moduleItem) + moduleP.amount = 1 + fit.cargo.insert(cargoIdx, moduleP) + + eos.db.commit() + self.recalc(fit) + + @staticmethod + @deprecated + def swapModules(fitID, src, dst): + pyfalog.debug("Swapping modules from source ({0}) to destination ({1}) for fit ID: {1}", src, dst, fitID) + fit = eos.db.getFit(fitID) + # Gather modules + srcMod = fit.modules[src] + dstMod = fit.modules[dst] + + # To swap, we simply remove mod and insert at destination. + fit.modules.remove(srcMod) + fit.modules.insert(dst, srcMod) + fit.modules.remove(dstMod) + fit.modules.insert(src, dstMod) + + eos.db.commit() + + @deprecated + def cloneModule(self, fitID, src, dst): + """ + Clone a module from src to dst + This will overwrite dst! Checking for empty module must be + done at a higher level + """ + pyfalog.debug("Cloning modules from source ({0}) to destination ({1}) for fit ID: {1}", src, dst, fitID) + fit = eos.db.getFit(fitID) + # Gather modules + srcMod = fit.modules[src] + dstMod = fit.modules[dst] # should be a placeholder module + + new = copy.deepcopy(srcMod) + new.owner = fit + if new.fits(fit): + # insert copy if module meets hardpoint restrictions + fit.modules.remove(dstMod) + fit.modules.insert(dst, new) + + eos.db.commit() + self.recalc(fit) + + @deprecated + def addCargo(self, fitID, itemID, amount=1, replace=False): + """ + Adds cargo via typeID of item. If replace = True, we replace amount with + given parameter, otherwise we increment + """ + pyfalog.debug("Adding cargo ({0}) fit ID: {1}", itemID, fitID) + + if fitID is None: + return False + + fit = eos.db.getFit(fitID) + item = eos.db.getItem(itemID) + cargo = None + + # adding from market + for x in fit.cargo.find(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 = es_Cargo(item) + + fit.cargo.append(cargo) + if replace: + cargo.amount = amount + else: + cargo.amount += amount + + self.recalc(fit) + eos.db.commit() + + return True + + @deprecated + def removeCargo(self, fitID, position): + pyfalog.debug("Removing cargo from position ({0}) fit ID: {1}", position, fitID) + if fitID is None: + return False + + fit = eos.db.getFit(fitID) + charge = fit.cargo[position] + fit.cargo.remove(charge) + self.recalc(fit) + return True + + @deprecated + def addFighter(self, fitID, itemID, recalc=True): + pyfalog.debug("Adding fighters ({0}) to fit ID: {1}", itemID, fitID) + if fitID is None: + return False + + fit = eos.db.getFit(fitID) + item = eos.db.getItem(itemID, eager=("attributes", "group.category")) + if item.category.name == "Fighter": + fighter = None + ''' + for d in fit.fighters.find(item): + if d is not None and d.amountActive == 0 and d.amount < max(5, fit.extraAttributes["maxActiveDrones"]): + drone = d + break + ''' + if fighter is None: + fighter = es_Fighter(item) + used = fit.getSlotsUsed(fighter.slot) + total = fit.getNumSlots(fighter.slot) + + if used >= total: + fighter.active = False + + if fighter.fits(fit) is True: + fit.fighters.append(fighter) + else: + return False + + eos.db.commit() + if recalc: + self.recalc(fit) + return True + else: + return False + + @deprecated + def removeFighter(self, fitID, i, recalc=True): + pyfalog.debug("Removing fighters from fit ID: {0}", fitID) + fit = eos.db.getFit(fitID) + f = fit.fighters[i] + fit.fighters.remove(f) + + eos.db.commit() + if recalc: + self.recalc(fit) + return True + + @deprecated + def toggleFighter(self, fitID, i): + pyfalog.debug("Toggling fighters for fit ID: {0}", fitID) + fit = eos.db.getFit(fitID) + f = fit.fighters[i] + f.active = not f.active + + eos.db.commit() + self.recalc(fit) + return True + + @deprecated + def toggleImplant(self, fitID, i): + pyfalog.debug("Toggling implant for fit ID: {0}", fitID) + fit = eos.db.getFit(fitID) + implant = fit.implants[i] + implant.active = not implant.active + + eos.db.commit() + self.recalc(fit) + return True + + @deprecated + def toggleBooster(self, fitID, i): + pyfalog.debug("Toggling booster for fit ID: {0}", fitID) + fit = eos.db.getFit(fitID) + booster = fit.boosters[i] + booster.active = not booster.active + + eos.db.commit() + self.recalc(fit) + return True + + @deprecated + def setAmmo(self, fitID, ammoID, modules, recalc=True): + pyfalog.debug("Set ammo for fit ID: {0}", fitID) + if fitID is None: + return + + fit = eos.db.getFit(fitID) + ammo = eos.db.getItem(ammoID) if ammoID else None + + for mod in modules: + if mod.isValidCharge(ammo): + mod.charge = ammo + + if recalc: + self.recalc(fit) + + @deprecated + def setMode(self, fitID, mode): + pyfalog.debug("Set mode for fit ID: {0}", fitID) + if fitID is None: + return + + fit = eos.db.getFit(fitID) + fit.mode = mode + eos.db.commit() + + self.recalc(fit) + + @deprecated + def toggleModulesState(self, fitID, base, modules, click): + pyfalog.debug("Toggle module state for fit ID: {0}", fitID) + changed = False + proposedState = es_Module.getProposedState(base, click) + + if proposedState != base.state: + changed = True + base.state = proposedState + for mod in modules: + if mod != base: + p = es_Module.getProposedState(mod, click, proposedState) + mod.state = p + if p != mod.state: + changed = True + + if changed: + eos.db.commit() + fit = eos.db.getFit(fitID) + + # 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, base) From bcbed3df39c02c7e9872f914d2b112b86646ad7a Mon Sep 17 00:00:00 2001 From: blitzmann Date: Thu, 16 Aug 2018 00:24:31 -0400 Subject: [PATCH 49/95] Fix an issue which caused pyfa to crash (turns out instantiating the commands in the init was not a good idea) --- gui/devTools.py | 15 +++++++++++++-- gui/fitCommands/guiAddBooster.py | 7 +++---- gui/fitCommands/guiAddCargo.py | 11 ++++++----- gui/fitCommands/guiAddCharge.py | 6 +++--- gui/fitCommands/guiAddCommand.py | 5 ++--- gui/fitCommands/guiAddFighter.py | 4 ++-- gui/fitCommands/guiAddImplant.py | 11 ++++++----- gui/fitCommands/guiCargoToModule.py | 1 + gui/fitCommands/guiMetaSwap.py | 3 +-- gui/fitCommands/guiModuleToCargo.py | 1 + gui/fitCommands/guiRemoveBooster.py | 7 +++---- gui/fitCommands/guiRemoveCargo.py | 9 ++++----- gui/fitCommands/guiRemoveCommand.py | 5 ++--- gui/fitCommands/guiRemoveImplant.py | 9 ++++----- gui/fitCommands/guiRemoveModule.py | 1 - gui/fitCommands/guiSetMode.py | 5 ++--- gui/fitCommands/guiSwapCloneModule.py | 4 ++++ gui/fitCommands/guiToggleCommand.py | 5 ++--- gui/fitCommands/guiToggleModuleState.py | 3 +-- 19 files changed, 60 insertions(+), 52 deletions(-) diff --git a/gui/devTools.py b/gui/devTools.py index 98a14662c..88486431a 100644 --- a/gui/devTools.py +++ b/gui/devTools.py @@ -35,7 +35,7 @@ class DevTools(wx.Dialog): def __init__(self, parent): wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title="Damage Pattern Editor", size=wx.Size(400, 240)) - + self.mainFrame = parent self.block = False self.SetSizeHints(wx.DefaultSize, wx.DefaultSize) @@ -56,13 +56,19 @@ class DevTools(wx.Dialog): self.fitTest = wx.Button(self, wx.ID_ANY, "Test fits", wx.DefaultPosition, wx.DefaultSize, 0) mainSizer.Add(self.fitTest, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5) - self.fitTest .Bind(wx.EVT_BUTTON, self.fit_test) + self.fitTest.Bind(wx.EVT_BUTTON, self.fit_test) + + self.cmdPrint = wx.Button(self, wx.ID_ANY, "Command Print", wx.DefaultPosition, wx.DefaultSize, 0) + mainSizer.Add(self.cmdPrint, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5) + + self.cmdPrint.Bind(wx.EVT_BUTTON, self.cmd_print) self.SetSizer(mainSizer) self.Layout() self.CenterOnParent() self.Show() + print(parent) def objects_by_id(self, evt): input = self.id_get.GetValue() @@ -81,6 +87,11 @@ class DevTools(wx.Dialog): else: print(None) + def cmd_print(self, evt): + print("="*20) + for x in self.mainFrame.command.GetCommands(): + print("{}{} {}".format("==> " if x == self.mainFrame.command.GetCurrentCommand() else "", x.GetName(), x)) + def gc_collect(self, evt): print(gc.collect()) print(gc.get_debug()) diff --git a/gui/fitCommands/guiAddBooster.py b/gui/fitCommands/guiAddBooster.py index 3dc423cf6..fc89209cb 100644 --- a/gui/fitCommands/guiAddBooster.py +++ b/gui/fitCommands/guiAddBooster.py @@ -12,18 +12,17 @@ class GuiAddBoosterCommand(wx.Command): self.sFit = Fit.getInstance() self.internal_history = wx.CommandProcessor() self.fitID = fitID - # can set his up no to not have to set variables on our object - self.cmd = FitAddBoosterCommand(fitID, itemID) + self.itemID = itemID def Do(self): - if self.internal_history.Submit(self.cmd): + if self.internal_history.Submit(FitAddBoosterCommand(self.fitID, self.itemID)): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True return False def Undo(self): - for x in self.internal_history.Commands: + for _ in self.internal_history.Commands: self.internal_history.Undo() self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) diff --git a/gui/fitCommands/guiAddCargo.py b/gui/fitCommands/guiAddCargo.py index db923c7d1..d23af64bb 100644 --- a/gui/fitCommands/guiAddCargo.py +++ b/gui/fitCommands/guiAddCargo.py @@ -12,18 +12,19 @@ class GuiAddCargoCommand(wx.Command): self.sFit = Fit.getInstance() self.internal_history = wx.CommandProcessor() self.fitID = fitID - # can set his up no to not have to set variables on our object - self.cmd = FitAddCargoCommand(fitID, itemID, amount, replace) + self.itemID = itemID + self.amount = amount + self.replace = replace def Do(self): - if self.internal_history.Submit(self.cmd): + if self.internal_history.Submit(FitAddCargoCommand(self.fitID, self.itemID, self.amount, self.replace)): wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True return False def Undo(self): - for x in self.internal_history.Commands: + for _ in self.internal_history.Commands: self.internal_history.Undo() - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True diff --git a/gui/fitCommands/guiAddCharge.py b/gui/fitCommands/guiAddCharge.py index 6d1e5e70a..26ae3bf94 100644 --- a/gui/fitCommands/guiAddCharge.py +++ b/gui/fitCommands/guiAddCharge.py @@ -12,11 +12,11 @@ class GuiModuleAddChargeCommand(wx.Command): self.sFit = Fit.getInstance() self.internal_history = wx.CommandProcessor() self.fitID = fitID - # can set his up no to not have to set variables on our object - self.cmd = FitSetChargeCommand(fitID, [mod.modPosition for mod in modules], itemID) + self.itemID = itemID + self.positions = [mod.modPosition for mod in modules] def Do(self): - if self.internal_history.Submit(self.cmd): + if self.internal_history.Submit(FitSetChargeCommand(self.fitID, self.positions, self.itemID)): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True diff --git a/gui/fitCommands/guiAddCommand.py b/gui/fitCommands/guiAddCommand.py index a46da244e..38f3a1110 100644 --- a/gui/fitCommands/guiAddCommand.py +++ b/gui/fitCommands/guiAddCommand.py @@ -12,11 +12,10 @@ class GuiAddCommandCommand(wx.Command): self.sFit = Fit.getInstance() self.internal_history = wx.CommandProcessor() self.fitID = fitID - # can set his up no to not have to set variables on our object - self.cmd = FitAddCommandCommand(fitID, commandFitID) + self.commandFitID = commandFitID def Do(self): - if self.internal_history.Submit(self.cmd): + if self.internal_history.Submit(FitAddCommandCommand(self.fitID, self.commandFitID)): wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) self.sFit.recalc(self.fitID) return True diff --git a/gui/fitCommands/guiAddFighter.py b/gui/fitCommands/guiAddFighter.py index 095688142..2e699b53a 100644 --- a/gui/fitCommands/guiAddFighter.py +++ b/gui/fitCommands/guiAddFighter.py @@ -15,8 +15,7 @@ class GuiAddFighterCommand(wx.Command): self.itemID = itemID def Do(self): - cmd = FitAddFighterCommand(self.fitID, self.itemID) - if self.internal_history.Submit(cmd): + if self.internal_history.Submit(FitAddFighterCommand(self.fitID, self.itemID)): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True @@ -25,6 +24,7 @@ class GuiAddFighterCommand(wx.Command): def Undo(self): for _ in self.internal_history.Commands: self.internal_history.Undo() + self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True diff --git a/gui/fitCommands/guiAddImplant.py b/gui/fitCommands/guiAddImplant.py index 33495398d..d819a55d3 100644 --- a/gui/fitCommands/guiAddImplant.py +++ b/gui/fitCommands/guiAddImplant.py @@ -12,18 +12,19 @@ class GuiAddImplantCommand(wx.Command): self.sFit = Fit.getInstance() self.internal_history = wx.CommandProcessor() self.fitID = fitID - # can set his up no to not have to set variables on our object - self.cmd = FitAddImplantCommand(fitID, itemID) + self.itemID = itemID def Do(self): - if self.internal_history.Submit(self.cmd): + if self.internal_history.Submit(FitAddImplantCommand(self.fitID, self.itemID)): + self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True return False def Undo(self): - for x in self.internal_history.Commands: + for _ in self.internal_history.Commands: self.internal_history.Undo() - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True diff --git a/gui/fitCommands/guiCargoToModule.py b/gui/fitCommands/guiCargoToModule.py index 3ce9cc4b0..506c47001 100644 --- a/gui/fitCommands/guiCargoToModule.py +++ b/gui/fitCommands/guiCargoToModule.py @@ -71,5 +71,6 @@ class GuiCargoToModuleCommand(wx.Command): def Undo(self): for _ in self.internal_history.Commands: self.internal_history.Undo() + self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True diff --git a/gui/fitCommands/guiMetaSwap.py b/gui/fitCommands/guiMetaSwap.py index e5f3848a5..9b4af4039 100644 --- a/gui/fitCommands/guiMetaSwap.py +++ b/gui/fitCommands/guiMetaSwap.py @@ -46,7 +46,6 @@ class GuiMetaSwapCommand(wx.Command): elif context == 'droneItem': raise NotImplementedError() - def Do(self): for cmds in self.data: for cmd in cmds: @@ -57,7 +56,7 @@ class GuiMetaSwapCommand(wx.Command): return True def Undo(self): - for x in self.internal_history.Commands: + for _ in self.internal_history.Commands: self.internal_history.Undo() self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) diff --git a/gui/fitCommands/guiModuleToCargo.py b/gui/fitCommands/guiModuleToCargo.py index d59680408..c0b483d2c 100644 --- a/gui/fitCommands/guiModuleToCargo.py +++ b/gui/fitCommands/guiModuleToCargo.py @@ -67,5 +67,6 @@ class GuiModuleToCargoCommand(wx.Command): def Undo(self): for _ in self.internal_history.Commands: self.internal_history.Undo() + self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True diff --git a/gui/fitCommands/guiRemoveBooster.py b/gui/fitCommands/guiRemoveBooster.py index 2155ab120..0e96f1c2e 100644 --- a/gui/fitCommands/guiRemoveBooster.py +++ b/gui/fitCommands/guiRemoveBooster.py @@ -12,18 +12,17 @@ class GuiRemoveBoosterCommand(wx.Command): self.sFit = Fit.getInstance() self.internal_history = wx.CommandProcessor() self.fitID = fitID - # can set his up no to not have to set variables on our object - self.cmd = FitRemoveBoosterCommand(fitID, position) + self.position = position def Do(self): - if self.internal_history.Submit(self.cmd): + if self.internal_history.Submit(FitRemoveBoosterCommand(self.fitID, self.position)): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True return False def Undo(self): - for x in self.internal_history.Commands: + for _ in self.internal_history.Commands: self.internal_history.Undo() self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) diff --git a/gui/fitCommands/guiRemoveCargo.py b/gui/fitCommands/guiRemoveCargo.py index 210252418..ec42e4d3c 100644 --- a/gui/fitCommands/guiRemoveCargo.py +++ b/gui/fitCommands/guiRemoveCargo.py @@ -12,18 +12,17 @@ class GuiRemoveCargoCommand(wx.Command): self.sFit = Fit.getInstance() self.internal_history = wx.CommandProcessor() self.fitID = fitID - # can set his up no to not have to set variables on our object - self.cmd = FitRemoveCargoCommand(fitID, itemID, stack=True) + self.itemID = itemID def Do(self): - if self.internal_history.Submit(self.cmd): + if self.internal_history.Submit(FitRemoveCargoCommand(self.fitID, self.itemID, stack=True)): wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True return False def Undo(self): - for x in self.internal_history.Commands: + for _ in self.internal_history.GetCommands(): self.internal_history.Undo() - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True diff --git a/gui/fitCommands/guiRemoveCommand.py b/gui/fitCommands/guiRemoveCommand.py index d01abce08..351f9697b 100644 --- a/gui/fitCommands/guiRemoveCommand.py +++ b/gui/fitCommands/guiRemoveCommand.py @@ -12,11 +12,10 @@ class GuiRemoveCommandCommand(wx.Command): self.sFit = Fit.getInstance() self.internal_history = wx.CommandProcessor() self.fitID = fitID - # can set his up no to not have to set variables on our object - self.cmd = FitRemoveCommandCommand(fitID, commandFitID) + self.commandFitID = commandFitID def Do(self): - if self.internal_history.Submit(self.cmd): + if self.internal_history.Submit(FitRemoveCommandCommand(self.fitID, self.commandFitID)): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True diff --git a/gui/fitCommands/guiRemoveImplant.py b/gui/fitCommands/guiRemoveImplant.py index af96355a4..7c9c6a4c1 100644 --- a/gui/fitCommands/guiRemoveImplant.py +++ b/gui/fitCommands/guiRemoveImplant.py @@ -12,18 +12,17 @@ class GuiRemoveImplantCommand(wx.Command): self.sFit = Fit.getInstance() self.internal_history = wx.CommandProcessor() self.fitID = fitID - # can set his up no to not have to set variables on our object - self.cmd = FitRemoveImplantCommand(fitID, position) + self.position = position def Do(self): - if self.internal_history.Submit(self.cmd): + if self.internal_history.Submit(FitRemoveImplantCommand(self.fitID, self.position)): wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True return False def Undo(self): - for x in self.internal_history.Commands: + for _ in self.internal_history.Commands: self.internal_history.Undo() - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True diff --git a/gui/fitCommands/guiRemoveModule.py b/gui/fitCommands/guiRemoveModule.py index 169dbe593..848708856 100644 --- a/gui/fitCommands/guiRemoveModule.py +++ b/gui/fitCommands/guiRemoveModule.py @@ -3,7 +3,6 @@ from service.fit import Fit import gui.mainFrame from gui import globalEvents as GE - from .helpers import ModuleInfoCache from .calc.fitRemoveModule import FitRemoveModuleCommand diff --git a/gui/fitCommands/guiSetMode.py b/gui/fitCommands/guiSetMode.py index 2c1e4864c..0ad7b80f6 100644 --- a/gui/fitCommands/guiSetMode.py +++ b/gui/fitCommands/guiSetMode.py @@ -12,11 +12,10 @@ class GuiSetModeCommand(wx.Command): self.sFit = Fit.getInstance() self.internal_history = wx.CommandProcessor() self.fitID = fitID - # can set his up no to not have to set variables on our object - self.cmd = FitSetModeCommand(fitID, mode) + self.mode = mode def Do(self): - if self.internal_history.Submit(self.cmd): + if self.internal_history.Submit(FitSetModeCommand(self.fitID, self.mode)): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True diff --git a/gui/fitCommands/guiSwapCloneModule.py b/gui/fitCommands/guiSwapCloneModule.py index 65ddea591..cbeaf0845 100644 --- a/gui/fitCommands/guiSwapCloneModule.py +++ b/gui/fitCommands/guiSwapCloneModule.py @@ -42,5 +42,9 @@ class GuiModuleSwapOrCloneCommand(wx.Command): pyfalog.debug("{} Undo()".format(self)) for _ in self.internal_history.Commands: self.internal_history.Undo() + + if self.clone: + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True diff --git a/gui/fitCommands/guiToggleCommand.py b/gui/fitCommands/guiToggleCommand.py index b7f07ed78..85f32c143 100644 --- a/gui/fitCommands/guiToggleCommand.py +++ b/gui/fitCommands/guiToggleCommand.py @@ -12,11 +12,10 @@ class GuiToggleCommandCommand(wx.Command): self.sFit = Fit.getInstance() self.internal_history = wx.CommandProcessor() self.fitID = fitID - # can set his up no to not have to set variables on our object - self.cmd = FitToggleCommandCommand(fitID, commandFitID) + self.commandFitID = commandFitID def Do(self): - if self.internal_history.Submit(self.cmd): + if self.internal_history.Submit(FitToggleCommandCommand(self.fitID, self.commandFitID)): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True diff --git a/gui/fitCommands/guiToggleModuleState.py b/gui/fitCommands/guiToggleModuleState.py index 7fcd824b1..d87339347 100644 --- a/gui/fitCommands/guiToggleModuleState.py +++ b/gui/fitCommands/guiToggleModuleState.py @@ -17,10 +17,9 @@ class GuiModuleStateChangeCommand(wx.Command): self.modules = modules self.click = click self.internal_history = wx.CommandProcessor() - self.cmd = FitChangeStatesCommand(self.fitID, self.baseMod, self.modules, self.click) def Do(self): - if self.internal_history.Submit(self.cmd): + if self.internal_history.Submit(FitChangeStatesCommand(self.fitID, self.baseMod, self.modules, self.click)): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True From 083b34c780e5a1dd7b0628741130fc8585f9a2b2 Mon Sep 17 00:00:00 2001 From: Ryan Holmes Date: Thu, 16 Aug 2018 23:40:50 -0400 Subject: [PATCH 50/95] working commit --- gui/builtinAdditionPanes/droneView.py | 6 +-- gui/fitCommands/__init__.py | 3 +- gui/fitCommands/calc/fitAddDrone.py | 53 +++++++++++++++++++++++++++ gui/fitCommands/guiAddDrone.py | 30 +++++++++++++++ service/fit.py | 2 + service/fitDeprecated.py | 28 ++++++++++++++ 6 files changed, 117 insertions(+), 5 deletions(-) create mode 100644 gui/fitCommands/calc/fitAddDrone.py create mode 100644 gui/fitCommands/guiAddDrone.py diff --git a/gui/builtinAdditionPanes/droneView.py b/gui/builtinAdditionPanes/droneView.py index e9b893047..264b07183 100644 --- a/gui/builtinAdditionPanes/droneView.py +++ b/gui/builtinAdditionPanes/droneView.py @@ -29,7 +29,7 @@ from gui.contextMenu import ContextMenu from gui.utils.staticHelpers import DragDropHelper from service.fit import Fit from service.market import Market - +import gui.fitCommands as cmd class DroneViewDrop(wx.DropTarget): def __init__(self, dropFn, *args, **kwargs): @@ -213,9 +213,7 @@ class DroneView(Display): event.Skip() return - trigger = sFit.addDrone(fitID, event.itemID) - if trigger: - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + if self.mainFrame.command.Submit(cmd.GuiAddDroneCommand(fitID, event.itemID)): self.mainFrame.additionsPane.select("Drones") event.Skip() diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index 8b053bf82..5394dafa0 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -22,4 +22,5 @@ from .guiRemoveFighter import GuiRemoveFighterCommand from .guiMetaSwap import GuiMetaSwapCommand from .guiToggleFighter import GuiToggleFighterCommand from .guiToggleImplant import GuiToggleImplantCommand -from .guiToggleBooster import GuiToggleImplantCommand \ No newline at end of file +from .guiToggleBooster import GuiToggleImplantCommand +from .guiAddDrone import GuiAddDroneCommand \ No newline at end of file diff --git a/gui/fitCommands/calc/fitAddDrone.py b/gui/fitCommands/calc/fitAddDrone.py new file mode 100644 index 000000000..59e01b807 --- /dev/null +++ b/gui/fitCommands/calc/fitAddDrone.py @@ -0,0 +1,53 @@ +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__) +from eos.saveddata.drone import Drone + +class FitAddDroneCommand(wx.Command): + """" + from sFit.addDrone + """ + def __init__(self, fitID, itemID, amount=1, replace=False): + wx.Command.__init__(self, True, "Drone add") + self.fitID = fitID + self.itemID = itemID + self.amount = amount # add x amount. If this goes over amount, removes stack + self.replace = replace # if this is false, we increment. + + def Do(self): + pyfalog.debug("Adding {0} drones ({1}) to fit ID: {2}", self.amount, self.itemID, self.fitID) + + fit = eos.db.getFit(self.fitID) + item = eos.db.getItem(self.itemID, eager=("attributes", "group.category")) + + for d in fit.drones.find(item): + if d is not None and d.amountActive == 0 and d.amount < max(5, fit.extraAttributes["maxActiveDrones"]): + drone = d + break + else: + try: + drone = Drone(item) + except ValueError: + pyfalog.warning("Invalid drone: {}", item) + return False + + if not drone.fits(fit): + return False + fit.drones.append(drone) + + drone.amount += self.amount + eos.db.commit() + return True + + def Undo(self): + from .fitRemoveCargo import FitRemoveCargoCommand # Avoid circular import + cmd = FitRemoveCargoCommand(self.fitID, self.itemID, self.amount) + cmd.Do() + return True diff --git a/gui/fitCommands/guiAddDrone.py b/gui/fitCommands/guiAddDrone.py new file mode 100644 index 000000000..f55f40363 --- /dev/null +++ b/gui/fitCommands/guiAddDrone.py @@ -0,0 +1,30 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from .calc.fitAddDrone import FitAddDroneCommand + +class GuiAddDroneCommand(wx.Command): + def __init__(self, fitID, itemID): + wx.Command.__init__(self, True, "Cargo Add") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() + self.fitID = fitID + self.itemID = itemID + + def Do(self): + cmd = FitAddDroneCommand(self.fitID, self.itemID) + if self.internal_history.Submit(cmd): + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for _ in self.internal_history.Commands: + self.internal_history.Undo() + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + diff --git a/service/fit.py b/service/fit.py index 0807ba8a8..0b9e73ed0 100644 --- a/service/fit.py +++ b/service/fit.py @@ -37,6 +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 import wx pyfalog = Logger(__name__) @@ -427,6 +428,7 @@ class Fit(FitDeprecated): else: return None + @deprecated def addDrone(self, fitID, itemID, numDronesToAdd=1, recalc=True): pyfalog.debug("Adding {0} drones ({1}) to fit ID: {2}", numDronesToAdd, itemID, fitID) if fitID is None: diff --git a/service/fitDeprecated.py b/service/fitDeprecated.py index 8bc522217..8593930a3 100644 --- a/service/fitDeprecated.py +++ b/service/fitDeprecated.py @@ -35,6 +35,34 @@ pyfalog = Logger(__name__) class FitDeprecated(object): + @deprecated + def addDrone(self, fitID, itemID, numDronesToAdd=1, recalc=True): + pyfalog.debug("Adding {0} drones ({1}) to fit ID: {2}", numDronesToAdd, itemID, fitID) + if fitID is None: + return False + + fit = eos.db.getFit(fitID) + item = eos.db.getItem(itemID, eager=("attributes", "group.category")) + if item.category.name == "Drone": + drone = None + for d in fit.drones.find(item): + if d is not None and d.amountActive == 0 and d.amount < max(5, fit.extraAttributes["maxActiveDrones"]): + drone = d + break + + if drone is None: + drone = es_Drone(item) + if drone.fits(fit) is True: + fit.drones.append(drone) + else: + return False + drone.amount += numDronesToAdd + eos.db.commit() + if recalc: + self.recalc(fit) + return True + else: + return False @deprecated def addImplant(self, fitID, itemID, recalc=True): From a37fdf48c852753c195cbf5c5b508252cd0a9a7c Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 18 Aug 2018 00:06:50 -0400 Subject: [PATCH 51/95] Fix implant / booster toggles, add qty change commands, started dinking with drone stacks, although think I might remove this altogether in favor of a qty change --- gui/builtinAdditionPanes/boosterView.py | 2 +- gui/builtinAdditionPanes/droneView.py | 4 +- gui/builtinContextMenus/amount.py | 9 +- gui/builtinContextMenus/droneRemoveStack.py | 5 +- gui/builtinContextMenus/droneSplit.py | 87 ++++++++++++++++++- gui/builtinContextMenus/itemRemove.py | 4 +- gui/fitCommands/__init__.py | 8 +- gui/fitCommands/calc/fitAddDrone.py | 9 +- gui/fitCommands/calc/fitChangeCargoQty.py | 33 +++++++ gui/fitCommands/calc/fitChangeFighterQty.py | 36 ++++++++ .../calc/fitChangeProjectedFitQty.py | 42 +++++++++ gui/fitCommands/calc/fitRemoveDrone.py | 49 +++++++++++ gui/fitCommands/guiChangeCargoQty.py | 38 ++++++++ gui/fitCommands/guiChangeFighterQty.py | 39 +++++++++ gui/fitCommands/guiChangeProjectedFitQty.py | 39 +++++++++ gui/fitCommands/guiRemoveDrone.py | 31 +++++++ gui/fitCommands/guiToggleBooster.py | 2 +- service/fit.py | 20 +---- service/fitDeprecated.py | 24 +++++ 19 files changed, 441 insertions(+), 40 deletions(-) create mode 100644 gui/fitCommands/calc/fitChangeCargoQty.py create mode 100644 gui/fitCommands/calc/fitChangeFighterQty.py create mode 100644 gui/fitCommands/calc/fitChangeProjectedFitQty.py create mode 100644 gui/fitCommands/calc/fitRemoveDrone.py create mode 100644 gui/fitCommands/guiChangeCargoQty.py create mode 100644 gui/fitCommands/guiChangeFighterQty.py create mode 100644 gui/fitCommands/guiChangeProjectedFitQty.py create mode 100644 gui/fitCommands/guiRemoveDrone.py diff --git a/gui/builtinAdditionPanes/boosterView.py b/gui/builtinAdditionPanes/boosterView.py index a68e4ff3a..1d487d2ad 100644 --- a/gui/builtinAdditionPanes/boosterView.py +++ b/gui/builtinAdditionPanes/boosterView.py @@ -157,7 +157,7 @@ class BoosterView(d.Display): col = self.getColumn(event.Position) if col == self.getColIndex(State): fitID = self.mainFrame.getActiveFit() - self.mainFrame.command.Submit(cmd.GuiToggleImplantCommand(fitID, row)) + self.mainFrame.command.Submit(cmd.GuiToggleBoosterCommand(fitID, row)) def scheduleMenu(self, event): event.Skip() diff --git a/gui/builtinAdditionPanes/droneView.py b/gui/builtinAdditionPanes/droneView.py index 264b07183..4200f1046 100644 --- a/gui/builtinAdditionPanes/droneView.py +++ b/gui/builtinAdditionPanes/droneView.py @@ -228,9 +228,7 @@ class DroneView(Display): def removeDrone(self, drone): fitID = self.mainFrame.getActiveFit() - sFit = Fit.getInstance() - sFit.removeDrone(fitID, self.original.index(drone)) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.GuiRemoveDroneCommand(fitID, self.original.index(drone))) def click(self, event): event.Skip() diff --git a/gui/builtinContextMenus/amount.py b/gui/builtinContextMenus/amount.py index eec575f29..e5416ede6 100644 --- a/gui/builtinContextMenus/amount.py +++ b/gui/builtinContextMenus/amount.py @@ -42,15 +42,18 @@ class ChangeAmount(ContextMenu): return sFit = Fit.getInstance() + fit = sFit.getFit(fitID) cleanInput = re.sub(r'[^0-9.]', '', dlg.input.GetLineText(0).strip()) if isinstance(thing, es_Cargo): - self.mainFrame.command.Submit(cmd.GuiAddCargoCommand(fitID, thing.item.ID, int(float(cleanInput)), replace=True)) + self.mainFrame.command.Submit(cmd.GuiChangeCargoQty(fitID, fit.cargo.index(thing), int(float(cleanInput)))) return # no need for post event here elif isinstance(thing, es_Fit): - sFit.changeAmount(fitID, thing, int(float(cleanInput))) + self.mainFrame.command.Submit(cmd.GuiChangeProjectedFitQty(fitID, thing.ID, int(float(cleanInput)))) + return elif isinstance(thing, es_Fighter): - sFit.changeActiveFighters(fitID, thing, int(float(cleanInput))) + self.mainFrame.command.Submit(cmd.GuiChangeFighterQty(fitID, fit.fighters.index(thing), int(float(cleanInput)))) + return wx.PostEvent(mainFrame, GE.FitChanged(fitID=fitID)) diff --git a/gui/builtinContextMenus/droneRemoveStack.py b/gui/builtinContextMenus/droneRemoveStack.py index c7dae1e03..5af373e41 100644 --- a/gui/builtinContextMenus/droneRemoveStack.py +++ b/gui/builtinContextMenus/droneRemoveStack.py @@ -5,6 +5,7 @@ import wx import gui.globalEvents as GE from service.fit import Fit from service.settings import ContextMenuSettings +import gui.fitCommands as cmd class ItemRemove(ContextMenu): @@ -27,9 +28,7 @@ class ItemRemove(ContextMenu): fit = sFit.getFit(fitID) idx = fit.drones.index(selection[0]) - sFit.removeDrone(fitID, idx, numDronesToRemove=fit.drones[idx].amount) - - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.GuiRemoveDroneCommand(fitID, idx, fit.drones[idx].amount)) ItemRemove.register() diff --git a/gui/builtinContextMenus/droneSplit.py b/gui/builtinContextMenus/droneSplit.py index ec52db3f8..9701cc10f 100644 --- a/gui/builtinContextMenus/droneSplit.py +++ b/gui/builtinContextMenus/droneSplit.py @@ -5,6 +5,7 @@ from service.fit import Fit # noinspection PyPackageRequirements import wx from service.settings import ContextMenuSettings +import re class DroneSplit(ContextMenu): @@ -23,14 +24,94 @@ class DroneSplit(ContextMenu): def activate(self, fullContext, selection, i): srcContext = fullContext[0] - dlg = DroneSpinner(self.mainFrame, selection[0], srcContext) - dlg.ShowModal() - dlg.Destroy() + drone = selection[0] + dlg = DroneStackSplit(self.mainFrame, drone.amount) + + if dlg.ShowModal() == wx.ID_OK: + + if dlg.input.GetLineText(0).strip() == '': + return + + sFit = Fit.getInstance() + cleanInput = re.sub(r'[^0-9.]', '', dlg.input.GetLineText(0).strip()) + fitID = self.mainFrame.getActiveFit() + + if srcContext == "droneItem": + sFit.splitDroneStack(fitID, drone, int(float(cleanInput))) + else: + sFit.splitProjectedDroneStack(fitID, drone, int(float(cleanInput))) + + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + + # if isinstance(thing, es_Cargo): + # self.mainFrame.command.Submit( + # cmd.GuiAddCargoCommand(fitID, thing.item.ID, int(float(cleanInput)), replace=True)) + # return # no need for post event here + # elif isinstance(thing, es_Fit): + # sFit.changeAmount(fitID, thing, int(float(cleanInput))) + # elif isinstance(thing, es_Fighter): + # sFit.changeActiveFighters(fitID, thing, int(float(cleanInput))) + # + # wx.PostEvent(mainFrame, GE.FitChanged(fitID=fitID)) + # + # dlg = DroneSpinner(self.mainFrame, selection[0], srcContext) + # dlg.ShowModal() + # dlg.Destroy() DroneSplit.register() +class DroneStackSplit(wx.Dialog): + def __init__(self, parent, value): + wx.Dialog.__init__(self, parent, title="Split Drone Stack") + self.SetMinSize((346, 156)) + + bSizer1 = wx.BoxSizer(wx.VERTICAL) + + bSizer2 = wx.BoxSizer(wx.VERTICAL) + text = wx.StaticText(self, wx.ID_ANY, "New Amount:") + bSizer2.Add(text, 0) + + bSizer1.Add(bSizer2, 0, wx.ALL, 10) + + self.input = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_PROCESS_ENTER) + self.input.SetValue(str(value)) + self.input.SelectAll() + + bSizer1.Add(self.input, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, 15) + + bSizer3 = wx.BoxSizer(wx.VERTICAL) + bSizer3.Add(wx.StaticLine(self, wx.ID_ANY), 0, wx.BOTTOM | wx.EXPAND, 15) + + bSizer3.Add(self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL), 0, wx.EXPAND) + bSizer1.Add(bSizer3, 0, wx.ALL | wx.EXPAND, 10) + + self.input.SetFocus() + self.input.Bind(wx.EVT_CHAR, self.onChar) + self.input.Bind(wx.EVT_TEXT_ENTER, self.processEnter) + self.SetSizer(bSizer1) + self.CenterOnParent() + self.Fit() + + def processEnter(self, evt): + self.EndModal(wx.ID_OK) + + # checks to make sure it's valid number + @staticmethod + def onChar(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 + + + class DroneSpinner(wx.Dialog): def __init__(self, parent, drone, context): wx.Dialog.__init__(self, parent, title="Select Amount", size=wx.Size(220, 60)) diff --git a/gui/builtinContextMenus/itemRemove.py b/gui/builtinContextMenus/itemRemove.py index 65094c7a4..cbae19145 100644 --- a/gui/builtinContextMenus/itemRemove.py +++ b/gui/builtinContextMenus/itemRemove.py @@ -40,8 +40,10 @@ class ItemRemove(ContextMenu): return # the command takes care of the PostEvent elif srcContext in ("fittingCharge", "projectedCharge"): self.mainFrame.command.Submit(cmd.GuiModuleAddChargeCommand(fitID, None, selection)) + return elif srcContext == "droneItem": - sFit.removeDrone(fitID, fit.drones.index(selection[0])) + self.mainFrame.command.Submit(cmd.GuiRemoveDroneCommand(fitID, fit.drones.index(selection[0]))) + return elif srcContext == "fighterItem": self.mainFrame.command.Submit(cmd.GuiRemoveFighterCommand(fitID, fit.fighters.index(selection[0]))) return # the command takes care of the PostEvent diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index 5394dafa0..b708d153a 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -22,5 +22,9 @@ from .guiRemoveFighter import GuiRemoveFighterCommand from .guiMetaSwap import GuiMetaSwapCommand from .guiToggleFighter import GuiToggleFighterCommand from .guiToggleImplant import GuiToggleImplantCommand -from .guiToggleBooster import GuiToggleImplantCommand -from .guiAddDrone import GuiAddDroneCommand \ No newline at end of file +from .guiToggleBooster import GuiToggleBoosterCommand +from .guiAddDrone import GuiAddDroneCommand +from .guiRemoveDrone import GuiRemoveDroneCommand +from .guiChangeFighterQty import GuiChangeFighterQty +from .guiChangeCargoQty import GuiChangeCargoQty +from .guiChangeProjectedFitQty import GuiChangeProjectedFitQty \ No newline at end of file diff --git a/gui/fitCommands/calc/fitAddDrone.py b/gui/fitCommands/calc/fitAddDrone.py index 59e01b807..c92f9fa78 100644 --- a/gui/fitCommands/calc/fitAddDrone.py +++ b/gui/fitCommands/calc/fitAddDrone.py @@ -20,6 +20,7 @@ class FitAddDroneCommand(wx.Command): self.itemID = itemID self.amount = amount # add x amount. If this goes over amount, removes stack self.replace = replace # if this is false, we increment. + self.index = None def Do(self): pyfalog.debug("Adding {0} drones ({1}) to fit ID: {2}", self.amount, self.itemID, self.fitID) @@ -44,10 +45,10 @@ class FitAddDroneCommand(wx.Command): drone.amount += self.amount eos.db.commit() + self.index = fit.drones.index(drone) return True def Undo(self): - from .fitRemoveCargo import FitRemoveCargoCommand # Avoid circular import - cmd = FitRemoveCargoCommand(self.fitID, self.itemID, self.amount) - cmd.Do() - return True + from .fitRemoveDrone import FitRemoveDroneCommand # Avoid circular import + cmd = FitRemoveDroneCommand(self.fitID, self.index, self.amount) + return cmd.Do() diff --git a/gui/fitCommands/calc/fitChangeCargoQty.py b/gui/fitCommands/calc/fitChangeCargoQty.py new file mode 100644 index 000000000..c737f3c22 --- /dev/null +++ b/gui/fitCommands/calc/fitChangeCargoQty.py @@ -0,0 +1,33 @@ +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__) +from eos.saveddata.drone import Drone + +class FitChangeCargoQty(wx.Command): + def __init__(self, fitID, position, amount=1): + wx.Command.__init__(self, True, "Drone add") + self.fitID = fitID + self.position = position + self.amount = amount # add x amount. If this goes over amount, removes stack + self.old_amount = None + + def Do(self): + pyfalog.debug("Changing cargo ({0}) for fit ({1}) to amount: {2}", self.position, self.fitID, self.amount) + fit = eos.db.getFit(self.fitID) + cargo = fit.cargo[self.position] + self.old_amount = cargo.amount + cargo.amount = self.amount + + eos.db.commit() + return True + + def Undo(self): + cmd = FitChangeCargoQty(self.fitID, self.position, self.old_amount) + return cmd.Do() diff --git a/gui/fitCommands/calc/fitChangeFighterQty.py b/gui/fitCommands/calc/fitChangeFighterQty.py new file mode 100644 index 000000000..d8c2af274 --- /dev/null +++ b/gui/fitCommands/calc/fitChangeFighterQty.py @@ -0,0 +1,36 @@ +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__) +from eos.saveddata.drone import Drone + +class FitChangeFighterQty(wx.Command): + """" + from sFit.changeActiveFighters + """ + def __init__(self, fitID, position, amount=1): + wx.Command.__init__(self, True, "Drone add") + self.fitID = fitID + self.position = position + self.amount = amount # add x amount. If this goes over amount, removes stack + self.old_amount = None + + def Do(self): + pyfalog.debug("Changing active fighters ({0}) for fit ({1}) to amount: {2}", self.position, self.fitID, self.amount) + fit = eos.db.getFit(self.fitID) + fighter = fit.fighters[self.position] + self.old_amount = fighter.amountActive + fighter.amountActive = self.amount + + eos.db.commit() + return True + + def Undo(self): + cmd = FitChangeFighterQty(self.fitID, self.position, self.old_amount) + return cmd.Do() diff --git a/gui/fitCommands/calc/fitChangeProjectedFitQty.py b/gui/fitCommands/calc/fitChangeProjectedFitQty.py new file mode 100644 index 000000000..e379ec883 --- /dev/null +++ b/gui/fitCommands/calc/fitChangeProjectedFitQty.py @@ -0,0 +1,42 @@ +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 FitChangeProjectedFitQty(wx.Command): + """" + from sFit.changeAmount + """ + def __init__(self, fitID, pfitID, amount=1): + wx.Command.__init__(self, True, "Drone add") + self.fitID = fitID + self.pfitID = pfitID + self.amount = amount + self.old_amount = None + + def Do(self): + fit = eos.db.getFit(self.fitID) + pfit = eos.db.getFit(self.pfitID) + + if not pfit: # fit was deleted + return False + + amount = min(20, max(1, self.amount)) # 1 <= a <= 20 + + projectionInfo = pfit.getProjectionInfo(self.fitID) + if projectionInfo: + self.old_amount = projectionInfo.amount + projectionInfo.amount = amount + + eos.db.commit() + return True + + def Undo(self): + cmd = FitChangeProjectedFitQty(self.fitID, self.pfitID, self.old_amount) + return cmd.Do() diff --git a/gui/fitCommands/calc/fitRemoveDrone.py b/gui/fitCommands/calc/fitRemoveDrone.py new file mode 100644 index 000000000..13e96d435 --- /dev/null +++ b/gui/fitCommands/calc/fitRemoveDrone.py @@ -0,0 +1,49 @@ +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__) +from eos.saveddata.drone import Drone + +class FitRemoveDroneCommand(wx.Command): + """" + from sFit.addDrone + """ + def __init__(self, fitID, position, amount=1): + wx.Command.__init__(self, True, "Drone add") + self.fitID = fitID + self.position = position + self.amount = amount # add x amount. If this goes over amount, removes stack + self.removed_item = None + + def Do(self): + pyfalog.debug("Removing {0} drones for fit ID: {1}", self.amount, self.fitID) + fit = eos.db.getFit(self.fitID) + d = fit.drones[self.position] + d.amount -= self.amount + if d.amountActive > 0: + d.amountActive -= self.amount + + if d.amount == 0: + self.removed_item = d.itemID + del fit.drones[self.position] + + eos.db.commit() + return True + + def Undo(self): + if self.removed_item: + from .fitAddDrone import FitAddDroneCommand # Avoid circular import + cmd = FitAddDroneCommand(self.fitID, self.removed_item, self.amount) + return cmd.Do() + else: + fit = eos.db.getFit(self.fitID) + d = fit.drones[self.position] + d.amount += self.amount + eos.db.commit() + return True diff --git a/gui/fitCommands/guiChangeCargoQty.py b/gui/fitCommands/guiChangeCargoQty.py new file mode 100644 index 000000000..b8a6c8873 --- /dev/null +++ b/gui/fitCommands/guiChangeCargoQty.py @@ -0,0 +1,38 @@ +import wx +import eos.db +import gui.mainFrame +from service.fit import Fit +from gui import globalEvents as GE +from .calc.fitAddModule import FitAddModuleCommand +from .calc.fitReplaceModule import FitReplaceModuleCommand +from .calc.fitChangeCargoQty import FitChangeCargoQty +from service.fit import Fit +from logbook import Logger +pyfalog = Logger(__name__) + + +class GuiChangeCargoQty(wx.Command): + def __init__(self, fitID, position, amount=1): + wx.Command.__init__(self, True, "") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.fitID = fitID + self.position = position + self.amount = amount + self.internal_history = wx.CommandProcessor() + + def Do(self): + cmd = FitChangeCargoQty(self.fitID, self.position, self.amount) + if self.internal_history.Submit(cmd): + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + + def Undo(self): + for _ in self.internal_history.Commands: + self.internal_history.Undo() + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True diff --git a/gui/fitCommands/guiChangeFighterQty.py b/gui/fitCommands/guiChangeFighterQty.py new file mode 100644 index 000000000..063c6cda5 --- /dev/null +++ b/gui/fitCommands/guiChangeFighterQty.py @@ -0,0 +1,39 @@ +import wx +import eos.db +import gui.mainFrame +from service.fit import Fit +from gui import globalEvents as GE +from .calc.fitAddModule import FitAddModuleCommand +from .calc.fitReplaceModule import FitReplaceModuleCommand +from .calc.fitChangeFighterQty import FitChangeFighterQty +from service.fit import Fit +from logbook import Logger +pyfalog = Logger(__name__) + + +class GuiChangeFighterQty(wx.Command): + def __init__(self, fitID, position, amount=1): + wx.Command.__init__(self, True, "") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.fitID = fitID + self.position = position + self.amount = amount + self.internal_history = wx.CommandProcessor() + + def Do(self): + cmd = FitChangeFighterQty(self.fitID, self.position, self.amount) + if self.internal_history.Submit(cmd): + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + + def Undo(self): + pyfalog.debug("{} Undo()".format(self)) + for _ in self.internal_history.Commands: + self.internal_history.Undo() + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True diff --git a/gui/fitCommands/guiChangeProjectedFitQty.py b/gui/fitCommands/guiChangeProjectedFitQty.py new file mode 100644 index 000000000..006876077 --- /dev/null +++ b/gui/fitCommands/guiChangeProjectedFitQty.py @@ -0,0 +1,39 @@ +import wx +import eos.db +import gui.mainFrame +from service.fit import Fit +from gui import globalEvents as GE +from .calc.fitAddModule import FitAddModuleCommand +from .calc.fitReplaceModule import FitReplaceModuleCommand +from .calc.fitChangeProjectedFitQty import FitChangeProjectedFitQty +from service.fit import Fit +from logbook import Logger +pyfalog = Logger(__name__) + + +class GuiChangeProjectedFitQty(wx.Command): + def __init__(self, fitID, pfitID, amount=1): + wx.Command.__init__(self, True, "") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.fitID = fitID + self.pfitID = pfitID + self.amount = amount + self.internal_history = wx.CommandProcessor() + + def Do(self): + cmd = FitChangeProjectedFitQty(self.fitID, self.pfitID, self.amount) + if self.internal_history.Submit(cmd): + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + + def Undo(self): + pyfalog.debug("{} Undo()".format(self)) + for _ in self.internal_history.Commands: + self.internal_history.Undo() + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True diff --git a/gui/fitCommands/guiRemoveDrone.py b/gui/fitCommands/guiRemoveDrone.py new file mode 100644 index 000000000..252adc2af --- /dev/null +++ b/gui/fitCommands/guiRemoveDrone.py @@ -0,0 +1,31 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from .calc.fitRemoveDrone import FitRemoveDroneCommand + +class GuiRemoveDroneCommand(wx.Command): + def __init__(self, fitID, position, amount=1): + wx.Command.__init__(self, True, "Cargo Add") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() + self.fitID = fitID + self.position = position + self.amount = amount + + def Do(self): + cmd = FitRemoveDroneCommand(self.fitID, self.position, self.amount) + if self.internal_history.Submit(cmd): + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for _ in self.internal_history.Commands: + self.internal_history.Undo() + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + diff --git a/gui/fitCommands/guiToggleBooster.py b/gui/fitCommands/guiToggleBooster.py index 7d5016dc5..166ad9648 100644 --- a/gui/fitCommands/guiToggleBooster.py +++ b/gui/fitCommands/guiToggleBooster.py @@ -5,7 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitToggleBooster import FitToggleBoosterCommand -class GuiToggleImplantCommand(wx.Command): +class GuiToggleBoosterCommand(wx.Command): def __init__(self, fitID, position): wx.Command.__init__(self, True, "") self.mainFrame = gui.mainFrame.MainFrame.getInstance() diff --git a/service/fit.py b/service/fit.py index 0b9e73ed0..6ed79829d 100644 --- a/service/fit.py +++ b/service/fit.py @@ -369,25 +369,6 @@ class Fit(FitDeprecated): self.recalc(fit) - def changeAmount(self, fitID, projected_fit, amount): - """Change amount of projected fits""" - pyfalog.debug("Changing fit ({0}) for projected fit ({1}) to new amount: {2}", fitID, projected_fit.getProjectionInfo(fitID), amount) - fit = eos.db.getFit(fitID) - amount = min(20, max(1, amount)) # 1 <= a <= 20 - projectionInfo = projected_fit.getProjectionInfo(fitID) - if projectionInfo: - projectionInfo.amount = amount - - eos.db.commit() - self.recalc(fit) - - def changeActiveFighters(self, fitID, fighter, amount): - pyfalog.debug("Changing active fighters ({0}) for fit ({1}) to amount: {2}", fighter.itemID, fitID, amount) - fit = eos.db.getFit(fitID) - fighter.amountActive = amount - - eos.db.commit() - self.recalc(fit) def changeMutatedValue(self, mutator, value): @@ -513,6 +494,7 @@ class Fit(FitDeprecated): fit = eos.db.getFit(fitID) self.splitDrones(fit, d, amount, fit.drones) + @deprecated def removeDrone(self, fitID, i, numDronesToRemove=1, recalc=True): pyfalog.debug("Removing {0} drones for fit ID: {1}", numDronesToRemove, fitID) fit = eos.db.getFit(fitID) diff --git a/service/fitDeprecated.py b/service/fitDeprecated.py index 8593930a3..165d929eb 100644 --- a/service/fitDeprecated.py +++ b/service/fitDeprecated.py @@ -35,6 +35,30 @@ pyfalog = Logger(__name__) class FitDeprecated(object): + + @deprecated + def changeAmount(self, fitID, projected_fit, amount): + """Change amount of projected fits""" + pyfalog.debug("Changing fit ({0}) for projected fit ({1}) to new amount: {2}", fitID, + projected_fit.getProjectionInfo(fitID), amount) + fit = eos.db.getFit(fitID) + amount = min(20, max(1, amount)) # 1 <= a <= 20 + projectionInfo = projected_fit.getProjectionInfo(fitID) + if projectionInfo: + projectionInfo.amount = amount + + eos.db.commit() + self.recalc(fit) + + @deprecated + def changeActiveFighters(self, fitID, fighter, amount): + pyfalog.debug("Changing active fighters ({0}) for fit ({1}) to amount: {2}", fighter.itemID, fitID, amount) + fit = eos.db.getFit(fitID) + fighter.amountActive = amount + + eos.db.commit() + self.recalc(fit) + @deprecated def addDrone(self, fitID, itemID, numDronesToAdd=1, recalc=True): pyfalog.debug("Adding {0} drones ({1}) to fit ID: {2}", numDronesToAdd, itemID, fitID) From fd83a4b709f146f94ebb1368ebacac0633452f8b Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 18 Aug 2018 00:39:05 -0400 Subject: [PATCH 52/95] Remove drone splitting / merging, and introduce drone change qty --- gui/builtinAdditionPanes/droneView.py | 10 +++-- gui/builtinAdditionPanes/projectedView.py | 4 +- gui/builtinContextMenus/amount.py | 5 ++- gui/contextMenu.py | 4 +- gui/fitCommands/__init__.py | 3 +- gui/fitCommands/calc/fitAddProjectedDrone.py | 2 + gui/fitCommands/calc/fitAddProjectedModule.py | 2 + gui/fitCommands/calc/fitChangeDroneQty.py | 32 ++++++++++++++++ gui/fitCommands/guiChangeDroneQty.py | 38 +++++++++++++++++++ 9 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 gui/fitCommands/calc/fitChangeDroneQty.py create mode 100644 gui/fitCommands/guiChangeDroneQty.py diff --git a/gui/builtinAdditionPanes/droneView.py b/gui/builtinAdditionPanes/droneView.py index 4200f1046..6e236d0fd 100644 --- a/gui/builtinAdditionPanes/droneView.py +++ b/gui/builtinAdditionPanes/droneView.py @@ -144,10 +144,12 @@ class DroneView(Display): data[1] is typeID or index of data we want to manipulate """ if data[0] == "drone": # we want to merge drones - srcRow = int(data[1]) - dstRow, _ = self.HitTest((x, y)) - if srcRow != -1 and dstRow != -1: - self._merge(srcRow, dstRow) + pass + # remove merge functionality, if people complain in the next while, can add it back + # srcRow = int(data[1]) + # dstRow, _ = self.HitTest((x, y)) + # if srcRow != -1 and dstRow != -1: + # self._merge(srcRow, dstRow) elif data[0] == "market": wx.PostEvent(self.mainFrame, ItemSelected(itemID=int(data[1]))) diff --git a/gui/builtinAdditionPanes/projectedView.py b/gui/builtinAdditionPanes/projectedView.py index 293f34cf2..678d3aa74 100644 --- a/gui/builtinAdditionPanes/projectedView.py +++ b/gui/builtinAdditionPanes/projectedView.py @@ -106,7 +106,9 @@ class ProjectedView(d.Display): if data[0] == "projected": # if source is coming from projected, we are trying to combine drones. - self.mergeDrones(x, y, int(data[1])) + pass + # removing merge functionality - if people complain about it, can add it back as a command + # self.mergeDrones(x, y, int(data[1])) elif data[0] == "fitting": dstRow, _ = self.HitTest((x, y)) # Gather module information to get position diff --git a/gui/builtinContextMenus/amount.py b/gui/builtinContextMenus/amount.py index e5416ede6..5389daacc 100644 --- a/gui/builtinContextMenus/amount.py +++ b/gui/builtinContextMenus/amount.py @@ -6,6 +6,7 @@ import gui.globalEvents as GE import wx import re from service.fit import Fit +from eos.saveddata.drone import Drone from eos.saveddata.cargo import Cargo as es_Cargo from eos.saveddata.fighter import Fighter as es_Fighter from service.settings import ContextMenuSettings @@ -20,7 +21,7 @@ class ChangeAmount(ContextMenu): if not self.settings.get('amount'): return False - return srcContext in ("cargoItem", "projectedFit", "fighterItem", "projectedFighter") + return srcContext in ("droneItem", "cargoItem", "projectedFit", "fighterItem", "projectedFighter") def getText(self, itmContext, selection): return u"Change {0} Quantity".format(itmContext) @@ -48,6 +49,8 @@ class ChangeAmount(ContextMenu): if isinstance(thing, es_Cargo): self.mainFrame.command.Submit(cmd.GuiChangeCargoQty(fitID, fit.cargo.index(thing), int(float(cleanInput)))) return # no need for post event here + elif isinstance(thing, Drone): + self.mainFrame.command.Submit(cmd.GuiChangeDroneQty(fitID, fit.drones.index(thing), int(float(cleanInput)))) elif isinstance(thing, es_Fit): self.mainFrame.command.Submit(cmd.GuiChangeProjectedFitQty(fitID, thing.ID, int(float(cleanInput)))) return diff --git a/gui/contextMenu.py b/gui/contextMenu.py index 08ea258d5..7060579a7 100644 --- a/gui/contextMenu.py +++ b/gui/contextMenu.py @@ -186,7 +186,7 @@ from gui.builtinContextMenus import ( # noqa: E402,F401 itemStats, damagePattern, marketJump, - droneSplit, + #droneSplit, itemRemove, droneRemoveStack, ammoPattern, @@ -202,7 +202,7 @@ from gui.builtinContextMenus import ( # noqa: E402,F401 priceOptions, amount, cargoAmmo, - droneStack, + #droneStack, metaSwap, implantSets, fighterAbilities, diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index b708d153a..93d012975 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -27,4 +27,5 @@ from .guiAddDrone import GuiAddDroneCommand from .guiRemoveDrone import GuiRemoveDroneCommand from .guiChangeFighterQty import GuiChangeFighterQty from .guiChangeCargoQty import GuiChangeCargoQty -from .guiChangeProjectedFitQty import GuiChangeProjectedFitQty \ No newline at end of file +from .guiChangeProjectedFitQty import GuiChangeProjectedFitQty +from .guiChangeDroneQty import GuiChangeDroneQty \ No newline at end of file diff --git a/gui/fitCommands/calc/fitAddProjectedDrone.py b/gui/fitCommands/calc/fitAddProjectedDrone.py index 9109c4b7b..5649b6048 100644 --- a/gui/fitCommands/calc/fitAddProjectedDrone.py +++ b/gui/fitCommands/calc/fitAddProjectedDrone.py @@ -37,6 +37,8 @@ class FitAddProjectedDroneCommand(wx.Command): if drone is None: drone = Drone(item) + if not drone.item.isType("projected"): + return False fit.projectedDrones.append(drone) self.index = fit.projectedDrones.index(drone) diff --git a/gui/fitCommands/calc/fitAddProjectedModule.py b/gui/fitCommands/calc/fitAddProjectedModule.py index bf9ebf6c2..7701e375e 100644 --- a/gui/fitCommands/calc/fitAddProjectedModule.py +++ b/gui/fitCommands/calc/fitAddProjectedModule.py @@ -30,6 +30,8 @@ class FitAddProjectedModuleCommand(wx.Command): try: module = Module(item) + if not module.item.isType("projected"): + return False except ValueError: return False diff --git a/gui/fitCommands/calc/fitChangeDroneQty.py b/gui/fitCommands/calc/fitChangeDroneQty.py new file mode 100644 index 000000000..162431837 --- /dev/null +++ b/gui/fitCommands/calc/fitChangeDroneQty.py @@ -0,0 +1,32 @@ +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 FitChangeDroneQty(wx.Command): + def __init__(self, fitID, position, amount=1): + wx.Command.__init__(self, True, "Drone add") + self.fitID = fitID + self.position = position + self.amount = amount # add x amount. If this goes over amount, removes stack + self.old_amount = None + + def Do(self): + pyfalog.debug("Changing active fighters ({0}) for fit ({1}) to amount: {2}", self.position, self.fitID, self.amount) + fit = eos.db.getFit(self.fitID) + drone = fit.drones[self.position] + self.old_amount = drone.amount + drone.amount = self.amount + + eos.db.commit() + return True + + def Undo(self): + cmd = FitChangeDroneQty(self.fitID, self.position, self.old_amount) + return cmd.Do() diff --git a/gui/fitCommands/guiChangeDroneQty.py b/gui/fitCommands/guiChangeDroneQty.py new file mode 100644 index 000000000..9c27a8945 --- /dev/null +++ b/gui/fitCommands/guiChangeDroneQty.py @@ -0,0 +1,38 @@ +import wx +import eos.db +import gui.mainFrame +from service.fit import Fit +from gui import globalEvents as GE +from .calc.fitAddModule import FitAddModuleCommand +from .calc.fitReplaceModule import FitReplaceModuleCommand +from .calc.fitChangeDroneQty import FitChangeDroneQty +from service.fit import Fit +from logbook import Logger +pyfalog = Logger(__name__) + + +class GuiChangeDroneQty(wx.Command): + def __init__(self, fitID, position, amount=1): + wx.Command.__init__(self, True, "") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.fitID = fitID + self.position = position + self.amount = amount + self.internal_history = wx.CommandProcessor() + + def Do(self): + cmd = FitChangeDroneQty(self.fitID, self.position, self.amount) + if self.internal_history.Submit(cmd): + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + + def Undo(self): + for _ in self.internal_history.Commands: + self.internal_history.Undo() + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True From b17314f3c6a367aa8a5618d6f08acea859ffa285 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 18 Aug 2018 00:45:26 -0400 Subject: [PATCH 53/95] Add projected drone change command, and remove some prints --- gui/builtinContextMenus/amount.py | 9 +++-- gui/builtinContextMenus/boosterSideEffects.py | 2 +- gui/builtinContextMenus/metaSwap.py | 4 +- gui/fitCommands/__init__.py | 3 +- .../calc/fitChangeProjectedDroneQty.py | 32 +++++++++++++++ gui/fitCommands/guiChangeProjectedDroneQty.py | 39 +++++++++++++++++++ 6 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 gui/fitCommands/calc/fitChangeProjectedDroneQty.py create mode 100644 gui/fitCommands/guiChangeProjectedDroneQty.py diff --git a/gui/builtinContextMenus/amount.py b/gui/builtinContextMenus/amount.py index 5389daacc..dc002d52b 100644 --- a/gui/builtinContextMenus/amount.py +++ b/gui/builtinContextMenus/amount.py @@ -21,7 +21,7 @@ class ChangeAmount(ContextMenu): if not self.settings.get('amount'): return False - return srcContext in ("droneItem", "cargoItem", "projectedFit", "fighterItem", "projectedFighter") + return srcContext in ("droneItem", "projectedDrone", "cargoItem", "projectedFit", "fighterItem", "projectedFighter") def getText(self, itmContext, selection): return u"Change {0} Quantity".format(itmContext) @@ -30,7 +30,7 @@ class ChangeAmount(ContextMenu): thing = selection[0] mainFrame = gui.mainFrame.MainFrame.getInstance() fitID = mainFrame.getActiveFit() - + srcContext = fullContext[0] if isinstance(thing, es_Fit): value = thing.getProjectionInfo(fitID).amount else: @@ -50,7 +50,10 @@ class ChangeAmount(ContextMenu): self.mainFrame.command.Submit(cmd.GuiChangeCargoQty(fitID, fit.cargo.index(thing), int(float(cleanInput)))) return # no need for post event here elif isinstance(thing, Drone): - self.mainFrame.command.Submit(cmd.GuiChangeDroneQty(fitID, fit.drones.index(thing), int(float(cleanInput)))) + if srcContext == "droneItem": + self.mainFrame.command.Submit(cmd.GuiChangeDroneQty(fitID, fit.drones.index(thing), int(float(cleanInput)))) + else: + self.mainFrame.command.Submit(cmd.GuiChangeProjectedDroneQty(fitID, fit.projectedDrones.index(thing), int(float(cleanInput)))) elif isinstance(thing, es_Fit): self.mainFrame.command.Submit(cmd.GuiChangeProjectedFitQty(fitID, thing.ID, int(float(cleanInput)))) return diff --git a/gui/builtinContextMenus/boosterSideEffects.py b/gui/builtinContextMenus/boosterSideEffects.py index a936e9340..eb162c3e7 100644 --- a/gui/builtinContextMenus/boosterSideEffects.py +++ b/gui/builtinContextMenus/boosterSideEffects.py @@ -50,7 +50,7 @@ class BoosterSideEffect(ContextMenu): if not effect.effect.isImplemented: continue menuItem = self.addEffect(rootMenu if msw else sub, effect) - sub.AppendItem(menuItem) + sub.Append(menuItem) menuItem.Check(effect.active) return sub diff --git a/gui/builtinContextMenus/metaSwap.py b/gui/builtinContextMenus/metaSwap.py index 1c4be8017..9909ab9fa 100644 --- a/gui/builtinContextMenus/metaSwap.py +++ b/gui/builtinContextMenus/metaSwap.py @@ -91,7 +91,7 @@ class MetaSwap(ContextMenu): # Sort items by metalevel, and group within that metalevel items = list(self.variations) - print(context) + if "implantItem" in context: # sort implants based on name items.sort(key=lambda x: x.name) @@ -122,7 +122,7 @@ class MetaSwap(ContextMenu): id = ContextMenu.nextID() mitem = wx.MenuItem(rootMenu, id, item.name) bindmenu.Bind(wx.EVT_MENU, self.handleModule, mitem) - print(context) + self.moduleLookup[id] = item, context m.Append(mitem) return m diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index 93d012975..2fce1e1c6 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -28,4 +28,5 @@ from .guiRemoveDrone import GuiRemoveDroneCommand from .guiChangeFighterQty import GuiChangeFighterQty from .guiChangeCargoQty import GuiChangeCargoQty from .guiChangeProjectedFitQty import GuiChangeProjectedFitQty -from .guiChangeDroneQty import GuiChangeDroneQty \ No newline at end of file +from .guiChangeDroneQty import GuiChangeDroneQty +from.guiChangeProjectedDroneQty import GuiChangeProjectedDroneQty \ No newline at end of file diff --git a/gui/fitCommands/calc/fitChangeProjectedDroneQty.py b/gui/fitCommands/calc/fitChangeProjectedDroneQty.py new file mode 100644 index 000000000..0ac99c098 --- /dev/null +++ b/gui/fitCommands/calc/fitChangeProjectedDroneQty.py @@ -0,0 +1,32 @@ +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 FitChangeProjectedDroneQty(wx.Command): + def __init__(self, fitID, position, amount=1): + wx.Command.__init__(self, True, "Drone add") + self.fitID = fitID + self.position = position + self.amount = amount # add x amount. If this goes over amount, removes stack + self.old_amount = None + + def Do(self): + pyfalog.debug("Changing active fighters ({0}) for fit ({1}) to amount: {2}", self.position, self.fitID, self.amount) + fit = eos.db.getFit(self.fitID) + drone = fit.projectedDrones[self.position] + self.old_amount = drone.amount + drone.amount = self.amount + + eos.db.commit() + return True + + def Undo(self): + cmd = FitChangeProjectedDroneQty(self.fitID, self.position, self.old_amount) + return cmd.Do() diff --git a/gui/fitCommands/guiChangeProjectedDroneQty.py b/gui/fitCommands/guiChangeProjectedDroneQty.py new file mode 100644 index 000000000..38fcf31f9 --- /dev/null +++ b/gui/fitCommands/guiChangeProjectedDroneQty.py @@ -0,0 +1,39 @@ +import wx +import eos.db +import gui.mainFrame +from service.fit import Fit +from gui import globalEvents as GE +from .calc.fitAddModule import FitAddModuleCommand +from .calc.fitReplaceModule import FitReplaceModuleCommand +from .calc.fitChangeProjectedDroneQty import FitChangeProjectedDroneQty +from service.fit import Fit +from logbook import Logger +pyfalog = Logger(__name__) + + +class GuiChangeProjectedDroneQty(wx.Command): + def __init__(self, fitID, position, amount=1): + wx.Command.__init__(self, True, "") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.fitID = fitID + self.position = position + self.amount = amount + self.internal_history = wx.CommandProcessor() + + def Do(self): + cmd = FitChangeProjectedDroneQty(self.fitID, self.position, self.amount) + if self.internal_history.Submit(cmd): + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + + def Undo(self): + pyfalog.debug("{} Undo()".format(self)) + for _ in self.internal_history.Commands: + self.internal_history.Undo() + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True From 7e94914f6591f3d9b631cb2af8716c81ff84803c Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 18 Aug 2018 01:09:37 -0400 Subject: [PATCH 54/95] Implement drone toggle command --- gui/builtinAdditionPanes/droneView.py | 4 +- gui/fitCommands/__init__.py | 3 +- gui/fitCommands/calc/fitToggleDrone.py | 35 ++++++++++ gui/fitCommands/guiToggleDrone.py | 30 +++++++++ service/fit.py | 86 ------------------------ service/fitDeprecated.py | 91 ++++++++++++++++++++++++++ 6 files changed, 159 insertions(+), 90 deletions(-) create mode 100644 gui/fitCommands/calc/fitToggleDrone.py create mode 100644 gui/fitCommands/guiToggleDrone.py diff --git a/gui/builtinAdditionPanes/droneView.py b/gui/builtinAdditionPanes/droneView.py index 6e236d0fd..e95906ae9 100644 --- a/gui/builtinAdditionPanes/droneView.py +++ b/gui/builtinAdditionPanes/droneView.py @@ -239,10 +239,8 @@ class DroneView(Display): col = self.getColumn(event.Position) if col == self.getColIndex(State): fitID = self.mainFrame.getActiveFit() - sFit = Fit.getInstance() drone = self.drones[row] - sFit.toggleDrone(fitID, self.original.index(drone)) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + self.mainFrame.command.Submit(cmd.GuiToggleDroneCommand(fitID, self.original.index(drone))) def scheduleMenu(self, event): event.Skip() diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index 2fce1e1c6..1c1e3905e 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -29,4 +29,5 @@ from .guiChangeFighterQty import GuiChangeFighterQty from .guiChangeCargoQty import GuiChangeCargoQty from .guiChangeProjectedFitQty import GuiChangeProjectedFitQty from .guiChangeDroneQty import GuiChangeDroneQty -from.guiChangeProjectedDroneQty import GuiChangeProjectedDroneQty \ No newline at end of file +from .guiChangeProjectedDroneQty import GuiChangeProjectedDroneQty +from .guiToggleDrone import GuiToggleDroneCommand \ No newline at end of file diff --git a/gui/fitCommands/calc/fitToggleDrone.py b/gui/fitCommands/calc/fitToggleDrone.py new file mode 100644 index 000000000..a10796888 --- /dev/null +++ b/gui/fitCommands/calc/fitToggleDrone.py @@ -0,0 +1,35 @@ +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 FitToggleDroneCommand(wx.Command): + """" + from sFit.toggleDrone + """ + def __init__(self, fitID, position): + wx.Command.__init__(self, True, "Cargo add") + self.fitID = fitID + self.position = position + + def Do(self): + pyfalog.debug("Toggling drones for fit ID: {0}", self.fitID) + fit = eos.db.getFit(self.fitID) + d = fit.drones[self.position] + if d.amount == d.amountActive: + d.amountActive = 0 + else: + d.amountActive = d.amount + + eos.db.commit() + return True + + def Undo(self): + cmd = FitToggleDroneCommand(self.fitID, self.position) + return cmd.Do() diff --git a/gui/fitCommands/guiToggleDrone.py b/gui/fitCommands/guiToggleDrone.py new file mode 100644 index 000000000..3dc8c4cec --- /dev/null +++ b/gui/fitCommands/guiToggleDrone.py @@ -0,0 +1,30 @@ +import wx +from service.fit import Fit + +import gui.mainFrame +from gui import globalEvents as GE +from .calc.fitToggleDrone import FitToggleDroneCommand + +class GuiToggleDroneCommand(wx.Command): + def __init__(self, fitID, position): + wx.Command.__init__(self, True, "") + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.internal_history = wx.CommandProcessor() + self.fitID = fitID + self.position = position + + def Do(self): + if self.internal_history.Submit(FitToggleDroneCommand(self.fitID, self.position)): + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + return False + + def Undo(self): + for _ in self.internal_history.Commands: + self.internal_history.Undo() + self.sFit.recalc(self.fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) + return True + diff --git a/service/fit.py b/service/fit.py index 6ed79829d..1f4b417dd 100644 --- a/service/fit.py +++ b/service/fit.py @@ -438,92 +438,6 @@ class Fit(FitDeprecated): else: return False - def mergeDrones(self, fitID, d1, d2, projected=False): - pyfalog.debug("Merging drones on fit ID: {0}", fitID) - if fitID is None: - return False - - fit = eos.db.getFit(fitID) - if d1.item != d2.item: - return False - - if projected: - fit.projectedDrones.remove(d1) - else: - fit.drones.remove(d1) - - d2.amount += d1.amount - d2.amountActive += d1.amountActive - - # If we have less than the total number of drones active, make them all active. Fixes #728 - # This could be removed if we ever add an enhancement to make drone stacks partially active. - if d2.amount > d2.amountActive: - d2.amountActive = d2.amount - - eos.db.commit() - self.recalc(fit) - return True - - @staticmethod - def splitDrones(fit, d, amount, l): - pyfalog.debug("Splitting drones for fit ID: {0}", fit) - total = d.amount - active = d.amountActive > 0 - d.amount = amount - d.amountActive = amount if active else 0 - - newD = es_Drone(d.item) - newD.amount = total - amount - newD.amountActive = newD.amount if active else 0 - l.append(newD) - eos.db.commit() - - def splitProjectedDroneStack(self, fitID, d, amount): - pyfalog.debug("Splitting projected drone stack for fit ID: {0}", fitID) - if fitID is None: - return False - - fit = eos.db.getFit(fitID) - self.splitDrones(fit, d, amount, fit.projectedDrones) - - def splitDroneStack(self, fitID, d, amount): - pyfalog.debug("Splitting drone stack for fit ID: {0}", fitID) - if fitID is None: - return False - - fit = eos.db.getFit(fitID) - self.splitDrones(fit, d, amount, fit.drones) - - @deprecated - def removeDrone(self, fitID, i, numDronesToRemove=1, recalc=True): - pyfalog.debug("Removing {0} drones for fit ID: {1}", numDronesToRemove, fitID) - fit = eos.db.getFit(fitID) - d = fit.drones[i] - d.amount -= numDronesToRemove - if d.amountActive > 0: - d.amountActive -= numDronesToRemove - - if d.amount == 0: - del fit.drones[i] - - eos.db.commit() - if recalc: - self.recalc(fit) - return True - - def toggleDrone(self, fitID, i): - pyfalog.debug("Toggling drones for fit ID: {0}", fitID) - fit = eos.db.getFit(fitID) - d = fit.drones[i] - if d.amount == d.amountActive: - d.amountActive = 0 - else: - d.amountActive = d.amount - - eos.db.commit() - self.recalc(fit) - return True - def toggleImplantSource(self, fitID, source): pyfalog.debug("Toggling implant source for fit ID: {0}", fitID) fit = eos.db.getFit(fitID) diff --git a/service/fitDeprecated.py b/service/fitDeprecated.py index 165d929eb..e36014364 100644 --- a/service/fitDeprecated.py +++ b/service/fitDeprecated.py @@ -36,6 +36,97 @@ pyfalog = Logger(__name__) class FitDeprecated(object): + @deprecated + def toggleDrone(self, fitID, i): + pyfalog.debug("Toggling drones for fit ID: {0}", fitID) + fit = eos.db.getFit(fitID) + d = fit.drones[i] + if d.amount == d.amountActive: + d.amountActive = 0 + else: + d.amountActive = d.amount + + eos.db.commit() + self.recalc(fit) + return True + + @deprecated + def mergeDrones(self, fitID, d1, d2, projected=False): + pyfalog.debug("Merging drones on fit ID: {0}", fitID) + if fitID is None: + return False + + fit = eos.db.getFit(fitID) + if d1.item != d2.item: + return False + + if projected: + fit.projectedDrones.remove(d1) + else: + fit.drones.remove(d1) + + d2.amount += d1.amount + d2.amountActive += d1.amountActive + + # If we have less than the total number of drones active, make them all active. Fixes #728 + # This could be removed if we ever add an enhancement to make drone stacks partially active. + if d2.amount > d2.amountActive: + d2.amountActive = d2.amount + + eos.db.commit() + self.recalc(fit) + return True + + @staticmethod + @deprecated + def splitDrones(fit, d, amount, l): + pyfalog.debug("Splitting drones for fit ID: {0}", fit) + total = d.amount + active = d.amountActive > 0 + d.amount = amount + d.amountActive = amount if active else 0 + + newD = es_Drone(d.item) + newD.amount = total - amount + newD.amountActive = newD.amount if active else 0 + l.append(newD) + eos.db.commit() + + @deprecated + def splitProjectedDroneStack(self, fitID, d, amount): + pyfalog.debug("Splitting projected drone stack for fit ID: {0}", fitID) + if fitID is None: + return False + + fit = eos.db.getFit(fitID) + self.splitDrones(fit, d, amount, fit.projectedDrones) + + @deprecated + def splitDroneStack(self, fitID, d, amount): + pyfalog.debug("Splitting drone stack for fit ID: {0}", fitID) + if fitID is None: + return False + + fit = eos.db.getFit(fitID) + self.splitDrones(fit, d, amount, fit.drones) + + @deprecated + def removeDrone(self, fitID, i, numDronesToRemove=1, recalc=True): + pyfalog.debug("Removing {0} drones for fit ID: {1}", numDronesToRemove, fitID) + fit = eos.db.getFit(fitID) + d = fit.drones[i] + d.amount -= numDronesToRemove + if d.amountActive > 0: + d.amountActive -= numDronesToRemove + + if d.amount == 0: + del fit.drones[i] + + eos.db.commit() + if recalc: + self.recalc(fit) + return True + @deprecated def changeAmount(self, fitID, projected_fit, amount): """Change amount of projected fits""" From 82d8c95d2fac205e1d054f2d1af0f53307818496 Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Thu, 23 Aug 2018 19:22:24 +0300 Subject: [PATCH 55/95] Rework export format for abyssal mods, now uses references --- service/port.py | 54 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/service/port.py b/service/port.py index 5ad5c4ed3..87ed7ac46 100644 --- a/service/port.py +++ b/service/port.py @@ -1066,7 +1066,7 @@ class Port(object): @classmethod - def exportEft(cls, fit, mutations=False, implants=False): + def exportEft(cls, fit, mutations=True, implants=False): # EFT formatted export is split in several sections, each section is # separated from another using 2 blank lines. Sections might have several # sub-sections, which are separated by 1 blank line @@ -1075,37 +1075,33 @@ class Port(object): header = '[{}, {}]'.format(fit.ship.item.name, fit.name) # Section 1: modules, rigs, subsystems, services - def formatAttrVal(val): - if int(val) == val: - return int(val) - return val - offineSuffix = ' /OFFLINE' modsBySlotType = {} + # Format: {reference number: module} + mutants = {} + mutantReference = 1 sFit = svcFit.getInstance() for module in fit.modules: slot = module.slot slotTypeMods = modsBySlotType.setdefault(slot, []) if module.item: - mutatedMod = bool(module.mutators) + mutated = bool(module.mutators) # if module was mutated, use base item name for export - if mutatedMod: + if mutated: modName = module.baseItem.name else: modName = module.item.name + if mutated and mutations: + mutants[mutantReference] = module + mutationSuffix = ' [{}]'.format(mutantReference) + mutantReference += 1 + else: + mutationSuffix = '' modOfflineSuffix = offineSuffix if module.state == State.OFFLINE else '' if module.charge and sFit.serviceFittingOptions['exportCharges']: - slotTypeMods.append('{}, {}{}'.format(modName, module.charge.name, modOfflineSuffix)) + slotTypeMods.append('{}, {}{}{}'.format(modName, module.charge.name, modOfflineSuffix, mutationSuffix)) else: - slotTypeMods.append('{}{}'.format(modName, modOfflineSuffix)) - if mutatedMod and mutations: - mutationGrade = module.mutaplasmid.item.name.split(' ', 1)[0].lower() - mutatedAttrs = {} - for attrID, mutator in module.mutators.items(): - attrName = getAttributeInfo(attrID).name - mutatedAttrs[attrName] = mutator.value - customAttrsLine = ', '.join('{} {}'.format(a, formatAttrVal(mutatedAttrs[a])) for a in sorted(mutatedAttrs)) - slotTypeMods.append(' {}: {}'.format(mutationGrade, customAttrsLine)) + slotTypeMods.append('{}{}{}'.format(modName, modOfflineSuffix, mutationSuffix)) else: slotTypeMods.append('[Empty {} slot]'.format(Slot.getName(slot).capitalize() if slot is not None else '')) modSection = [] @@ -1157,6 +1153,28 @@ class Port(object): if cargoLines: sections.append('\n'.join(cargoLines)) + # Section 5: mutated modules' details + mutationLines = [] + if mutants and mutations: + + def formatAttrVal(val): + if int(val) == val: + return int(val) + return val + + for mutantReference in sorted(mutants): + mutant = mutants[mutantReference] + mutatedAttrs = {} + for attrID, mutator in mutant.mutators.items(): + attrName = getAttributeInfo(attrID).name + mutatedAttrs[attrName] = mutator.value + mutationLines.append('[{}] {}'.format(mutantReference, mutant.baseItem.name)) + mutationLines.append(' {}'.format(mutant.mutaplasmid.item.name)) + customAttrsLine = ', '.join('{} {}'.format(a, formatAttrVal(mutatedAttrs[a])) for a in sorted(mutatedAttrs)) + mutationLines.append(' {}'.format(customAttrsLine)) + if mutationLines: + sections.append('\n'.join(mutationLines)) + return '{}\n\n{}'.format(header, '\n\n\n'.join(sections)) @classmethod From 13498e9b35e7ed401a73b690e793ac29ab932642 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Thu, 23 Aug 2018 21:46:13 -0400 Subject: [PATCH 56/95] bump --- config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.py b/config.py index 7afe652f5..50894c424 100644 --- a/config.py +++ b/config.py @@ -24,7 +24,7 @@ saveInRoot = False # Version data -version = "2.4.0" +version = "2.5.0b1" tag = "Stable" expansionName = "YC120.8" expansionVersion = "1.0" From 6240f23c02fd957b48bbdacb1b6cca7dc39abeb5 Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Fri, 24 Aug 2018 09:54:03 +0300 Subject: [PATCH 57/95] Enumerate mutated modules based on their export order rather than how pyfa order, and round attribute values to avoid float errors --- service/port.py | 65 +++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/service/port.py b/service/port.py index 87ed7ac46..d964f7bb5 100644 --- a/service/port.py +++ b/service/port.py @@ -33,6 +33,7 @@ import xml.parsers.expat from eos import db from eos.db.gamedata.queries import getAttributeInfo +from gui.utils.numberFormatter import roundToPrec from service.fit import Fit as svcFit # noinspection PyPackageRequirements @@ -1075,41 +1076,40 @@ class Port(object): header = '[{}, {}]'.format(fit.ship.item.name, fit.name) # Section 1: modules, rigs, subsystems, services - offineSuffix = ' /OFFLINE' modsBySlotType = {} - # Format: {reference number: module} - mutants = {} - mutantReference = 1 sFit = svcFit.getInstance() for module in fit.modules: slot = module.slot - slotTypeMods = modsBySlotType.setdefault(slot, []) - if module.item: - mutated = bool(module.mutators) - # if module was mutated, use base item name for export - if mutated: - modName = module.baseItem.name - else: - modName = module.item.name - if mutated and mutations: - mutants[mutantReference] = module - mutationSuffix = ' [{}]'.format(mutantReference) - mutantReference += 1 - else: - mutationSuffix = '' - modOfflineSuffix = offineSuffix if module.state == State.OFFLINE else '' - if module.charge and sFit.serviceFittingOptions['exportCharges']: - slotTypeMods.append('{}, {}{}{}'.format(modName, module.charge.name, modOfflineSuffix, mutationSuffix)) - else: - slotTypeMods.append('{}{}{}'.format(modName, modOfflineSuffix, mutationSuffix)) - else: - slotTypeMods.append('[Empty {} slot]'.format(Slot.getName(slot).capitalize() if slot is not None else '')) + modsBySlotType.setdefault(slot, []).append(module) + # Format: {reference number: module} modSection = [] + offineSuffix = ' /OFFLINE' + mutants = {} + mutantReference = 1 for slotType in EFT_SLOT_ORDER: rackLines = [] - data = modsBySlotType.get(slotType, ()) - for line in data: - rackLines.append(line) + modules = modsBySlotType.get(slotType, ()) + for module in modules: + if module.item: + mutated = bool(module.mutators) + # if module was mutated, use base item name for export + if mutated: + modName = module.baseItem.name + else: + modName = module.item.name + if mutated and mutations: + mutants[mutantReference] = module + mutationSuffix = ' [{}]'.format(mutantReference) + mutantReference += 1 + else: + mutationSuffix = '' + modOfflineSuffix = offineSuffix if module.state == State.OFFLINE else '' + if module.charge and sFit.serviceFittingOptions['exportCharges']: + rackLines.append('{}, {}{}{}'.format(modName, module.charge.name, modOfflineSuffix, mutationSuffix)) + else: + rackLines.append('{}{}{}'.format(modName, modOfflineSuffix, mutationSuffix)) + else: + rackLines.append('[Empty {} slot]'.format(Slot.getName(slotType).capitalize() if slotType is not None else '')) if rackLines: modSection.append('\n'.join(rackLines)) if modSection: @@ -1156,12 +1156,6 @@ class Port(object): # Section 5: mutated modules' details mutationLines = [] if mutants and mutations: - - def formatAttrVal(val): - if int(val) == val: - return int(val) - return val - for mutantReference in sorted(mutants): mutant = mutants[mutantReference] mutatedAttrs = {} @@ -1170,7 +1164,8 @@ class Port(object): mutatedAttrs[attrName] = mutator.value mutationLines.append('[{}] {}'.format(mutantReference, mutant.baseItem.name)) mutationLines.append(' {}'.format(mutant.mutaplasmid.item.name)) - customAttrsLine = ', '.join('{} {}'.format(a, formatAttrVal(mutatedAttrs[a])) for a in sorted(mutatedAttrs)) + # Round to 7th significant number to avoid exporting float errors + customAttrsLine = ', '.join('{} {}'.format(a, roundToPrec(mutatedAttrs[a], 7)) for a in sorted(mutatedAttrs)) mutationLines.append(' {}'.format(customAttrsLine)) if mutationLines: sections.append('\n'.join(mutationLines)) From 0a2fa62e21e37c4e3d8c9133d18572a5848a7884 Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Fri, 24 Aug 2018 09:55:32 +0300 Subject: [PATCH 58/95] Fix misplaced comment --- service/port.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/service/port.py b/service/port.py index d964f7bb5..13795c65e 100644 --- a/service/port.py +++ b/service/port.py @@ -1081,10 +1081,9 @@ class Port(object): for module in fit.modules: slot = module.slot modsBySlotType.setdefault(slot, []).append(module) - # Format: {reference number: module} modSection = [] offineSuffix = ' /OFFLINE' - mutants = {} + mutants = {} # Format: {reference number: module} mutantReference = 1 for slotType in EFT_SLOT_ORDER: rackLines = [] From 83222489c4b039108671f93f7bd8060051e96278 Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Fri, 24 Aug 2018 10:01:31 +0300 Subject: [PATCH 59/95] Condense code a bit more --- service/port.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/service/port.py b/service/port.py index 13795c65e..f5fec6378 100644 --- a/service/port.py +++ b/service/port.py @@ -1079,8 +1079,7 @@ class Port(object): modsBySlotType = {} sFit = svcFit.getInstance() for module in fit.modules: - slot = module.slot - modsBySlotType.setdefault(slot, []).append(module) + modsBySlotType.setdefault(module.slot, []).append(module) modSection = [] offineSuffix = ' /OFFLINE' mutants = {} # Format: {reference number: module} From 66d559306fbdd7776bc207b359b85ddff6863172 Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Fri, 24 Aug 2018 10:03:44 +0300 Subject: [PATCH 60/95] Avoid doing too wide lines --- service/port.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/service/port.py b/service/port.py index f5fec6378..8a6cf7343 100644 --- a/service/port.py +++ b/service/port.py @@ -1103,11 +1103,13 @@ class Port(object): mutationSuffix = '' modOfflineSuffix = offineSuffix if module.state == State.OFFLINE else '' if module.charge and sFit.serviceFittingOptions['exportCharges']: - rackLines.append('{}, {}{}{}'.format(modName, module.charge.name, modOfflineSuffix, mutationSuffix)) + rackLines.append('{}, {}{}{}'.format( + modName, module.charge.name, modOfflineSuffix, mutationSuffix)) else: rackLines.append('{}{}{}'.format(modName, modOfflineSuffix, mutationSuffix)) else: - rackLines.append('[Empty {} slot]'.format(Slot.getName(slotType).capitalize() if slotType is not None else '')) + rackLines.append('[Empty {} slot]'.format( + Slot.getName(slotType).capitalize() if slotType is not None else '')) if rackLines: modSection.append('\n'.join(rackLines)) if modSection: @@ -1146,7 +1148,10 @@ class Port(object): # Section 4: cargo cargoLines = [] - for cargo in sorted(fit.cargo, key=lambda c: (c.item.group.category.name, c.item.group.name, c.item.name)): + for cargo in sorted( + fit.cargo, + key=lambda c: (c.item.group.category.name, c.item.group.name, c.item.name) + ): cargoLines.append('{} x{}'.format(cargo.item.name, cargo.amount)) if cargoLines: sections.append('\n'.join(cargoLines)) @@ -1163,7 +1168,9 @@ class Port(object): mutationLines.append('[{}] {}'.format(mutantReference, mutant.baseItem.name)) mutationLines.append(' {}'.format(mutant.mutaplasmid.item.name)) # Round to 7th significant number to avoid exporting float errors - customAttrsLine = ', '.join('{} {}'.format(a, roundToPrec(mutatedAttrs[a], 7)) for a in sorted(mutatedAttrs)) + customAttrsLine = ', '.join( + '{} {}'.format(a, roundToPrec(mutatedAttrs[a], 7)) + for a in sorted(mutatedAttrs)) mutationLines.append(' {}'.format(customAttrsLine)) if mutationLines: sections.append('\n'.join(mutationLines)) From 4a27c60486c5b6355e8e99054d295ab7bd496432 Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Fri, 24 Aug 2018 13:25:41 +0300 Subject: [PATCH 61/95] Clean up the fit being imported before parsing --- service/port.py | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/service/port.py b/service/port.py index 8a6cf7343..a0f8ddf32 100644 --- a/service/port.py +++ b/service/port.py @@ -625,21 +625,28 @@ class Port(object): @staticmethod def importEft(eftString): + # Split passed string in lines and clean them up + lines = eftString.splitlines() + for i in range(len(lines)): + lines[i] = lines[i].strip() + while lines and not lines[0]: + del lines[0] + while lines and not lines[-1]: + del lines[-1] + sMkt = Market.getInstance() - offineSuffix = " /OFFLINE" + offineSuffix = ' /OFFLINE' fit = Fit() - eftString = eftString.strip() - lines = re.split('[\n\r]+', eftString) - info = lines[0][1:-1].split(",", 1) - - if len(info) == 2: - shipType = info[0].strip() - fitName = info[1].strip() - else: - shipType = info[0].strip() - fitName = "Imported %s" % shipType + # Ship and fit name from header + header = lines.pop(0) + m = re.match('\[(?P[\w\s]+), (?P.+)\]', header) + if not m: + pyfalog.warning('Corrupted fit header in importEft') + return + shipType = m.group('shipType').strip() + fitName = m.group('fitName').strip() try: ship = sMkt.getItem(shipType) try: From 2dd1ddddd59266f9d812793f1be6e3dccda801e1 Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Fri, 24 Aug 2018 18:57:42 +0300 Subject: [PATCH 62/95] Further rework of import function --- service/port.py | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/service/port.py b/service/port.py index a0f8ddf32..f67c6e4ff 100644 --- a/service/port.py +++ b/service/port.py @@ -658,6 +658,91 @@ class Port(object): pyfalog.warning("Exception caught in importEft") return + def sectionIter(lines): + section = [] + for line in lines: + if not line: + if section: + yield section + section = [] + section.append(line) + if section: + yield section + + stubPattern = '^\[.+\]$' + modulePattern = '^(?P[^,/]+)(, (?P[^,/]+))?(?P /OFFLINE)?( \[(?P\d+)\])?$' + droneCargoPattern = '^(?P[^,/]+) x(?P\d+)$' + + sections = [] + for section in sectionIter(lines): + sectionItemData = [] + for line in section: + # Stub line + if re.match(stubPattern, line): + sectionItemData.append({'type': 'stub'}) + continue + # Items with quantity specifier + m = re.match(droneCargoPattern, line) + if m: + sectionItemData.append({ + 'type': 'multi', + 'typeName': m.group('typeName'), + 'amount': int(m.group('amount'))}) + continue + # All other items + m = re.match(modulePattern, line) + if m: + sectionItemData.append({ + 'type': 'normal', + 'typeName': m.group('typeName'), + 'chargeName': m.group('charge'), + 'offline': True if m.group('offline') else False, + 'mutation': int(m.group('mutation')) if m.group('mutation') else None}) + # Strip stubs from tail + while sectionItemData and sectionItemData[-1]['type'] == 'stub': + del sectionItemData[-1] + if sectionItemData: + sections.append(sectionItemData) + + + + for sectionItemData in sections: + sectionCats = set() + for entry in sectionItemData: + if entry['type'] == 'stub': + continue + try: + item = sMkt.getItem(entry['typeName'], eager='group.category') + except: + pyfalog.warning('no data can be found (old names)') + entry['type'] = 'stub' + continue + entry['item'] = item + import sys + sys.stderr.write('{}\n'.format(item.slot)) + sectionCats.add(item.category.name) + processStubs = ( + # To process stubs, we must make sure that all the items in section + # are from the same category + len(sectionCats) == 1 and tuple(sectionCats)[0] == 'Module' and + # And that they do not contain items with quantity specifier + all(i['type'] in ('stub', 'normal') for i in sectionItemData)) + isDronebay = ( + len(sectionCats) == 1 and tuple(sectionCats)[0] == 'Drone' and + all(i['type'] == 'multi' for i in sectionItemData)) + isFighterbay = ( + len(sectionCats) == 1 and tuple(sectionCats)[0] == 'Fighter' and + all(i['type'] == 'multi' for i in sectionItemData)) + + + + + + + + + + # maintain map of drones and their quantities droneMap = {} cargoMap = {} From a8c69abc72ae817d28f4213be4ceeb2d70aad2d0 Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Sat, 25 Aug 2018 11:06:33 +0300 Subject: [PATCH 63/95] Move EFT import/export related functions to separate file --- service/eftPort.py | 526 +++++++++++++++++++++++++++++++++++++++++++++ service/port.py | 371 +------------------------------- 2 files changed, 534 insertions(+), 363 deletions(-) create mode 100644 service/eftPort.py diff --git a/service/eftPort.py b/service/eftPort.py new file mode 100644 index 000000000..de69bd966 --- /dev/null +++ b/service/eftPort.py @@ -0,0 +1,526 @@ +# ============================================================================= +# Copyright (C) 2014 Ryan Holmes +# +# 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 . +# ============================================================================= + + +import re + +from logbook import Logger + +from eos.db.gamedata.queries import getAttributeInfo +from eos.saveddata.citadel import Citadel +from eos.saveddata.module import Module, Slot, State +from eos.saveddata.ship import Ship +from gui.utils.numberFormatter import roundToPrec +from service.fit import Fit as svcFit +from service.market import Market + + +pyfalog = Logger(__name__) + + +def fetchItem(typeName, eagerCat=True): + sMkt = Market.getInstance() + eager = 'group.category' if eagerCat else None + try: + return sMkt.getItem(typeName, eager=eager) + except: + pyfalog.warning('EftPort: unable to fetch item "{}"'.format(typeName)) + return + + +class EftImportError(Exception): + """Exception class emitted and consumed by EFT importer/exporter internally.""" + ... + + +class AmountMap(dict): + + def add(self, entity, amount): + if entity not in self: + self[entity] = 0 + self[entity] += amount + + +class AbstractFit: + + def __init__(self): + self.modulesHigh = [] + self.modulesMed = [] + self.modulesLow = [] + self.rigs = [] + self.subsystems = [] + self.services = [] + self.drones = AmountMap() + self.fighters = AmountMap() + self.implants = set() + self.boosters = set() + self.cargo = AmountMap() + + # def addModule(self, m): + # modContMap = { + # Slot.HIGH: self.modulesHigh, + # Slot.MED: self.modulesMed, + # Slot.LOW: self.modulesLow, + # Slot.RIG: self.rigs, + # Slot.SUBSYSTEM: self.subsystems, + # Slot.SERVICE: self.services} + + +class Section: + + def __init__(self): + self.lines = [] + self.itemData = [] + self.__itemDataCats = None + + @property + def itemDataCats(self): + if self.__itemDataCats is None: + cats = set() + for itemSpec in self.itemData: + if itemSpec is None: + continue + cats.add(itemSpec.item.category.name) + self.__itemDataCats = tuple(sorted(cats)) + return self.__itemDataCats + + def cleanItemDataTail(self): + while self.itemData and self.itemData[-1] is None: + del self.itemData[-1] + + +class BaseItemSpec: + + def __init__(self, typeName): + item = fetchItem(typeName, eagerCat=True) + if item is None: + raise EftImportError + self.typeName = typeName + self.item = item + + +class ItemSpec(BaseItemSpec): + + def __init__(self, typeName, chargeName=None): + super().__init__(typeName) + self.charge = self.__fetchCharge(chargeName) + self.offline = False + self.mutationIdx = None + + def __fetchCharge(self, chargeName): + if chargeName: + charge = fetchItem(chargeName, eagerCat=True) + if charge.category.name != 'Charge': + charge = None + else: + charge = None + return charge + + +class MultiItemSpec(BaseItemSpec): + + def __init__(self, typeName): + super().__init__(typeName) + self.amount = 0 + + +class EftPort: + + SLOT_ORDER = [Slot.LOW, Slot.MED, Slot.HIGH, Slot.RIG, Slot.SUBSYSTEM, Slot.SERVICE] + OFFLINE_SUFFIX = ' /OFFLINE' + + @classmethod + def exportEft(cls, fit, mutations, implants): + # EFT formatted export is split in several sections, each section is + # separated from another using 2 blank lines. Sections might have several + # sub-sections, which are separated by 1 blank line + sections = [] + + header = '[{}, {}]'.format(fit.ship.item.name, fit.name) + + # Section 1: modules, rigs, subsystems, services + modsBySlotType = {} + sFit = svcFit.getInstance() + for module in fit.modules: + modsBySlotType.setdefault(module.slot, []).append(module) + modSection = [] + + mutants = {} # Format: {reference number: module} + mutantReference = 1 + for slotType in cls.SLOT_ORDER: + rackLines = [] + modules = modsBySlotType.get(slotType, ()) + for module in modules: + if module.item: + mutated = bool(module.mutators) + # if module was mutated, use base item name for export + if mutated: + modName = module.baseItem.name + else: + modName = module.item.name + if mutated and mutations: + mutants[mutantReference] = module + mutationSuffix = ' [{}]'.format(mutantReference) + mutantReference += 1 + else: + mutationSuffix = '' + modOfflineSuffix = cls.OFFLINE_SUFFIX if module.state == State.OFFLINE else '' + if module.charge and sFit.serviceFittingOptions['exportCharges']: + rackLines.append('{}, {}{}{}'.format( + modName, module.charge.name, modOfflineSuffix, mutationSuffix)) + else: + rackLines.append('{}{}{}'.format(modName, modOfflineSuffix, mutationSuffix)) + else: + rackLines.append('[Empty {} slot]'.format( + Slot.getName(slotType).capitalize() if slotType is not None else '')) + if rackLines: + modSection.append('\n'.join(rackLines)) + if modSection: + sections.append('\n\n'.join(modSection)) + + # Section 2: drones, fighters + minionSection = [] + droneLines = [] + for drone in sorted(fit.drones, key=lambda d: d.item.name): + droneLines.append('{} x{}'.format(drone.item.name, drone.amount)) + if droneLines: + minionSection.append('\n'.join(droneLines)) + fighterLines = [] + for fighter in sorted(fit.fighters, key=lambda f: f.item.name): + fighterLines.append('{} x{}'.format(fighter.item.name, fighter.amountActive)) + if fighterLines: + minionSection.append('\n'.join(fighterLines)) + if minionSection: + sections.append('\n\n'.join(minionSection)) + + # Section 3: implants, boosters + if implants: + charSection = [] + implantLines = [] + for implant in fit.implants: + implantLines.append(implant.item.name) + if implantLines: + charSection.append('\n'.join(implantLines)) + boosterLines = [] + for booster in fit.boosters: + boosterLines.append(booster.item.name) + if boosterLines: + charSection.append('\n'.join(boosterLines)) + if charSection: + sections.append('\n\n'.join(charSection)) + + # Section 4: cargo + cargoLines = [] + for cargo in sorted( + fit.cargo, + key=lambda c: (c.item.group.category.name, c.item.group.name, c.item.name) + ): + cargoLines.append('{} x{}'.format(cargo.item.name, cargo.amount)) + if cargoLines: + sections.append('\n'.join(cargoLines)) + + # Section 5: mutated modules' details + mutationLines = [] + if mutants and mutations: + for mutantReference in sorted(mutants): + mutant = mutants[mutantReference] + mutatedAttrs = {} + for attrID, mutator in mutant.mutators.items(): + attrName = getAttributeInfo(attrID).name + mutatedAttrs[attrName] = mutator.value + mutationLines.append('[{}] {}'.format(mutantReference, mutant.baseItem.name)) + mutationLines.append(' {}'.format(mutant.mutaplasmid.item.name)) + # Round to 7th significant number to avoid exporting float errors + customAttrsLine = ', '.join( + '{} {}'.format(a, roundToPrec(mutatedAttrs[a], 7)) + for a in sorted(mutatedAttrs)) + mutationLines.append(' {}'.format(customAttrsLine)) + if mutationLines: + sections.append('\n'.join(mutationLines)) + + return '{}\n\n{}'.format(header, '\n\n\n'.join(sections)) + + @classmethod + def importEft(cls, eftString): + lines = cls.__prepareImportString(eftString) + try: + fit = cls.__createFit(lines) + except EftImportError: + return + + aFit = AbstractFit() + + stubPattern = '^\[.+\]$' + modulePattern = '^(?P[^,/]+)(, (?P[^,/]+))?(?P{})?( \[(?P\d+)\])?$'.format(cls.OFFLINE_SUFFIX) + droneCargoPattern = '^(?P[^,/]+) x(?P\d+)$' + + dronebaySeen = False + fightersSeen = False + for section in cls.__importSectionIter(lines): + for line in section.lines: + # Stub line + if re.match(stubPattern, line): + section.itemData.append(None) + continue + # Items with quantity specifier + m = re.match(droneCargoPattern, line) + if m: + try: + itemSpec = MultiItemSpec(m.group('typeName')) + # Items which cannot be fetched are considered as stubs + except EftImportError: + section.itemData.append(None) + else: + itemSpec.amount = int(m.group('amount')) + section.itemData.append(itemSpec) + # All other items + m = re.match(modulePattern, line) + if m: + try: + itemSpec = ItemSpec(m.group('typeName'), chargeName=m.group('chargeName')) + # Items which cannot be fetched are considered as stubs + except EftImportError: + section.itemData.append(None) + else: + if m.group('offline'): + itemSpec.offline = True + if m.group('mutation'): + itemSpec.mutationIdx = int(m.group('mutation')) + section.itemData.append(itemSpec) + section.cleanItemDataTail() + # Finally, start putting items into intermediate containers + # All items in section have quantity specifier + if all(isinstance(id, MultiItemSpec) for id in section.itemData): + # Dronebay + if len(section.itemDataCats) == 1 and section.itemDataCats[0] == 'Drone' and not dronebaySeen: + for entry in section.itemData: + aFit.drones.add(entry['typeName'], entry['amount']) + dronebaySeen = True + # Fighters + elif len(section.itemDataCats) == 1 and section.itemDataCats[0] == 'Fighter' and not fightersSeen: + for entry in section.itemData: + aFit.fighters.add(entry['typeName'], entry['amount']) + fightersSeen = True + # Cargo + else: + for entry in section.itemData: + aFit.cargo.add(entry['typeName'], entry['amount']) + # All of items are normal or stubs + elif all(isinstance(id, ItemSpec) or id is None for id in section.itemData): + if len(section.itemDataCats) == 1: + if section.itemDataCats[0] in ('Module', 'Subsystem', 'Structure Module'): + slotTypes = set() + for entry in itemData: + if entry['type'] == 'stub': + continue + try: + m = Module(entry['item']) + except ValueError: + m = None + else: + slotTypes.add(m.slot) + entry['module'] = m + # If whole section uses container of the same type, + if len(slotTypes) == 1: + pass + else: + pass + + else: + pass + else: + pass + + # Mix between all types + else: + pass + + + + # maintain map of drones and their quantities + droneMap = {} + cargoMap = {} + moduleList = [] + for i in range(1, len(lines)): + ammoName = None + extraAmount = None + + line = lines[i].strip() + if not line: + continue + + setOffline = line.endswith(offineSuffix) + if setOffline is True: + # remove offline suffix from line + line = line[:len(line) - len(offineSuffix)] + + modAmmo = line.split(",") + # matches drone and cargo with x{qty} + modExtra = modAmmo[0].split(" x") + + if len(modAmmo) == 2: + # line with a module and ammo + ammoName = modAmmo[1].strip() + modName = modAmmo[0].strip() + elif len(modExtra) == 2: + # line with drone/cargo and qty + extraAmount = modExtra[1].strip() + modName = modExtra[0].strip() + else: + # line with just module + modName = modExtra[0].strip() + + try: + # get item information. If we are on a Drone/Cargo line, throw out cargo + item = sMkt.getItem(modName, eager="group.category") + except: + # if no data can be found (old names) + pyfalog.warning("no data can be found (old names)") + continue + + if not item.published: + continue + + if item.category.name == "Drone": + extraAmount = int(extraAmount) if extraAmount is not None else 1 + if modName not in droneMap: + droneMap[modName] = 0 + droneMap[modName] += extraAmount + elif item.category.name == "Fighter": + extraAmount = int(extraAmount) if extraAmount is not None else 1 + fighterItem = Fighter(item) + if extraAmount > fighterItem.fighterSquadronMaxSize: # Amount bigger then max fightergroup size + extraAmount = fighterItem.fighterSquadronMaxSize + if fighterItem.fits(fit): + fit.fighters.append(fighterItem) + + if len(modExtra) == 2 and item.category.name != "Drone" and item.category.name != "Fighter": + extraAmount = int(extraAmount) if extraAmount is not None else 1 + if modName not in cargoMap: + cargoMap[modName] = 0 + cargoMap[modName] += extraAmount + elif item.category.name == "Implant": + if "implantness" in item.attributes: + fit.implants.append(Implant(item)) + elif "boosterness" in item.attributes: + fit.boosters.append(Booster(item)) + else: + pyfalog.error("Failed to import implant: {0}", line) + # elif item.category.name == "Subsystem": + # try: + # subsystem = Module(item) + # except ValueError: + # continue + # + # if subsystem.fits(fit): + # fit.modules.append(subsystem) + else: + try: + m = Module(item) + except ValueError: + continue + # Add subsystems before modules to make sure T3 cruisers have subsystems installed + if item.category.name == "Subsystem": + if m.fits(fit): + fit.modules.append(m) + else: + if ammoName: + try: + ammo = sMkt.getItem(ammoName) + if m.isValidCharge(ammo) and m.charge is None: + m.charge = ammo + except: + pass + + if setOffline is True and m.isValidState(State.OFFLINE): + m.state = State.OFFLINE + elif m.isValidState(State.ACTIVE): + m.state = State.ACTIVE + + moduleList.append(m) + + # Recalc to get slot numbers correct for T3 cruisers + svcFit.getInstance().recalc(fit) + + for m in moduleList: + if m.fits(fit): + m.owner = fit + if not m.isValidState(m.state): + pyfalog.warning("Error: Module {0} cannot have state {1}", m, m.state) + + fit.modules.append(m) + + for droneName in droneMap: + d = Drone(sMkt.getItem(droneName)) + d.amount = droneMap[droneName] + fit.drones.append(d) + + for cargoName in cargoMap: + c = Cargo(sMkt.getItem(cargoName)) + c.amount = cargoMap[cargoName] + fit.cargo.append(c) + + return fit + + @staticmethod + def __prepareImportString(eftString): + lines = eftString.splitlines() + for i in range(len(lines)): + lines[i] = lines[i].strip() + while lines and not lines[0]: + del lines[0] + while lines and not lines[-1]: + del lines[-1] + return lines + + @classmethod + def __createFit(cls, lines): + """Create fit and set top-level entity (ship or citadel).""" + fit = Fit() + header = lines.pop(0) + m = re.match('\[(?P[\w\s]+), (?P.+)\]', header) + if not m: + pyfalog.warning('EftPort.importEft: corrupted fit header') + raise EftImportError + shipType = m.group('shipType').strip() + fitName = m.group('fitName').strip() + try: + ship = fetchItem(shipType, eagerCat=False) + try: + fit.ship = Ship(ship) + except ValueError: + fit.ship = Citadel(ship) + fit.name = fitName + except: + pyfalog.warning('EftPort.importEft: exception caught when parsing header') + raise EftImportError + return fit + + @staticmethod + def __importSectionIter(lines): + section = Section() + for line in lines: + if not line: + if section.lines: + yield section + section = Section() + else: + section.lines.append(line) + if section.lines: + yield section diff --git a/service/port.py b/service/port.py index f67c6e4ff..bf1ff4f90 100644 --- a/service/port.py +++ b/service/port.py @@ -32,8 +32,6 @@ from codecs import open import xml.parsers.expat from eos import db -from eos.db.gamedata.queries import getAttributeInfo -from gui.utils.numberFormatter import roundToPrec from service.fit import Fit as svcFit # noinspection PyPackageRequirements @@ -53,6 +51,7 @@ from utils.strfunctions import sequential_rep, replace_ltgt from abc import ABCMeta, abstractmethod from service.esi import Esi +from service.eftPort import EftPort from collections import OrderedDict @@ -62,7 +61,6 @@ class ESIExportException(Exception): pyfalog = Logger(__name__) -EFT_SLOT_ORDER = [Slot.LOW, Slot.MED, Slot.HIGH, Slot.RIG, Slot.SUBSYSTEM, Slot.SERVICE] INV_FLAGS = { Slot.LOW: 11, Slot.MED: 19, @@ -213,11 +211,7 @@ class IPortUser(metaclass=ABCMeta): class Port(object): - """ - 2017/03/31 NOTE: About change - 1. want to keep the description recorded in fit - 2. i think should not write wx.CallAfter in here - """ + """Service which houses all import/export format functions""" instance = None __tag_replace_flag = True @@ -351,8 +345,6 @@ class Port(object): db.save(fit) return fits - """Service which houses all import/export format functions""" - @classmethod def exportESI(cls, ofit, callback=None): # A few notes: @@ -625,248 +617,7 @@ class Port(object): @staticmethod def importEft(eftString): - # Split passed string in lines and clean them up - lines = eftString.splitlines() - for i in range(len(lines)): - lines[i] = lines[i].strip() - while lines and not lines[0]: - del lines[0] - while lines and not lines[-1]: - del lines[-1] - - sMkt = Market.getInstance() - offineSuffix = ' /OFFLINE' - - fit = Fit() - - # Ship and fit name from header - header = lines.pop(0) - m = re.match('\[(?P[\w\s]+), (?P.+)\]', header) - if not m: - pyfalog.warning('Corrupted fit header in importEft') - return - shipType = m.group('shipType').strip() - fitName = m.group('fitName').strip() - try: - ship = sMkt.getItem(shipType) - try: - fit.ship = Ship(ship) - except ValueError: - fit.ship = Citadel(ship) - fit.name = fitName - except: - pyfalog.warning("Exception caught in importEft") - return - - def sectionIter(lines): - section = [] - for line in lines: - if not line: - if section: - yield section - section = [] - section.append(line) - if section: - yield section - - stubPattern = '^\[.+\]$' - modulePattern = '^(?P[^,/]+)(, (?P[^,/]+))?(?P /OFFLINE)?( \[(?P\d+)\])?$' - droneCargoPattern = '^(?P[^,/]+) x(?P\d+)$' - - sections = [] - for section in sectionIter(lines): - sectionItemData = [] - for line in section: - # Stub line - if re.match(stubPattern, line): - sectionItemData.append({'type': 'stub'}) - continue - # Items with quantity specifier - m = re.match(droneCargoPattern, line) - if m: - sectionItemData.append({ - 'type': 'multi', - 'typeName': m.group('typeName'), - 'amount': int(m.group('amount'))}) - continue - # All other items - m = re.match(modulePattern, line) - if m: - sectionItemData.append({ - 'type': 'normal', - 'typeName': m.group('typeName'), - 'chargeName': m.group('charge'), - 'offline': True if m.group('offline') else False, - 'mutation': int(m.group('mutation')) if m.group('mutation') else None}) - # Strip stubs from tail - while sectionItemData and sectionItemData[-1]['type'] == 'stub': - del sectionItemData[-1] - if sectionItemData: - sections.append(sectionItemData) - - - - for sectionItemData in sections: - sectionCats = set() - for entry in sectionItemData: - if entry['type'] == 'stub': - continue - try: - item = sMkt.getItem(entry['typeName'], eager='group.category') - except: - pyfalog.warning('no data can be found (old names)') - entry['type'] = 'stub' - continue - entry['item'] = item - import sys - sys.stderr.write('{}\n'.format(item.slot)) - sectionCats.add(item.category.name) - processStubs = ( - # To process stubs, we must make sure that all the items in section - # are from the same category - len(sectionCats) == 1 and tuple(sectionCats)[0] == 'Module' and - # And that they do not contain items with quantity specifier - all(i['type'] in ('stub', 'normal') for i in sectionItemData)) - isDronebay = ( - len(sectionCats) == 1 and tuple(sectionCats)[0] == 'Drone' and - all(i['type'] == 'multi' for i in sectionItemData)) - isFighterbay = ( - len(sectionCats) == 1 and tuple(sectionCats)[0] == 'Fighter' and - all(i['type'] == 'multi' for i in sectionItemData)) - - - - - - - - - - - # maintain map of drones and their quantities - droneMap = {} - cargoMap = {} - moduleList = [] - for i in range(1, len(lines)): - ammoName = None - extraAmount = None - - line = lines[i].strip() - if not line: - continue - - setOffline = line.endswith(offineSuffix) - if setOffline is True: - # remove offline suffix from line - line = line[:len(line) - len(offineSuffix)] - - modAmmo = line.split(",") - # matches drone and cargo with x{qty} - modExtra = modAmmo[0].split(" x") - - if len(modAmmo) == 2: - # line with a module and ammo - ammoName = modAmmo[1].strip() - modName = modAmmo[0].strip() - elif len(modExtra) == 2: - # line with drone/cargo and qty - extraAmount = modExtra[1].strip() - modName = modExtra[0].strip() - else: - # line with just module - modName = modExtra[0].strip() - - try: - # get item information. If we are on a Drone/Cargo line, throw out cargo - item = sMkt.getItem(modName, eager="group.category") - except: - # if no data can be found (old names) - pyfalog.warning("no data can be found (old names)") - continue - - if not item.published: - continue - - if item.category.name == "Drone": - extraAmount = int(extraAmount) if extraAmount is not None else 1 - if modName not in droneMap: - droneMap[modName] = 0 - droneMap[modName] += extraAmount - elif item.category.name == "Fighter": - extraAmount = int(extraAmount) if extraAmount is not None else 1 - fighterItem = Fighter(item) - if extraAmount > fighterItem.fighterSquadronMaxSize: # Amount bigger then max fightergroup size - extraAmount = fighterItem.fighterSquadronMaxSize - if fighterItem.fits(fit): - fit.fighters.append(fighterItem) - - if len(modExtra) == 2 and item.category.name != "Drone" and item.category.name != "Fighter": - extraAmount = int(extraAmount) if extraAmount is not None else 1 - if modName not in cargoMap: - cargoMap[modName] = 0 - cargoMap[modName] += extraAmount - elif item.category.name == "Implant": - if "implantness" in item.attributes: - fit.implants.append(Implant(item)) - elif "boosterness" in item.attributes: - fit.boosters.append(Booster(item)) - else: - pyfalog.error("Failed to import implant: {0}", line) - # elif item.category.name == "Subsystem": - # try: - # subsystem = Module(item) - # except ValueError: - # continue - # - # if subsystem.fits(fit): - # fit.modules.append(subsystem) - else: - try: - m = Module(item) - except ValueError: - continue - # Add subsystems before modules to make sure T3 cruisers have subsystems installed - if item.category.name == "Subsystem": - if m.fits(fit): - fit.modules.append(m) - else: - if ammoName: - try: - ammo = sMkt.getItem(ammoName) - if m.isValidCharge(ammo) and m.charge is None: - m.charge = ammo - except: - pass - - if setOffline is True and m.isValidState(State.OFFLINE): - m.state = State.OFFLINE - elif m.isValidState(State.ACTIVE): - m.state = State.ACTIVE - - moduleList.append(m) - - # Recalc to get slot numbers correct for T3 cruisers - svcFit.getInstance().recalc(fit) - - for m in moduleList: - if m.fits(fit): - m.owner = fit - if not m.isValidState(m.state): - pyfalog.warning("Error: Module {0} cannot have state {1}", m, m.state) - - fit.modules.append(m) - - for droneName in droneMap: - d = Drone(sMkt.getItem(droneName)) - d.amount = droneMap[droneName] - fit.drones.append(d) - - for cargoName in cargoMap: - c = Cargo(sMkt.getItem(cargoName)) - c.amount = cargoMap[cargoName] - fit.cargo.append(c) - - return fit + return EftPort.importEft(eftString) @staticmethod def importEftCfg(shipname, contents, iportuser=None): @@ -1159,119 +910,12 @@ class Port(object): @classmethod - def exportEft(cls, fit, mutations=True, implants=False): - # EFT formatted export is split in several sections, each section is - # separated from another using 2 blank lines. Sections might have several - # sub-sections, which are separated by 1 blank line - sections = [] - - header = '[{}, {}]'.format(fit.ship.item.name, fit.name) - - # Section 1: modules, rigs, subsystems, services - modsBySlotType = {} - sFit = svcFit.getInstance() - for module in fit.modules: - modsBySlotType.setdefault(module.slot, []).append(module) - modSection = [] - offineSuffix = ' /OFFLINE' - mutants = {} # Format: {reference number: module} - mutantReference = 1 - for slotType in EFT_SLOT_ORDER: - rackLines = [] - modules = modsBySlotType.get(slotType, ()) - for module in modules: - if module.item: - mutated = bool(module.mutators) - # if module was mutated, use base item name for export - if mutated: - modName = module.baseItem.name - else: - modName = module.item.name - if mutated and mutations: - mutants[mutantReference] = module - mutationSuffix = ' [{}]'.format(mutantReference) - mutantReference += 1 - else: - mutationSuffix = '' - modOfflineSuffix = offineSuffix if module.state == State.OFFLINE else '' - if module.charge and sFit.serviceFittingOptions['exportCharges']: - rackLines.append('{}, {}{}{}'.format( - modName, module.charge.name, modOfflineSuffix, mutationSuffix)) - else: - rackLines.append('{}{}{}'.format(modName, modOfflineSuffix, mutationSuffix)) - else: - rackLines.append('[Empty {} slot]'.format( - Slot.getName(slotType).capitalize() if slotType is not None else '')) - if rackLines: - modSection.append('\n'.join(rackLines)) - if modSection: - sections.append('\n\n'.join(modSection)) - - # Section 2: drones, fighters - minionSection = [] - droneLines = [] - for drone in sorted(fit.drones, key=lambda d: d.item.name): - droneLines.append('{} x{}'.format(drone.item.name, drone.amount)) - if droneLines: - minionSection.append('\n'.join(droneLines)) - fighterLines = [] - for fighter in sorted(fit.fighters, key=lambda f: f.item.name): - fighterLines.append('{} x{}'.format(fighter.item.name, fighter.amountActive)) - if fighterLines: - minionSection.append('\n'.join(fighterLines)) - if minionSection: - sections.append('\n\n'.join(minionSection)) - - # Section 3: implants, boosters - if implants: - charSection = [] - implantLines = [] - for implant in fit.implants: - implantLines.append(implant.item.name) - if implantLines: - charSection.append('\n'.join(implantLines)) - boosterLines = [] - for booster in fit.boosters: - boosterLines.append(booster.item.name) - if boosterLines: - charSection.append('\n'.join(boosterLines)) - if charSection: - sections.append('\n\n'.join(charSection)) - - # Section 4: cargo - cargoLines = [] - for cargo in sorted( - fit.cargo, - key=lambda c: (c.item.group.category.name, c.item.group.name, c.item.name) - ): - cargoLines.append('{} x{}'.format(cargo.item.name, cargo.amount)) - if cargoLines: - sections.append('\n'.join(cargoLines)) - - # Section 5: mutated modules' details - mutationLines = [] - if mutants and mutations: - for mutantReference in sorted(mutants): - mutant = mutants[mutantReference] - mutatedAttrs = {} - for attrID, mutator in mutant.mutators.items(): - attrName = getAttributeInfo(attrID).name - mutatedAttrs[attrName] = mutator.value - mutationLines.append('[{}] {}'.format(mutantReference, mutant.baseItem.name)) - mutationLines.append(' {}'.format(mutant.mutaplasmid.item.name)) - # Round to 7th significant number to avoid exporting float errors - customAttrsLine = ', '.join( - '{} {}'.format(a, roundToPrec(mutatedAttrs[a], 7)) - for a in sorted(mutatedAttrs)) - mutationLines.append(' {}'.format(customAttrsLine)) - if mutationLines: - sections.append('\n'.join(mutationLines)) - - return '{}\n\n{}'.format(header, '\n\n\n'.join(sections)) + def exportEft(cls, fit): + return EftPort.exportEft(fit, mutations=False, implants=False) @classmethod def exportEftImps(cls, fit): - return cls.exportEft(fit, implants=True) + return EftPort.exportEft(fit, mutations=False, implants=True) @staticmethod def exportDna(fit): @@ -1478,7 +1122,8 @@ class Port(object): class PortProcessing(object): - """Port Processing class """ + """Port Processing class""" + @staticmethod def backupFits(path, iportuser): success = True From eb8fa2f259b36f73409d733a02368142bae2d9f1 Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Sat, 25 Aug 2018 16:03:45 +0300 Subject: [PATCH 64/95] Rework EFT importing --- service/eftPort.py | 496 +++++++++++++++++++++++++-------------------- 1 file changed, 272 insertions(+), 224 deletions(-) diff --git a/service/eftPort.py b/service/eftPort.py index de69bd966..028e7e274 100644 --- a/service/eftPort.py +++ b/service/eftPort.py @@ -23,9 +23,15 @@ import re from logbook import Logger from eos.db.gamedata.queries import getAttributeInfo +from eos.saveddata.cargo import Cargo from eos.saveddata.citadel import Citadel -from eos.saveddata.module import Module, Slot, State +from eos.saveddata.booster import Booster +from eos.saveddata.drone import Drone +from eos.saveddata.fighter import Fighter +from eos.saveddata.implant import Implant +from eos.saveddata.module import Module, State, Slot from eos.saveddata.ship import Ship +from eos.saveddata.fit import Fit from gui.utils.numberFormatter import roundToPrec from service.fit import Fit as svcFit from service.market import Market @@ -33,76 +39,74 @@ from service.market import Market pyfalog = Logger(__name__) +MODULE_CATS = ('Module', 'Subsystem', 'Structure Module') +SLOT_ORDER = (Slot.LOW, Slot.MED, Slot.HIGH, Slot.RIG, Slot.SUBSYSTEM, Slot.SERVICE) +OFFLINE_SUFFIX = ' /OFFLINE' + def fetchItem(typeName, eagerCat=True): sMkt = Market.getInstance() eager = 'group.category' if eagerCat else None try: - return sMkt.getItem(typeName, eager=eager) + item = sMkt.getItem(typeName, eager=eager) except: pyfalog.warning('EftPort: unable to fetch item "{}"'.format(typeName)) - return + return None + if sMkt.getPublicityByItem(item): + return item + else: + return None + + +def clearTail(lst): + while lst and lst[-1] is None: + del lst[-1] class EftImportError(Exception): - """Exception class emitted and consumed by EFT importer/exporter internally.""" + """Exception class emitted and consumed by EFT importer internally.""" ... -class AmountMap(dict): - - def add(self, entity, amount): - if entity not in self: - self[entity] = 0 - self[entity] += amount - - -class AbstractFit: - - def __init__(self): - self.modulesHigh = [] - self.modulesMed = [] - self.modulesLow = [] - self.rigs = [] - self.subsystems = [] - self.services = [] - self.drones = AmountMap() - self.fighters = AmountMap() - self.implants = set() - self.boosters = set() - self.cargo = AmountMap() - - # def addModule(self, m): - # modContMap = { - # Slot.HIGH: self.modulesHigh, - # Slot.MED: self.modulesMed, - # Slot.LOW: self.modulesLow, - # Slot.RIG: self.rigs, - # Slot.SUBSYSTEM: self.subsystems, - # Slot.SERVICE: self.services} - - class Section: def __init__(self): self.lines = [] - self.itemData = [] + self.itemSpecs = [] self.__itemDataCats = None @property def itemDataCats(self): if self.__itemDataCats is None: cats = set() - for itemSpec in self.itemData: + for itemSpec in self.itemSpecs: if itemSpec is None: continue cats.add(itemSpec.item.category.name) self.__itemDataCats = tuple(sorted(cats)) return self.__itemDataCats - def cleanItemDataTail(self): - while self.itemData and self.itemData[-1] is None: - del self.itemData[-1] + @property + def isModuleRack(self): + return all(i is None or i.isModule for i in self.itemSpecs) + + @property + def isImplantRack(self): + return all(i is not None and i.isImplant for i in self.itemSpecs) + + @property + def isDroneBay(self): + return all(i is not None and i.isDrone for i in self.itemSpecs) + + @property + def isFighterBay(self): + return all(i is not None and i.isFighter for i in self.itemSpecs) + + @property + def isCargoHold(self): + return ( + all(i is not None and i.isCargo for i in self.itemSpecs) and + not self.isDroneBay and not self.isFighterBay) class BaseItemSpec: @@ -114,8 +118,28 @@ class BaseItemSpec: self.typeName = typeName self.item = item + @property + def isModule(self): + return False -class ItemSpec(BaseItemSpec): + @property + def isImplant(self): + return False + + @property + def isDrone(self): + return False + + @property + def isFighter(self): + return False + + @property + def isCargo(self): + return False + + +class RegularItemSpec(BaseItemSpec): def __init__(self, typeName, chargeName=None): super().__init__(typeName) @@ -132,6 +156,17 @@ class ItemSpec(BaseItemSpec): charge = None return charge + @property + def isModule(self): + return self.item.category.name in MODULE_CATS + + @property + def isImplant(self): + return ( + self.item.category.name == 'Implant' and ( + 'implantness' in self.item.attributes or + 'boosterness' in self.item.attributes)) + class MultiItemSpec(BaseItemSpec): @@ -139,12 +174,127 @@ class MultiItemSpec(BaseItemSpec): super().__init__(typeName) self.amount = 0 + @property + def isDrone(self): + return self.item.category.name == 'Drone' + + @property + def isFighter(self): + return self.item.category.name == 'Fighter' + + @property + def isCargo(self): + return True + + +class AbstractFit: + + def __init__(self): + # Modules + self.modulesHigh = [] + self.modulesMed = [] + self.modulesLow = [] + self.rigs = [] + self.subsystems = [] + self.services = [] + # Non-modules + self.implants = [] + self.boosters = [] + self.drones = {} # Format: {item: Drone} + self.fighters = [] + self.cargo = {} # Format: {item: Cargo} + + @property + def modContMap(self): + return { + Slot.HIGH: self.modulesHigh, + Slot.MED: self.modulesMed, + Slot.LOW: self.modulesLow, + Slot.RIG: self.rigs, + Slot.SUBSYSTEM: self.subsystems, + Slot.SERVICE: self.services} + + def addModules(self, itemSpecs): + modules = [] + slotTypes = set() + for itemSpec in itemSpecs: + if itemSpec is None: + modules.append(None) + continue + m = self.__makeModule(itemSpec) + if m is None: + modules.append(None) + continue + modules.append(m) + slotTypes.add(m.slot) + clearTail(modules) + modContMap = self.modContMap + # If all the modules have same slot type, put them to appropriate + # container with stubs + if len(slotTypes) == 1: + slotType = tuple(slotTypes)[0] + modContMap[slotType].extend(modules) + # Otherwise, put just modules + else: + for m in modules: + if m is None: + continue + modContMap[m.slot].append(m) + + def addModule(self, itemSpec): + if itemSpec is None: + return + m = self.__makeModule(itemSpec) + if m is not None: + self.modContMap[m.slot].append(m) + + def __makeModule(self, itemSpec): + try: + m = Module(itemSpec.item) + except ValueError: + return None + if itemSpec.charge is not None and m.isValidCharge(itemSpec.charge): + m.charge = itemSpec.charge + if itemSpec.offline and m.isValidState(State.OFFLINE): + m.state = State.OFFLINE + elif m.isValidState(State.ACTIVE): + m.state = State.ACTIVE + return m + + def addImplant(self, itemSpec): + if itemSpec is None: + return + if 'implantness' in itemSpec.item.attributes: + self.implants.append(Implant(itemSpec.item)) + elif 'boosterness' in itemSpec.item.attributes: + self.boosters.append(Booster(itemSpec.item)) + else: + pyfalog.error('Failed to import implant: {}', itemSpec.typeName) + + def addDrone(self, itemSpec): + if itemSpec is None: + return + if itemSpec.item not in self.drones: + self.drones[itemSpec.item] = Drone(itemSpec.item) + self.drones[itemSpec.item].amount += itemSpec.amount + + def addFighter(self, itemSpec): + if itemSpec is None: + return + fighter = Fighter(itemSpec.item) + fighter.amount = itemSpec.amount + self.fighters.append(fighter) + + def addCargo(self, itemSpec): + if itemSpec is None: + return + if itemSpec.item not in self.cargo: + self.cargo[itemSpec.item] = Cargo(itemSpec.item) + self.cargo[itemSpec.item].amount += itemSpec.amount + class EftPort: - SLOT_ORDER = [Slot.LOW, Slot.MED, Slot.HIGH, Slot.RIG, Slot.SUBSYSTEM, Slot.SERVICE] - OFFLINE_SUFFIX = ' /OFFLINE' - @classmethod def exportEft(cls, fit, mutations, implants): # EFT formatted export is split in several sections, each section is @@ -163,7 +313,7 @@ class EftPort: mutants = {} # Format: {reference number: module} mutantReference = 1 - for slotType in cls.SLOT_ORDER: + for slotType in SLOT_ORDER: rackLines = [] modules = modsBySlotType.get(slotType, ()) for module in modules: @@ -180,7 +330,7 @@ class EftPort: mutantReference += 1 else: mutationSuffix = '' - modOfflineSuffix = cls.OFFLINE_SUFFIX if module.state == State.OFFLINE else '' + modOfflineSuffix = OFFLINE_SUFFIX if module.state == State.OFFLINE else '' if module.charge and sFit.serviceFittingOptions['exportCharges']: rackLines.append('{}, {}{}{}'.format( modName, module.charge.name, modOfflineSuffix, mutationSuffix)) @@ -267,16 +417,15 @@ class EftPort: aFit = AbstractFit() stubPattern = '^\[.+\]$' - modulePattern = '^(?P[^,/]+)(, (?P[^,/]+))?(?P{})?( \[(?P\d+)\])?$'.format(cls.OFFLINE_SUFFIX) + modulePattern = '^(?P[^,/]+)(, (?P[^,/]+))?(?P{})?( \[(?P\d+)\])?$'.format(OFFLINE_SUFFIX) droneCargoPattern = '^(?P[^,/]+) x(?P\d+)$' - dronebaySeen = False - fightersSeen = False + sections = [] for section in cls.__importSectionIter(lines): for line in section.lines: # Stub line if re.match(stubPattern, line): - section.itemData.append(None) + section.itemSpecs.append(None) continue # Items with quantity specifier m = re.match(droneCargoPattern, line) @@ -285,197 +434,96 @@ class EftPort: itemSpec = MultiItemSpec(m.group('typeName')) # Items which cannot be fetched are considered as stubs except EftImportError: - section.itemData.append(None) + section.itemSpecs.append(None) else: itemSpec.amount = int(m.group('amount')) - section.itemData.append(itemSpec) + section.itemSpecs.append(itemSpec) # All other items m = re.match(modulePattern, line) if m: try: - itemSpec = ItemSpec(m.group('typeName'), chargeName=m.group('chargeName')) + itemSpec = RegularItemSpec(m.group('typeName'), chargeName=m.group('chargeName')) # Items which cannot be fetched are considered as stubs except EftImportError: - section.itemData.append(None) + section.itemSpecs.append(None) else: if m.group('offline'): itemSpec.offline = True if m.group('mutation'): itemSpec.mutationIdx = int(m.group('mutation')) - section.itemData.append(itemSpec) - section.cleanItemDataTail() - # Finally, start putting items into intermediate containers - # All items in section have quantity specifier - if all(isinstance(id, MultiItemSpec) for id in section.itemData): - # Dronebay - if len(section.itemDataCats) == 1 and section.itemDataCats[0] == 'Drone' and not dronebaySeen: - for entry in section.itemData: - aFit.drones.add(entry['typeName'], entry['amount']) - dronebaySeen = True - # Fighters - elif len(section.itemDataCats) == 1 and section.itemDataCats[0] == 'Fighter' and not fightersSeen: - for entry in section.itemData: - aFit.fighters.add(entry['typeName'], entry['amount']) - fightersSeen = True - # Cargo - else: - for entry in section.itemData: - aFit.cargo.add(entry['typeName'], entry['amount']) - # All of items are normal or stubs - elif all(isinstance(id, ItemSpec) or id is None for id in section.itemData): - if len(section.itemDataCats) == 1: - if section.itemDataCats[0] in ('Module', 'Subsystem', 'Structure Module'): - slotTypes = set() - for entry in itemData: - if entry['type'] == 'stub': - continue - try: - m = Module(entry['item']) - except ValueError: - m = None - else: - slotTypes.add(m.slot) - entry['module'] = m - # If whole section uses container of the same type, - if len(slotTypes) == 1: - pass - else: - pass + section.itemSpecs.append(itemSpec) + clearTail(section.itemSpecs) + sections.append(section) - else: - pass - else: - pass - - # Mix between all types + hasDroneBay = any(s.isDroneBay for s in sections) + hasFighterBay = any(s.isFighterBay for s in sections) + for section in sections: + if section.isModuleRack: + aFit.addModules(section.itemSpecs) + elif section.isImplantRack: + for itemSpec in section.itemSpecs: + aFit.addImplant(itemSpec) + elif section.isDroneBay: + for itemSpec in section.itemSpecs: + aFit.addDrone(itemSpec) + elif section.isFighterBay: + for itemSpec in section.itemSpecs: + aFit.addFighter(itemSpec) + elif section.isCargoHold: + for itemSpec in section.itemSpecs: + aFit.addCargo(itemSpec) + # Mix between different kinds of item specs (can happen when some + # blank lines are removed) else: - pass + for itemSpec in section.itemSpecs: + if itemSpec is None: + continue + if itemSpec.isModule: + aFit.addModule(itemSpec) + elif itemSpec.isImplant: + aFit.addImplant(itemSpec) + elif itemSpec.isDrone and not hasDroneBay: + aFit.addDrone(itemSpec) + elif itemSpec.isFighter and not hasFighterBay: + aFit.addFighter(itemSpec) + elif itemSpec.isCargo: + aFit.addCargo(itemSpec) - - - # maintain map of drones and their quantities - droneMap = {} - cargoMap = {} - moduleList = [] - for i in range(1, len(lines)): - ammoName = None - extraAmount = None - - line = lines[i].strip() - if not line: + # Subsystems first because they modify slot amount + for subsystem in aFit.subsystems: + if subsystem is None: continue - - setOffline = line.endswith(offineSuffix) - if setOffline is True: - # remove offline suffix from line - line = line[:len(line) - len(offineSuffix)] - - modAmmo = line.split(",") - # matches drone and cargo with x{qty} - modExtra = modAmmo[0].split(" x") - - if len(modAmmo) == 2: - # line with a module and ammo - ammoName = modAmmo[1].strip() - modName = modAmmo[0].strip() - elif len(modExtra) == 2: - # line with drone/cargo and qty - extraAmount = modExtra[1].strip() - modName = modExtra[0].strip() - else: - # line with just module - modName = modExtra[0].strip() - - try: - # get item information. If we are on a Drone/Cargo line, throw out cargo - item = sMkt.getItem(modName, eager="group.category") - except: - # if no data can be found (old names) - pyfalog.warning("no data can be found (old names)") - continue - - if not item.published: - continue - - if item.category.name == "Drone": - extraAmount = int(extraAmount) if extraAmount is not None else 1 - if modName not in droneMap: - droneMap[modName] = 0 - droneMap[modName] += extraAmount - elif item.category.name == "Fighter": - extraAmount = int(extraAmount) if extraAmount is not None else 1 - fighterItem = Fighter(item) - if extraAmount > fighterItem.fighterSquadronMaxSize: # Amount bigger then max fightergroup size - extraAmount = fighterItem.fighterSquadronMaxSize - if fighterItem.fits(fit): - fit.fighters.append(fighterItem) - - if len(modExtra) == 2 and item.category.name != "Drone" and item.category.name != "Fighter": - extraAmount = int(extraAmount) if extraAmount is not None else 1 - if modName not in cargoMap: - cargoMap[modName] = 0 - cargoMap[modName] += extraAmount - elif item.category.name == "Implant": - if "implantness" in item.attributes: - fit.implants.append(Implant(item)) - elif "boosterness" in item.attributes: - fit.boosters.append(Booster(item)) - else: - pyfalog.error("Failed to import implant: {0}", line) - # elif item.category.name == "Subsystem": - # try: - # subsystem = Module(item) - # except ValueError: - # continue - # - # if subsystem.fits(fit): - # fit.modules.append(subsystem) - else: - try: - m = Module(item) - except ValueError: - continue - # Add subsystems before modules to make sure T3 cruisers have subsystems installed - if item.category.name == "Subsystem": - if m.fits(fit): - fit.modules.append(m) - else: - if ammoName: - try: - ammo = sMkt.getItem(ammoName) - if m.isValidCharge(ammo) and m.charge is None: - m.charge = ammo - except: - pass - - if setOffline is True and m.isValidState(State.OFFLINE): - m.state = State.OFFLINE - elif m.isValidState(State.ACTIVE): - m.state = State.ACTIVE - - moduleList.append(m) - - # Recalc to get slot numbers correct for T3 cruisers + if subsystem.fits(fit): + subsystem.owner = fit + fit.modules.append(subsystem) svcFit.getInstance().recalc(fit) - for m in moduleList: - if m.fits(fit): - m.owner = fit - if not m.isValidState(m.state): - pyfalog.warning("Error: Module {0} cannot have state {1}", m, m.state) - - fit.modules.append(m) - - for droneName in droneMap: - d = Drone(sMkt.getItem(droneName)) - d.amount = droneMap[droneName] - fit.drones.append(d) - - for cargoName in cargoMap: - c = Cargo(sMkt.getItem(cargoName)) - c.amount = cargoMap[cargoName] - fit.cargo.append(c) - + # Other stuff + for modRack in ( + aFit.rigs, + aFit.services, + aFit.modulesHigh, + aFit.modulesMed, + aFit.modulesLow, + ): + for m in modRack: + if m is None: + continue + if m.fits(fit): + m.owner = fit + if not m.isValidState(m.state): + pyfalog.warning('EftPort.importEft: module {} cannot have state {}', m, m.state) + fit.modules.append(m) + for implant in aFit.implants: + fit.implants.append(implant) + for booster in aFit.boosters: + fit.boosters.append(booster) + for drone in aFit.drones.values(): + fit.drones.append(drone) + for fighter in aFit.fighters: + fit.fighters.append(fighter) + for cargo in aFit.cargo.values(): + fit.cargo.append(cargo) return fit @staticmethod From 44aed364b70daab42217dce9331a829a91d5c72c Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Sat, 25 Aug 2018 16:21:28 +0300 Subject: [PATCH 65/95] Fix oversight which broke dronebay/fighterbay/cargo detection --- service/eftPort.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/service/eftPort.py b/service/eftPort.py index 028e7e274..7c3df50e3 100644 --- a/service/eftPort.py +++ b/service/eftPort.py @@ -438,6 +438,7 @@ class EftPort: else: itemSpec.amount = int(m.group('amount')) section.itemSpecs.append(itemSpec) + continue # All other items m = re.match(modulePattern, line) if m: @@ -452,6 +453,7 @@ class EftPort: if m.group('mutation'): itemSpec.mutationIdx = int(m.group('mutation')) section.itemSpecs.append(itemSpec) + continue clearTail(section.itemSpecs) sections.append(section) @@ -524,6 +526,7 @@ class EftPort: fit.fighters.append(fighter) for cargo in aFit.cargo.values(): fit.cargo.append(cargo) + return fit @staticmethod From 93f1a18b37aeafcebf1c2a423dcd2c4feb7fd251 Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Sat, 25 Aug 2018 17:42:19 +0300 Subject: [PATCH 66/95] Respect spaces between the modules during import --- eos/effectHandlerHelpers.py | 4 ++++ service/eftPort.py | 43 +++++++++++++++++++++++++------------ 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/eos/effectHandlerHelpers.py b/eos/effectHandlerHelpers.py index f890ae0ed..927958702 100644 --- a/eos/effectHandlerHelpers.py +++ b/eos/effectHandlerHelpers.py @@ -113,6 +113,7 @@ class HandledList(list): class HandledModuleList(HandledList): + def append(self, mod): emptyPosition = float("Inf") for i in range(len(self)): @@ -130,6 +131,9 @@ class HandledModuleList(HandledList): self.remove(mod) return + self.appendIgnoreEmpty(mod) + + def appendIgnoreEmpty(self, mod): mod.position = len(self) HandledList.append(self, mod) if mod.isInvalid: diff --git a/service/eftPort.py b/service/eftPort.py index 7c3df50e3..ca7cc1be6 100644 --- a/service/eftPort.py +++ b/service/eftPort.py @@ -205,7 +205,7 @@ class AbstractFit: self.cargo = {} # Format: {item: Cargo} @property - def modContMap(self): + def __slotContainerMap(self): return { Slot.HIGH: self.modulesHigh, Slot.MED: self.modulesMed, @@ -214,6 +214,17 @@ class AbstractFit: Slot.SUBSYSTEM: self.subsystems, Slot.SERVICE: self.services} + def getContainerBySlot(self, slotType): + return self.__slotContainerMap.get(slotType) + + def getSlotByContainer(self, container): + slotType = None + for k, v in self.__slotContainerMap.items(): + if v is container: + slotType = k + break + return slotType + def addModules(self, itemSpecs): modules = [] slotTypes = set() @@ -228,25 +239,24 @@ class AbstractFit: modules.append(m) slotTypes.add(m.slot) clearTail(modules) - modContMap = self.modContMap # If all the modules have same slot type, put them to appropriate # container with stubs if len(slotTypes) == 1: slotType = tuple(slotTypes)[0] - modContMap[slotType].extend(modules) + self.getContainerBySlot(slotType).extend(modules) # Otherwise, put just modules else: for m in modules: if m is None: continue - modContMap[m.slot].append(m) + self.getContainerBySlot(m.slot).append(m) def addModule(self, itemSpec): if itemSpec is None: return m = self.__makeModule(itemSpec) if m is not None: - self.modContMap[m.slot].append(m) + self.getContainerBySlot(m.slot).append(m) def __makeModule(self, itemSpec): try: @@ -492,12 +502,15 @@ class EftPort: aFit.addCargo(itemSpec) # Subsystems first because they modify slot amount - for subsystem in aFit.subsystems: - if subsystem is None: - continue - if subsystem.fits(fit): - subsystem.owner = fit - fit.modules.append(subsystem) + for m in aFit.subsystems: + if m is None: + dummy = Module.buildEmpty(aFit.getSlotByContainer(aFit.subsystems)) + dummy.owner = fit + fit.modules.appendIgnoreEmpty(dummy) + elif m.fits(fit): + m.owner = fit + pyfalog.error('kurwa {}'.format(type(fit.modules))) + fit.modules.appendIgnoreEmpty(m) svcFit.getInstance().recalc(fit) # Other stuff @@ -510,12 +523,14 @@ class EftPort: ): for m in modRack: if m is None: - continue - if m.fits(fit): + dummy = Module.buildEmpty(aFit.getSlotByContainer(modRack)) + dummy.owner = fit + fit.modules.appendIgnoreEmpty(dummy) + elif m.fits(fit): m.owner = fit if not m.isValidState(m.state): pyfalog.warning('EftPort.importEft: module {} cannot have state {}', m, m.state) - fit.modules.append(m) + fit.modules.appendIgnoreEmpty(m) for implant in aFit.implants: fit.implants.append(implant) for booster in aFit.boosters: From f2c2e2e65a7aebc2f1c66fba3a166a31a296e8bd Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Sat, 25 Aug 2018 19:27:03 +0300 Subject: [PATCH 67/95] Implement mutated attributes import --- eos/db/gamedata/queries.py | 15 ++++ service/eftPort.py | 142 +++++++++++++++++++++++++++++-------- service/port.py | 1 - 3 files changed, 126 insertions(+), 32 deletions(-) diff --git a/eos/db/gamedata/queries.py b/eos/db/gamedata/queries.py index 90e757788..c6ee5c70b 100644 --- a/eos/db/gamedata/queries.py +++ b/eos/db/gamedata/queries.py @@ -396,6 +396,21 @@ def getAbyssalTypes(): return set([r.resultingTypeID for r in gamedata_session.query(DynamicItem.resultingTypeID).distinct()]) +@cachedQuery(1, "itemID") +def getDynamicItem(itemID, eager=None): + try: + if isinstance(itemID, int): + if eager is None: + result = gamedata_session.query(DynamicItem).filter(DynamicItem.ID == itemID).one() + else: + result = gamedata_session.query(DynamicItem).options(*processEager(eager)).filter(DynamicItem.ID == itemID).one() + else: + raise TypeError("Need integer as argument") + except exc.NoResultFound: + result = None + return result + + def getRequiredFor(itemID, attrMapping): Attribute1 = aliased(Attribute) Attribute2 = aliased(Attribute) diff --git a/service/eftPort.py b/service/eftPort.py index ca7cc1be6..c5b1da145 100644 --- a/service/eftPort.py +++ b/service/eftPort.py @@ -22,7 +22,7 @@ import re from logbook import Logger -from eos.db.gamedata.queries import getAttributeInfo +from eos.db.gamedata.queries import getAttributeInfo, getDynamicItem from eos.saveddata.cargo import Cargo from eos.saveddata.citadel import Citadel from eos.saveddata.booster import Booster @@ -44,7 +44,7 @@ SLOT_ORDER = (Slot.LOW, Slot.MED, Slot.HIGH, Slot.RIG, Slot.SUBSYSTEM, Slot.SERV OFFLINE_SUFFIX = ' /OFFLINE' -def fetchItem(typeName, eagerCat=True): +def fetchItem(typeName, eagerCat=False): sMkt = Market.getInstance() eager = 'group.category' if eagerCat else None try: @@ -150,7 +150,7 @@ class RegularItemSpec(BaseItemSpec): def __fetchCharge(self, chargeName): if chargeName: charge = fetchItem(chargeName, eagerCat=True) - if charge.category.name != 'Charge': + if not charge or charge.category.name != 'Charge': charge = None else: charge = None @@ -203,6 +203,8 @@ class AbstractFit: self.drones = {} # Format: {item: Drone} self.fighters = [] self.cargo = {} # Format: {item: Cargo} + # Other stuff + self.mutations = {} # Format: {reference: (mutaplamid item, {attr ID: attr value})} @property def __slotContainerMap(self): @@ -259,10 +261,28 @@ class AbstractFit: self.getContainerBySlot(m.slot).append(m) def __makeModule(self, itemSpec): - try: - m = Module(itemSpec.item) - except ValueError: - return None + # Mutate item if needed + m = None + if itemSpec.mutationIdx in self.mutations: + mutaItem, mutaAttrs = self.mutations[itemSpec.mutationIdx] + mutaplasmid = getDynamicItem(mutaItem.ID) + if mutaplasmid: + try: + m = Module(mutaplasmid.resultingItem, itemSpec.item, mutaplasmid) + except ValueError: + pass + else: + for attrID, mutator in m.mutators.items(): + if attrID in mutaAttrs: + mutator.value = mutaAttrs[attrID] + # If we still don't have item (item is not mutated or we + # failed to construct mutated item), try to make regular item + if m is None: + try: + m = Module(itemSpec.item) + except ValueError: + return None + if itemSpec.charge is not None and m.isValidCharge(itemSpec.charge): m.charge = itemSpec.charge if itemSpec.offline and m.isValidState(State.OFFLINE): @@ -425,10 +445,13 @@ class EftPort: return aFit = AbstractFit() + aFit.mutations = cls.__getMutationData(lines) + pyfalog.error('{}'.format(aFit.mutations)) + nameChars = '[^,/\[\]]' # Characters which are allowed to be used in name stubPattern = '^\[.+\]$' - modulePattern = '^(?P[^,/]+)(, (?P[^,/]+))?(?P{})?( \[(?P\d+)\])?$'.format(OFFLINE_SUFFIX) - droneCargoPattern = '^(?P[^,/]+) x(?P\d+)$' + modulePattern = '^(?P{0}+)(, (?P{0}+))?(?P{1})?( \[(?P\d+)\])?$'.format(nameChars, OFFLINE_SUFFIX) + droneCargoPattern = '^(?P{}+) x(?P\d+)$'.format(nameChars) sections = [] for section in cls.__importSectionIter(lines): @@ -467,6 +490,7 @@ class EftPort: clearTail(section.itemSpecs) sections.append(section) + hasDroneBay = any(s.isDroneBay for s in sections) hasFighterBay = any(s.isFighterBay for s in sections) for section in sections: @@ -555,28 +579,61 @@ class EftPort: del lines[-1] return lines - @classmethod - def __createFit(cls, lines): - """Create fit and set top-level entity (ship or citadel).""" - fit = Fit() - header = lines.pop(0) - m = re.match('\[(?P[\w\s]+), (?P.+)\]', header) - if not m: - pyfalog.warning('EftPort.importEft: corrupted fit header') - raise EftImportError - shipType = m.group('shipType').strip() - fitName = m.group('fitName').strip() - try: - ship = fetchItem(shipType, eagerCat=False) - try: - fit.ship = Ship(ship) - except ValueError: - fit.ship = Citadel(ship) - fit.name = fitName - except: - pyfalog.warning('EftPort.importEft: exception caught when parsing header') - raise EftImportError - return fit + @staticmethod + def __getMutationData(lines): + data = {} + consumedIndices = set() + for i in range(len(lines)): + line = lines[i] + m = re.match('^\[(?P\d+)\]', line) + if m: + ref = int(m.group('ref')) + # Attempt to apply mutation is useless w/o mutaplasmid, so skip it + # altogether if we have no info on it + try: + mutaName = lines[i + 1] + except IndexError: + continue + else: + consumedIndices.add(i) + consumedIndices.add(i + 1) + # Get custom attribute values + mutaAttrs = {} + try: + mutaAttrsLine = lines[i + 2] + except IndexError: + pass + else: + consumedIndices.add(i + 2) + pairs = [p.strip() for p in mutaAttrsLine.split(',')] + for pair in pairs: + try: + attrName, value = pair.split(' ') + except ValueError: + continue + try: + value = float(value) + except (ValueError, TypeError): + continue + attrInfo = getAttributeInfo(attrName.strip()) + if attrInfo is None: + continue + mutaAttrs[attrInfo.ID] = value + mutaItem = fetchItem(mutaName) + if mutaItem is None: + continue + data[ref] = (mutaItem, mutaAttrs) + # If we got here, we have seen at least correct reference line and + # mutaplasmid name line + i += 2 + # Bonus points for seeing correct attrs line. Worst case we + # will have to scan it once again + if mutaAttrs: + i += 1 + # Cleanup the lines from mutaplasmid info + for i in sorted(consumedIndices, reverse=True): + del lines[i] + return data @staticmethod def __importSectionIter(lines): @@ -590,3 +647,26 @@ class EftPort: section.lines.append(line) if section.lines: yield section + + @classmethod + def __createFit(cls, lines): + """Create fit and set top-level entity (ship or citadel).""" + fit = Fit() + header = lines.pop(0) + m = re.match('\[(?P[\w\s]+), (?P.+)\]', header) + if not m: + pyfalog.warning('EftPort.importEft: corrupted fit header') + raise EftImportError + shipType = m.group('shipType').strip() + fitName = m.group('fitName').strip() + try: + ship = fetchItem(shipType) + try: + fit.ship = Ship(ship) + except ValueError: + fit.ship = Citadel(ship) + fit.name = fitName + except: + pyfalog.warning('EftPort.importEft: exception caught when parsing header') + raise EftImportError + return fit diff --git a/service/port.py b/service/port.py index bf1ff4f90..1337825c8 100644 --- a/service/port.py +++ b/service/port.py @@ -908,7 +908,6 @@ class Port(object): return fit_list - @classmethod def exportEft(cls, fit): return EftPort.exportEft(fit, mutations=False, implants=False) From 18ee37d8fd8af16a23c7ad2a99f2c3001217771d Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Sat, 25 Aug 2018 19:30:48 +0300 Subject: [PATCH 68/95] Fix small oversight --- service/port.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/port.py b/service/port.py index 1337825c8..810d9b919 100644 --- a/service/port.py +++ b/service/port.py @@ -51,7 +51,7 @@ from utils.strfunctions import sequential_rep, replace_ltgt from abc import ABCMeta, abstractmethod from service.esi import Esi -from service.eftPort import EftPort +from service.eftPort import EftPort, SLOT_ORDER as EFT_SLOT_ORDER from collections import OrderedDict From ebe0efac8185b51efdb91b237691e4482a2568d7 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 25 Aug 2018 17:24:08 -0400 Subject: [PATCH 69/95] First bit of work for GUI support for abyssal export. --- gui/copySelectDialog.py | 74 +++++++++++++++++++++++++++++------------ gui/mainFrame.py | 22 ++++++------ service/eftPort.py | 27 ++++++++++++--- service/port.py | 4 +-- 4 files changed, 88 insertions(+), 39 deletions(-) diff --git a/gui/copySelectDialog.py b/gui/copySelectDialog.py index 9f5291026..9fd2c7e21 100644 --- a/gui/copySelectDialog.py +++ b/gui/copySelectDialog.py @@ -20,41 +20,59 @@ # noinspection PyPackageRequirements import wx +from service.eftPort import EFT_OPTIONS class CopySelectDialog(wx.Dialog): copyFormatEft = 0 - copyFormatEftImps = 1 - copyFormatXml = 2 - copyFormatDna = 3 - copyFormatEsi = 4 - copyFormatMultiBuy = 5 - copyFormatEfs = 6 + copyFormatXml = 1 + copyFormatDna = 2 + copyFormatEsi = 3 + copyFormatMultiBuy = 4 + copyFormatEfs = 5 def __init__(self, parent): wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title="Select a format", size=(-1, -1), style=wx.DEFAULT_DIALOG_STYLE) mainSizer = wx.BoxSizer(wx.VERTICAL) - copyFormats = ["EFT", "EFT (Implants)", "XML", "DNA", "ESI", "MultiBuy", "EFS"] - copyFormatTooltips = {CopySelectDialog.copyFormatEft: "EFT text format", - CopySelectDialog.copyFormatEftImps: "EFT text format", - CopySelectDialog.copyFormatXml: "EVE native XML format", - CopySelectDialog.copyFormatDna: "A one-line text format", - CopySelectDialog.copyFormatEsi: "A JSON format used for ESI", - CopySelectDialog.copyFormatMultiBuy: "MultiBuy text format", - CopySelectDialog.copyFormatEfs: "JSON data format used by EFS"} - selector = wx.RadioBox(self, wx.ID_ANY, label="Copy to the clipboard using:", choices=copyFormats, - style=wx.RA_SPECIFY_ROWS) - selector.Bind(wx.EVT_RADIOBOX, self.Selected) - for format, tooltip in copyFormatTooltips.items(): - selector.SetItemToolTip(format, tooltip) + self.copyFormats = { + "EFT": CopySelectDialog.copyFormatEft, + "XML": CopySelectDialog.copyFormatXml, + "DNA": CopySelectDialog.copyFormatDna, + "ESI": CopySelectDialog.copyFormatEsi, + "MultiBuy": CopySelectDialog.copyFormatMultiBuy, + "EFS": CopySelectDialog.copyFormatEfs + } + + for i, format in enumerate(self.copyFormats.keys()): + if i == 0: + rdo = wx.RadioButton(self, wx.ID_ANY, format, style=wx.RB_GROUP) + else: + rdo = wx.RadioButton(self, wx.ID_ANY, format) + rdo.Bind(wx.EVT_RADIOBUTTON, self.Selected) + mainSizer.Add(rdo, 0, wx.EXPAND | wx.ALL, 5) self.copyFormat = CopySelectDialog.copyFormatEft - selector.SetSelection(self.copyFormat) - mainSizer.Add(selector, 0, wx.EXPAND | wx.ALL, 5) + # some sizer magic to deal with https://github.com/wxWidgets/Phoenix/issues/974 + self.box1 = wx.StaticBox(self, -1, "EFT Options") + self.bsizer1 = wx.BoxSizer(wx.VERTICAL) + self.bsizer2 = wx.BoxSizer(wx.VERTICAL) + self.bsizer1.AddSpacer(10) + self.bsizer1.Add(self.bsizer2, 1, wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT | wx.BOTTOM, 10) + + self.options = {} + + for x, v in EFT_OPTIONS.items(): + ch = wx.CheckBox(self.box1, -1, v['name']) + self.options[x] = ch + self.bsizer2.Add(ch, 1, wx.EXPAND) + + self.box1.SetSizer(self.bsizer1) + + mainSizer.Add(self.box1, 0, wx.EXPAND | wx.ALL, 5) buttonSizer = self.CreateButtonSizer(wx.OK | wx.CANCEL) if buttonSizer: mainSizer.Add(buttonSizer, 0, wx.EXPAND | wx.ALL, 5) @@ -64,7 +82,19 @@ class CopySelectDialog(wx.Dialog): self.Center() def Selected(self, event): - self.copyFormat = event.GetSelection() + obj = event.GetEventObject() + format = obj.GetLabel() + self.box1.Show(format == "EFT") + self.Fit() + self.copyFormat = self.copyFormats[format] def GetSelected(self): return self.copyFormat + + def GetOptions(self): + i = 0 + for x, v in self.options.items(): + if v.IsChecked(): + i = i ^ x.value + return i + diff --git a/gui/mainFrame.py b/gui/mainFrame.py index 9bd02feee..ba6715908 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -703,31 +703,31 @@ class MainFrame(wx.Frame): else: self.marketBrowser.search.Focus() - def clipboardEft(self): + def clipboardEft(self, options): fit = db_getFit(self.getActiveFit()) - toClipboard(Port.exportEft(fit)) + toClipboard(Port.exportEft(fit, options)) - def clipboardEftImps(self): + def clipboardEftImps(self, options): fit = db_getFit(self.getActiveFit()) toClipboard(Port.exportEftImps(fit)) - def clipboardDna(self): + def clipboardDna(self, options): fit = db_getFit(self.getActiveFit()) toClipboard(Port.exportDna(fit)) - def clipboardEsi(self): + def clipboardEsi(self, options): fit = db_getFit(self.getActiveFit()) toClipboard(Port.exportESI(fit)) - def clipboardXml(self): + def clipboardXml(self, options): fit = db_getFit(self.getActiveFit()) toClipboard(Port.exportXml(None, fit)) - def clipboardMultiBuy(self): + def clipboardMultiBuy(self, options): fit = db_getFit(self.getActiveFit()) toClipboard(Port.exportMultiBuy(fit)) - def clipboardEfs(self): + def clipboardEfs(self, options): fit = db_getFit(self.getActiveFit()) toClipboard(EfsPort.exportEfs(fit, 0)) @@ -742,7 +742,7 @@ class MainFrame(wx.Frame): def exportToClipboard(self, event): CopySelectDict = {CopySelectDialog.copyFormatEft: self.clipboardEft, - CopySelectDialog.copyFormatEftImps: self.clipboardEftImps, + #CopySelectDialog.copyFormatEftImps: self.clipboardEftImps, CopySelectDialog.copyFormatXml: self.clipboardXml, CopySelectDialog.copyFormatDna: self.clipboardDna, CopySelectDialog.copyFormatEsi: self.clipboardEsi, @@ -751,8 +751,8 @@ class MainFrame(wx.Frame): dlg = CopySelectDialog(self) dlg.ShowModal() selected = dlg.GetSelected() - - CopySelectDict[selected]() + options = dlg.GetOptions() + CopySelectDict[selected](options) try: dlg.Destroy() diff --git a/service/eftPort.py b/service/eftPort.py index c5b1da145..775c89cfa 100644 --- a/service/eftPort.py +++ b/service/eftPort.py @@ -35,14 +35,33 @@ from eos.saveddata.fit import Fit from gui.utils.numberFormatter import roundToPrec from service.fit import Fit as svcFit from service.market import Market +from enum import Enum pyfalog = Logger(__name__) + +class Options(Enum): + IMPLANTS = 1 + MUTATIONS = 2 + + MODULE_CATS = ('Module', 'Subsystem', 'Structure Module') SLOT_ORDER = (Slot.LOW, Slot.MED, Slot.HIGH, Slot.RIG, Slot.SUBSYSTEM, Slot.SERVICE) OFFLINE_SUFFIX = ' /OFFLINE' +EFT_OPTIONS = { + Options.IMPLANTS: { + "name": "Implants", + "description": "Exports implants" + }, + Options.MUTATIONS: { + "name": "Abyssal", + "description": "Exports Abyssal stats" + } + # 4: [] +} + def fetchItem(typeName, eagerCat=False): sMkt = Market.getInstance() @@ -326,7 +345,7 @@ class AbstractFit: class EftPort: @classmethod - def exportEft(cls, fit, mutations, implants): + def exportEft(cls, fit, options): # EFT formatted export is split in several sections, each section is # separated from another using 2 blank lines. Sections might have several # sub-sections, which are separated by 1 blank line @@ -354,7 +373,7 @@ class EftPort: modName = module.baseItem.name else: modName = module.item.name - if mutated and mutations: + if mutated and options & Options.MUTATIONS.value: mutants[mutantReference] = module mutationSuffix = ' [{}]'.format(mutantReference) mutantReference += 1 @@ -390,7 +409,7 @@ class EftPort: sections.append('\n\n'.join(minionSection)) # Section 3: implants, boosters - if implants: + if options & Options.IMPLANTS.value: charSection = [] implantLines = [] for implant in fit.implants: @@ -417,7 +436,7 @@ class EftPort: # Section 5: mutated modules' details mutationLines = [] - if mutants and mutations: + if mutants and options & Options.MUTATIONS.value: for mutantReference in sorted(mutants): mutant = mutants[mutantReference] mutatedAttrs = {} diff --git a/service/port.py b/service/port.py index 810d9b919..7e7ec7aea 100644 --- a/service/port.py +++ b/service/port.py @@ -909,8 +909,8 @@ class Port(object): return fit_list @classmethod - def exportEft(cls, fit): - return EftPort.exportEft(fit, mutations=False, implants=False) + def exportEft(cls, fit, options): + return EftPort.exportEft(fit, options) @classmethod def exportEftImps(cls, fit): From c530660132e8f57d6c89910b1d909fa4ce08ec38 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 25 Aug 2018 19:01:49 -0400 Subject: [PATCH 70/95] Save last export setting --- gui/copySelectDialog.py | 14 +++++++++++--- gui/mainFrame.py | 5 +++++ service/eftPort.py | 4 ++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/gui/copySelectDialog.py b/gui/copySelectDialog.py index 9fd2c7e21..d130b3174 100644 --- a/gui/copySelectDialog.py +++ b/gui/copySelectDialog.py @@ -21,6 +21,7 @@ # noinspection PyPackageRequirements import wx from service.eftPort import EFT_OPTIONS +from service.settings import SettingsProvider class CopySelectDialog(wx.Dialog): @@ -36,6 +37,8 @@ class CopySelectDialog(wx.Dialog): style=wx.DEFAULT_DIALOG_STYLE) mainSizer = wx.BoxSizer(wx.VERTICAL) + self.settings = SettingsProvider.getInstance().getSettings("pyfaExport", {"format": 0, "options": 0}) + self.copyFormats = { "EFT": CopySelectDialog.copyFormatEft, "XML": CopySelectDialog.copyFormatXml, @@ -51,10 +54,11 @@ class CopySelectDialog(wx.Dialog): else: rdo = wx.RadioButton(self, wx.ID_ANY, format) rdo.Bind(wx.EVT_RADIOBUTTON, self.Selected) + if self.settings['format'] == self.copyFormats[format]: + rdo.SetValue(True) + self.copyFormat = self.copyFormats[format] mainSizer.Add(rdo, 0, wx.EXPAND | wx.ALL, 5) - self.copyFormat = CopySelectDialog.copyFormatEft - # some sizer magic to deal with https://github.com/wxWidgets/Phoenix/issues/974 self.box1 = wx.StaticBox(self, -1, "EFT Options") self.bsizer1 = wx.BoxSizer(wx.VERTICAL) @@ -68,6 +72,8 @@ class CopySelectDialog(wx.Dialog): for x, v in EFT_OPTIONS.items(): ch = wx.CheckBox(self.box1, -1, v['name']) self.options[x] = ch + if self.settings['options'] & x: + ch.SetValue(True) self.bsizer2.Add(ch, 1, wx.EXPAND) self.box1.SetSizer(self.bsizer1) @@ -77,6 +83,8 @@ class CopySelectDialog(wx.Dialog): if buttonSizer: mainSizer.Add(buttonSizer, 0, wx.EXPAND | wx.ALL, 5) + self.box1.Show(self.GetSelected() == CopySelectDialog.copyFormatEft) + self.SetSizer(mainSizer) self.Fit() self.Center() @@ -95,6 +103,6 @@ class CopySelectDialog(wx.Dialog): i = 0 for x, v in self.options.items(): if v.IsChecked(): - i = i ^ x.value + i = i ^ x return i diff --git a/gui/mainFrame.py b/gui/mainFrame.py index ba6715908..c89914e44 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -752,6 +752,11 @@ class MainFrame(wx.Frame): dlg.ShowModal() selected = dlg.GetSelected() options = dlg.GetOptions() + + settings = SettingsProvider.getInstance().getSettings("pyfaExport") + settings["format"] = selected + settings["options"] = options + CopySelectDict[selected](options) try: diff --git a/service/eftPort.py b/service/eftPort.py index 775c89cfa..dfab8312d 100644 --- a/service/eftPort.py +++ b/service/eftPort.py @@ -51,11 +51,11 @@ SLOT_ORDER = (Slot.LOW, Slot.MED, Slot.HIGH, Slot.RIG, Slot.SUBSYSTEM, Slot.SERV OFFLINE_SUFFIX = ' /OFFLINE' EFT_OPTIONS = { - Options.IMPLANTS: { + Options.IMPLANTS.value: { "name": "Implants", "description": "Exports implants" }, - Options.MUTATIONS: { + Options.MUTATIONS.value: { "name": "Abyssal", "description": "Exports Abyssal stats" } From a1071715430828ebe5881e826ec5c923b6422ce4 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 25 Aug 2018 19:24:41 -0400 Subject: [PATCH 71/95] Fix for #1712 - instead of adding module (which is a simple append), we must replace module (where we give it a position) --- gui/fitCommands/calc/fitRemoveModule.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gui/fitCommands/calc/fitRemoveModule.py b/gui/fitCommands/calc/fitRemoveModule.py index 79ae52198..5134f2f1b 100644 --- a/gui/fitCommands/calc/fitRemoveModule.py +++ b/gui/fitCommands/calc/fitRemoveModule.py @@ -48,11 +48,11 @@ class FitRemoveModuleCommand(wx.Command): def Undo(self): pyfalog.debug("Reapplying {} removed module(s) for {}", len(self.modCache), self.fitID) - from gui.fitCommands.calc.fitAddModule import FitAddModuleCommand # avoids circular import + from gui.fitCommands.calc.fitReplaceModule import FitReplaceModuleCommand # avoids circular import for mod in self.modCache: pyfalog.debug(" -- {}", mod) # todo, send the state and charge? - cmd = FitAddModuleCommand(self.fitID, mod.itemID, mod.mutaplasmidID, mod.baseID) + cmd = FitReplaceModuleCommand(self.fitID, mod.modPosition, mod.itemID) cmd.Do() cmd.module.state = mod.state cmd.module.charge = mod.charge From c2b7cc00dd914ad031b478bf61583a2801012d73 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 25 Aug 2018 19:28:34 -0400 Subject: [PATCH 72/95] Fix for #1713 - should look at Fit.processors, not Fit.__class__.processors - artifact from a rewrite --- service/fit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/service/fit.py b/service/fit.py index ae5a59eb8..b96cd3aa2 100644 --- a/service/fit.py +++ b/service/fit.py @@ -217,8 +217,8 @@ class Fit(FitDeprecated): eos.db.remove(fit) - if fitID in Fit.__class__.processors: - del Fit.__class__.processors[fitID] + if fitID in Fit.processors: + del Fit.processors[fitID] pyfalog.debug(" Need to refresh {} fits: {}", len(refreshFits), refreshFits) for fit in refreshFits: From e7d846063df785465d212115dd3cdd9bca19577a Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 25 Aug 2018 19:33:30 -0400 Subject: [PATCH 73/95] Fix for #1714 - was sending in the entire module, not just the position --- gui/fitCommands/guiCargoToModule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/fitCommands/guiCargoToModule.py b/gui/fitCommands/guiCargoToModule.py index 506c47001..018014081 100644 --- a/gui/fitCommands/guiCargoToModule.py +++ b/gui/fitCommands/guiCargoToModule.py @@ -38,7 +38,7 @@ class GuiCargoToModuleCommand(wx.Command): # We're trying to move a charge from cargo to a slot. Use SetCharge command (don't respect move vs copy) if sFit.isAmmo(cargo.item.ID): - result = self.internal_history.Submit(FitSetChargeCommand(self.fitID, [module], cargo.item.ID)) + result = self.internal_history.Submit(FitSetChargeCommand(self.fitID, [module.modPosition], cargo.item.ID)) else: pyfalog.debug("Moving cargo item to module for fit ID: {0}", self.fitID) From 3faa57f39aa2bedf80bf3df6754face752381853 Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Sun, 26 Aug 2018 11:10:14 +0300 Subject: [PATCH 74/95] Remove debugging log requests --- service/eftPort.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/service/eftPort.py b/service/eftPort.py index dfab8312d..01adfc6ec 100644 --- a/service/eftPort.py +++ b/service/eftPort.py @@ -465,7 +465,6 @@ class EftPort: aFit = AbstractFit() aFit.mutations = cls.__getMutationData(lines) - pyfalog.error('{}'.format(aFit.mutations)) nameChars = '[^,/\[\]]' # Characters which are allowed to be used in name stubPattern = '^\[.+\]$' @@ -552,7 +551,6 @@ class EftPort: fit.modules.appendIgnoreEmpty(dummy) elif m.fits(fit): m.owner = fit - pyfalog.error('kurwa {}'.format(type(fit.modules))) fit.modules.appendIgnoreEmpty(m) svcFit.getInstance().recalc(fit) From 0a47fba10767f381b48edd504d24e6cc542ee1ae Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Tue, 28 Aug 2018 19:00:39 +0300 Subject: [PATCH 75/95] Move import/export facilities to their own folder --- gui/copySelectDialog.py | 2 +- gui/esiFittings.py | 2 +- gui/mainFrame.py | 3 +-- service/port/__init__.py | 2 ++ service/{efsPort.py => port/efs.py} | 0 service/{eftPort.py => port/eft.py} | 0 service/{ => port}/port.py | 2 +- 7 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 service/port/__init__.py rename service/{efsPort.py => port/efs.py} (100%) rename service/{eftPort.py => port/eft.py} (100%) rename service/{ => port}/port.py (99%) diff --git a/gui/copySelectDialog.py b/gui/copySelectDialog.py index d130b3174..11fa79bb9 100644 --- a/gui/copySelectDialog.py +++ b/gui/copySelectDialog.py @@ -20,7 +20,7 @@ # noinspection PyPackageRequirements import wx -from service.eftPort import EFT_OPTIONS +from service.port.eft import EFT_OPTIONS from service.settings import SettingsProvider diff --git a/gui/esiFittings.py b/gui/esiFittings.py index af3da77a5..5b7dec36d 100644 --- a/gui/esiFittings.py +++ b/gui/esiFittings.py @@ -15,7 +15,7 @@ import gui.globalEvents as GE from logbook import Logger from service.esi import Esi from service.esiAccess import APIException -from service.port import ESIExportException +from service.port.port import ESIExportException pyfalog = Logger(__name__) diff --git a/gui/mainFrame.py b/gui/mainFrame.py index c89914e44..ced466577 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -76,8 +76,7 @@ from service.esiAccess import SsoMode from eos.modifiedAttributeDict import ModifiedAttributeDict from eos.db.saveddata.loadDefaultDatabaseValues import DefaultDatabaseValues from eos.db.saveddata.queries import getFit as db_getFit -from service.port import Port, IPortUser -from service.efsPort import EfsPort +from service.port import Port, IPortUser, EfsPort from service.settings import HTMLExportSettings from time import gmtime, strftime diff --git a/service/port/__init__.py b/service/port/__init__.py new file mode 100644 index 000000000..2e884d214 --- /dev/null +++ b/service/port/__init__.py @@ -0,0 +1,2 @@ +from .efs import EfsPort +from .port import Port, IPortUser diff --git a/service/efsPort.py b/service/port/efs.py similarity index 100% rename from service/efsPort.py rename to service/port/efs.py diff --git a/service/eftPort.py b/service/port/eft.py similarity index 100% rename from service/eftPort.py rename to service/port/eft.py diff --git a/service/port.py b/service/port/port.py similarity index 99% rename from service/port.py rename to service/port/port.py index 7e7ec7aea..5b942263e 100644 --- a/service/port.py +++ b/service/port/port.py @@ -51,7 +51,7 @@ from utils.strfunctions import sequential_rep, replace_ltgt from abc import ABCMeta, abstractmethod from service.esi import Esi -from service.eftPort import EftPort, SLOT_ORDER as EFT_SLOT_ORDER +from service.port.eft import EftPort, SLOT_ORDER as EFT_SLOT_ORDER from collections import OrderedDict From d1e6647d1f7c5c4efb5c1adb469d2aede7505c64 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Thu, 30 Aug 2018 00:07:37 -0400 Subject: [PATCH 76/95] Don't show/hide options box, move options to under EFT, and simply disable them when EFT not selected --- gui/copySelectDialog.py | 40 ++++++++++++++++++---------------------- service/port/eft.py | 2 +- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/gui/copySelectDialog.py b/gui/copySelectDialog.py index 11fa79bb9..45191f6d9 100644 --- a/gui/copySelectDialog.py +++ b/gui/copySelectDialog.py @@ -48,6 +48,8 @@ class CopySelectDialog(wx.Dialog): "EFS": CopySelectDialog.copyFormatEfs } + self.options = {} + for i, format in enumerate(self.copyFormats.keys()): if i == 0: rdo = wx.RadioButton(self, wx.ID_ANY, format, style=wx.RB_GROUP) @@ -59,32 +61,22 @@ class CopySelectDialog(wx.Dialog): self.copyFormat = self.copyFormats[format] mainSizer.Add(rdo, 0, wx.EXPAND | wx.ALL, 5) - # some sizer magic to deal with https://github.com/wxWidgets/Phoenix/issues/974 - self.box1 = wx.StaticBox(self, -1, "EFT Options") - self.bsizer1 = wx.BoxSizer(wx.VERTICAL) - self.bsizer2 = wx.BoxSizer(wx.VERTICAL) - self.bsizer1.AddSpacer(10) + if format == "EFT": + bsizer = wx.BoxSizer(wx.VERTICAL) - self.bsizer1.Add(self.bsizer2, 1, wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT | wx.BOTTOM, 10) + for x, v in EFT_OPTIONS.items(): + ch = wx.CheckBox(self, -1, v['name']) + self.options[x] = ch + if self.settings['options'] & x: + ch.SetValue(True) + bsizer.Add(ch, 1, wx.EXPAND | wx.TOP | wx.BOTTOM, 3) + mainSizer.Add(bsizer, 1, wx.EXPAND | wx.LEFT, 20) - self.options = {} - - for x, v in EFT_OPTIONS.items(): - ch = wx.CheckBox(self.box1, -1, v['name']) - self.options[x] = ch - if self.settings['options'] & x: - ch.SetValue(True) - self.bsizer2.Add(ch, 1, wx.EXPAND) - - self.box1.SetSizer(self.bsizer1) - - mainSizer.Add(self.box1, 0, wx.EXPAND | wx.ALL, 5) buttonSizer = self.CreateButtonSizer(wx.OK | wx.CANCEL) if buttonSizer: mainSizer.Add(buttonSizer, 0, wx.EXPAND | wx.ALL, 5) - self.box1.Show(self.GetSelected() == CopySelectDialog.copyFormatEft) - + self.toggleOptions() self.SetSizer(mainSizer) self.Fit() self.Center() @@ -92,9 +84,13 @@ class CopySelectDialog(wx.Dialog): def Selected(self, event): obj = event.GetEventObject() format = obj.GetLabel() - self.box1.Show(format == "EFT") - self.Fit() self.copyFormat = self.copyFormats[format] + self.toggleOptions() + self.Fit() + + def toggleOptions(self): + for ch in self.options.values(): + ch.Enable(self.GetSelected() == CopySelectDialog.copyFormatEft) def GetSelected(self): return self.copyFormat diff --git a/service/port/eft.py b/service/port/eft.py index 01adfc6ec..ad984a068 100644 --- a/service/port/eft.py +++ b/service/port/eft.py @@ -56,7 +56,7 @@ EFT_OPTIONS = { "description": "Exports implants" }, Options.MUTATIONS.value: { - "name": "Abyssal", + "name": "Mutated Attributes", "description": "Exports Abyssal stats" } # 4: [] From ba157af496604976c99e3ee106167f6f6f84c96f Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Thu, 30 Aug 2018 14:25:40 +0300 Subject: [PATCH 77/95] Allow format to have no space between: ship name - fit name; module name - charge name; module spec - offline suffix; module spec - mutastats reference This fixes import of modules with charges from zkb and few other issues --- service/port/eft.py | 12 ++++++------ service/port/port.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/service/port/eft.py b/service/port/eft.py index ad984a068..fac4b8508 100644 --- a/service/port/eft.py +++ b/service/port/eft.py @@ -48,7 +48,7 @@ class Options(Enum): MODULE_CATS = ('Module', 'Subsystem', 'Structure Module') SLOT_ORDER = (Slot.LOW, Slot.MED, Slot.HIGH, Slot.RIG, Slot.SUBSYSTEM, Slot.SERVICE) -OFFLINE_SUFFIX = ' /OFFLINE' +OFFLINE_SUFFIX = '/OFFLINE' EFT_OPTIONS = { Options.IMPLANTS.value: { @@ -379,7 +379,7 @@ class EftPort: mutantReference += 1 else: mutationSuffix = '' - modOfflineSuffix = OFFLINE_SUFFIX if module.state == State.OFFLINE else '' + modOfflineSuffix = ' {}'.format(OFFLINE_SUFFIX) if module.state == State.OFFLINE else '' if module.charge and sFit.serviceFittingOptions['exportCharges']: rackLines.append('{}, {}{}{}'.format( modName, module.charge.name, modOfflineSuffix, mutationSuffix)) @@ -467,9 +467,9 @@ class EftPort: aFit.mutations = cls.__getMutationData(lines) nameChars = '[^,/\[\]]' # Characters which are allowed to be used in name - stubPattern = '^\[.+\]$' - modulePattern = '^(?P{0}+)(, (?P{0}+))?(?P{1})?( \[(?P\d+)\])?$'.format(nameChars, OFFLINE_SUFFIX) - droneCargoPattern = '^(?P{}+) x(?P\d+)$'.format(nameChars) + stubPattern = '^\[.+?\]$' + modulePattern = '^(?P{0}+?)(,\s*(?P{0}+?))?(?P\s*{1})?(\s*\[(?P\d+?)\])?$'.format(nameChars, OFFLINE_SUFFIX) + droneCargoPattern = '^(?P{}+?) x(?P\d+?)$'.format(nameChars) sections = [] for section in cls.__importSectionIter(lines): @@ -670,7 +670,7 @@ class EftPort: """Create fit and set top-level entity (ship or citadel).""" fit = Fit() header = lines.pop(0) - m = re.match('\[(?P[\w\s]+), (?P.+)\]', header) + m = re.match('\[(?P[\w\s]+),\s*(?P.+)\]', header) if not m: pyfalog.warning('EftPort.importEft: corrupted fit header') raise EftImportError diff --git a/service/port/port.py b/service/port/port.py index 5b942263e..9f359b36b 100644 --- a/service/port/port.py +++ b/service/port/port.py @@ -814,7 +814,7 @@ class Port(object): @staticmethod def importXml(text, iportuser=None): - # type: (basestring, IPortUser, basestring) -> list[eos.saveddata.fit.Fit] + # type: (str, IPortUser) -> list[eos.saveddata.fit.Fit] sMkt = Market.getInstance() doc = xml.dom.minidom.parseString(text) # NOTE: From 302cab54fdae03e58b2f742f10584eb0a130bc48 Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Thu, 30 Aug 2018 15:23:24 +0300 Subject: [PATCH 78/95] Get rid of PortProcessing object --- service/port/eft.py | 890 +++++++++++++++++++++++++---------------- service/port/port.py | 271 ++----------- service/port/shared.py | 69 ++++ 3 files changed, 643 insertions(+), 587 deletions(-) create mode 100644 service/port/shared.py diff --git a/service/port/eft.py b/service/port/eft.py index fac4b8508..80640bfff 100644 --- a/service/port/eft.py +++ b/service/port/eft.py @@ -35,6 +35,7 @@ from eos.saveddata.fit import Fit from gui.utils.numberFormatter import roundToPrec from service.fit import Fit as svcFit from service.market import Market +from service.port.shared import IPortUser, processing_notify from enum import Enum @@ -59,10 +60,550 @@ EFT_OPTIONS = { "name": "Mutated Attributes", "description": "Exports Abyssal stats" } - # 4: [] } +class EftPort: + + @classmethod + def exportEft(cls, fit, options): + # EFT formatted export is split in several sections, each section is + # separated from another using 2 blank lines. Sections might have several + # sub-sections, which are separated by 1 blank line + sections = [] + + header = '[{}, {}]'.format(fit.ship.item.name, fit.name) + + # Section 1: modules, rigs, subsystems, services + modsBySlotType = {} + sFit = svcFit.getInstance() + for module in fit.modules: + modsBySlotType.setdefault(module.slot, []).append(module) + modSection = [] + + mutants = {} # Format: {reference number: module} + mutantReference = 1 + for slotType in SLOT_ORDER: + rackLines = [] + modules = modsBySlotType.get(slotType, ()) + for module in modules: + if module.item: + mutated = bool(module.mutators) + # if module was mutated, use base item name for export + if mutated: + modName = module.baseItem.name + else: + modName = module.item.name + if mutated and options & Options.MUTATIONS.value: + mutants[mutantReference] = module + mutationSuffix = ' [{}]'.format(mutantReference) + mutantReference += 1 + else: + mutationSuffix = '' + modOfflineSuffix = ' {}'.format(OFFLINE_SUFFIX) if module.state == State.OFFLINE else '' + if module.charge and sFit.serviceFittingOptions['exportCharges']: + rackLines.append('{}, {}{}{}'.format( + modName, module.charge.name, modOfflineSuffix, mutationSuffix)) + else: + rackLines.append('{}{}{}'.format(modName, modOfflineSuffix, mutationSuffix)) + else: + rackLines.append('[Empty {} slot]'.format( + Slot.getName(slotType).capitalize() if slotType is not None else '')) + if rackLines: + modSection.append('\n'.join(rackLines)) + if modSection: + sections.append('\n\n'.join(modSection)) + + # Section 2: drones, fighters + minionSection = [] + droneLines = [] + for drone in sorted(fit.drones, key=lambda d: d.item.name): + droneLines.append('{} x{}'.format(drone.item.name, drone.amount)) + if droneLines: + minionSection.append('\n'.join(droneLines)) + fighterLines = [] + for fighter in sorted(fit.fighters, key=lambda f: f.item.name): + fighterLines.append('{} x{}'.format(fighter.item.name, fighter.amountActive)) + if fighterLines: + minionSection.append('\n'.join(fighterLines)) + if minionSection: + sections.append('\n\n'.join(minionSection)) + + # Section 3: implants, boosters + if options & Options.IMPLANTS.value: + charSection = [] + implantLines = [] + for implant in fit.implants: + implantLines.append(implant.item.name) + if implantLines: + charSection.append('\n'.join(implantLines)) + boosterLines = [] + for booster in fit.boosters: + boosterLines.append(booster.item.name) + if boosterLines: + charSection.append('\n'.join(boosterLines)) + if charSection: + sections.append('\n\n'.join(charSection)) + + # Section 4: cargo + cargoLines = [] + for cargo in sorted( + fit.cargo, + key=lambda c: (c.item.group.category.name, c.item.group.name, c.item.name) + ): + cargoLines.append('{} x{}'.format(cargo.item.name, cargo.amount)) + if cargoLines: + sections.append('\n'.join(cargoLines)) + + # Section 5: mutated modules' details + mutationLines = [] + if mutants and options & Options.MUTATIONS.value: + for mutantReference in sorted(mutants): + mutant = mutants[mutantReference] + mutatedAttrs = {} + for attrID, mutator in mutant.mutators.items(): + attrName = getAttributeInfo(attrID).name + mutatedAttrs[attrName] = mutator.value + mutationLines.append('[{}] {}'.format(mutantReference, mutant.baseItem.name)) + mutationLines.append(' {}'.format(mutant.mutaplasmid.item.name)) + # Round to 7th significant number to avoid exporting float errors + customAttrsLine = ', '.join( + '{} {}'.format(a, roundToPrec(mutatedAttrs[a], 7)) + for a in sorted(mutatedAttrs)) + mutationLines.append(' {}'.format(customAttrsLine)) + if mutationLines: + sections.append('\n'.join(mutationLines)) + + return '{}\n\n{}'.format(header, '\n\n\n'.join(sections)) + + @classmethod + def importEft(cls, eftString): + lines = cls.__prepareImportString(eftString) + try: + fit = cls.__createFit(lines) + except EftImportError: + return + + aFit = AbstractFit() + aFit.mutations = cls.__getMutationData(lines) + + nameChars = '[^,/\[\]]' # Characters which are allowed to be used in name + stubPattern = '^\[.+?\]$' + modulePattern = '^(?P{0}+?)(,\s*(?P{0}+?))?(?P\s*{1})?(\s*\[(?P\d+?)\])?$'.format(nameChars, OFFLINE_SUFFIX) + droneCargoPattern = '^(?P{}+?) x(?P\d+?)$'.format(nameChars) + + sections = [] + for section in cls.__importSectionIter(lines): + for line in section.lines: + # Stub line + if re.match(stubPattern, line): + section.itemSpecs.append(None) + continue + # Items with quantity specifier + m = re.match(droneCargoPattern, line) + if m: + try: + itemSpec = MultiItemSpec(m.group('typeName')) + # Items which cannot be fetched are considered as stubs + except EftImportError: + section.itemSpecs.append(None) + else: + itemSpec.amount = int(m.group('amount')) + section.itemSpecs.append(itemSpec) + continue + # All other items + m = re.match(modulePattern, line) + if m: + try: + itemSpec = RegularItemSpec(m.group('typeName'), chargeName=m.group('chargeName')) + # Items which cannot be fetched are considered as stubs + except EftImportError: + section.itemSpecs.append(None) + else: + if m.group('offline'): + itemSpec.offline = True + if m.group('mutation'): + itemSpec.mutationIdx = int(m.group('mutation')) + section.itemSpecs.append(itemSpec) + continue + clearTail(section.itemSpecs) + sections.append(section) + + + hasDroneBay = any(s.isDroneBay for s in sections) + hasFighterBay = any(s.isFighterBay for s in sections) + for section in sections: + if section.isModuleRack: + aFit.addModules(section.itemSpecs) + elif section.isImplantRack: + for itemSpec in section.itemSpecs: + aFit.addImplant(itemSpec) + elif section.isDroneBay: + for itemSpec in section.itemSpecs: + aFit.addDrone(itemSpec) + elif section.isFighterBay: + for itemSpec in section.itemSpecs: + aFit.addFighter(itemSpec) + elif section.isCargoHold: + for itemSpec in section.itemSpecs: + aFit.addCargo(itemSpec) + # Mix between different kinds of item specs (can happen when some + # blank lines are removed) + else: + for itemSpec in section.itemSpecs: + if itemSpec is None: + continue + if itemSpec.isModule: + aFit.addModule(itemSpec) + elif itemSpec.isImplant: + aFit.addImplant(itemSpec) + elif itemSpec.isDrone and not hasDroneBay: + aFit.addDrone(itemSpec) + elif itemSpec.isFighter and not hasFighterBay: + aFit.addFighter(itemSpec) + elif itemSpec.isCargo: + aFit.addCargo(itemSpec) + + # Subsystems first because they modify slot amount + for m in aFit.subsystems: + if m is None: + dummy = Module.buildEmpty(aFit.getSlotByContainer(aFit.subsystems)) + dummy.owner = fit + fit.modules.appendIgnoreEmpty(dummy) + elif m.fits(fit): + m.owner = fit + fit.modules.appendIgnoreEmpty(m) + svcFit.getInstance().recalc(fit) + + # Other stuff + for modRack in ( + aFit.rigs, + aFit.services, + aFit.modulesHigh, + aFit.modulesMed, + aFit.modulesLow, + ): + for m in modRack: + if m is None: + dummy = Module.buildEmpty(aFit.getSlotByContainer(modRack)) + dummy.owner = fit + fit.modules.appendIgnoreEmpty(dummy) + elif m.fits(fit): + m.owner = fit + if not m.isValidState(m.state): + pyfalog.warning('EftPort.importEft: module {} cannot have state {}', m, m.state) + fit.modules.appendIgnoreEmpty(m) + for implant in aFit.implants: + fit.implants.append(implant) + for booster in aFit.boosters: + fit.boosters.append(booster) + for drone in aFit.drones.values(): + fit.drones.append(drone) + for fighter in aFit.fighters: + fit.fighters.append(fighter) + for cargo in aFit.cargo.values(): + fit.cargo.append(cargo) + + return fit + + @staticmethod + def importEftCfg(shipname, contents, iportuser): + """Handle import from EFT config store file""" + + # Check if we have such ship in database, bail if we don't + sMkt = Market.getInstance() + try: + sMkt.getItem(shipname) + except: + return [] # empty list is expected + + fits = [] # List for fits + fitIndices = [] # List for starting line numbers for each fit + lines = re.split('[\n\r]+', contents) # Separate string into lines + + for line in lines: + # Detect fit header + if line[:1] == "[" and line[-1:] == "]": + # Line index where current fit starts + startPos = lines.index(line) + fitIndices.append(startPos) + + for i, startPos in enumerate(fitIndices): + # End position is last file line if we're trying to get it for last fit, + # or start position of next fit minus 1 + endPos = len(lines) if i == len(fitIndices) - 1 else fitIndices[i + 1] + + # Finally, get lines for current fitting + fitLines = lines[startPos:endPos] + + try: + # Create fit object + fitobj = Fit() + # Strip square brackets and pull out a fit name + fitobj.name = fitLines[0][1:-1] + # Assign ship to fitting + try: + fitobj.ship = Ship(sMkt.getItem(shipname)) + except ValueError: + fitobj.ship = Citadel(sMkt.getItem(shipname)) + + moduleList = [] + for x in range(1, len(fitLines)): + line = fitLines[x] + if not line: + continue + + # Parse line into some data we will need + misc = re.match("(Drones|Implant|Booster)_(Active|Inactive)=(.+)", line) + cargo = re.match("Cargohold=(.+)", line) + # 2017/03/27 NOTE: store description from EFT + description = re.match("Description=(.+)", line) + + if misc: + entityType = misc.group(1) + entityState = misc.group(2) + entityData = misc.group(3) + if entityType == "Drones": + droneData = re.match("(.+),([0-9]+)", entityData) + # Get drone name and attempt to detect drone number + droneName = droneData.group(1) if droneData else entityData + droneAmount = int(droneData.group(2)) if droneData else 1 + # Bail if we can't get item or it's not from drone category + try: + droneItem = sMkt.getItem(droneName, eager="group.category") + except: + pyfalog.warning("Cannot get item.") + continue + if droneItem.category.name == "Drone": + # Add drone to the fitting + d = Drone(droneItem) + d.amount = droneAmount + if entityState == "Active": + d.amountActive = droneAmount + elif entityState == "Inactive": + d.amountActive = 0 + fitobj.drones.append(d) + elif droneItem.category.name == "Fighter": # EFT saves fighter as drones + ft = Fighter(droneItem) + ft.amount = int(droneAmount) if ft.amount <= ft.fighterSquadronMaxSize else ft.fighterSquadronMaxSize + fitobj.fighters.append(ft) + else: + continue + elif entityType == "Implant": + # Bail if we can't get item or it's not from implant category + try: + implantItem = sMkt.getItem(entityData, eager="group.category") + except: + pyfalog.warning("Cannot get item.") + continue + if implantItem.category.name != "Implant": + continue + # Add implant to the fitting + imp = Implant(implantItem) + if entityState == "Active": + imp.active = True + elif entityState == "Inactive": + imp.active = False + fitobj.implants.append(imp) + elif entityType == "Booster": + # Bail if we can't get item or it's not from implant category + try: + boosterItem = sMkt.getItem(entityData, eager="group.category") + except: + pyfalog.warning("Cannot get item.") + continue + # All boosters have implant category + if boosterItem.category.name != "Implant": + continue + # Add booster to the fitting + b = Booster(boosterItem) + if entityState == "Active": + b.active = True + elif entityState == "Inactive": + b.active = False + fitobj.boosters.append(b) + # If we don't have any prefixes, then it's a module + elif cargo: + cargoData = re.match("(.+),([0-9]+)", cargo.group(1)) + cargoName = cargoData.group(1) if cargoData else cargo.group(1) + cargoAmount = int(cargoData.group(2)) if cargoData else 1 + # Bail if we can't get item + try: + item = sMkt.getItem(cargoName) + except: + pyfalog.warning("Cannot get item.") + continue + # Add Cargo to the fitting + c = Cargo(item) + c.amount = cargoAmount + fitobj.cargo.append(c) + # 2017/03/27 NOTE: store description from EFT + elif description: + fitobj.notes = description.group(1).replace("|", "\n") + else: + withCharge = re.match("(.+),(.+)", line) + modName = withCharge.group(1) if withCharge else line + chargeName = withCharge.group(2) if withCharge else None + # If we can't get module item, skip it + try: + modItem = sMkt.getItem(modName) + except: + pyfalog.warning("Cannot get item.") + continue + + # Create module + m = Module(modItem) + + # Add subsystems before modules to make sure T3 cruisers have subsystems installed + if modItem.category.name == "Subsystem": + if m.fits(fitobj): + fitobj.modules.append(m) + else: + m.owner = fitobj + # Activate mod if it is activable + if m.isValidState(State.ACTIVE): + m.state = State.ACTIVE + # Add charge to mod if applicable, on any errors just don't add anything + if chargeName: + try: + chargeItem = sMkt.getItem(chargeName, eager="group.category") + if chargeItem.category.name == "Charge": + m.charge = chargeItem + except: + pyfalog.warning("Cannot get item.") + pass + # Append module to fit + moduleList.append(m) + + # Recalc to get slot numbers correct for T3 cruisers + svcFit.getInstance().recalc(fitobj) + + for module in moduleList: + if module.fits(fitobj): + fitobj.modules.append(module) + + # Append fit to list of fits + fits.append(fitobj) + + if iportuser: # NOTE: Send current processing status + processing_notify( + iportuser, IPortUser.PROCESS_IMPORT | IPortUser.ID_UPDATE, + "%s:\n%s" % (fitobj.ship.name, fitobj.name) + ) + + # Skip fit silently if we get an exception + except Exception as e: + pyfalog.error("Caught exception on fit.") + pyfalog.error(e) + pass + + return fits + + @staticmethod + def __prepareImportString(eftString): + lines = eftString.splitlines() + for i in range(len(lines)): + lines[i] = lines[i].strip() + while lines and not lines[0]: + del lines[0] + while lines and not lines[-1]: + del lines[-1] + return lines + + @staticmethod + def __getMutationData(lines): + data = {} + consumedIndices = set() + for i in range(len(lines)): + line = lines[i] + m = re.match('^\[(?P\d+)\]', line) + if m: + ref = int(m.group('ref')) + # Attempt to apply mutation is useless w/o mutaplasmid, so skip it + # altogether if we have no info on it + try: + mutaName = lines[i + 1] + except IndexError: + continue + else: + consumedIndices.add(i) + consumedIndices.add(i + 1) + # Get custom attribute values + mutaAttrs = {} + try: + mutaAttrsLine = lines[i + 2] + except IndexError: + pass + else: + consumedIndices.add(i + 2) + pairs = [p.strip() for p in mutaAttrsLine.split(',')] + for pair in pairs: + try: + attrName, value = pair.split(' ') + except ValueError: + continue + try: + value = float(value) + except (ValueError, TypeError): + continue + attrInfo = getAttributeInfo(attrName.strip()) + if attrInfo is None: + continue + mutaAttrs[attrInfo.ID] = value + mutaItem = fetchItem(mutaName) + if mutaItem is None: + continue + data[ref] = (mutaItem, mutaAttrs) + # If we got here, we have seen at least correct reference line and + # mutaplasmid name line + i += 2 + # Bonus points for seeing correct attrs line. Worst case we + # will have to scan it once again + if mutaAttrs: + i += 1 + # Cleanup the lines from mutaplasmid info + for i in sorted(consumedIndices, reverse=True): + del lines[i] + return data + + @staticmethod + def __importSectionIter(lines): + section = Section() + for line in lines: + if not line: + if section.lines: + yield section + section = Section() + else: + section.lines.append(line) + if section.lines: + yield section + + @staticmethod + def __createFit(lines): + """Create fit and set top-level entity (ship or citadel).""" + fit = Fit() + header = lines.pop(0) + m = re.match('\[(?P[\w\s]+),\s*(?P.+)\]', header) + if not m: + pyfalog.warning('EftPort.importEft: corrupted fit header') + raise EftImportError + shipType = m.group('shipType').strip() + fitName = m.group('fitName').strip() + try: + ship = fetchItem(shipType) + try: + fit.ship = Ship(ship) + except ValueError: + fit.ship = Citadel(ship) + fit.name = fitName + except: + pyfalog.warning('EftPort.importEft: exception caught when parsing header') + raise EftImportError + return fit + +# Various methods and functions which assist with EFT import-export + def fetchItem(typeName, eagerCat=False): sMkt = Market.getInstance() eager = 'group.category' if eagerCat else None @@ -340,350 +881,3 @@ class AbstractFit: if itemSpec.item not in self.cargo: self.cargo[itemSpec.item] = Cargo(itemSpec.item) self.cargo[itemSpec.item].amount += itemSpec.amount - - -class EftPort: - - @classmethod - def exportEft(cls, fit, options): - # EFT formatted export is split in several sections, each section is - # separated from another using 2 blank lines. Sections might have several - # sub-sections, which are separated by 1 blank line - sections = [] - - header = '[{}, {}]'.format(fit.ship.item.name, fit.name) - - # Section 1: modules, rigs, subsystems, services - modsBySlotType = {} - sFit = svcFit.getInstance() - for module in fit.modules: - modsBySlotType.setdefault(module.slot, []).append(module) - modSection = [] - - mutants = {} # Format: {reference number: module} - mutantReference = 1 - for slotType in SLOT_ORDER: - rackLines = [] - modules = modsBySlotType.get(slotType, ()) - for module in modules: - if module.item: - mutated = bool(module.mutators) - # if module was mutated, use base item name for export - if mutated: - modName = module.baseItem.name - else: - modName = module.item.name - if mutated and options & Options.MUTATIONS.value: - mutants[mutantReference] = module - mutationSuffix = ' [{}]'.format(mutantReference) - mutantReference += 1 - else: - mutationSuffix = '' - modOfflineSuffix = ' {}'.format(OFFLINE_SUFFIX) if module.state == State.OFFLINE else '' - if module.charge and sFit.serviceFittingOptions['exportCharges']: - rackLines.append('{}, {}{}{}'.format( - modName, module.charge.name, modOfflineSuffix, mutationSuffix)) - else: - rackLines.append('{}{}{}'.format(modName, modOfflineSuffix, mutationSuffix)) - else: - rackLines.append('[Empty {} slot]'.format( - Slot.getName(slotType).capitalize() if slotType is not None else '')) - if rackLines: - modSection.append('\n'.join(rackLines)) - if modSection: - sections.append('\n\n'.join(modSection)) - - # Section 2: drones, fighters - minionSection = [] - droneLines = [] - for drone in sorted(fit.drones, key=lambda d: d.item.name): - droneLines.append('{} x{}'.format(drone.item.name, drone.amount)) - if droneLines: - minionSection.append('\n'.join(droneLines)) - fighterLines = [] - for fighter in sorted(fit.fighters, key=lambda f: f.item.name): - fighterLines.append('{} x{}'.format(fighter.item.name, fighter.amountActive)) - if fighterLines: - minionSection.append('\n'.join(fighterLines)) - if minionSection: - sections.append('\n\n'.join(minionSection)) - - # Section 3: implants, boosters - if options & Options.IMPLANTS.value: - charSection = [] - implantLines = [] - for implant in fit.implants: - implantLines.append(implant.item.name) - if implantLines: - charSection.append('\n'.join(implantLines)) - boosterLines = [] - for booster in fit.boosters: - boosterLines.append(booster.item.name) - if boosterLines: - charSection.append('\n'.join(boosterLines)) - if charSection: - sections.append('\n\n'.join(charSection)) - - # Section 4: cargo - cargoLines = [] - for cargo in sorted( - fit.cargo, - key=lambda c: (c.item.group.category.name, c.item.group.name, c.item.name) - ): - cargoLines.append('{} x{}'.format(cargo.item.name, cargo.amount)) - if cargoLines: - sections.append('\n'.join(cargoLines)) - - # Section 5: mutated modules' details - mutationLines = [] - if mutants and options & Options.MUTATIONS.value: - for mutantReference in sorted(mutants): - mutant = mutants[mutantReference] - mutatedAttrs = {} - for attrID, mutator in mutant.mutators.items(): - attrName = getAttributeInfo(attrID).name - mutatedAttrs[attrName] = mutator.value - mutationLines.append('[{}] {}'.format(mutantReference, mutant.baseItem.name)) - mutationLines.append(' {}'.format(mutant.mutaplasmid.item.name)) - # Round to 7th significant number to avoid exporting float errors - customAttrsLine = ', '.join( - '{} {}'.format(a, roundToPrec(mutatedAttrs[a], 7)) - for a in sorted(mutatedAttrs)) - mutationLines.append(' {}'.format(customAttrsLine)) - if mutationLines: - sections.append('\n'.join(mutationLines)) - - return '{}\n\n{}'.format(header, '\n\n\n'.join(sections)) - - @classmethod - def importEft(cls, eftString): - lines = cls.__prepareImportString(eftString) - try: - fit = cls.__createFit(lines) - except EftImportError: - return - - aFit = AbstractFit() - aFit.mutations = cls.__getMutationData(lines) - - nameChars = '[^,/\[\]]' # Characters which are allowed to be used in name - stubPattern = '^\[.+?\]$' - modulePattern = '^(?P{0}+?)(,\s*(?P{0}+?))?(?P\s*{1})?(\s*\[(?P\d+?)\])?$'.format(nameChars, OFFLINE_SUFFIX) - droneCargoPattern = '^(?P{}+?) x(?P\d+?)$'.format(nameChars) - - sections = [] - for section in cls.__importSectionIter(lines): - for line in section.lines: - # Stub line - if re.match(stubPattern, line): - section.itemSpecs.append(None) - continue - # Items with quantity specifier - m = re.match(droneCargoPattern, line) - if m: - try: - itemSpec = MultiItemSpec(m.group('typeName')) - # Items which cannot be fetched are considered as stubs - except EftImportError: - section.itemSpecs.append(None) - else: - itemSpec.amount = int(m.group('amount')) - section.itemSpecs.append(itemSpec) - continue - # All other items - m = re.match(modulePattern, line) - if m: - try: - itemSpec = RegularItemSpec(m.group('typeName'), chargeName=m.group('chargeName')) - # Items which cannot be fetched are considered as stubs - except EftImportError: - section.itemSpecs.append(None) - else: - if m.group('offline'): - itemSpec.offline = True - if m.group('mutation'): - itemSpec.mutationIdx = int(m.group('mutation')) - section.itemSpecs.append(itemSpec) - continue - clearTail(section.itemSpecs) - sections.append(section) - - - hasDroneBay = any(s.isDroneBay for s in sections) - hasFighterBay = any(s.isFighterBay for s in sections) - for section in sections: - if section.isModuleRack: - aFit.addModules(section.itemSpecs) - elif section.isImplantRack: - for itemSpec in section.itemSpecs: - aFit.addImplant(itemSpec) - elif section.isDroneBay: - for itemSpec in section.itemSpecs: - aFit.addDrone(itemSpec) - elif section.isFighterBay: - for itemSpec in section.itemSpecs: - aFit.addFighter(itemSpec) - elif section.isCargoHold: - for itemSpec in section.itemSpecs: - aFit.addCargo(itemSpec) - # Mix between different kinds of item specs (can happen when some - # blank lines are removed) - else: - for itemSpec in section.itemSpecs: - if itemSpec is None: - continue - if itemSpec.isModule: - aFit.addModule(itemSpec) - elif itemSpec.isImplant: - aFit.addImplant(itemSpec) - elif itemSpec.isDrone and not hasDroneBay: - aFit.addDrone(itemSpec) - elif itemSpec.isFighter and not hasFighterBay: - aFit.addFighter(itemSpec) - elif itemSpec.isCargo: - aFit.addCargo(itemSpec) - - # Subsystems first because they modify slot amount - for m in aFit.subsystems: - if m is None: - dummy = Module.buildEmpty(aFit.getSlotByContainer(aFit.subsystems)) - dummy.owner = fit - fit.modules.appendIgnoreEmpty(dummy) - elif m.fits(fit): - m.owner = fit - fit.modules.appendIgnoreEmpty(m) - svcFit.getInstance().recalc(fit) - - # Other stuff - for modRack in ( - aFit.rigs, - aFit.services, - aFit.modulesHigh, - aFit.modulesMed, - aFit.modulesLow, - ): - for m in modRack: - if m is None: - dummy = Module.buildEmpty(aFit.getSlotByContainer(modRack)) - dummy.owner = fit - fit.modules.appendIgnoreEmpty(dummy) - elif m.fits(fit): - m.owner = fit - if not m.isValidState(m.state): - pyfalog.warning('EftPort.importEft: module {} cannot have state {}', m, m.state) - fit.modules.appendIgnoreEmpty(m) - for implant in aFit.implants: - fit.implants.append(implant) - for booster in aFit.boosters: - fit.boosters.append(booster) - for drone in aFit.drones.values(): - fit.drones.append(drone) - for fighter in aFit.fighters: - fit.fighters.append(fighter) - for cargo in aFit.cargo.values(): - fit.cargo.append(cargo) - - return fit - - @staticmethod - def __prepareImportString(eftString): - lines = eftString.splitlines() - for i in range(len(lines)): - lines[i] = lines[i].strip() - while lines and not lines[0]: - del lines[0] - while lines and not lines[-1]: - del lines[-1] - return lines - - @staticmethod - def __getMutationData(lines): - data = {} - consumedIndices = set() - for i in range(len(lines)): - line = lines[i] - m = re.match('^\[(?P\d+)\]', line) - if m: - ref = int(m.group('ref')) - # Attempt to apply mutation is useless w/o mutaplasmid, so skip it - # altogether if we have no info on it - try: - mutaName = lines[i + 1] - except IndexError: - continue - else: - consumedIndices.add(i) - consumedIndices.add(i + 1) - # Get custom attribute values - mutaAttrs = {} - try: - mutaAttrsLine = lines[i + 2] - except IndexError: - pass - else: - consumedIndices.add(i + 2) - pairs = [p.strip() for p in mutaAttrsLine.split(',')] - for pair in pairs: - try: - attrName, value = pair.split(' ') - except ValueError: - continue - try: - value = float(value) - except (ValueError, TypeError): - continue - attrInfo = getAttributeInfo(attrName.strip()) - if attrInfo is None: - continue - mutaAttrs[attrInfo.ID] = value - mutaItem = fetchItem(mutaName) - if mutaItem is None: - continue - data[ref] = (mutaItem, mutaAttrs) - # If we got here, we have seen at least correct reference line and - # mutaplasmid name line - i += 2 - # Bonus points for seeing correct attrs line. Worst case we - # will have to scan it once again - if mutaAttrs: - i += 1 - # Cleanup the lines from mutaplasmid info - for i in sorted(consumedIndices, reverse=True): - del lines[i] - return data - - @staticmethod - def __importSectionIter(lines): - section = Section() - for line in lines: - if not line: - if section.lines: - yield section - section = Section() - else: - section.lines.append(line) - if section.lines: - yield section - - @classmethod - def __createFit(cls, lines): - """Create fit and set top-level entity (ship or citadel).""" - fit = Fit() - header = lines.pop(0) - m = re.match('\[(?P[\w\s]+),\s*(?P.+)\]', header) - if not m: - pyfalog.warning('EftPort.importEft: corrupted fit header') - raise EftImportError - shipType = m.group('shipType').strip() - fitName = m.group('fitName').strip() - try: - ship = fetchItem(shipType) - try: - fit.ship = Ship(ship) - except ValueError: - fit.ship = Citadel(ship) - fit.name = fitName - except: - pyfalog.warning('EftPort.importEft: exception caught when parsing header') - raise EftImportError - return fit diff --git a/service/port/port.py b/service/port/port.py index 9f359b36b..3fc08aa25 100644 --- a/service/port/port.py +++ b/service/port/port.py @@ -38,8 +38,6 @@ from service.fit import Fit as svcFit import wx from eos.saveddata.cargo import Cargo -from eos.saveddata.implant import Implant -from eos.saveddata.booster import Booster from eos.saveddata.drone import Drone from eos.saveddata.fighter import Fighter from eos.saveddata.module import Module, State, Slot @@ -52,6 +50,7 @@ from abc import ABCMeta, abstractmethod from service.esi import Esi from service.port.eft import EftPort, SLOT_ORDER as EFT_SLOT_ORDER +from service.port.shared import processing_notify from collections import OrderedDict @@ -235,10 +234,26 @@ class Port(object): @staticmethod def backupFits(path, iportuser): pyfalog.debug("Starting backup fits thread.") -# thread = FitBackupThread(path, callback) -# thread.start() + + def backupFitsWorkerFunc(path, iportuser): + success = True + try: + iportuser.on_port_process_start() + backedUpFits = Port.exportXml(iportuser, + *svcFit.getInstance().getAllFits()) + backupFile = open(path, "w", encoding="utf-8") + backupFile.write(backedUpFits) + backupFile.close() + except UserCancelException: + success = False + # Send done signal to GUI + # wx.CallAfter(callback, -1, "Done.") + flag = IPortUser.ID_ERROR if not success else IPortUser.ID_DONE + iportuser.on_port_processing(IPortUser.PROCESS_EXPORT | flag, + "User canceled or some error occurrence." if not success else "Done.") + threading.Thread( - target=PortProcessing.backupFits, + target=backupFitsWorkerFunc, args=(path, iportuser) ).start() @@ -251,10 +266,14 @@ class Port(object): :rtype: None """ pyfalog.debug("Starting import fits thread.") -# thread = FitImportThread(paths, iportuser) -# thread.start() + + def importFitsFromFileWorkerFunc(paths, iportuser): + iportuser.on_port_process_start() + success, result = Port.importFitFromFiles(paths, iportuser) + flag = IPortUser.ID_ERROR if not success else IPortUser.ID_DONE + iportuser.on_port_processing(IPortUser.PROCESS_IMPORT | flag, result) threading.Thread( - target=PortProcessing.importFitsFromFile, + target=importFitsFromFileWorkerFunc, args=(paths, iportuser) ).start() @@ -275,7 +294,7 @@ class Port(object): if iportuser: # Pulse msg = "Processing file:\n%s" % path pyfalog.debug(msg) - PortProcessing.notify(iportuser, IPortUser.PROCESS_IMPORT | IPortUser.ID_UPDATE, msg) + processing_notify(iportuser, IPortUser.PROCESS_IMPORT | IPortUser.ID_UPDATE, msg) # wx.CallAfter(callback, 1, msg) with open(path, "rb") as file_: @@ -310,7 +329,7 @@ class Port(object): # IDs.append(fit.ID) if iportuser: # Pulse pyfalog.debug("Processing complete, saving fits to database: {0}/{1}", idx + 1, numFits) - PortProcessing.notify( + processing_notify( iportuser, IPortUser.PROCESS_IMPORT | IPortUser.ID_UPDATE, "Processing complete, saving fits to database\n(%d/%d) %s" % (idx + 1, numFits, fit.ship.name) ) @@ -621,196 +640,7 @@ class Port(object): @staticmethod def importEftCfg(shipname, contents, iportuser=None): - """Handle import from EFT config store file""" - - # Check if we have such ship in database, bail if we don't - sMkt = Market.getInstance() - try: - sMkt.getItem(shipname) - except: - return [] # empty list is expected - - fits = [] # List for fits - fitIndices = [] # List for starting line numbers for each fit - lines = re.split('[\n\r]+', contents) # Separate string into lines - - for line in lines: - # Detect fit header - if line[:1] == "[" and line[-1:] == "]": - # Line index where current fit starts - startPos = lines.index(line) - fitIndices.append(startPos) - - for i, startPos in enumerate(fitIndices): - # End position is last file line if we're trying to get it for last fit, - # or start position of next fit minus 1 - endPos = len(lines) if i == len(fitIndices) - 1 else fitIndices[i + 1] - - # Finally, get lines for current fitting - fitLines = lines[startPos:endPos] - - try: - # Create fit object - fitobj = Fit() - # Strip square brackets and pull out a fit name - fitobj.name = fitLines[0][1:-1] - # Assign ship to fitting - try: - fitobj.ship = Ship(sMkt.getItem(shipname)) - except ValueError: - fitobj.ship = Citadel(sMkt.getItem(shipname)) - - moduleList = [] - for x in range(1, len(fitLines)): - line = fitLines[x] - if not line: - continue - - # Parse line into some data we will need - misc = re.match("(Drones|Implant|Booster)_(Active|Inactive)=(.+)", line) - cargo = re.match("Cargohold=(.+)", line) - # 2017/03/27 NOTE: store description from EFT - description = re.match("Description=(.+)", line) - - if misc: - entityType = misc.group(1) - entityState = misc.group(2) - entityData = misc.group(3) - if entityType == "Drones": - droneData = re.match("(.+),([0-9]+)", entityData) - # Get drone name and attempt to detect drone number - droneName = droneData.group(1) if droneData else entityData - droneAmount = int(droneData.group(2)) if droneData else 1 - # Bail if we can't get item or it's not from drone category - try: - droneItem = sMkt.getItem(droneName, eager="group.category") - except: - pyfalog.warning("Cannot get item.") - continue - if droneItem.category.name == "Drone": - # Add drone to the fitting - d = Drone(droneItem) - d.amount = droneAmount - if entityState == "Active": - d.amountActive = droneAmount - elif entityState == "Inactive": - d.amountActive = 0 - fitobj.drones.append(d) - elif droneItem.category.name == "Fighter": # EFT saves fighter as drones - ft = Fighter(droneItem) - ft.amount = int(droneAmount) if ft.amount <= ft.fighterSquadronMaxSize else ft.fighterSquadronMaxSize - fitobj.fighters.append(ft) - else: - continue - elif entityType == "Implant": - # Bail if we can't get item or it's not from implant category - try: - implantItem = sMkt.getItem(entityData, eager="group.category") - except: - pyfalog.warning("Cannot get item.") - continue - if implantItem.category.name != "Implant": - continue - # Add implant to the fitting - imp = Implant(implantItem) - if entityState == "Active": - imp.active = True - elif entityState == "Inactive": - imp.active = False - fitobj.implants.append(imp) - elif entityType == "Booster": - # Bail if we can't get item or it's not from implant category - try: - boosterItem = sMkt.getItem(entityData, eager="group.category") - except: - pyfalog.warning("Cannot get item.") - continue - # All boosters have implant category - if boosterItem.category.name != "Implant": - continue - # Add booster to the fitting - b = Booster(boosterItem) - if entityState == "Active": - b.active = True - elif entityState == "Inactive": - b.active = False - fitobj.boosters.append(b) - # If we don't have any prefixes, then it's a module - elif cargo: - cargoData = re.match("(.+),([0-9]+)", cargo.group(1)) - cargoName = cargoData.group(1) if cargoData else cargo.group(1) - cargoAmount = int(cargoData.group(2)) if cargoData else 1 - # Bail if we can't get item - try: - item = sMkt.getItem(cargoName) - except: - pyfalog.warning("Cannot get item.") - continue - # Add Cargo to the fitting - c = Cargo(item) - c.amount = cargoAmount - fitobj.cargo.append(c) - # 2017/03/27 NOTE: store description from EFT - elif description: - fitobj.notes = description.group(1).replace("|", "\n") - else: - withCharge = re.match("(.+),(.+)", line) - modName = withCharge.group(1) if withCharge else line - chargeName = withCharge.group(2) if withCharge else None - # If we can't get module item, skip it - try: - modItem = sMkt.getItem(modName) - except: - pyfalog.warning("Cannot get item.") - continue - - # Create module - m = Module(modItem) - - # Add subsystems before modules to make sure T3 cruisers have subsystems installed - if modItem.category.name == "Subsystem": - if m.fits(fitobj): - fitobj.modules.append(m) - else: - m.owner = fitobj - # Activate mod if it is activable - if m.isValidState(State.ACTIVE): - m.state = State.ACTIVE - # Add charge to mod if applicable, on any errors just don't add anything - if chargeName: - try: - chargeItem = sMkt.getItem(chargeName, eager="group.category") - if chargeItem.category.name == "Charge": - m.charge = chargeItem - except: - pyfalog.warning("Cannot get item.") - pass - # Append module to fit - moduleList.append(m) - - # Recalc to get slot numbers correct for T3 cruisers - svcFit.getInstance().recalc(fitobj) - - for module in moduleList: - if module.fits(fitobj): - fitobj.modules.append(module) - - # Append fit to list of fits - fits.append(fitobj) - - if iportuser: # NOTE: Send current processing status - PortProcessing.notify( - iportuser, IPortUser.PROCESS_IMPORT | IPortUser.ID_UPDATE, - "%s:\n%s" % (fitobj.ship.name, fitobj.name) - ) - - # Skip fit silently if we get an exception - except Exception as e: - pyfalog.error("Caught exception on fit.") - pyfalog.error(e) - pass - - return fits + return EftPort.importEftCfg(shipname, contents, iportuser) @staticmethod def importXml(text, iportuser=None): @@ -901,7 +731,7 @@ class Port(object): fit_list.append(fitobj) if iportuser: # NOTE: Send current processing status - PortProcessing.notify( + processing_notify( iportuser, IPortUser.PROCESS_IMPORT | IPortUser.ID_UPDATE, "Processing %s\n%s" % (fitobj.ship.name, fitobj.name) ) @@ -912,10 +742,6 @@ class Port(object): def exportEft(cls, fit, options): return EftPort.exportEft(fit, options) - @classmethod - def exportEftImps(cls, fit): - return EftPort.exportEft(fit, mutations=False, implants=True) - @staticmethod def exportDna(fit): dna = str(fit.shipID) @@ -1065,7 +891,7 @@ class Port(object): continue finally: if iportuser: - PortProcessing.notify( + processing_notify( iportuser, IPortUser.PROCESS_EXPORT | IPortUser.ID_UPDATE, (i, "convert to xml (%s/%s) %s" % (i + 1, fit_count, fit.ship.name)) ) @@ -1118,36 +944,3 @@ class Port(object): export = export[:-1] return export - - -class PortProcessing(object): - """Port Processing class""" - - @staticmethod - def backupFits(path, iportuser): - success = True - try: - iportuser.on_port_process_start() - backedUpFits = Port.exportXml(iportuser, *svcFit.getInstance().getAllFits()) - backupFile = open(path, "w", encoding="utf-8") - backupFile.write(backedUpFits) - backupFile.close() - except UserCancelException: - success = False - # Send done signal to GUI -# wx.CallAfter(callback, -1, "Done.") - flag = IPortUser.ID_ERROR if not success else IPortUser.ID_DONE - iportuser.on_port_processing(IPortUser.PROCESS_EXPORT | flag, - "User canceled or some error occurrence." if not success else "Done.") - - @staticmethod - def importFitsFromFile(paths, iportuser): - iportuser.on_port_process_start() - success, result = Port.importFitFromFiles(paths, iportuser) - flag = IPortUser.ID_ERROR if not success else IPortUser.ID_DONE - iportuser.on_port_processing(IPortUser.PROCESS_IMPORT | flag, result) - - @staticmethod - def notify(iportuser, flag, data): - if not iportuser.on_port_processing(flag, data): - raise UserCancelException diff --git a/service/port/shared.py b/service/port/shared.py new file mode 100644 index 000000000..39838a907 --- /dev/null +++ b/service/port/shared.py @@ -0,0 +1,69 @@ +# ============================================================================= +# Copyright (C) 2014 Ryan Holmes +# +# 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 . +# ============================================================================= + + +from abc import ABCMeta, abstractmethod + + +class UserCancelException(Exception): + """when user cancel on port processing.""" + pass + + +class IPortUser(metaclass=ABCMeta): + + ID_PULSE = 1 + # Pulse the progress bar + ID_UPDATE = ID_PULSE << 1 + # Replace message with data: update messate + ID_DONE = ID_PULSE << 2 + # open fits: import process done + ID_ERROR = ID_PULSE << 3 + # display error: raise some error + + PROCESS_IMPORT = ID_PULSE << 4 + # means import process. + PROCESS_EXPORT = ID_PULSE << 5 + # means import process. + + @abstractmethod + def on_port_processing(self, action, data=None): + """ + While importing fits from file, the logic calls back to this function to + update progress bar to show activity. XML files can contain multiple + ships with multiple fits, whereas EFT cfg files contain many fits of + a single ship. When iterating through the files, we update the message + when we start a new file, and then Pulse the progress bar with every fit + that is processed. + + action : a flag that lets us know how to deal with :data + None: Pulse the progress bar + 1: Replace message with data + other: Close dialog and handle based on :action (-1 open fits, -2 display error) + return: True is continue process, False is cancel. + """ + pass + + def on_port_process_start(self): + pass + + +def processing_notify(iportuser, flag, data): + if not iportuser.on_port_processing(flag, data): + raise UserCancelException From 02e35181d587f97bc5693296ccf04134414ea77d Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Thu, 30 Aug 2018 15:46:29 +0300 Subject: [PATCH 79/95] Move out DNA format into separate file --- service/port/dna.py | 176 ++++++++++++++++++++++++++++++++ service/port/port.py | 223 +++++------------------------------------ service/port/shared.py | 3 +- 3 files changed, 203 insertions(+), 199 deletions(-) create mode 100644 service/port/dna.py diff --git a/service/port/dna.py b/service/port/dna.py new file mode 100644 index 000000000..bd2645ef8 --- /dev/null +++ b/service/port/dna.py @@ -0,0 +1,176 @@ +# ============================================================================= +# Copyright (C) 2014 Ryan Holmes +# +# 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 . +# ============================================================================= + + +import re +from collections import OrderedDict + +from logbook import Logger + +from eos.saveddata.cargo import Cargo +from eos.saveddata.citadel import Citadel +from eos.saveddata.drone import Drone +from eos.saveddata.fighter import Fighter +from eos.saveddata.fit import Fit +from eos.saveddata.module import Module, State, Slot +from eos.saveddata.ship import Ship +from service.fit import Fit as svcFit +from service.market import Market + + +pyfalog = Logger(__name__) + + +def importDna(string): + sMkt = Market.getInstance() + + ids = list(map(int, re.findall(r'\d+', string))) + for id_ in ids: + try: + try: + try: + Ship(sMkt.getItem(sMkt.getItem(id_))) + except ValueError: + Citadel(sMkt.getItem(sMkt.getItem(id_))) + except ValueError: + Citadel(sMkt.getItem(id_)) + string = string[string.index(str(id_)):] + break + except: + pyfalog.warning("Exception caught in importDna") + pass + string = string[:string.index("::") + 2] + info = string.split(":") + + f = Fit() + try: + try: + f.ship = Ship(sMkt.getItem(int(info[0]))) + except ValueError: + f.ship = Citadel(sMkt.getItem(int(info[0]))) + f.name = "{0} - DNA Imported".format(f.ship.item.name) + except UnicodeEncodeError: + def logtransform(s_): + if len(s_) > 10: + return s_[:10] + "..." + return s_ + + pyfalog.exception("Couldn't import ship data {0}", [logtransform(s) for s in info]) + return None + + moduleList = [] + for itemInfo in info[1:]: + if itemInfo: + itemID, amount = itemInfo.split(";") + item = sMkt.getItem(int(itemID), eager="group.category") + + if item.category.name == "Drone": + d = Drone(item) + d.amount = int(amount) + f.drones.append(d) + elif item.category.name == "Fighter": + ft = Fighter(item) + ft.amount = int(amount) if ft.amount <= ft.fighterSquadronMaxSize else ft.fighterSquadronMaxSize + if ft.fits(f): + f.fighters.append(ft) + elif item.category.name == "Charge": + c = Cargo(item) + c.amount = int(amount) + f.cargo.append(c) + else: + for i in range(int(amount)): + try: + m = Module(item) + except: + pyfalog.warning("Exception caught in importDna") + continue + # Add subsystems before modules to make sure T3 cruisers have subsystems installed + if item.category.name == "Subsystem": + if m.fits(f): + f.modules.append(m) + else: + m.owner = f + if m.isValidState(State.ACTIVE): + m.state = State.ACTIVE + moduleList.append(m) + + # Recalc to get slot numbers correct for T3 cruisers + svcFit.getInstance().recalc(f) + + for module in moduleList: + if module.fits(f): + module.owner = f + if module.isValidState(State.ACTIVE): + module.state = State.ACTIVE + f.modules.append(module) + + return f + + +def exportDna(fit): + dna = str(fit.shipID) + subsystems = [] # EVE cares which order you put these in + mods = OrderedDict() + charges = OrderedDict() + sFit = svcFit.getInstance() + for mod in fit.modules: + if not mod.isEmpty: + if mod.slot == Slot.SUBSYSTEM: + subsystems.append(mod) + continue + if mod.itemID not in mods: + mods[mod.itemID] = 0 + mods[mod.itemID] += 1 + + if mod.charge and sFit.serviceFittingOptions["exportCharges"]: + if mod.chargeID not in charges: + charges[mod.chargeID] = 0 + # `or 1` because some charges (ie scripts) are without qty + charges[mod.chargeID] += mod.numCharges or 1 + + for subsystem in sorted(subsystems, key=lambda mod_: mod_.getModifiedItemAttr("subSystemSlot")): + dna += ":{0};1".format(subsystem.itemID) + + for mod in mods: + dna += ":{0};{1}".format(mod, mods[mod]) + + for drone in fit.drones: + dna += ":{0};{1}".format(drone.itemID, drone.amount) + + for fighter in fit.fighters: + dna += ":{0};{1}".format(fighter.itemID, fighter.amountActive) + + for fighter in fit.fighters: + dna += ":{0};{1}".format(fighter.itemID, fighter.amountActive) + + for cargo in fit.cargo: + # DNA format is a simple/dumb format. As CCP uses the slot information of the item itself + # without designating slots in the DNA standard, we need to make sure we only include + # charges in the DNA export. If modules were included, the EVE Client will interpret these + # as being "Fitted" to whatever slot they are for, and it causes an corruption error in the + # client when trying to save the fit + if cargo.item.category.name == "Charge": + if cargo.item.ID not in charges: + charges[cargo.item.ID] = 0 + charges[cargo.item.ID] += cargo.amount + + for charge in charges: + dna += ":{0};{1}".format(charge, charges[charge]) + + return dna + "::" diff --git a/service/port/port.py b/service/port/port.py index 3fc08aa25..29b5eba81 100644 --- a/service/port/port.py +++ b/service/port/port.py @@ -46,12 +46,11 @@ from eos.saveddata.citadel import Citadel from eos.saveddata.fit import Fit, ImplantLocation from service.market import Market from utils.strfunctions import sequential_rep, replace_ltgt -from abc import ABCMeta, abstractmethod from service.esi import Esi +from service.port.dna import exportDna, importDna from service.port.eft import EftPort, SLOT_ORDER as EFT_SLOT_ORDER -from service.port.shared import processing_notify -from collections import OrderedDict +from service.port.shared import IPortUser, UserCancelException, processing_notify class ESIExportException(Exception): @@ -165,50 +164,6 @@ def _resolve_module(hardware, sMkt, b_localized): return item -class UserCancelException(Exception): - """when user cancel on port processing.""" - pass - - -class IPortUser(metaclass=ABCMeta): - - ID_PULSE = 1 - # Pulse the progress bar - ID_UPDATE = ID_PULSE << 1 - # Replace message with data: update messate - ID_DONE = ID_PULSE << 2 - # open fits: import process done - ID_ERROR = ID_PULSE << 3 - # display error: raise some error - - PROCESS_IMPORT = ID_PULSE << 4 - # means import process. - PROCESS_EXPORT = ID_PULSE << 5 - # means import process. - - @abstractmethod - def on_port_processing(self, action, data=None): - """ - While importing fits from file, the logic calls back to this function to - update progress bar to show activity. XML files can contain multiple - ships with multiple fits, whereas EFT cfg files contain many fits of - a single ship. When iterating through the files, we update the message - when we start a new file, and then Pulse the progress bar with every fit - that is processed. - - action : a flag that lets us know how to deal with :data - None: Pulse the progress bar - 1: Replace message with data - other: Close dialog and handle based on :action (-1 open fits, -2 display error) - """ - - """return: True is continue process, False is cancel.""" - pass - - def on_port_process_start(self): - pass - - class Port(object): """Service which houses all import/export format functions""" instance = None @@ -272,6 +227,7 @@ class Port(object): success, result = Port.importFitFromFiles(paths, iportuser) flag = IPortUser.ID_ERROR if not success else IPortUser.ID_DONE iportuser.on_port_processing(IPortUser.PROCESS_IMPORT | flag, result) + threading.Thread( target=importFitsFromFileWorkerFunc, args=(paths, iportuser) @@ -548,100 +504,6 @@ class Port(object): return fitobj - @staticmethod - def importDna(string): - sMkt = Market.getInstance() - - ids = list(map(int, re.findall(r'\d+', string))) - for id_ in ids: - try: - try: - try: - Ship(sMkt.getItem(sMkt.getItem(id_))) - except ValueError: - Citadel(sMkt.getItem(sMkt.getItem(id_))) - except ValueError: - Citadel(sMkt.getItem(id_)) - string = string[string.index(str(id_)):] - break - except: - pyfalog.warning("Exception caught in importDna") - pass - string = string[:string.index("::") + 2] - info = string.split(":") - - f = Fit() - try: - try: - f.ship = Ship(sMkt.getItem(int(info[0]))) - except ValueError: - f.ship = Citadel(sMkt.getItem(int(info[0]))) - f.name = "{0} - DNA Imported".format(f.ship.item.name) - except UnicodeEncodeError: - def logtransform(s_): - if len(s_) > 10: - return s_[:10] + "..." - return s_ - - pyfalog.exception("Couldn't import ship data {0}", [logtransform(s) for s in info]) - return None - - moduleList = [] - for itemInfo in info[1:]: - if itemInfo: - itemID, amount = itemInfo.split(";") - item = sMkt.getItem(int(itemID), eager="group.category") - - if item.category.name == "Drone": - d = Drone(item) - d.amount = int(amount) - f.drones.append(d) - elif item.category.name == "Fighter": - ft = Fighter(item) - ft.amount = int(amount) if ft.amount <= ft.fighterSquadronMaxSize else ft.fighterSquadronMaxSize - if ft.fits(f): - f.fighters.append(ft) - elif item.category.name == "Charge": - c = Cargo(item) - c.amount = int(amount) - f.cargo.append(c) - else: - for i in range(int(amount)): - try: - m = Module(item) - except: - pyfalog.warning("Exception caught in importDna") - continue - # Add subsystems before modules to make sure T3 cruisers have subsystems installed - if item.category.name == "Subsystem": - if m.fits(f): - f.modules.append(m) - else: - m.owner = f - if m.isValidState(State.ACTIVE): - m.state = State.ACTIVE - moduleList.append(m) - - # Recalc to get slot numbers correct for T3 cruisers - svcFit.getInstance().recalc(f) - - for module in moduleList: - if module.fits(f): - module.owner = f - if module.isValidState(State.ACTIVE): - module.state = State.ACTIVE - f.modules.append(module) - - return f - - @staticmethod - def importEft(eftString): - return EftPort.importEft(eftString) - - @staticmethod - def importEftCfg(shipname, contents, iportuser=None): - return EftPort.importEftCfg(shipname, contents, iportuser) - @staticmethod def importXml(text, iportuser=None): # type: (str, IPortUser) -> list[eos.saveddata.fit.Fit] @@ -738,63 +600,6 @@ class Port(object): return fit_list - @classmethod - def exportEft(cls, fit, options): - return EftPort.exportEft(fit, options) - - @staticmethod - def exportDna(fit): - dna = str(fit.shipID) - subsystems = [] # EVE cares which order you put these in - mods = OrderedDict() - charges = OrderedDict() - sFit = svcFit.getInstance() - for mod in fit.modules: - if not mod.isEmpty: - if mod.slot == Slot.SUBSYSTEM: - subsystems.append(mod) - continue - if mod.itemID not in mods: - mods[mod.itemID] = 0 - mods[mod.itemID] += 1 - - if mod.charge and sFit.serviceFittingOptions["exportCharges"]: - if mod.chargeID not in charges: - charges[mod.chargeID] = 0 - # `or 1` because some charges (ie scripts) are without qty - charges[mod.chargeID] += mod.numCharges or 1 - - for subsystem in sorted(subsystems, key=lambda mod_: mod_.getModifiedItemAttr("subSystemSlot")): - dna += ":{0};1".format(subsystem.itemID) - - for mod in mods: - dna += ":{0};{1}".format(mod, mods[mod]) - - for drone in fit.drones: - dna += ":{0};{1}".format(drone.itemID, drone.amount) - - for fighter in fit.fighters: - dna += ":{0};{1}".format(fighter.itemID, fighter.amountActive) - - for fighter in fit.fighters: - dna += ":{0};{1}".format(fighter.itemID, fighter.amountActive) - - for cargo in fit.cargo: - # DNA format is a simple/dumb format. As CCP uses the slot information of the item itself - # without designating slots in the DNA standard, we need to make sure we only include - # charges in the DNA export. If modules were included, the EVE Client will interpret these - # as being "Fitted" to whatever slot they are for, and it causes an corruption error in the - # client when trying to save the fit - if cargo.item.category.name == "Charge": - if cargo.item.ID not in charges: - charges[cargo.item.ID] = 0 - charges[cargo.item.ID] += cargo.amount - - for charge in charges: - dna += ":{0};{1}".format(charge, charges[charge]) - - return dna + "::" - @staticmethod def exportXml(iportuser=None, *fits): doc = xml.dom.minidom.Document() @@ -944,3 +749,25 @@ class Port(object): export = export[:-1] return export + + # EFT-related methods + @staticmethod + def importEft(eftString): + return EftPort.importEft(eftString) + + @staticmethod + def importEftCfg(shipname, contents, iportuser=None): + return EftPort.importEftCfg(shipname, contents, iportuser) + + @classmethod + def exportEft(cls, fit, options): + return EftPort.exportEft(fit, options) + + # DNA-related methods + @staticmethod + def importDna(string): + return importDna(string) + + @staticmethod + def exportDna(fit): + return exportDna(fit) diff --git a/service/port/shared.py b/service/port/shared.py index 39838a907..a21a81d63 100644 --- a/service/port/shared.py +++ b/service/port/shared.py @@ -56,8 +56,9 @@ class IPortUser(metaclass=ABCMeta): None: Pulse the progress bar 1: Replace message with data other: Close dialog and handle based on :action (-1 open fits, -2 display error) - return: True is continue process, False is cancel. """ + + """return: True is continue process, False is cancel.""" pass def on_port_process_start(self): From dd0fbfddb94843897247ad2135decf51e18cce31 Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Thu, 30 Aug 2018 15:57:59 +0300 Subject: [PATCH 80/95] Split ESI stuff into its own file --- gui/esiFittings.py | 2 +- service/port/esi.py | 208 +++++++++++++++++++++++++++++++++++++++++++ service/port/port.py | 180 +++---------------------------------- 3 files changed, 219 insertions(+), 171 deletions(-) create mode 100644 service/port/esi.py diff --git a/gui/esiFittings.py b/gui/esiFittings.py index 5b7dec36d..c471a1334 100644 --- a/gui/esiFittings.py +++ b/gui/esiFittings.py @@ -15,7 +15,7 @@ import gui.globalEvents as GE from logbook import Logger from service.esi import Esi from service.esiAccess import APIException -from service.port.port import ESIExportException +from service.port.esi import ESIExportException pyfalog = Logger(__name__) diff --git a/service/port/esi.py b/service/port/esi.py new file mode 100644 index 000000000..f1e02d13a --- /dev/null +++ b/service/port/esi.py @@ -0,0 +1,208 @@ +# ============================================================================= +# Copyright (C) 2014 Ryan Holmes +# +# 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 . +# ============================================================================= + + +import collections +import json + +from logbook import Logger + +from eos.saveddata.cargo import Cargo +from eos.saveddata.citadel import Citadel +from eos.saveddata.drone import Drone +from eos.saveddata.fighter import Fighter +from eos.saveddata.fit import Fit +from eos.saveddata.module import Module, State, Slot +from eos.saveddata.ship import Ship +from service.fit import Fit as svcFit +from service.market import Market + + +class ESIExportException(Exception): + pass + + +pyfalog = Logger(__name__) + +INV_FLAGS = { + Slot.LOW: 11, + Slot.MED: 19, + Slot.HIGH: 27, + Slot.RIG: 92, + Slot.SUBSYSTEM: 125, + Slot.SERVICE: 164 +} + +INV_FLAG_CARGOBAY = 5 +INV_FLAG_DRONEBAY = 87 +INV_FLAG_FIGHTER = 158 + + +def exportESI(ofit): + # A few notes: + # max fit name length is 50 characters + # Most keys are created simply because they are required, but bogus data is okay + + nested_dict = lambda: collections.defaultdict(nested_dict) + fit = nested_dict() + sFit = svcFit.getInstance() + + # max length is 50 characters + name = ofit.name[:47] + '...' if len(ofit.name) > 50 else ofit.name + fit['name'] = name + fit['ship_type_id'] = ofit.ship.item.ID + + # 2017/03/29 NOTE: "<" or "<" is Ignored + # fit['description'] = "" % ofit.ID + fit['description'] = ofit.notes[:397] + '...' if len(ofit.notes) > 400 else ofit.notes if ofit.notes is not None else "" + fit['items'] = [] + + slotNum = {} + charges = {} + for module in ofit.modules: + if module.isEmpty: + continue + + item = nested_dict() + slot = module.slot + + if slot == Slot.SUBSYSTEM: + # Order of subsystem matters based on this attr. See GH issue #130 + slot = int(module.getModifiedItemAttr("subSystemSlot")) + item['flag'] = slot + else: + if slot not in slotNum: + slotNum[slot] = INV_FLAGS[slot] + + item['flag'] = slotNum[slot] + slotNum[slot] += 1 + + item['quantity'] = 1 + item['type_id'] = module.item.ID + fit['items'].append(item) + + if module.charge and sFit.serviceFittingOptions["exportCharges"]: + if module.chargeID not in charges: + charges[module.chargeID] = 0 + # `or 1` because some charges (ie scripts) are without qty + charges[module.chargeID] += module.numCharges or 1 + + for cargo in ofit.cargo: + item = nested_dict() + item['flag'] = INV_FLAG_CARGOBAY + item['quantity'] = cargo.amount + item['type_id'] = cargo.item.ID + fit['items'].append(item) + + for chargeID, amount in list(charges.items()): + item = nested_dict() + item['flag'] = INV_FLAG_CARGOBAY + item['quantity'] = amount + item['type_id'] = chargeID + fit['items'].append(item) + + for drone in ofit.drones: + item = nested_dict() + item['flag'] = INV_FLAG_DRONEBAY + item['quantity'] = drone.amount + item['type_id'] = drone.item.ID + fit['items'].append(item) + + for fighter in ofit.fighters: + item = nested_dict() + item['flag'] = INV_FLAG_FIGHTER + item['quantity'] = fighter.amountActive + item['type_id'] = fighter.item.ID + fit['items'].append(item) + + if len(fit['items']) == 0: + raise ESIExportException("Cannot export fitting: module list cannot be empty.") + + return json.dumps(fit) + + +def importESI(str_): + + sMkt = Market.getInstance() + fitobj = Fit() + refobj = json.loads(str_) + items = refobj['items'] + # "<" and ">" is replace to "<", ">" by EVE client + fitobj.name = refobj['name'] + # 2017/03/29: read description + fitobj.notes = refobj['description'] + + try: + ship = refobj['ship_type_id'] + try: + fitobj.ship = Ship(sMkt.getItem(ship)) + except ValueError: + fitobj.ship = Citadel(sMkt.getItem(ship)) + except: + pyfalog.warning("Caught exception in importESI") + return None + + items.sort(key=lambda k: k['flag']) + + moduleList = [] + for module in items: + try: + item = sMkt.getItem(module['type_id'], eager="group.category") + if not item.published: + continue + if module['flag'] == INV_FLAG_DRONEBAY: + d = Drone(item) + d.amount = module['quantity'] + fitobj.drones.append(d) + elif module['flag'] == INV_FLAG_CARGOBAY: + c = Cargo(item) + c.amount = module['quantity'] + fitobj.cargo.append(c) + elif module['flag'] == INV_FLAG_FIGHTER: + fighter = Fighter(item) + fitobj.fighters.append(fighter) + else: + try: + m = Module(item) + # When item can't be added to any slot (unknown item or just charge), ignore it + except ValueError: + pyfalog.debug("Item can't be added to any slot (unknown item or just charge)") + continue + # Add subsystems before modules to make sure T3 cruisers have subsystems installed + if item.category.name == "Subsystem": + if m.fits(fitobj): + fitobj.modules.append(m) + else: + if m.isValidState(State.ACTIVE): + m.state = State.ACTIVE + + moduleList.append(m) + + except: + pyfalog.warning("Could not process module.") + continue + + # Recalc to get slot numbers correct for T3 cruisers + svcFit.getInstance().recalc(fitobj) + + for module in moduleList: + if module.fits(fitobj): + fitobj.modules.append(module) + + return fitobj diff --git a/service/port/port.py b/service/port/port.py index 29b5eba81..97acaba98 100644 --- a/service/port/port.py +++ b/service/port/port.py @@ -47,30 +47,15 @@ from eos.saveddata.fit import Fit, ImplantLocation from service.market import Market from utils.strfunctions import sequential_rep, replace_ltgt -from service.esi import Esi from service.port.dna import exportDna, importDna from service.port.eft import EftPort, SLOT_ORDER as EFT_SLOT_ORDER +from service.port.esi import importESI, exportESI from service.port.shared import IPortUser, UserCancelException, processing_notify -class ESIExportException(Exception): - pass - pyfalog = Logger(__name__) -INV_FLAGS = { - Slot.LOW: 11, - Slot.MED: 19, - Slot.HIGH: 27, - Slot.RIG: 92, - Slot.SUBSYSTEM: 125, - Slot.SERVICE: 164 -} - -INV_FLAG_CARGOBAY = 5 -INV_FLAG_DRONEBAY = 87 -INV_FLAG_FIGHTER = 158 # 2017/04/05 NOTE: simple validation, for xml file RE_XML_START = r'<\?xml\s+version="1.0"\s*\?>' @@ -320,89 +305,6 @@ class Port(object): db.save(fit) return fits - @classmethod - def exportESI(cls, ofit, callback=None): - # A few notes: - # max fit name length is 50 characters - # Most keys are created simply because they are required, but bogus data is okay - - nested_dict = lambda: collections.defaultdict(nested_dict) - fit = nested_dict() - sFit = svcFit.getInstance() - - # max length is 50 characters - name = ofit.name[:47] + '...' if len(ofit.name) > 50 else ofit.name - fit['name'] = name - fit['ship_type_id'] = ofit.ship.item.ID - - # 2017/03/29 NOTE: "<" or "<" is Ignored - # fit['description'] = "" % ofit.ID - fit['description'] = ofit.notes[:397] + '...' if len(ofit.notes) > 400 else ofit.notes if ofit.notes is not None else "" - fit['items'] = [] - - slotNum = {} - charges = {} - for module in ofit.modules: - if module.isEmpty: - continue - - item = nested_dict() - slot = module.slot - - if slot == Slot.SUBSYSTEM: - # Order of subsystem matters based on this attr. See GH issue #130 - slot = int(module.getModifiedItemAttr("subSystemSlot")) - item['flag'] = slot - else: - if slot not in slotNum: - slotNum[slot] = INV_FLAGS[slot] - - item['flag'] = slotNum[slot] - slotNum[slot] += 1 - - item['quantity'] = 1 - item['type_id'] = module.item.ID - fit['items'].append(item) - - if module.charge and sFit.serviceFittingOptions["exportCharges"]: - if module.chargeID not in charges: - charges[module.chargeID] = 0 - # `or 1` because some charges (ie scripts) are without qty - charges[module.chargeID] += module.numCharges or 1 - - for cargo in ofit.cargo: - item = nested_dict() - item['flag'] = INV_FLAG_CARGOBAY - item['quantity'] = cargo.amount - item['type_id'] = cargo.item.ID - fit['items'].append(item) - - for chargeID, amount in list(charges.items()): - item = nested_dict() - item['flag'] = INV_FLAG_CARGOBAY - item['quantity'] = amount - item['type_id'] = chargeID - fit['items'].append(item) - - for drone in ofit.drones: - item = nested_dict() - item['flag'] = INV_FLAG_DRONEBAY - item['quantity'] = drone.amount - item['type_id'] = drone.item.ID - fit['items'].append(item) - - for fighter in ofit.fighters: - item = nested_dict() - item['flag'] = INV_FLAG_FIGHTER - item['quantity'] = fighter.amountActive - item['type_id'] = fighter.item.ID - fit['items'].append(item) - - if len(fit['items']) == 0: - raise ESIExportException("Cannot export fitting: module list cannot be empty.") - - return json.dumps(fit) - @classmethod def importAuto(cls, string, path=None, activeFit=None, iportuser=None): # type: (basestring, basestring, object, IPortUser, basestring) -> object @@ -433,77 +335,6 @@ class Port(object): # Use DNA format for all other cases return "DNA", (cls.importDna(string),) - @staticmethod - def importESI(str_): - - sMkt = Market.getInstance() - fitobj = Fit() - refobj = json.loads(str_) - items = refobj['items'] - # "<" and ">" is replace to "<", ">" by EVE client - fitobj.name = refobj['name'] - # 2017/03/29: read description - fitobj.notes = refobj['description'] - - try: - ship = refobj['ship_type_id'] - try: - fitobj.ship = Ship(sMkt.getItem(ship)) - except ValueError: - fitobj.ship = Citadel(sMkt.getItem(ship)) - except: - pyfalog.warning("Caught exception in importESI") - return None - - items.sort(key=lambda k: k['flag']) - - moduleList = [] - for module in items: - try: - item = sMkt.getItem(module['type_id'], eager="group.category") - if not item.published: - continue - if module['flag'] == INV_FLAG_DRONEBAY: - d = Drone(item) - d.amount = module['quantity'] - fitobj.drones.append(d) - elif module['flag'] == INV_FLAG_CARGOBAY: - c = Cargo(item) - c.amount = module['quantity'] - fitobj.cargo.append(c) - elif module['flag'] == INV_FLAG_FIGHTER: - fighter = Fighter(item) - fitobj.fighters.append(fighter) - else: - try: - m = Module(item) - # When item can't be added to any slot (unknown item or just charge), ignore it - except ValueError: - pyfalog.debug("Item can't be added to any slot (unknown item or just charge)") - continue - # Add subsystems before modules to make sure T3 cruisers have subsystems installed - if item.category.name == "Subsystem": - if m.fits(fitobj): - fitobj.modules.append(m) - else: - if m.isValidState(State.ACTIVE): - m.state = State.ACTIVE - - moduleList.append(m) - - except: - pyfalog.warning("Could not process module.") - continue - - # Recalc to get slot numbers correct for T3 cruisers - svcFit.getInstance().recalc(fitobj) - - for module in moduleList: - if module.fits(fitobj): - fitobj.modules.append(module) - - return fitobj - @staticmethod def importXml(text, iportuser=None): # type: (str, IPortUser) -> list[eos.saveddata.fit.Fit] @@ -771,3 +602,12 @@ class Port(object): @staticmethod def exportDna(fit): return exportDna(fit) + + # ESI-related methods + @staticmethod + def importESI(string): + importESI(string) + + @staticmethod + def exportESI(fit): + exportESI(fit) From 4e5a70993e661f5ae5693b0868ef11f7d66ffcee Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Thu, 30 Aug 2018 16:15:23 +0300 Subject: [PATCH 81/95] Split XML facilities into their own file as well --- service/port/port.py | 331 +++---------------------------------------- service/port/xml.py | 325 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 342 insertions(+), 314 deletions(-) create mode 100644 service/port/xml.py diff --git a/service/port/port.py b/service/port/port.py index 97acaba98..045f5561e 100644 --- a/service/port/port.py +++ b/service/port/port.py @@ -19,135 +19,29 @@ import re import os -import xml.dom -from logbook import Logger -import collections -import json import threading -from bs4 import UnicodeDammit - - +import xml.dom +import xml.parsers.expat from codecs import open -import xml.parsers.expat +from bs4 import UnicodeDammit +from logbook import Logger from eos import db +from eos.saveddata.fit import ImplantLocation from service.fit import Fit as svcFit - -# noinspection PyPackageRequirements -import wx - -from eos.saveddata.cargo import Cargo -from eos.saveddata.drone import Drone -from eos.saveddata.fighter import Fighter -from eos.saveddata.module import Module, State, Slot -from eos.saveddata.ship import Ship -from eos.saveddata.citadel import Citadel -from eos.saveddata.fit import Fit, ImplantLocation -from service.market import Market -from utils.strfunctions import sequential_rep, replace_ltgt - from service.port.dna import exportDna, importDna from service.port.eft import EftPort, SLOT_ORDER as EFT_SLOT_ORDER from service.port.esi import importESI, exportESI from service.port.shared import IPortUser, UserCancelException, processing_notify - +from service.port.xml import importXml, exportXml pyfalog = Logger(__name__) - # 2017/04/05 NOTE: simple validation, for xml file RE_XML_START = r'<\?xml\s+version="1.0"\s*\?>' -# -- 170327 Ignored description -- -RE_LTGT = "&(lt|gt);" -L_MARK = "<localized hint="" -# <localized hint="([^"]+)">([^\*]+)\*<\/localized> -LOCALIZED_PATTERN = re.compile(r'([^\*]+)\*') - - -def _extract_match(t): - m = LOCALIZED_PATTERN.match(t) - # hint attribute, text content - return m.group(1), m.group(2) - - -def _resolve_ship(fitting, sMkt, b_localized): - # type: (xml.dom.minidom.Element, service.market.Market, bool) -> eos.saveddata.fit.Fit - """ NOTE: Since it is meaningless unless a correct ship object can be constructed, - process flow changed - """ - # ------ Confirm ship - # Maelstrom - shipType = fitting.getElementsByTagName("shipType").item(0).getAttribute("value") - anything = None - if b_localized: - # expect an official name, emergency cache - shipType, anything = _extract_match(shipType) - - limit = 2 - ship = None - while True: - must_retry = False - try: - try: - ship = Ship(sMkt.getItem(shipType)) - except ValueError: - ship = Citadel(sMkt.getItem(shipType)) - except Exception as e: - pyfalog.warning("Caught exception on _resolve_ship") - pyfalog.error(e) - limit -= 1 - if limit is 0: - break - shipType = anything - must_retry = True - if not must_retry: - break - - if ship is None: - raise Exception("cannot resolve ship type.") - - fitobj = Fit(ship=ship) - # ------ Confirm fit name - anything = fitting.getAttribute("name") - # 2017/03/29 NOTE: - # if fit name contained "<" or ">" then reprace to named html entity by EVE client - # if re.search(RE_LTGT, anything): - if "<" in anything or ">" in anything: - anything = replace_ltgt(anything) - fitobj.name = anything - - return fitobj - - -def _resolve_module(hardware, sMkt, b_localized): - # type: (xml.dom.minidom.Element, service.market.Market, bool) -> eos.saveddata.module.Module - moduleName = hardware.getAttribute("type") - emergency = None - if b_localized: - # expect an official name, emergency cache - moduleName, emergency = _extract_match(moduleName) - - item = None - limit = 2 - while True: - must_retry = False - try: - item = sMkt.getItem(moduleName, eager="group.category") - except Exception as e: - pyfalog.warning("Caught exception on _resolve_module") - pyfalog.error(e) - limit -= 1 - if limit is 0: - break - moduleName = emergency - must_retry = True - if not must_retry: - break - return item - class Port(object): """Service which houses all import/export format functions""" @@ -288,7 +182,7 @@ class Port(object): @staticmethod def importFitFromBuffer(bufferStr, activeFit=None): - # type: (basestring, object) -> object + # type: (str, object) -> object # TODO: catch the exception? # activeFit is reserved?, bufferStr is unicode? (assume only clipboard string? sFit = svcFit.getInstance() @@ -307,7 +201,7 @@ class Port(object): @classmethod def importAuto(cls, string, path=None, activeFit=None, iportuser=None): - # type: (basestring, basestring, object, IPortUser, basestring) -> object + # type: (Port, str, str, object, IPortUser) -> object # Get first line and strip space symbols of it to avoid possible detection errors firstLine = re.split("[\n\r]+", string.strip(), maxsplit=1)[0] firstLine = firstLine.strip() @@ -335,206 +229,6 @@ class Port(object): # Use DNA format for all other cases return "DNA", (cls.importDna(string),) - @staticmethod - def importXml(text, iportuser=None): - # type: (str, IPortUser) -> list[eos.saveddata.fit.Fit] - sMkt = Market.getInstance() - doc = xml.dom.minidom.parseString(text) - # NOTE: - # When L_MARK is included at this point, - # Decided to be localized data - b_localized = L_MARK in text - fittings = doc.getElementsByTagName("fittings").item(0) - fittings = fittings.getElementsByTagName("fitting") - fit_list = [] - failed = 0 - - for fitting in fittings: - try: - fitobj = _resolve_ship(fitting, sMkt, b_localized) - except: - failed += 1 - continue - - # -- 170327 Ignored description -- - # read description from exported xml. (EVE client, EFT) - description = fitting.getElementsByTagName("description").item(0).getAttribute("value") - if description is None: - description = "" - elif len(description): - # convert
to "\n" and remove html tags. - if Port.is_tag_replace(): - description = replace_ltgt( - sequential_rep(description, r"<(br|BR)>", "\n", r"<[^<>]+>", "") - ) - fitobj.notes = description - - hardwares = fitting.getElementsByTagName("hardware") - moduleList = [] - for hardware in hardwares: - try: - item = _resolve_module(hardware, sMkt, b_localized) - if not item or not item.published: - continue - - if item.category.name == "Drone": - d = Drone(item) - d.amount = int(hardware.getAttribute("qty")) - fitobj.drones.append(d) - elif item.category.name == "Fighter": - ft = Fighter(item) - ft.amount = int(hardware.getAttribute("qty")) if ft.amount <= ft.fighterSquadronMaxSize else ft.fighterSquadronMaxSize - fitobj.fighters.append(ft) - elif hardware.getAttribute("slot").lower() == "cargo": - # although the eve client only support charges in cargo, third-party programs - # may support items or "refits" in cargo. Support these by blindly adding all - # cargo, not just charges - c = Cargo(item) - c.amount = int(hardware.getAttribute("qty")) - fitobj.cargo.append(c) - else: - try: - m = Module(item) - # When item can't be added to any slot (unknown item or just charge), ignore it - except ValueError: - pyfalog.warning("item can't be added to any slot (unknown item or just charge), ignore it") - continue - # Add subsystems before modules to make sure T3 cruisers have subsystems installed - if item.category.name == "Subsystem": - if m.fits(fitobj): - m.owner = fitobj - fitobj.modules.append(m) - else: - if m.isValidState(State.ACTIVE): - m.state = State.ACTIVE - - moduleList.append(m) - - except KeyboardInterrupt: - pyfalog.warning("Keyboard Interrupt") - continue - - # Recalc to get slot numbers correct for T3 cruisers - svcFit.getInstance().recalc(fitobj) - - for module in moduleList: - if module.fits(fitobj): - module.owner = fitobj - fitobj.modules.append(module) - - fit_list.append(fitobj) - if iportuser: # NOTE: Send current processing status - processing_notify( - iportuser, IPortUser.PROCESS_IMPORT | IPortUser.ID_UPDATE, - "Processing %s\n%s" % (fitobj.ship.name, fitobj.name) - ) - - return fit_list - - @staticmethod - def exportXml(iportuser=None, *fits): - doc = xml.dom.minidom.Document() - fittings = doc.createElement("fittings") - # fit count - fit_count = len(fits) - fittings.setAttribute("count", "%s" % fit_count) - doc.appendChild(fittings) - sFit = svcFit.getInstance() - - for i, fit in enumerate(fits): - try: - fitting = doc.createElement("fitting") - fitting.setAttribute("name", fit.name) - fittings.appendChild(fitting) - description = doc.createElement("description") - # -- 170327 Ignored description -- - try: - notes = fit.notes # unicode - - if notes: - notes = notes[:397] + '...' if len(notes) > 400 else notes - - description.setAttribute( - "value", re.sub("(\r|\n|\r\n)+", "
", notes) if notes is not None else "" - ) - except Exception as e: - pyfalog.warning("read description is failed, msg=%s\n" % e.args) - - fitting.appendChild(description) - shipType = doc.createElement("shipType") - shipType.setAttribute("value", fit.ship.name) - fitting.appendChild(shipType) - - charges = {} - slotNum = {} - for module in fit.modules: - if module.isEmpty: - continue - - slot = module.slot - - if slot == Slot.SUBSYSTEM: - # Order of subsystem matters based on this attr. See GH issue #130 - slotId = module.getModifiedItemAttr("subSystemSlot") - 125 - else: - if slot not in slotNum: - slotNum[slot] = 0 - - slotId = slotNum[slot] - slotNum[slot] += 1 - - hardware = doc.createElement("hardware") - hardware.setAttribute("type", module.item.name) - slotName = Slot.getName(slot).lower() - slotName = slotName if slotName != "high" else "hi" - hardware.setAttribute("slot", "%s slot %d" % (slotName, slotId)) - fitting.appendChild(hardware) - - if module.charge and sFit.serviceFittingOptions["exportCharges"]: - if module.charge.name not in charges: - charges[module.charge.name] = 0 - # `or 1` because some charges (ie scripts) are without qty - charges[module.charge.name] += module.numCharges or 1 - - for drone in fit.drones: - hardware = doc.createElement("hardware") - hardware.setAttribute("qty", "%d" % drone.amount) - hardware.setAttribute("slot", "drone bay") - hardware.setAttribute("type", drone.item.name) - fitting.appendChild(hardware) - - for fighter in fit.fighters: - hardware = doc.createElement("hardware") - hardware.setAttribute("qty", "%d" % fighter.amountActive) - hardware.setAttribute("slot", "fighter bay") - hardware.setAttribute("type", fighter.item.name) - fitting.appendChild(hardware) - - for cargo in fit.cargo: - if cargo.item.name not in charges: - charges[cargo.item.name] = 0 - charges[cargo.item.name] += cargo.amount - - for name, qty in list(charges.items()): - hardware = doc.createElement("hardware") - hardware.setAttribute("qty", "%d" % qty) - hardware.setAttribute("slot", "cargo") - hardware.setAttribute("type", name) - fitting.appendChild(hardware) - except Exception as e: - # print("Failed on fitID: %d" % fit.ID) - pyfalog.error("Failed on fitID: %d, message: %s" % e.message) - continue - finally: - if iportuser: - processing_notify( - iportuser, IPortUser.PROCESS_EXPORT | IPortUser.ID_UPDATE, - (i, "convert to xml (%s/%s) %s" % (i + 1, fit_count, fit.ship.name)) - ) -# wx.CallAfter(callback, i, "(%s/%s) %s" % (i, fit_count, fit.ship.name)) - - return doc.toprettyxml() - @staticmethod def exportMultiBuy(fit): export = "%s\n" % fit.ship.item.name @@ -611,3 +305,12 @@ class Port(object): @staticmethod def exportESI(fit): exportESI(fit) + + # XML-related methods + @staticmethod + def importXml(text, iportuser=None): + return importXml(text, iportuser) + + @staticmethod + def exportXml(iportuser=None, *fits): + exportXml(iportuser, *fits) diff --git a/service/port/xml.py b/service/port/xml.py new file mode 100644 index 000000000..d5a5f08e0 --- /dev/null +++ b/service/port/xml.py @@ -0,0 +1,325 @@ +# ============================================================================= +# Copyright (C) 2014 Ryan Holmes +# +# 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 . +# ============================================================================= + +import re +import xml.dom +import xml.parsers.expat + +from logbook import Logger + +from eos.saveddata.cargo import Cargo +from eos.saveddata.citadel import Citadel +from eos.saveddata.drone import Drone +from eos.saveddata.fighter import Fighter +from eos.saveddata.fit import Fit +from eos.saveddata.module import Module, State, Slot +from eos.saveddata.ship import Ship +from service.fit import Fit as svcFit +from service.market import Market +from utils.strfunctions import sequential_rep, replace_ltgt + +from service.port.shared import IPortUser, processing_notify + + +pyfalog = Logger(__name__) + +# -- 170327 Ignored description -- +RE_LTGT = "&(lt|gt);" +L_MARK = "<localized hint="" +# <localized hint="([^"]+)">([^\*]+)\*<\/localized> +LOCALIZED_PATTERN = re.compile(r'([^\*]+)\*') + + +def _extract_match(t): + m = LOCALIZED_PATTERN.match(t) + # hint attribute, text content + return m.group(1), m.group(2) + + +def _resolve_ship(fitting, sMkt, b_localized): + # type: (xml.dom.minidom.Element, service.market.Market, bool) -> eos.saveddata.fit.Fit + """ NOTE: Since it is meaningless unless a correct ship object can be constructed, + process flow changed + """ + # ------ Confirm ship + # Maelstrom + shipType = fitting.getElementsByTagName("shipType").item(0).getAttribute("value") + anything = None + if b_localized: + # expect an official name, emergency cache + shipType, anything = _extract_match(shipType) + + limit = 2 + ship = None + while True: + must_retry = False + try: + try: + ship = Ship(sMkt.getItem(shipType)) + except ValueError: + ship = Citadel(sMkt.getItem(shipType)) + except Exception as e: + pyfalog.warning("Caught exception on _resolve_ship") + pyfalog.error(e) + limit -= 1 + if limit is 0: + break + shipType = anything + must_retry = True + if not must_retry: + break + + if ship is None: + raise Exception("cannot resolve ship type.") + + fitobj = Fit(ship=ship) + # ------ Confirm fit name + anything = fitting.getAttribute("name") + # 2017/03/29 NOTE: + # if fit name contained "<" or ">" then reprace to named html entity by EVE client + # if re.search(RE_LTGT, anything): + if "<" in anything or ">" in anything: + anything = replace_ltgt(anything) + fitobj.name = anything + + return fitobj + + +def _resolve_module(hardware, sMkt, b_localized): + # type: (xml.dom.minidom.Element, service.market.Market, bool) -> eos.saveddata.module.Module + moduleName = hardware.getAttribute("type") + emergency = None + if b_localized: + # expect an official name, emergency cache + moduleName, emergency = _extract_match(moduleName) + + item = None + limit = 2 + while True: + must_retry = False + try: + item = sMkt.getItem(moduleName, eager="group.category") + except Exception as e: + pyfalog.warning("Caught exception on _resolve_module") + pyfalog.error(e) + limit -= 1 + if limit is 0: + break + moduleName = emergency + must_retry = True + if not must_retry: + break + return item + + +def importXml(text, iportuser): + # type: (str, IPortUser) -> list[eos.saveddata.fit.Fit] + sMkt = Market.getInstance() + doc = xml.dom.minidom.parseString(text) + # NOTE: + # When L_MARK is included at this point, + # Decided to be localized data + b_localized = L_MARK in text + fittings = doc.getElementsByTagName("fittings").item(0) + fittings = fittings.getElementsByTagName("fitting") + fit_list = [] + failed = 0 + + for fitting in fittings: + try: + fitobj = _resolve_ship(fitting, sMkt, b_localized) + except: + failed += 1 + continue + + # -- 170327 Ignored description -- + # read description from exported xml. (EVE client, EFT) + description = fitting.getElementsByTagName("description").item(0).getAttribute("value") + if description is None: + description = "" + elif len(description): + # convert
to "\n" and remove html tags. + if Port.is_tag_replace(): + description = replace_ltgt( + sequential_rep(description, r"<(br|BR)>", "\n", r"<[^<>]+>", "") + ) + fitobj.notes = description + + hardwares = fitting.getElementsByTagName("hardware") + moduleList = [] + for hardware in hardwares: + try: + item = _resolve_module(hardware, sMkt, b_localized) + if not item or not item.published: + continue + + if item.category.name == "Drone": + d = Drone(item) + d.amount = int(hardware.getAttribute("qty")) + fitobj.drones.append(d) + elif item.category.name == "Fighter": + ft = Fighter(item) + ft.amount = int(hardware.getAttribute("qty")) if ft.amount <= ft.fighterSquadronMaxSize else ft.fighterSquadronMaxSize + fitobj.fighters.append(ft) + elif hardware.getAttribute("slot").lower() == "cargo": + # although the eve client only support charges in cargo, third-party programs + # may support items or "refits" in cargo. Support these by blindly adding all + # cargo, not just charges + c = Cargo(item) + c.amount = int(hardware.getAttribute("qty")) + fitobj.cargo.append(c) + else: + try: + m = Module(item) + # When item can't be added to any slot (unknown item or just charge), ignore it + except ValueError: + pyfalog.warning("item can't be added to any slot (unknown item or just charge), ignore it") + continue + # Add subsystems before modules to make sure T3 cruisers have subsystems installed + if item.category.name == "Subsystem": + if m.fits(fitobj): + m.owner = fitobj + fitobj.modules.append(m) + else: + if m.isValidState(State.ACTIVE): + m.state = State.ACTIVE + + moduleList.append(m) + + except KeyboardInterrupt: + pyfalog.warning("Keyboard Interrupt") + continue + + # Recalc to get slot numbers correct for T3 cruisers + svcFit.getInstance().recalc(fitobj) + + for module in moduleList: + if module.fits(fitobj): + module.owner = fitobj + fitobj.modules.append(module) + + fit_list.append(fitobj) + if iportuser: # NOTE: Send current processing status + processing_notify( + iportuser, IPortUser.PROCESS_IMPORT | IPortUser.ID_UPDATE, + "Processing %s\n%s" % (fitobj.ship.name, fitobj.name) + ) + + return fit_list + + +def exportXml(iportuser, *fits): + doc = xml.dom.minidom.Document() + fittings = doc.createElement("fittings") + # fit count + fit_count = len(fits) + fittings.setAttribute("count", "%s" % fit_count) + doc.appendChild(fittings) + sFit = svcFit.getInstance() + + for i, fit in enumerate(fits): + try: + fitting = doc.createElement("fitting") + fitting.setAttribute("name", fit.name) + fittings.appendChild(fitting) + description = doc.createElement("description") + # -- 170327 Ignored description -- + try: + notes = fit.notes # unicode + + if notes: + notes = notes[:397] + '...' if len(notes) > 400 else notes + + description.setAttribute( + "value", re.sub("(\r|\n|\r\n)+", "
", notes) if notes is not None else "" + ) + except Exception as e: + pyfalog.warning("read description is failed, msg=%s\n" % e.args) + + fitting.appendChild(description) + shipType = doc.createElement("shipType") + shipType.setAttribute("value", fit.ship.name) + fitting.appendChild(shipType) + + charges = {} + slotNum = {} + for module in fit.modules: + if module.isEmpty: + continue + + slot = module.slot + + if slot == Slot.SUBSYSTEM: + # Order of subsystem matters based on this attr. See GH issue #130 + slotId = module.getModifiedItemAttr("subSystemSlot") - 125 + else: + if slot not in slotNum: + slotNum[slot] = 0 + + slotId = slotNum[slot] + slotNum[slot] += 1 + + hardware = doc.createElement("hardware") + hardware.setAttribute("type", module.item.name) + slotName = Slot.getName(slot).lower() + slotName = slotName if slotName != "high" else "hi" + hardware.setAttribute("slot", "%s slot %d" % (slotName, slotId)) + fitting.appendChild(hardware) + + if module.charge and sFit.serviceFittingOptions["exportCharges"]: + if module.charge.name not in charges: + charges[module.charge.name] = 0 + # `or 1` because some charges (ie scripts) are without qty + charges[module.charge.name] += module.numCharges or 1 + + for drone in fit.drones: + hardware = doc.createElement("hardware") + hardware.setAttribute("qty", "%d" % drone.amount) + hardware.setAttribute("slot", "drone bay") + hardware.setAttribute("type", drone.item.name) + fitting.appendChild(hardware) + + for fighter in fit.fighters: + hardware = doc.createElement("hardware") + hardware.setAttribute("qty", "%d" % fighter.amountActive) + hardware.setAttribute("slot", "fighter bay") + hardware.setAttribute("type", fighter.item.name) + fitting.appendChild(hardware) + + for cargo in fit.cargo: + if cargo.item.name not in charges: + charges[cargo.item.name] = 0 + charges[cargo.item.name] += cargo.amount + + for name, qty in list(charges.items()): + hardware = doc.createElement("hardware") + hardware.setAttribute("qty", "%d" % qty) + hardware.setAttribute("slot", "cargo") + hardware.setAttribute("type", name) + fitting.appendChild(hardware) + except Exception as e: + pyfalog.error("Failed on fitID: %d, message: %s" % e.message) + continue + finally: + if iportuser: + processing_notify( + iportuser, IPortUser.PROCESS_EXPORT | IPortUser.ID_UPDATE, + (i, "convert to xml (%s/%s) %s" % (i + 1, fit_count, fit.ship.name)) + ) + return doc.toprettyxml() From 52dbd8d9ef98bbdcd7c164af305c633165198998 Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Thu, 30 Aug 2018 16:17:56 +0300 Subject: [PATCH 82/95] Fix few export/import functions --- service/port/port.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/service/port/port.py b/service/port/port.py index 045f5561e..b821a126f 100644 --- a/service/port/port.py +++ b/service/port/port.py @@ -300,11 +300,11 @@ class Port(object): # ESI-related methods @staticmethod def importESI(string): - importESI(string) + return importESI(string) @staticmethod def exportESI(fit): - exportESI(fit) + return exportESI(fit) # XML-related methods @staticmethod @@ -313,4 +313,4 @@ class Port(object): @staticmethod def exportXml(iportuser=None, *fits): - exportXml(iportuser, *fits) + return exportXml(iportuser, *fits) From 8abad416bd5ca4045d94aadbedaaf9852f6e288d Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Thu, 30 Aug 2018 16:23:20 +0300 Subject: [PATCH 83/95] Split multibuy into its own file as well --- service/port/multibuy.py | 68 ++++++++++++++++++++++++++++++++++++++++ service/port/port.py | 63 +++++++------------------------------ 2 files changed, 80 insertions(+), 51 deletions(-) create mode 100644 service/port/multibuy.py diff --git a/service/port/multibuy.py b/service/port/multibuy.py new file mode 100644 index 000000000..2bf2d7a8a --- /dev/null +++ b/service/port/multibuy.py @@ -0,0 +1,68 @@ +# ============================================================================= +# Copyright (C) 2014 Ryan Holmes +# +# 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 . +# ============================================================================= + + +from service.fit import Fit as svcFit +from service.port.eft import SLOT_ORDER as EFT_SLOT_ORDER + + +def exportMultiBuy(fit): + export = "%s\n" % fit.ship.item.name + stuff = {} + sFit = svcFit.getInstance() + for module in fit.modules: + slot = module.slot + if slot not in stuff: + stuff[slot] = [] + curr = "%s\n" % module.item.name if module.item else "" + if module.charge and sFit.serviceFittingOptions["exportCharges"]: + curr += "%s x%s\n" % (module.charge.name, module.numCharges) + stuff[slot].append(curr) + + for slotType in EFT_SLOT_ORDER: + data = stuff.get(slotType) + if data is not None: + # export += "\n" + for curr in data: + export += curr + + if len(fit.drones) > 0: + for drone in fit.drones: + export += "%s x%s\n" % (drone.item.name, drone.amount) + + if len(fit.cargo) > 0: + for cargo in fit.cargo: + export += "%s x%s\n" % (cargo.item.name, cargo.amount) + + if len(fit.implants) > 0: + for implant in fit.implants: + export += "%s\n" % implant.item.name + + if len(fit.boosters) > 0: + for booster in fit.boosters: + export += "%s\n" % booster.item.name + + if len(fit.fighters) > 0: + for fighter in fit.fighters: + export += "%s x%s\n" % (fighter.item.name, fighter.amountActive) + + if export[-1] == "\n": + export = export[:-1] + + return export diff --git a/service/port/port.py b/service/port/port.py index b821a126f..bc09e301a 100644 --- a/service/port/port.py +++ b/service/port/port.py @@ -17,6 +17,7 @@ # along with pyfa. If not, see . # ============================================================================= + import re import os import threading @@ -31,8 +32,9 @@ from eos import db from eos.saveddata.fit import ImplantLocation from service.fit import Fit as svcFit from service.port.dna import exportDna, importDna -from service.port.eft import EftPort, SLOT_ORDER as EFT_SLOT_ORDER +from service.port.eft import EftPort from service.port.esi import importESI, exportESI +from service.port.multibuy import exportMultiBuy from service.port.shared import IPortUser, UserCancelException, processing_notify from service.port.xml import importXml, exportXml @@ -229,53 +231,7 @@ class Port(object): # Use DNA format for all other cases return "DNA", (cls.importDna(string),) - @staticmethod - def exportMultiBuy(fit): - export = "%s\n" % fit.ship.item.name - stuff = {} - sFit = svcFit.getInstance() - for module in fit.modules: - slot = module.slot - if slot not in stuff: - stuff[slot] = [] - curr = "%s\n" % module.item.name if module.item else "" - if module.charge and sFit.serviceFittingOptions["exportCharges"]: - curr += "%s x%s\n" % (module.charge.name, module.numCharges) - stuff[slot].append(curr) - - for slotType in EFT_SLOT_ORDER: - data = stuff.get(slotType) - if data is not None: - # export += "\n" - for curr in data: - export += curr - - if len(fit.drones) > 0: - for drone in fit.drones: - export += "%s x%s\n" % (drone.item.name, drone.amount) - - if len(fit.cargo) > 0: - for cargo in fit.cargo: - export += "%s x%s\n" % (cargo.item.name, cargo.amount) - - if len(fit.implants) > 0: - for implant in fit.implants: - export += "%s\n" % implant.item.name - - if len(fit.boosters) > 0: - for booster in fit.boosters: - export += "%s\n" % booster.item.name - - if len(fit.fighters) > 0: - for fighter in fit.fighters: - export += "%s x%s\n" % (fighter.item.name, fighter.amountActive) - - if export[-1] == "\n": - export = export[:-1] - - return export - - # EFT-related methods + ### EFT-related methods @staticmethod def importEft(eftString): return EftPort.importEft(eftString) @@ -288,7 +244,7 @@ class Port(object): def exportEft(cls, fit, options): return EftPort.exportEft(fit, options) - # DNA-related methods + ### DNA-related methods @staticmethod def importDna(string): return importDna(string) @@ -297,7 +253,7 @@ class Port(object): def exportDna(fit): return exportDna(fit) - # ESI-related methods + ### ESI-related methods @staticmethod def importESI(string): return importESI(string) @@ -306,7 +262,7 @@ class Port(object): def exportESI(fit): return exportESI(fit) - # XML-related methods + ### XML-related methods @staticmethod def importXml(text, iportuser=None): return importXml(text, iportuser) @@ -314,3 +270,8 @@ class Port(object): @staticmethod def exportXml(iportuser=None, *fits): return exportXml(iportuser, *fits) + + ### Multibuy-related methods + @staticmethod + def exportMultiBuy(fit): + return exportMultiBuy(fit) From f4311d1cefddd3933edfaf1acf87605c2caac325 Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Thu, 30 Aug 2018 21:39:28 +0300 Subject: [PATCH 84/95] Remove object which we don't actually need --- service/port/eft.py | 1017 +++++++++++++++++++++--------------------- service/port/port.py | 10 +- 2 files changed, 511 insertions(+), 516 deletions(-) diff --git a/service/port/eft.py b/service/port/eft.py index 80640bfff..645a2ca2d 100644 --- a/service/port/eft.py +++ b/service/port/eft.py @@ -63,548 +63,543 @@ EFT_OPTIONS = { } -class EftPort: +def exportEft(fit, options): + # EFT formatted export is split in several sections, each section is + # separated from another using 2 blank lines. Sections might have several + # sub-sections, which are separated by 1 blank line + sections = [] - @classmethod - def exportEft(cls, fit, options): - # EFT formatted export is split in several sections, each section is - # separated from another using 2 blank lines. Sections might have several - # sub-sections, which are separated by 1 blank line - sections = [] + header = '[{}, {}]'.format(fit.ship.item.name, fit.name) - header = '[{}, {}]'.format(fit.ship.item.name, fit.name) + # Section 1: modules, rigs, subsystems, services + modsBySlotType = {} + sFit = svcFit.getInstance() + for module in fit.modules: + modsBySlotType.setdefault(module.slot, []).append(module) + modSection = [] - # Section 1: modules, rigs, subsystems, services - modsBySlotType = {} - sFit = svcFit.getInstance() - for module in fit.modules: - modsBySlotType.setdefault(module.slot, []).append(module) - modSection = [] - - mutants = {} # Format: {reference number: module} - mutantReference = 1 - for slotType in SLOT_ORDER: - rackLines = [] - modules = modsBySlotType.get(slotType, ()) - for module in modules: - if module.item: - mutated = bool(module.mutators) - # if module was mutated, use base item name for export - if mutated: - modName = module.baseItem.name - else: - modName = module.item.name - if mutated and options & Options.MUTATIONS.value: - mutants[mutantReference] = module - mutationSuffix = ' [{}]'.format(mutantReference) - mutantReference += 1 - else: - mutationSuffix = '' - modOfflineSuffix = ' {}'.format(OFFLINE_SUFFIX) if module.state == State.OFFLINE else '' - if module.charge and sFit.serviceFittingOptions['exportCharges']: - rackLines.append('{}, {}{}{}'.format( - modName, module.charge.name, modOfflineSuffix, mutationSuffix)) - else: - rackLines.append('{}{}{}'.format(modName, modOfflineSuffix, mutationSuffix)) + mutants = {} # Format: {reference number: module} + mutantReference = 1 + for slotType in SLOT_ORDER: + rackLines = [] + modules = modsBySlotType.get(slotType, ()) + for module in modules: + if module.item: + mutated = bool(module.mutators) + # if module was mutated, use base item name for export + if mutated: + modName = module.baseItem.name else: - rackLines.append('[Empty {} slot]'.format( - Slot.getName(slotType).capitalize() if slotType is not None else '')) - if rackLines: - modSection.append('\n'.join(rackLines)) - if modSection: - sections.append('\n\n'.join(modSection)) - - # Section 2: drones, fighters - minionSection = [] - droneLines = [] - for drone in sorted(fit.drones, key=lambda d: d.item.name): - droneLines.append('{} x{}'.format(drone.item.name, drone.amount)) - if droneLines: - minionSection.append('\n'.join(droneLines)) - fighterLines = [] - for fighter in sorted(fit.fighters, key=lambda f: f.item.name): - fighterLines.append('{} x{}'.format(fighter.item.name, fighter.amountActive)) - if fighterLines: - minionSection.append('\n'.join(fighterLines)) - if minionSection: - sections.append('\n\n'.join(minionSection)) - - # Section 3: implants, boosters - if options & Options.IMPLANTS.value: - charSection = [] - implantLines = [] - for implant in fit.implants: - implantLines.append(implant.item.name) - if implantLines: - charSection.append('\n'.join(implantLines)) - boosterLines = [] - for booster in fit.boosters: - boosterLines.append(booster.item.name) - if boosterLines: - charSection.append('\n'.join(boosterLines)) - if charSection: - sections.append('\n\n'.join(charSection)) - - # Section 4: cargo - cargoLines = [] - for cargo in sorted( - fit.cargo, - key=lambda c: (c.item.group.category.name, c.item.group.name, c.item.name) - ): - cargoLines.append('{} x{}'.format(cargo.item.name, cargo.amount)) - if cargoLines: - sections.append('\n'.join(cargoLines)) - - # Section 5: mutated modules' details - mutationLines = [] - if mutants and options & Options.MUTATIONS.value: - for mutantReference in sorted(mutants): - mutant = mutants[mutantReference] - mutatedAttrs = {} - for attrID, mutator in mutant.mutators.items(): - attrName = getAttributeInfo(attrID).name - mutatedAttrs[attrName] = mutator.value - mutationLines.append('[{}] {}'.format(mutantReference, mutant.baseItem.name)) - mutationLines.append(' {}'.format(mutant.mutaplasmid.item.name)) - # Round to 7th significant number to avoid exporting float errors - customAttrsLine = ', '.join( - '{} {}'.format(a, roundToPrec(mutatedAttrs[a], 7)) - for a in sorted(mutatedAttrs)) - mutationLines.append(' {}'.format(customAttrsLine)) - if mutationLines: - sections.append('\n'.join(mutationLines)) - - return '{}\n\n{}'.format(header, '\n\n\n'.join(sections)) - - @classmethod - def importEft(cls, eftString): - lines = cls.__prepareImportString(eftString) - try: - fit = cls.__createFit(lines) - except EftImportError: - return - - aFit = AbstractFit() - aFit.mutations = cls.__getMutationData(lines) - - nameChars = '[^,/\[\]]' # Characters which are allowed to be used in name - stubPattern = '^\[.+?\]$' - modulePattern = '^(?P{0}+?)(,\s*(?P{0}+?))?(?P\s*{1})?(\s*\[(?P\d+?)\])?$'.format(nameChars, OFFLINE_SUFFIX) - droneCargoPattern = '^(?P{}+?) x(?P\d+?)$'.format(nameChars) - - sections = [] - for section in cls.__importSectionIter(lines): - for line in section.lines: - # Stub line - if re.match(stubPattern, line): - section.itemSpecs.append(None) - continue - # Items with quantity specifier - m = re.match(droneCargoPattern, line) - if m: - try: - itemSpec = MultiItemSpec(m.group('typeName')) - # Items which cannot be fetched are considered as stubs - except EftImportError: - section.itemSpecs.append(None) - else: - itemSpec.amount = int(m.group('amount')) - section.itemSpecs.append(itemSpec) - continue - # All other items - m = re.match(modulePattern, line) - if m: - try: - itemSpec = RegularItemSpec(m.group('typeName'), chargeName=m.group('chargeName')) - # Items which cannot be fetched are considered as stubs - except EftImportError: - section.itemSpecs.append(None) - else: - if m.group('offline'): - itemSpec.offline = True - if m.group('mutation'): - itemSpec.mutationIdx = int(m.group('mutation')) - section.itemSpecs.append(itemSpec) - continue - clearTail(section.itemSpecs) - sections.append(section) - - - hasDroneBay = any(s.isDroneBay for s in sections) - hasFighterBay = any(s.isFighterBay for s in sections) - for section in sections: - if section.isModuleRack: - aFit.addModules(section.itemSpecs) - elif section.isImplantRack: - for itemSpec in section.itemSpecs: - aFit.addImplant(itemSpec) - elif section.isDroneBay: - for itemSpec in section.itemSpecs: - aFit.addDrone(itemSpec) - elif section.isFighterBay: - for itemSpec in section.itemSpecs: - aFit.addFighter(itemSpec) - elif section.isCargoHold: - for itemSpec in section.itemSpecs: - aFit.addCargo(itemSpec) - # Mix between different kinds of item specs (can happen when some - # blank lines are removed) + modName = module.item.name + if mutated and options & Options.MUTATIONS.value: + mutants[mutantReference] = module + mutationSuffix = ' [{}]'.format(mutantReference) + mutantReference += 1 + else: + mutationSuffix = '' + modOfflineSuffix = ' {}'.format(OFFLINE_SUFFIX) if module.state == State.OFFLINE else '' + if module.charge and sFit.serviceFittingOptions['exportCharges']: + rackLines.append('{}, {}{}{}'.format( + modName, module.charge.name, modOfflineSuffix, mutationSuffix)) + else: + rackLines.append('{}{}{}'.format(modName, modOfflineSuffix, mutationSuffix)) else: - for itemSpec in section.itemSpecs: - if itemSpec is None: - continue - if itemSpec.isModule: - aFit.addModule(itemSpec) - elif itemSpec.isImplant: - aFit.addImplant(itemSpec) - elif itemSpec.isDrone and not hasDroneBay: - aFit.addDrone(itemSpec) - elif itemSpec.isFighter and not hasFighterBay: - aFit.addFighter(itemSpec) - elif itemSpec.isCargo: - aFit.addCargo(itemSpec) + rackLines.append('[Empty {} slot]'.format( + Slot.getName(slotType).capitalize() if slotType is not None else '')) + if rackLines: + modSection.append('\n'.join(rackLines)) + if modSection: + sections.append('\n\n'.join(modSection)) - # Subsystems first because they modify slot amount - for m in aFit.subsystems: + # Section 2: drones, fighters + minionSection = [] + droneLines = [] + for drone in sorted(fit.drones, key=lambda d: d.item.name): + droneLines.append('{} x{}'.format(drone.item.name, drone.amount)) + if droneLines: + minionSection.append('\n'.join(droneLines)) + fighterLines = [] + for fighter in sorted(fit.fighters, key=lambda f: f.item.name): + fighterLines.append('{} x{}'.format(fighter.item.name, fighter.amountActive)) + if fighterLines: + minionSection.append('\n'.join(fighterLines)) + if minionSection: + sections.append('\n\n'.join(minionSection)) + + # Section 3: implants, boosters + if options & Options.IMPLANTS.value: + charSection = [] + implantLines = [] + for implant in fit.implants: + implantLines.append(implant.item.name) + if implantLines: + charSection.append('\n'.join(implantLines)) + boosterLines = [] + for booster in fit.boosters: + boosterLines.append(booster.item.name) + if boosterLines: + charSection.append('\n'.join(boosterLines)) + if charSection: + sections.append('\n\n'.join(charSection)) + + # Section 4: cargo + cargoLines = [] + for cargo in sorted( + fit.cargo, + key=lambda c: (c.item.group.category.name, c.item.group.name, c.item.name) + ): + cargoLines.append('{} x{}'.format(cargo.item.name, cargo.amount)) + if cargoLines: + sections.append('\n'.join(cargoLines)) + + # Section 5: mutated modules' details + mutationLines = [] + if mutants and options & Options.MUTATIONS.value: + for mutantReference in sorted(mutants): + mutant = mutants[mutantReference] + mutatedAttrs = {} + for attrID, mutator in mutant.mutators.items(): + attrName = getAttributeInfo(attrID).name + mutatedAttrs[attrName] = mutator.value + mutationLines.append('[{}] {}'.format(mutantReference, mutant.baseItem.name)) + mutationLines.append(' {}'.format(mutant.mutaplasmid.item.name)) + # Round to 7th significant number to avoid exporting float errors + customAttrsLine = ', '.join( + '{} {}'.format(a, roundToPrec(mutatedAttrs[a], 7)) + for a in sorted(mutatedAttrs)) + mutationLines.append(' {}'.format(customAttrsLine)) + if mutationLines: + sections.append('\n'.join(mutationLines)) + + return '{}\n\n{}'.format(header, '\n\n\n'.join(sections)) + + +def importEft(eftString): + lines = _importPrepareString(eftString) + try: + fit = _importCreateFit(lines) + except EftImportError: + return + + aFit = AbstractFit() + aFit.mutations = _importGetMutationData(lines) + + nameChars = '[^,/\[\]]' # Characters which are allowed to be used in name + stubPattern = '^\[.+?\]$' + modulePattern = '^(?P{0}+?)(,\s*(?P{0}+?))?(?P\s*{1})?(\s*\[(?P\d+?)\])?$'.format(nameChars, OFFLINE_SUFFIX) + droneCargoPattern = '^(?P{}+?) x(?P\d+?)$'.format(nameChars) + + sections = [] + for section in _importSectionIter(lines): + for line in section.lines: + # Stub line + if re.match(stubPattern, line): + section.itemSpecs.append(None) + continue + # Items with quantity specifier + m = re.match(droneCargoPattern, line) + if m: + try: + itemSpec = MultiItemSpec(m.group('typeName')) + # Items which cannot be fetched are considered as stubs + except EftImportError: + section.itemSpecs.append(None) + else: + itemSpec.amount = int(m.group('amount')) + section.itemSpecs.append(itemSpec) + continue + # All other items + m = re.match(modulePattern, line) + if m: + try: + itemSpec = RegularItemSpec(m.group('typeName'), chargeName=m.group('chargeName')) + # Items which cannot be fetched are considered as stubs + except EftImportError: + section.itemSpecs.append(None) + else: + if m.group('offline'): + itemSpec.offline = True + if m.group('mutation'): + itemSpec.mutationIdx = int(m.group('mutation')) + section.itemSpecs.append(itemSpec) + continue + _clearTail(section.itemSpecs) + sections.append(section) + + + hasDroneBay = any(s.isDroneBay for s in sections) + hasFighterBay = any(s.isFighterBay for s in sections) + for section in sections: + if section.isModuleRack: + aFit.addModules(section.itemSpecs) + elif section.isImplantRack: + for itemSpec in section.itemSpecs: + aFit.addImplant(itemSpec) + elif section.isDroneBay: + for itemSpec in section.itemSpecs: + aFit.addDrone(itemSpec) + elif section.isFighterBay: + for itemSpec in section.itemSpecs: + aFit.addFighter(itemSpec) + elif section.isCargoHold: + for itemSpec in section.itemSpecs: + aFit.addCargo(itemSpec) + # Mix between different kinds of item specs (can happen when some + # blank lines are removed) + else: + for itemSpec in section.itemSpecs: + if itemSpec is None: + continue + if itemSpec.isModule: + aFit.addModule(itemSpec) + elif itemSpec.isImplant: + aFit.addImplant(itemSpec) + elif itemSpec.isDrone and not hasDroneBay: + aFit.addDrone(itemSpec) + elif itemSpec.isFighter and not hasFighterBay: + aFit.addFighter(itemSpec) + elif itemSpec.isCargo: + aFit.addCargo(itemSpec) + + # Subsystems first because they modify slot amount + for m in aFit.subsystems: + if m is None: + dummy = Module.buildEmpty(aFit.getSlotByContainer(aFit.subsystems)) + dummy.owner = fit + fit.modules.appendIgnoreEmpty(dummy) + elif m.fits(fit): + m.owner = fit + fit.modules.appendIgnoreEmpty(m) + svcFit.getInstance().recalc(fit) + + # Other stuff + for modRack in ( + aFit.rigs, + aFit.services, + aFit.modulesHigh, + aFit.modulesMed, + aFit.modulesLow, + ): + for m in modRack: if m is None: - dummy = Module.buildEmpty(aFit.getSlotByContainer(aFit.subsystems)) + dummy = Module.buildEmpty(aFit.getSlotByContainer(modRack)) dummy.owner = fit fit.modules.appendIgnoreEmpty(dummy) elif m.fits(fit): m.owner = fit + if not m.isValidState(m.state): + pyfalog.warning('EftPort.importEft: module {} cannot have state {}', m, m.state) fit.modules.appendIgnoreEmpty(m) - svcFit.getInstance().recalc(fit) + for implant in aFit.implants: + fit.implants.append(implant) + for booster in aFit.boosters: + fit.boosters.append(booster) + for drone in aFit.drones.values(): + fit.drones.append(drone) + for fighter in aFit.fighters: + fit.fighters.append(fighter) + for cargo in aFit.cargo.values(): + fit.cargo.append(cargo) - # Other stuff - for modRack in ( - aFit.rigs, - aFit.services, - aFit.modulesHigh, - aFit.modulesMed, - aFit.modulesLow, - ): - for m in modRack: - if m is None: - dummy = Module.buildEmpty(aFit.getSlotByContainer(modRack)) - dummy.owner = fit - fit.modules.appendIgnoreEmpty(dummy) - elif m.fits(fit): - m.owner = fit - if not m.isValidState(m.state): - pyfalog.warning('EftPort.importEft: module {} cannot have state {}', m, m.state) - fit.modules.appendIgnoreEmpty(m) - for implant in aFit.implants: - fit.implants.append(implant) - for booster in aFit.boosters: - fit.boosters.append(booster) - for drone in aFit.drones.values(): - fit.drones.append(drone) - for fighter in aFit.fighters: - fit.fighters.append(fighter) - for cargo in aFit.cargo.values(): - fit.cargo.append(cargo) + return fit - return fit - @staticmethod - def importEftCfg(shipname, contents, iportuser): - """Handle import from EFT config store file""" +def importEftCfg(shipname, contents, iportuser): + """Handle import from EFT config store file""" + + # Check if we have such ship in database, bail if we don't + sMkt = Market.getInstance() + try: + sMkt.getItem(shipname) + except: + return [] # empty list is expected + + fits = [] # List for fits + fitIndices = [] # List for starting line numbers for each fit + lines = re.split('[\n\r]+', contents) # Separate string into lines + + for line in lines: + # Detect fit header + if line[:1] == "[" and line[-1:] == "]": + # Line index where current fit starts + startPos = lines.index(line) + fitIndices.append(startPos) + + for i, startPos in enumerate(fitIndices): + # End position is last file line if we're trying to get it for last fit, + # or start position of next fit minus 1 + endPos = len(lines) if i == len(fitIndices) - 1 else fitIndices[i + 1] + + # Finally, get lines for current fitting + fitLines = lines[startPos:endPos] - # Check if we have such ship in database, bail if we don't - sMkt = Market.getInstance() try: - sMkt.getItem(shipname) - except: - return [] # empty list is expected - - fits = [] # List for fits - fitIndices = [] # List for starting line numbers for each fit - lines = re.split('[\n\r]+', contents) # Separate string into lines - - for line in lines: - # Detect fit header - if line[:1] == "[" and line[-1:] == "]": - # Line index where current fit starts - startPos = lines.index(line) - fitIndices.append(startPos) - - for i, startPos in enumerate(fitIndices): - # End position is last file line if we're trying to get it for last fit, - # or start position of next fit minus 1 - endPos = len(lines) if i == len(fitIndices) - 1 else fitIndices[i + 1] - - # Finally, get lines for current fitting - fitLines = lines[startPos:endPos] - + # Create fit object + fitobj = Fit() + # Strip square brackets and pull out a fit name + fitobj.name = fitLines[0][1:-1] + # Assign ship to fitting try: - # Create fit object - fitobj = Fit() - # Strip square brackets and pull out a fit name - fitobj.name = fitLines[0][1:-1] - # Assign ship to fitting - try: - fitobj.ship = Ship(sMkt.getItem(shipname)) - except ValueError: - fitobj.ship = Citadel(sMkt.getItem(shipname)) + fitobj.ship = Ship(sMkt.getItem(shipname)) + except ValueError: + fitobj.ship = Citadel(sMkt.getItem(shipname)) - moduleList = [] - for x in range(1, len(fitLines)): - line = fitLines[x] - if not line: + moduleList = [] + for x in range(1, len(fitLines)): + line = fitLines[x] + if not line: + continue + + # Parse line into some data we will need + misc = re.match("(Drones|Implant|Booster)_(Active|Inactive)=(.+)", line) + cargo = re.match("Cargohold=(.+)", line) + # 2017/03/27 NOTE: store description from EFT + description = re.match("Description=(.+)", line) + + if misc: + entityType = misc.group(1) + entityState = misc.group(2) + entityData = misc.group(3) + if entityType == "Drones": + droneData = re.match("(.+),([0-9]+)", entityData) + # Get drone name and attempt to detect drone number + droneName = droneData.group(1) if droneData else entityData + droneAmount = int(droneData.group(2)) if droneData else 1 + # Bail if we can't get item or it's not from drone category + try: + droneItem = sMkt.getItem(droneName, eager="group.category") + except: + pyfalog.warning("Cannot get item.") + continue + if droneItem.category.name == "Drone": + # Add drone to the fitting + d = Drone(droneItem) + d.amount = droneAmount + if entityState == "Active": + d.amountActive = droneAmount + elif entityState == "Inactive": + d.amountActive = 0 + fitobj.drones.append(d) + elif droneItem.category.name == "Fighter": # EFT saves fighter as drones + ft = Fighter(droneItem) + ft.amount = int(droneAmount) if ft.amount <= ft.fighterSquadronMaxSize else ft.fighterSquadronMaxSize + fitobj.fighters.append(ft) + else: + continue + elif entityType == "Implant": + # Bail if we can't get item or it's not from implant category + try: + implantItem = sMkt.getItem(entityData, eager="group.category") + except: + pyfalog.warning("Cannot get item.") + continue + if implantItem.category.name != "Implant": + continue + # Add implant to the fitting + imp = Implant(implantItem) + if entityState == "Active": + imp.active = True + elif entityState == "Inactive": + imp.active = False + fitobj.implants.append(imp) + elif entityType == "Booster": + # Bail if we can't get item or it's not from implant category + try: + boosterItem = sMkt.getItem(entityData, eager="group.category") + except: + pyfalog.warning("Cannot get item.") + continue + # All boosters have implant category + if boosterItem.category.name != "Implant": + continue + # Add booster to the fitting + b = Booster(boosterItem) + if entityState == "Active": + b.active = True + elif entityState == "Inactive": + b.active = False + fitobj.boosters.append(b) + # If we don't have any prefixes, then it's a module + elif cargo: + cargoData = re.match("(.+),([0-9]+)", cargo.group(1)) + cargoName = cargoData.group(1) if cargoData else cargo.group(1) + cargoAmount = int(cargoData.group(2)) if cargoData else 1 + # Bail if we can't get item + try: + item = sMkt.getItem(cargoName) + except: + pyfalog.warning("Cannot get item.") + continue + # Add Cargo to the fitting + c = Cargo(item) + c.amount = cargoAmount + fitobj.cargo.append(c) + # 2017/03/27 NOTE: store description from EFT + elif description: + fitobj.notes = description.group(1).replace("|", "\n") + else: + withCharge = re.match("(.+),(.+)", line) + modName = withCharge.group(1) if withCharge else line + chargeName = withCharge.group(2) if withCharge else None + # If we can't get module item, skip it + try: + modItem = sMkt.getItem(modName) + except: + pyfalog.warning("Cannot get item.") continue - # Parse line into some data we will need - misc = re.match("(Drones|Implant|Booster)_(Active|Inactive)=(.+)", line) - cargo = re.match("Cargohold=(.+)", line) - # 2017/03/27 NOTE: store description from EFT - description = re.match("Description=(.+)", line) + # Create module + m = Module(modItem) - if misc: - entityType = misc.group(1) - entityState = misc.group(2) - entityData = misc.group(3) - if entityType == "Drones": - droneData = re.match("(.+),([0-9]+)", entityData) - # Get drone name and attempt to detect drone number - droneName = droneData.group(1) if droneData else entityData - droneAmount = int(droneData.group(2)) if droneData else 1 - # Bail if we can't get item or it's not from drone category - try: - droneItem = sMkt.getItem(droneName, eager="group.category") - except: - pyfalog.warning("Cannot get item.") - continue - if droneItem.category.name == "Drone": - # Add drone to the fitting - d = Drone(droneItem) - d.amount = droneAmount - if entityState == "Active": - d.amountActive = droneAmount - elif entityState == "Inactive": - d.amountActive = 0 - fitobj.drones.append(d) - elif droneItem.category.name == "Fighter": # EFT saves fighter as drones - ft = Fighter(droneItem) - ft.amount = int(droneAmount) if ft.amount <= ft.fighterSquadronMaxSize else ft.fighterSquadronMaxSize - fitobj.fighters.append(ft) - else: - continue - elif entityType == "Implant": - # Bail if we can't get item or it's not from implant category - try: - implantItem = sMkt.getItem(entityData, eager="group.category") - except: - pyfalog.warning("Cannot get item.") - continue - if implantItem.category.name != "Implant": - continue - # Add implant to the fitting - imp = Implant(implantItem) - if entityState == "Active": - imp.active = True - elif entityState == "Inactive": - imp.active = False - fitobj.implants.append(imp) - elif entityType == "Booster": - # Bail if we can't get item or it's not from implant category - try: - boosterItem = sMkt.getItem(entityData, eager="group.category") - except: - pyfalog.warning("Cannot get item.") - continue - # All boosters have implant category - if boosterItem.category.name != "Implant": - continue - # Add booster to the fitting - b = Booster(boosterItem) - if entityState == "Active": - b.active = True - elif entityState == "Inactive": - b.active = False - fitobj.boosters.append(b) - # If we don't have any prefixes, then it's a module - elif cargo: - cargoData = re.match("(.+),([0-9]+)", cargo.group(1)) - cargoName = cargoData.group(1) if cargoData else cargo.group(1) - cargoAmount = int(cargoData.group(2)) if cargoData else 1 - # Bail if we can't get item - try: - item = sMkt.getItem(cargoName) - except: - pyfalog.warning("Cannot get item.") - continue - # Add Cargo to the fitting - c = Cargo(item) - c.amount = cargoAmount - fitobj.cargo.append(c) - # 2017/03/27 NOTE: store description from EFT - elif description: - fitobj.notes = description.group(1).replace("|", "\n") + # Add subsystems before modules to make sure T3 cruisers have subsystems installed + if modItem.category.name == "Subsystem": + if m.fits(fitobj): + fitobj.modules.append(m) else: - withCharge = re.match("(.+),(.+)", line) - modName = withCharge.group(1) if withCharge else line - chargeName = withCharge.group(2) if withCharge else None - # If we can't get module item, skip it - try: - modItem = sMkt.getItem(modName) - except: - pyfalog.warning("Cannot get item.") - continue + m.owner = fitobj + # Activate mod if it is activable + if m.isValidState(State.ACTIVE): + m.state = State.ACTIVE + # Add charge to mod if applicable, on any errors just don't add anything + if chargeName: + try: + chargeItem = sMkt.getItem(chargeName, eager="group.category") + if chargeItem.category.name == "Charge": + m.charge = chargeItem + except: + pyfalog.warning("Cannot get item.") + pass + # Append module to fit + moduleList.append(m) - # Create module - m = Module(modItem) + # Recalc to get slot numbers correct for T3 cruisers + svcFit.getInstance().recalc(fitobj) - # Add subsystems before modules to make sure T3 cruisers have subsystems installed - if modItem.category.name == "Subsystem": - if m.fits(fitobj): - fitobj.modules.append(m) - else: - m.owner = fitobj - # Activate mod if it is activable - if m.isValidState(State.ACTIVE): - m.state = State.ACTIVE - # Add charge to mod if applicable, on any errors just don't add anything - if chargeName: - try: - chargeItem = sMkt.getItem(chargeName, eager="group.category") - if chargeItem.category.name == "Charge": - m.charge = chargeItem - except: - pyfalog.warning("Cannot get item.") - pass - # Append module to fit - moduleList.append(m) + for module in moduleList: + if module.fits(fitobj): + fitobj.modules.append(module) - # Recalc to get slot numbers correct for T3 cruisers - svcFit.getInstance().recalc(fitobj) + # Append fit to list of fits + fits.append(fitobj) - for module in moduleList: - if module.fits(fitobj): - fitobj.modules.append(module) + if iportuser: # NOTE: Send current processing status + processing_notify( + iportuser, IPortUser.PROCESS_IMPORT | IPortUser.ID_UPDATE, + "%s:\n%s" % (fitobj.ship.name, fitobj.name) + ) - # Append fit to list of fits - fits.append(fitobj) + # Skip fit silently if we get an exception + except Exception as e: + pyfalog.error("Caught exception on fit.") + pyfalog.error(e) + pass - if iportuser: # NOTE: Send current processing status - processing_notify( - iportuser, IPortUser.PROCESS_IMPORT | IPortUser.ID_UPDATE, - "%s:\n%s" % (fitobj.ship.name, fitobj.name) - ) + return fits - # Skip fit silently if we get an exception - except Exception as e: - pyfalog.error("Caught exception on fit.") - pyfalog.error(e) - pass - return fits +def _importPrepareString(eftString): + lines = eftString.splitlines() + for i in range(len(lines)): + lines[i] = lines[i].strip() + while lines and not lines[0]: + del lines[0] + while lines and not lines[-1]: + del lines[-1] + return lines - @staticmethod - def __prepareImportString(eftString): - lines = eftString.splitlines() - for i in range(len(lines)): - lines[i] = lines[i].strip() - while lines and not lines[0]: - del lines[0] - while lines and not lines[-1]: - del lines[-1] - return lines - - @staticmethod - def __getMutationData(lines): - data = {} - consumedIndices = set() - for i in range(len(lines)): - line = lines[i] - m = re.match('^\[(?P\d+)\]', line) - if m: - ref = int(m.group('ref')) - # Attempt to apply mutation is useless w/o mutaplasmid, so skip it - # altogether if we have no info on it - try: - mutaName = lines[i + 1] - except IndexError: - continue - else: - consumedIndices.add(i) - consumedIndices.add(i + 1) - # Get custom attribute values - mutaAttrs = {} - try: - mutaAttrsLine = lines[i + 2] - except IndexError: - pass - else: - consumedIndices.add(i + 2) - pairs = [p.strip() for p in mutaAttrsLine.split(',')] - for pair in pairs: - try: - attrName, value = pair.split(' ') - except ValueError: - continue - try: - value = float(value) - except (ValueError, TypeError): - continue - attrInfo = getAttributeInfo(attrName.strip()) - if attrInfo is None: - continue - mutaAttrs[attrInfo.ID] = value - mutaItem = fetchItem(mutaName) - if mutaItem is None: - continue - data[ref] = (mutaItem, mutaAttrs) - # If we got here, we have seen at least correct reference line and - # mutaplasmid name line - i += 2 - # Bonus points for seeing correct attrs line. Worst case we - # will have to scan it once again - if mutaAttrs: - i += 1 - # Cleanup the lines from mutaplasmid info - for i in sorted(consumedIndices, reverse=True): - del lines[i] - return data - - @staticmethod - def __importSectionIter(lines): - section = Section() - for line in lines: - if not line: - if section.lines: - yield section - section = Section() - else: - section.lines.append(line) - if section.lines: - yield section - - @staticmethod - def __createFit(lines): - """Create fit and set top-level entity (ship or citadel).""" - fit = Fit() - header = lines.pop(0) - m = re.match('\[(?P[\w\s]+),\s*(?P.+)\]', header) - if not m: - pyfalog.warning('EftPort.importEft: corrupted fit header') - raise EftImportError - shipType = m.group('shipType').strip() - fitName = m.group('fitName').strip() - try: - ship = fetchItem(shipType) +def _importGetMutationData(lines): + data = {} + consumedIndices = set() + for i in range(len(lines)): + line = lines[i] + m = re.match('^\[(?P\d+)\]', line) + if m: + ref = int(m.group('ref')) + # Attempt to apply mutation is useless w/o mutaplasmid, so skip it + # altogether if we have no info on it try: - fit.ship = Ship(ship) - except ValueError: - fit.ship = Citadel(ship) - fit.name = fitName - except: - pyfalog.warning('EftPort.importEft: exception caught when parsing header') - raise EftImportError - return fit + mutaName = lines[i + 1] + except IndexError: + continue + else: + consumedIndices.add(i) + consumedIndices.add(i + 1) + # Get custom attribute values + mutaAttrs = {} + try: + mutaAttrsLine = lines[i + 2] + except IndexError: + pass + else: + consumedIndices.add(i + 2) + pairs = [p.strip() for p in mutaAttrsLine.split(',')] + for pair in pairs: + try: + attrName, value = pair.split(' ') + except ValueError: + continue + try: + value = float(value) + except (ValueError, TypeError): + continue + attrInfo = getAttributeInfo(attrName.strip()) + if attrInfo is None: + continue + mutaAttrs[attrInfo.ID] = value + mutaItem = _fetchItem(mutaName) + if mutaItem is None: + continue + data[ref] = (mutaItem, mutaAttrs) + # If we got here, we have seen at least correct reference line and + # mutaplasmid name line + i += 2 + # Bonus points for seeing correct attrs line. Worst case we + # will have to scan it once again + if mutaAttrs: + i += 1 + # Cleanup the lines from mutaplasmid info + for i in sorted(consumedIndices, reverse=True): + del lines[i] + return data -# Various methods and functions which assist with EFT import-export -def fetchItem(typeName, eagerCat=False): +def _importSectionIter(lines): + section = Section() + for line in lines: + if not line: + if section.lines: + yield section + section = Section() + else: + section.lines.append(line) + if section.lines: + yield section + + +def _importCreateFit(lines): + """Create fit and set top-level entity (ship or citadel).""" + fit = Fit() + header = lines.pop(0) + m = re.match('\[(?P[\w\s]+),\s*(?P.+)\]', header) + if not m: + pyfalog.warning('EftPort.importEft: corrupted fit header') + raise EftImportError + shipType = m.group('shipType').strip() + fitName = m.group('fitName').strip() + try: + ship = _fetchItem(shipType) + try: + fit.ship = Ship(ship) + except ValueError: + fit.ship = Citadel(ship) + fit.name = fitName + except: + pyfalog.warning('EftPort.importEft: exception caught when parsing header') + raise EftImportError + return fit + + +def _fetchItem(typeName, eagerCat=False): sMkt = Market.getInstance() eager = 'group.category' if eagerCat else None try: @@ -618,7 +613,7 @@ def fetchItem(typeName, eagerCat=False): return None -def clearTail(lst): +def _clearTail(lst): while lst and lst[-1] is None: del lst[-1] @@ -672,7 +667,7 @@ class Section: class BaseItemSpec: def __init__(self, typeName): - item = fetchItem(typeName, eagerCat=True) + item = _fetchItem(typeName, eagerCat=True) if item is None: raise EftImportError self.typeName = typeName @@ -709,7 +704,7 @@ class RegularItemSpec(BaseItemSpec): def __fetchCharge(self, chargeName): if chargeName: - charge = fetchItem(chargeName, eagerCat=True) + charge = _fetchItem(chargeName, eagerCat=True) if not charge or charge.category.name != 'Charge': charge = None else: @@ -800,7 +795,7 @@ class AbstractFit: continue modules.append(m) slotTypes.add(m.slot) - clearTail(modules) + _clearTail(modules) # If all the modules have same slot type, put them to appropriate # container with stubs if len(slotTypes) == 1: diff --git a/service/port/port.py b/service/port/port.py index bc09e301a..021b89e07 100644 --- a/service/port/port.py +++ b/service/port/port.py @@ -32,8 +32,8 @@ from eos import db from eos.saveddata.fit import ImplantLocation from service.fit import Fit as svcFit from service.port.dna import exportDna, importDna -from service.port.eft import EftPort -from service.port.esi import importESI, exportESI +from service.port.eft import exportEft, importEft, importEftCfg +from service.port.esi import exportESI, importESI from service.port.multibuy import exportMultiBuy from service.port.shared import IPortUser, UserCancelException, processing_notify from service.port.xml import importXml, exportXml @@ -234,15 +234,15 @@ class Port(object): ### EFT-related methods @staticmethod def importEft(eftString): - return EftPort.importEft(eftString) + return importEft(eftString) @staticmethod def importEftCfg(shipname, contents, iportuser=None): - return EftPort.importEftCfg(shipname, contents, iportuser) + return importEftCfg(shipname, contents, iportuser) @classmethod def exportEft(cls, fit, options): - return EftPort.exportEft(fit, options) + return exportEft(fit, options) ### DNA-related methods @staticmethod From b05f1573c699e8e6b5e95cc22ad6fb1b199a0685 Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Thu, 30 Aug 2018 21:41:50 +0300 Subject: [PATCH 85/95] Fix log messages --- service/port/eft.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/service/port/eft.py b/service/port/eft.py index 645a2ca2d..fbcd4c3b2 100644 --- a/service/port/eft.py +++ b/service/port/eft.py @@ -288,7 +288,7 @@ def importEft(eftString): elif m.fits(fit): m.owner = fit if not m.isValidState(m.state): - pyfalog.warning('EftPort.importEft: module {} cannot have state {}', m, m.state) + pyfalog.warning('service.port.eft.importEft: module {} cannot have state {}', m, m.state) fit.modules.appendIgnoreEmpty(m) for implant in aFit.implants: fit.implants.append(implant) @@ -582,7 +582,7 @@ def _importCreateFit(lines): header = lines.pop(0) m = re.match('\[(?P[\w\s]+),\s*(?P.+)\]', header) if not m: - pyfalog.warning('EftPort.importEft: corrupted fit header') + pyfalog.warning('service.port.eft.importEft: corrupted fit header') raise EftImportError shipType = m.group('shipType').strip() fitName = m.group('fitName').strip() @@ -594,7 +594,7 @@ def _importCreateFit(lines): fit.ship = Citadel(ship) fit.name = fitName except: - pyfalog.warning('EftPort.importEft: exception caught when parsing header') + pyfalog.warning('service.port.eft.importEft: exception caught when parsing header') raise EftImportError return fit @@ -605,7 +605,7 @@ def _fetchItem(typeName, eagerCat=False): try: item = sMkt.getItem(typeName, eager=eager) except: - pyfalog.warning('EftPort: unable to fetch item "{}"'.format(typeName)) + pyfalog.warning('service.port.eft: unable to fetch item "{}"'.format(typeName)) return None if sMkt.getPublicityByItem(item): return item From c552f6a1d457bbd6c47b108789e11da4d9c351aa Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 1 Sep 2018 17:54:10 -0400 Subject: [PATCH 86/95] formatting fixes --- gui/copySelectDialog.py | 1 - gui/mainFrame.py | 2 +- service/port/eft.py | 2 +- service/port/port.py | 10 +++++----- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/gui/copySelectDialog.py b/gui/copySelectDialog.py index 45191f6d9..10eff2647 100644 --- a/gui/copySelectDialog.py +++ b/gui/copySelectDialog.py @@ -101,4 +101,3 @@ class CopySelectDialog(wx.Dialog): if v.IsChecked(): i = i ^ x return i - diff --git a/gui/mainFrame.py b/gui/mainFrame.py index ced466577..ee0396c87 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -741,7 +741,7 @@ class MainFrame(wx.Frame): def exportToClipboard(self, event): CopySelectDict = {CopySelectDialog.copyFormatEft: self.clipboardEft, - #CopySelectDialog.copyFormatEftImps: self.clipboardEftImps, + # CopySelectDialog.copyFormatEftImps: self.clipboardEftImps, CopySelectDialog.copyFormatXml: self.clipboardXml, CopySelectDialog.copyFormatDna: self.clipboardDna, CopySelectDialog.copyFormatEsi: self.clipboardEsi, diff --git a/service/port/eft.py b/service/port/eft.py index fbcd4c3b2..fc8576d01 100644 --- a/service/port/eft.py +++ b/service/port/eft.py @@ -226,7 +226,6 @@ def importEft(eftString): _clearTail(section.itemSpecs) sections.append(section) - hasDroneBay = any(s.isDroneBay for s in sections) hasFighterBay = any(s.isFighterBay for s in sections) for section in sections: @@ -507,6 +506,7 @@ def _importPrepareString(eftString): del lines[-1] return lines + def _importGetMutationData(lines): data = {} consumedIndices = set() diff --git a/service/port/port.py b/service/port/port.py index 021b89e07..560af14ea 100644 --- a/service/port/port.py +++ b/service/port/port.py @@ -231,7 +231,7 @@ class Port(object): # Use DNA format for all other cases return "DNA", (cls.importDna(string),) - ### EFT-related methods + # EFT-related methods @staticmethod def importEft(eftString): return importEft(eftString) @@ -244,7 +244,7 @@ class Port(object): def exportEft(cls, fit, options): return exportEft(fit, options) - ### DNA-related methods + # DNA-related methods @staticmethod def importDna(string): return importDna(string) @@ -253,7 +253,7 @@ class Port(object): def exportDna(fit): return exportDna(fit) - ### ESI-related methods + # ESI-related methods @staticmethod def importESI(string): return importESI(string) @@ -262,7 +262,7 @@ class Port(object): def exportESI(fit): return exportESI(fit) - ### XML-related methods + # XML-related methods @staticmethod def importXml(text, iportuser=None): return importXml(text, iportuser) @@ -271,7 +271,7 @@ class Port(object): def exportXml(iportuser=None, *fits): return exportXml(iportuser, *fits) - ### Multibuy-related methods + # Multibuy-related methods @staticmethod def exportMultiBuy(fit): return exportMultiBuy(fit) From 6f5d0453a6fe139ba7748b299cf6ba14d4ab3911 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 1 Sep 2018 18:02:04 -0400 Subject: [PATCH 87/95] Added import of Port, which has a method that XML import uses. Importing inside the function to avoid circular import --- service/port/xml.py | 1 + 1 file changed, 1 insertion(+) diff --git a/service/port/xml.py b/service/port/xml.py index d5a5f08e0..54d5a98eb 100644 --- a/service/port/xml.py +++ b/service/port/xml.py @@ -129,6 +129,7 @@ def _resolve_module(hardware, sMkt, b_localized): def importXml(text, iportuser): + from .port import Port # type: (str, IPortUser) -> list[eos.saveddata.fit.Fit] sMkt = Market.getInstance() doc = xml.dom.minidom.parseString(text) From b08406b7d68b8d8c44242cd57b4de54152829a62 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 15 Sep 2018 17:46:55 -0400 Subject: [PATCH 88/95] Move the FitRenameCommand command --- gui/builtinShipBrowser/fitItem.py | 22 +------------------- gui/fitCommands/__init__.py | 3 ++- gui/fitCommands/calc/fitRename.py | 30 +++++++++++++++++++++++++++ gui/fitCommands/guiFitRename.py | 34 +++++++++++++++++++++++++++++++ service/fit.py | 9 -------- service/fitDeprecated.py | 10 +++++++++ 6 files changed, 77 insertions(+), 31 deletions(-) create mode 100644 gui/fitCommands/calc/fitRename.py create mode 100644 gui/fitCommands/guiFitRename.py diff --git a/gui/builtinShipBrowser/fitItem.py b/gui/builtinShipBrowser/fitItem.py index 58aa0f553..88be52aff 100644 --- a/gui/builtinShipBrowser/fitItem.py +++ b/gui/builtinShipBrowser/fitItem.py @@ -20,26 +20,6 @@ from service.fit import Fit import gui.fitCommands as cmd pyfalog = Logger(__name__) - -class FitRenameCommand(wx.Command): - def __init__(self, fitID, newName): - wx.Command.__init__(self, True, "FitRename") - self.fitID = fitID - self.newName = newName - self.mainFrame = gui.mainFrame.MainFrame.getInstance() - self.oldName = None - self.sFit = Fit.getInstance() - - def Do(self): - self.oldName, _ = self.sFit.renameFit(self.fitID, self.newName) - wx.PostEvent(self.mainFrame, FitRenamed(fitID=self.fitID)) - return True - - def Undo(self): - self.sFit.renameFit(self.fitID, self.oldName) - wx.PostEvent(self.mainFrame, FitRenamed(fitID=self.fitID)) - return True - class FitItem(SFItem.SFBrowserItem): def __init__(self, parent, fitID=None, shipFittingInfo=("Test", "TestTrait", "cnc's avatar", 0, 0, None), shipID=None, itemData=None, graphicID=None, @@ -345,7 +325,7 @@ class FitItem(SFItem.SFBrowserItem): fitName = self.tcFitName.GetValue() if fitName: self.fitName = fitName - self.mainFrame.command.Submit(FitRenameCommand(self.fitID, self.fitName)) + self.mainFrame.command.Submit(cmd.GuiFitRenameCommand(self.fitID, self.fitName)) else: self.tcFitName.SetValue(self.fitName) diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index 1c1e3905e..ae651d7bd 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -30,4 +30,5 @@ from .guiChangeCargoQty import GuiChangeCargoQty from .guiChangeProjectedFitQty import GuiChangeProjectedFitQty from .guiChangeDroneQty import GuiChangeDroneQty from .guiChangeProjectedDroneQty import GuiChangeProjectedDroneQty -from .guiToggleDrone import GuiToggleDroneCommand \ No newline at end of file +from .guiToggleDrone import GuiToggleDroneCommand +from .guiFitRename import GuiFitRenameCommand \ No newline at end of file diff --git a/gui/fitCommands/calc/fitRename.py b/gui/fitCommands/calc/fitRename.py new file mode 100644 index 000000000..bd840d41f --- /dev/null +++ b/gui/fitCommands/calc/fitRename.py @@ -0,0 +1,30 @@ +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 FitRenameCommand(wx.Command): + def __init__(self, fitID, newName): + wx.Command.__init__(self, True, "FitRename") + self.fitID = fitID + self.newName = newName + self.oldName = None + + def Do(self): + pyfalog.debug("Renaming fit ({0}) to: {1}", self.fitID, self.newName) + fit = eos.db.getFit(self.fitID) + self.oldName = fit.name + fit.name = self.newName + eos.db.commit() + return True + + def Undo(self): + cmd = FitRenameCommand(self.fitID, self.oldName) + return cmd.Do() diff --git a/gui/fitCommands/guiFitRename.py b/gui/fitCommands/guiFitRename.py new file mode 100644 index 000000000..7958a7c53 --- /dev/null +++ b/gui/fitCommands/guiFitRename.py @@ -0,0 +1,34 @@ +import wx +import eos.db +import gui.mainFrame +from service.fit import Fit +from gui import globalEvents as GE +from .calc.fitRename import FitRenameCommand +from service.fit import Fit +from logbook import Logger +from gui.builtinShipBrowser.events import FitRenamed +pyfalog = Logger(__name__) + + +class GuiFitRenameCommand(wx.Command): + def __init__(self, fitID, newName): + wx.Command.__init__(self, True) + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.sFit = Fit.getInstance() + self.fitID = fitID + self.newName = newName + self.internal_history = wx.CommandProcessor() + + def Do(self): + if self.internal_history.Submit(FitRenameCommand(self.fitID, self.newName)): + wx.PostEvent(self.mainFrame, FitRenamed(fitID=self.fitID)) + return True + return False + + + def Undo(self): + pyfalog.debug("{} Undo()".format(self)) + for _ in self.internal_history.Commands: + self.internal_history.Undo() + wx.PostEvent(self.mainFrame, FitRenamed(fitID=self.fitID)) + return True diff --git a/service/fit.py b/service/fit.py index b96cd3aa2..f5e48706f 100644 --- a/service/fit.py +++ b/service/fit.py @@ -185,15 +185,6 @@ class Fit(FitDeprecated): fit.booster = not fit.booster eos.db.commit() - @staticmethod - def renameFit(fitID, newName): - pyfalog.debug("Renaming fit ({0}) to: {1}", fitID, newName) - fit = eos.db.getFit(fitID) - old_name = fit.name - fit.name = newName - eos.db.commit() - return old_name, newName - @staticmethod def deleteFit(fitID): fit = eos.db.getFit(fitID) diff --git a/service/fitDeprecated.py b/service/fitDeprecated.py index e36014364..3edc9aab5 100644 --- a/service/fitDeprecated.py +++ b/service/fitDeprecated.py @@ -36,6 +36,16 @@ pyfalog = Logger(__name__) class FitDeprecated(object): + @staticmethod + @deprecated + def renameFit(fitID, newName): + pyfalog.debug("Renaming fit ({0}) to: {1}", fitID, newName) + fit = eos.db.getFit(fitID) + old_name = fit.name + fit.name = newName + eos.db.commit() + return old_name, newName + @deprecated def toggleDrone(self, fitID, i): pyfalog.debug("Toggling drones for fit ID: {0}", fitID) From 621672bf34b444d0f503c4ee6abdb05c8b9c4d29 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 15 Sep 2018 19:25:37 -0400 Subject: [PATCH 89/95] Some tox fixes --- config.py | 1 - eos/effectHandlerHelpers.py | 1 + gui/builtinAdditionPanes/boosterView.py | 1 + gui/builtinAdditionPanes/commandView.py | 3 +-- gui/builtinAdditionPanes/droneView.py | 1 + gui/builtinAdditionPanes/implantView.py | 1 + gui/builtinAdditionPanes/projectedView.py | 1 - gui/builtinContextMenus/amount.py | 1 + gui/builtinContextMenus/cargoAmmo.py | 1 + gui/builtinContextMenus/commandFits.py | 2 +- gui/builtinContextMenus/droneSplit.py | 1 - gui/builtinContextMenus/itemRemove.py | 1 + gui/builtinContextMenus/metaSwap.py | 2 +- gui/builtinContextMenus/moduleAmmoPicker.py | 1 + gui/builtinContextMenus/moduleGlobalAmmoPicker.py | 2 +- gui/builtinContextMenus/project.py | 2 +- gui/builtinContextMenus/tabbedFits.py | 1 + gui/builtinContextMenus/tacticalMode.py | 1 + gui/builtinContextMenus/whProjector.py | 1 + gui/builtinShipBrowser/fitItem.py | 1 + gui/builtinViews/fittingView.py | 4 ++-- gui/contextMenu.py | 4 ++-- gui/devTools.py | 2 +- gui/fitCommands/calc/fitAddBooster.py | 11 +++-------- gui/fitCommands/calc/fitAddCargo.py | 9 ++------- gui/fitCommands/calc/fitAddCommand.py | 6 ------ gui/fitCommands/calc/fitAddDrone.py | 9 ++------- gui/fitCommands/calc/fitAddFighter.py | 9 ++------- gui/fitCommands/calc/fitAddImplant.py | 9 ++------- gui/fitCommands/calc/fitAddModule.py | 7 +------ gui/fitCommands/calc/fitAddProjectedDrone.py | 9 --------- gui/fitCommands/calc/fitAddProjectedEnv.py | 9 --------- gui/fitCommands/calc/fitAddProjectedFighter.py | 7 ------- gui/fitCommands/calc/fitAddProjectedFit.py | 10 ---------- gui/fitCommands/calc/fitAddProjectedModule.py | 10 +--------- gui/fitCommands/calc/fitChangeCargoQty.py | 8 +------- gui/fitCommands/calc/fitChangeDroneQty.py | 7 +------ gui/fitCommands/calc/fitChangeFighterQty.py | 8 +------- gui/fitCommands/calc/fitChangeProjectedDroneQty.py | 7 +------ gui/fitCommands/calc/fitChangeProjectedFitQty.py | 8 +------- gui/fitCommands/calc/fitChangeState.py | 9 +++++---- gui/fitCommands/calc/fitCloneModule.py | 9 ++------- gui/fitCommands/calc/fitRemoveBooster.py | 2 -- gui/fitCommands/calc/fitRemoveCargo.py | 2 -- gui/fitCommands/calc/fitRemoveCommand.py | 8 +------- gui/fitCommands/calc/fitRemoveDrone.py | 8 +------- gui/fitCommands/calc/fitRemoveImplant.py | 4 +--- gui/fitCommands/calc/fitRemoveProjectedDrone.py | 9 --------- gui/fitCommands/calc/fitRemoveProjectedEnv.py | 9 --------- gui/fitCommands/calc/fitRemoveProjectedFighter.py | 10 ---------- gui/fitCommands/calc/fitRemoveProjectedFit.py | 9 --------- gui/fitCommands/calc/fitRemoveProjectedModule.py | 9 --------- gui/fitCommands/calc/fitRename.py | 10 +++------- gui/fitCommands/calc/fitSetCharge.py | 5 +++-- gui/fitCommands/calc/fitSetMode.py | 6 ------ gui/fitCommands/calc/fitSwapModule.py | 6 ------ gui/fitCommands/calc/fitToggleBooster.py | 7 +------ gui/fitCommands/calc/fitToggleCommand.py | 8 +------- gui/fitCommands/calc/fitToggleDrone.py | 7 +------ gui/fitCommands/calc/fitToggleFighter.py | 8 +------- gui/fitCommands/calc/fitToggleImplant.py | 8 +------- gui/fitCommands/guiAddBooster.py | 2 +- gui/fitCommands/guiAddCargo.py | 2 +- gui/fitCommands/guiAddCharge.py | 2 +- gui/fitCommands/guiAddCommand.py | 2 +- gui/fitCommands/guiAddDrone.py | 2 +- gui/fitCommands/guiAddFighter.py | 2 +- gui/fitCommands/guiAddImplant.py | 2 +- gui/fitCommands/guiAddModule.py | 2 -- gui/fitCommands/guiAddProjected.py | 1 - gui/fitCommands/guiCargoToModule.py | 1 + gui/fitCommands/guiChangeCargoQty.py | 5 ----- gui/fitCommands/guiChangeDroneQty.py | 5 ----- gui/fitCommands/guiChangeFighterQty.py | 5 ----- gui/fitCommands/guiChangeProjectedDroneQty.py | 5 ----- gui/fitCommands/guiChangeProjectedFitQty.py | 5 ----- gui/fitCommands/guiFitRename.py | 4 ---- gui/fitCommands/guiMetaSwap.py | 1 - gui/fitCommands/guiModuleToCargo.py | 4 +++- gui/fitCommands/guiRemoveBooster.py | 2 +- gui/fitCommands/guiRemoveCargo.py | 2 +- gui/fitCommands/guiRemoveCommand.py | 2 +- gui/fitCommands/guiRemoveDrone.py | 2 +- gui/fitCommands/guiRemoveImplant.py | 2 +- gui/fitCommands/guiRemoveModule.py | 3 ++- gui/fitCommands/guiRemoveProjected.py | 6 ++---- gui/fitCommands/guiSetMode.py | 2 +- gui/fitCommands/guiToggleBooster.py | 2 +- gui/fitCommands/guiToggleCommand.py | 2 +- gui/fitCommands/guiToggleDrone.py | 2 +- gui/fitCommands/guiToggleFighter.py | 2 +- gui/fitCommands/guiToggleImplant.py | 2 +- gui/fitCommands/guiToggleModuleState.py | 1 - service/fit.py | 5 +---- service/fitDeprecated.py | 2 +- utils/deprecated.py | 1 + 96 files changed, 90 insertions(+), 334 deletions(-) diff --git a/config.py b/config.py index 50894c424..7b366a209 100644 --- a/config.py +++ b/config.py @@ -230,7 +230,6 @@ def defLogging(): ]) - class LoggerWriter(object): def __init__(self, level): # self.level is really like using log.debug(message) diff --git a/eos/effectHandlerHelpers.py b/eos/effectHandlerHelpers.py index 3b5206185..3e9350b66 100644 --- a/eos/effectHandlerHelpers.py +++ b/eos/effectHandlerHelpers.py @@ -258,6 +258,7 @@ class HandledProjectedModList(HandledList): return oldEffect.itemID return None + class HandledProjectedDroneList(HandledDroneCargoList): def append(self, proj): proj.projected = True diff --git a/gui/builtinAdditionPanes/boosterView.py b/gui/builtinAdditionPanes/boosterView.py index 1d487d2ad..11bac08ca 100644 --- a/gui/builtinAdditionPanes/boosterView.py +++ b/gui/builtinAdditionPanes/boosterView.py @@ -28,6 +28,7 @@ from gui.utils.staticHelpers import DragDropHelper from service.fit import Fit import gui.fitCommands as cmd + class BoosterViewDrop(wx.DropTarget): def __init__(self, dropFn, *args, **kwargs): super(BoosterViewDrop, self).__init__(*args, **kwargs) diff --git a/gui/builtinAdditionPanes/commandView.py b/gui/builtinAdditionPanes/commandView.py index d05e4fe8c..ce73e06b8 100644 --- a/gui/builtinAdditionPanes/commandView.py +++ b/gui/builtinAdditionPanes/commandView.py @@ -32,6 +32,7 @@ from gui.utils.staticHelpers import DragDropHelper from service.fit import Fit import gui.fitCommands as cmd + class DummyItem(object): def __init__(self, txt): self.name = txt @@ -100,7 +101,6 @@ class CommandView(d.Display): keycode = event.GetKeyCode() if keycode == wx.WXK_DELETE or keycode == wx.WXK_NUMPAD_DELETE: fitID = self.mainFrame.getActiveFit() - sFit = Fit.getInstance() row = self.GetFirstSelected() if row != -1: self.mainFrame.command.Submit(cmd.GuiRemoveCommandCommand(fitID, self.get(row).ID)) @@ -218,7 +218,6 @@ class CommandView(d.Display): col = self.getColumn(event.Position) if col != self.getColIndex(State): fitID = self.mainFrame.getActiveFit() - sFit = Fit.getInstance() thing = self.get(row) if thing: # thing doesn't exist if it's the dummy value self.mainFrame.command.Submit(cmd.GuiRemoveCommandCommand(fitID, thing.ID)) diff --git a/gui/builtinAdditionPanes/droneView.py b/gui/builtinAdditionPanes/droneView.py index e95906ae9..2918c5aa4 100644 --- a/gui/builtinAdditionPanes/droneView.py +++ b/gui/builtinAdditionPanes/droneView.py @@ -31,6 +31,7 @@ from service.fit import Fit from service.market import Market import gui.fitCommands as cmd + class DroneViewDrop(wx.DropTarget): def __init__(self, dropFn, *args, **kwargs): super(DroneViewDrop, self).__init__(*args, **kwargs) diff --git a/gui/builtinAdditionPanes/implantView.py b/gui/builtinAdditionPanes/implantView.py index 0e2188e6f..323b7c89b 100644 --- a/gui/builtinAdditionPanes/implantView.py +++ b/gui/builtinAdditionPanes/implantView.py @@ -30,6 +30,7 @@ from service.fit import Fit from service.market import Market import gui.fitCommands as cmd + class ImplantView(wx.Panel): def __init__(self, parent): wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, style=wx.TAB_TRAVERSAL) diff --git a/gui/builtinAdditionPanes/projectedView.py b/gui/builtinAdditionPanes/projectedView.py index 678d3aa74..09db4d57f 100644 --- a/gui/builtinAdditionPanes/projectedView.py +++ b/gui/builtinAdditionPanes/projectedView.py @@ -322,7 +322,6 @@ class ProjectedView(d.Display): col = self.getColumn(event.Position) if col != self.getColIndex(State): fitID = self.mainFrame.getActiveFit() - sFit = Fit.getInstance() thing = self.get(row) if thing: # thing doesn't exist if it's the dummy value self.mainFrame.command.Submit(cmd.GuiRemoveProjectedCommand(fitID, thing)) diff --git a/gui/builtinContextMenus/amount.py b/gui/builtinContextMenus/amount.py index dc002d52b..3a70896f9 100644 --- a/gui/builtinContextMenus/amount.py +++ b/gui/builtinContextMenus/amount.py @@ -12,6 +12,7 @@ from eos.saveddata.fighter import Fighter as es_Fighter from service.settings import ContextMenuSettings import gui.fitCommands as cmd + class ChangeAmount(ContextMenu): def __init__(self): self.mainFrame = gui.mainFrame.MainFrame.getInstance() diff --git a/gui/builtinContextMenus/cargoAmmo.py b/gui/builtinContextMenus/cargoAmmo.py index e80801975..af3a855ac 100644 --- a/gui/builtinContextMenus/cargoAmmo.py +++ b/gui/builtinContextMenus/cargoAmmo.py @@ -6,6 +6,7 @@ from service.settings import ContextMenuSettings from service.fit import Fit import gui.fitCommands as cmd + class CargoAmmo(ContextMenu): def __init__(self): self.mainFrame = gui.mainFrame.MainFrame.getInstance() diff --git a/gui/builtinContextMenus/commandFits.py b/gui/builtinContextMenus/commandFits.py index d2dd7ec94..7433efbec 100644 --- a/gui/builtinContextMenus/commandFits.py +++ b/gui/builtinContextMenus/commandFits.py @@ -9,6 +9,7 @@ from gui.contextMenu import ContextMenu from service.settings import ContextMenuSettings import gui.fitCommands as cmd + class CommandFits(ContextMenu): # Get list of items that define a command fit sMkt = Market.getInstance() @@ -97,7 +98,6 @@ class CommandFits(ContextMenu): event.Skip() return - sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() self.mainFrame.command.Submit(cmd.GuiAddCommandCommand(fitID, fit.ID)) diff --git a/gui/builtinContextMenus/droneSplit.py b/gui/builtinContextMenus/droneSplit.py index 9701cc10f..462bd7198 100644 --- a/gui/builtinContextMenus/droneSplit.py +++ b/gui/builtinContextMenus/droneSplit.py @@ -111,7 +111,6 @@ class DroneStackSplit(wx.Dialog): return False - class DroneSpinner(wx.Dialog): def __init__(self, parent, drone, context): wx.Dialog.__init__(self, parent, title="Select Amount", size=wx.Size(220, 60)) diff --git a/gui/builtinContextMenus/itemRemove.py b/gui/builtinContextMenus/itemRemove.py index cbae19145..e5d083471 100644 --- a/gui/builtinContextMenus/itemRemove.py +++ b/gui/builtinContextMenus/itemRemove.py @@ -7,6 +7,7 @@ from service.fit import Fit from service.settings import ContextMenuSettings import gui.fitCommands as cmd + class ItemRemove(ContextMenu): def __init__(self): self.mainFrame = gui.mainFrame.MainFrame.getInstance() diff --git a/gui/builtinContextMenus/metaSwap.py b/gui/builtinContextMenus/metaSwap.py index 9909ab9fa..83304f4f7 100644 --- a/gui/builtinContextMenus/metaSwap.py +++ b/gui/builtinContextMenus/metaSwap.py @@ -17,6 +17,7 @@ from eos.saveddata.implant import Implant from eos.saveddata.cargo import Cargo import gui.fitCommands as cmd + class MetaSwap(ContextMenu): def __init__(self): self.mainFrame = gui.mainFrame.MainFrame.getInstance() @@ -153,5 +154,4 @@ class MetaSwap(ContextMenu): # sFit.addDrone(fitID, item.ID, drone_count, True) - MetaSwap.register() diff --git a/gui/builtinContextMenus/moduleAmmoPicker.py b/gui/builtinContextMenus/moduleAmmoPicker.py index 9b9a3a308..30e1b25d6 100644 --- a/gui/builtinContextMenus/moduleAmmoPicker.py +++ b/gui/builtinContextMenus/moduleAmmoPicker.py @@ -13,6 +13,7 @@ from gui.bitmap_loader import BitmapLoader from service.settings import ContextMenuSettings import gui.fitCommands as cmd + class ModuleAmmoPicker(ContextMenu): DAMAGE_TYPES = ("em", "explosive", "kinetic", "thermal") MISSILE_ORDER = ("em", "thermal", "kinetic", "explosive", "mixed") diff --git a/gui/builtinContextMenus/moduleGlobalAmmoPicker.py b/gui/builtinContextMenus/moduleGlobalAmmoPicker.py index 6f19aec96..d0fdbf55b 100644 --- a/gui/builtinContextMenus/moduleGlobalAmmoPicker.py +++ b/gui/builtinContextMenus/moduleGlobalAmmoPicker.py @@ -9,6 +9,7 @@ from service.fit import Fit from service.settings import ContextMenuSettings import gui.fitCommands as cmd + class ModuleGlobalAmmoPicker(ModuleAmmoPicker): def __init__(self): super(ModuleGlobalAmmoPicker, self).__init__() @@ -28,7 +29,6 @@ class ModuleGlobalAmmoPicker(ModuleAmmoPicker): event.Skip() return - sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() fit = db_getFit(fitID) diff --git a/gui/builtinContextMenus/project.py b/gui/builtinContextMenus/project.py index dbfa16724..4b41a30e2 100644 --- a/gui/builtinContextMenus/project.py +++ b/gui/builtinContextMenus/project.py @@ -7,6 +7,7 @@ from service.fit import Fit from service.settings import ContextMenuSettings import gui.fitCommands as cmd + class Project(ContextMenu): def __init__(self): self.mainFrame = gui.mainFrame.MainFrame.getInstance() @@ -33,7 +34,6 @@ class Project(ContextMenu): return "Project {0} onto Fit".format(itmContext) def activate(self, fullContext, selection, i): - sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() self.mainFrame.command.Submit(cmd.GuiAddProjectedCommand(fitID, selection[0].ID, 'item')) diff --git a/gui/builtinContextMenus/tabbedFits.py b/gui/builtinContextMenus/tabbedFits.py index 689622c3b..582f4158d 100644 --- a/gui/builtinContextMenus/tabbedFits.py +++ b/gui/builtinContextMenus/tabbedFits.py @@ -10,6 +10,7 @@ from gui.contextMenu import ContextMenu from gui.builtinViews.emptyView import BlankPage import gui.fitCommands as cmd + class TabbedFits(ContextMenu): def __init__(self): self.mainFrame = gui.mainFrame.MainFrame.getInstance() diff --git a/gui/builtinContextMenus/tacticalMode.py b/gui/builtinContextMenus/tacticalMode.py index 04c82574f..a8edff27b 100644 --- a/gui/builtinContextMenus/tacticalMode.py +++ b/gui/builtinContextMenus/tacticalMode.py @@ -8,6 +8,7 @@ from service.fit import Fit from service.settings import ContextMenuSettings import gui.fitCommands as cmd + class TacticalMode(ContextMenu): def __init__(self): self.mainFrame = gui.mainFrame.MainFrame.getInstance() diff --git a/gui/builtinContextMenus/whProjector.py b/gui/builtinContextMenus/whProjector.py index 1ec8252e8..16b1255b5 100644 --- a/gui/builtinContextMenus/whProjector.py +++ b/gui/builtinContextMenus/whProjector.py @@ -10,6 +10,7 @@ from itertools import chain import re import gui.fitCommands as cmd + class WhProjector(ContextMenu): # CCP doesn't currently provide a mapping between the general Environment, and the specific environment effect diff --git a/gui/builtinShipBrowser/fitItem.py b/gui/builtinShipBrowser/fitItem.py index 88be52aff..05470f97a 100644 --- a/gui/builtinShipBrowser/fitItem.py +++ b/gui/builtinShipBrowser/fitItem.py @@ -20,6 +20,7 @@ from service.fit import Fit import gui.fitCommands as cmd pyfalog = Logger(__name__) + class FitItem(SFItem.SFBrowserItem): def __init__(self, parent, fitID=None, shipFittingInfo=("Test", "TestTrait", "cnc's avatar", 0, 0, None), shipID=None, itemData=None, graphicID=None, diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index eab0b9fa0..85fbbb8b2 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -450,7 +450,6 @@ class FittingView(d.Display): mod1 = fit.modules[srcIdx] mod2 = self.mods[dstRow] - if not isinstance(mod2, Module): return @@ -622,7 +621,8 @@ 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.GuiModuleStateChangeCommand(fitID, self.mods[self.GetItemData(row)].modPosition, [mod.modPosition for mod in mods], click)) + self.mainFrame.command.Submit(cmd.GuiModuleStateChangeCommand( + fitID, self.mods[self.GetItemData(row)].modPosition, [mod.modPosition for mod in mods], click)) # update state tooltip tooltip = self.activeColumns[col].getToolTip(self.mods[self.GetItemData(row)]) diff --git a/gui/contextMenu.py b/gui/contextMenu.py index 7060579a7..be972b0f8 100644 --- a/gui/contextMenu.py +++ b/gui/contextMenu.py @@ -186,7 +186,7 @@ from gui.builtinContextMenus import ( # noqa: E402,F401 itemStats, damagePattern, marketJump, - #droneSplit, + # droneSplit, itemRemove, droneRemoveStack, ammoPattern, @@ -202,7 +202,7 @@ from gui.builtinContextMenus import ( # noqa: E402,F401 priceOptions, amount, cargoAmmo, - #droneStack, + # droneStack, metaSwap, implantSets, fighterAbilities, diff --git a/gui/devTools.py b/gui/devTools.py index 88486431a..44012128c 100644 --- a/gui/devTools.py +++ b/gui/devTools.py @@ -88,7 +88,7 @@ class DevTools(wx.Dialog): print(None) def cmd_print(self, evt): - print("="*20) + print("=" * 20) for x in self.mainFrame.command.GetCommands(): print("{}{} {}".format("==> " if x == self.mainFrame.command.GetCurrentCommand() else "", x.GetName(), x)) diff --git a/gui/fitCommands/calc/fitAddBooster.py b/gui/fitCommands/calc/fitAddBooster.py index d030c4026..0470b556b 100644 --- a/gui/fitCommands/calc/fitAddBooster.py +++ b/gui/fitCommands/calc/fitAddBooster.py @@ -1,14 +1,9 @@ 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__) from eos.saveddata.booster import Booster +pyfalog = Logger(__name__) + class FitAddBoosterCommand(wx.Command): """" @@ -20,7 +15,7 @@ class FitAddBoosterCommand(wx.Command): self.itemID = itemID self.new_index = None self.old_item = None - + def Do(self): pyfalog.debug("Adding booster ({0}) to fit ID: {1}", self.itemID, self.fitID) diff --git a/gui/fitCommands/calc/fitAddCargo.py b/gui/fitCommands/calc/fitAddCargo.py index 85bfae3eb..fff3abd26 100644 --- a/gui/fitCommands/calc/fitAddCargo.py +++ b/gui/fitCommands/calc/fitAddCargo.py @@ -1,14 +1,9 @@ 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__) from eos.saveddata.cargo import Cargo +pyfalog = Logger(__name__) + class FitAddCargoCommand(wx.Command): """" diff --git a/gui/fitCommands/calc/fitAddCommand.py b/gui/fitCommands/calc/fitAddCommand.py index 61dbc68b7..660d7b5a0 100644 --- a/gui/fitCommands/calc/fitAddCommand.py +++ b/gui/fitCommands/calc/fitAddCommand.py @@ -1,10 +1,4 @@ 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__) diff --git a/gui/fitCommands/calc/fitAddDrone.py b/gui/fitCommands/calc/fitAddDrone.py index c92f9fa78..a7b8ed41c 100644 --- a/gui/fitCommands/calc/fitAddDrone.py +++ b/gui/fitCommands/calc/fitAddDrone.py @@ -1,14 +1,9 @@ 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__) from eos.saveddata.drone import Drone +pyfalog = Logger(__name__) + class FitAddDroneCommand(wx.Command): """" diff --git a/gui/fitCommands/calc/fitAddFighter.py b/gui/fitCommands/calc/fitAddFighter.py index dfaccbf3d..42ca59be1 100644 --- a/gui/fitCommands/calc/fitAddFighter.py +++ b/gui/fitCommands/calc/fitAddFighter.py @@ -1,14 +1,9 @@ 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__) from eos.saveddata.fighter import Fighter +pyfalog = Logger(__name__) + class FitAddFighterCommand(wx.Command): """" diff --git a/gui/fitCommands/calc/fitAddImplant.py b/gui/fitCommands/calc/fitAddImplant.py index ae8ea848b..4e3fd372c 100644 --- a/gui/fitCommands/calc/fitAddImplant.py +++ b/gui/fitCommands/calc/fitAddImplant.py @@ -1,14 +1,9 @@ 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__) from eos.saveddata.implant import Implant +pyfalog = Logger(__name__) + class FitAddImplantCommand(wx.Command): """" diff --git a/gui/fitCommands/calc/fitAddModule.py b/gui/fitCommands/calc/fitAddModule.py index 5d1a2c35c..f0d421baf 100644 --- a/gui/fitCommands/calc/fitAddModule.py +++ b/gui/fitCommands/calc/fitAddModule.py @@ -1,9 +1,4 @@ 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 @@ -64,7 +59,7 @@ class FitAddModuleCommand(wx.Command): # Then, check states of all modules and change where needed. This will recalc if needed # self.checkStates(fit, m) - #fit.fill() + # fit.fill() eos.db.commit() self.change = numSlots != len(fit.modules) diff --git a/gui/fitCommands/calc/fitAddProjectedDrone.py b/gui/fitCommands/calc/fitAddProjectedDrone.py index 5649b6048..6c2ddf270 100644 --- a/gui/fitCommands/calc/fitAddProjectedDrone.py +++ b/gui/fitCommands/calc/fitAddProjectedDrone.py @@ -1,16 +1,7 @@ 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 -from eos.saveddata.module import Module from eos.saveddata.drone import Drone -from eos.saveddata.fighter import Fighter -from .fitRemoveProjectedModule import FitRemoveProjectedModuleCommand pyfalog = Logger(__name__) diff --git a/gui/fitCommands/calc/fitAddProjectedEnv.py b/gui/fitCommands/calc/fitAddProjectedEnv.py index 974f8efa5..f896a77df 100644 --- a/gui/fitCommands/calc/fitAddProjectedEnv.py +++ b/gui/fitCommands/calc/fitAddProjectedEnv.py @@ -1,16 +1,7 @@ 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 -from eos.saveddata.module import Module -from eos.saveddata.drone import Drone -from eos.saveddata.fighter import Fighter -from .fitRemoveProjectedModule import FitRemoveProjectedModuleCommand pyfalog = Logger(__name__) diff --git a/gui/fitCommands/calc/fitAddProjectedFighter.py b/gui/fitCommands/calc/fitAddProjectedFighter.py index df0163c01..17d50e14b 100644 --- a/gui/fitCommands/calc/fitAddProjectedFighter.py +++ b/gui/fitCommands/calc/fitAddProjectedFighter.py @@ -1,14 +1,7 @@ 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 from eos.saveddata.fighter import Fighter -from eos.saveddata.drone import Drone pyfalog = Logger(__name__) diff --git a/gui/fitCommands/calc/fitAddProjectedFit.py b/gui/fitCommands/calc/fitAddProjectedFit.py index 70fdece0a..cd1e1a7f9 100644 --- a/gui/fitCommands/calc/fitAddProjectedFit.py +++ b/gui/fitCommands/calc/fitAddProjectedFit.py @@ -1,16 +1,6 @@ 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 -from eos.saveddata.module import Module -from eos.saveddata.drone import Drone -from eos.saveddata.fighter import Fighter -from .fitRemoveProjectedModule import FitRemoveProjectedModuleCommand pyfalog = Logger(__name__) diff --git a/gui/fitCommands/calc/fitAddProjectedModule.py b/gui/fitCommands/calc/fitAddProjectedModule.py index 7701e375e..6d2ad3f4f 100644 --- a/gui/fitCommands/calc/fitAddProjectedModule.py +++ b/gui/fitCommands/calc/fitAddProjectedModule.py @@ -1,15 +1,7 @@ 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 -from eos.saveddata.module import Module -from eos.saveddata.drone import Drone -from eos.saveddata.fighter import Fighter +from eos.saveddata.module import Module, State pyfalog = Logger(__name__) diff --git a/gui/fitCommands/calc/fitChangeCargoQty.py b/gui/fitCommands/calc/fitChangeCargoQty.py index c737f3c22..2ba30e085 100644 --- a/gui/fitCommands/calc/fitChangeCargoQty.py +++ b/gui/fitCommands/calc/fitChangeCargoQty.py @@ -1,14 +1,8 @@ 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__) -from eos.saveddata.drone import Drone + class FitChangeCargoQty(wx.Command): def __init__(self, fitID, position, amount=1): diff --git a/gui/fitCommands/calc/fitChangeDroneQty.py b/gui/fitCommands/calc/fitChangeDroneQty.py index 162431837..8f7e8e801 100644 --- a/gui/fitCommands/calc/fitChangeDroneQty.py +++ b/gui/fitCommands/calc/fitChangeDroneQty.py @@ -1,14 +1,9 @@ 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 FitChangeDroneQty(wx.Command): def __init__(self, fitID, position, amount=1): wx.Command.__init__(self, True, "Drone add") diff --git a/gui/fitCommands/calc/fitChangeFighterQty.py b/gui/fitCommands/calc/fitChangeFighterQty.py index d8c2af274..4cef20034 100644 --- a/gui/fitCommands/calc/fitChangeFighterQty.py +++ b/gui/fitCommands/calc/fitChangeFighterQty.py @@ -1,14 +1,8 @@ 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__) -from eos.saveddata.drone import Drone + class FitChangeFighterQty(wx.Command): """" diff --git a/gui/fitCommands/calc/fitChangeProjectedDroneQty.py b/gui/fitCommands/calc/fitChangeProjectedDroneQty.py index 0ac99c098..3ca926c17 100644 --- a/gui/fitCommands/calc/fitChangeProjectedDroneQty.py +++ b/gui/fitCommands/calc/fitChangeProjectedDroneQty.py @@ -1,14 +1,9 @@ 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 FitChangeProjectedDroneQty(wx.Command): def __init__(self, fitID, position, amount=1): wx.Command.__init__(self, True, "Drone add") diff --git a/gui/fitCommands/calc/fitChangeProjectedFitQty.py b/gui/fitCommands/calc/fitChangeProjectedFitQty.py index e379ec883..aa75e8491 100644 --- a/gui/fitCommands/calc/fitChangeProjectedFitQty.py +++ b/gui/fitCommands/calc/fitChangeProjectedFitQty.py @@ -1,14 +1,9 @@ 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 FitChangeProjectedFitQty(wx.Command): """" from sFit.changeAmount @@ -21,7 +16,6 @@ class FitChangeProjectedFitQty(wx.Command): self.old_amount = None def Do(self): - fit = eos.db.getFit(self.fitID) pfit = eos.db.getFit(self.pfitID) if not pfit: # fit was deleted diff --git a/gui/fitCommands/calc/fitChangeState.py b/gui/fitCommands/calc/fitChangeState.py index a6a1548cd..4354f6c32 100644 --- a/gui/fitCommands/calc/fitChangeState.py +++ b/gui/fitCommands/calc/fitChangeState.py @@ -1,13 +1,14 @@ import wx -from service.fit import Fit +from logbook import Logger import gui.mainFrame -from gui import globalEvents as GE -from logbook import Logger from eos.saveddata.module import Module -pyfalog = Logger(__name__) +from service.fit import Fit import eos.db +pyfalog = Logger(__name__) + + class FitChangeStatesCommand(wx.Command): """ Fitting command that trys to change the state of modules in [positions]. We use the base module to determine the diff --git a/gui/fitCommands/calc/fitCloneModule.py b/gui/fitCommands/calc/fitCloneModule.py index 14c24ddc6..519b653ef 100644 --- a/gui/fitCommands/calc/fitCloneModule.py +++ b/gui/fitCommands/calc/fitCloneModule.py @@ -1,14 +1,9 @@ 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__) import copy +pyfalog = Logger(__name__) + class FitCloneModuleCommand(wx.Command): """ diff --git a/gui/fitCommands/calc/fitRemoveBooster.py b/gui/fitCommands/calc/fitRemoveBooster.py index f22b6fb8e..14733c93b 100644 --- a/gui/fitCommands/calc/fitRemoveBooster.py +++ b/gui/fitCommands/calc/fitRemoveBooster.py @@ -1,6 +1,4 @@ import wx - -#from .helpers import ModuleInfoCache import eos.db from logbook import Logger pyfalog = Logger(__name__) diff --git a/gui/fitCommands/calc/fitRemoveCargo.py b/gui/fitCommands/calc/fitRemoveCargo.py index 6b92278b3..779c7c757 100644 --- a/gui/fitCommands/calc/fitRemoveCargo.py +++ b/gui/fitCommands/calc/fitRemoveCargo.py @@ -1,6 +1,4 @@ import wx - -#from .helpers import ModuleInfoCache import eos.db from logbook import Logger pyfalog = Logger(__name__) diff --git a/gui/fitCommands/calc/fitRemoveCommand.py b/gui/fitCommands/calc/fitRemoveCommand.py index 57052aa1e..29e681b60 100644 --- a/gui/fitCommands/calc/fitRemoveCommand.py +++ b/gui/fitCommands/calc/fitRemoveCommand.py @@ -1,16 +1,10 @@ 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 FitRemoveCommandCommand(wx.Command): # well that's an unfrtunate name +class FitRemoveCommandCommand(wx.Command): # well that's an unfortunate name """" from sFit.removeCommand """ diff --git a/gui/fitCommands/calc/fitRemoveDrone.py b/gui/fitCommands/calc/fitRemoveDrone.py index 13e96d435..4e1fb0a6a 100644 --- a/gui/fitCommands/calc/fitRemoveDrone.py +++ b/gui/fitCommands/calc/fitRemoveDrone.py @@ -1,14 +1,8 @@ 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__) -from eos.saveddata.drone import Drone + class FitRemoveDroneCommand(wx.Command): """" diff --git a/gui/fitCommands/calc/fitRemoveImplant.py b/gui/fitCommands/calc/fitRemoveImplant.py index 2a834878a..d0f8101cd 100644 --- a/gui/fitCommands/calc/fitRemoveImplant.py +++ b/gui/fitCommands/calc/fitRemoveImplant.py @@ -1,6 +1,4 @@ import wx - -#from .helpers import ModuleInfoCache import eos.db from logbook import Logger pyfalog = Logger(__name__) @@ -28,7 +26,7 @@ class FitRemoveImplantCommand(wx.Command): return True def Undo(self): - from gui.fitCommands.calc.fitAddImplant import FitAddImplantCommand # Avoid circular import + from gui.fitCommands.calc.fitAddImplant import FitAddImplantCommand # Avoid circular import cmd = FitAddImplantCommand(self.fitID, self.old_implant) cmd.Do() return True diff --git a/gui/fitCommands/calc/fitRemoveProjectedDrone.py b/gui/fitCommands/calc/fitRemoveProjectedDrone.py index 3742dc9eb..9d70ade2e 100644 --- a/gui/fitCommands/calc/fitRemoveProjectedDrone.py +++ b/gui/fitCommands/calc/fitRemoveProjectedDrone.py @@ -1,15 +1,6 @@ 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 -from eos.saveddata.module import Module -from eos.saveddata.drone import Drone -from eos.saveddata.fighter import Fighter pyfalog = Logger(__name__) diff --git a/gui/fitCommands/calc/fitRemoveProjectedEnv.py b/gui/fitCommands/calc/fitRemoveProjectedEnv.py index b53f40ab0..61b6ee939 100644 --- a/gui/fitCommands/calc/fitRemoveProjectedEnv.py +++ b/gui/fitCommands/calc/fitRemoveProjectedEnv.py @@ -1,15 +1,6 @@ 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 -from eos.saveddata.module import Module -from eos.saveddata.drone import Drone -from eos.saveddata.fighter import Fighter from .fitRemoveProjectedModule import FitRemoveProjectedModuleCommand pyfalog = Logger(__name__) diff --git a/gui/fitCommands/calc/fitRemoveProjectedFighter.py b/gui/fitCommands/calc/fitRemoveProjectedFighter.py index 186ee0b43..d3550b43e 100644 --- a/gui/fitCommands/calc/fitRemoveProjectedFighter.py +++ b/gui/fitCommands/calc/fitRemoveProjectedFighter.py @@ -1,16 +1,6 @@ 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 -from eos.saveddata.module import Module -from eos.saveddata.drone import Drone -from eos.saveddata.fighter import Fighter -from .fitRemoveProjectedModule import FitRemoveProjectedModuleCommand pyfalog = Logger(__name__) diff --git a/gui/fitCommands/calc/fitRemoveProjectedFit.py b/gui/fitCommands/calc/fitRemoveProjectedFit.py index 829c7d3ea..66d62ab10 100644 --- a/gui/fitCommands/calc/fitRemoveProjectedFit.py +++ b/gui/fitCommands/calc/fitRemoveProjectedFit.py @@ -1,15 +1,6 @@ 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 -from eos.saveddata.module import Module -from eos.saveddata.drone import Drone -from eos.saveddata.fighter import Fighter from .fitRemoveProjectedModule import FitRemoveProjectedModuleCommand pyfalog = Logger(__name__) diff --git a/gui/fitCommands/calc/fitRemoveProjectedModule.py b/gui/fitCommands/calc/fitRemoveProjectedModule.py index ffb398006..46f8dadba 100644 --- a/gui/fitCommands/calc/fitRemoveProjectedModule.py +++ b/gui/fitCommands/calc/fitRemoveProjectedModule.py @@ -1,15 +1,6 @@ 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 -from eos.saveddata.module import Module -from eos.saveddata.drone import Drone -from eos.saveddata.fighter import Fighter pyfalog = Logger(__name__) diff --git a/gui/fitCommands/calc/fitRename.py b/gui/fitCommands/calc/fitRename.py index bd840d41f..38a72c519 100644 --- a/gui/fitCommands/calc/fitRename.py +++ b/gui/fitCommands/calc/fitRename.py @@ -1,12 +1,8 @@ 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 + +import eos.db + pyfalog = Logger(__name__) diff --git a/gui/fitCommands/calc/fitSetCharge.py b/gui/fitCommands/calc/fitSetCharge.py index eeb4df407..6cc6d0988 100644 --- a/gui/fitCommands/calc/fitSetCharge.py +++ b/gui/fitCommands/calc/fitSetCharge.py @@ -5,8 +5,9 @@ import gui.mainFrame from gui import globalEvents as GE from eos.saveddata.module import Module from logbook import Logger -pyfalog = Logger(__name__) import eos.db +pyfalog = Logger(__name__) + class FitSetChargeCommand(wx.Command): def __init__(self, fitID, positions, chargeID=None): @@ -43,4 +44,4 @@ class FitSetChargeCommand(wx.Command): result = True mod.charge = ammo eos.db.commit() - return result \ No newline at end of file + return result diff --git a/gui/fitCommands/calc/fitSetMode.py b/gui/fitCommands/calc/fitSetMode.py index 183c292aa..750be78dd 100644 --- a/gui/fitCommands/calc/fitSetMode.py +++ b/gui/fitCommands/calc/fitSetMode.py @@ -1,10 +1,4 @@ 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__) diff --git a/gui/fitCommands/calc/fitSwapModule.py b/gui/fitCommands/calc/fitSwapModule.py index 8f5ff4212..38ed8d4eb 100644 --- a/gui/fitCommands/calc/fitSwapModule.py +++ b/gui/fitCommands/calc/fitSwapModule.py @@ -1,10 +1,4 @@ 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__) diff --git a/gui/fitCommands/calc/fitToggleBooster.py b/gui/fitCommands/calc/fitToggleBooster.py index 504ab114a..53b56487b 100644 --- a/gui/fitCommands/calc/fitToggleBooster.py +++ b/gui/fitCommands/calc/fitToggleBooster.py @@ -1,14 +1,9 @@ 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 FitToggleBoosterCommand(wx.Command): """" from sFit.toggleBooster diff --git a/gui/fitCommands/calc/fitToggleCommand.py b/gui/fitCommands/calc/fitToggleCommand.py index c8adc87ac..c7d5a43ad 100644 --- a/gui/fitCommands/calc/fitToggleCommand.py +++ b/gui/fitCommands/calc/fitToggleCommand.py @@ -1,14 +1,8 @@ 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__) -from eos.saveddata.implant import Implant + class FitToggleCommandCommand(wx.Command): """" diff --git a/gui/fitCommands/calc/fitToggleDrone.py b/gui/fitCommands/calc/fitToggleDrone.py index a10796888..b281be700 100644 --- a/gui/fitCommands/calc/fitToggleDrone.py +++ b/gui/fitCommands/calc/fitToggleDrone.py @@ -1,14 +1,9 @@ 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 FitToggleDroneCommand(wx.Command): """" from sFit.toggleDrone diff --git a/gui/fitCommands/calc/fitToggleFighter.py b/gui/fitCommands/calc/fitToggleFighter.py index d0e2a325c..589b4bdd2 100644 --- a/gui/fitCommands/calc/fitToggleFighter.py +++ b/gui/fitCommands/calc/fitToggleFighter.py @@ -1,14 +1,8 @@ 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__) -from eos.saveddata.implant import Implant + class FitToggleFighterCommand(wx.Command): """" diff --git a/gui/fitCommands/calc/fitToggleImplant.py b/gui/fitCommands/calc/fitToggleImplant.py index a44b5f293..c004c297d 100644 --- a/gui/fitCommands/calc/fitToggleImplant.py +++ b/gui/fitCommands/calc/fitToggleImplant.py @@ -1,14 +1,8 @@ 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__) -from eos.saveddata.implant import Implant + class FitToggleImplantCommand(wx.Command): """" diff --git a/gui/fitCommands/guiAddBooster.py b/gui/fitCommands/guiAddBooster.py index fc89209cb..fc732d857 100644 --- a/gui/fitCommands/guiAddBooster.py +++ b/gui/fitCommands/guiAddBooster.py @@ -5,6 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitAddBooster import FitAddBoosterCommand + class GuiAddBoosterCommand(wx.Command): def __init__(self, fitID, itemID): wx.Command.__init__(self, True, "Booster Add") @@ -27,4 +28,3 @@ class GuiAddBoosterCommand(wx.Command): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiAddCargo.py b/gui/fitCommands/guiAddCargo.py index d23af64bb..4ff0f3447 100644 --- a/gui/fitCommands/guiAddCargo.py +++ b/gui/fitCommands/guiAddCargo.py @@ -5,6 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitAddCargo import FitAddCargoCommand + class GuiAddCargoCommand(wx.Command): def __init__(self, fitID, itemID, amount=1, replace=False): wx.Command.__init__(self, True, "Cargo Add") @@ -27,4 +28,3 @@ class GuiAddCargoCommand(wx.Command): self.internal_history.Undo() wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiAddCharge.py b/gui/fitCommands/guiAddCharge.py index 26ae3bf94..ad6c5a2f2 100644 --- a/gui/fitCommands/guiAddCharge.py +++ b/gui/fitCommands/guiAddCharge.py @@ -5,6 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitSetCharge import FitSetChargeCommand + class GuiModuleAddChargeCommand(wx.Command): def __init__(self, fitID, itemID, modules): wx.Command.__init__(self, True, "Module Charge Add") @@ -28,4 +29,3 @@ class GuiModuleAddChargeCommand(wx.Command): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiAddCommand.py b/gui/fitCommands/guiAddCommand.py index 38f3a1110..06cfcbe98 100644 --- a/gui/fitCommands/guiAddCommand.py +++ b/gui/fitCommands/guiAddCommand.py @@ -5,6 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitAddCommand import FitAddCommandCommand + class GuiAddCommandCommand(wx.Command): def __init__(self, fitID, commandFitID): wx.Command.__init__(self, True, "") @@ -27,4 +28,3 @@ class GuiAddCommandCommand(wx.Command): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiAddDrone.py b/gui/fitCommands/guiAddDrone.py index f55f40363..6549d1e21 100644 --- a/gui/fitCommands/guiAddDrone.py +++ b/gui/fitCommands/guiAddDrone.py @@ -5,6 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitAddDrone import FitAddDroneCommand + class GuiAddDroneCommand(wx.Command): def __init__(self, fitID, itemID): wx.Command.__init__(self, True, "Cargo Add") @@ -27,4 +28,3 @@ class GuiAddDroneCommand(wx.Command): self.internal_history.Undo() wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiAddFighter.py b/gui/fitCommands/guiAddFighter.py index 2e699b53a..01024e706 100644 --- a/gui/fitCommands/guiAddFighter.py +++ b/gui/fitCommands/guiAddFighter.py @@ -5,6 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitAddFighter import FitAddFighterCommand + class GuiAddFighterCommand(wx.Command): def __init__(self, fitID, itemID): wx.Command.__init__(self, True, "Cargo Add") @@ -27,4 +28,3 @@ class GuiAddFighterCommand(wx.Command): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiAddImplant.py b/gui/fitCommands/guiAddImplant.py index d819a55d3..ffbc1e0a4 100644 --- a/gui/fitCommands/guiAddImplant.py +++ b/gui/fitCommands/guiAddImplant.py @@ -5,6 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitAddImplant import FitAddImplantCommand + class GuiAddImplantCommand(wx.Command): def __init__(self, fitID, itemID): wx.Command.__init__(self, True, "Implant Add") @@ -27,4 +28,3 @@ class GuiAddImplantCommand(wx.Command): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiAddModule.py b/gui/fitCommands/guiAddModule.py index 0964e03ae..f826566f4 100644 --- a/gui/fitCommands/guiAddModule.py +++ b/gui/fitCommands/guiAddModule.py @@ -1,7 +1,6 @@ import wx import eos.db import gui.mainFrame -from service.fit import Fit from gui import globalEvents as GE from .calc.fitAddModule import FitAddModuleCommand from .calc.fitReplaceModule import FitReplaceModuleCommand @@ -60,7 +59,6 @@ class GuiModuleAddCommand(wx.Command): return True return False - def Undo(self): pyfalog.debug("{} Undo()".format(self)) for _ in self.internal_history.Commands: diff --git a/gui/fitCommands/guiAddProjected.py b/gui/fitCommands/guiAddProjected.py index 7bc81bb76..b2114e111 100644 --- a/gui/fitCommands/guiAddProjected.py +++ b/gui/fitCommands/guiAddProjected.py @@ -54,4 +54,3 @@ class GuiAddProjectedCommand(wx.Command): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiCargoToModule.py b/gui/fitCommands/guiCargoToModule.py index 018014081..a2583e47c 100644 --- a/gui/fitCommands/guiCargoToModule.py +++ b/gui/fitCommands/guiCargoToModule.py @@ -10,6 +10,7 @@ from .calc.fitAddCargo import FitAddCargoCommand from logbook import Logger pyfalog = Logger(__name__) + class GuiCargoToModuleCommand(wx.Command): """ Moves cargo to fitting window. Can either do a copy, move, or swap with current module diff --git a/gui/fitCommands/guiChangeCargoQty.py b/gui/fitCommands/guiChangeCargoQty.py index b8a6c8873..80a906fc3 100644 --- a/gui/fitCommands/guiChangeCargoQty.py +++ b/gui/fitCommands/guiChangeCargoQty.py @@ -1,10 +1,6 @@ import wx -import eos.db import gui.mainFrame -from service.fit import Fit from gui import globalEvents as GE -from .calc.fitAddModule import FitAddModuleCommand -from .calc.fitReplaceModule import FitReplaceModuleCommand from .calc.fitChangeCargoQty import FitChangeCargoQty from service.fit import Fit from logbook import Logger @@ -29,7 +25,6 @@ class GuiChangeCargoQty(wx.Command): return True return False - def Undo(self): for _ in self.internal_history.Commands: self.internal_history.Undo() diff --git a/gui/fitCommands/guiChangeDroneQty.py b/gui/fitCommands/guiChangeDroneQty.py index 9c27a8945..5aa2ea12e 100644 --- a/gui/fitCommands/guiChangeDroneQty.py +++ b/gui/fitCommands/guiChangeDroneQty.py @@ -1,10 +1,6 @@ import wx -import eos.db import gui.mainFrame -from service.fit import Fit from gui import globalEvents as GE -from .calc.fitAddModule import FitAddModuleCommand -from .calc.fitReplaceModule import FitReplaceModuleCommand from .calc.fitChangeDroneQty import FitChangeDroneQty from service.fit import Fit from logbook import Logger @@ -29,7 +25,6 @@ class GuiChangeDroneQty(wx.Command): return True return False - def Undo(self): for _ in self.internal_history.Commands: self.internal_history.Undo() diff --git a/gui/fitCommands/guiChangeFighterQty.py b/gui/fitCommands/guiChangeFighterQty.py index 063c6cda5..280bd1a16 100644 --- a/gui/fitCommands/guiChangeFighterQty.py +++ b/gui/fitCommands/guiChangeFighterQty.py @@ -1,10 +1,6 @@ import wx -import eos.db import gui.mainFrame -from service.fit import Fit from gui import globalEvents as GE -from .calc.fitAddModule import FitAddModuleCommand -from .calc.fitReplaceModule import FitReplaceModuleCommand from .calc.fitChangeFighterQty import FitChangeFighterQty from service.fit import Fit from logbook import Logger @@ -29,7 +25,6 @@ class GuiChangeFighterQty(wx.Command): return True return False - def Undo(self): pyfalog.debug("{} Undo()".format(self)) for _ in self.internal_history.Commands: diff --git a/gui/fitCommands/guiChangeProjectedDroneQty.py b/gui/fitCommands/guiChangeProjectedDroneQty.py index 38fcf31f9..f7ceaa657 100644 --- a/gui/fitCommands/guiChangeProjectedDroneQty.py +++ b/gui/fitCommands/guiChangeProjectedDroneQty.py @@ -1,10 +1,6 @@ import wx -import eos.db import gui.mainFrame -from service.fit import Fit from gui import globalEvents as GE -from .calc.fitAddModule import FitAddModuleCommand -from .calc.fitReplaceModule import FitReplaceModuleCommand from .calc.fitChangeProjectedDroneQty import FitChangeProjectedDroneQty from service.fit import Fit from logbook import Logger @@ -29,7 +25,6 @@ class GuiChangeProjectedDroneQty(wx.Command): return True return False - def Undo(self): pyfalog.debug("{} Undo()".format(self)) for _ in self.internal_history.Commands: diff --git a/gui/fitCommands/guiChangeProjectedFitQty.py b/gui/fitCommands/guiChangeProjectedFitQty.py index 006876077..7014a808b 100644 --- a/gui/fitCommands/guiChangeProjectedFitQty.py +++ b/gui/fitCommands/guiChangeProjectedFitQty.py @@ -1,10 +1,6 @@ import wx -import eos.db import gui.mainFrame -from service.fit import Fit from gui import globalEvents as GE -from .calc.fitAddModule import FitAddModuleCommand -from .calc.fitReplaceModule import FitReplaceModuleCommand from .calc.fitChangeProjectedFitQty import FitChangeProjectedFitQty from service.fit import Fit from logbook import Logger @@ -29,7 +25,6 @@ class GuiChangeProjectedFitQty(wx.Command): return True return False - def Undo(self): pyfalog.debug("{} Undo()".format(self)) for _ in self.internal_history.Commands: diff --git a/gui/fitCommands/guiFitRename.py b/gui/fitCommands/guiFitRename.py index 7958a7c53..b9a7a81d7 100644 --- a/gui/fitCommands/guiFitRename.py +++ b/gui/fitCommands/guiFitRename.py @@ -1,8 +1,5 @@ import wx -import eos.db import gui.mainFrame -from service.fit import Fit -from gui import globalEvents as GE from .calc.fitRename import FitRenameCommand from service.fit import Fit from logbook import Logger @@ -25,7 +22,6 @@ class GuiFitRenameCommand(wx.Command): return True return False - def Undo(self): pyfalog.debug("{} Undo()".format(self)) for _ in self.internal_history.Commands: diff --git a/gui/fitCommands/guiMetaSwap.py b/gui/fitCommands/guiMetaSwap.py index 9b4af4039..13497a233 100644 --- a/gui/fitCommands/guiMetaSwap.py +++ b/gui/fitCommands/guiMetaSwap.py @@ -61,4 +61,3 @@ class GuiMetaSwapCommand(wx.Command): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiModuleToCargo.py b/gui/fitCommands/guiModuleToCargo.py index c0b483d2c..95e9be0b6 100644 --- a/gui/fitCommands/guiModuleToCargo.py +++ b/gui/fitCommands/guiModuleToCargo.py @@ -12,6 +12,7 @@ from .calc.fitAddCargo import FitAddCargoCommand from logbook import Logger pyfalog = Logger(__name__) + class GuiModuleToCargoCommand(wx.Command): def __init__(self, fitID, moduleIdx, cargoIdx, copy=False): wx.Command.__init__(self, True, "Module State Change") @@ -31,7 +32,8 @@ class GuiModuleToCargoCommand(wx.Command): if self.cargoIdx: # we're swapping with cargo if self.copy: # if copying, simply add item to cargo - result = self.internal_history.Submit(FitAddCargoCommand(self.mainFrame.getActiveFit(), module.item.ID if not module.item.isAbyssal else module.baseItemID)) + result = self.internal_history.Submit(FitAddCargoCommand( + self.mainFrame.getActiveFit(), module.item.ID if not module.item.isAbyssal else module.baseItemID)) else: # otherwise, try to swap by replacing module with cargo item. If successful, remove old cargo and add new cargo cargo = fit.cargo[self.cargoIdx] diff --git a/gui/fitCommands/guiRemoveBooster.py b/gui/fitCommands/guiRemoveBooster.py index 0e96f1c2e..15b504575 100644 --- a/gui/fitCommands/guiRemoveBooster.py +++ b/gui/fitCommands/guiRemoveBooster.py @@ -5,6 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitRemoveBooster import FitRemoveBoosterCommand + class GuiRemoveBoosterCommand(wx.Command): def __init__(self, fitID, position): wx.Command.__init__(self, True, "") @@ -27,4 +28,3 @@ class GuiRemoveBoosterCommand(wx.Command): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiRemoveCargo.py b/gui/fitCommands/guiRemoveCargo.py index ec42e4d3c..f9aa5872a 100644 --- a/gui/fitCommands/guiRemoveCargo.py +++ b/gui/fitCommands/guiRemoveCargo.py @@ -5,6 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitRemoveCargo import FitRemoveCargoCommand + class GuiRemoveCargoCommand(wx.Command): def __init__(self, fitID, itemID): wx.Command.__init__(self, True, "Module Charge Add") @@ -25,4 +26,3 @@ class GuiRemoveCargoCommand(wx.Command): self.internal_history.Undo() wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiRemoveCommand.py b/gui/fitCommands/guiRemoveCommand.py index 351f9697b..206be23c3 100644 --- a/gui/fitCommands/guiRemoveCommand.py +++ b/gui/fitCommands/guiRemoveCommand.py @@ -5,6 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitRemoveCommand import FitRemoveCommandCommand + class GuiRemoveCommandCommand(wx.Command): def __init__(self, fitID, commandFitID): wx.Command.__init__(self, True, "") @@ -27,4 +28,3 @@ class GuiRemoveCommandCommand(wx.Command): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiRemoveDrone.py b/gui/fitCommands/guiRemoveDrone.py index 252adc2af..42e651e3d 100644 --- a/gui/fitCommands/guiRemoveDrone.py +++ b/gui/fitCommands/guiRemoveDrone.py @@ -5,6 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitRemoveDrone import FitRemoveDroneCommand + class GuiRemoveDroneCommand(wx.Command): def __init__(self, fitID, position, amount=1): wx.Command.__init__(self, True, "Cargo Add") @@ -28,4 +29,3 @@ class GuiRemoveDroneCommand(wx.Command): self.internal_history.Undo() wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiRemoveImplant.py b/gui/fitCommands/guiRemoveImplant.py index 7c9c6a4c1..af9ee74bc 100644 --- a/gui/fitCommands/guiRemoveImplant.py +++ b/gui/fitCommands/guiRemoveImplant.py @@ -5,6 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitRemoveImplant import FitRemoveImplantCommand + class GuiRemoveImplantCommand(wx.Command): def __init__(self, fitID, position): wx.Command.__init__(self, True, "") @@ -25,4 +26,3 @@ class GuiRemoveImplantCommand(wx.Command): self.internal_history.Undo() wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiRemoveModule.py b/gui/fitCommands/guiRemoveModule.py index 848708856..944a63160 100644 --- a/gui/fitCommands/guiRemoveModule.py +++ b/gui/fitCommands/guiRemoveModule.py @@ -19,7 +19,8 @@ class GuiModuleRemoveCommand(wx.Command): self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.sFit = Fit.getInstance() self.fitID = fitID - self.modCache = [ModuleInfoCache(mod.modPosition, mod.item.ID, mod.state, mod.charge, mod.baseItemID, mod.mutaplasmidID) for mod in modules if not mod.isEmpty] + self.modCache = [ModuleInfoCache( + mod.modPosition, mod.item.ID, mod.state, mod.charge, mod.baseItemID, mod.mutaplasmidID) for mod in modules if not mod.isEmpty] self.internal_history = wx.CommandProcessor() def Do(self): diff --git a/gui/fitCommands/guiRemoveProjected.py b/gui/fitCommands/guiRemoveProjected.py index 2bf91b876..74d1ab308 100644 --- a/gui/fitCommands/guiRemoveProjected.py +++ b/gui/fitCommands/guiRemoveProjected.py @@ -3,20 +3,19 @@ from service.fit import Fit import gui.mainFrame from gui import globalEvents as GE -from eos.saveddata.module import Module from .calc.fitRemoveProjectedModule import FitRemoveProjectedModuleCommand from .calc.fitRemoveProjectedEnv import FitRemoveProjectedEnvCommand from .calc.fitRemoveProjectedFit import FitRemoveProjectedFitCommand from .calc.fitRemoveProjectedFighter import FitRemoveProjectedFighterCommand from logbook import Logger from .calc.fitRemoveProjectedDrone import FitRemoveProjectedDroneCommand -pyfalog = Logger(__name__) -import eos.db from eos.saveddata.drone import Drone from eos.saveddata.module import Module from eos.saveddata.fighter import Fighter +pyfalog = Logger(__name__) + class GuiRemoveProjectedCommand(wx.Command): mapping = { @@ -88,4 +87,3 @@ class GuiRemoveProjectedCommand(wx.Command): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiSetMode.py b/gui/fitCommands/guiSetMode.py index 0ad7b80f6..9639028f9 100644 --- a/gui/fitCommands/guiSetMode.py +++ b/gui/fitCommands/guiSetMode.py @@ -5,6 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitSetMode import FitSetModeCommand + class GuiSetModeCommand(wx.Command): def __init__(self, fitID, mode): wx.Command.__init__(self, True, "Cargo Add") @@ -27,4 +28,3 @@ class GuiSetModeCommand(wx.Command): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiToggleBooster.py b/gui/fitCommands/guiToggleBooster.py index 166ad9648..2a586a888 100644 --- a/gui/fitCommands/guiToggleBooster.py +++ b/gui/fitCommands/guiToggleBooster.py @@ -5,6 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitToggleBooster import FitToggleBoosterCommand + class GuiToggleBoosterCommand(wx.Command): def __init__(self, fitID, position): wx.Command.__init__(self, True, "") @@ -27,4 +28,3 @@ class GuiToggleBoosterCommand(wx.Command): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiToggleCommand.py b/gui/fitCommands/guiToggleCommand.py index 85f32c143..50785da26 100644 --- a/gui/fitCommands/guiToggleCommand.py +++ b/gui/fitCommands/guiToggleCommand.py @@ -5,6 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitToggleCommand import FitToggleCommandCommand + class GuiToggleCommandCommand(wx.Command): def __init__(self, fitID, commandFitID): wx.Command.__init__(self, True, "") @@ -27,4 +28,3 @@ class GuiToggleCommandCommand(wx.Command): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiToggleDrone.py b/gui/fitCommands/guiToggleDrone.py index 3dc8c4cec..7913df516 100644 --- a/gui/fitCommands/guiToggleDrone.py +++ b/gui/fitCommands/guiToggleDrone.py @@ -5,6 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitToggleDrone import FitToggleDroneCommand + class GuiToggleDroneCommand(wx.Command): def __init__(self, fitID, position): wx.Command.__init__(self, True, "") @@ -27,4 +28,3 @@ class GuiToggleDroneCommand(wx.Command): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiToggleFighter.py b/gui/fitCommands/guiToggleFighter.py index eee3c945e..f5aee10d6 100644 --- a/gui/fitCommands/guiToggleFighter.py +++ b/gui/fitCommands/guiToggleFighter.py @@ -5,6 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitToggleFighter import FitToggleFighterCommand + class GuiToggleFighterCommand(wx.Command): def __init__(self, fitID, position): wx.Command.__init__(self, True, "") @@ -27,4 +28,3 @@ class GuiToggleFighterCommand(wx.Command): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiToggleImplant.py b/gui/fitCommands/guiToggleImplant.py index e7ae24669..899eff0ee 100644 --- a/gui/fitCommands/guiToggleImplant.py +++ b/gui/fitCommands/guiToggleImplant.py @@ -5,6 +5,7 @@ import gui.mainFrame from gui import globalEvents as GE from .calc.fitToggleImplant import FitToggleImplantCommand + class GuiToggleImplantCommand(wx.Command): def __init__(self, fitID, position): wx.Command.__init__(self, True, "") @@ -27,4 +28,3 @@ class GuiToggleImplantCommand(wx.Command): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/gui/fitCommands/guiToggleModuleState.py b/gui/fitCommands/guiToggleModuleState.py index d87339347..71e307f93 100644 --- a/gui/fitCommands/guiToggleModuleState.py +++ b/gui/fitCommands/guiToggleModuleState.py @@ -31,4 +31,3 @@ class GuiModuleStateChangeCommand(wx.Command): self.sFit.recalc(self.fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID)) return True - diff --git a/service/fit.py b/service/fit.py index f5e48706f..f58c5eed4 100644 --- a/service/fit.py +++ b/service/fit.py @@ -39,10 +39,10 @@ from service.damagePattern import DamagePattern from service.settings import SettingsProvider from utils.deprecated import deprecated import wx +from service.fitDeprecated import FitDeprecated pyfalog = Logger(__name__) -from service.fitDeprecated import FitDeprecated class DeferRecalc(): def __init__(self, fitID): @@ -359,9 +359,6 @@ class Fit(FitDeprecated): eos.db.commit() self.recalc(fit) - - - def changeMutatedValue(self, mutator, value): pyfalog.debug("Changing mutated value for {} / {}: {} => {}".format(mutator.module, mutator.module.mutaplasmid, mutator.value, value)) mutator.value = value diff --git a/service/fitDeprecated.py b/service/fitDeprecated.py index 3edc9aab5..c145b858c 100644 --- a/service/fitDeprecated.py +++ b/service/fitDeprecated.py @@ -44,7 +44,7 @@ class FitDeprecated(object): old_name = fit.name fit.name = newName eos.db.commit() - return old_name, newName + return old_name, newName @deprecated def toggleDrone(self, fitID, i): diff --git a/utils/deprecated.py b/utils/deprecated.py index e7eeb9fad..b3433515e 100644 --- a/utils/deprecated.py +++ b/utils/deprecated.py @@ -1,6 +1,7 @@ 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 From f0353a7dd7a6985619311b8ffa950a458b31a95e Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 15 Sep 2018 23:44:16 -0400 Subject: [PATCH 90/95] some dict cleanup --- scripts/itemDiff.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/scripts/itemDiff.py b/scripts/itemDiff.py index 053e36222..1874bcd92 100755 --- a/scripts/itemDiff.py +++ b/scripts/itemDiff.py @@ -282,14 +282,12 @@ def main(old, new, groups=True, effects=True, attributes=True, renames=True): oldgroup = old_itmdata[item][0] groupdata = (S["unchanged"], oldgroup, None) # Set old set of effects and mark all as unchanged - effectsdata = {} - effectsdata[S["unchanged"]] = set() + effectsdata = {S["unchanged"]: set()} if effects: oldeffects = old_itmdata[item][1] effectsdata[S["unchanged"]].update(oldeffects) # Set old set of attributes and mark all as unchanged - attrdata = {} - attrdata[S["unchanged"]] = {} + attrdata = {S["unchanged"]: {}} if attributes: oldattrs = old_itmdata[item][2] for attr in oldattrs: @@ -307,14 +305,12 @@ def main(old, new, groups=True, effects=True, attributes=True, renames=True): newgroup = new_itmdata[item][0] groupdata = (S["unchanged"], None, newgroup) # Set new set of effects and mark all as unchanged - effectsdata = {} - effectsdata[S["unchanged"]] = set() + effectsdata = {S["unchanged"]: set()} if effects: neweffects = new_itmdata[item][1] effectsdata[S["unchanged"]].update(neweffects) # Set new set of attributes and mark all as unchanged - attrdata = {} - attrdata[S["unchanged"]] = {} + attrdata = {S["unchanged"]: {}} if attributes: newattrs = new_itmdata[item][2] for attr in newattrs: From 5c6303995d18b05cd4be977199457dca5afe71eb Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 15 Sep 2018 23:44:32 -0400 Subject: [PATCH 91/95] Replace set() with a literal --- gui/builtinContextMenus/commandFits.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/builtinContextMenus/commandFits.py b/gui/builtinContextMenus/commandFits.py index 7433efbec..d97118297 100644 --- a/gui/builtinContextMenus/commandFits.py +++ b/gui/builtinContextMenus/commandFits.py @@ -26,7 +26,7 @@ class CommandFits(ContextMenu): if evt is not None: ids = getattr(evt, 'typeID') if not isinstance(ids, set): - ids = set([ids]) + ids = {ids} if evt is None or not ids.isdisjoint(cls.commandTypeIDs): # we are adding or removing an item that defines a command fit. Need to refresh fit list From b4b8a158f529a5b1537366f24bfd3afdb96c7cd1 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sun, 16 Sep 2018 00:05:36 -0400 Subject: [PATCH 92/95] Bunch of import optimizations --- _development/helpers_fits.py | 1 - _development/helpers_items.py | 1 - eos/db/gamedata/category.py | 4 +- eos/db/gamedata/item.py | 10 +- eos/db/gamedata/queries.py | 8 +- eos/db/saveddata/fit.py | 31 +++-- eos/db/saveddata/mutator.py | 5 +- eos/saveddata/module.py | 12 +- gui/attribute_gauge.py | 11 +- gui/bitmap_loader.py | 3 +- gui/builtinContextMenus/cargo.py | 6 +- gui/builtinContextMenus/cargoAmmo.py | 9 +- gui/builtinContextMenus/commandFits.py | 7 +- gui/builtinContextMenus/droneRemoveStack.py | 6 +- gui/builtinContextMenus/metaSwap.py | 16 +-- gui/builtinContextMenus/moduleAmmoPicker.py | 14 +-- .../moduleGlobalAmmoPicker.py | 13 +- gui/builtinContextMenus/project.py | 6 +- gui/builtinContextMenus/tabbedFits.py | 9 +- gui/builtinContextMenus/tacticalMode.py | 7 +- gui/builtinContextMenus/whProjector.py | 16 +-- gui/builtinItemStatsViews/attributeSlider.py | 4 +- gui/builtinItemStatsViews/itemMutator.py | 18 ++- gui/builtinMarketBrowser/itemView.py | 17 ++- .../pyfaEsiPreferences.py | 10 +- .../pyfaGaugePreferences.py | 5 +- gui/builtinShipBrowser/fitItem.py | 8 +- gui/builtinShipBrowser/shipItem.py | 2 +- gui/builtinViews/fittingView.py | 27 ++--- gui/characterEditor.py | 33 +++-- gui/fitCommands/calc/fitRemoveFighter.py | 6 +- gui/fitCommands/calc/fitReplaceModule.py | 12 +- gui/fitCommands/calc/fitSetCharge.py | 9 +- gui/fitCommands/guiModuleToCargo.py | 9 +- gui/mainFrame.py | 114 ++++++++---------- gui/pyfa_gauge.py | 5 +- pyfa.py | 7 +- scripts/dynamicattributes.py | 7 +- scripts/icons_update.py | 8 +- scripts/itemDiff.py | 1 - scripts/jsonToSql.py | 4 +- scripts/t3conversions.py | 8 +- service/fit.py | 16 ++- service/jargon/jargon.py | 3 - service/market.py | 15 +-- service/marketSources/evemarketdata.py | 6 +- service/marketSources/evemarketer.py | 6 +- service/port/efs.py | 27 ++--- service/prereqsCheck.py | 5 +- service/price.py | 10 +- service/update.py | 12 +- tests/test_locale/file_dialog.py | 4 +- tests/test_modules/test_eos/test_gamedata.py | 2 - .../test_eos/test_modifiedAttributeDict.py | 2 - .../test_eos/test_saveddata/test_booster.py | 3 - .../test_eos/test_saveddata/test_fit_2.py | 3 - tests/test_modules/test_service/test_fit.py | 2 - 57 files changed, 260 insertions(+), 365 deletions(-) diff --git a/_development/helpers_fits.py b/_development/helpers_fits.py index a0506827d..347b0622b 100644 --- a/_development/helpers_fits.py +++ b/_development/helpers_fits.py @@ -1,7 +1,6 @@ import pytest # noinspection PyPackageRequirements -from _development.helpers import DBInMemory as DB, Gamedata, Saveddata # noinspection PyShadowingNames diff --git a/_development/helpers_items.py b/_development/helpers_items.py index 7ae722e23..d77adb026 100644 --- a/_development/helpers_items.py +++ b/_development/helpers_items.py @@ -1,7 +1,6 @@ import pytest # noinspection PyPackageRequirements -from _development.helpers import DBInMemory as DB, Gamedata, Saveddata # noinspection PyShadowingNames diff --git a/eos/db/gamedata/category.py b/eos/db/gamedata/category.py index c167cf1df..502f26c22 100644 --- a/eos/db/gamedata/category.py +++ b/eos/db/gamedata/category.py @@ -17,8 +17,8 @@ # along with eos. If not, see . # =============================================================================== -from sqlalchemy import Column, String, Integer, ForeignKey, Boolean, Table -from sqlalchemy.orm import relation, mapper, synonym, deferred +from sqlalchemy import Boolean, Column, Integer, String, Table +from sqlalchemy.orm import deferred, mapper, synonym from eos.db import gamedata_meta from eos.gamedata import Category diff --git a/eos/db/gamedata/item.py b/eos/db/gamedata/item.py index fba3e9820..df7508e43 100644 --- a/eos/db/gamedata/item.py +++ b/eos/db/gamedata/item.py @@ -17,15 +17,15 @@ # along with eos. If not, see . # =============================================================================== -from sqlalchemy import Column, String, Integer, Boolean, ForeignKey, Table, Float +from sqlalchemy import Boolean, Column, Float, ForeignKey, Integer, String, Table from sqlalchemy.ext.associationproxy import association_proxy -from sqlalchemy.orm import relation, mapper, synonym, deferred, backref +from sqlalchemy.orm import backref, deferred, mapper, relation, synonym from sqlalchemy.orm.collections import attribute_mapped_collection -from eos.db.gamedata.effect import typeeffects_table from eos.db import gamedata_meta -from eos.gamedata import Attribute, Effect, Group, Item, MetaType, Traits, DynamicItemItem, DynamicItem -from eos.db.gamedata.dynamicAttributes import dynamicApplicable_table, dynamic_table +from eos.db.gamedata.dynamicAttributes import dynamicApplicable_table +from eos.db.gamedata.effect import typeeffects_table +from eos.gamedata import Attribute, DynamicItem, Effect, Group, Item, MetaType, Traits items_table = Table("invtypes", gamedata_meta, Column("typeID", Integer, primary_key=True), diff --git a/eos/db/gamedata/queries.py b/eos/db/gamedata/queries.py index c6ee5c70b..a026704cb 100644 --- a/eos/db/gamedata/queries.py +++ b/eos/db/gamedata/queries.py @@ -17,16 +17,16 @@ # along with eos. If not, see . # =============================================================================== -from sqlalchemy.orm import join, exc, aliased, joinedload, subqueryload -from sqlalchemy.sql import and_, or_, select from sqlalchemy.inspection import inspect +from sqlalchemy.orm import aliased, exc, join +from sqlalchemy.sql import and_, or_, select import eos.config from eos.db import gamedata_session -from eos.db.gamedata.metaGroup import metatypes_table, items_table from eos.db.gamedata.group import groups_table +from eos.db.gamedata.metaGroup import items_table, metatypes_table from eos.db.util import processEager, processWhere -from eos.gamedata import AlphaClone, Attribute, Category, Group, Item, MarketGroup, MetaGroup, AttributeInfo, MetaData, DynamicItem +from eos.gamedata import AlphaClone, Attribute, AttributeInfo, Category, DynamicItem, Group, Item, MarketGroup, MetaData, MetaGroup cache = {} configVal = getattr(eos.config, "gamedataCache", None) diff --git a/eos/db/saveddata/fit.py b/eos/db/saveddata/fit.py index 7e3c76f5f..dbee2c622 100644 --- a/eos/db/saveddata/fit.py +++ b/eos/db/saveddata/fit.py @@ -17,33 +17,32 @@ # along with eos. If not, see . # =============================================================================== -from sqlalchemy.ext.associationproxy import association_proxy -from sqlalchemy.orm.collections import attribute_mapped_collection -from sqlalchemy.sql import and_ -from sqlalchemy.orm import relation, reconstructor, mapper, relationship -from sqlalchemy import ForeignKey, Column, Integer, String, Table, Boolean, DateTime import datetime -from eos.db import saveddata_meta -from eos.db import saveddata_session +from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer, String, Table +from sqlalchemy.ext.associationproxy import association_proxy +from sqlalchemy.orm import mapper, reconstructor, relation, relationship +from sqlalchemy.orm.collections import attribute_mapped_collection +from sqlalchemy.sql import and_ + +from eos.db import saveddata_meta, saveddata_session from eos.db.saveddata.cargo import cargo_table from eos.db.saveddata.drone import drones_table from eos.db.saveddata.fighter import fighters_table from eos.db.saveddata.implant import fitImplants_table from eos.db.saveddata.module import modules_table -from eos.effectHandlerHelpers import HandledModuleList, HandledImplantBoosterList, HandledProjectedModList, \ - HandledDroneCargoList, HandledProjectedDroneList -from eos.saveddata.implant import Implant -from eos.saveddata.character import Character -from eos.saveddata.user import User -from eos.saveddata.fighter import Fighter -from eos.saveddata.fit import Fit as es_Fit, ImplantLocation -from eos.saveddata.drone import Drone +from eos.effectHandlerHelpers import HandledDroneCargoList, HandledImplantBoosterList, HandledModuleList, HandledProjectedDroneList, HandledProjectedModList from eos.saveddata.booster import Booster -from eos.saveddata.module import Module from eos.saveddata.cargo import Cargo +from eos.saveddata.character import Character from eos.saveddata.damagePattern import DamagePattern +from eos.saveddata.drone import Drone +from eos.saveddata.fighter import Fighter +from eos.saveddata.fit import Fit as es_Fit +from eos.saveddata.implant import Implant +from eos.saveddata.module import Module from eos.saveddata.targetResists import TargetResists +from eos.saveddata.user import User fits_table = Table("fits", saveddata_meta, Column("ID", Integer, primary_key=True), diff --git a/eos/db/saveddata/mutator.py b/eos/db/saveddata/mutator.py index 11b595025..1ba81e097 100644 --- a/eos/db/saveddata/mutator.py +++ b/eos/db/saveddata/mutator.py @@ -17,10 +17,11 @@ # along with eos. If not, see . # =============================================================================== -from sqlalchemy import Table, Column, Integer, ForeignKey, Boolean, DateTime, Float -from sqlalchemy.orm import mapper import datetime +from sqlalchemy import Column, DateTime, Float, ForeignKey, Integer, Table +from sqlalchemy.orm import mapper + from eos.db import saveddata_meta from eos.saveddata.mutator import Mutator diff --git a/eos/saveddata/module.py b/eos/saveddata/module.py index a675b0fb0..3bb92dcf4 100644 --- a/eos/saveddata/module.py +++ b/eos/saveddata/module.py @@ -17,19 +17,17 @@ # along with eos. If not, see . # =============================================================================== -from logbook import Logger -from copy import deepcopy - -from sqlalchemy.orm import validates, reconstructor from math import floor +from logbook import Logger +from sqlalchemy.orm import reconstructor, validates + import eos.db -from eos.effectHandlerHelpers import HandledItem, HandledCharge +from eos.effectHandlerHelpers import HandledCharge, HandledItem from eos.enum import Enum -from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut, ChargeAttrShortcut +from eos.modifiedAttributeDict import ChargeAttrShortcut, ItemAttrShortcut, ModifiedAttributeDict from eos.saveddata.citadel import Citadel from eos.saveddata.mutator import Mutator -from utils.deprecated import deprecated pyfalog = Logger(__name__) diff --git a/gui/attribute_gauge.py b/gui/attribute_gauge.py index 1057775f7..e275b2dc2 100644 --- a/gui/attribute_gauge.py +++ b/gui/attribute_gauge.py @@ -1,10 +1,13 @@ -import copy import wx import math -from gui.utils import color as color_utils -from gui.utils import draw, anim_effects -from service.fit import Fit +from gui.utils import anim_effects +import math + +import wx + +from gui.utils import anim_effects + # todo: clean class up. Took from pyfa gauge, has a bunch of extra shit we don't need diff --git a/gui/bitmap_loader.py b/gui/bitmap_loader.py index 061e05a0c..deb0712f4 100644 --- a/gui/bitmap_loader.py +++ b/gui/bitmap_loader.py @@ -19,15 +19,14 @@ import io import os.path -import zipfile from collections import OrderedDict # noinspection PyPackageRequirements import wx +from logbook import Logger import config -from logbook import Logger logging = Logger(__name__) diff --git a/gui/builtinContextMenus/cargo.py b/gui/builtinContextMenus/cargo.py index a0b1c6e80..3bcadfa31 100644 --- a/gui/builtinContextMenus/cargo.py +++ b/gui/builtinContextMenus/cargo.py @@ -1,11 +1,9 @@ -from gui.contextMenu import ContextMenu +import gui.fitCommands as cmd import gui.mainFrame -import gui.globalEvents as GE +from gui.contextMenu import ContextMenu # noinspection PyPackageRequirements -import wx from service.fit import Fit from service.settings import ContextMenuSettings -import gui.fitCommands as cmd class Cargo(ContextMenu): diff --git a/gui/builtinContextMenus/cargoAmmo.py b/gui/builtinContextMenus/cargoAmmo.py index af3a855ac..b92ba8e3a 100644 --- a/gui/builtinContextMenus/cargoAmmo.py +++ b/gui/builtinContextMenus/cargoAmmo.py @@ -1,10 +1,7 @@ -from gui.contextMenu import ContextMenu -import gui.mainFrame -import gui.globalEvents as GE -import wx -from service.settings import ContextMenuSettings -from service.fit import Fit import gui.fitCommands as cmd +import gui.mainFrame +from gui.contextMenu import ContextMenu +from service.settings import ContextMenuSettings class CargoAmmo(ContextMenu): diff --git a/gui/builtinContextMenus/commandFits.py b/gui/builtinContextMenus/commandFits.py index d97118297..97496bb75 100644 --- a/gui/builtinContextMenus/commandFits.py +++ b/gui/builtinContextMenus/commandFits.py @@ -1,13 +1,12 @@ # noinspection PyPackageRequirements import wx +import gui.fitCommands as cmd +import gui.mainFrame +from gui.contextMenu import ContextMenu from service.fit import Fit from service.market import Market -import gui.mainFrame -import gui.globalEvents as GE -from gui.contextMenu import ContextMenu from service.settings import ContextMenuSettings -import gui.fitCommands as cmd class CommandFits(ContextMenu): diff --git a/gui/builtinContextMenus/droneRemoveStack.py b/gui/builtinContextMenus/droneRemoveStack.py index 5af373e41..fad83f1e8 100644 --- a/gui/builtinContextMenus/droneRemoveStack.py +++ b/gui/builtinContextMenus/droneRemoveStack.py @@ -1,11 +1,9 @@ -from gui.contextMenu import ContextMenu +import gui.fitCommands as cmd import gui.mainFrame +from gui.contextMenu import ContextMenu # noinspection PyPackageRequirements -import wx -import gui.globalEvents as GE from service.fit import Fit from service.settings import ContextMenuSettings -import gui.fitCommands as cmd class ItemRemove(ContextMenu): diff --git a/gui/builtinContextMenus/metaSwap.py b/gui/builtinContextMenus/metaSwap.py index 83304f4f7..2cbbb2221 100644 --- a/gui/builtinContextMenus/metaSwap.py +++ b/gui/builtinContextMenus/metaSwap.py @@ -3,19 +3,11 @@ # noinspection PyPackageRequirements import wx -from service.fit import Fit -from service.market import Market -import gui.mainFrame -import gui.globalEvents as GE -from gui.contextMenu import ContextMenu -from service.settings import ContextMenuSettings -from eos.saveddata.booster import Booster -from eos.saveddata.module import Module -from eos.saveddata.drone import Drone -from eos.saveddata.fighter import Fighter -from eos.saveddata.implant import Implant -from eos.saveddata.cargo import Cargo import gui.fitCommands as cmd +import gui.mainFrame +from gui.contextMenu import ContextMenu +from service.market import Market +from service.settings import ContextMenuSettings class MetaSwap(ContextMenu): diff --git a/gui/builtinContextMenus/moduleAmmoPicker.py b/gui/builtinContextMenus/moduleAmmoPicker.py index 30e1b25d6..2506a1eb1 100644 --- a/gui/builtinContextMenus/moduleAmmoPicker.py +++ b/gui/builtinContextMenus/moduleAmmoPicker.py @@ -3,15 +3,13 @@ # noinspection PyPackageRequirements import wx -from service.fit import Fit -from service.market import Market -from eos.saveddata.module import Hardpoint -import gui.mainFrame -import gui.globalEvents as GE -from gui.contextMenu import ContextMenu -from gui.bitmap_loader import BitmapLoader -from service.settings import ContextMenuSettings import gui.fitCommands as cmd +import gui.mainFrame +from eos.saveddata.module import Hardpoint +from gui.bitmap_loader import BitmapLoader +from gui.contextMenu import ContextMenu +from service.market import Market +from service.settings import ContextMenuSettings class ModuleAmmoPicker(ContextMenu): diff --git a/gui/builtinContextMenus/moduleGlobalAmmoPicker.py b/gui/builtinContextMenus/moduleGlobalAmmoPicker.py index d0fdbf55b..70a41c351 100644 --- a/gui/builtinContextMenus/moduleGlobalAmmoPicker.py +++ b/gui/builtinContextMenus/moduleGlobalAmmoPicker.py @@ -1,13 +1,10 @@ # -*- coding: utf-8 -*- -import gui.mainFrame -# noinspection PyPackageRequirements -import wx -import gui.globalEvents as GE -from gui.builtinContextMenus.moduleAmmoPicker import ModuleAmmoPicker -from eos.db.saveddata.queries import getFit as db_getFit -from service.fit import Fit -from service.settings import ContextMenuSettings import gui.fitCommands as cmd +import gui.mainFrame +from eos.db.saveddata.queries import getFit as db_getFit +# noinspection PyPackageRequirements +from gui.builtinContextMenus.moduleAmmoPicker import ModuleAmmoPicker +from service.settings import ContextMenuSettings class ModuleGlobalAmmoPicker(ModuleAmmoPicker): diff --git a/gui/builtinContextMenus/project.py b/gui/builtinContextMenus/project.py index 4b41a30e2..6bbb974b3 100644 --- a/gui/builtinContextMenus/project.py +++ b/gui/builtinContextMenus/project.py @@ -1,11 +1,9 @@ -from gui.contextMenu import ContextMenu +import gui.fitCommands as cmd import gui.mainFrame -import gui.globalEvents as GE +from gui.contextMenu import ContextMenu # noinspection PyPackageRequirements -import wx from service.fit import Fit from service.settings import ContextMenuSettings -import gui.fitCommands as cmd class Project(ContextMenu): diff --git a/gui/builtinContextMenus/tabbedFits.py b/gui/builtinContextMenus/tabbedFits.py index 582f4158d..f86562fa6 100644 --- a/gui/builtinContextMenus/tabbedFits.py +++ b/gui/builtinContextMenus/tabbedFits.py @@ -3,12 +3,11 @@ # noinspection PyPackageRequirements import wx -from service.fit import Fit -import gui.mainFrame -import gui.globalEvents as GE -from gui.contextMenu import ContextMenu -from gui.builtinViews.emptyView import BlankPage import gui.fitCommands as cmd +import gui.mainFrame +from gui.builtinViews.emptyView import BlankPage +from gui.contextMenu import ContextMenu +from service.fit import Fit class TabbedFits(ContextMenu): diff --git a/gui/builtinContextMenus/tacticalMode.py b/gui/builtinContextMenus/tacticalMode.py index a8edff27b..94bfc1076 100644 --- a/gui/builtinContextMenus/tacticalMode.py +++ b/gui/builtinContextMenus/tacticalMode.py @@ -1,12 +1,11 @@ # noinspection PyPackageRequirements import wx -from gui.contextMenu import ContextMenu -import gui.mainFrame -import gui.globalEvents as GE +import gui.fitCommands as cmd +import gui.mainFrame +from gui.contextMenu import ContextMenu from service.fit import Fit from service.settings import ContextMenuSettings -import gui.fitCommands as cmd class TacticalMode(ContextMenu): diff --git a/gui/builtinContextMenus/whProjector.py b/gui/builtinContextMenus/whProjector.py index 16b1255b5..c6e083676 100644 --- a/gui/builtinContextMenus/whProjector.py +++ b/gui/builtinContextMenus/whProjector.py @@ -1,14 +1,14 @@ -from gui.contextMenu import ContextMenu -import gui.mainFrame -import gui.globalEvents as GE +import re +from itertools import chain + # noinspection PyPackageRequirements import wx -from service.market import Market -from service.fit import Fit -from service.settings import ContextMenuSettings -from itertools import chain -import re + import gui.fitCommands as cmd +import gui.mainFrame +from gui.contextMenu import ContextMenu +from service.market import Market +from service.settings import ContextMenuSettings class WhProjector(ContextMenu): diff --git a/gui/builtinItemStatsViews/attributeSlider.py b/gui/builtinItemStatsViews/attributeSlider.py index 69358278c..8de27e347 100644 --- a/gui/builtinItemStatsViews/attributeSlider.py +++ b/gui/builtinItemStatsViews/attributeSlider.py @@ -1,9 +1,7 @@ import wx import wx.lib.newevent -from gui.attribute_gauge import AttributeGauge -import eos -import eos.db +from gui.attribute_gauge import AttributeGauge _ValueChanged, EVT_VALUE_CHANGED = wx.lib.newevent.NewEvent() diff --git a/gui/builtinItemStatsViews/itemMutator.py b/gui/builtinItemStatsViews/itemMutator.py index 614274e6e..30ba82fd9 100644 --- a/gui/builtinItemStatsViews/itemMutator.py +++ b/gui/builtinItemStatsViews/itemMutator.py @@ -1,18 +1,16 @@ # noinspection PyPackageRequirements -import wx - -from service.fit import Fit -from .attributeSlider import AttributeSlider, EVT_VALUE_CHANGED - -import gui.mainFrame -from gui.contextMenu import ContextMenu -from .itemAttributes import ItemParams -from gui.bitmap_loader import BitmapLoader -import gui.globalEvents as GE import random +import wx from logbook import Logger +import gui.globalEvents as GE +import gui.mainFrame +from gui.bitmap_loader import BitmapLoader +from service.fit import Fit +from .attributeSlider import AttributeSlider, EVT_VALUE_CHANGED +from .itemAttributes import ItemParams + pyfalog = Logger(__name__) diff --git a/gui/builtinMarketBrowser/itemView.py b/gui/builtinMarketBrowser/itemView.py index 7a26cfed1..82454502a 100644 --- a/gui/builtinMarketBrowser/itemView.py +++ b/gui/builtinMarketBrowser/itemView.py @@ -1,16 +1,13 @@ import wx - -import config -import gui.builtinMarketBrowser.pfSearchBox as SBox -from gui.contextMenu import ContextMenu -from gui.display import Display -from service.attribute import Attribute -from service.fit import Fit -from gui.utils.staticHelpers import DragDropHelper - from logbook import Logger -from gui.builtinMarketBrowser.events import RECENTLY_USED_MODULES, MAX_RECENTLY_USED_MODULES, ItemSelected +import gui.builtinMarketBrowser.pfSearchBox as SBox +from gui.builtinMarketBrowser.events import ItemSelected, MAX_RECENTLY_USED_MODULES, RECENTLY_USED_MODULES +from gui.contextMenu import ContextMenu +from gui.display import Display +from gui.utils.staticHelpers import DragDropHelper +from service.attribute import Attribute +from service.fit import Fit pyfalog = Logger(__name__) diff --git a/gui/builtinPreferenceViews/pyfaEsiPreferences.py b/gui/builtinPreferenceViews/pyfaEsiPreferences.py index 7eaf31a4e..39125ed38 100644 --- a/gui/builtinPreferenceViews/pyfaEsiPreferences.py +++ b/gui/builtinPreferenceViews/pyfaEsiPreferences.py @@ -1,17 +1,13 @@ # noinspection PyPackageRequirements import wx -from gui.preferenceView import PreferenceView -from gui.bitmap_loader import BitmapLoader - import gui.mainFrame - +from gui.bitmap_loader import BitmapLoader +from gui.preferenceView import PreferenceView from service.settings import EsiSettings -# noinspection PyPackageRequirements -from wx.lib.intctrl import IntCtrl -from service.esi import Esi +# noinspection PyPackageRequirements class PFEsiPref(PreferenceView): diff --git a/gui/builtinPreferenceViews/pyfaGaugePreferences.py b/gui/builtinPreferenceViews/pyfaGaugePreferences.py index c0ca68a98..7ba91eff3 100644 --- a/gui/builtinPreferenceViews/pyfaGaugePreferences.py +++ b/gui/builtinPreferenceViews/pyfaGaugePreferences.py @@ -3,12 +3,9 @@ # noinspection PyPackageRequirements import wx -import copy -from gui.preferenceView import PreferenceView from gui.bitmap_loader import BitmapLoader -from gui.utils.color import CalculateTransition -import gui.utils.draw as drawUtils +from gui.preferenceView import PreferenceView ########################################################################### diff --git a/gui/builtinShipBrowser/fitItem.py b/gui/builtinShipBrowser/fitItem.py index 05470f97a..c0bd9c07b 100644 --- a/gui/builtinShipBrowser/fitItem.py +++ b/gui/builtinShipBrowser/fitItem.py @@ -2,22 +2,22 @@ import re import time -import config import wx from logbook import Logger +import config import gui.builtinShipBrowser.sfBrowserItem as SFItem -import gui.globalEvents as GE +import gui.fitCommands as cmd import gui.mainFrame import gui.utils.color as colorUtils import gui.utils.draw as drawUtils import gui.utils.fonts as fonts -from .events import ImportSelected, SearchSelected, FitSelected, BoosterListUpdated, Stage3Selected, FitRenamed, FitRemoved from gui.bitmap_loader import BitmapLoader from gui.builtinShipBrowser.pfBitmapFrame import PFBitmapFrame from service.fit import Fit -import gui.fitCommands as cmd +from .events import BoosterListUpdated, FitRemoved, FitSelected, ImportSelected, SearchSelected, Stage3Selected + pyfalog = Logger(__name__) diff --git a/gui/builtinShipBrowser/shipItem.py b/gui/builtinShipBrowser/shipItem.py index 517648ad6..cf1de024c 100644 --- a/gui/builtinShipBrowser/shipItem.py +++ b/gui/builtinShipBrowser/shipItem.py @@ -8,11 +8,11 @@ import gui.mainFrame import gui.utils.color as colorUtils import gui.utils.draw as drawUtils import gui.utils.fonts as fonts -from .events import Stage3Selected, Stage2Selected, Stage1Selected, FitSelected from gui.bitmap_loader import BitmapLoader from gui.contextMenu import ContextMenu from service.fit import Fit from service.market import Market +from .events import FitSelected, Stage3Selected pyfalog = Logger(__name__) diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index 85fbbb8b2..5eda0eadc 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -21,29 +21,26 @@ import wx # noinspection PyPackageRequirements import wx.lib.newevent -import gui.mainFrame -from gui.builtinMarketBrowser.events import ItemSelected, ITEM_SELECTED +from logbook import Logger + +import gui.builtinViews.emptyView import gui.display as d -from gui.contextMenu import ContextMenu -from gui.builtinShipBrowser.events import EVT_FIT_RENAMED, EVT_FIT_REMOVED, FitSelected, EVT_FIT_SELECTED +import gui.fitCommands as cmd +import gui.globalEvents as GE +import gui.mainFrame import gui.multiSwitch from eos.saveddata.mode import Mode -from eos.saveddata.module import Module, Slot, Rack -from gui.builtinViewColumns.state import State +from eos.saveddata.module import Module, Rack, Slot from gui.bitmap_loader import BitmapLoader -import gui.builtinViews.emptyView -from logbook import Logger +from gui.builtinMarketBrowser.events import ITEM_SELECTED +from gui.builtinShipBrowser.events import EVT_FIT_REMOVED, EVT_FIT_RENAMED, EVT_FIT_SELECTED, FitSelected +from gui.builtinViewColumns.state import State from gui.chrome_tabs import EVT_NOTEBOOK_PAGE_CHANGED -import gui.fitCommands as cmd - +from gui.contextMenu import ContextMenu +from gui.utils.staticHelpers import DragDropHelper from service.fit import Fit from service.market import Market -from gui.utils.staticHelpers import DragDropHelper -import gui.utils.fonts as fonts - -import gui.globalEvents as GE - pyfalog = Logger(__name__) diff --git a/gui/characterEditor.py b/gui/characterEditor.py index c0d8de298..6fe7c809a 100644 --- a/gui/characterEditor.py +++ b/gui/characterEditor.py @@ -17,35 +17,30 @@ # along with pyfa. If not, see . # ============================================================================= +import re + +import roman # noinspection PyPackageRequirements import wx import wx.dataview import wx.lib.agw.hyperlink - # noinspection PyPackageRequirements import wx.lib.newevent +from logbook import Logger # noinspection PyPackageRequirements from wx.dataview import TreeListCtrl -from gui.bitmap_loader import BitmapLoader -from gui.contextMenu import ContextMenu -import gui.globalEvents as GE -from gui.builtinViews.implantEditor import BaseImplantEditorView -from gui.builtinViews.entityEditor import EntityEditor, BaseValidator, TextEntryValidatedDialog -from service.fit import Fit -from service.character import Character -from service.esi import Esi -from service.network import AuthenticationError, TimeoutError -from service.market import Market -from logbook import Logger - from wx.lib.agw.floatspin import FloatSpin - -from gui.utils.clipboard import toClipboard, fromClipboard - -import roman -import re -import webbrowser +import gui.globalEvents as GE +from gui.bitmap_loader import BitmapLoader +from gui.builtinViews.entityEditor import BaseValidator, EntityEditor, TextEntryValidatedDialog +from gui.builtinViews.implantEditor import BaseImplantEditorView +from gui.contextMenu import ContextMenu +from gui.utils.clipboard import fromClipboard, toClipboard +from service.character import Character +from service.esi import Esi +from service.fit import Fit +from service.market import Market pyfalog = Logger(__name__) diff --git a/gui/fitCommands/calc/fitRemoveFighter.py b/gui/fitCommands/calc/fitRemoveFighter.py index 58b1f7c6a..da186bd48 100644 --- a/gui/fitCommands/calc/fitRemoveFighter.py +++ b/gui/fitCommands/calc/fitRemoveFighter.py @@ -1,8 +1,8 @@ import wx - -from gui.fitCommands.helpers import ModuleInfoCache -import eos.db from logbook import Logger + +import eos.db + pyfalog = Logger(__name__) diff --git a/gui/fitCommands/calc/fitReplaceModule.py b/gui/fitCommands/calc/fitReplaceModule.py index ddfd2c770..19674df80 100644 --- a/gui/fitCommands/calc/fitReplaceModule.py +++ b/gui/fitCommands/calc/fitReplaceModule.py @@ -1,12 +1,10 @@ import wx -from service.fit import Fit - -import gui.mainFrame -from gui import globalEvents as GE -from gui.fitCommands.helpers import ModuleInfoCache -from eos.saveddata.module import Module, State -import eos.db from logbook import Logger + +import eos.db +from eos.saveddata.module import Module, State +from gui.fitCommands.helpers import ModuleInfoCache + pyfalog = Logger(__name__) diff --git a/gui/fitCommands/calc/fitSetCharge.py b/gui/fitCommands/calc/fitSetCharge.py index 6cc6d0988..93a6da4ae 100644 --- a/gui/fitCommands/calc/fitSetCharge.py +++ b/gui/fitCommands/calc/fitSetCharge.py @@ -1,11 +1,10 @@ import wx +from logbook import Logger + +import eos.db +import gui.mainFrame from service.fit import Fit -import gui.mainFrame -from gui import globalEvents as GE -from eos.saveddata.module import Module -from logbook import Logger -import eos.db pyfalog = Logger(__name__) diff --git a/gui/fitCommands/guiModuleToCargo.py b/gui/fitCommands/guiModuleToCargo.py index 95e9be0b6..66a9f9833 100644 --- a/gui/fitCommands/guiModuleToCargo.py +++ b/gui/fitCommands/guiModuleToCargo.py @@ -1,15 +1,14 @@ import wx -from service.fit import Fit +from logbook import Logger import gui.mainFrame from gui import globalEvents as GE -from gui.fitCommands.calc.fitSetCharge import FitSetChargeCommand -from gui.fitCommands.calc.fitReplaceModule import FitReplaceModuleCommand from gui.fitCommands.calc.fitRemoveCargo import FitRemoveCargoCommand from gui.fitCommands.calc.fitRemoveModule import FitRemoveModuleCommand - +from gui.fitCommands.calc.fitReplaceModule import FitReplaceModuleCommand +from service.fit import Fit from .calc.fitAddCargo import FitAddCargoCommand -from logbook import Logger + pyfalog = Logger(__name__) diff --git a/gui/mainFrame.py b/gui/mainFrame.py index b8277e8cb..7c6e71877 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -17,76 +17,62 @@ # along with pyfa. If not, see . # ============================================================================= -import sys -import os.path -from logbook import Logger - -import sqlalchemy -# noinspection PyPackageRequirements -import wx -# noinspection PyPackageRequirements -from wx.lib.wordwrap import wordwrap -# noinspection PyPackageRequirements -from wx.lib.inspection import InspectionTool -import time - -from codecs import open - -import config - -from eos.config import gamedata_version, gamedata_date import datetime - -import gui.aboutData -from gui.chrome_tabs import ChromeNotebook -import gui.globalEvents as GE - -from gui.bitmap_loader import BitmapLoader -from gui.mainMenuBar import MainMenuBar -from gui.additionsPane import AdditionsPane -from gui.marketBrowser import MarketBrowser -from gui.builtinMarketBrowser.events import ItemSelected -from gui.multiSwitch import MultiSwitch -from gui.statsPane import StatsPane -from gui.shipBrowser import ShipBrowser -from gui.builtinShipBrowser.events import FitSelected, ImportSelected, Stage3Selected -from gui.characterEditor import CharacterEditor -from gui.characterSelection import CharacterSelection -from gui.patternEditor import DmgPatternEditorDlg -from gui.resistsEditor import ResistsEditorDlg -from gui.setEditor import ImplantSetEditorDlg -from gui.devTools import DevTools -from gui.preferenceDialog import PreferenceDialog -from gui.graphFrame import GraphFrame -from gui.ssoLogin import SsoLogin -from gui.copySelectDialog import CopySelectDialog -from gui.utils.clipboard import toClipboard, fromClipboard -from gui.updateDialog import UpdateDialog -# noinspection PyUnresolvedReferences -from gui.builtinViews import emptyView, entityEditor, fittingView, implantEditor # noqa: F401 -from gui import graphFrame - -from service.settings import SettingsProvider -from service.fit import Fit -from service.character import Character -from service.update import Update -from service.esiAccess import SsoMode - -# import this to access override setting -from eos.modifiedAttributeDict import ModifiedAttributeDict -from eos.db.saveddata.loadDefaultDatabaseValues import DefaultDatabaseValues -from eos.db.saveddata.queries import getFit as db_getFit -from service.port import Port, IPortUser, EfsPort -from service.settings import HTMLExportSettings - +import os.path +import threading +import time +import webbrowser +from codecs import open from time import gmtime, strftime -import threading -import webbrowser +# noinspection PyPackageRequirements +import wx import wx.adv +from logbook import Logger +# noinspection PyPackageRequirements +# noinspection PyPackageRequirements +from wx.lib.inspection import InspectionTool -from service.esi import Esi, LoginMethod +import config +import gui.globalEvents as GE +from eos.config import gamedata_date, gamedata_version +from eos.db.saveddata.loadDefaultDatabaseValues import DefaultDatabaseValues +from eos.db.saveddata.queries import getFit as db_getFit +# import this to access override setting +from eos.modifiedAttributeDict import ModifiedAttributeDict +from gui import graphFrame +from gui.additionsPane import AdditionsPane +from gui.bitmap_loader import BitmapLoader +from gui.builtinMarketBrowser.events import ItemSelected +from gui.builtinShipBrowser.events import FitSelected, ImportSelected, Stage3Selected +# noinspection PyUnresolvedReferences +from gui.builtinViews import emptyView, entityEditor, fittingView, implantEditor # noqa: F401 +from gui.characterEditor import CharacterEditor +from gui.characterSelection import CharacterSelection +from gui.chrome_tabs import ChromeNotebook +from gui.copySelectDialog import CopySelectDialog +from gui.devTools import DevTools from gui.esiFittings import EveFittings, ExportToEve, SsoCharacterMgmt +from gui.graphFrame import GraphFrame +from gui.mainMenuBar import MainMenuBar +from gui.marketBrowser import MarketBrowser +from gui.multiSwitch import MultiSwitch +from gui.patternEditor import DmgPatternEditorDlg +from gui.preferenceDialog import PreferenceDialog +from gui.resistsEditor import ResistsEditorDlg +from gui.setEditor import ImplantSetEditorDlg +from gui.shipBrowser import ShipBrowser +from gui.ssoLogin import SsoLogin +from gui.statsPane import StatsPane +from gui.updateDialog import UpdateDialog +from gui.utils.clipboard import fromClipboard, toClipboard +from service.character import Character +from service.esi import Esi, LoginMethod +from service.esiAccess import SsoMode +from service.fit import Fit +from service.port import EfsPort, IPortUser, Port +from service.settings import HTMLExportSettings, SettingsProvider +from service.update import Update disableOverrideEditor = False diff --git a/gui/pyfa_gauge.py b/gui/pyfa_gauge.py index 61379c5b0..c3e3e1c16 100644 --- a/gui/pyfa_gauge.py +++ b/gui/pyfa_gauge.py @@ -14,11 +14,10 @@ # =============================================================================== import copy + import wx -from gui.utils import color as color_utils -from gui.utils import draw, anim_effects -from service.fit import Fit +from gui.utils import anim_effects, color as color_utils, draw class PyGauge(wx.Window): diff --git a/pyfa.py b/pyfa.py index 740d443ab..d73ef0975 100755 --- a/pyfa.py +++ b/pyfa.py @@ -19,13 +19,14 @@ # ============================================================================== +import datetime import os import sys -import traceback from optparse import AmbiguousOptionError, BadOptionError, OptionParser -from service.prereqsCheck import PreCheckException, PreCheckMessage, version_precheck, version_block + import config -import datetime +from service.prereqsCheck import PreCheckException, PreCheckMessage, version_block, version_precheck + # ascii_text = ''' # ++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/scripts/dynamicattributes.py b/scripts/dynamicattributes.py index f21a5f96a..b6a2d720b 100644 --- a/scripts/dynamicattributes.py +++ b/scripts/dynamicattributes.py @@ -6,13 +6,8 @@ This script will generate a dynamicItemAttributes.json file using res files import argparse -import os -import re -import sqlite3 import json - -from PIL import Image - +import os from shutil import copyfile parser = argparse.ArgumentParser(description='This script updates module icons for pyfa') diff --git a/scripts/icons_update.py b/scripts/icons_update.py index 0ad4c5359..663d168b9 100644 --- a/scripts/icons_update.py +++ b/scripts/icons_update.py @@ -6,15 +6,13 @@ This script updates only market/item icons. import argparse -import os -import re -import sqlite3 import json +import os +import sqlite3 +from shutil import copyfile from PIL import Image -from shutil import copyfile - parser = argparse.ArgumentParser(description='This script updates module icons for pyfa') parser.add_argument('-e', '--eve', required=True, type=str, help='path to eve\'s ') parser.add_argument('-s', '--server', required=False, default='tq', type=str, help='which server to use (defaults to tq)') diff --git a/scripts/itemDiff.py b/scripts/itemDiff.py index 1874bcd92..42f31561a 100755 --- a/scripts/itemDiff.py +++ b/scripts/itemDiff.py @@ -29,7 +29,6 @@ import argparse import os.path import re import sqlite3 -import sys script_dir = os.path.dirname(__file__) default_old = os.path.join(script_dir, "..", "eve.db") diff --git a/scripts/jsonToSql.py b/scripts/jsonToSql.py index add0fe957..eb3ea6cdc 100755 --- a/scripts/jsonToSql.py +++ b/scripts/jsonToSql.py @@ -18,10 +18,9 @@ # License along with eos. If not, see . #====================================================================== +import functools import os import sys -import functools -import re # Add eos root path to sys.path so we can import ourselves path = os.path.dirname(__file__) @@ -46,7 +45,6 @@ def main(db, json_path): eos.config.debug = False # Now thats done, we can import the eos modules using the config - import eos.db import eos.gamedata # Create the database tables diff --git a/scripts/t3conversions.py b/scripts/t3conversions.py index 8b6e7e09a..4f2445071 100644 --- a/scripts/t3conversions.py +++ b/scripts/t3conversions.py @@ -2,11 +2,11 @@ # Requires eve-old.db file (which is the previous releases database so that we can lookup the old items) # See https://community.eveonline.com/news/patch-notes/patch-notes-for-july-2017-release -import sys -from os.path import realpath, join, dirname, abspath -from sqlalchemy import MetaData, create_engine -from sqlalchemy.orm import sessionmaker import csv +import sys +from os.path import abspath, dirname, join, realpath + +from sqlalchemy import create_engine newDB = create_engine('sqlite:///' + unicode(realpath(join(dirname(abspath(__file__)), "..", "eve.db")), sys.getfilesystemencoding())) oldDB = create_engine('sqlite:///' + unicode(realpath(join(dirname(abspath(__file__)), "..", "eve-old.db")), sys.getfilesystemencoding())) diff --git a/service/fit.py b/service/fit.py index f58c5eed4..d3ac0f9d8 100644 --- a/service/fit.py +++ b/service/fit.py @@ -18,28 +18,26 @@ # =============================================================================== import copy -from logbook import Logger -from time import time import datetime +from time import time + +import wx +from logbook import Logger import eos.db -from eos.saveddata.booster import Booster as es_Booster -from eos.saveddata.cargo import Cargo as es_Cargo from eos.saveddata.character import Character as saveddata_Character from eos.saveddata.citadel import Citadel as es_Citadel from eos.saveddata.damagePattern import DamagePattern as es_DamagePattern from eos.saveddata.drone import Drone as es_Drone from eos.saveddata.fighter import Fighter as es_Fighter -from eos.saveddata.implant import Implant as es_Implant -from eos.saveddata.ship import Ship as es_Ship -from eos.saveddata.module import Module as es_Module, State, Slot, ProjectedMap, ProjectedSystem, LocalMap from eos.saveddata.fit import Fit as FitType, ImplantLocation +from eos.saveddata.module import Module as es_Module, State +from eos.saveddata.ship import Ship as es_Ship from service.character import Character from service.damagePattern import DamagePattern +from service.fitDeprecated import FitDeprecated from service.settings import SettingsProvider from utils.deprecated import deprecated -import wx -from service.fitDeprecated import FitDeprecated pyfalog = Logger(__name__) diff --git a/service/jargon/jargon.py b/service/jargon/jargon.py index bc9a0d525..3530d0859 100644 --- a/service/jargon/jargon.py +++ b/service/jargon/jargon.py @@ -17,9 +17,6 @@ # along with pyfa. If not, see . # ============================================================================= -import config -import pkg_resources - class Jargon(object): def __init__(self, rawdata: dict): diff --git a/service/market.py b/service/market.py index 545b1a66f..3e128cbbc 100644 --- a/service/market.py +++ b/service/market.py @@ -17,25 +17,22 @@ # along with pyfa. If not, see . # =============================================================================== -import re -import threading -from logbook import Logger import queue -from itertools import chain +import threading +from collections import OrderedDict # noinspection PyPackageRequirements import wx +from logbook import Logger from sqlalchemy.sql import or_ import config import eos.db -from service import conversions -from service.settings import SettingsProvider -from service.jargon import JargonLoader - from eos.gamedata import Category as types_Category, Group as types_Group, Item as types_Item, MarketGroup as types_MarketGroup, \ MetaGroup as types_MetaGroup, MetaType as types_MetaType -from collections import OrderedDict +from service import conversions +from service.jargon import JargonLoader +from service.settings import SettingsProvider pyfalog = Logger(__name__) diff --git a/service/marketSources/evemarketdata.py b/service/marketSources/evemarketdata.py index be42cb66d..bd1f8f3af 100644 --- a/service/marketSources/evemarketdata.py +++ b/service/marketSources/evemarketdata.py @@ -18,12 +18,12 @@ # ============================================================================= import time -from logbook import Logger from xml.dom import minidom -from service.network import Network -from service.price import Price, VALIDITY, TIMEOUT, TimeoutError +from logbook import Logger +from service.network import Network +from service.price import Price, TIMEOUT, VALIDITY pyfalog = Logger(__name__) diff --git a/service/marketSources/evemarketer.py b/service/marketSources/evemarketer.py index 948b9ec48..a2728ddfb 100644 --- a/service/marketSources/evemarketer.py +++ b/service/marketSources/evemarketer.py @@ -18,12 +18,12 @@ # ============================================================================= import time -from logbook import Logger from xml.dom import minidom -from service.network import Network -from service.price import Price, VALIDITY, TIMEOUT, TimeoutError +from logbook import Logger +from service.network import Network +from service.price import Price, VALIDITY pyfalog = Logger(__name__) diff --git a/service/port/efs.py b/service/port/efs.py index d1dd394d9..b3342fb8f 100755 --- a/service/port/efs.py +++ b/service/port/efs.py @@ -1,23 +1,20 @@ -import inspect -import os -import platform -import re -import sys -import traceback import json -import eos.db - +import json from math import log + +from logbook import Logger + +import eos.db from config import version as pyfaVersion +from eos.db import gamedata_session, getAttributeInfo, getCategory, getGroup +from eos.effectHandlerHelpers import HandledList +from eos.enum import Enum +from eos.gamedata import Attribute, Effect, Group, Item, ItemEffect +from eos.saveddata.drone import Drone +from eos.saveddata.module import Hardpoint, Module, Slot, State from service.fit import Fit from service.market import Market -from eos.enum import Enum -from eos.saveddata.module import Hardpoint, Slot, Module, State -from eos.saveddata.drone import Drone -from eos.effectHandlerHelpers import HandledList -from eos.db import gamedata_session, getItemsByCategory, getCategory, getAttributeInfo, getGroup -from eos.gamedata import Category, Group, Item, Traits, Attribute, Effect, ItemEffect -from logbook import Logger + pyfalog = Logger(__name__) diff --git a/service/prereqsCheck.py b/service/prereqsCheck.py index f0e064796..60c258d0e 100644 --- a/service/prereqsCheck.py +++ b/service/prereqsCheck.py @@ -1,7 +1,6 @@ -import sys -import inspect -import re import platform +import re +import sys version_block = '' diff --git a/service/price.py b/service/price.py index 2b8cd474b..fed4b3eb2 100644 --- a/service/price.py +++ b/service/price.py @@ -18,18 +18,17 @@ # ============================================================================= -import time -import threading import queue -from xml.dom import minidom +import threading +import time -from logbook import Logger import wx +from logbook import Logger from eos import db -from service.network import Network, TimeoutError from service.fit import Fit from service.market import Market +from service.network import TimeoutError pyfalog = Logger(__name__) @@ -235,4 +234,3 @@ class PriceWorkerThread(threading.Thread): self.wait[x.typeID].append(callback) -from service.marketSources import evemarketer, evemarketdata # noqa: E402 diff --git a/service/update.py b/service/update.py index 246b520fd..a2f4cf730 100644 --- a/service/update.py +++ b/service/update.py @@ -17,21 +17,19 @@ # along with pyfa. If not, see . # ============================================================================= -import threading -import json import calendar +import threading -# noinspection PyPackageRequirements -import wx # noinspection PyPackageRequirements import dateutil.parser +# noinspection PyPackageRequirements +import wx +from logbook import Logger +from packaging.version import Version import config from service.network import Network from service.settings import UpdateSettings -from logbook import Logger -from packaging.version import Version - pyfalog = Logger(__name__) diff --git a/tests/test_locale/file_dialog.py b/tests/test_locale/file_dialog.py index 357037265..f72dccf8c 100644 --- a/tests/test_locale/file_dialog.py +++ b/tests/test_locale/file_dialog.py @@ -1,9 +1,9 @@ # noinspection PyPackageRequirements -import wx -import sys import os import sys +import wx + script_dir = os.path.dirname(os.path.abspath(__file__)) # Add root to python paths, this allows us to import submodules sys.path.append(os.path.realpath(os.path.join(script_dir, '..', '..'))) diff --git a/tests/test_modules/test_eos/test_gamedata.py b/tests/test_modules/test_eos/test_gamedata.py index 4a8674339..73aac3945 100644 --- a/tests/test_modules/test_eos/test_gamedata.py +++ b/tests/test_modules/test_eos/test_gamedata.py @@ -6,8 +6,6 @@ script_dir = os.path.dirname(os.path.abspath(__file__)) sys.path.append(os.path.realpath(os.path.join(script_dir, '..', '..', '..'))) # noinspection PyPackageRequirements -from _development.helpers import DBInMemory as DB, Gamedata, Saveddata -from _development.helpers_fits import RifterFit, KeepstarFit def test_race(DB, RifterFit, KeepstarFit): """ diff --git a/tests/test_modules/test_eos/test_modifiedAttributeDict.py b/tests/test_modules/test_eos/test_modifiedAttributeDict.py index 649cfaee8..71bc5d892 100644 --- a/tests/test_modules/test_eos/test_modifiedAttributeDict.py +++ b/tests/test_modules/test_eos/test_modifiedAttributeDict.py @@ -9,8 +9,6 @@ print(script_dir) sys.path.append(script_dir) # noinspection PyPackageRequirements -from _development.helpers import DBInMemory as DB, Gamedata, Saveddata -from _development.helpers_fits import RifterFit def test_multiply_stacking_penalties(DB, Saveddata, RifterFit): """ diff --git a/tests/test_modules/test_eos/test_saveddata/test_booster.py b/tests/test_modules/test_eos/test_saveddata/test_booster.py index 05576c3fc..11df6280d 100644 --- a/tests/test_modules/test_eos/test_saveddata/test_booster.py +++ b/tests/test_modules/test_eos/test_saveddata/test_booster.py @@ -7,9 +7,6 @@ script_dir = os.path.dirname(os.path.abspath(__file__)) sys.path.append(os.path.realpath(os.path.join(script_dir, '..', '..', '..', '..'))) # noinspection PyPackageRequirements -from _development.helpers import DBInMemory as DB, Gamedata, Saveddata -from _development.helpers_fits import RifterFit, KeepstarFit -from _development.helpers_items import StrongBluePillBooster def test_itemModifiedAttributes(DB, StrongBluePillBooster): diff --git a/tests/test_modules/test_eos/test_saveddata/test_fit_2.py b/tests/test_modules/test_eos/test_saveddata/test_fit_2.py index e60d43088..894a3e103 100644 --- a/tests/test_modules/test_eos/test_saveddata/test_fit_2.py +++ b/tests/test_modules/test_eos/test_saveddata/test_fit_2.py @@ -4,14 +4,11 @@ # This must be done on every test in order to pass in Travis import os import sys -from copy import deepcopy script_dir = os.path.dirname(os.path.abspath(__file__)) sys.path.append(os.path.realpath(os.path.join(script_dir, '..', '..', '..', '..'))) # noinspection PyPackageRequirements -from _development.helpers import DBInMemory as DB, Gamedata, Saveddata -from _development.helpers_fits import RifterFit, KeepstarFit, HeronFit def test_calculateModifiedAttributes(DB, RifterFit, KeepstarFit): diff --git a/tests/test_modules/test_service/test_fit.py b/tests/test_modules/test_service/test_fit.py index b110dd2da..18f5a9e52 100644 --- a/tests/test_modules/test_service/test_fit.py +++ b/tests/test_modules/test_service/test_fit.py @@ -6,9 +6,7 @@ script_dir = os.path.dirname(os.path.abspath(__file__)) sys.path.append(os.path.realpath(os.path.join(script_dir, '..', '..', '..'))) # noinspection PyPackageRequirements -from _development.helpers import DBInMemory as DB, Gamedata, Saveddata # noinspection PyPackageRequirements -from _development.helpers_fits import RifterFit, KeepstarFit from service.fit import Fit From 5850026aa990d56656341a8733bde6bea2692869 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sun, 16 Sep 2018 01:09:55 -0400 Subject: [PATCH 93/95] docstring fixes --- eos/effects/modulebonuswarfarelinkarmor.py | 4 ++-- eos/modifiedAttributeDict.py | 4 ++-- gui/builtinViews/fittingView.py | 6 +++--- scripts/itemDiff.py | 4 ++-- scripts/sdeReadIcons.py | 4 ++-- service/esiAccess.py | 4 ++-- utils/strfunctions.py | 4 ++-- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/eos/effects/modulebonuswarfarelinkarmor.py b/eos/effects/modulebonuswarfarelinkarmor.py index be5843988..c7cf29ce3 100644 --- a/eos/effects/modulebonuswarfarelinkarmor.py +++ b/eos/effects/modulebonuswarfarelinkarmor.py @@ -3,14 +3,14 @@ # Used by: # Variations of module: Armor Command Burst I (2 of 2) -''' +""" Some documentation: When the fit is calculated, we gather up all the gang effects and stick them onto the fit. We don't run the actual effect yet, only give the fit details so that it can run the effect at a later time. We need to do this so that we can only run the strongest effect. When we are done, one of the last things that we do with the fit is to loop through those bonuses and actually run the effect. To do this, we have a special argument passed into the effect handler that tells it which warfareBuffID to run (shouldn't need this right now, but better safe than sorry) -''' +""" type = "active", "gang" diff --git a/eos/modifiedAttributeDict.py b/eos/modifiedAttributeDict.py index 06d348b81..245087dcf 100644 --- a/eos/modifiedAttributeDict.py +++ b/eos/modifiedAttributeDict.py @@ -34,10 +34,10 @@ class ItemAttrShortcut(object): return return_value or default def getBaseAttrValue(self, key, default=0): - ''' + """ Gets base value in this order: Mutated value > override value > attribute value - ''' + """ return_value = self.itemModifiedAttributes.getOriginal(key) return return_value or default diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index 5eda0eadc..fe9b73358 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -358,9 +358,9 @@ class FittingView(d.Display): self.parent.SetPageTextIcon(pageIndex, text, bitmap) def appendItem(self, event): - ''' + """ Adds items that are double clicks from the market browser. We handle both modules and ammo - ''' + """ if not self: event.Skip() return @@ -387,7 +387,7 @@ class FittingView(d.Display): event.Skip() def removeItem(self, event): - '''Double Left Click - remove module''' + """Double Left Click - remove module""" if event.CmdDown(): return row, _ = self.HitTest(event.Position) diff --git a/scripts/itemDiff.py b/scripts/itemDiff.py index 42f31561a..e03f259d6 100755 --- a/scripts/itemDiff.py +++ b/scripts/itemDiff.py @@ -19,11 +19,11 @@ #=============================================================================== -''' +""" This script is used to compare two different database versions. It shows removed/changed/new items with list of changed effects, changed attributes and effects which were renamed -''' +""" import argparse import os.path diff --git a/scripts/sdeReadIcons.py b/scripts/sdeReadIcons.py index 66010a53c..d099f6bd5 100644 --- a/scripts/sdeReadIcons.py +++ b/scripts/sdeReadIcons.py @@ -1,8 +1,8 @@ -''' +""" A change to EVE Online's cache format rendered Reverence unable to correctly dump the icons file. As a stop gap, this reads the offical SDE iconIDs.yaml and populates our own icons.json file. This files should then be transferred to the other JSON files Phobos dumps before being converted to SQL -''' +""" import yaml import json diff --git a/service/esiAccess.py b/service/esiAccess.py index bbddc6384..905252b74 100644 --- a/service/esiAccess.py +++ b/service/esiAccess.py @@ -1,4 +1,4 @@ -''' +""" A lot of the inspiration (and straight up code copying!) for this class comes from EsiPy Much of the credit goes to the maintainer of that package, Kyria . The reasoning for no @@ -7,7 +7,7 @@ low level. Eventually I'll rewrite this to be a bit cleaner and a bit more generic, but for now, it works! -''' +""" # noinspection PyPackageRequirements from logbook import Logger diff --git a/utils/strfunctions.py b/utils/strfunctions.py index 8532d9c18..833277d17 100644 --- a/utils/strfunctions.py +++ b/utils/strfunctions.py @@ -1,6 +1,6 @@ -''' +""" string manipulation module -''' +""" import re From 31c3101d6d7af4b86c77a8e195ccdd4d9d8d8398 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sun, 16 Sep 2018 01:11:16 -0400 Subject: [PATCH 94/95] Remove redundant parenthesis --- _development/helpers.py | 4 ++-- dist_assets/win/dist.py | 2 +- eos/gamedata.py | 8 ++++---- eos/modifiedAttributeDict.py | 2 +- eos/saveddata/module.py | 2 +- eos/saveddata/ship.py | 2 +- gui/builtinContextMenus/boosterSideEffects.py | 2 +- gui/builtinContextMenus/mutaplasmids.py | 2 +- gui/builtinStatsViews/priceViewFull.py | 10 +++++----- gui/builtinStatsViews/priceViewMinimal.py | 10 +++++----- gui/chrome_tabs.py | 4 ++-- gui/esiFittings.py | 4 ++-- scripts/effectUsedBy.py | 2 +- scripts/icons_update.py | 2 +- scripts/jsonToSql.py | 4 ++-- service/attribute.py | 4 ++-- service/character.py | 2 +- service/esi.py | 2 +- service/esiAccess.py | 8 ++++---- service/fit.py | 2 +- service/fitDeprecated.py | 2 +- service/port/efs.py | 4 ++-- service/prereqsCheck.py | 2 +- tests/test_unread_desc.py | 4 ++-- 24 files changed, 45 insertions(+), 45 deletions(-) diff --git a/_development/helpers.py b/_development/helpers.py index 8af8f9733..ad1447371 100644 --- a/_development/helpers.py +++ b/_development/helpers.py @@ -100,8 +100,8 @@ def DBInMemory(): import eos.db # Output debug info to help us troubleshoot Travis - print((eos.db.saveddata_engine)) - print((eos.db.gamedata_engine)) + print(eos.db.saveddata_engine) + print(eos.db.gamedata_engine) helper = { 'config': eos.config, diff --git a/dist_assets/win/dist.py b/dist_assets/win/dist.py index a34ed3140..ec6da3928 100644 --- a/dist_assets/win/dist.py +++ b/dist_assets/win/dist.py @@ -38,7 +38,7 @@ call([ iscc, os.path.join(os.getcwd(), "dist_assets", "win", "pyfa-setup.iss"), "/dMyAppVersion=%s" % (config['version']), - "/dMyAppExpansion=%s" % (expansion), + "/dMyAppExpansion=%s" % expansion, "/dMyAppDir=%s" % source, "/dMyOutputDir=%s" % os.path.join(os.getcwd(), "dist"), "/dMyOutputFile=%s" % fileName]) # stdout=devnull, stderr=devnull diff --git a/eos/gamedata.py b/eos/gamedata.py index 0fc9482e2..9c14f23ac 100644 --- a/eos/gamedata.py +++ b/eos/gamedata.py @@ -166,14 +166,14 @@ class Effect(EqBase): t = t if isinstance(t, tuple) or t is None else (t,) self.__type = t - except (ImportError) as e: + except ImportError as e: # Effect probably doesn't exist, so create a dummy effect and flag it with a warning. self.__handler = effectDummy self.__runTime = "normal" self.__activeByDefault = True self.__type = None pyfalog.debug("ImportError generating handler: {0}", e) - except (AttributeError) as e: + except AttributeError as e: # Effect probably exists but there is an issue with it. Turn it into a dummy effect so we can continue, but flag it with an error. self.__handler = effectDummy self.__runTime = "normal" @@ -630,8 +630,8 @@ class Unit(EqBase): def attributeIDCallback(v): v = int(v) if not v: # some attributes come through with a value of 0? See #1387 - return "%d" % (v) - attribute = eos.db.getAttributeInfo(v, eager=("unit")) + return "%d" % v + attribute = eos.db.getAttributeInfo(v, eager="unit") return "%s (%d)" % (attribute.name.capitalize(), v) def TranslateValue(self, value): diff --git a/eos/modifiedAttributeDict.py b/eos/modifiedAttributeDict.py index 245087dcf..d660dd38b 100644 --- a/eos/modifiedAttributeDict.py +++ b/eos/modifiedAttributeDict.py @@ -382,7 +382,7 @@ class ModifiedAttributeDict(collections.MutableMapping): if resist: afflictPenal += "r" - self.__afflict(attributeName, "%s*" % (afflictPenal), multiplier, multiplier != 1) + self.__afflict(attributeName, "%s*" % afflictPenal, multiplier, multiplier != 1) def boost(self, attributeName, boostFactor, skill=None, *args, **kwargs): """Boost value by some percentage""" diff --git a/eos/saveddata/module.py b/eos/saveddata/module.py index 3bb92dcf4..57aacf101 100644 --- a/eos/saveddata/module.py +++ b/eos/saveddata/module.py @@ -649,7 +649,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): for i in range(5): itemChargeGroup = self.getModifiedItemAttr('chargeGroup' + str(i), None) if itemChargeGroup is not None: - g = eos.db.getGroup(int(itemChargeGroup), eager=("items.attributes")) + g = eos.db.getGroup(int(itemChargeGroup), eager="items.attributes") if g is None: continue for singleItem in g.items: diff --git a/eos/saveddata/ship.py b/eos/saveddata/ship.py index 1e1dd30d6..a7cbc15b7 100644 --- a/eos/saveddata/ship.py +++ b/eos/saveddata/ship.py @@ -131,7 +131,7 @@ class Ship(ItemAttrShortcut, HandledItem): return None items = [] - g = eos.db.getGroup("Ship Modifiers", eager=("items.attributes")) + g = eos.db.getGroup("Ship Modifiers", eager="items.attributes") for item in g.items: # Rely on name detection because race is not reliable if item.name.lower().startswith(self.item.name.lower()): diff --git a/gui/builtinContextMenus/boosterSideEffects.py b/gui/builtinContextMenus/boosterSideEffects.py index eb162c3e7..d6dbc38c6 100644 --- a/gui/builtinContextMenus/boosterSideEffects.py +++ b/gui/builtinContextMenus/boosterSideEffects.py @@ -16,7 +16,7 @@ class BoosterSideEffect(ContextMenu): # if not self.settings.get('fighterAbilities'): # return False - if self.mainFrame.getActiveFit() is None or srcContext not in ("boosterItem"): + if self.mainFrame.getActiveFit() is None or srcContext not in "boosterItem": return False self.booster = selection[0] diff --git a/gui/builtinContextMenus/mutaplasmids.py b/gui/builtinContextMenus/mutaplasmids.py index 253cdac60..98656b840 100644 --- a/gui/builtinContextMenus/mutaplasmids.py +++ b/gui/builtinContextMenus/mutaplasmids.py @@ -18,7 +18,7 @@ class MutaplasmidCM(ContextMenu): # if not self.settings.get('ammoPattern'): # return False - if srcContext not in ("fittingModule") or self.mainFrame.getActiveFit() is None: + if srcContext not in "fittingModule" or self.mainFrame.getActiveFit() is None: return False mod = selection[0] diff --git a/gui/builtinStatsViews/priceViewFull.py b/gui/builtinStatsViews/priceViewFull.py index 9eb03ea22..767ad958f 100644 --- a/gui/builtinStatsViews/priceViewFull.py +++ b/gui/builtinStatsViews/priceViewFull.py @@ -129,15 +129,15 @@ class PriceViewFull(StatsView): total_price = 0 - if (self.settings.get("ship")): + if self.settings.get("ship"): total_price += ship_price - if (self.settings.get("modules")): + if self.settings.get("modules"): total_price += module_price - if (self.settings.get("drones")): + if self.settings.get("drones"): total_price += drone_price + fighter_price - if (self.settings.get("cargo")): + if self.settings.get("cargo"): total_price += cargo_price - if (self.settings.get("character")): + if self.settings.get("character"): total_price += booster_price + implant_price self.labelPriceShip.SetLabel("%s ISK" % formatAmount(ship_price, 3, 3, 9, currency=True)) diff --git a/gui/builtinStatsViews/priceViewMinimal.py b/gui/builtinStatsViews/priceViewMinimal.py index ec1d5357f..8d6a5ce83 100644 --- a/gui/builtinStatsViews/priceViewMinimal.py +++ b/gui/builtinStatsViews/priceViewMinimal.py @@ -125,15 +125,15 @@ class PriceViewMinimal(StatsView): total_price = 0 - if (self.settings.get("ship")): + if self.settings.get("ship"): total_price += ship_price - if (self.settings.get("modules")): + if self.settings.get("modules"): total_price += module_price - if (self.settings.get("drones")): + if self.settings.get("drones"): total_price += drone_price + fighter_price - if (self.settings.get("cargo")): + if self.settings.get("cargo"): total_price += cargo_price - if (self.settings.get("character")): + if self.settings.get("character"): total_price += booster_price + implant_price self.labelPriceShip.SetLabel("%s ISK" % formatAmount(ship_price, 3, 3, 9, currency=True)) diff --git a/gui/chrome_tabs.py b/gui/chrome_tabs.py index 95d79415d..b50073565 100644 --- a/gui/chrome_tabs.py +++ b/gui/chrome_tabs.py @@ -30,7 +30,7 @@ PageAdded, EVT_NOTEBOOK_PAGE_ADDED = wx.lib.newevent.NewEvent() PageClosed, EVT_NOTEBOOK_PAGE_CLOSED = wx.lib.newevent.NewEvent() -class VetoAble(): +class VetoAble: def __init__(self): self.__vetoed = False @@ -41,7 +41,7 @@ class VetoAble(): return self.__vetoed -class NotebookTabChangeEvent(): +class NotebookTabChangeEvent: def __init__(self, old, new): self.__old = old self.__new = new diff --git a/gui/esiFittings.py b/gui/esiFittings.py index c471a1334..20fc2ed74 100644 --- a/gui/esiFittings.py +++ b/gui/esiFittings.py @@ -319,7 +319,7 @@ class SsoCharacterMgmt(wx.Dialog): self.Centre(wx.BOTH) def ssoLogin(self, event): - if (self): + if self: # todo: these events don't unbind properly when window is closed (?), hence the `if`. Figure out better way of doing this. self.popCharList() event.Skip() @@ -384,7 +384,7 @@ class FittingsTreeView(wx.Panel): dict = {} fits = data for fit in fits: - if (fit['fitting_id'] in sEsi.fittings_deleted): + if fit['fitting_id'] in sEsi.fittings_deleted: continue ship = getItem(fit['ship_type_id']) if ship is None: diff --git a/scripts/effectUsedBy.py b/scripts/effectUsedBy.py index dc231c61c..aa5f878b3 100755 --- a/scripts/effectUsedBy.py +++ b/scripts/effectUsedBy.py @@ -410,7 +410,7 @@ else: if not effect_file.startswith('__'): file_name, file_extension = effect_file.rsplit('.', 1) # Ignore non-py files and exclude implementation-specific 'effects' - if file_extension == "py" and not file_name in ("__init__"): + if file_extension == "py" and not file_name in "__init__": effect_list.append(file_name) # Stage 2 diff --git a/scripts/icons_update.py b/scripts/icons_update.py index 663d168b9..73813c505 100644 --- a/scripts/icons_update.py +++ b/scripts/icons_update.py @@ -65,7 +65,7 @@ graphics = graphicIDsLoader.load(os.path.join(to_path, 'graphicIDs.fsdbinary')) graphics_py_ob = {} for x, v in graphics.items(): - if (hasattr(v, 'iconFolder')): + if hasattr(v, 'iconFolder'): graphics_py_ob[x] = v.iconFolder # Add children to market group list diff --git a/scripts/jsonToSql.py b/scripts/jsonToSql.py index eb3ea6cdc..24492637a 100755 --- a/scripts/jsonToSql.py +++ b/scripts/jsonToSql.py @@ -239,7 +239,7 @@ def main(db, json_path): row['iconFile'] = row['iconFile'].lower().replace('modules/', '').replace('.png', '') if jsonName is 'clonegrades': - if (row['alphaCloneID'] not in tmp): + if row['alphaCloneID'] not in tmp: cloneParent = eos.gamedata.AlphaClone() setattr(cloneParent, 'alphaCloneID', row['alphaCloneID']) setattr(cloneParent, 'alphaCloneName', row['alphaCloneName']) @@ -247,7 +247,7 @@ def main(db, json_path): tmp.append(row['alphaCloneID']) for k, v in row.items(): - if (isinstance(v, str)): + if isinstance(v, str): v = v.strip() setattr(instance, fieldMap.get(k, k), v) diff --git a/service/attribute.py b/service/attribute.py index b4c3453e9..b5ebcae66 100644 --- a/service/attribute.py +++ b/service/attribute.py @@ -33,10 +33,10 @@ class Attribute(object): @staticmethod def getAttributeInfo(identity): if isinstance(identity, (int, str)): - info = eos.db.getAttributeInfo(identity, eager=("unit")) + info = eos.db.getAttributeInfo(identity, eager="unit") elif isinstance(identity, (int, float)): id_ = int(identity) - info = eos.db.getAttributeInfo(id_, eager=("unit")) + info = eos.db.getAttributeInfo(id_, eager="unit") else: info = None return info diff --git a/service/character.py b/service/character.py index 2ff03de67..565d7d329 100644 --- a/service/character.py +++ b/service/character.py @@ -337,7 +337,7 @@ class Character(object): @staticmethod def getApiDetails(charID): # todo: fix this (or get rid of?) - return ("", "", "", []) + return "", "", "", [] char = eos.db.getCharacter(charID) if char.chars is not None: chars = json.loads(char.chars) diff --git a/service/esi.py b/service/esi.py index 4b5f8198f..7b5247bec 100644 --- a/service/esi.py +++ b/service/esi.py @@ -138,7 +138,7 @@ class Esi(EsiAccess): def handleLogin(self, message): # we already have authenticated stuff for the auto mode - if (self.settings.get('ssoMode') == SsoMode.AUTO): + if self.settings.get('ssoMode') == SsoMode.AUTO: ssoInfo = message['SSOInfo'][0] auth_response = json.loads(base64.b64decode(ssoInfo)) else: diff --git a/service/esiAccess.py b/service/esiAccess.py index 905252b74..db1931fa2 100644 --- a/service/esiAccess.py +++ b/service/esiAccess.py @@ -63,7 +63,7 @@ class APIException(Exception): elif 'message' in self.response: return 'HTTP Error %s: %s' % (self.status_code, self.response['message']) - return 'HTTP Error %s' % (self.status_code) + return 'HTTP Error %s' % self.status_code class ESIEndpoints(Enum): @@ -89,7 +89,7 @@ class EsiAccess(object): @property def sso_url(self): - if (self.settings.get("ssoMode") == SsoMode.CUSTOM): + if self.settings.get("ssoMode") == SsoMode.CUSTOM: return "https://login.eveonline.com" return "https://www.pyfa.io" @@ -136,7 +136,7 @@ class EsiAccess(object): def getLoginURI(self, redirect=None): self.state = str(uuid.uuid4()) - if (self.settings.get("ssoMode") == SsoMode.AUTO): + if self.settings.get("ssoMode") == SsoMode.AUTO: args = { 'state': self.state, 'pyfa_version': config.version, @@ -256,7 +256,7 @@ class EsiAccess(object): self._session.headers.update(self.get_oauth_header(ssoChar.accessToken)) def _after_request(self, resp): - if ("warning" in resp.headers): + if "warning" in resp.headers: pyfalog.warn("{} - {}".format(resp.headers["warning"], resp.url)) if resp.status_code >= 400: diff --git a/service/fit.py b/service/fit.py index d3ac0f9d8..d830dda3e 100644 --- a/service/fit.py +++ b/service/fit.py @@ -42,7 +42,7 @@ from utils.deprecated import deprecated pyfalog = Logger(__name__) -class DeferRecalc(): +class DeferRecalc: def __init__(self, fitID): self.fitID = fitID self.sFit = Fit.getInstance() diff --git a/service/fitDeprecated.py b/service/fitDeprecated.py index c145b858c..531191b9d 100644 --- a/service/fitDeprecated.py +++ b/service/fitDeprecated.py @@ -458,7 +458,7 @@ class FitDeprecated(object): if m.isValidState(State.ACTIVE): m.state = State.ACTIVE - if (recalc): + if recalc: # 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 diff --git a/service/port/efs.py b/service/port/efs.py index b3342fb8f..4420adc90 100755 --- a/service/port/efs.py +++ b/service/port/efs.py @@ -26,7 +26,7 @@ class RigSize(Enum): CAPITAL = 4 -class EfsPort(): +class EfsPort: wepTestSet = {} version = 0.01 @@ -497,7 +497,7 @@ class EfsPort(): # Since the effect modules are fairly opaque a mock test fit is used to test the impact of traits. # standin class used to prevent . notation causing issues when used as an arg - class standin(): + class standin: pass tf = standin() tf.modules = HandledList(turrets + launchers) diff --git a/service/prereqsCheck.py b/service/prereqsCheck.py index 60c258d0e..159468591 100644 --- a/service/prereqsCheck.py +++ b/service/prereqsCheck.py @@ -9,7 +9,7 @@ class PreCheckException(Exception): pass -class PreCheckMessage(): +class PreCheckMessage: def __init__(self, msg): # wx may not be installed, in which case print to console. For all other prechecks, should pop up a MessageDialog try: diff --git a/tests/test_unread_desc.py b/tests/test_unread_desc.py index 5fc54fd14..824475d4f 100644 --- a/tests/test_unread_desc.py +++ b/tests/test_unread_desc.py @@ -64,8 +64,8 @@ def print_db_info(): import eos print() print("------------ data base connection info ------------") - print((eos.db.saveddata_engine)) - print((eos.db.gamedata_engine)) + print(eos.db.saveddata_engine) + print(eos.db.gamedata_engine) print() From f598e8e3c2299349937ab0b8832444c4249d0e91 Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Wed, 19 Sep 2018 04:51:14 +0300 Subject: [PATCH 95/95] Fix couple of price-related bugs --- gui/builtinViewColumns/price.py | 9 ++++++--- service/price.py | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/gui/builtinViewColumns/price.py b/gui/builtinViewColumns/price.py index ad99b8fb3..a68614b83 100644 --- a/gui/builtinViewColumns/price.py +++ b/gui/builtinViewColumns/price.py @@ -50,10 +50,13 @@ class Price(ViewColumn): if not price or not price.isValid: return False - if isinstance(stuff, Drone) or isinstance(stuff, Cargo): - price.price *= stuff.amount + # Fetch actual price as float to not modify its value on Price object + price = price.price - return formatAmount(price.price, 3, 3, 9, currency=True) + if isinstance(stuff, Drone) or isinstance(stuff, Cargo): + price *= stuff.amount + + return formatAmount(price, 3, 3, 9, currency=True) def delayedText(self, mod, display, colItem): sPrice = ServicePrice.getInstance() diff --git a/service/price.py b/service/price.py index fed4b3eb2..ebefe15a1 100644 --- a/service/price.py +++ b/service/price.py @@ -234,3 +234,5 @@ class PriceWorkerThread(threading.Thread): self.wait[x.typeID].append(callback) +# Import market sources only to initialize price source modules, they register on their own +from .marketSources import *