From f42fd1de43d2d8e2c30bed51bba5fa0f0817ce9a Mon Sep 17 00:00:00 2001 From: blitzmann Date: Mon, 10 Mar 2014 18:49:25 -0400 Subject: [PATCH 01/19] Tweaks to about box, including adding my name as developer --- gui/aboutData.py | 13 ++++++++++--- gui/mainFrame.py | 10 +++++----- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/gui/aboutData.py b/gui/aboutData.py index 0d1b029b5..29ed93be6 100644 --- a/gui/aboutData.py +++ b/gui/aboutData.py @@ -21,6 +21,13 @@ import config versionString = "{0} {1} - {2} {3}".format(config.version, config.tag, config.expansionName, config.expansionVersion) license = "pyfa is released under GNU GPLv3" licenseLocation = "gpl.txt" -developers = ("\n cncfanatics \t(Sakari Orisi)\n" , " DarkPhoenix \t(Kadesh Priestess)\n", " Darriele \t(Darriele)") -credits = (("Entity (Entity) \t\tCapacitor calculations / EVEAPI python lib / Reverence"), ("Aurora \t\tMaths"), ("Corollax (Aamrr) \tVarious EOS/pyfa improvements")) -description = "Pyfa (the Python Fitting Assistant) is a standalone application able to create and simulate fittings for EVE-Online SciFi MMORPG with a very high degree of accuracy.\nPyfa can be virtually ran on all platforms where python and wxwidgets are supported.\n\n\nAll EVE-Online related materials are property of CCP hf.\n\nSilk Icons Set by famfamfam.com released under Creative Commons Attribution 2.5 License\n\nFat Cow Icons by fatcow.com released under Creative Commons Attribution 3.0 License" +developers = ("cncfanatics \t(Sakari Orisi)" , "DarkPhoenix \t(Kadesh Priestess)", "Darriele \t(Darriele)", "blitzmann \t(Sable Blitzmann)") +credits = ("Entity (Entity) \t\tCapacitor calculations / EVEAPI python lib / Reverence", "Aurora \t\t\tMaths", "Corollax (Aamrr) \tVarious EOS / pyfa improvements") +description = ( + "Pyfa (the Python Fitting Assistant) is an open-source standalone application able to " + "create and simulate fittings for EVE-Online SciFi MMORPG with a very high degree of " + "accuracy. Pyfa can run on all platforms where Python and wxWidgets are supported.\n\n" + "All EVE-Online related materials are property of CCP hf.\n" + "Silk Icons Set by famfamfam.com released under Creative Commons Attribution 2.5 License\n" + "Fat Cow Icons by fatcow.com released under Creative Commons Attribution 3.0 License" +) diff --git a/gui/mainFrame.py b/gui/mainFrame.py index 2d04cb94d..96f4e54e2 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -243,11 +243,11 @@ class MainFrame(wx.Frame): info = wx.AboutDialogInfo() info.Name = "pyfa" info.Version = gui.aboutData.versionString - info.Description = wordwrap(gui.aboutData.description + "\n\n\nDevelopers: " + - "".join(gui.aboutData.developers) + - "\n\nAdditional credits:\n " + - "\n ".join(gui.aboutData.credits) - + "\n\nLicense: " + + info.Description = wordwrap(gui.aboutData.description + "\n\nDevelopers:\n\t" + + "\n\t".join(gui.aboutData.developers) + + "\n\nAdditional credits:\n\t" + + "\n\t".join(gui.aboutData.credits) + + "\n\nLicense:\n\t" + gui.aboutData.license + " - see included " + gui.aboutData.licenseLocation + From 4bcb368d174b08770f7c4a6ee53f3f4fe285bb68 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Tue, 11 Mar 2014 21:49:50 -0400 Subject: [PATCH 02/19] More about box changes --- gui/aboutData.py | 15 ++++++++------- gui/mainFrame.py | 6 ++---- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/gui/aboutData.py b/gui/aboutData.py index 29ed93be6..69fa96d51 100644 --- a/gui/aboutData.py +++ b/gui/aboutData.py @@ -19,15 +19,16 @@ import config versionString = "{0} {1} - {2} {3}".format(config.version, config.tag, config.expansionName, config.expansionVersion) -license = "pyfa is released under GNU GPLv3" -licenseLocation = "gpl.txt" -developers = ("cncfanatics \t(Sakari Orisi)" , "DarkPhoenix \t(Kadesh Priestess)", "Darriele \t(Darriele)", "blitzmann \t(Sable Blitzmann)") +licenses = ( + "pyfa is released under GNU GPLv3 - see included gpl.txt", + "All EVE-Online related materials are property of CCP hf.", + "Silk Icons Set by famfamfam.com - Creative Commons Attribution 2.5 License", + "Fat Cow Icons by fatcow.com - Creative Commons Attribution 3.0 License" +) +developers = ("blitzmann \t(Sable Blitzmann)", "cncfanatics \t(Sakari Orisi)" , "DarkPhoenix \t(Kadesh Priestess) (Project Lead)", "Darriele \t(Darriele)") credits = ("Entity (Entity) \t\tCapacitor calculations / EVEAPI python lib / Reverence", "Aurora \t\t\tMaths", "Corollax (Aamrr) \tVarious EOS / pyfa improvements") description = ( "Pyfa (the Python Fitting Assistant) is an open-source standalone application able to " "create and simulate fittings for EVE-Online SciFi MMORPG with a very high degree of " - "accuracy. Pyfa can run on all platforms where Python and wxWidgets are supported.\n\n" - "All EVE-Online related materials are property of CCP hf.\n" - "Silk Icons Set by famfamfam.com released under Creative Commons Attribution 2.5 License\n" - "Fat Cow Icons by fatcow.com released under Creative Commons Attribution 3.0 License" + "accuracy. Pyfa can run on all platforms where Python and wxWidgets are supported." ) diff --git a/gui/mainFrame.py b/gui/mainFrame.py index 96f4e54e2..2e0d778c5 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -247,10 +247,8 @@ class MainFrame(wx.Frame): "\n\t".join(gui.aboutData.developers) + "\n\nAdditional credits:\n\t" + "\n\t".join(gui.aboutData.credits) + - "\n\nLicense:\n\t" + - gui.aboutData.license + - " - see included " + - gui.aboutData.licenseLocation + + "\n\nLicenses:\n\t" + + "\n\t".join(gui.aboutData.licenses) + "\n\nPython: \t" + sys.version + "\nwxPython: \t" + wx.__version__ + "\nSQLAlchemy: \t" + sqlalchemy.__version__, From 9bbe7f7fb023caf1f4683ba73598901be90f921f Mon Sep 17 00:00:00 2001 From: blitzmann Date: Mon, 31 Mar 2014 00:18:22 -0400 Subject: [PATCH 03/19] Tweak to HTML export - have ship group link to fit if only 1 fit exists --- gui/utils/exportHtml.py | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/gui/utils/exportHtml.py b/gui/utils/exportHtml.py index 049d3535a..061728fa4 100644 --- a/gui/utils/exportHtml.py +++ b/gui/utils/exportHtml.py @@ -132,20 +132,28 @@ class exportHtmlThread(threading.Thread): if len(fits) > 0: groupFits += len(fits) - # Ship group header - HTMLship = ( - '
  • \n' - '

    ' + ship.name + ' '+str(len(fits))+'

    \n' - '
      \n') - - for fit in fits: + if len(fits) == 1: if self.stopRunning: - return; + return + fit = fits[0] dnaFit = sFit.exportDna(fit[0]) - HTMLship += '
    • ' + fit[1] + '
    • \n' + HTMLgroup += ( + '
    • ' + ship.name + ": " + fit[1] + '
    • \n') + else: + # Ship group header + HTMLship = ( + '
    • \n' + '

      ' + ship.name + ' '+str(len(fits))+'

      \n' + '
        \n') - HTMLgroup += HTMLship + ('
      \n' - '
    • \n') + for fit in fits: + if self.stopRunning: + return + dnaFit = sFit.exportDna(fit[0]) + HTMLship += '
    • ' + fit[1] + '
    • \n' + + HTMLgroup += HTMLship + ('
    \n' + '
  • \n') if groupFits > 0: # Market group header HTML += ( From 23e633190952ae3c2b1785c2f3cc319c426119d6 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Thu, 3 Apr 2014 19:44:03 -0400 Subject: [PATCH 04/19] Some Mac love, and added missing accelerator for fleet pane (set as CTRL+5) --- gui/mainFrame.py | 11 ++++++++--- gui/mainMenuBar.py | 11 +---------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/gui/mainFrame.py b/gui/mainFrame.py index a1f82b15d..91c93ae2a 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -364,7 +364,7 @@ class MainFrame(wx.Frame): # Export HTML self.Bind(wx.EVT_MENU, self.exportHtml, id=menuBar.exportHtmlId) # Preference dialog - self.Bind(wx.EVT_MENU, self.showPreferenceDialog, id = menuBar.preferencesId) + self.Bind(wx.EVT_MENU, self.showPreferenceDialog, id=wx.ID_PREFERENCES) # User guide self.Bind(wx.EVT_MENU, self.goWiki, id = menuBar.wikiId) # EVE Forums @@ -384,6 +384,7 @@ class MainFrame(wx.Frame): self.additionstab2 = wx.NewId() self.additionstab3 = wx.NewId() self.additionstab4 = wx.NewId() + self.additionstab5 = wx.NewId() # Close Page self.Bind(wx.EVT_MENU, self.CloseCurrentPage, id=self.closePageId) @@ -396,6 +397,7 @@ class MainFrame(wx.Frame): self.Bind(wx.EVT_MENU, self.AdditionsTabSelect, id = self.additionstab2) self.Bind(wx.EVT_MENU, self.AdditionsTabSelect, id = self.additionstab3) self.Bind(wx.EVT_MENU, self.AdditionsTabSelect, id = self.additionstab4) + self.Bind(wx.EVT_MENU, self.AdditionsTabSelect, id = self.additionstab5) actb = [(wx.ACCEL_CTRL, ord('T'), self.addPageId), (wx.ACCEL_CMD, ord('T'), self.addPageId), @@ -416,10 +418,12 @@ class MainFrame(wx.Frame): (wx.ACCEL_CTRL, ord('2'), self.additionstab2), (wx.ACCEL_CTRL, ord('3'), self.additionstab3), (wx.ACCEL_CTRL, ord('4'), self.additionstab4), + (wx.ACCEL_CTRL, ord('5'), self.additionstab5), (wx.ACCEL_CMD, ord('1'), self.additionstab1), (wx.ACCEL_CMD, ord('2'), self.additionstab2), (wx.ACCEL_CMD, ord('3'), self.additionstab3), - (wx.ACCEL_CMD, ord('4'), self.additionstab4) + (wx.ACCEL_CMD, ord('4'), self.additionstab4), + (wx.ACCEL_CMD, ord('5'), self.additionstab5) ] atable = wx.AcceleratorTable(actb) self.SetAcceleratorTable(atable) @@ -434,7 +438,8 @@ class MainFrame(wx.Frame): selTab = 2 if event.GetId() == self.additionstab4: selTab = 3 - + if event.GetId() == self.additionstab5: + selTab = 4 if selTab is not None: self.additionsPane.notebook.SetSelection(selTab) diff --git a/gui/mainMenuBar.py b/gui/mainMenuBar.py index ffef67857..cdfa9108c 100644 --- a/gui/mainMenuBar.py +++ b/gui/mainMenuBar.py @@ -33,7 +33,6 @@ class MainMenuBar(wx.MenuBar): self.exportSkillsNeededId = wx.NewId() self.importCharacterId = wx.NewId() self.exportHtmlId = wx.NewId() - self.preferencesId = wx.NewId() self.wikiId = wx.NewId() self.forumId = wx.NewId() @@ -59,7 +58,6 @@ class MainMenuBar(wx.MenuBar): fileMenu.AppendSeparator() fileMenu.Append(wx.ID_EXIT) - # Edit menu editMenu = wx.Menu() self.Append(editMenu, "&Edit") @@ -67,7 +65,6 @@ class MainMenuBar(wx.MenuBar): #editMenu.Append(wx.ID_UNDO) #editMenu.Append(wx.ID_REDO) - copyText = "&To Clipboard" + ("\tCTRL+C" if 'wxMSW' in wx.PlatformInfo else "") pasteText = "&From Clipboard" + ("\tCTRL+V" if 'wxMSW' in wx.PlatformInfo else "") editMenu.Append(wx.ID_COPY, copyText, "Export a fit to the clipboard") @@ -89,13 +86,9 @@ class MainMenuBar(wx.MenuBar): graphFrameItem.SetBitmap(bitmapLoader.getBitmap("graphs_small", "icons")) windowMenu.AppendItem(graphFrameItem) - #======================================================================= - # DISABLED FOR RC2 Release - # - preferencesItem = wx.MenuItem(windowMenu, self.preferencesId, "Preferences\tCTRL+P") + preferencesItem = wx.MenuItem(windowMenu, wx.ID_PREFERENCES, "Preferences\tCTRL+P") preferencesItem.SetBitmap(bitmapLoader.getBitmap("preferences_small", "icons")) windowMenu.AppendItem(preferencesItem) - #======================================================================= # Help menu helpMenu = wx.Menu() @@ -108,8 +101,6 @@ class MainMenuBar(wx.MenuBar): if config.debug: helpMenu.Append( self.mainFrame.widgetInspectMenuID, "Open Widgets Inspect tool", "Open Widgets Inspect tool") - - self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) def fitChanged(self, event): From 631d97e21a854b2ae41f2672961d750e816cc49a Mon Sep 17 00:00:00 2001 From: blitzmann Date: Tue, 8 Apr 2014 12:47:29 -0400 Subject: [PATCH 05/19] Fix #71 --- gui/builtinContextMenus/moduleAmmoPicker.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gui/builtinContextMenus/moduleAmmoPicker.py b/gui/builtinContextMenus/moduleAmmoPicker.py index 6f69f90d2..7f11207cc 100644 --- a/gui/builtinContextMenus/moduleAmmoPicker.py +++ b/gui/builtinContextMenus/moduleAmmoPicker.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- from gui.contextMenu import ContextMenu import gui.mainFrame import service @@ -112,7 +113,7 @@ class ModuleAmmoPicker(ContextMenu): def addSeperator(self, m, text): id = wx.NewId() - m.Append(id, "--- %s ---" % text) + m.Append(id, u'─ %s ─' % text) m.Enable(id, False) def getSubMenu(self, context, selection, menu, i): @@ -132,6 +133,11 @@ class ModuleAmmoPicker(ContextMenu): sub = None self.charges.sort(key=self.turretSorter) for charge in self.charges: + # fix issue 71 - will probably have to change if CCP adds more Orbital ammo + if "Orbital" in charge.name: + item = self.addCharge(m, charge) + items.append(item) + continue currBase = charge.name.rsplit()[-2:] currRange = charge.getAttribute("weaponRangeMultiplier") if nameBase is None or range != currRange or nameBase != currBase: @@ -156,6 +162,7 @@ class ModuleAmmoPicker(ContextMenu): if sub is not None: self.addSeperator(sub, "More Damage") + for item in items: m.AppendItem(item) From 507c423e0993e386c5124c57240d694640769340 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Fri, 11 Apr 2014 21:44:11 -0400 Subject: [PATCH 06/19] Fix #73 --- gui/itemStats.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gui/itemStats.py b/gui/itemStats.py index 791c2eab4..6f4d1c6fa 100644 --- a/gui/itemStats.py +++ b/gui/itemStats.py @@ -26,9 +26,13 @@ import wx.lib.mixins.listctrl as listmix import wx.html from eos.types import Ship, Module, Skill, Booster, Implant, Drone from gui.utils.numberFormatter import formatAmount -from collections import OrderedDict import service +try: + from collections import OrderedDict +except ImportError: + from gui.utils.compat import OrderedDict + class ItemStatsDialog(wx.Dialog): counter = 0 def __init__(self, victim, fullContext=None, pos = wx.DefaultPosition, size = wx.DefaultSize, maximized = False): From e873f1b88e36f7199686797a2f7dffa1567a5651 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Tue, 22 Apr 2014 01:46:31 -0400 Subject: [PATCH 07/19] Include loaded charges from modules in DNA export https://forums.eveonline.com/default.aspx?g=posts&m=4498408#post4498408 --- eos/saveddata/fit.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index 446588f9e..6003fa41d 100755 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -491,18 +491,28 @@ class Fit(object): def exportDna(self): dna = str(self.shipID) mods = OrderedDict() + charges = OrderedDict() for mod in self.modules: if not mod.isEmpty: if not mod.itemID in mods: mods[mod.itemID] = 0 mods[mod.itemID] += 1 + if mod.charge: + if not mod.chargeID in charges: + charges[mod.chargeID] = 0 + # `or 1` because some charges (ie scripts) are without qty + charges[mod.chargeID] += mod.numShots or 1 + for mod in mods: dna += ":{0};{1}".format(mod, mods[mod]) for drone in self.drones: dna += ":{0};{1}".format(drone.itemID, drone.amount) + for charge in charges: + dna += ":{0};{1}".format(charge, charges[charge]) + return dna + "::" @classmethod From 08573899d3aa7c29be85246df7f7bf4d632d21d4 Mon Sep 17 00:00:00 2001 From: Ryan Holmes Date: Wed, 23 Apr 2014 00:34:54 -0400 Subject: [PATCH 08/19] Removes "res:/UI/Texture/Icons/....png" from iconFile --- eos/utils/scripts/jsonToSql.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/eos/utils/scripts/jsonToSql.py b/eos/utils/scripts/jsonToSql.py index bc4136405..c669d2fcc 100755 --- a/eos/utils/scripts/jsonToSql.py +++ b/eos/utils/scripts/jsonToSql.py @@ -99,6 +99,10 @@ if __name__ == "__main__": # We don't care about some kind of rows, filter it out if so if not isIgnored(jsonName, row): instance = tables[jsonName]() + # fix for issue 80 + if jsonName is "icons" and "res:/UI/Texture/Icons/" in str(row['iconFile']): + row['iconFile'] = row['iconFile'].replace('res:/UI/Texture/Icons/','') + row['iconFile'] = row['iconFile'].replace('.png','') for k, v in row.iteritems(): setattr(instance, fieldMap.get(k, k), v) From 943ddd3da1a715184a8d39d88c731054c62dec8d Mon Sep 17 00:00:00 2001 From: Ryan Holmes Date: Wed, 23 Apr 2014 01:14:35 -0400 Subject: [PATCH 09/19] Add loaded charges to XML export --- eos/saveddata/fit.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index 6003fa41d..f3fc4be8f 100755 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -520,7 +520,6 @@ class Fit(object): doc = xml.dom.minidom.Document() fittings = doc.createElement("fittings") doc.appendChild(fittings) - for fit in fits: fitting = doc.createElement("fitting") fitting.setAttribute("name", fit.name) @@ -531,7 +530,8 @@ class Fit(object): shipType = doc.createElement("shipType") shipType.setAttribute("value", fit.ship.item.name) fitting.appendChild(shipType) - + + charges = {} slotNum = {} for module in fit.modules: if module.isEmpty: @@ -548,6 +548,12 @@ class Fit(object): hardware.setAttribute("slot", "%s slot %d" % (slotName, slotId)) fitting.appendChild(hardware) + if module.charge: + if not module.charge.name in charges: + charges[module.charge.name] = 0 + # `or 1` because some charges (ie scripts) are without qty + charges[module.charge.name] += module.numShots or 1 + for drone in fit.drones: hardware = doc.createElement("hardware") hardware.setAttribute("qty", "%d" % drone.amount) @@ -555,6 +561,13 @@ class Fit(object): hardware.setAttribute("type", drone.item.name) fitting.appendChild(hardware) + for name, qty in charges.items(): + hardware = doc.createElement("hardware") + hardware.setAttribute("qty", "%d" % qty) + hardware.setAttribute("slot", "cargo") + hardware.setAttribute("type", name) + fitting.appendChild(hardware) + return doc.toprettyxml() @reconstructor From d9653ea43c20a30d7061b2eb6220d127493c69b7 Mon Sep 17 00:00:00 2001 From: Ryan Holmes Date: Wed, 23 Apr 2014 10:39:36 -0400 Subject: [PATCH 10/19] Redundancy --- eos/utils/scripts/jsonToSql.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/eos/utils/scripts/jsonToSql.py b/eos/utils/scripts/jsonToSql.py index c669d2fcc..01cbfeca6 100755 --- a/eos/utils/scripts/jsonToSql.py +++ b/eos/utils/scripts/jsonToSql.py @@ -101,8 +101,7 @@ if __name__ == "__main__": instance = tables[jsonName]() # fix for issue 80 if jsonName is "icons" and "res:/UI/Texture/Icons/" in str(row['iconFile']): - row['iconFile'] = row['iconFile'].replace('res:/UI/Texture/Icons/','') - row['iconFile'] = row['iconFile'].replace('.png','') + row['iconFile'] = row['iconFile'].replace('res:/UI/Texture/Icons/','').replace('.png','') for k, v in row.iteritems(): setattr(instance, fieldMap.get(k, k), v) From 1fea4e5876b8372cbde8a183eb85da4301fbf838 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Wed, 23 Apr 2014 23:30:07 -0400 Subject: [PATCH 11/19] Adds missing icons --- staticdata/icons/icon108_5.png | Bin 0 -> 756 bytes staticdata/icons/icon113_64_1.png | Bin 0 -> 3526 bytes staticdata/icons/icon113_64_2.png | Bin 0 -> 3479 bytes staticdata/icons/icon113_64_3.png | Bin 0 -> 3464 bytes staticdata/icons/icon53_64_16.png | Bin 0 -> 914 bytes staticdata/icons/icon94_64_9.png | Bin 0 -> 698 bytes staticdata/icons/iconMarketIcon_16px_Amarr.png | Bin 0 -> 662 bytes staticdata/icons/iconMarketIcon_16px_Caldari.png | Bin 0 -> 852 bytes .../icons/iconMarketIcon_16px_Gallente.png | Bin 0 -> 794 bytes .../icons/iconMarketIcon_16px_Minmatar.png | Bin 0 -> 776 bytes 10 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 staticdata/icons/icon108_5.png create mode 100644 staticdata/icons/icon113_64_1.png create mode 100644 staticdata/icons/icon113_64_2.png create mode 100644 staticdata/icons/icon113_64_3.png create mode 100644 staticdata/icons/icon53_64_16.png create mode 100644 staticdata/icons/icon94_64_9.png create mode 100644 staticdata/icons/iconMarketIcon_16px_Amarr.png create mode 100644 staticdata/icons/iconMarketIcon_16px_Caldari.png create mode 100644 staticdata/icons/iconMarketIcon_16px_Gallente.png create mode 100644 staticdata/icons/iconMarketIcon_16px_Minmatar.png diff --git a/staticdata/icons/icon108_5.png b/staticdata/icons/icon108_5.png new file mode 100644 index 0000000000000000000000000000000000000000..0b96f8ce4fc3537e08e995b360155affe16cfcfb GIT binary patch literal 756 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47@GrpLR^8||NsAg`t-CV)jHQ% zM2dkySy_3{o;`wsf`9(}$#j?9Ft3q;k+Hm@0;r52xVN?S$H%8YWq<$t2BLp||NQv= z_5GVywV@gpw@?56_V$*AeH)g~xqIXCjVl*U9X$XyFwaqN#-uJF_v_cMQ}f;8LcL1M zDk38z_ph6yuOcBPF2T>w4^e#g`UM3MHlXt%E(Z!8-n2+Y0OT(q*wB@5VBM@hV_^|) zCWy$Q2?a;CEGOM?7>(Si(E*_qhHr5L$n99*P%1h}Q0t6M!YPjBCP{K1B{nW zSUuVewBVqpi(`ny<>UkgW;ZuCyE=t~2N)i6b8vBTa~*JzkaTr9dPG&l)m1^sC+L#V zrlL<=U59D}7}Hc!MMF(Xd3|+rWj8Q%=hZkR1r>G8+thrEQ|8Xi`zGICo4NU^Wp_dr6$uq@@DQEqH|)_ z0tv^-t?T-G@yGywn$YD_W! literal 0 HcmV?d00001 diff --git a/staticdata/icons/icon113_64_1.png b/staticdata/icons/icon113_64_1.png new file mode 100644 index 0000000000000000000000000000000000000000..c54aac0313647577299c93ec327a1bde0d713552 GIT binary patch literal 3526 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 AcmMzZ literal 0 HcmV?d00001 diff --git a/staticdata/icons/icon113_64_2.png b/staticdata/icons/icon113_64_2.png new file mode 100644 index 0000000000000000000000000000000000000000..604e32b4a0f4c87fd3064bca7797dec3a9c06944 GIT binary patch literal 3479 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 DqaPw> literal 0 HcmV?d00001 diff --git a/staticdata/icons/icon94_64_9.png b/staticdata/icons/icon94_64_9.png new file mode 100644 index 0000000000000000000000000000000000000000..acd08557b8f6c9cc646a571cb1bf9f43581e0b1f GIT binary patch literal 698 zcmV;r0!96aP)K$-Bf6bZwD(8+S*aq>2qK2b3ZTeznB9M z07Q#`;$JyB+<*^&k)>wO8~5Z+Q4~89E*K7yAW!b?Xz}bX$|r-HmAXjzCH!NZAb!Gm z-f{bz5ExR&M7J6X^NG`>&qUq9NP3X^Ge>(?0R3;Dv=3X%`+O=M_1imG%|R5}3MzgG3PNC-j84U3Tg%I>S@p336I-Zq={ zVPmyvL@DME6l$|32%vt@aO%i%FA4x$%@zEVjXTq5_-cKkxW!A3n@ssJ^N(A-UHZpe zF6egT1Oo2yt|HU%S+6SPg5%DkR{s2F-m|_D|I$kajq+lX!%DVql23M9tDE=gwPY(` zFXpm!IT?~k^X}Zi+A_m%{n?X5wLZBAfN*&e`mU|QzJ|~JpiwDivRT@h2Q>DZ43+k* zb(JMRO)}7Sx$5xyXyCP8oiPf4vvdLh1m{0~(n%(#`{=LV-y|^{Pg!~C$^xrx+Z=yB zUC6Mr^06;3U${pXHq8AT2u#gRGz1pLn*eWcKNCd*SPg&zAOOpV0HoENHj-57Dgr}fP7VubAquZbKoBnU3ld(t2n(7LEC2ui07*qoM6N<$f;#s#l>h($ literal 0 HcmV?d00001 diff --git a/staticdata/icons/iconMarketIcon_16px_Amarr.png b/staticdata/icons/iconMarketIcon_16px_Amarr.png new file mode 100644 index 0000000000000000000000000000000000000000..7c8626a8e616658591d31a1ccf014714132e4856 GIT binary patch literal 662 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47_9?*LR^7dRu&c@$;QSCBw3i5 zBt-au3~o+#eqJ7a9(Fk?5iSmP8za^7G>=Wo3wLerT(M$OLcE`dh%he~o35%fNG~f> zysx2@5POcVLbQuQMwnVox@mKv!Pag|Yg5@|KTRnykeN)3jH1E#^hK40EPA z*Gm3AX$kVHy7_PU(W9bwC&`Cg{rB(5Obe^eR(k`PCH+o6s*=9x7!bs0QX(N!p}?ZV z%|D?l_7Tv^#hxyXArhC96BM`&j2tD;=p=Ma?UmI!aFBD_qesskK7A}MAR;6tD9X&) z;qBq&dHTeuliC_un#@17R%N}CniX}+YFE`Swl+5&o?~ju(w>P;3%h2vt?V0L9}kb; zIlXmx?_NsE&5OHdx37+e=O1IEo8v*ng^9Z!Ho6H;cgbUQp$;ml$&U`By zTcC)Pw5*_z5Gxy7P*~)y1ILaXKd!E>22|tW8cZP9vK}T9j~aY0u&dQkWvCOfNVH$aB|btHv)2jvc{$sKnBo2pgS$BY$3Wh zxwyQ1gQ^?bfi?yN1>b-0(8t#|AUMp^H$X&GR9jb1KtK?v3n;6iu92RR31n;Q=(&3b zsA*`iv$F$@GPAHTw*q+t4r-e^a`FnfxVV^@n1Bi-B&F;fUAefqfeL`;B&1|!7nCKX z=QudK@$&M*b#ZWTC@HHN8JlZr=>W9=Rl=o^8R1b0PhWrd@$1jFeaG#bT(8`EWM$)E zVQuf>?Qd)EY+`0*=jiI@=?e@lQwtkQ8;2!pww<|j%ihT?HM_W=w8q8VXTy)pAOjmp zg8YIR`06fxdb!1q#rWx;x1U$?i@*AJvdGJ!;PE2vX@}!>etlMC^5m~Clm4%-X?x$T z-?#VuYTm3HrZNF4!pE*E=G{<}*1C92)8*Gsr}bZ^?*4oH^;TKI<$G0^KD#qJ<@2vX zE=Gwv2R%*Q>fUcQ)VuoY@1Gs+Y*Gy;o;*0%XwJ?mu4kgmKk401pj!@lx;TbNTux3< z;4&~W+`M7a#^M7%=EU&cvDwq>Tk}U?U&De48#-3Z*x|ByiAaRQE?2iOzc|N0&q&u$ z-V@>1FI>5F?c&w!tL7QTCQMus+h@<1H8VOQse?jPQ`_Z4+SR%UNqcT=+OA1Cbg_Ty7|J3D@X623?^Nt zTzYoZJIDvf4Gal1vo#M14+&3+6cQE`5Eis^u(PnYFf}t35*F&2+ox-+7a9>NAt|9} ztmhHnsi~*w?C!$N!`(2UN!Lg>I5aq~ra(ba9%vLCh>45l)#PjHYxOUjq;IS*E-uc= z$;r;n&cn;2tfm~15~ZcD6%rm=+*oq>-`UOrymV85ueXcvE1Wp(Aa)HvS& zKY2xYO6+bh;?^l68)Fwg*Sfw2J5PH{XDeqvmztisn2fmioCLo} zf44yQ;P}w+$F|M> zx3^)!lymd9#r)md@MoTsm83=1uf4yQ2kNR@)&JPr@cZ3`aGTT5e(ycLtamL?)4%VZ z_IkeiGMibm@8!FViR#Sks?7_dl-XDXQZib_fc9?lba4!kxSX7DfJtKJjL3+aH!Ll7 z?oed1vD{g?r{)h+lhdJq#y?Gm79|M=8WwVPG^BWDMpn9}hHe!JafosY^NVu~^o(TH zS`f8(*}8=*m#$sREqdXyxq*q1nW3q1d*;RsTQ+UmxOH=R1DA!BMCjn_e`HN lY1XuP6Fc8LUh_r=nADrjXz*p-oWll+FHcuLmvv4FO#qx!AyWVV literal 0 HcmV?d00001 diff --git a/staticdata/icons/iconMarketIcon_16px_Minmatar.png b/staticdata/icons/iconMarketIcon_16px_Minmatar.png new file mode 100644 index 0000000000000000000000000000000000000000..56c17d24870bdbc473941c1086f44a5cfb54226d GIT binary patch literal 776 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47?%Y2gt!8^jEsz|EG&(Q(JQJ; z)-=`5?&*}3l>v%#aIi0FYvkwS4KX*BmXy%Y&;ToDsE!WPS5cA{63X%R@Nl%()zMLs z5YO;-V`E{Nkdh!Oz`vup=GMm5OiWBb^=z!Hl0t&jp#dx`%vy3Xj`p@;_BNV|@<6Fn zZ+9&fB@Q-L4i1jo?5w4W7y5X5T$(XSS4jaV+n=4z#lfL~cro|%a$$kNP7Uk|7eA`T>h zo`ta4*;s+%KnK93d`*m^tu1Dz#Jd~l2b-IC8tC5Gx+%ii(n&|F)ZeEsHZs%2aZ*A| zcTB{Tq`2nr;8I`DSbG~+1Kp*0nd=I&SLSCg%}UL6bM`Va@G~`@my=!{ zoo%qSRe-r^(9`GFfKH4m3GxeO;MczX^~=RXR=o$QpQabG3qRep;r{xzzE8FP=6wC- z#OS*Jd*-ZN+vjlo?5%Izae3a49m0Q;F6|b1d%t|6TS?IGa-$~(ceWWbrFFQ!`MKGh zjm1S#r+dxf9086W6?a5{w(RtDaSV~ToSdM*Wng5udBdiS#Rq=OiMeAFc+qfA%^!h% z4GC)|6vXW5$Y_#qaj`M7YI zq*+*5?l#%JW!u*B9lIKH3%`H(^6A~1SKmH<{oKAoN5MeDLd8Vq&Q1AeW#xR8|2jH6 cD%Z%dGC01{5L{K}s|1QoPgg&ebxsLQ0QB?vYXATM literal 0 HcmV?d00001 From 83c0bbe37b883ffaf21a80db55fdb4625680053a Mon Sep 17 00:00:00 2001 From: blitzmann Date: Thu, 24 Apr 2014 00:12:10 -0400 Subject: [PATCH 12/19] Fix #82 --- eos/saveddata/module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eos/saveddata/module.py b/eos/saveddata/module.py index ad4a52811..bde1a9aa6 100755 --- a/eos/saveddata/module.py +++ b/eos/saveddata/module.py @@ -569,7 +569,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): context = ("module",) projected = False - if self.charge is not None and not projected: + if self.charge is not None: for effect in self.charge.effects.itervalues(): if effect.runTime == runTime: effect.handler(fit, self, ("moduleCharge",)) From 38bd33dce48e946c6d34c2d04f1ac46e4acadd78 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Wed, 30 Apr 2014 10:44:06 -0400 Subject: [PATCH 13/19] Fix incorrect indentation which caused improper XML import processing --- eos/saveddata/fit.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index f3fc4be8f..22172b14c 100755 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -437,9 +437,7 @@ class Fit(object): f.modules.append(m) except KeyboardInterrupt: continue - - fits.append(f) - + fits.append(f) return fits @@ -530,7 +528,7 @@ class Fit(object): shipType = doc.createElement("shipType") shipType.setAttribute("value", fit.ship.item.name) fitting.appendChild(shipType) - + charges = {} slotNum = {} for module in fit.modules: From fb1323ba17f6ae1557ed077b678d995a6fd5af1d Mon Sep 17 00:00:00 2001 From: blitzmann Date: Wed, 30 Apr 2014 11:52:56 -0400 Subject: [PATCH 14/19] Fix #87 - enforce proper Item in `Ship.__init__` --- eos/saveddata/ship.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/eos/saveddata/ship.py b/eos/saveddata/ship.py index 6a0118011..05cd99c02 100755 --- a/eos/saveddata/ship.py +++ b/eos/saveddata/ship.py @@ -22,6 +22,10 @@ from eos.effectHandlerHelpers import HandledItem class Ship(ItemAttrShortcut, HandledItem): def __init__(self, item): + + if item.category.name != "Ship": + raise ValueError('Passed item "%s" (category: (%s)) is not under Ship category'%(item.name, item.category.name)) + self.__item = item self.__itemModifiedAttributes = ModifiedAttributeDict() if not isinstance(item, int): From 234af1ac3d4446c9533f20b4e1f1aaf0bdee575a Mon Sep 17 00:00:00 2001 From: blitzmann Date: Wed, 30 Apr 2014 12:57:00 -0400 Subject: [PATCH 15/19] Fix #86 - Importing EFT with cargo --- eos/saveddata/fit.py | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index 22172b14c..84a68f34f 100755 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -195,10 +195,12 @@ class Fit(object): def importEft(cls, eftString): from eos import db offineSuffix = " /OFFLINE" + fit = cls() 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() @@ -211,28 +213,46 @@ class Fit(object): fit.name = fitName except: return + + # maintain map of drones and their quantities droneMap = {} for i in range(1, len(lines)): + ammoName = None + droneAmount = None + line = lines[i].strip() if not line: continue + setOffline = line.endswith(offineSuffix) if setOffline == True: + # remove offline suffix from line line = line[:len(line) - len(offineSuffix)] + modAmmo = line.split(",") - modDrone = modAmmo[0].split(" x") - if len(modAmmo) == 2: ammoName = modAmmo[1].strip() - else: ammoName = None - modName = modDrone[0].strip() - if len(modDrone) == 2: droneAmount = modDrone[1].strip() - else: droneAmount = None + # 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 + droneAmount = 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 = db.getItem(modName, eager="group.category") - except: - try: - item = db.getItem(modAmmo[0], eager="group.category") - except: + if len(modExtra) == 2 and item.category.name != "Drone": continue + except: + # if no data can be found (old names) + continue if item.category.name == "Drone": droneAmount = int(droneAmount) if droneAmount is not None else 1 @@ -248,7 +268,9 @@ class Fit(object): continue if ammoName: try: - m.charge = db.getItem(ammoName) + ammo = db.getItem(ammoName) + if m.isValidCharge(ammo) and m.charge is None: + m.charge = ammo except: pass From a2727d5f4750a3f4fff785100fe0ec8eafabf220 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Thu, 1 May 2014 22:08:27 -0400 Subject: [PATCH 16/19] Create new Fit relationship with fits that current fit is projected onto (see #90) --- eos/db/saveddata/fit.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/eos/db/saveddata/fit.py b/eos/db/saveddata/fit.py index 25516b7b6..16dd17f6a 100755 --- a/eos/db/saveddata/fit.py +++ b/eos/db/saveddata/fit.py @@ -65,5 +65,12 @@ mapper(Fit, fits_table, primaryjoin = projectedFits_table.c.victimID == fits_table.c.ID, secondaryjoin = fits_table.c.ID == projectedFits_table.c.sourceID, secondary = projectedFits_table, + collection_class = HandledProjectedFitList), + # projectedOnto is not currently used and probably won't be + # It simply makes data clean-up easier. See GH issue #90 + "_Fit__projectedOnto" : relation(Fit, + primaryjoin = fits_table.c.ID == projectedFits_table.c.sourceID, + secondaryjoin = fits_table.c.ID == projectedFits_table.c.victimID == fits_table.c.ID, + secondary = projectedFits_table, collection_class = HandledProjectedFitList) }) From fb9da5ec8d58e6ba888ca0922602e8fec137794d Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 3 May 2014 00:40:13 -0400 Subject: [PATCH 17/19] Revert "Create new Fit relationship with fits that current fit is projected onto (see #90)" This reverts commit a2727d5f4750a3f4fff785100fe0ec8eafabf220. --- eos/db/saveddata/fit.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/eos/db/saveddata/fit.py b/eos/db/saveddata/fit.py index 16dd17f6a..25516b7b6 100755 --- a/eos/db/saveddata/fit.py +++ b/eos/db/saveddata/fit.py @@ -65,12 +65,5 @@ mapper(Fit, fits_table, primaryjoin = projectedFits_table.c.victimID == fits_table.c.ID, secondaryjoin = fits_table.c.ID == projectedFits_table.c.sourceID, secondary = projectedFits_table, - collection_class = HandledProjectedFitList), - # projectedOnto is not currently used and probably won't be - # It simply makes data clean-up easier. See GH issue #90 - "_Fit__projectedOnto" : relation(Fit, - primaryjoin = fits_table.c.ID == projectedFits_table.c.sourceID, - secondaryjoin = fits_table.c.ID == projectedFits_table.c.victimID == fits_table.c.ID, - secondary = projectedFits_table, collection_class = HandledProjectedFitList) }) From 197a61253ff603917aa06f6199cb32d50d42c3c8 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 3 May 2014 00:42:08 -0400 Subject: [PATCH 18/19] Better way to fix deletion of projection relationships --- eos/db/__init__.py | 2 +- eos/db/saveddata/queries.py | 11 ++++++++++- service/fit.py | 12 +++++++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/eos/db/__init__.py b/eos/db/__init__.py index 09a092c81..789141435 100755 --- a/eos/db/__init__.py +++ b/eos/db/__init__.py @@ -66,7 +66,7 @@ from eos.db.saveddata.queries import getUser, getCharacter, getFit, getFitsWithS getCharacterList, getPrice, getDamagePatternList, getDamagePattern, \ getFitList, getFleetList, getFleet, save, remove, commit, add, \ getCharactersForUser, getMiscData, getSquadsIDsWithFitID, getWing, \ - getSquad, getBoosterFits + getSquad, getBoosterFits, getProjectedFits #If using in memory saveddata, you'll want to reflect it so the data structure is good. if config.saveddata_connectionstring == "sqlite:///:memory:": diff --git a/eos/db/saveddata/queries.py b/eos/db/saveddata/queries.py index 01c2888ce..ddb8d53ac 100755 --- a/eos/db/saveddata/queries.py +++ b/eos/db/saveddata/queries.py @@ -21,6 +21,7 @@ from eos.db.util import processEager, processWhere from eos.db import saveddata_session, sd_lock from eos.types import User, Character, Fit, Price, DamagePattern, Fleet, MiscData, Wing, Squad from eos.db.saveddata.fleet import squadmembers_table +from eos.db.saveddata.fit import projectedFits_table from sqlalchemy.sql import and_ import eos.config @@ -360,7 +361,15 @@ def getSquadsIDsWithFitID(fitID): return squads else: raise TypeError("Need integer as argument") - + +def getProjectedFits(fitID): + if isinstance(fitID, int): + with sd_lock: + filter = and_(projectedFits_table.c.sourceID == fitID, Fit.ID == projectedFits_table.c.victimID) + fits = saveddata_session.query(Fit).filter(filter).all() + return fits + else: + raise TypeError("Need integer as argument") def add(stuff): with sd_lock: diff --git a/service/fit.py b/service/fit.py index a1dfa4cd0..7f849cb37 100644 --- a/service/fit.py +++ b/service/fit.py @@ -162,6 +162,8 @@ class Fit(object): fit = eos.db.getFit(fitID) sFlt = Fleet.getInstance() sFlt.removeAssociatedFleetData(fit) + self.removeProjectedData(fitID) + eos.db.remove(fit) def copyFit(self, fitID): @@ -177,7 +179,15 @@ class Fit(object): fit = eos.db.getFit(fitID) fit.clear() return fit - + + def removeProjectedData(self, fitID): + '''Removes projection relation from ships that have fitID as projection. See GitHub issue #90''' + fit = eos.db.getFit(fitID) + fits = eos.db.getProjectedFits(fitID) + + for projectee in fits: + projectee.projectedFits.remove(fit) + def toggleFactorReload(self, fitID): if fitID is None: return None From 2651a048802a9c53d7eb7b8423b1d24e7f2cf460 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sat, 3 May 2014 01:21:45 -0400 Subject: [PATCH 19/19] Refresh active fit upon fit deletion (deleted fit may have been projected) --- gui/builtinViews/fittingView.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index 359ed7751..bc407da4e 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -233,10 +233,23 @@ class FittingView(d.Display): event.Skip() def fitRemoved(self, event): + '''If fit is removed and active, the page is deleted. + We also refresh the fit of the new current page in case + delete fit caused change in stats (projected) + ''' fitID = event.fitID + if fitID == self.getActiveFit(): self.parent.DeletePage(self.parent.GetPageIndex(self)) - + + try: + # Sometimes there is no active page after deletion, hence the try block + cFit = service.Fit.getInstance() + cFit.refreshFit(self.getActiveFit()) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.activeFitID)) + except wx._core.PyDeadObjectError: + pass + event.Skip() def fitRenamed(self, event):