diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 000000000..2b5037ed5 --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,26 @@ +codecov: + notify: + require_ci_to_pass: yes + +coverage: + precision: 2 + round: down + range: "70...100" + + status: + project: yes + patch: yes + changes: no + +parsers: + gcov: + branch_detection: + conditional: yes + loop: yes + method: no + macro: no + +comment: + layout: "header, diff" + behavior: default + require_changes: no diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..880b12415 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,40 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Explicitly declare text files you want to always be normalized and converted +# to native line endings on checkout. +# *.c text +# *.h text + +# Declare files that will always have CRLF line endings on checkout. +# Source files +# ============ +*.pxd text eol=crlf +*.py text eol=crlf +*.py3 text eol=crlf +*.pyw text eol=crlf +*.pyx text eol=crlf + + +# Denote all files that are truly binary and should not be modified. +# Binary files +# ============ +*.db binary +*.p binary +*.pkl binary +*.pyc binary +*.pyd binary +*.pyo binary + +# Note: .db, .p, and .pkl files are associated +# with the python modules ``pickle``, ``dbm.*``, +# ``shelve``, ``marshal``, ``anydbm``, & ``bsddb`` +# (among others). + +# Denote all files that are truly binary and should not be modified. +# Image files +# ============ +*.png binary +*.jpg binary +*.icns binary +*.ico binary diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..497b67b08 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,25 @@ +language: python +python: + - '2.7' +env: + - TOXENV=pep8 +addons: + apt: + packages: + # for wxPython: + - python-wxgtk2.8 + - python-wxtools + - wx2.8-doc + - wx2.8-examples + - wx2.8-headers + - wx2.8-i18n +before_install: + - pip install -U tox +install: + - pip install -r requirements.txt + - pip install -r requirements_test.txt +script: + - tox + - py.test --cov=./ +after_success: + - bash <(curl -s https://codecov.io/bash) diff --git a/README.md b/README.md index 4f26244f4..f78438e89 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ If you wish to help with development or simply need to run pyfa through a Python * Python 2.7 * `wxPython` 2.8/3.0 -* `sqlalchemy` >= 0.6 +* `sqlalchemy` >= 1.0.5 * `dateutil` * `matplotlib` (for some Linux distributions you may need to install separate wxPython bindings such as `python-matplotlib-wx`) * `requests` diff --git a/config.py b/config.py index 0a9c1a799..aa9221023 100644 --- a/config.py +++ b/config.py @@ -31,18 +31,20 @@ gameDB = None class StreamToLogger(object): - """ - Fake file-like stream object that redirects writes to a logger instance. - From: http://www.electricmonk.nl/log/2011/08/14/redirect-stdout-and-stderr-to-a-logger-in-python/ - """ - def __init__(self, logger, log_level=logging.INFO): - self.logger = logger - self.log_level = log_level - self.linebuf = '' + """ + Fake file-like stream object that redirects writes to a logger instance. + From: http://www.electricmonk.nl/log/2011/08/14/redirect-stdout-and-stderr-to-a-logger-in-python/ + """ + + def __init__(self, logger, log_level=logging.INFO): + self.logger = logger + self.log_level = log_level + self.linebuf = '' + + def write(self, buf): + for line in buf.rstrip().splitlines(): + self.logger.log(self.log_level, line.rstrip()) - def write(self, buf): - for line in buf.rstrip().splitlines(): - self.logger.log(self.log_level, line.rstrip()) def isFrozen(): if hasattr(sys, 'frozen'): @@ -50,16 +52,12 @@ def isFrozen(): else: return False -def getPyfaRoot(): - base = getattr(sys.modules['__main__'], "__file__", sys.executable) if isFrozen() else sys.argv[0] - root = os.path.dirname(os.path.realpath(os.path.abspath(base))) - root = unicode(root, sys.getfilesystemencoding()) - return root def __createDirs(path): if not os.path.exists(path): os.makedirs(path) + def defPaths(customSavePath): global debug global pyfaPath @@ -77,32 +75,32 @@ def defPaths(customSavePath): # Python 2.X uses ANSI by default, so we need to convert the character encoding pyfaPath = getattr(configforced, "pyfaPath", pyfaPath) if pyfaPath is None: - pyfaPath = getPyfaRoot() + pyfaPath = getPyfaPath() # Where we store the saved fits etc, default is the current users home directory if saveInRoot is True: savePath = getattr(configforced, "savePath", None) if savePath is None: - savePath = os.path.join(pyfaPath, "saveddata") + savePath = getPyfaPath("saveddata") else: savePath = getattr(configforced, "savePath", None) if savePath is None: - if customSavePath is None: # customSavePath is not overriden - savePath = unicode(os.path.expanduser(os.path.join("~", ".pyfa")), - sys.getfilesystemencoding()) + if customSavePath is None: # customSavePath is not overriden + savePath = os.path.expanduser(os.path.join("~", ".pyfa")) else: savePath = customSavePath __createDirs(savePath) if isFrozen(): - os.environ["REQUESTS_CA_BUNDLE"] = os.path.join(pyfaPath, "cacert.pem") - os.environ["SSL_CERT_FILE"] = os.path.join(pyfaPath, "cacert.pem") + certName = "cacert.pem" + os.environ["REQUESTS_CA_BUNDLE"] = getPyfaPath(certName).encode('utf8') + os.environ["SSL_CERT_FILE"] = getPyfaPath(certName).encode('utf8') - format = '%(asctime)s %(name)-24s %(levelname)-8s %(message)s' - logging.basicConfig(format=format, level=logLevel) - handler = logging.handlers.RotatingFileHandler(os.path.join(savePath, "log.txt"), maxBytes=1000000, backupCount=3) - formatter = logging.Formatter(format) + loggingFormat = '%(asctime)s %(name)-24s %(levelname)-8s %(message)s' + logging.basicConfig(format=loggingFormat, level=logLevel) + handler = logging.handlers.RotatingFileHandler(getSavePath("log.txt"), maxBytes=1000000, backupCount=3) + formatter = logging.Formatter(loggingFormat) handler.setFormatter(formatter) logging.getLogger('').addHandler(handler) @@ -114,23 +112,61 @@ def defPaths(customSavePath): sys.stdout = sl # This interferes with cx_Freeze's own handling of exceptions. Find a way to fix this. - #stderr_logger = logging.getLogger('STDERR') - #sl = StreamToLogger(stderr_logger, logging.ERROR) - #sys.stderr = sl + # stderr_logger = logging.getLogger('STDERR') + # sl = StreamToLogger(stderr_logger, logging.ERROR) + # sys.stderr = sl # The database where we store all the fits etc - saveDB = os.path.join(savePath, "saveddata.db") + saveDB = getSavePath("saveddata.db") # The database where the static EVE data from the datadump is kept. # This is not the standard sqlite datadump but a modified version created by eos # maintenance script - gameDB = os.path.join(pyfaPath, "eve.db") + gameDB = getPyfaPath("eve.db") - ## DON'T MODIFY ANYTHING BELOW ## + # DON'T MODIFY ANYTHING BELOW! import eos.config - #Caching modifiers, disable all gamedata caching, its unneeded. + # Caching modifiers, disable all gamedata caching, its unneeded. eos.config.gamedataCache = False # saveddata db location modifier, shouldn't ever need to touch this eos.config.saveddata_connectionstring = "sqlite:///" + saveDB + "?check_same_thread=False" eos.config.gamedata_connectionstring = "sqlite:///" + gameDB + "?check_same_thread=False" + + +def getPyfaPath(Append=None): + base = getattr(sys.modules['__main__'], "__file__", sys.executable) if isFrozen() else sys.argv[0] + root = os.path.dirname(os.path.realpath(os.path.abspath(base))) + + if Append: + path = parsePath(root, Append) + else: + path = parsePath(root) + + return path + + +def getSavePath(Append=None): + root = savePath + + if Append: + path = parsePath(root, Append) + else: + path = parsePath(root) + + return path + + +def parsePath(root, Append=None): + if Append: + path = os.path.join(root, Append) + else: + path = root + + if type(path) == str: # leave unicode ones alone + try: + path = path.decode('utf8') + except UnicodeDecodeError: + path = path.decode('windows-1252') + + return path diff --git a/eos/config.py b/eos/config.py index 63bf7695b..01d65cfe0 100644 --- a/eos/config.py +++ b/eos/config.py @@ -4,10 +4,12 @@ from os.path import realpath, join, dirname, abspath debug = False gamedataCache = True saveddataCache = True +gamedata_version = "" gamedata_connectionstring = 'sqlite:///' + unicode(realpath(join(dirname(abspath(__file__)), "..", "eve.db")), sys.getfilesystemencoding()) saveddata_connectionstring = 'sqlite:///' + unicode( realpath(join(dirname(abspath(__file__)), "..", "saveddata", "saveddata.db")), sys.getfilesystemencoding()) + # Autodetect path, only change if the autodetection bugs out. path = dirname(unicode(__file__, sys.getfilesystemencoding())) diff --git a/eos/db/gamedata/__init__.py b/eos/db/gamedata/__init__.py index 83fe03c97..eabfd7f1b 100644 --- a/eos/db/gamedata/__init__.py +++ b/eos/db/gamedata/__init__.py @@ -1,2 +1,2 @@ __all__ = ["attribute", "category", "effect", "group", "metaData", - "icon", "item", "marketGroup", "metaGroup", "unit"] + "icon", "item", "marketGroup", "metaGroup", "unit", "alphaClones"] diff --git a/eos/db/gamedata/alphaClones.py b/eos/db/gamedata/alphaClones.py new file mode 100644 index 000000000..602f8070c --- /dev/null +++ b/eos/db/gamedata/alphaClones.py @@ -0,0 +1,46 @@ +# =============================================================================== +# Copyright (C) 2010 Diego Duclos +# +# This file is part of eos. +# +# eos is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# eos is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with eos. If not, see . +# =============================================================================== + +from sqlalchemy import Column, String, Integer, Table, ForeignKey +from sqlalchemy.orm import relation, mapper, synonym + +from eos.db import gamedata_meta +from eos.types import AlphaClone, AlphaCloneSkill + +alphaclones_table = Table("alphaClones", gamedata_meta, + Column("alphaCloneID", Integer, primary_key=True), + Column("alphaCloneName", String), + ) + +alphacloneskskills_table = Table("alphaCloneSkills", gamedata_meta, + Column("alphaCloneID", Integer, ForeignKey("alphaClones.alphaCloneID"), primary_key=True), + Column("typeID", Integer, primary_key=True), + Column("level", Integer), + ) + +mapper(AlphaClone, alphaclones_table, + properties={ + "ID": synonym("alphaCloneID"), + "skills": relation( + AlphaCloneSkill, + cascade="all,delete-orphan", + backref="clone") + }) + +mapper(AlphaCloneSkill, alphacloneskskills_table) diff --git a/eos/db/gamedata/item.py b/eos/db/gamedata/item.py index a23c3a786..f0100e761 100644 --- a/eos/db/gamedata/item.py +++ b/eos/db/gamedata/item.py @@ -39,8 +39,8 @@ items_table = Table("invtypes", gamedata_meta, Column("iconID", Integer, ForeignKey("icons.iconID")), Column("groupID", Integer, ForeignKey("invgroups.groupID"), index=True)) -from .metaGroup import metatypes_table -from .traits import traits_table +from .metaGroup import metatypes_table # noqa +from .traits import traits_table # noqa mapper(Item, items_table, properties={"group": relation(Group, backref="items"), diff --git a/eos/db/gamedata/queries.py b/eos/db/gamedata/queries.py index b2db92437..d449dd062 100644 --- a/eos/db/gamedata/queries.py +++ b/eos/db/gamedata/queries.py @@ -21,10 +21,13 @@ from sqlalchemy.orm import join, exc from sqlalchemy.sql import and_, or_, select import eos.config +# TODO: Unsure which item the code below needs :( +# from eos.gamedata import Item +from eos.gamedata import Attribute from eos.db import gamedata_session from eos.db.gamedata.metaGroup import metatypes_table, items_table from eos.db.util import processEager, processWhere -from eos.types import Item, Category, Group, MarketGroup, AttributeInfo, MetaData, MetaGroup +from eos.types import Item, Category, Group, MarketGroup, AttributeInfo, MetaData, MetaGroup, AlphaClone configVal = getattr(eos.config, "gamedataCache", None) if configVal is True: @@ -97,6 +100,24 @@ def getItem(lookfor, eager=None): return item +@cachedQuery(1, "lookfor") +def getAlphaClone(lookfor, eager=None): + if isinstance(lookfor, int): + if eager is None: + item = gamedata_session.query(AlphaClone).get(lookfor) + else: + item = gamedata_session.query(AlphaClone).options(*processEager(eager)).filter(AlphaClone.ID == lookfor).first() + else: + raise TypeError("Need integer as argument") + return item + + +def getAlphaCloneList(eager=None): + eager = processEager(eager) + clones = gamedata_session.query(AlphaClone).options(*eager).all() + return clones + + groupNameMap = {} @@ -280,9 +301,9 @@ def directAttributeRequest(itemIDs, attrIDs): if not isinstance(itemID, int): raise TypeError("All itemIDs must be integer") - q = select((eos.types.Item.typeID, eos.types.Attribute.attributeID, eos.types.Attribute.value), - and_(eos.types.Attribute.attributeID.in_(attrIDs), eos.types.Item.typeID.in_(itemIDs)), - from_obj=[join(eos.types.Attribute, eos.types.Item)]) + q = select((Item.typeID, Attribute.attributeID, Attribute.value), + and_(Attribute.attributeID.in_(attrIDs), Item.typeID.in_(itemIDs)), + from_obj=[join(Attribute, Item)]) result = gamedata_session.execute(q).fetchall() return result diff --git a/eos/db/migrations/upgrade1.py b/eos/db/migrations/upgrade1.py index fc2148734..5eb3478c6 100644 --- a/eos/db/migrations/upgrade1.py +++ b/eos/db/migrations/upgrade1.py @@ -45,7 +45,7 @@ CONVERSIONS = { 8746, # Quantum Co-Processor 8745, # Photonic CPU Enhancer 15425, # Naiyon's Modified Co-Processor (never existed but convert - # anyway as some fits may include it) + # anyway as some fits may include it) ], 8748: [ # Upgraded Co-Processor 8747, # Nanomechanical CPU Enhancer I @@ -70,7 +70,7 @@ CONVERSIONS = { 16543, # Micro 'Vigor' Core Augmentation ], 8089: [ # Compact Light Missile Launcher - 8093, # Prototype 'Arbalest' Light Missile Launcher + 8093, # Prototype 'Arbalest' Light Missile Launcher ], 8091: [ # Ample Light Missile Launcher 7993, # Experimental TE-2100 Light Missile Launcher @@ -82,6 +82,7 @@ CONVERSIONS = { ] } + def upgrade(saveddata_engine): # Update fits schema to include target resists attribute try: @@ -92,6 +93,7 @@ def upgrade(saveddata_engine): # Convert modules for replacement_item, list in CONVERSIONS.iteritems(): for retired_item in list: - saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item)) - saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item)) - + saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?', + (replacement_item, retired_item)) + saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?', + (replacement_item, retired_item)) diff --git a/eos/db/migrations/upgrade10.py b/eos/db/migrations/upgrade10.py index 0bfb0f0ee..1ceeb59e8 100644 --- a/eos/db/migrations/upgrade10.py +++ b/eos/db/migrations/upgrade10.py @@ -6,6 +6,7 @@ Migration 10 import sqlalchemy + def upgrade(saveddata_engine): # Update projectedFits schema to include active attribute try: diff --git a/eos/db/migrations/upgrade11.py b/eos/db/migrations/upgrade11.py index 7265e064a..475537b01 100644 --- a/eos/db/migrations/upgrade11.py +++ b/eos/db/migrations/upgrade11.py @@ -7,7 +7,6 @@ Migration 11 modules with their new replacements """ - CONVERSIONS = { 16467: ( # Medium Gremlin Compact Energy Neutralizer 16471, # Medium Unstable Power Fluctuator I @@ -106,11 +105,12 @@ CONVERSIONS = { ), } -def upgrade(saveddata_engine): +def upgrade(saveddata_engine): # Convert modules for replacement_item, list in CONVERSIONS.iteritems(): for retired_item in list: - saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item)) - saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item)) - + saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?', + (replacement_item, retired_item)) + saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?', + (replacement_item, retired_item)) diff --git a/eos/db/migrations/upgrade12.py b/eos/db/migrations/upgrade12.py index dc0eee511..6e3a1d73b 100644 --- a/eos/db/migrations/upgrade12.py +++ b/eos/db/migrations/upgrade12.py @@ -7,7 +7,6 @@ Migration 12 modules with their new replacements """ - CONVERSIONS = { 16457: ( # Crosslink Compact Ballistic Control System 16459, # Muon Coil Bolt Array I @@ -330,11 +329,12 @@ CONVERSIONS = { ), } -def upgrade(saveddata_engine): +def upgrade(saveddata_engine): # Convert modules for replacement_item, list in CONVERSIONS.iteritems(): for retired_item in list: - saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item)) - saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item)) - + saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?', + (replacement_item, retired_item)) + saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?', + (replacement_item, retired_item)) diff --git a/eos/db/migrations/upgrade13.py b/eos/db/migrations/upgrade13.py index 047dc7129..b8af898e8 100644 --- a/eos/db/migrations/upgrade13.py +++ b/eos/db/migrations/upgrade13.py @@ -6,10 +6,11 @@ Migration 13 import sqlalchemy + def upgrade(saveddata_engine): # Update fits schema to include implant location attribute try: saveddata_engine.execute("SELECT implantLocation FROM fits LIMIT 1") except sqlalchemy.exc.DatabaseError: saveddata_engine.execute("ALTER TABLE fits ADD COLUMN implantLocation INTEGER;") - saveddata_engine.execute("UPDATE fits SET implantLocation = 0") \ No newline at end of file + saveddata_engine.execute("UPDATE fits SET implantLocation = 0") diff --git a/eos/db/migrations/upgrade14.py b/eos/db/migrations/upgrade14.py index 8b39947b2..c62afa6d1 100644 --- a/eos/db/migrations/upgrade14.py +++ b/eos/db/migrations/upgrade14.py @@ -6,8 +6,10 @@ Migration 14 import sqlalchemy + def upgrade(saveddata_engine): - if saveddata_engine.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='fighters'").scalar() == 'fighters': + if saveddata_engine.execute( + "SELECT name FROM sqlite_master WHERE type='table' AND name='fighters'").scalar() == 'fighters': # Fighters table exists try: saveddata_engine.execute("SELECT active FROM fighters LIMIT 1") @@ -16,4 +18,4 @@ def upgrade(saveddata_engine): # (they will be recreated) saveddata_engine.execute("DROP TABLE fighters") - saveddata_engine.execute("DROP TABLE fightersAbilities") \ No newline at end of file + saveddata_engine.execute("DROP TABLE fightersAbilities") diff --git a/eos/db/migrations/upgrade15.py b/eos/db/migrations/upgrade15.py index d3c57a957..13852b035 100644 --- a/eos/db/migrations/upgrade15.py +++ b/eos/db/migrations/upgrade15.py @@ -6,8 +6,8 @@ Migration 15 import sqlalchemy -def upgrade(saveddata_engine): +def upgrade(saveddata_engine): sql = """ DELETE FROM modules WHERE ID IN ( diff --git a/eos/db/migrations/upgrade16.py b/eos/db/migrations/upgrade16.py index 7dfaac97c..15f9b8786 100644 --- a/eos/db/migrations/upgrade16.py +++ b/eos/db/migrations/upgrade16.py @@ -6,6 +6,7 @@ Migration 16 import sqlalchemy + def upgrade(saveddata_engine): # Update fits schema to include notes attribute try: diff --git a/eos/db/migrations/upgrade17.py b/eos/db/migrations/upgrade17.py index c3d996899..1d6a4cff8 100644 --- a/eos/db/migrations/upgrade17.py +++ b/eos/db/migrations/upgrade17.py @@ -33,7 +33,8 @@ def upgrade(saveddata_engine): inserts.append({"boosterID": value, "boostedID": boosted, "active": 1}) try: - saveddata_session.execute(commandFits_table.insert(), {"boosterID": value, "boostedID": boosted, "active": 1}) - except Exception, e: + saveddata_session.execute(commandFits_table.insert(), + {"boosterID": value, "boostedID": boosted, "active": 1}) + except Exception: pass saveddata_session.commit() diff --git a/eos/db/migrations/upgrade18.py b/eos/db/migrations/upgrade18.py index fadc65134..4a13b7d57 100644 --- a/eos/db/migrations/upgrade18.py +++ b/eos/db/migrations/upgrade18.py @@ -4,27 +4,26 @@ Migration 8 - Converts modules from old Warfare Links to Command Modules """ - CONVERSIONS = { 42526: ( # Armor Command Burst I - 20069, # Armored Warfare Link - Damage Control I - 20409, # Armored Warfare Link - Passive Defense I - 22227, # Armored Warfare Link - Rapid Repair I + 20069, # Armored Warfare Link - Damage Control I + 20409, # Armored Warfare Link - Passive Defense I + 22227, # Armored Warfare Link - Rapid Repair I ), 43552: ( # Armor Command Burst II - 4264, # Armored Warfare Link - Damage Control II - 4266, # Armored Warfare Link - Passive Defense II - 4266, # Armored Warfare Link - Rapid Repair II + 4264, # Armored Warfare Link - Damage Control II + 4266, # Armored Warfare Link - Passive Defense II + 4266, # Armored Warfare Link - Rapid Repair II ), 42527: ( # Information Command Burst I - 11052, # Information Warfare Link - Sensor Integrity I - 20405, # Information Warfare Link - Recon Operation I - 20406, # Information Warfare Link - Electronic Superiority I + 11052, # Information Warfare Link - Sensor Integrity I + 20405, # Information Warfare Link - Recon Operation I + 20406, # Information Warfare Link - Electronic Superiority I ), 43554: ( # Information Command Burst II - 4268, # Information Warfare Link - Electronic Superiority II - 4270, # Information Warfare Link - Recon Operation II - 4272, # Information Warfare Link - Sensor Integrity II + 4268, # Information Warfare Link - Electronic Superiority II + 4270, # Information Warfare Link - Recon Operation II + 4272, # Information Warfare Link - Sensor Integrity II ), 42529: ( # Shield Command Burst I 20124, # Siege Warfare Link - Active Shielding I @@ -34,17 +33,17 @@ CONVERSIONS = { 43555: ( # Shield Command Burst II 4280, # Siege Warfare Link - Active Shielding II 4282, # Siege Warfare Link - Shield Efficiency II - 4284 # Siege Warfare Link - Shield Harmonizing II + 4284 # Siege Warfare Link - Shield Harmonizing II ), 42530: ( # Skirmish Command Burst I - 11017, # Skirmish Warfare Link - Interdiction Maneuvers I - 20070, # Skirmish Warfare Link - Evasive Maneuvers I - 20408, # Skirmish Warfare Link - Rapid Deployment I + 11017, # Skirmish Warfare Link - Interdiction Maneuvers I + 20070, # Skirmish Warfare Link - Evasive Maneuvers I + 20408, # Skirmish Warfare Link - Rapid Deployment I ), 43556: ( # Skirmish Command Burst II 4286, # Skirmish Warfare Link - Evasive Maneuvers II 4288, # Skirmish Warfare Link - Interdiction Maneuvers II - 4290 # Skirmish Warfare Link - Rapid Deployment II + 4290 # Skirmish Warfare Link - Rapid Deployment II ), 42528: ( # Mining Foreman Burst I 22553, # Mining Foreman Link - Harvester Capacitor Efficiency I @@ -54,15 +53,16 @@ CONVERSIONS = { 43551: ( # Mining Foreman Burst II 4274, # Mining Foreman Link - Harvester Capacitor Efficiency II 4276, # Mining Foreman Link - Laser Optimization II - 4278 # Mining Foreman Link - Mining Laser Field Enhancement II + 4278 # Mining Foreman Link - Mining Laser Field Enhancement II ), } -def upgrade(saveddata_engine): +def upgrade(saveddata_engine): # Convert modules for replacement_item, list in CONVERSIONS.iteritems(): for retired_item in list: - saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item)) - saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item)) - + saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?', + (replacement_item, retired_item)) + saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?', + (replacement_item, retired_item)) diff --git a/eos/db/migrations/upgrade19.py b/eos/db/migrations/upgrade19.py index 4d93edc7c..090f07dda 100644 --- a/eos/db/migrations/upgrade19.py +++ b/eos/db/migrations/upgrade19.py @@ -11,10 +11,10 @@ def upgrade(saveddata_engine): from eos.db import saveddata_session sql = """ - DELETE FROM commandFits - WHERE boosterID NOT IN (select ID from fits) - OR boostedID NOT IN (select ID from fits) - """ + DELETE FROM commandFits + WHERE boosterID NOT IN (select ID from fits) + OR boostedID NOT IN (select ID from fits) + """ saveddata_session.execute(sql) saveddata_session.commit() diff --git a/eos/db/migrations/upgrade2.py b/eos/db/migrations/upgrade2.py index 917a5218e..526177896 100644 --- a/eos/db/migrations/upgrade2.py +++ b/eos/db/migrations/upgrade2.py @@ -6,6 +6,7 @@ Migration 2 import sqlalchemy + def upgrade(saveddata_engine): # Update characters schema to include default chars try: diff --git a/eos/db/migrations/upgrade20.py b/eos/db/migrations/upgrade20.py new file mode 100644 index 000000000..20da4331e --- /dev/null +++ b/eos/db/migrations/upgrade20.py @@ -0,0 +1,15 @@ +""" +Migration 20 + +- Adds support for alpha clones to the characters table +""" + +import sqlalchemy + + +def upgrade(saveddata_engine): + # Update characters schema to include alphaCloneID + try: + saveddata_engine.execute("SELECT alphaCloneID FROM characters LIMIT 1") + except sqlalchemy.exc.DatabaseError: + saveddata_engine.execute("ALTER TABLE characters ADD COLUMN alphaCloneID INTEGER;") diff --git a/eos/db/migrations/upgrade3.py b/eos/db/migrations/upgrade3.py index 0350ded72..ccc481047 100644 --- a/eos/db/migrations/upgrade3.py +++ b/eos/db/migrations/upgrade3.py @@ -6,6 +6,7 @@ Migration 3 import sqlalchemy + def upgrade(saveddata_engine): try: saveddata_engine.execute("SELECT modeID FROM fits LIMIT 1") diff --git a/eos/db/migrations/upgrade4.py b/eos/db/migrations/upgrade4.py index 87906cffc..f8c670684 100644 --- a/eos/db/migrations/upgrade4.py +++ b/eos/db/migrations/upgrade4.py @@ -10,7 +10,6 @@ Migration 4 and output of itemDiff.py """ - CONVERSIONS = { 506: ( # 'Basic' Capacitor Power Relay 8205, # Alpha Reactor Control: Capacitor Power Relay @@ -131,11 +130,12 @@ CONVERSIONS = { ), } -def upgrade(saveddata_engine): +def upgrade(saveddata_engine): # Convert modules for replacement_item, list in CONVERSIONS.iteritems(): for retired_item in list: - saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item)) - saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item)) - + saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?', + (replacement_item, retired_item)) + saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?', + (replacement_item, retired_item)) diff --git a/eos/db/migrations/upgrade5.py b/eos/db/migrations/upgrade5.py index cf6a3385d..1f5201cf5 100644 --- a/eos/db/migrations/upgrade5.py +++ b/eos/db/migrations/upgrade5.py @@ -4,5 +4,6 @@ Migration 5 Simply deletes damage profiles with a blank name. See GH issue #256 """ + def upgrade(saveddata_engine): saveddata_engine.execute('DELETE FROM damagePatterns WHERE name LIKE ?', ("",)) diff --git a/eos/db/migrations/upgrade6.py b/eos/db/migrations/upgrade6.py index ee8a091e6..724a94008 100644 --- a/eos/db/migrations/upgrade6.py +++ b/eos/db/migrations/upgrade6.py @@ -4,6 +4,8 @@ Migration 6 Overwrites damage profile 0 to reset bad uniform values (bad values set with bug) """ + def upgrade(saveddata_engine): saveddata_engine.execute('DELETE FROM damagePatterns WHERE name LIKE ? OR ID LIKE ?', ("Uniform", "1")) - saveddata_engine.execute('INSERT INTO damagePatterns VALUES (?, ?, ?, ?, ?, ?, ?)', (1, "Uniform", 25, 25, 25, 25, None)) + saveddata_engine.execute('INSERT INTO damagePatterns VALUES (?, ?, ?, ?, ?, ?, ?)', + (1, "Uniform", 25, 25, 25, 25, None)) diff --git a/eos/db/migrations/upgrade7.py b/eos/db/migrations/upgrade7.py index 226f84b3a..fbb74f910 100644 --- a/eos/db/migrations/upgrade7.py +++ b/eos/db/migrations/upgrade7.py @@ -8,17 +8,16 @@ Migration 7 Pyfa. """ - CONVERSIONS = { 640: ( # Scorpion 4005, # Scorpion Ishukone Watch ) } -def upgrade(saveddata_engine): +def upgrade(saveddata_engine): # Convert ships for replacement_item, list in CONVERSIONS.iteritems(): for retired_item in list: - saveddata_engine.execute('UPDATE "fits" SET "shipID" = ? WHERE "shipID" = ?', (replacement_item, retired_item)) - + saveddata_engine.execute('UPDATE "fits" SET "shipID" = ? WHERE "shipID" = ?', + (replacement_item, retired_item)) diff --git a/eos/db/migrations/upgrade8.py b/eos/db/migrations/upgrade8.py index 9d2c04321..19185443b 100644 --- a/eos/db/migrations/upgrade8.py +++ b/eos/db/migrations/upgrade8.py @@ -7,7 +7,6 @@ Migration 8 modules with their new replacements """ - CONVERSIONS = { 8529: ( # Large F-S9 Regolith Compact Shield Extender 8409, # Large Subordinate Screen Stabilizer I @@ -71,15 +70,16 @@ CONVERSIONS = { 11321, # 800mm Reinforced Nanofiber Plates I ), 11317: ( # 800mm Rolled Tungsten Compact Plates - 11315, # 800mm Reinforced Titanium Plates I + 11315, # 800mm Reinforced Titanium Plates I ), } -def upgrade(saveddata_engine): +def upgrade(saveddata_engine): # Convert modules for replacement_item, list in CONVERSIONS.iteritems(): for retired_item in list: - saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item)) - saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?', (replacement_item, retired_item)) - + saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?', + (replacement_item, retired_item)) + saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?', + (replacement_item, retired_item)) diff --git a/eos/db/migrations/upgrade9.py b/eos/db/migrations/upgrade9.py index ae7b66ad5..a2f5b6148 100644 --- a/eos/db/migrations/upgrade9.py +++ b/eos/db/migrations/upgrade9.py @@ -16,8 +16,10 @@ CREATE TABLE boostersTemp ( ) """ + def upgrade(saveddata_engine): saveddata_engine.execute(tmpTable) - saveddata_engine.execute("INSERT INTO boostersTemp (ID, itemID, fitID, active) SELECT ID, itemID, fitID, active FROM boosters") + saveddata_engine.execute( + "INSERT INTO boostersTemp (ID, itemID, fitID, active) SELECT ID, itemID, fitID, active FROM boosters") saveddata_engine.execute("DROP TABLE boosters") saveddata_engine.execute("ALTER TABLE boostersTemp RENAME TO boosters") diff --git a/eos/db/saveddata/character.py b/eos/db/saveddata/character.py index fad8c579d..aa9a99c74 100644 --- a/eos/db/saveddata/character.py +++ b/eos/db/saveddata/character.py @@ -33,10 +33,12 @@ characters_table = Table("characters", saveddata_meta, Column("defaultChar", Integer), Column("chars", String, nullable=True), Column("defaultLevel", Integer, nullable=True), + Column("alphaCloneID", Integer, nullable=True), Column("ownerID", ForeignKey("users.ID"), nullable=True)) mapper(Character, characters_table, properties={ + "_Character__alphaCloneID": characters_table.c.alphaCloneID, "savedName": characters_table.c.name, "_Character__owner": relation( User, diff --git a/eos/db/saveddata/databaseRepair.py b/eos/db/saveddata/databaseRepair.py index ede0f2fde..d2654d67b 100644 --- a/eos/db/saveddata/databaseRepair.py +++ b/eos/db/saveddata/databaseRepair.py @@ -28,77 +28,135 @@ class DatabaseCleanup: pass @staticmethod - def OrphanedCharacterSkills(saveddata_engine): - # Finds and fixes database corruption issues. - logger.debug("Start databsae validation and cleanup.") + def ExecuteSQLQuery(saveddata_engine, query): + try: + results = saveddata_engine.execute(query) + return results + except sqlalchemy.exc.DatabaseError: + logger.error("Failed to connect to database or error executing query:\n%s",query) + return None + @staticmethod + def OrphanedCharacterSkills(saveddata_engine): # Find orphaned character skills. # This solves an issue where the character doesn't exist, but skills for that character do. # See issue #917 - try: - logger.debug("Running database cleanup for character skills.") - results = saveddata_engine.execute("SELECT COUNT(*) AS num FROM characterSkills " - "WHERE characterID NOT IN (SELECT ID from characters)") - row = results.first() + logger.debug("Running database cleanup for character skills.") + query = "SELECT COUNT(*) AS num FROM characterSkills WHERE characterID NOT IN (SELECT ID from characters)" + results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query) - if row and row['num']: - delete = saveddata_engine.execute("DELETE FROM characterSkills WHERE characterID NOT IN (SELECT ID from characters)") - logger.error("Database corruption found. Cleaning up %d records.", delete.rowcount) + if results is None: + return - except sqlalchemy.exc.DatabaseError: - logger.error("Failed to connect to database.") + row = results.first() + + if row and row['num']: + query = "DELETE FROM characterSkills WHERE characterID NOT IN (SELECT ID from characters)" + delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query) + logger.error("Database corruption found. Cleaning up %d records.", delete.rowcount) @staticmethod def OrphanedFitDamagePatterns(saveddata_engine): # Find orphaned damage patterns. # This solves an issue where the damage pattern doesn't exist, but fits reference the pattern. # See issue #777 - try: - logger.debug("Running database cleanup for orphaned damage patterns attached to fits.") + logger.debug("Running database cleanup for orphaned damage patterns attached to fits.") + query = "SELECT COUNT(*) AS num FROM fits WHERE damagePatternID NOT IN (SELECT ID FROM damagePatterns) OR damagePatternID IS NULL" + results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query) - results = saveddata_engine.execute("SELECT COUNT(*) AS num FROM fits WHERE damagePatternID NOT IN (SELECT ID FROM damagePatterns) OR damagePatternID IS NULL") - row = results.first() + if results is None: + return - if row and row['num']: - # Get Uniform damage pattern ID - query = saveddata_engine.execute("SELECT ID FROM damagePatterns WHERE name = 'Uniform'") - rows = query.fetchall() + row = results.first() - if len(rows) == 0: - logger.error("Missing uniform damage pattern.") - elif len(rows) > 1: - logger.error("More than one uniform damage pattern found.") - else: - uniform_damage_pattern_id = rows[0]['ID'] - update = saveddata_engine.execute("UPDATE 'fits' SET 'damagePatternID' = ? " - "WHERE damagePatternID NOT IN (SELECT ID FROM damagePatterns) OR damagePatternID IS NULL", - uniform_damage_pattern_id) - logger.error("Database corruption found. Cleaning up %d records.", update.rowcount) - except sqlalchemy.exc.DatabaseError: - logger.error("Failed to connect to database.") + if row and row['num']: + # Get Uniform damage pattern ID + uniform_query = "SELECT ID FROM damagePatterns WHERE name = 'Uniform'" + uniform_results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, uniform_query) + + if uniform_results is None: + return + + rows = uniform_results.fetchall() + + if len(rows) == 0: + logger.error("Missing uniform damage pattern.") + elif len(rows) > 1: + logger.error("More than one uniform damage pattern found.") + else: + uniform_damage_pattern_id = rows[0]['ID'] + update_query = "UPDATE 'fits' SET 'damagePatternID' = " + str(uniform_damage_pattern_id) + \ + " WHERE damagePatternID NOT IN (SELECT ID FROM damagePatterns) OR damagePatternID IS NULL" + update_results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, update_query) + logger.error("Database corruption found. Cleaning up %d records.", update_results.rowcount) @staticmethod def OrphanedFitCharacterIDs(saveddata_engine): # Find orphaned character IDs. This solves an issue where the character doesn't exist, but fits reference the pattern. - try: - logger.debug("Running database cleanup for orphaned characters attached to fits.") - results = saveddata_engine.execute("SELECT COUNT(*) AS num FROM fits WHERE characterID NOT IN (SELECT ID FROM characters) OR characterID IS NULL") - row = results.first() + logger.debug("Running database cleanup for orphaned characters attached to fits.") + query = "SELECT COUNT(*) AS num FROM fits WHERE characterID NOT IN (SELECT ID FROM characters) OR characterID IS NULL" + results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query) - if row['num']: - # Get All 5 character ID - query = saveddata_engine.execute("SELECT ID FROM characters WHERE name = 'All 5'") - rows = query.fetchall() + if results is None: + return - if len(rows) == 0: - logger.error("Missing 'All 5' character.") - elif len(rows) > 1: - logger.error("More than one 'All 5' character found.") - else: - all5_id = rows[0]['ID'] - update = saveddata_engine.execute("UPDATE 'fits' SET 'characterID' = ? " - "WHERE characterID not in (select ID from characters) OR characterID IS NULL", - all5_id) - logger.error("Database corruption found. Cleaning up %d records.", update.rowcount) - except sqlalchemy.exc.DatabaseError: - logger.error("Failed to connect to database.") + row = results.first() + + if row and row['num']: + # Get All 5 character ID + all5_query = "SELECT ID FROM characters WHERE name = 'All 5'" + all5_results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, all5_query) + + if all5_results is None: + return + + rows = all5_results.fetchall() + + if len(rows) == 0: + logger.error("Missing 'All 5' character.") + elif len(rows) > 1: + logger.error("More than one 'All 5' character found.") + else: + all5_id = rows[0]['ID'] + update_query = "UPDATE 'fits' SET 'characterID' = " + str(all5_id) + \ + " WHERE characterID not in (select ID from characters) OR characterID IS NULL" + update_results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, update_query) + logger.error("Database corruption found. Cleaning up %d records.", update_results.rowcount) + + @staticmethod + def NullDamagePatternNames(saveddata_engine): + # Find damage patterns that are missing the name. + # This solves an issue where the damage pattern ends up with a name that is null. + # See issue #949 + logger.debug("Running database cleanup for missing damage pattern names.") + query = "SELECT COUNT(*) AS num FROM damagePatterns WHERE name IS NULL OR name = ''" + results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query) + + if results is None: + return + + row = results.first() + + if row and row['num']: + query = "DELETE FROM damagePatterns WHERE name IS NULL OR name = ''" + delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query) + logger.error("Database corruption found. Cleaning up %d records.", delete.rowcount) + + @staticmethod + def NullTargetResistNames(saveddata_engine): + # Find target resists that are missing the name. + # This solves an issue where the target resist ends up with a name that is null. + # See issue #949 + logger.debug("Running database cleanup for missing target resist names.") + query = "SELECT COUNT(*) AS num FROM targetResists WHERE name IS NULL OR name = ''" + results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query) + + if results is None: + return + + row = results.first() + + if row and row['num']: + query = "DELETE FROM targetResists WHERE name IS NULL OR name = ''" + delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query) + logger.error("Database corruption found. Cleaning up %d records.", delete.rowcount) diff --git a/eos/db/saveddata/fighter.py b/eos/db/saveddata/fighter.py index 7074369da..179edab11 100644 --- a/eos/db/saveddata/fighter.py +++ b/eos/db/saveddata/fighter.py @@ -18,7 +18,7 @@ # =============================================================================== from sqlalchemy import Table, Column, Integer, ForeignKey, Boolean -from sqlalchemy.orm import * +from sqlalchemy.orm import mapper, relation from eos.db import saveddata_meta from eos.types import Fighter, Fit diff --git a/eos/db/saveddata/fit.py b/eos/db/saveddata/fit.py index 46a9ff5f5..c698a4ec7 100644 --- a/eos/db/saveddata/fit.py +++ b/eos/db/saveddata/fit.py @@ -17,20 +17,22 @@ # along with eos. If not, see . # =============================================================================== -from sqlalchemy import * from sqlalchemy.ext.associationproxy import association_proxy -from sqlalchemy.orm import * 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 from eos.db import saveddata_meta +from eos.db import 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 * -from eos.types import Fit, Module, User, Booster, Drone, Fighter, Cargo, Implant, Character, DamagePattern, \ +from eos.effectHandlerHelpers import HandledModuleList, HandledImplantBoosterList, HandledProjectedModList, \ + HandledDroneCargoList, HandledProjectedDroneList +from eos.types import Fit as es_Fit, Module, User, Booster, Drone, Fighter, Cargo, Implant, Character, DamagePattern, \ TargetResists, ImplantLocation fits_table = Table("fits", saveddata_meta, @@ -45,7 +47,7 @@ fits_table = Table("fits", saveddata_meta, Column("targetResistsID", ForeignKey("targetResists.ID"), nullable=True), Column("modeID", Integer, nullable=True), Column("implantLocation", Integer, nullable=False, default=ImplantLocation.FIT), - Column("notes", String, nullable = True), + Column("notes", String, nullable=True), ) projectedFits_table = Table("projectedFits", saveddata_meta, @@ -61,6 +63,7 @@ commandFits_table = Table("commandFits", saveddata_meta, Column("active", Boolean, nullable=False, default=1) ) + class ProjectedFit(object): def __init__(self, sourceID, source_fit, amount=1, active=True): self.sourceID = sourceID @@ -72,9 +75,9 @@ class ProjectedFit(object): def init(self): if self.source_fit.isInvalid: # Very rare for this to happen, but be prepared for it - eos.db.saveddata_session.delete(self.source_fit) - eos.db.saveddata_session.flush() - eos.db.saveddata_session.refresh(self.victim_fit) + saveddata_session.delete(self.source_fit) + saveddata_session.flush() + saveddata_session.refresh(self.victim_fit) # We have a series of setters and getters here just in case someone # downgrades and screws up the table with NULL values @@ -91,6 +94,7 @@ class ProjectedFit(object): self.sourceID, self.victimID, self.amount, self.active, hex(id(self)) ) + class CommandFit(object): def __init__(self, boosterID, booster_fit, active=True): self.boosterID = boosterID @@ -101,125 +105,126 @@ class CommandFit(object): def init(self): if self.booster_fit.isInvalid: # Very rare for this to happen, but be prepared for it - eos.db.saveddata_session.delete(self.booster_fit) - eos.db.saveddata_session.flush() - eos.db.saveddata_session.refresh(self.boosted_fit) + saveddata_session.delete(self.booster_fit) + saveddata_session.flush() + saveddata_session.refresh(self.boosted_fit) def __repr__(self): return "CommandFit(boosterID={}, boostedID={}, active={}) at {}".format( self.boosterID, self.boostedID, self.active, hex(id(self)) ) -Fit._Fit__projectedFits = association_proxy( + +es_Fit._Fit__projectedFits = association_proxy( "victimOf", # look at the victimOf association... "source_fit", # .. and return the source fits creator=lambda sourceID, source_fit: ProjectedFit(sourceID, source_fit) ) -Fit._Fit__commandFits = association_proxy( +es_Fit._Fit__commandFits = association_proxy( "boostedOf", # look at the boostedOf association... "booster_fit", # .. and return the booster fit creator=lambda boosterID, booster_fit: CommandFit(boosterID, booster_fit) ) -mapper(Fit, fits_table, - properties={ - "_Fit__modules": relation( - Module, - collection_class=HandledModuleList, - primaryjoin=and_(modules_table.c.fitID == fits_table.c.ID, modules_table.c.projected == False), - order_by=modules_table.c.position, - cascade='all, delete, delete-orphan'), - "_Fit__projectedModules": relation( - Module, - collection_class=HandledProjectedModList, - cascade='all, delete, delete-orphan', - single_parent=True, - primaryjoin=and_(modules_table.c.fitID == fits_table.c.ID, modules_table.c.projected == True)), - "owner": relation( - User, - backref="fits"), - "itemID": fits_table.c.shipID, - "shipID": fits_table.c.shipID, - "_Fit__boosters": relation( - Booster, - collection_class=HandledImplantBoosterList, - cascade='all, delete, delete-orphan', - single_parent=True), - "_Fit__drones": relation( - Drone, - collection_class=HandledDroneCargoList, - cascade='all, delete, delete-orphan', - single_parent=True, - primaryjoin=and_(drones_table.c.fitID == fits_table.c.ID, drones_table.c.projected == False)), - "_Fit__fighters": relation( - Fighter, - collection_class=HandledDroneCargoList, - cascade='all, delete, delete-orphan', - single_parent=True, - primaryjoin=and_(fighters_table.c.fitID == fits_table.c.ID, fighters_table.c.projected == False)), - "_Fit__cargo": relation( - Cargo, - collection_class=HandledDroneCargoList, - cascade='all, delete, delete-orphan', - single_parent=True, - primaryjoin=and_(cargo_table.c.fitID == fits_table.c.ID)), - "_Fit__projectedDrones": relation( - Drone, - collection_class=HandledProjectedDroneList, - cascade='all, delete, delete-orphan', - single_parent=True, - primaryjoin=and_(drones_table.c.fitID == fits_table.c.ID, drones_table.c.projected == True)), - "_Fit__projectedFighters": relation( - Fighter, - collection_class=HandledProjectedDroneList, - cascade='all, delete, delete-orphan', - single_parent=True, - primaryjoin=and_(fighters_table.c.fitID == fits_table.c.ID, fighters_table.c.projected == True)), - "_Fit__implants": relation( - Implant, - collection_class=HandledImplantBoosterList, - cascade='all, delete, delete-orphan', - backref='fit', - single_parent=True, - primaryjoin=fitImplants_table.c.fitID == fits_table.c.ID, - secondaryjoin=fitImplants_table.c.implantID == Implant.ID, - secondary=fitImplants_table), - "_Fit__character": relation( - Character, - backref="fits"), - "_Fit__damagePattern": relation(DamagePattern), - "_Fit__targetResists": relation(TargetResists), - "projectedOnto": relationship( - ProjectedFit, - primaryjoin=projectedFits_table.c.sourceID == fits_table.c.ID, - backref='source_fit', - collection_class=attribute_mapped_collection('victimID'), - cascade='all, delete, delete-orphan'), - "victimOf": relationship( - ProjectedFit, - primaryjoin=fits_table.c.ID == projectedFits_table.c.victimID, - backref='victim_fit', - collection_class=attribute_mapped_collection('sourceID'), - cascade='all, delete, delete-orphan'), - "boostedOnto": relationship( - CommandFit, - primaryjoin=commandFits_table.c.boosterID == fits_table.c.ID, - backref='booster_fit', - collection_class=attribute_mapped_collection('boostedID'), - cascade='all, delete, delete-orphan'), - "boostedOf": relationship( - CommandFit, - primaryjoin=fits_table.c.ID == commandFits_table.c.boostedID, - backref='boosted_fit', - collection_class=attribute_mapped_collection('boosterID'), - cascade='all, delete, delete-orphan'), - } -) +mapper(es_Fit, fits_table, + properties={ + "_Fit__modules": relation( + Module, + collection_class=HandledModuleList, + primaryjoin=and_(modules_table.c.fitID == fits_table.c.ID, modules_table.c.projected == False), # noqa + order_by=modules_table.c.position, + cascade='all, delete, delete-orphan'), + "_Fit__projectedModules": relation( + Module, + collection_class=HandledProjectedModList, + cascade='all, delete, delete-orphan', + single_parent=True, + primaryjoin=and_(modules_table.c.fitID == fits_table.c.ID, modules_table.c.projected == True)), # noqa + "owner": relation( + User, + backref="fits"), + "itemID": fits_table.c.shipID, + "shipID": fits_table.c.shipID, + "_Fit__boosters": relation( + Booster, + collection_class=HandledImplantBoosterList, + cascade='all, delete, delete-orphan', + single_parent=True), + "_Fit__drones": relation( + Drone, + collection_class=HandledDroneCargoList, + cascade='all, delete, delete-orphan', + single_parent=True, + primaryjoin=and_(drones_table.c.fitID == fits_table.c.ID, drones_table.c.projected == False)), # noqa + "_Fit__fighters": relation( + Fighter, + collection_class=HandledDroneCargoList, + cascade='all, delete, delete-orphan', + single_parent=True, + primaryjoin=and_(fighters_table.c.fitID == fits_table.c.ID, fighters_table.c.projected == False)), # noqa + "_Fit__cargo": relation( + Cargo, + collection_class=HandledDroneCargoList, + cascade='all, delete, delete-orphan', + single_parent=True, + primaryjoin=and_(cargo_table.c.fitID == fits_table.c.ID)), + "_Fit__projectedDrones": relation( + Drone, + collection_class=HandledProjectedDroneList, + cascade='all, delete, delete-orphan', + single_parent=True, + primaryjoin=and_(drones_table.c.fitID == fits_table.c.ID, drones_table.c.projected == True)), # noqa + "_Fit__projectedFighters": relation( + Fighter, + collection_class=HandledProjectedDroneList, + cascade='all, delete, delete-orphan', + single_parent=True, + primaryjoin=and_(fighters_table.c.fitID == fits_table.c.ID, fighters_table.c.projected == True)), # noqa + "_Fit__implants": relation( + Implant, + collection_class=HandledImplantBoosterList, + cascade='all, delete, delete-orphan', + backref='fit', + single_parent=True, + primaryjoin=fitImplants_table.c.fitID == fits_table.c.ID, + secondaryjoin=fitImplants_table.c.implantID == Implant.ID, + secondary=fitImplants_table), + "_Fit__character": relation( + Character, + backref="fits"), + "_Fit__damagePattern": relation(DamagePattern), + "_Fit__targetResists": relation(TargetResists), + "projectedOnto": relationship( + ProjectedFit, + primaryjoin=projectedFits_table.c.sourceID == fits_table.c.ID, + backref='source_fit', + collection_class=attribute_mapped_collection('victimID'), + cascade='all, delete, delete-orphan'), + "victimOf": relationship( + ProjectedFit, + primaryjoin=fits_table.c.ID == projectedFits_table.c.victimID, + backref='victim_fit', + collection_class=attribute_mapped_collection('sourceID'), + cascade='all, delete, delete-orphan'), + "boostedOnto": relationship( + CommandFit, + primaryjoin=commandFits_table.c.boosterID == fits_table.c.ID, + backref='booster_fit', + collection_class=attribute_mapped_collection('boostedID'), + cascade='all, delete, delete-orphan'), + "boostedOf": relationship( + CommandFit, + primaryjoin=fits_table.c.ID == commandFits_table.c.boostedID, + backref='boosted_fit', + collection_class=attribute_mapped_collection('boosterID'), + cascade='all, delete, delete-orphan'), + } + ) mapper(ProjectedFit, projectedFits_table, - properties={ - "_ProjectedFit__amount": projectedFits_table.c.amount, - } -) + properties={ + "_ProjectedFit__amount": projectedFits_table.c.amount, + } + ) -mapper(CommandFit, commandFits_table) \ No newline at end of file +mapper(CommandFit, commandFits_table) diff --git a/eos/db/saveddata/loadDefaultDatabaseValues.py b/eos/db/saveddata/loadDefaultDatabaseValues.py index 3dcccca68..29534bc5e 100644 --- a/eos/db/saveddata/loadDefaultDatabaseValues.py +++ b/eos/db/saveddata/loadDefaultDatabaseValues.py @@ -18,7 +18,8 @@ # =============================================================================== import eos.db -import eos.types +from eos.saveddata.damagePattern import DamagePattern as es_DamagePattern +from eos.saveddata.targetResists import TargetResists as es_TargetResists class ImportError(Exception): @@ -118,7 +119,7 @@ class DefaultDatabaseValues(): name, em, therm, kin, exp = damageProfileRow damageProfile = eos.db.getDamagePattern(name) if damageProfile is None: - damageProfile = eos.types.DamagePattern(em, therm, kin, exp) + damageProfile = es_DamagePattern(em, therm, kin, exp) damageProfile.name = name eos.db.save(damageProfile) @@ -180,7 +181,7 @@ class DefaultDatabaseValues(): name, em, therm, kin, exp = targetResistProfileRow resistsProfile = eos.db.eos.db.getTargetResists(name) if resistsProfile is None: - resistsProfile = eos.types.TargetResists(em, therm, kin, exp) + resistsProfile = es_TargetResists(em, therm, kin, exp) resistsProfile.name = name eos.db.save(resistsProfile) @@ -192,6 +193,6 @@ class DefaultDatabaseValues(): name, em, therm, kin, exp = damageProfileRow damageProfile = eos.db.getDamagePattern(name) if damageProfile is None: - damageProfile = eos.types.DamagePattern(em, therm, kin, exp) + damageProfile = es_DamagePattern(em, therm, kin, exp) damageProfile.name = name eos.db.save(damageProfile) diff --git a/eos/db/saveddata/queries.py b/eos/db/saveddata/queries.py index 8c0d1c2b6..287e83d5a 100644 --- a/eos/db/saveddata/queries.py +++ b/eos/db/saveddata/queries.py @@ -17,6 +17,10 @@ # along with eos. If not, see . # =============================================================================== +from sqlalchemy.sql import and_ + +from eos.db import saveddata_session, sd_lock +from eos.db.saveddata.fit import projectedFits_table from eos.db.util import processEager, processWhere from eos.db import saveddata_session, sd_lock @@ -32,7 +36,6 @@ if configVal is True: itemCache = {} queryCache = {} - def cachedQuery(type, amount, *keywords): itemCache[type] = localItemCache = weakref.WeakValueDictionary() queryCache[type] = typeQueryCache = {} @@ -91,7 +94,6 @@ if configVal is True: return deco - def removeCachedEntry(type, ID): if type not in queryCache: return @@ -121,7 +123,6 @@ else: return deco - def removeCachedEntry(*args, **kwargs): return @@ -210,6 +211,7 @@ def getFit(lookfor, eager=None): return fit + def getFitsWithShip(shipID, ownerID=None, where=None, eager=None): """ Get all the fits using a certain ship. @@ -293,6 +295,7 @@ def getFitList(eager=None): return fits + @cachedQuery(Price, 1, "typeID") def getPrice(typeID): if isinstance(typeID, int): @@ -416,6 +419,7 @@ def searchFits(nameLike, where=None, eager=None): return fits + def getProjectedFits(fitID): if isinstance(fitID, int): with sd_lock: diff --git a/eos/effectHandlerHelpers.py b/eos/effectHandlerHelpers.py index 300e0b4cc..b0a61be69 100644 --- a/eos/effectHandlerHelpers.py +++ b/eos/effectHandlerHelpers.py @@ -21,7 +21,6 @@ import logging import eos.db -import eos.types logger = logging.getLogger(__name__) diff --git a/eos/effects/adaptivearmorhardener.py b/eos/effects/adaptivearmorhardener.py index bf20478c2..33e9f143c 100644 --- a/eos/effects/adaptivearmorhardener.py +++ b/eos/effects/adaptivearmorhardener.py @@ -8,13 +8,15 @@ logger = logging.getLogger(__name__) runTime = "late" type = "active" + + def handler(fit, module, context): damagePattern = fit.damagePattern # Skip if there is no damage pattern. Example: projected ships or fleet boosters if damagePattern: - #logger.debug("Damage Pattern: %f/%f/%f/%f", damagePattern.emAmount, damagePattern.thermalAmount, damagePattern.kineticAmount, damagePattern.explosiveAmount) - #logger.debug("Original Armor Resists: %f/%f/%f/%f", fit.ship.getModifiedItemAttr('armorEmDamageResonance'), fit.ship.getModifiedItemAttr('armorThermalDamageResonance'), fit.ship.getModifiedItemAttr('armorKineticDamageResonance'), fit.ship.getModifiedItemAttr('armorExplosiveDamageResonance')) + # logger.debug("Damage Pattern: %f/%f/%f/%f", damagePattern.emAmount, damagePattern.thermalAmount, damagePattern.kineticAmount, damagePattern.explosiveAmount) + # logger.debug("Original Armor Resists: %f/%f/%f/%f", fit.ship.getModifiedItemAttr('armorEmDamageResonance'), fit.ship.getModifiedItemAttr('armorThermalDamageResonance'), fit.ship.getModifiedItemAttr('armorKineticDamageResonance'), fit.ship.getModifiedItemAttr('armorExplosiveDamageResonance')) # Populate a tuple with the damage profile modified by current armor resists. baseDamageTaken = ( @@ -23,35 +25,36 @@ def handler(fit, module, context): damagePattern.kineticAmount * fit.ship.getModifiedItemAttr('armorKineticDamageResonance'), damagePattern.explosiveAmount * fit.ship.getModifiedItemAttr('armorExplosiveDamageResonance'), ) - #logger.debug("Damage Adjusted for Armor Resists: %f/%f/%f/%f", baseDamageTaken[0], baseDamageTaken[1], baseDamageTaken[2], baseDamageTaken[3]) + # logger.debug("Damage Adjusted for Armor Resists: %f/%f/%f/%f", baseDamageTaken[0], baseDamageTaken[1], baseDamageTaken[2], baseDamageTaken[3]) - resistanceShiftAmount = module.getModifiedItemAttr('resistanceShiftAmount') / 100 # The attribute is in percent and we want a fraction + resistanceShiftAmount = module.getModifiedItemAttr( + 'resistanceShiftAmount') / 100 # The attribute is in percent and we want a fraction RAHResistance = [ - module.getModifiedItemAttr('armorEmDamageResonance'), - module.getModifiedItemAttr('armorThermalDamageResonance'), - module.getModifiedItemAttr('armorKineticDamageResonance'), + module.getModifiedItemAttr('armorEmDamageResonance'), + module.getModifiedItemAttr('armorThermalDamageResonance'), + module.getModifiedItemAttr('armorKineticDamageResonance'), module.getModifiedItemAttr('armorExplosiveDamageResonance'), ] - + # Simulate RAH cycles until the RAH either stops changing or enters a loop. # The number of iterations is limited to prevent an infinite loop if something goes wrong. cycleList = [] loopStart = -20 for num in range(50): - #logger.debug("Starting cycle %d.", num) + # logger.debug("Starting cycle %d.", num) # The strange order is to emulate the ingame sorting when different types have taken the same amount of damage. # This doesn't take into account stacking penalties. In a few cases fitting a Damage Control causes an inaccurate result. damagePattern_tuples = [ (0, baseDamageTaken[0] * RAHResistance[0], RAHResistance[0]), - (3, baseDamageTaken[3] * RAHResistance[3], RAHResistance[3]), + (3, baseDamageTaken[3] * RAHResistance[3], RAHResistance[3]), (2, baseDamageTaken[2] * RAHResistance[2], RAHResistance[2]), (1, baseDamageTaken[1] * RAHResistance[1], RAHResistance[1]), ] - #logger.debug("Damage taken this cycle: %f/%f/%f/%f", damagePattern_tuples[0][1], damagePattern_tuples[3][1], damagePattern_tuples[2][1], damagePattern_tuples[1][1]) - + # logger.debug("Damage taken this cycle: %f/%f/%f/%f", damagePattern_tuples[0][1], damagePattern_tuples[3][1], damagePattern_tuples[2][1], damagePattern_tuples[1][1]) + # Sort the tuple to drop the highest damage value to the bottom sortedDamagePattern_tuples = sorted(damagePattern_tuples, key=lambda damagePattern: damagePattern[1]) - + if sortedDamagePattern_tuples[2][1] == 0: # One damage type: the top damage type takes from the other three # Since the resistances not taking damage will end up going to the type taking damage we just do the whole thing at once. @@ -72,41 +75,47 @@ def handler(fit, module, context): change1 = min(resistanceShiftAmount, 1 - sortedDamagePattern_tuples[1][2]) change2 = -(change0 + change1) / 2 change3 = -(change0 + change1) / 2 - + RAHResistance[sortedDamagePattern_tuples[0][0]] = sortedDamagePattern_tuples[0][2] + change0 RAHResistance[sortedDamagePattern_tuples[1][0]] = sortedDamagePattern_tuples[1][2] + change1 RAHResistance[sortedDamagePattern_tuples[2][0]] = sortedDamagePattern_tuples[2][2] + change2 RAHResistance[sortedDamagePattern_tuples[3][0]] = sortedDamagePattern_tuples[3][2] + change3 - #logger.debug("Resistances shifted to %f/%f/%f/%f", RAHResistance[0], RAHResistance[1], RAHResistance[2], RAHResistance[3]) - + # logger.debug("Resistances shifted to %f/%f/%f/%f", RAHResistance[0], RAHResistance[1], RAHResistance[2], RAHResistance[3]) + # See if the current RAH profile has been encountered before, indicating a loop. for i, val in enumerate(cycleList): - tolerance = 1e-06 - if abs(RAHResistance[0] - val[0]) <= tolerance and abs(RAHResistance[1] - val[1]) <= tolerance and abs(RAHResistance[2] - val[2]) <= tolerance and abs(RAHResistance[3] - val[3]) <= tolerance: + tolerance = 1e-06 + if abs(RAHResistance[0] - val[0]) <= tolerance and \ + abs(RAHResistance[1] - val[1]) <= tolerance and \ + abs(RAHResistance[2] - val[2]) <= tolerance and \ + abs(RAHResistance[3] - val[3]) <= tolerance: loopStart = i - #logger.debug("Loop found: %d-%d", loopStart, num) + # logger.debug("Loop found: %d-%d", loopStart, num) break - if loopStart >= 0: break - + if loopStart >= 0: + break + cycleList.append(list(RAHResistance)) - + if loopStart < 0: - logger.error("Reactive Armor Hardener failed to find equilibrium. Damage profile after armor: %f/%f/%f/%f", baseDamageTaken[0], baseDamageTaken[1], baseDamageTaken[2], baseDamageTaken[3]) - - # Average the profiles in the RAH loop, or the last 20 if it didn't find a loop. + logger.error("Reactive Armor Hardener failed to find equilibrium. Damage profile after armor: %f/%f/%f/%f", + baseDamageTaken[0], baseDamageTaken[1], baseDamageTaken[2], baseDamageTaken[3]) + + # Average the profiles in the RAH loop, or the last 20 if it didn't find a loop. loopCycles = cycleList[loopStart:] numCycles = len(loopCycles) average = [0, 0, 0, 0] for cycle in loopCycles: for i in range(4): average[i] += cycle[i] - + for i in range(4): average[i] = round(average[i] / numCycles, 3) - + # Set the new resistances - #logger.debug("Setting new resist profile: %f/%f/%f/%f", average[0], average[1], average[2],average[3]) - for i, attr in enumerate(('armorEmDamageResonance', 'armorThermalDamageResonance', 'armorKineticDamageResonance', 'armorExplosiveDamageResonance')): + # logger.debug("Setting new resist profile: %f/%f/%f/%f", average[0], average[1], average[2],average[3]) + for i, attr in enumerate(( + 'armorEmDamageResonance', 'armorThermalDamageResonance', 'armorKineticDamageResonance', + 'armorExplosiveDamageResonance')): module.increaseItemAttr(attr, average[i] - module.getModifiedItemAttr(attr)) fit.ship.multiplyItemAttr(attr, average[i], stackingPenalties=True, penaltyGroup="preMul") - \ No newline at end of file diff --git a/eos/effects/angelsetbonus.py b/eos/effects/angelsetbonus.py index 9057b5876..1591e9be1 100644 --- a/eos/effects/angelsetbonus.py +++ b/eos/effects/angelsetbonus.py @@ -8,7 +8,7 @@ type = "passive" def handler(fit, implant, context): fit.appliedImplants.filteredItemMultiply( - lambda - implant: "signatureRadiusBonus" in implant.itemModifiedAttributes and "implantSetAngel" in implant.itemModifiedAttributes, + lambda implant: "signatureRadiusBonus" in implant.itemModifiedAttributes and + "implantSetAngel" in implant.itemModifiedAttributes, "signatureRadiusBonus", implant.getModifiedItemAttr("implantSetAngel")) diff --git a/eos/effects/armoredcommanddurationbonus.py b/eos/effects/armoredcommanddurationbonus.py index 031c6d0ef..171dfbbb2 100644 --- a/eos/effects/armoredcommanddurationbonus.py +++ b/eos/effects/armoredcommanddurationbonus.py @@ -3,6 +3,9 @@ # Used by: # Skill: Armored Command type = "passive" + + def handler(fit, src, context): lvl = src.level - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration", src.getModifiedItemAttr("durationBonus") * lvl) + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration", + src.getModifiedItemAttr("durationBonus") * lvl) diff --git a/eos/effects/armoredcommandmindlink.py b/eos/effects/armoredcommandmindlink.py index 832bc2678..2e36ed6f0 100644 --- a/eos/effects/armoredcommandmindlink.py +++ b/eos/effects/armoredcommandmindlink.py @@ -5,9 +5,16 @@ # Implant: Federation Navy Command Mindlink # Implant: Imperial Navy Command Mindlink type = "passive" + + def handler(fit, src, context): - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Multiplier", src.getModifiedItemAttr("mindlinkBonus")) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Multiplier", src.getModifiedItemAttr("mindlinkBonus")) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Multiplier", src.getModifiedItemAttr("mindlinkBonus")) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Multiplier", src.getModifiedItemAttr("mindlinkBonus")) - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration", src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Multiplier", + src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Multiplier", + src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Multiplier", + src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Multiplier", + src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration", + src.getModifiedItemAttr("mindlinkBonus")) diff --git a/eos/effects/armoredcommandstrengthbonus.py b/eos/effects/armoredcommandstrengthbonus.py index 363c4f1a8..6bc5e365e 100644 --- a/eos/effects/armoredcommandstrengthbonus.py +++ b/eos/effects/armoredcommandstrengthbonus.py @@ -3,9 +3,15 @@ # Used by: # Skill: Armored Command Specialist type = "passive" + + def handler(fit, src, context): lvl = src.level - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Multiplier", + src.getModifiedItemAttr("commandStrengthBonus") * lvl) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Multiplier", + src.getModifiedItemAttr("commandStrengthBonus") * lvl) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Multiplier", + src.getModifiedItemAttr("commandStrengthBonus") * lvl) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Multiplier", + src.getModifiedItemAttr("commandStrengthBonus") * lvl) diff --git a/eos/effects/caldarishipewstrengthcb.py b/eos/effects/caldarishipewstrengthcb.py index b362382d1..48bdccb60 100644 --- a/eos/effects/caldarishipewstrengthcb.py +++ b/eos/effects/caldarishipewstrengthcb.py @@ -7,5 +7,7 @@ type = "passive" def handler(fit, ship, context): for sensorType in ("Gravimetric", "Ladar", "Magnetometric", "Radar"): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Electronic Warfare"), "scan{0}StrengthBonus".format(sensorType), - ship.getModifiedItemAttr("shipBonusCB"), stackingPenalties=True, skill="Caldari Battleship") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Electronic Warfare"), + "scan{0}StrengthBonus".format(sensorType), + ship.getModifiedItemAttr("shipBonusCB"), stackingPenalties=True, + skill="Caldari Battleship") diff --git a/eos/effects/commandburstaoebonus.py b/eos/effects/commandburstaoebonus.py index 8b7bbfce3..7965a6877 100644 --- a/eos/effects/commandburstaoebonus.py +++ b/eos/effects/commandburstaoebonus.py @@ -5,6 +5,8 @@ # Skill: Leadership # Skill: Wing Command type = "passive" + + def handler(fit, src, context): fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Leadership"), "maxRange", diff --git a/eos/effects/commandburstaoerolebonus.py b/eos/effects/commandburstaoerolebonus.py index eddf8713e..63de8ca87 100644 --- a/eos/effects/commandburstaoerolebonus.py +++ b/eos/effects/commandburstaoerolebonus.py @@ -11,5 +11,8 @@ # Ship: Orca # Ship: Rorqual type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Leadership"), "maxRange", src.getModifiedItemAttr("roleBonusCommandBurstAoERange")) + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Leadership"), "maxRange", + src.getModifiedItemAttr("roleBonusCommandBurstAoERange")) diff --git a/eos/effects/commandburstreloadtimebonus.py b/eos/effects/commandburstreloadtimebonus.py index 1af92ee57..c0207bef4 100644 --- a/eos/effects/commandburstreloadtimebonus.py +++ b/eos/effects/commandburstreloadtimebonus.py @@ -3,6 +3,8 @@ # Used by: # Skill: Command Burst Specialist type = "passive" + + def handler(fit, src, context): lvl = src.level fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Leadership"), diff --git a/eos/effects/commandprocessoreffect.py b/eos/effects/commandprocessoreffect.py index 03030ed85..887644ece 100644 --- a/eos/effects/commandprocessoreffect.py +++ b/eos/effects/commandprocessoreffect.py @@ -3,6 +3,10 @@ # Used by: # Modules named like: Command Processor I (4 of 4) type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Leadership"), "maxGroupActive", src.getModifiedItemAttr("maxGangModules")) - fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Leadership"), "maxGroupOnline", src.getModifiedItemAttr("maxGangModules")) + fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Leadership"), "maxGroupActive", + src.getModifiedItemAttr("maxGangModules")) + fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Leadership"), "maxGroupOnline", + src.getModifiedItemAttr("maxGangModules")) diff --git a/eos/effects/commandshipmultirelayeffect.py b/eos/effects/commandshipmultirelayeffect.py index de57a5160..9a3b30089 100644 --- a/eos/effects/commandshipmultirelayeffect.py +++ b/eos/effects/commandshipmultirelayeffect.py @@ -6,6 +6,9 @@ # Ship: Rorqual type = "passive" + def handler(fit, src, context): - fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Leadership"), "maxGroupActive", src.getModifiedItemAttr("maxGangModules")) - fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Leadership"), "maxGroupOnline", src.getModifiedItemAttr("maxGangModules")) \ No newline at end of file + fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Leadership"), "maxGroupActive", + src.getModifiedItemAttr("maxGangModules")) + fit.modules.filteredItemIncrease(lambda mod: mod.item.requiresSkill("Leadership"), "maxGroupOnline", + src.getModifiedItemAttr("maxGangModules")) diff --git a/eos/effects/elitebonuscommanddestroyerarmored1.py b/eos/effects/elitebonuscommanddestroyerarmored1.py index 4b5442b0d..83df03351 100644 --- a/eos/effects/elitebonuscommanddestroyerarmored1.py +++ b/eos/effects/elitebonuscommanddestroyerarmored1.py @@ -4,9 +4,16 @@ # Ship: Magus # Ship: Pontifex type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Value", + src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Value", + src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration", + src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Value", + src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Value", + src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") diff --git a/eos/effects/elitebonuscommanddestroyerinfo1.py b/eos/effects/elitebonuscommanddestroyerinfo1.py index 9198bc1c7..2f17453b2 100644 --- a/eos/effects/elitebonuscommanddestroyerinfo1.py +++ b/eos/effects/elitebonuscommanddestroyerinfo1.py @@ -4,9 +4,16 @@ # Ship: Pontifex # Ship: Stork type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff1Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff3Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff2Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "buffDuration", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff4Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff1Value", + src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff3Value", + src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff2Value", + src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "buffDuration", + src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff4Value", + src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") diff --git a/eos/effects/elitebonuscommanddestroyershield1.py b/eos/effects/elitebonuscommanddestroyershield1.py index ef5d75c29..03c2e2b8e 100644 --- a/eos/effects/elitebonuscommanddestroyershield1.py +++ b/eos/effects/elitebonuscommanddestroyershield1.py @@ -4,9 +4,16 @@ # Ship: Bifrost # Ship: Stork type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff3Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "buffDuration", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff1Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff4Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff2Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff3Value", + src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "buffDuration", + src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff1Value", + src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff4Value", + src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff2Value", + src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") diff --git a/eos/effects/elitebonuscommanddestroyerskirmish1.py b/eos/effects/elitebonuscommanddestroyerskirmish1.py index aa600f865..b33bdfa02 100644 --- a/eos/effects/elitebonuscommanddestroyerskirmish1.py +++ b/eos/effects/elitebonuscommanddestroyerskirmish1.py @@ -4,9 +4,16 @@ # Ship: Bifrost # Ship: Magus type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff3Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "buffDuration", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff1Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff4Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff2Value", src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff3Value", + src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "buffDuration", + src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff1Value", + src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff4Value", + src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff2Value", + src.getModifiedItemAttr("eliteBonusCommandDestroyer1"), skill="Command Destroyers") diff --git a/eos/effects/elitebonuscommandshiparmoredcs3.py b/eos/effects/elitebonuscommandshiparmoredcs3.py index 4832b2904..d7bc3fc46 100644 --- a/eos/effects/elitebonuscommandshiparmoredcs3.py +++ b/eos/effects/elitebonuscommandshiparmoredcs3.py @@ -3,9 +3,16 @@ # Used by: # Ships from group: Command Ship (4 of 8) type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Value", + src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Value", + src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Value", + src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration", + src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Value", + src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") diff --git a/eos/effects/elitebonuscommandshipinformationcs3.py b/eos/effects/elitebonuscommandshipinformationcs3.py index ffa02ba05..283cc76d6 100644 --- a/eos/effects/elitebonuscommandshipinformationcs3.py +++ b/eos/effects/elitebonuscommandshipinformationcs3.py @@ -3,9 +3,16 @@ # Used by: # Ships from group: Command Ship (4 of 8) type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "buffDuration", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff3Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff2Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff1Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff4Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "buffDuration", + src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff3Value", + src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff2Value", + src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff1Value", + src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff4Value", + src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") diff --git a/eos/effects/elitebonuscommandshipsiegecs3.py b/eos/effects/elitebonuscommandshipsiegecs3.py index 4e7395d21..a17eb44dc 100644 --- a/eos/effects/elitebonuscommandshipsiegecs3.py +++ b/eos/effects/elitebonuscommandshipsiegecs3.py @@ -3,9 +3,16 @@ # Used by: # Ships from group: Command Ship (4 of 8) type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff1Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff4Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff2Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "buffDuration", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff3Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff1Value", + src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff4Value", + src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff2Value", + src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "buffDuration", + src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff3Value", + src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") diff --git a/eos/effects/elitebonuscommandshipskirmishcs3.py b/eos/effects/elitebonuscommandshipskirmishcs3.py index 2c6d03add..345191164 100644 --- a/eos/effects/elitebonuscommandshipskirmishcs3.py +++ b/eos/effects/elitebonuscommandshipskirmishcs3.py @@ -3,9 +3,16 @@ # Used by: # Ships from group: Command Ship (4 of 8) type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff2Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff1Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff3Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff4Value", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "buffDuration", src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff2Value", + src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff1Value", + src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff3Value", + src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff4Value", + src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "buffDuration", + src.getModifiedItemAttr("eliteBonusCommandShips3"), skill="Command Ships") diff --git a/eos/effects/elitebonuscoveropsnosneutfalloff1.py b/eos/effects/elitebonuscoveropsnosneutfalloff1.py index df0711cac..aa5b5b558 100644 --- a/eos/effects/elitebonuscoveropsnosneutfalloff1.py +++ b/eos/effects/elitebonuscoveropsnosneutfalloff1.py @@ -3,7 +3,9 @@ # Used by: # Ship: Caedes type = "passive" + + def handler(fit, src, context): fit.modules.filteredItemBoost(lambda mod: mod.item.group.name in ("Energy Nosferatu", "Energy Neutralizer"), - "falloffEffectiveness", src.getModifiedItemAttr("eliteBonusCoverOps1"), stackingPenalties=True, skill="Covert Ops") - + "falloffEffectiveness", src.getModifiedItemAttr("eliteBonusCoverOps1"), + stackingPenalties=True, skill="Covert Ops") diff --git a/eos/effects/elitebonuslogisticremotearmorrepairduration3.py b/eos/effects/elitebonuslogisticremotearmorrepairduration3.py index d26ef3525..5c9b24c1c 100644 --- a/eos/effects/elitebonuslogisticremotearmorrepairduration3.py +++ b/eos/effects/elitebonuslogisticremotearmorrepairduration3.py @@ -3,5 +3,8 @@ # Used by: # Ship: Rabisu type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems"), "duration", src.getModifiedItemAttr("eliteBonusLogistics3"), skill="Logistics Cruisers") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems"), "duration", + src.getModifiedItemAttr("eliteBonusLogistics3"), skill="Logistics Cruisers") diff --git a/eos/effects/energyneutralizerfalloff.py b/eos/effects/energyneutralizerfalloff.py index 212f05ffa..e4c22c3fa 100644 --- a/eos/effects/energyneutralizerfalloff.py +++ b/eos/effects/energyneutralizerfalloff.py @@ -8,8 +8,8 @@ type = "active", "projected" def handler(fit, src, context): - if "projected" in context and ( - (hasattr(src, "state") and src.state >= State.ACTIVE) or hasattr(src, "amountActive")): + if "projected" in context and ((hasattr(src, "state") and src.state >= State.ACTIVE) or + hasattr(src, "amountActive")): amount = src.getModifiedItemAttr("energyNeutralizerAmount") time = src.getModifiedItemAttr("duration") diff --git a/eos/effects/entityenergyneutralizerfalloff.py b/eos/effects/entityenergyneutralizerfalloff.py index 0783295cf..a02abca12 100644 --- a/eos/effects/entityenergyneutralizerfalloff.py +++ b/eos/effects/entityenergyneutralizerfalloff.py @@ -8,8 +8,8 @@ type = "active", "projected" def handler(fit, src, context): - if "projected" in context and ( - (hasattr(src, "state") and src.state >= State.ACTIVE) or hasattr(src, "amountActive")): + if "projected" in context and ((hasattr(src, "state") and src.state >= State.ACTIVE) or + hasattr(src, "amountActive")): amount = src.getModifiedItemAttr("energyNeutralizerAmount") time = src.getModifiedItemAttr("energyNeutralizerDuration") diff --git a/eos/effects/iceharvestingdronespecbonus.py b/eos/effects/iceharvestingdronespecbonus.py index 6fee3f685..18af9f3b1 100644 --- a/eos/effects/iceharvestingdronespecbonus.py +++ b/eos/effects/iceharvestingdronespecbonus.py @@ -3,7 +3,11 @@ # Used by: # Skill: Ice Harvesting Drone Specialization type = "passive" + + def handler(fit, src, context): lvl = src.level - fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Ice Harvesting Drone Specialization"), "duration", src.getModifiedItemAttr("rofBonus") * lvl) - fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Ice Harvesting Drone Specialization"), "maxVelocity", src.getModifiedItemAttr("maxVelocityBonus") * lvl) + fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Ice Harvesting Drone Specialization"), "duration", + src.getModifiedItemAttr("rofBonus") * lvl) + fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Ice Harvesting Drone Specialization"), + "maxVelocity", src.getModifiedItemAttr("maxVelocityBonus") * lvl) diff --git a/eos/effects/industrialbonusdronedamage.py b/eos/effects/industrialbonusdronedamage.py index db3fba01d..f6c5137bd 100644 --- a/eos/effects/industrialbonusdronedamage.py +++ b/eos/effects/industrialbonusdronedamage.py @@ -11,8 +11,8 @@ # Ship: Rorqual type = "passive" + def handler(fit, src, context): fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Drones"), "damageMultiplier", src.getModifiedItemAttr("industrialBonusDroneDamage")) - diff --git a/eos/effects/informationcommanddurationbonus.py b/eos/effects/informationcommanddurationbonus.py index 2235cde74..f5a7dc351 100644 --- a/eos/effects/informationcommanddurationbonus.py +++ b/eos/effects/informationcommanddurationbonus.py @@ -3,6 +3,9 @@ # Used by: # Skill: Information Command type = "passive" + + def handler(fit, src, context): lvl = src.level - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "buffDuration", src.getModifiedItemAttr("durationBonus") * lvl) + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "buffDuration", + src.getModifiedItemAttr("durationBonus") * lvl) diff --git a/eos/effects/informationcommandmindlink.py b/eos/effects/informationcommandmindlink.py index a4551304d..f545ab629 100644 --- a/eos/effects/informationcommandmindlink.py +++ b/eos/effects/informationcommandmindlink.py @@ -5,9 +5,16 @@ # Implant: Imperial Navy Command Mindlink # Implant: Information Command Mindlink type = "passive" + + def handler(fit, src, context): - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff4Multiplier", src.getModifiedItemAttr("mindlinkBonus")) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff3Multiplier", src.getModifiedItemAttr("mindlinkBonus")) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff1Multiplier", src.getModifiedItemAttr("mindlinkBonus")) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff2Multiplier", src.getModifiedItemAttr("mindlinkBonus")) - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "buffDuration", src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff4Multiplier", + src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff3Multiplier", + src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff1Multiplier", + src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff2Multiplier", + src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "buffDuration", + src.getModifiedItemAttr("mindlinkBonus")) diff --git a/eos/effects/informationcommandstrengthbonus.py b/eos/effects/informationcommandstrengthbonus.py index 04f17d646..e4431bee0 100644 --- a/eos/effects/informationcommandstrengthbonus.py +++ b/eos/effects/informationcommandstrengthbonus.py @@ -3,9 +3,15 @@ # Used by: # Skill: Information Command Specialist type = "passive" + + def handler(fit, src, context): lvl = src.level - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff2Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff1Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff3Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff4Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff2Multiplier", + src.getModifiedItemAttr("commandStrengthBonus") * lvl) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff1Multiplier", + src.getModifiedItemAttr("commandStrengthBonus") * lvl) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff3Multiplier", + src.getModifiedItemAttr("commandStrengthBonus") * lvl) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff4Multiplier", + src.getModifiedItemAttr("commandStrengthBonus") * lvl) diff --git a/eos/effects/invulnerabilitycoredurationbonus.py b/eos/effects/invulnerabilitycoredurationbonus.py index 8d4165859..b318f11cb 100644 --- a/eos/effects/invulnerabilitycoredurationbonus.py +++ b/eos/effects/invulnerabilitycoredurationbonus.py @@ -3,7 +3,11 @@ # Used by: # Skill: Invulnerability Core Operation type = "passive" + + def handler(fit, src, context): lvl = src.level - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Invulnerability Core Operation"), "buffDuration", src.getModifiedItemAttr("durationBonus") * lvl) - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Invulnerability Core Operation"), "duration", src.getModifiedItemAttr("durationBonus") * lvl) + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Invulnerability Core Operation"), "buffDuration", + src.getModifiedItemAttr("durationBonus") * lvl) + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Invulnerability Core Operation"), "duration", + src.getModifiedItemAttr("durationBonus") * lvl) diff --git a/eos/effects/miningdronespecbonus.py b/eos/effects/miningdronespecbonus.py index 17c36723c..fe8cdff5a 100644 --- a/eos/effects/miningdronespecbonus.py +++ b/eos/effects/miningdronespecbonus.py @@ -3,7 +3,11 @@ # Used by: # Skill: Mining Drone Specialization type = "passive" + + def handler(fit, src, context): lvl = src.level - fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Drone Specialization"), "miningAmount", src.getModifiedItemAttr("miningAmountBonus") * lvl) - fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Drone Specialization"), "maxVelocity", src.getModifiedItemAttr("maxVelocityBonus") * lvl) + fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Drone Specialization"), "miningAmount", + src.getModifiedItemAttr("miningAmountBonus") * lvl) + fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Drone Specialization"), "maxVelocity", + src.getModifiedItemAttr("maxVelocityBonus") * lvl) diff --git a/eos/effects/miningforemanburstbonusics2.py b/eos/effects/miningforemanburstbonusics2.py index a2664b025..485138a26 100644 --- a/eos/effects/miningforemanburstbonusics2.py +++ b/eos/effects/miningforemanburstbonusics2.py @@ -3,9 +3,16 @@ # Used by: # Ships from group: Industrial Command Ship (2 of 2) type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff4Multiplier", src.getModifiedItemAttr("shipBonusICS2"), skill="Industrial Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff1Multiplier", src.getModifiedItemAttr("shipBonusICS2"), skill="Industrial Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "buffDuration", src.getModifiedItemAttr("shipBonusICS2"), skill="Industrial Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff3Multiplier", src.getModifiedItemAttr("shipBonusICS2"), skill="Industrial Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff2Multiplier", src.getModifiedItemAttr("shipBonusICS2"), skill="Industrial Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff4Multiplier", + src.getModifiedItemAttr("shipBonusICS2"), skill="Industrial Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff1Multiplier", + src.getModifiedItemAttr("shipBonusICS2"), skill="Industrial Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "buffDuration", + src.getModifiedItemAttr("shipBonusICS2"), skill="Industrial Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff3Multiplier", + src.getModifiedItemAttr("shipBonusICS2"), skill="Industrial Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff2Multiplier", + src.getModifiedItemAttr("shipBonusICS2"), skill="Industrial Command Ships") diff --git a/eos/effects/miningforemanburstbonusorecapital2.py b/eos/effects/miningforemanburstbonusorecapital2.py index e66243732..b1e7f4b57 100644 --- a/eos/effects/miningforemanburstbonusorecapital2.py +++ b/eos/effects/miningforemanburstbonusorecapital2.py @@ -3,9 +3,16 @@ # Used by: # Ship: Rorqual type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff1Multiplier", src.getModifiedItemAttr("shipBonusORECapital2"), skill="Capital Industrial Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff2Multiplier", src.getModifiedItemAttr("shipBonusORECapital2"), skill="Capital Industrial Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff4Multiplier", src.getModifiedItemAttr("shipBonusORECapital2"), skill="Capital Industrial Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff3Multiplier", src.getModifiedItemAttr("shipBonusORECapital2"), skill="Capital Industrial Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "buffDuration", src.getModifiedItemAttr("shipBonusORECapital2"), skill="Capital Industrial Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff1Multiplier", + src.getModifiedItemAttr("shipBonusORECapital2"), skill="Capital Industrial Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff2Multiplier", + src.getModifiedItemAttr("shipBonusORECapital2"), skill="Capital Industrial Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff4Multiplier", + src.getModifiedItemAttr("shipBonusORECapital2"), skill="Capital Industrial Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff3Multiplier", + src.getModifiedItemAttr("shipBonusORECapital2"), skill="Capital Industrial Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "buffDuration", + src.getModifiedItemAttr("shipBonusORECapital2"), skill="Capital Industrial Ships") diff --git a/eos/effects/miningforemandurationbonus.py b/eos/effects/miningforemandurationbonus.py index 88f33e00a..14a290d2e 100644 --- a/eos/effects/miningforemandurationbonus.py +++ b/eos/effects/miningforemandurationbonus.py @@ -3,6 +3,9 @@ # Used by: # Skill: Mining Foreman type = "passive" + + def handler(fit, src, context): lvl = src.level - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "buffDuration", src.getModifiedItemAttr("durationBonus") * lvl) + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "buffDuration", + src.getModifiedItemAttr("durationBonus") * lvl) diff --git a/eos/effects/miningforemanmindlink.py b/eos/effects/miningforemanmindlink.py index e8d89bdd7..ad4339f67 100644 --- a/eos/effects/miningforemanmindlink.py +++ b/eos/effects/miningforemanmindlink.py @@ -4,9 +4,16 @@ # Implant: Mining Foreman Mindlink # Implant: ORE Mining Director Mindlink type = "passive" + + def handler(fit, src, context): - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff4Multiplier", src.getModifiedItemAttr("mindlinkBonus")) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff2Multiplier", src.getModifiedItemAttr("mindlinkBonus")) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff1Multiplier", src.getModifiedItemAttr("mindlinkBonus")) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff3Multiplier", src.getModifiedItemAttr("mindlinkBonus")) - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "buffDuration", src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff4Multiplier", + src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff2Multiplier", + src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff1Multiplier", + src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff3Multiplier", + src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "buffDuration", + src.getModifiedItemAttr("mindlinkBonus")) diff --git a/eos/effects/mininginfomultiplier.py b/eos/effects/mininginfomultiplier.py index d0ca12180..6cb722d76 100644 --- a/eos/effects/mininginfomultiplier.py +++ b/eos/effects/mininginfomultiplier.py @@ -7,5 +7,6 @@ type = "passive" def handler(fit, module, context): - module.multiplyItemAttr("specialtyMiningAmount", module.getModifiedChargeAttr("specialisationAsteroidYieldMultiplier")) - #module.multiplyItemAttr("miningAmount", module.getModifiedChargeAttr("specialisationAsteroidYieldMultiplier")) + module.multiplyItemAttr("specialtyMiningAmount", + module.getModifiedChargeAttr("specialisationAsteroidYieldMultiplier")) + # module.multiplyItemAttr("miningAmount", module.getModifiedChargeAttr("specialisationAsteroidYieldMultiplier")) diff --git a/eos/effects/modedamptdresistspostdiv.py b/eos/effects/modedamptdresistspostdiv.py index db8580229..891b84a82 100644 --- a/eos/effects/modedamptdresistspostdiv.py +++ b/eos/effects/modedamptdresistspostdiv.py @@ -4,6 +4,7 @@ # Modules named like: Sharpshooter Mode (4 of 4) type = "passive" + def handler(fit, module, context): fit.ship.multiplyItemAttr("weaponDisruptionResistance", 1 / module.getModifiedItemAttr("modeEwarResistancePostDiv")) fit.ship.multiplyItemAttr("sensorDampenerResistance", 1 / module.getModifiedItemAttr("modeEwarResistancePostDiv")) diff --git a/eos/effects/modulebonusafterburner.py b/eos/effects/modulebonusafterburner.py index e48bdb437..c26412bb0 100644 --- a/eos/effects/modulebonusafterburner.py +++ b/eos/effects/modulebonusafterburner.py @@ -11,4 +11,4 @@ def handler(fit, module, context): speedBoost = module.getModifiedItemAttr("speedFactor") mass = fit.ship.getModifiedItemAttr("mass") thrust = module.getModifiedItemAttr("speedBoostFactor") - fit.ship.boostItemAttr("maxVelocity", speedBoost * thrust / mass) \ No newline at end of file + fit.ship.boostItemAttr("maxVelocity", speedBoost * thrust / mass) diff --git a/eos/effects/modulebonusancillaryremotearmorrepairer.py b/eos/effects/modulebonusancillaryremotearmorrepairer.py index c3c157b81..78a6ef855 100644 --- a/eos/effects/modulebonusancillaryremotearmorrepairer.py +++ b/eos/effects/modulebonusancillaryremotearmorrepairer.py @@ -7,7 +7,8 @@ type = "projected", "active" def handler(fit, module, context): - if "projected" not in context: return + if "projected" not in context: + return if module.charge and module.charge.name == "Nanite Repair Paste": multiplier = 3 diff --git a/eos/effects/modulebonusancillaryremoteshieldbooster.py b/eos/effects/modulebonusancillaryremoteshieldbooster.py index 74443b269..99b1a444c 100644 --- a/eos/effects/modulebonusancillaryremoteshieldbooster.py +++ b/eos/effects/modulebonusancillaryremoteshieldbooster.py @@ -7,7 +7,8 @@ type = "projected", "active" def handler(fit, module, context): - if "projected" not in context: return + if "projected" not in context: + return amount = module.getModifiedItemAttr("shieldBonus") speed = module.getModifiedItemAttr("duration") / 1000.0 fit.extraAttributes.increase("shieldRepair", amount / speed) diff --git a/eos/effects/modulebonusmicrowarpdrive.py b/eos/effects/modulebonusmicrowarpdrive.py index 2c4f6cd91..75df915ce 100644 --- a/eos/effects/modulebonusmicrowarpdrive.py +++ b/eos/effects/modulebonusmicrowarpdrive.py @@ -12,4 +12,5 @@ def handler(fit, module, context): mass = fit.ship.getModifiedItemAttr("mass") thrust = module.getModifiedItemAttr("speedBoostFactor") fit.ship.boostItemAttr("maxVelocity", speedBoost * thrust / mass) - fit.ship.boostItemAttr("signatureRadius", module.getModifiedItemAttr("signatureRadiusBonus"), stackingPenalties = True) + fit.ship.boostItemAttr("signatureRadius", module.getModifiedItemAttr("signatureRadiusBonus"), + stackingPenalties=True) diff --git a/eos/effects/noscpuneedbonuseffect.py b/eos/effects/noscpuneedbonuseffect.py index 9f92b373c..d54b6e023 100644 --- a/eos/effects/noscpuneedbonuseffect.py +++ b/eos/effects/noscpuneedbonuseffect.py @@ -3,5 +3,8 @@ # Used by: # Ship: Rabisu type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Energy Nosferatu", "cpu", src.getModifiedItemAttr("nosferatuCpuNeedBonus")) + fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Energy Nosferatu", "cpu", + src.getModifiedItemAttr("nosferatuCpuNeedBonus")) diff --git a/eos/effects/powerbooster.py b/eos/effects/powerbooster.py index 6fdafc9a4..42dcaca89 100644 --- a/eos/effects/powerbooster.py +++ b/eos/effects/powerbooster.py @@ -11,6 +11,7 @@ def handler(fit, module, context): # Make so that reloads are always taken into account during clculations module.forceReload = True - if module.charge is None: return + if module.charge is None: + return capAmount = module.getModifiedChargeAttr("capacitorBonus") or 0 module.itemModifiedAttributes["capacitorNeed"] = -capAmount diff --git a/eos/effects/remotehullrepairentity.py b/eos/effects/remotehullrepairentity.py index db8de5fe4..367d08bf1 100644 --- a/eos/effects/remotehullrepairentity.py +++ b/eos/effects/remotehullrepairentity.py @@ -7,7 +7,8 @@ runTime = "late" def handler(fit, module, context): - if "projected" not in context: return + if "projected" not in context: + return bonus = module.getModifiedItemAttr("structureDamageAmount") duration = module.getModifiedItemAttr("duration") / 1000.0 fit.extraAttributes.increase("hullRepair", bonus / duration) diff --git a/eos/effects/remotehullrepairfalloff.py b/eos/effects/remotehullrepairfalloff.py index d7344b646..eaecf6bf9 100644 --- a/eos/effects/remotehullrepairfalloff.py +++ b/eos/effects/remotehullrepairfalloff.py @@ -7,7 +7,8 @@ runTime = "late" def handler(fit, module, context): - if "projected" not in context: return + if "projected" not in context: + return bonus = module.getModifiedItemAttr("structureDamageAmount") duration = module.getModifiedItemAttr("duration") / 1000.0 fit.extraAttributes.increase("hullRepair", bonus / duration) diff --git a/eos/effects/remotewebifierentity.py b/eos/effects/remotewebifierentity.py index 38028881a..cf9905405 100644 --- a/eos/effects/remotewebifierentity.py +++ b/eos/effects/remotewebifierentity.py @@ -6,6 +6,7 @@ type = "active", "projected" def handler(fit, module, context): - if "projected" not in context: return + if "projected" not in context: + return fit.ship.boostItemAttr("maxVelocity", module.getModifiedItemAttr("speedFactor"), stackingPenalties=True, remoteResists=True) diff --git a/eos/effects/remotewebifierfalloff.py b/eos/effects/remotewebifierfalloff.py index 67f6d4dc5..1db5eb858 100644 --- a/eos/effects/remotewebifierfalloff.py +++ b/eos/effects/remotewebifierfalloff.py @@ -7,6 +7,7 @@ type = "active", "projected" def handler(fit, module, context): - if "projected" not in context: return + if "projected" not in context: + return fit.ship.boostItemAttr("maxVelocity", module.getModifiedItemAttr("speedFactor"), stackingPenalties=True, remoteResists=True) diff --git a/eos/effects/setbonusasklepian.py b/eos/effects/setbonusasklepian.py index 4bd989f13..5d063f470 100644 --- a/eos/effects/setbonusasklepian.py +++ b/eos/effects/setbonusasklepian.py @@ -1,8 +1,8 @@ # setBonusAsklepian # # Used by: -# Implants named like: Asklepian Omega (3 of 3) # Implants named like: Grade Asklepian (16 of 16) +# Implants named like: grade Asklepian Omega (2 of 2) runTime = "early" type = "passive" diff --git a/eos/effects/shieldcommandburstbonusics3.py b/eos/effects/shieldcommandburstbonusics3.py index 9c6ee1541..1a61286b7 100644 --- a/eos/effects/shieldcommandburstbonusics3.py +++ b/eos/effects/shieldcommandburstbonusics3.py @@ -3,9 +3,16 @@ # Used by: # Ship: Orca type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff4Multiplier", src.getModifiedItemAttr("shipBonusICS3"), skill="Industrial Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff1Multiplier", src.getModifiedItemAttr("shipBonusICS3"), skill="Industrial Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff2Multiplier", src.getModifiedItemAttr("shipBonusICS3"), skill="Industrial Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff3Multiplier", src.getModifiedItemAttr("shipBonusICS3"), skill="Industrial Command Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "buffDuration", src.getModifiedItemAttr("shipBonusICS3"), skill="Industrial Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff4Multiplier", + src.getModifiedItemAttr("shipBonusICS3"), skill="Industrial Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff1Multiplier", + src.getModifiedItemAttr("shipBonusICS3"), skill="Industrial Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff2Multiplier", + src.getModifiedItemAttr("shipBonusICS3"), skill="Industrial Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff3Multiplier", + src.getModifiedItemAttr("shipBonusICS3"), skill="Industrial Command Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "buffDuration", + src.getModifiedItemAttr("shipBonusICS3"), skill="Industrial Command Ships") diff --git a/eos/effects/shieldcommandburstbonusorecapital3.py b/eos/effects/shieldcommandburstbonusorecapital3.py index 595d7afae..5972f2044 100644 --- a/eos/effects/shieldcommandburstbonusorecapital3.py +++ b/eos/effects/shieldcommandburstbonusorecapital3.py @@ -3,9 +3,16 @@ # Used by: # Ship: Rorqual type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff4Multiplier", src.getModifiedItemAttr("shipBonusORECapital3"), skill="Capital Industrial Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "buffDuration", src.getModifiedItemAttr("shipBonusORECapital3"), skill="Capital Industrial Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff1Multiplier", src.getModifiedItemAttr("shipBonusORECapital3"), skill="Capital Industrial Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff3Multiplier", src.getModifiedItemAttr("shipBonusORECapital3"), skill="Capital Industrial Ships") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff2Multiplier", src.getModifiedItemAttr("shipBonusORECapital3"), skill="Capital Industrial Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff4Multiplier", + src.getModifiedItemAttr("shipBonusORECapital3"), skill="Capital Industrial Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "buffDuration", + src.getModifiedItemAttr("shipBonusORECapital3"), skill="Capital Industrial Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff1Multiplier", + src.getModifiedItemAttr("shipBonusORECapital3"), skill="Capital Industrial Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff3Multiplier", + src.getModifiedItemAttr("shipBonusORECapital3"), skill="Capital Industrial Ships") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff2Multiplier", + src.getModifiedItemAttr("shipBonusORECapital3"), skill="Capital Industrial Ships") diff --git a/eos/effects/shieldcommanddurationbonus.py b/eos/effects/shieldcommanddurationbonus.py index 8e7c78ea5..a7425a974 100644 --- a/eos/effects/shieldcommanddurationbonus.py +++ b/eos/effects/shieldcommanddurationbonus.py @@ -3,6 +3,9 @@ # Used by: # Skill: Shield Command type = "passive" + + def handler(fit, src, context): lvl = src.level - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "buffDuration", src.getModifiedItemAttr("durationBonus") * lvl) + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "buffDuration", + src.getModifiedItemAttr("durationBonus") * lvl) diff --git a/eos/effects/shieldcommandmindlink.py b/eos/effects/shieldcommandmindlink.py index a350e5c29..fac7a7720 100644 --- a/eos/effects/shieldcommandmindlink.py +++ b/eos/effects/shieldcommandmindlink.py @@ -3,9 +3,16 @@ # Used by: # Implants from group: Cyber Leadership (4 of 10) type = "passive" + + def handler(fit, src, context): - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff4Multiplier", src.getModifiedItemAttr("mindlinkBonus")) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff3Multiplier", src.getModifiedItemAttr("mindlinkBonus")) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff2Multiplier", src.getModifiedItemAttr("mindlinkBonus")) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff1Multiplier", src.getModifiedItemAttr("mindlinkBonus")) - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "buffDuration", src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff4Multiplier", + src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff3Multiplier", + src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff2Multiplier", + src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff1Multiplier", + src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "buffDuration", + src.getModifiedItemAttr("mindlinkBonus")) diff --git a/eos/effects/shieldcommandstrengthbonus.py b/eos/effects/shieldcommandstrengthbonus.py index 775e54d62..b95fe66df 100644 --- a/eos/effects/shieldcommandstrengthbonus.py +++ b/eos/effects/shieldcommandstrengthbonus.py @@ -3,9 +3,15 @@ # Used by: # Skill: Shield Command Specialist type = "passive" + + def handler(fit, src, context): lvl = src.level - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff3Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff1Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff2Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff4Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff3Multiplier", + src.getModifiedItemAttr("commandStrengthBonus") * lvl) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff1Multiplier", + src.getModifiedItemAttr("commandStrengthBonus") * lvl) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff2Multiplier", + src.getModifiedItemAttr("commandStrengthBonus") * lvl) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff4Multiplier", + src.getModifiedItemAttr("commandStrengthBonus") * lvl) diff --git a/eos/effects/shipbonuscarriera4warfarelinksbonus.py b/eos/effects/shipbonuscarriera4warfarelinksbonus.py index 43a053e04..31981bba6 100644 --- a/eos/effects/shipbonuscarriera4warfarelinksbonus.py +++ b/eos/effects/shipbonuscarriera4warfarelinksbonus.py @@ -3,9 +3,21 @@ # Used by: # Ship: Archon type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command") or mod.item.requiresSkill("Information Command"), "buffDuration", src.getModifiedItemAttr("shipBonusCarrierA4"), skill="Amarr Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command") or mod.item.requiresSkill("Information Command"), "warfareBuff3Value", src.getModifiedItemAttr("shipBonusCarrierA4"), skill="Amarr Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command") or mod.item.requiresSkill("Information Command"), "warfareBuff1Value", src.getModifiedItemAttr("shipBonusCarrierA4"), skill="Amarr Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command") or mod.item.requiresSkill("Information Command"), "warfareBuff4Value", src.getModifiedItemAttr("shipBonusCarrierA4"), skill="Amarr Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command") or mod.item.requiresSkill("Information Command"), "warfareBuff2Value", src.getModifiedItemAttr("shipBonusCarrierA4"), skill="Amarr Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Armored Command") or mod.item.requiresSkill("Information Command"), + "buffDuration", src.getModifiedItemAttr("shipBonusCarrierA4"), skill="Amarr Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Armored Command") or mod.item.requiresSkill("Information Command"), + "warfareBuff3Value", src.getModifiedItemAttr("shipBonusCarrierA4"), skill="Amarr Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Armored Command") or mod.item.requiresSkill("Information Command"), + "warfareBuff1Value", src.getModifiedItemAttr("shipBonusCarrierA4"), skill="Amarr Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Armored Command") or mod.item.requiresSkill("Information Command"), + "warfareBuff4Value", src.getModifiedItemAttr("shipBonusCarrierA4"), skill="Amarr Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Armored Command") or mod.item.requiresSkill("Information Command"), + "warfareBuff2Value", src.getModifiedItemAttr("shipBonusCarrierA4"), skill="Amarr Carrier") diff --git a/eos/effects/shipbonuscarrierc4warfarelinksbonus.py b/eos/effects/shipbonuscarrierc4warfarelinksbonus.py index ecaf23399..4e19f6916 100644 --- a/eos/effects/shipbonuscarrierc4warfarelinksbonus.py +++ b/eos/effects/shipbonuscarrierc4warfarelinksbonus.py @@ -3,9 +3,21 @@ # Used by: # Ship: Chimera type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), "warfareBuff2Value", src.getModifiedItemAttr("shipBonusCarrierC4"), skill="Caldari Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), "buffDuration", src.getModifiedItemAttr("shipBonusCarrierC4"), skill="Caldari Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), "warfareBuff3Value", src.getModifiedItemAttr("shipBonusCarrierC4"), skill="Caldari Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), "warfareBuff4Value", src.getModifiedItemAttr("shipBonusCarrierC4"), skill="Caldari Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), "warfareBuff1Value", src.getModifiedItemAttr("shipBonusCarrierC4"), skill="Caldari Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), + "warfareBuff2Value", src.getModifiedItemAttr("shipBonusCarrierC4"), skill="Caldari Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), + "buffDuration", src.getModifiedItemAttr("shipBonusCarrierC4"), skill="Caldari Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), + "warfareBuff3Value", src.getModifiedItemAttr("shipBonusCarrierC4"), skill="Caldari Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), + "warfareBuff4Value", src.getModifiedItemAttr("shipBonusCarrierC4"), skill="Caldari Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), + "warfareBuff1Value", src.getModifiedItemAttr("shipBonusCarrierC4"), skill="Caldari Carrier") diff --git a/eos/effects/shipbonuscarrierg4warfarelinksbonus.py b/eos/effects/shipbonuscarrierg4warfarelinksbonus.py index 673807782..05eb85c60 100644 --- a/eos/effects/shipbonuscarrierg4warfarelinksbonus.py +++ b/eos/effects/shipbonuscarrierg4warfarelinksbonus.py @@ -3,9 +3,21 @@ # Used by: # Ship: Thanatos type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), "warfareBuff2Value", src.getModifiedItemAttr("shipBonusCarrierG4"), skill="Gallente Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), "warfareBuff3Value", src.getModifiedItemAttr("shipBonusCarrierG4"), skill="Gallente Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), "warfareBuff4Value", src.getModifiedItemAttr("shipBonusCarrierG4"), skill="Gallente Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), "buffDuration", src.getModifiedItemAttr("shipBonusCarrierG4"), skill="Gallente Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), "warfareBuff1Value", src.getModifiedItemAttr("shipBonusCarrierG4"), skill="Gallente Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), + "warfareBuff2Value", src.getModifiedItemAttr("shipBonusCarrierG4"), skill="Gallente Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), + "warfareBuff3Value", src.getModifiedItemAttr("shipBonusCarrierG4"), skill="Gallente Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), + "warfareBuff4Value", src.getModifiedItemAttr("shipBonusCarrierG4"), skill="Gallente Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), + "buffDuration", src.getModifiedItemAttr("shipBonusCarrierG4"), skill="Gallente Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), + "warfareBuff1Value", src.getModifiedItemAttr("shipBonusCarrierG4"), skill="Gallente Carrier") diff --git a/eos/effects/shipbonuscarrierm4warfarelinksbonus.py b/eos/effects/shipbonuscarrierm4warfarelinksbonus.py index 36fbbfa01..11592c9df 100644 --- a/eos/effects/shipbonuscarrierm4warfarelinksbonus.py +++ b/eos/effects/shipbonuscarrierm4warfarelinksbonus.py @@ -3,9 +3,21 @@ # Used by: # Ship: Nidhoggur type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), "warfareBuff4Value", src.getModifiedItemAttr("shipBonusCarrierM4"), skill="Minmatar Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), "warfareBuff2Value", src.getModifiedItemAttr("shipBonusCarrierM4"), skill="Minmatar Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), "warfareBuff3Value", src.getModifiedItemAttr("shipBonusCarrierM4"), skill="Minmatar Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), "warfareBuff1Value", src.getModifiedItemAttr("shipBonusCarrierM4"), skill="Minmatar Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), "buffDuration", src.getModifiedItemAttr("shipBonusCarrierM4"), skill="Minmatar Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), + "warfareBuff4Value", src.getModifiedItemAttr("shipBonusCarrierM4"), skill="Minmatar Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), + "warfareBuff2Value", src.getModifiedItemAttr("shipBonusCarrierM4"), skill="Minmatar Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), + "warfareBuff3Value", src.getModifiedItemAttr("shipBonusCarrierM4"), skill="Minmatar Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), + "warfareBuff1Value", src.getModifiedItemAttr("shipBonusCarrierM4"), skill="Minmatar Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), + "buffDuration", src.getModifiedItemAttr("shipBonusCarrierM4"), skill="Minmatar Carrier") diff --git a/eos/effects/shipbonuscloakcpumc2.py b/eos/effects/shipbonuscloakcpumc2.py index 0f8c90e35..ac83921f0 100644 --- a/eos/effects/shipbonuscloakcpumc2.py +++ b/eos/effects/shipbonuscloakcpumc2.py @@ -3,5 +3,8 @@ # Used by: # Ship: Rabisu type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Cloaking"), "cpu", src.getModifiedItemAttr("shipBonusMC2"), skill="Minmatar Cruiser") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Cloaking"), "cpu", + src.getModifiedItemAttr("shipBonusMC2"), skill="Minmatar Cruiser") diff --git a/eos/effects/shipbonuscloakcpumf1.py b/eos/effects/shipbonuscloakcpumf1.py index 62a6d0aa7..fe201e1df 100644 --- a/eos/effects/shipbonuscloakcpumf1.py +++ b/eos/effects/shipbonuscloakcpumf1.py @@ -3,5 +3,8 @@ # Used by: # Ship: Caedes type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Cloaking"), "cpu", src.getModifiedItemAttr("shipBonusMF"), skill="Minmatar Frigate") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Cloaking"), "cpu", + src.getModifiedItemAttr("shipBonusMF"), skill="Minmatar Frigate") diff --git a/eos/effects/shipbonusdronehpdamageminingics4.py b/eos/effects/shipbonusdronehpdamageminingics4.py index c8d49571f..8b06c6dec 100644 --- a/eos/effects/shipbonusdronehpdamageminingics4.py +++ b/eos/effects/shipbonusdronehpdamageminingics4.py @@ -35,4 +35,3 @@ def handler(fit, src, context): src.getModifiedItemAttr("shipBonusICS4"), skill="Industrial Command Ships" ) - diff --git a/eos/effects/shipbonusdronehpdamageminingorecapital4.py b/eos/effects/shipbonusdronehpdamageminingorecapital4.py index 1b5ed13f5..8cd53cd81 100644 --- a/eos/effects/shipbonusdronehpdamageminingorecapital4.py +++ b/eos/effects/shipbonusdronehpdamageminingorecapital4.py @@ -35,4 +35,3 @@ def handler(fit, src, context): src.getModifiedItemAttr("shipBonusORECapital4"), skill="Capital Industrial Ships" ) - diff --git a/eos/effects/shipbonusdroneiceharvestingrole.py b/eos/effects/shipbonusdroneiceharvestingrole.py index 010fbea1b..b45241f9f 100644 --- a/eos/effects/shipbonusdroneiceharvestingrole.py +++ b/eos/effects/shipbonusdroneiceharvestingrole.py @@ -3,5 +3,8 @@ # Used by: # Ship: Orca type = "passive" + + def handler(fit, src, context): - fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Ice Harvesting Drone Operation"), "duration", src.getModifiedItemAttr("roleBonusDroneIceHarvestingSpeed")) + fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Ice Harvesting Drone Operation"), "duration", + src.getModifiedItemAttr("roleBonusDroneIceHarvestingSpeed")) diff --git a/eos/effects/shipbonusdronerepairmc1.py b/eos/effects/shipbonusdronerepairmc1.py index baaff71f5..77cc9a69d 100644 --- a/eos/effects/shipbonusdronerepairmc1.py +++ b/eos/effects/shipbonusdronerepairmc1.py @@ -3,7 +3,12 @@ # Used by: # Ship: Rabisu type = "passive" + + def handler(fit, src, context): - fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Drones"), "shieldBonus", src.getModifiedItemAttr("shipBonusMC"), skill="Minmatar Cruiser") - fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Drones"), "structureDamageAmount", src.getModifiedItemAttr("shipBonusMC"), skill="Minmatar Cruiser") - fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Drones"), "armorDamageAmount", src.getModifiedItemAttr("shipBonusMC"), skill="Minmatar Cruiser") + fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Drones"), "shieldBonus", + src.getModifiedItemAttr("shipBonusMC"), skill="Minmatar Cruiser") + fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Drones"), "structureDamageAmount", + src.getModifiedItemAttr("shipBonusMC"), skill="Minmatar Cruiser") + fit.drones.filteredItemBoost(lambda mod: mod.item.requiresSkill("Drones"), "armorDamageAmount", + src.getModifiedItemAttr("shipBonusMC"), skill="Minmatar Cruiser") diff --git a/eos/effects/shipbonusforceauxiliaryc4warfarelinksbonus.py b/eos/effects/shipbonusforceauxiliaryc4warfarelinksbonus.py index e2e6cd483..fda300de2 100644 --- a/eos/effects/shipbonusforceauxiliaryc4warfarelinksbonus.py +++ b/eos/effects/shipbonusforceauxiliaryc4warfarelinksbonus.py @@ -3,9 +3,21 @@ # Used by: # Ship: Minokawa type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), "warfareBuff3Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryC4"), skill="Caldari Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), "warfareBuff4Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryC4"), skill="Caldari Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), "warfareBuff2Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryC4"), skill="Caldari Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), "buffDuration", src.getModifiedItemAttr("shipBonusForceAuxiliaryC4"), skill="Caldari Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), "warfareBuff1Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryC4"), skill="Caldari Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), + "warfareBuff3Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryC4"), skill="Caldari Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), + "warfareBuff4Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryC4"), skill="Caldari Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), + "warfareBuff2Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryC4"), skill="Caldari Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), + "buffDuration", src.getModifiedItemAttr("shipBonusForceAuxiliaryC4"), skill="Caldari Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), + "warfareBuff1Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryC4"), skill="Caldari Carrier") diff --git a/eos/effects/shipbonusforceauxiliaryg4warfarelinksbonus.py b/eos/effects/shipbonusforceauxiliaryg4warfarelinksbonus.py index 147ae8df0..63efca50e 100644 --- a/eos/effects/shipbonusforceauxiliaryg4warfarelinksbonus.py +++ b/eos/effects/shipbonusforceauxiliaryg4warfarelinksbonus.py @@ -3,9 +3,21 @@ # Used by: # Ship: Ninazu type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), "warfareBuff3Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryG4"), skill="Gallente Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), "warfareBuff4Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryG4"), skill="Gallente Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), "buffDuration", src.getModifiedItemAttr("shipBonusForceAuxiliaryG4"), skill="Gallente Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), "warfareBuff2Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryG4"), skill="Gallente Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), "warfareBuff1Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryG4"), skill="Gallente Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), + "warfareBuff3Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryG4"), skill="Gallente Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), + "warfareBuff4Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryG4"), skill="Gallente Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), + "buffDuration", src.getModifiedItemAttr("shipBonusForceAuxiliaryG4"), skill="Gallente Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), + "warfareBuff2Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryG4"), skill="Gallente Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), + "warfareBuff1Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryG4"), skill="Gallente Carrier") diff --git a/eos/effects/shipbonusforceauxiliarym4warfarelinksbonus.py b/eos/effects/shipbonusforceauxiliarym4warfarelinksbonus.py index 0c476942a..df5b5181b 100644 --- a/eos/effects/shipbonusforceauxiliarym4warfarelinksbonus.py +++ b/eos/effects/shipbonusforceauxiliarym4warfarelinksbonus.py @@ -3,9 +3,21 @@ # Used by: # Ship: Lif type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), "warfareBuff3Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryM4"), skill="Minmatar Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), "warfareBuff2Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryM4"), skill="Minmatar Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), "warfareBuff1Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryM4"), skill="Minmatar Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), "buffDuration", src.getModifiedItemAttr("shipBonusForceAuxiliaryM4"), skill="Minmatar Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), "warfareBuff4Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryM4"), skill="Minmatar Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), + "warfareBuff3Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryM4"), skill="Minmatar Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), + "warfareBuff2Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryM4"), skill="Minmatar Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), + "warfareBuff1Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryM4"), skill="Minmatar Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), + "buffDuration", src.getModifiedItemAttr("shipBonusForceAuxiliaryM4"), skill="Minmatar Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), + "warfareBuff4Value", src.getModifiedItemAttr("shipBonusForceAuxiliaryM4"), skill="Minmatar Carrier") diff --git a/eos/effects/shipbonusminingdroneamountpercentrookie.py b/eos/effects/shipbonusminingdroneamountpercentrookie.py index ddffa24e9..bffbe6b81 100644 --- a/eos/effects/shipbonusminingdroneamountpercentrookie.py +++ b/eos/effects/shipbonusminingdroneamountpercentrookie.py @@ -8,6 +8,5 @@ type = "passive" def handler(fit, container, context): - level = container.level if "skill" in context else 1 fit.drones.filteredItemBoost(lambda drone: drone.item.group.name == "Mining Drone", "miningAmount", container.getModifiedItemAttr("rookieDroneBonus")) diff --git a/eos/effects/shipbonusnosoptimalfalloffac2.py b/eos/effects/shipbonusnosoptimalfalloffac2.py index f741681b5..355b6e22c 100644 --- a/eos/effects/shipbonusnosoptimalfalloffac2.py +++ b/eos/effects/shipbonusnosoptimalfalloffac2.py @@ -3,6 +3,10 @@ # Used by: # Ship: Rabisu type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Energy Nosferatu", "falloffEffectiveness", src.getModifiedItemAttr("shipBonusAC2"), skill="Amarr Cruiser") - fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Energy Nosferatu", "maxRange", src.getModifiedItemAttr("shipBonusAC2"), skill="Amarr Cruiser") + fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Energy Nosferatu", "falloffEffectiveness", + src.getModifiedItemAttr("shipBonusAC2"), skill="Amarr Cruiser") + fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Energy Nosferatu", "maxRange", + src.getModifiedItemAttr("shipBonusAC2"), skill="Amarr Cruiser") diff --git a/eos/effects/shipbonussetfalloffaf2.py b/eos/effects/shipbonussetfalloffaf2.py index cf22eedbd..9c6f67d13 100644 --- a/eos/effects/shipbonussetfalloffaf2.py +++ b/eos/effects/shipbonussetfalloffaf2.py @@ -3,5 +3,8 @@ # Used by: # Ship: Caedes type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Small Energy Turret"), "falloff", src.getModifiedItemAttr("shipBonus2AF"), skill="Amarr Frigate") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Small Energy Turret"), "falloff", + src.getModifiedItemAttr("shipBonus2AF"), skill="Amarr Frigate") diff --git a/eos/effects/shipbonussupercarriera5warfarelinksbonus.py b/eos/effects/shipbonussupercarriera5warfarelinksbonus.py index e1d000525..fdc2f24bc 100644 --- a/eos/effects/shipbonussupercarriera5warfarelinksbonus.py +++ b/eos/effects/shipbonussupercarriera5warfarelinksbonus.py @@ -3,9 +3,21 @@ # Used by: # Ship: Aeon type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command") or mod.item.requiresSkill("Information Command"), "warfareBuff4Value", src.getModifiedItemAttr("shipBonusSupercarrierA5"), skill="Amarr Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command") or mod.item.requiresSkill("Information Command"), "warfareBuff3Value", src.getModifiedItemAttr("shipBonusSupercarrierA5"), skill="Amarr Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command") or mod.item.requiresSkill("Information Command"), "buffDuration", src.getModifiedItemAttr("shipBonusSupercarrierA5"), skill="Amarr Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command") or mod.item.requiresSkill("Information Command"), "warfareBuff2Value", src.getModifiedItemAttr("shipBonusSupercarrierA5"), skill="Amarr Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command") or mod.item.requiresSkill("Information Command"), "warfareBuff1Value", src.getModifiedItemAttr("shipBonusSupercarrierA5"), skill="Amarr Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Armored Command") or mod.item.requiresSkill("Information Command"), + "warfareBuff4Value", src.getModifiedItemAttr("shipBonusSupercarrierA5"), skill="Amarr Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Armored Command") or mod.item.requiresSkill("Information Command"), + "warfareBuff3Value", src.getModifiedItemAttr("shipBonusSupercarrierA5"), skill="Amarr Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Armored Command") or mod.item.requiresSkill("Information Command"), + "buffDuration", src.getModifiedItemAttr("shipBonusSupercarrierA5"), skill="Amarr Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Armored Command") or mod.item.requiresSkill("Information Command"), + "warfareBuff2Value", src.getModifiedItemAttr("shipBonusSupercarrierA5"), skill="Amarr Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Armored Command") or mod.item.requiresSkill("Information Command"), + "warfareBuff1Value", src.getModifiedItemAttr("shipBonusSupercarrierA5"), skill="Amarr Carrier") diff --git a/eos/effects/shipbonussupercarrierc5warfarelinksbonus.py b/eos/effects/shipbonussupercarrierc5warfarelinksbonus.py index 768818b2d..5ff00b1ca 100644 --- a/eos/effects/shipbonussupercarrierc5warfarelinksbonus.py +++ b/eos/effects/shipbonussupercarrierc5warfarelinksbonus.py @@ -3,9 +3,21 @@ # Used by: # Ship: Wyvern type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), "buffDuration", src.getModifiedItemAttr("shipBonusSupercarrierC5"), skill="Caldari Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), "warfareBuff2Value", src.getModifiedItemAttr("shipBonusSupercarrierC5"), skill="Caldari Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), "warfareBuff1Value", src.getModifiedItemAttr("shipBonusSupercarrierC5"), skill="Caldari Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), "warfareBuff4Value", src.getModifiedItemAttr("shipBonusSupercarrierC5"), skill="Caldari Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), "warfareBuff3Value", src.getModifiedItemAttr("shipBonusSupercarrierC5"), skill="Caldari Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), + "buffDuration", src.getModifiedItemAttr("shipBonusSupercarrierC5"), skill="Caldari Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), + "warfareBuff2Value", src.getModifiedItemAttr("shipBonusSupercarrierC5"), skill="Caldari Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), + "warfareBuff1Value", src.getModifiedItemAttr("shipBonusSupercarrierC5"), skill="Caldari Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), + "warfareBuff4Value", src.getModifiedItemAttr("shipBonusSupercarrierC5"), skill="Caldari Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Shield Command") or mod.item.requiresSkill("Information Command"), + "warfareBuff3Value", src.getModifiedItemAttr("shipBonusSupercarrierC5"), skill="Caldari Carrier") diff --git a/eos/effects/shipbonussupercarrierg5warfarelinksbonus.py b/eos/effects/shipbonussupercarrierg5warfarelinksbonus.py index 28dd6ab20..aa6d4d1e2 100644 --- a/eos/effects/shipbonussupercarrierg5warfarelinksbonus.py +++ b/eos/effects/shipbonussupercarrierg5warfarelinksbonus.py @@ -3,9 +3,21 @@ # Used by: # Ship: Nyx type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), "warfareBuff2Value", src.getModifiedItemAttr("shipBonusSupercarrierG5"), skill="Gallente Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), "buffDuration", src.getModifiedItemAttr("shipBonusSupercarrierG5"), skill="Gallente Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), "warfareBuff1Value", src.getModifiedItemAttr("shipBonusSupercarrierG5"), skill="Gallente Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), "warfareBuff3Value", src.getModifiedItemAttr("shipBonusSupercarrierG5"), skill="Gallente Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), "warfareBuff4Value", src.getModifiedItemAttr("shipBonusSupercarrierG5"), skill="Gallente Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), + "warfareBuff2Value", src.getModifiedItemAttr("shipBonusSupercarrierG5"), skill="Gallente Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), + "buffDuration", src.getModifiedItemAttr("shipBonusSupercarrierG5"), skill="Gallente Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), + "warfareBuff1Value", src.getModifiedItemAttr("shipBonusSupercarrierG5"), skill="Gallente Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), + "warfareBuff3Value", src.getModifiedItemAttr("shipBonusSupercarrierG5"), skill="Gallente Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Armored Command"), + "warfareBuff4Value", src.getModifiedItemAttr("shipBonusSupercarrierG5"), skill="Gallente Carrier") diff --git a/eos/effects/shipbonussupercarrierm5warfarelinksbonus.py b/eos/effects/shipbonussupercarrierm5warfarelinksbonus.py index 53a6fafec..403b6c6a7 100644 --- a/eos/effects/shipbonussupercarrierm5warfarelinksbonus.py +++ b/eos/effects/shipbonussupercarrierm5warfarelinksbonus.py @@ -3,9 +3,21 @@ # Used by: # Ship: Hel type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), "warfareBuff4Value", src.getModifiedItemAttr("shipBonusSupercarrierM5"), skill="Minmatar Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), "warfareBuff1Value", src.getModifiedItemAttr("shipBonusSupercarrierM5"), skill="Minmatar Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), "warfareBuff3Value", src.getModifiedItemAttr("shipBonusSupercarrierM5"), skill="Minmatar Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), "buffDuration", src.getModifiedItemAttr("shipBonusSupercarrierM5"), skill="Minmatar Carrier") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), "warfareBuff2Value", src.getModifiedItemAttr("shipBonusSupercarrierM5"), skill="Minmatar Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), + "warfareBuff4Value", src.getModifiedItemAttr("shipBonusSupercarrierM5"), skill="Minmatar Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), + "warfareBuff1Value", src.getModifiedItemAttr("shipBonusSupercarrierM5"), skill="Minmatar Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), + "warfareBuff3Value", src.getModifiedItemAttr("shipBonusSupercarrierM5"), skill="Minmatar Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), + "buffDuration", src.getModifiedItemAttr("shipBonusSupercarrierM5"), skill="Minmatar Carrier") + fit.modules.filteredItemBoost( + lambda mod: mod.item.requiresSkill("Skirmish Command") or mod.item.requiresSkill("Shield Command"), + "warfareBuff2Value", src.getModifiedItemAttr("shipBonusSupercarrierM5"), skill="Minmatar Carrier") diff --git a/eos/effects/shipmodesmallmissiledamagepostdiv.py b/eos/effects/shipmodesmallmissiledamagepostdiv.py index 4db9c2f16..85a4cb534 100644 --- a/eos/effects/shipmodesmallmissiledamagepostdiv.py +++ b/eos/effects/shipmodesmallmissiledamagepostdiv.py @@ -4,6 +4,7 @@ # Module: Jackdaw Sharpshooter Mode type = "passive" + def handler(fit, module, context): types = ("thermal", "em", "explosive", "kinetic") for type in types: diff --git a/eos/effects/skirmishcommanddurationbonus.py b/eos/effects/skirmishcommanddurationbonus.py index 5ab212a25..7b42437e1 100644 --- a/eos/effects/skirmishcommanddurationbonus.py +++ b/eos/effects/skirmishcommanddurationbonus.py @@ -3,6 +3,9 @@ # Used by: # Skill: Skirmish Command type = "passive" + + def handler(fit, src, context): lvl = src.level - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "buffDuration", src.getModifiedItemAttr("durationBonus") * lvl) + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "buffDuration", + src.getModifiedItemAttr("durationBonus") * lvl) diff --git a/eos/effects/skirmishcommandmindlink.py b/eos/effects/skirmishcommandmindlink.py index 4b5d09cad..9999d7f56 100644 --- a/eos/effects/skirmishcommandmindlink.py +++ b/eos/effects/skirmishcommandmindlink.py @@ -5,9 +5,16 @@ # Implant: Republic Fleet Command Mindlink # Implant: Skirmish Command Mindlink type = "passive" + + def handler(fit, src, context): - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff3Multiplier", src.getModifiedItemAttr("mindlinkBonus")) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff4Multiplier", src.getModifiedItemAttr("mindlinkBonus")) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff2Multiplier", src.getModifiedItemAttr("mindlinkBonus")) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff1Multiplier", src.getModifiedItemAttr("mindlinkBonus")) - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "buffDuration", src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff3Multiplier", + src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff4Multiplier", + src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff2Multiplier", + src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff1Multiplier", + src.getModifiedItemAttr("mindlinkBonus")) + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "buffDuration", + src.getModifiedItemAttr("mindlinkBonus")) diff --git a/eos/effects/skirmishcommandstrengthbonus.py b/eos/effects/skirmishcommandstrengthbonus.py index f0af86f77..7963755df 100644 --- a/eos/effects/skirmishcommandstrengthbonus.py +++ b/eos/effects/skirmishcommandstrengthbonus.py @@ -3,9 +3,15 @@ # Used by: # Skill: Skirmish Command Specialist type = "passive" + + def handler(fit, src, context): lvl = src.level - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff3Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff4Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff1Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl) - fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff2Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff3Multiplier", + src.getModifiedItemAttr("commandStrengthBonus") * lvl) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff4Multiplier", + src.getModifiedItemAttr("commandStrengthBonus") * lvl) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff1Multiplier", + src.getModifiedItemAttr("commandStrengthBonus") * lvl) + fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff2Multiplier", + src.getModifiedItemAttr("commandStrengthBonus") * lvl) diff --git a/eos/effects/spatialphenomenagenerationdurationbonus.py b/eos/effects/spatialphenomenagenerationdurationbonus.py index 846fb6040..b127ae30d 100644 --- a/eos/effects/spatialphenomenagenerationdurationbonus.py +++ b/eos/effects/spatialphenomenagenerationdurationbonus.py @@ -3,6 +3,9 @@ # Used by: # Skill: Spatial Phenomena Generation type = "passive" + + def handler(fit, src, context): lvl = src.level - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Spatial Phenomena Generation"), "buffDuration", src.getModifiedItemAttr("durationBonus") * lvl) + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Spatial Phenomena Generation"), "buffDuration", + src.getModifiedItemAttr("durationBonus") * lvl) diff --git a/eos/effects/structureenergyneutralizerfalloff.py b/eos/effects/structureenergyneutralizerfalloff.py index 673630a6b..e383f523b 100644 --- a/eos/effects/structureenergyneutralizerfalloff.py +++ b/eos/effects/structureenergyneutralizerfalloff.py @@ -6,8 +6,8 @@ type = "active", "projected" def handler(fit, container, context): amount = 0 - if "projected" in context and ((hasattr(container, "state") - and container.state >= State.ACTIVE) or hasattr(container, "amountActive")): - amount = container.getModifiedItemAttr("energyNeutralizerAmount") - time = container.getModifiedItemAttr("duration") - fit.addDrain(container, time, amount, 0) + if "projected" in context: + if (hasattr(container, "state") and container.state >= State.ACTIVE) or hasattr(container, "amountActive"): + amount = container.getModifiedItemAttr("energyNeutralizerAmount") + time = container.getModifiedItemAttr("duration") + fit.addDrain(container, time, amount, 0) diff --git a/eos/effects/structuremoduleeffectstasiswebifier.py b/eos/effects/structuremoduleeffectstasiswebifier.py index dc4b6f046..0aa907fc6 100644 --- a/eos/effects/structuremoduleeffectstasiswebifier.py +++ b/eos/effects/structuremoduleeffectstasiswebifier.py @@ -3,6 +3,7 @@ type = "active", "projected" def handler(fit, module, context): - if "projected" not in context: return + if "projected" not in context: + return fit.ship.boostItemAttr("maxVelocity", module.getModifiedItemAttr("speedFactor"), stackingPenalties=True, remoteResists=True) diff --git a/eos/effects/subsystembonusamarrdefensive2remotearmorrepairamount.py b/eos/effects/subsystembonusamarrdefensive2remotearmorrepairamount.py index 9ff4f9d42..5805bbd60 100644 --- a/eos/effects/subsystembonusamarrdefensive2remotearmorrepairamount.py +++ b/eos/effects/subsystembonusamarrdefensive2remotearmorrepairamount.py @@ -4,6 +4,8 @@ # Subsystem: Legion Defensive - Adaptive Augmenter type = "passive" runTime = "early" + + def handler(fit, module, context): fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems"), "armorDamageAmount", module.getModifiedItemAttr("subsystemBonusAmarrDefensive2"), diff --git a/eos/effects/subsystembonusamarrdefensivearmoredwarfare.py b/eos/effects/subsystembonusamarrdefensivearmoredwarfare.py index 4a045cd49..75bcf296d 100644 --- a/eos/effects/subsystembonusamarrdefensivearmoredwarfare.py +++ b/eos/effects/subsystembonusamarrdefensivearmoredwarfare.py @@ -3,9 +3,21 @@ # Used by: # Subsystem: Legion Defensive - Warfare Processor type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Value", src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), skill="Amarr Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Value", src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), skill="Amarr Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Value", src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), skill="Amarr Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration", src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), skill="Amarr Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Value", src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), skill="Amarr Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Value", + src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), + skill="Amarr Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Value", + src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), + skill="Amarr Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Value", + src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), + skill="Amarr Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration", + src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), + skill="Amarr Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Value", + src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), + skill="Amarr Defensive Systems") diff --git a/eos/effects/subsystembonusamarrdefensiveinformationwarfare.py b/eos/effects/subsystembonusamarrdefensiveinformationwarfare.py index 2f3b96474..1d5b476b7 100644 --- a/eos/effects/subsystembonusamarrdefensiveinformationwarfare.py +++ b/eos/effects/subsystembonusamarrdefensiveinformationwarfare.py @@ -3,9 +3,21 @@ # Used by: # Subsystem: Legion Defensive - Warfare Processor type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff1Value", src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), skill="Amarr Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff4Value", src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), skill="Amarr Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff3Value", src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), skill="Amarr Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff2Value", src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), skill="Amarr Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "buffDuration", src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), skill="Amarr Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff1Value", + src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), + skill="Amarr Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff4Value", + src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), + skill="Amarr Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff3Value", + src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), + skill="Amarr Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff2Value", + src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), + skill="Amarr Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "buffDuration", + src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), + skill="Amarr Defensive Systems") diff --git a/eos/effects/subsystembonusamarrdefensiveinformationwarfarehidden.py b/eos/effects/subsystembonusamarrdefensiveinformationwarfarehidden.py index 9dfb9ad19..7dd70fefa 100644 --- a/eos/effects/subsystembonusamarrdefensiveinformationwarfarehidden.py +++ b/eos/effects/subsystembonusamarrdefensiveinformationwarfarehidden.py @@ -1,5 +1,7 @@ # Not used by any item type = "passive" + + def handler(fit, module, context): fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command Specialist"), "commandBonusHidden", module.getModifiedItemAttr("subsystemBonusAmarrDefensive"), skill="Amarr Defensive Systems") diff --git a/eos/effects/subsystembonusamarrdefensiveskirmishwarfare.py b/eos/effects/subsystembonusamarrdefensiveskirmishwarfare.py index c767405fb..141f65cef 100644 --- a/eos/effects/subsystembonusamarrdefensiveskirmishwarfare.py +++ b/eos/effects/subsystembonusamarrdefensiveskirmishwarfare.py @@ -3,9 +3,21 @@ # Used by: # Subsystem: Legion Defensive - Warfare Processor type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff4Value", src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), skill="Amarr Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff1Value", src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), skill="Amarr Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "buffDuration", src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), skill="Amarr Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff2Value", src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), skill="Amarr Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff3Value", src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), skill="Amarr Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff4Value", + src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), + skill="Amarr Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff1Value", + src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), + skill="Amarr Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "buffDuration", + src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), + skill="Amarr Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff2Value", + src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), + skill="Amarr Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff3Value", + src.getModifiedItemAttr("subsystemBonusAmarrDefensive"), + skill="Amarr Defensive Systems") diff --git a/eos/effects/subsystembonuscaldaridefensive2remoteshieldtransporteramount.py b/eos/effects/subsystembonuscaldaridefensive2remoteshieldtransporteramount.py index 1f3b20c03..4478365ef 100644 --- a/eos/effects/subsystembonuscaldaridefensive2remoteshieldtransporteramount.py +++ b/eos/effects/subsystembonuscaldaridefensive2remoteshieldtransporteramount.py @@ -4,6 +4,8 @@ # Subsystem: Tengu Defensive - Adaptive Shielding type = "passive" runTime = "early" + + def handler(fit, module, context): fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Emission Systems"), "shieldBonus", module.getModifiedItemAttr("subsystemBonusCaldariDefensive2"), diff --git a/eos/effects/subsystembonuscaldaridefensiveinformationwarfare.py b/eos/effects/subsystembonuscaldaridefensiveinformationwarfare.py index c06646196..aefcd0b2d 100644 --- a/eos/effects/subsystembonuscaldaridefensiveinformationwarfare.py +++ b/eos/effects/subsystembonuscaldaridefensiveinformationwarfare.py @@ -3,9 +3,21 @@ # Used by: # Subsystem: Tengu Defensive - Warfare Processor type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "buffDuration", src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), skill="Caldari Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff3Value", src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), skill="Caldari Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff1Value", src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), skill="Caldari Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff2Value", src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), skill="Caldari Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff4Value", src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), skill="Caldari Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "buffDuration", + src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), + skill="Caldari Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff3Value", + src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), + skill="Caldari Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff1Value", + src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), + skill="Caldari Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff2Value", + src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), + skill="Caldari Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff4Value", + src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), + skill="Caldari Defensive Systems") diff --git a/eos/effects/subsystembonuscaldaridefensiveinformationwarfarehidden.py b/eos/effects/subsystembonuscaldaridefensiveinformationwarfarehidden.py index f01b7efb7..0cf7a3ef8 100644 --- a/eos/effects/subsystembonuscaldaridefensiveinformationwarfarehidden.py +++ b/eos/effects/subsystembonuscaldaridefensiveinformationwarfarehidden.py @@ -1,5 +1,7 @@ # Not used by any item type = "passive" + + def handler(fit, module, context): fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command Specialist"), "commandBonusHidden", module.getModifiedItemAttr("subsystemBonusCaldariDefensive"), skill="Caldari Defensive Systems") diff --git a/eos/effects/subsystembonuscaldaridefensivesiegewarfare.py b/eos/effects/subsystembonuscaldaridefensivesiegewarfare.py index 9a3de25c4..2869a8227 100644 --- a/eos/effects/subsystembonuscaldaridefensivesiegewarfare.py +++ b/eos/effects/subsystembonuscaldaridefensivesiegewarfare.py @@ -3,9 +3,21 @@ # Used by: # Subsystem: Tengu Defensive - Warfare Processor type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff2Value", src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), skill="Caldari Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff1Value", src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), skill="Caldari Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff3Value", src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), skill="Caldari Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "buffDuration", src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), skill="Caldari Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff4Value", src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), skill="Caldari Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff2Value", + src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), + skill="Caldari Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff1Value", + src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), + skill="Caldari Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff3Value", + src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), + skill="Caldari Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "buffDuration", + src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), + skill="Caldari Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff4Value", + src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), + skill="Caldari Defensive Systems") diff --git a/eos/effects/subsystembonuscaldaridefensiveskirmishwarfare.py b/eos/effects/subsystembonuscaldaridefensiveskirmishwarfare.py index 21a1a2ad5..54778136c 100644 --- a/eos/effects/subsystembonuscaldaridefensiveskirmishwarfare.py +++ b/eos/effects/subsystembonuscaldaridefensiveskirmishwarfare.py @@ -3,9 +3,21 @@ # Used by: # Subsystem: Tengu Defensive - Warfare Processor type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "buffDuration", src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), skill="Caldari Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff1Value", src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), skill="Caldari Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff4Value", src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), skill="Caldari Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff2Value", src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), skill="Caldari Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff3Value", src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), skill="Caldari Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "buffDuration", + src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), + skill="Caldari Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff1Value", + src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), + skill="Caldari Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff4Value", + src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), + skill="Caldari Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff2Value", + src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), + skill="Caldari Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff3Value", + src.getModifiedItemAttr("subsystemBonusCaldariDefensive"), + skill="Caldari Defensive Systems") diff --git a/eos/effects/subsystembonusgallentedefensive2remotearmorrepairamount.py b/eos/effects/subsystembonusgallentedefensive2remotearmorrepairamount.py index f18b60266..f9e7e5039 100644 --- a/eos/effects/subsystembonusgallentedefensive2remotearmorrepairamount.py +++ b/eos/effects/subsystembonusgallentedefensive2remotearmorrepairamount.py @@ -4,6 +4,8 @@ # Subsystem: Proteus Defensive - Adaptive Augmenter type = "passive" runTime = "early" + + def handler(fit, module, context): fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems"), "armorDamageAmount", module.getModifiedItemAttr("subsystemBonusGallenteDefensive2"), diff --git a/eos/effects/subsystembonusgallentedefensivearmoredwarfare.py b/eos/effects/subsystembonusgallentedefensivearmoredwarfare.py index 5d9369857..d66f4fc32 100644 --- a/eos/effects/subsystembonusgallentedefensivearmoredwarfare.py +++ b/eos/effects/subsystembonusgallentedefensivearmoredwarfare.py @@ -3,9 +3,21 @@ # Used by: # Subsystem: Proteus Defensive - Warfare Processor type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration", src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), skill="Gallente Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Value", src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), skill="Gallente Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Value", src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), skill="Gallente Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Value", src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), skill="Gallente Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Value", src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), skill="Gallente Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration", + src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), + skill="Gallente Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Value", + src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), + skill="Gallente Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Value", + src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), + skill="Gallente Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Value", + src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), + skill="Gallente Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Value", + src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), + skill="Gallente Defensive Systems") diff --git a/eos/effects/subsystembonusgallentedefensiveinformationwarfare.py b/eos/effects/subsystembonusgallentedefensiveinformationwarfare.py index 83a9943ee..90e90eac6 100644 --- a/eos/effects/subsystembonusgallentedefensiveinformationwarfare.py +++ b/eos/effects/subsystembonusgallentedefensiveinformationwarfare.py @@ -3,9 +3,21 @@ # Used by: # Subsystem: Proteus Defensive - Warfare Processor type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff4Value", src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), skill="Gallente Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff2Value", src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), skill="Gallente Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff3Value", src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), skill="Gallente Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "buffDuration", src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), skill="Gallente Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff1Value", src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), skill="Gallente Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff4Value", + src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), + skill="Gallente Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff2Value", + src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), + skill="Gallente Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff3Value", + src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), + skill="Gallente Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "buffDuration", + src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), + skill="Gallente Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command"), "warfareBuff1Value", + src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), + skill="Gallente Defensive Systems") diff --git a/eos/effects/subsystembonusgallentedefensiveinformationwarfarehidden.py b/eos/effects/subsystembonusgallentedefensiveinformationwarfarehidden.py index 7a3f8205f..19b0cf02e 100644 --- a/eos/effects/subsystembonusgallentedefensiveinformationwarfarehidden.py +++ b/eos/effects/subsystembonusgallentedefensiveinformationwarfarehidden.py @@ -1,5 +1,7 @@ # Not used by any item type = "passive" + + def handler(fit, module, context): fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Information Command Specialist"), "commandBonusHidden", module.getModifiedItemAttr("subsystemBonusGallenteDefensive"), skill="Gallente Defensive Systems") diff --git a/eos/effects/subsystembonusgallentedefensiveskirmishwarfare.py b/eos/effects/subsystembonusgallentedefensiveskirmishwarfare.py index 6aae7922b..b4ed4e9e2 100644 --- a/eos/effects/subsystembonusgallentedefensiveskirmishwarfare.py +++ b/eos/effects/subsystembonusgallentedefensiveskirmishwarfare.py @@ -3,9 +3,21 @@ # Used by: # Subsystem: Proteus Defensive - Warfare Processor type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff4Value", src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), skill="Gallente Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff2Value", src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), skill="Gallente Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff1Value", src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), skill="Gallente Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff3Value", src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), skill="Gallente Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "buffDuration", src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), skill="Gallente Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff4Value", + src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), + skill="Gallente Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff2Value", + src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), + skill="Gallente Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff1Value", + src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), + skill="Gallente Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff3Value", + src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), + skill="Gallente Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "buffDuration", + src.getModifiedItemAttr("subsystemBonusGallenteDefensive"), + skill="Gallente Defensive Systems") diff --git a/eos/effects/subsystembonusminmatardefensive2remoteshieldtransporteramount.py b/eos/effects/subsystembonusminmatardefensive2remoteshieldtransporteramount.py index 784c7e7e8..2586c28ec 100644 --- a/eos/effects/subsystembonusminmatardefensive2remoteshieldtransporteramount.py +++ b/eos/effects/subsystembonusminmatardefensive2remoteshieldtransporteramount.py @@ -4,6 +4,8 @@ # Subsystem: Loki Defensive - Adaptive Shielding type = "passive" runTime = "early" + + def handler(fit, module, context): fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Emission Systems"), "shieldBonus", module.getModifiedItemAttr("subsystemBonusMinmatarDefensive2"), diff --git a/eos/effects/subsystembonusminmatardefensivearmoredwarfare.py b/eos/effects/subsystembonusminmatardefensivearmoredwarfare.py index f38d8af9c..7921b5713 100644 --- a/eos/effects/subsystembonusminmatardefensivearmoredwarfare.py +++ b/eos/effects/subsystembonusminmatardefensivearmoredwarfare.py @@ -3,9 +3,21 @@ # Used by: # Subsystem: Loki Defensive - Warfare Processor type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration", src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), skill="Minmatar Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Value", src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), skill="Minmatar Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Value", src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), skill="Minmatar Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Value", src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), skill="Minmatar Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Value", src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), skill="Minmatar Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "buffDuration", + src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), + skill="Minmatar Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff2Value", + src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), + skill="Minmatar Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff4Value", + src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), + skill="Minmatar Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff1Value", + src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), + skill="Minmatar Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Armored Command"), "warfareBuff3Value", + src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), + skill="Minmatar Defensive Systems") diff --git a/eos/effects/subsystembonusminmatardefensivesiegewarfare.py b/eos/effects/subsystembonusminmatardefensivesiegewarfare.py index 80547e83e..de019c309 100644 --- a/eos/effects/subsystembonusminmatardefensivesiegewarfare.py +++ b/eos/effects/subsystembonusminmatardefensivesiegewarfare.py @@ -3,9 +3,21 @@ # Used by: # Subsystem: Loki Defensive - Warfare Processor type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff1Value", src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), skill="Minmatar Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "buffDuration", src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), skill="Minmatar Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff4Value", src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), skill="Minmatar Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff3Value", src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), skill="Minmatar Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff2Value", src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), skill="Minmatar Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff1Value", + src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), + skill="Minmatar Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "buffDuration", + src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), + skill="Minmatar Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff4Value", + src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), + skill="Minmatar Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff3Value", + src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), + skill="Minmatar Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Command"), "warfareBuff2Value", + src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), + skill="Minmatar Defensive Systems") diff --git a/eos/effects/subsystembonusminmatardefensiveskirmishwarfare.py b/eos/effects/subsystembonusminmatardefensiveskirmishwarfare.py index 75ecd4da2..645257326 100644 --- a/eos/effects/subsystembonusminmatardefensiveskirmishwarfare.py +++ b/eos/effects/subsystembonusminmatardefensiveskirmishwarfare.py @@ -3,9 +3,21 @@ # Used by: # Subsystem: Loki Defensive - Warfare Processor type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff1Value", src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), skill="Minmatar Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff3Value", src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), skill="Minmatar Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff4Value", src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), skill="Minmatar Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff2Value", src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), skill="Minmatar Defensive Systems") - fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "buffDuration", src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), skill="Minmatar Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff1Value", + src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), + skill="Minmatar Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff3Value", + src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), + skill="Minmatar Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff4Value", + src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), + skill="Minmatar Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "warfareBuff2Value", + src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), + skill="Minmatar Defensive Systems") + fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Skirmish Command"), "buffDuration", + src.getModifiedItemAttr("subsystemBonusMinmatarDefensive"), + skill="Minmatar Defensive Systems") diff --git a/eos/effects/systemarmorrepairamount.py b/eos/effects/systemarmorrepairamount.py index 1b28168f1..da585583d 100644 --- a/eos/effects/systemarmorrepairamount.py +++ b/eos/effects/systemarmorrepairamount.py @@ -7,7 +7,7 @@ type = ("projected", "passive") def handler(fit, module, context): - fit.modules.filteredItemMultiply(lambda mod: mod.item.requiresSkill("Repair Systems") - or mod.item.requiresSkill("Capital Repair Systems"), + fit.modules.filteredItemMultiply(lambda mod: mod.item.requiresSkill("Repair Systems") or + mod.item.requiresSkill("Capital Repair Systems"), "armorDamageAmount", module.getModifiedItemAttr("armorDamageAmountMultiplier"), stackingPenalties=True, penaltyGroup="postMul") diff --git a/eos/effects/systemshieldrepairamountshieldskills.py b/eos/effects/systemshieldrepairamountshieldskills.py index bde28cd04..707e2dbbb 100644 --- a/eos/effects/systemshieldrepairamountshieldskills.py +++ b/eos/effects/systemshieldrepairamountshieldskills.py @@ -7,7 +7,7 @@ type = ("projected", "passive") def handler(fit, module, context): - fit.modules.filteredItemMultiply(lambda mod: mod.item.requiresSkill("Shield Operation") - or mod.item.requiresSkill("Capital Shield Operation"), + fit.modules.filteredItemMultiply(lambda mod: mod.item.requiresSkill("Shield Operation") or + mod.item.requiresSkill("Capital Shield Operation"), "shieldBonus", module.getModifiedItemAttr("shieldBonusMultiplier"), stackingPenalties=True, penaltyGroup="postMul") diff --git a/eos/effects/techtwocommandburstbonus.py b/eos/effects/techtwocommandburstbonus.py index a85f78ab9..757513cef 100644 --- a/eos/effects/techtwocommandburstbonus.py +++ b/eos/effects/techtwocommandburstbonus.py @@ -2,6 +2,7 @@ type = "passive" runTime = "late" + def handler(fit, module, context): for x in xrange(1, 4): module.boostChargeAttr("warfareBuff{}Multiplier".format(x), module.getModifiedItemAttr("commandBurstStrengthBonus")) diff --git a/eos/effects/zcolinorcasurveyscannerbonus.py b/eos/effects/zcolinorcasurveyscannerbonus.py index feed0cc0c..a1eb01fea 100644 --- a/eos/effects/zcolinorcasurveyscannerbonus.py +++ b/eos/effects/zcolinorcasurveyscannerbonus.py @@ -3,5 +3,8 @@ # Used by: # Ships from group: Industrial Command Ship (2 of 2) type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Survey Scanner", "surveyScanRange", src.getModifiedItemAttr("roleBonusSurveyScannerRange")) + fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Survey Scanner", "surveyScanRange", + src.getModifiedItemAttr("roleBonusSurveyScannerRange")) diff --git a/eos/effects/zcolinorcatractorrangebonus.py b/eos/effects/zcolinorcatractorrangebonus.py index b2262a1e9..9c4a20c03 100644 --- a/eos/effects/zcolinorcatractorrangebonus.py +++ b/eos/effects/zcolinorcatractorrangebonus.py @@ -3,5 +3,8 @@ # Used by: # Ships from group: Industrial Command Ship (2 of 2) type = "passive" + + def handler(fit, src, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Tractor Beam", "maxRange", src.getModifiedItemAttr("roleBonusTractorBeamRange")) + fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Tractor Beam", "maxRange", + src.getModifiedItemAttr("roleBonusTractorBeamRange")) diff --git a/eos/effects/zcolinorcatractorvelocitybonus.py b/eos/effects/zcolinorcatractorvelocitybonus.py index 95219da80..736643324 100644 --- a/eos/effects/zcolinorcatractorvelocitybonus.py +++ b/eos/effects/zcolinorcatractorvelocitybonus.py @@ -6,4 +6,5 @@ type = "passive" def handler(fit, ship, context): - fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Tractor Beam", "maxTractorVelocity", ship.getModifiedItemAttr("roleBonusTractorBeamVelocity")) + fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Tractor Beam", "maxTractorVelocity", + ship.getModifiedItemAttr("roleBonusTractorBeamVelocity")) diff --git a/eos/gamedata.py b/eos/gamedata.py index c4b58b235..e4a4afa1c 100644 --- a/eos/gamedata.py +++ b/eos/gamedata.py @@ -444,6 +444,25 @@ class Category(EqBase): pass +class AlphaClone(EqBase): + @reconstructor + def init(self): + self.skillCache = {} + + for x in self.skills: + self.skillCache[x.typeID] = x + + def getSkillLevel(self, skill): + if skill.item.ID in self.skillCache: + return self.skillCache[skill.item.ID].level + else: + return None + + +class AlphaCloneSkill(EqBase): + pass + + class Group(EqBase): pass diff --git a/eos/graph/fitDps.py b/eos/graph/fitDps.py index cfc9ec5f4..04ef910a5 100644 --- a/eos/graph/fitDps.py +++ b/eos/graph/fitDps.py @@ -1,183 +1,182 @@ -# =============================================================================== -# Copyright (C) 2010 Diego Duclos -# -# This file is part of eos. -# -# eos is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# eos is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with eos. If not, see . -# =============================================================================== - -from math import log, sin, radians, exp - -from eos.graph import Graph -from eos.types import Hardpoint, State - - -class FitDpsGraph(Graph): - defaults = {"angle": 0, - "distance": 0, - "signatureRadius": None, - "velocity": 0} - - def __init__(self, fit, data=None): - Graph.__init__(self, fit, self.calcDps, data if data is not None else self.defaults) - self.fit = fit - - def calcDps(self, data): - ew = {'signatureRadius': [], 'velocity': []} - fit = self.fit - total = 0 - distance = data["distance"] * 1000 - abssort = lambda val: -abs(val - 1) - - for mod in fit.modules: - if not mod.isEmpty and mod.state >= State.ACTIVE: - if "remoteTargetPaintFalloff" in mod.item.effects: - ew['signatureRadius'].append( - 1 + (mod.getModifiedItemAttr("signatureRadiusBonus") / 100) * self.calculateModuleMultiplier( - mod, data)) - if "remoteWebifierFalloff" in mod.item.effects: - if distance <= mod.getModifiedItemAttr("maxRange"): - ew['velocity'].append(1 + (mod.getModifiedItemAttr("speedFactor") / 100)) - elif mod.getModifiedItemAttr("falloffEffectiveness") > 0: - # I am affected by falloff - ew['velocity'].append( - 1 + (mod.getModifiedItemAttr("speedFactor") / 100) * self.calculateModuleMultiplier(mod, - data)) - - ew['signatureRadius'].sort(key=abssort) - ew['velocity'].sort(key=abssort) - - for attr, values in ew.iteritems(): - val = data[attr] - try: - for i in xrange(len(values)): - bonus = values[i] - val *= 1 + (bonus - 1) * exp(- i ** 2 / 7.1289) - data[attr] = val - except: - pass - - for mod in fit.modules: - dps, _ = mod.damageStats(fit.targetResists) - if mod.hardpoint == Hardpoint.TURRET: - if mod.state >= State.ACTIVE: - total += dps * self.calculateTurretMultiplier(mod, data) - - elif mod.hardpoint == Hardpoint.MISSILE: - if mod.state >= State.ACTIVE and mod.maxRange >= distance: - total += dps * self.calculateMissileMultiplier(mod, data) - - if distance <= fit.extraAttributes["droneControlRange"]: - for drone in fit.drones: - multiplier = 1 if drone.getModifiedItemAttr("maxVelocity") > 1 else self.calculateTurretMultiplier( - drone, data) - dps, _ = drone.damageStats(fit.targetResists) - total += dps * multiplier - - # this is janky as fuck - for fighter in fit.fighters: - for ability in fighter.abilities: - if ability.dealsDamage and ability.active: - multiplier = self.calculateFighterMissileMultiplier(ability, data) - dps, _ = ability.damageStats(fit.targetResists) - total += dps * multiplier - - return total - - def calculateMissileMultiplier(self, mod, data): - targetSigRad = data["signatureRadius"] - targetVelocity = data["velocity"] - explosionRadius = mod.getModifiedChargeAttr("aoeCloudSize") - targetSigRad = explosionRadius if targetSigRad is None else targetSigRad - explosionVelocity = mod.getModifiedChargeAttr("aoeVelocity") - damageReductionFactor = mod.getModifiedChargeAttr("aoeDamageReductionFactor") - - sigRadiusFactor = targetSigRad / explosionRadius - if targetVelocity: - velocityFactor = ( - explosionVelocity / explosionRadius * targetSigRad / targetVelocity) ** damageReductionFactor - else: - velocityFactor = 1 - - return min(sigRadiusFactor, velocityFactor, 1) - - def calculateTurretMultiplier(self, mod, data): - # Source for most of turret calculation info: http://wiki.eveonline.com/en/wiki/Falloff - chanceToHit = self.calculateTurretChanceToHit(mod, data) - if chanceToHit > 0.01: - # AvgDPS = Base Damage * [ ( ChanceToHit^2 + ChanceToHit + 0.0499 ) / 2 ] - multiplier = (chanceToHit ** 2 + chanceToHit + 0.0499) / 2 - else: - # All hits are wreckings - multiplier = chanceToHit * 3 - dmgScaling = mod.getModifiedItemAttr("turretDamageScalingRadius") - if dmgScaling: - targetSigRad = data["signatureRadius"] - multiplier = min(1, (float(targetSigRad) / dmgScaling) ** 2) - return multiplier - - def calculateFighterMissileMultiplier(self, ability, data): - prefix = ability.attrPrefix - - targetSigRad = data["signatureRadius"] - targetVelocity = data["velocity"] - explosionRadius = ability.fighter.getModifiedItemAttr("{}ExplosionRadius".format(prefix)) - explosionVelocity = ability.fighter.getModifiedItemAttr("{}ExplosionVelocity".format(prefix)) - damageReductionFactor = ability.fighter.getModifiedItemAttr("{}ReductionFactor".format(prefix)) - - # the following conditionals are because CCP can't keep a decent naming convention, as if fighter implementation - # wasn't already fucked. - if damageReductionFactor is None: - damageReductionFactor = ability.fighter.getModifiedItemAttr("{}DamageReductionFactor".format(prefix)) - - damageReductionSensitivity = ability.fighter.getModifiedItemAttr("{}ReductionSensitivity".format(prefix)) - if damageReductionSensitivity is None: - damageReductionSensitivity = ability.fighter.getModifiedItemAttr( - "{}DamageReductionSensitivity".format(prefix)) - - targetSigRad = explosionRadius if targetSigRad is None else targetSigRad - sigRadiusFactor = targetSigRad / explosionRadius - - if targetVelocity: - velocityFactor = (explosionVelocity / explosionRadius * targetSigRad / targetVelocity) ** ( - log(damageReductionFactor) / log(damageReductionSensitivity)) - else: - velocityFactor = 1 - - return min(sigRadiusFactor, velocityFactor, 1) - - def calculateTurretChanceToHit(self, mod, data): - distance = data["distance"] * 1000 - tracking = mod.getModifiedItemAttr("trackingSpeed") - turretOptimal = mod.maxRange - turretFalloff = mod.falloff - turretSigRes = mod.getModifiedItemAttr("optimalSigRadius") - targetSigRad = data["signatureRadius"] - targetSigRad = turretSigRes if targetSigRad is None else targetSigRad - transversal = sin(radians(data["angle"])) * data["velocity"] - trackingEq = (((transversal / (distance * tracking)) * - (turretSigRes / targetSigRad)) ** 2) - rangeEq = ((max(0, distance - turretOptimal)) / turretFalloff) ** 2 - - return 0.5 ** (trackingEq + rangeEq) - - def calculateModuleMultiplier(self, mod, data): - # Simplified formula, we make some assumptions about the module - # This is basically the calculateTurretChanceToHit without tracking values - distance = data["distance"] * 1000 - turretOptimal = mod.maxRange - turretFalloff = mod.falloff - rangeEq = ((max(0, distance - turretOptimal)) / turretFalloff) ** 2 - - return 0.5 ** (rangeEq) +# =============================================================================== +# Copyright (C) 2010 Diego Duclos +# +# This file is part of eos. +# +# eos is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# eos is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with eos. If not, see . +# =============================================================================== + +from math import log, sin, radians, exp + +from eos.graph import Graph +from eos.types import Hardpoint, State + + +class FitDpsGraph(Graph): + defaults = {"angle": 0, + "distance": 0, + "signatureRadius": None, + "velocity": 0} + + def __init__(self, fit, data=None): + Graph.__init__(self, fit, self.calcDps, data if data is not None else self.defaults) + self.fit = fit + + def calcDps(self, data): + ew = {'signatureRadius': [], 'velocity': []} + fit = self.fit + total = 0 + distance = data["distance"] * 1000 + abssort = lambda val: -abs(val - 1) + + for mod in fit.modules: + if not mod.isEmpty and mod.state >= State.ACTIVE: + if "remoteTargetPaintFalloff" in mod.item.effects: + ew['signatureRadius'].append( + 1 + (mod.getModifiedItemAttr("signatureRadiusBonus") / 100) * self.calculateModuleMultiplier( + mod, data)) + if "remoteWebifierFalloff" in mod.item.effects: + if distance <= mod.getModifiedItemAttr("maxRange"): + ew['velocity'].append(1 + (mod.getModifiedItemAttr("speedFactor") / 100)) + elif mod.getModifiedItemAttr("falloffEffectiveness") > 0: + # I am affected by falloff + ew['velocity'].append( + 1 + (mod.getModifiedItemAttr("speedFactor") / 100) * self.calculateModuleMultiplier(mod, + data)) + + ew['signatureRadius'].sort(key=abssort) + ew['velocity'].sort(key=abssort) + + for attr, values in ew.iteritems(): + val = data[attr] + try: + for i in xrange(len(values)): + bonus = values[i] + val *= 1 + (bonus - 1) * exp(- i ** 2 / 7.1289) + data[attr] = val + except: + pass + + for mod in fit.modules: + dps, _ = mod.damageStats(fit.targetResists) + if mod.hardpoint == Hardpoint.TURRET: + if mod.state >= State.ACTIVE: + total += dps * self.calculateTurretMultiplier(mod, data) + + elif mod.hardpoint == Hardpoint.MISSILE: + if mod.state >= State.ACTIVE and mod.maxRange >= distance: + total += dps * self.calculateMissileMultiplier(mod, data) + + if distance <= fit.extraAttributes["droneControlRange"]: + for drone in fit.drones: + multiplier = 1 if drone.getModifiedItemAttr("maxVelocity") > 1 else self.calculateTurretMultiplier( + drone, data) + dps, _ = drone.damageStats(fit.targetResists) + total += dps * multiplier + + # this is janky as fuck + for fighter in fit.fighters: + for ability in fighter.abilities: + if ability.dealsDamage and ability.active: + multiplier = self.calculateFighterMissileMultiplier(ability, data) + dps, _ = ability.damageStats(fit.targetResists) + total += dps * multiplier + + return total + + def calculateMissileMultiplier(self, mod, data): + targetSigRad = data["signatureRadius"] + targetVelocity = data["velocity"] + explosionRadius = mod.getModifiedChargeAttr("aoeCloudSize") + targetSigRad = explosionRadius if targetSigRad is None else targetSigRad + explosionVelocity = mod.getModifiedChargeAttr("aoeVelocity") + damageReductionFactor = mod.getModifiedChargeAttr("aoeDamageReductionFactor") + + sigRadiusFactor = targetSigRad / explosionRadius + if targetVelocity: + velocityFactor = (explosionVelocity / explosionRadius * targetSigRad / targetVelocity) ** damageReductionFactor + else: + velocityFactor = 1 + + return min(sigRadiusFactor, velocityFactor, 1) + + def calculateTurretMultiplier(self, mod, data): + # Source for most of turret calculation info: http://wiki.eveonline.com/en/wiki/Falloff + chanceToHit = self.calculateTurretChanceToHit(mod, data) + if chanceToHit > 0.01: + # AvgDPS = Base Damage * [ ( ChanceToHit^2 + ChanceToHit + 0.0499 ) / 2 ] + multiplier = (chanceToHit ** 2 + chanceToHit + 0.0499) / 2 + else: + # All hits are wreckings + multiplier = chanceToHit * 3 + dmgScaling = mod.getModifiedItemAttr("turretDamageScalingRadius") + if dmgScaling: + targetSigRad = data["signatureRadius"] + multiplier = min(1, (float(targetSigRad) / dmgScaling) ** 2) + return multiplier + + def calculateFighterMissileMultiplier(self, ability, data): + prefix = ability.attrPrefix + + targetSigRad = data["signatureRadius"] + targetVelocity = data["velocity"] + explosionRadius = ability.fighter.getModifiedItemAttr("{}ExplosionRadius".format(prefix)) + explosionVelocity = ability.fighter.getModifiedItemAttr("{}ExplosionVelocity".format(prefix)) + damageReductionFactor = ability.fighter.getModifiedItemAttr("{}ReductionFactor".format(prefix)) + + # the following conditionals are because CCP can't keep a decent naming convention, as if fighter implementation + # wasn't already fucked. + if damageReductionFactor is None: + damageReductionFactor = ability.fighter.getModifiedItemAttr("{}DamageReductionFactor".format(prefix)) + + damageReductionSensitivity = ability.fighter.getModifiedItemAttr("{}ReductionSensitivity".format(prefix)) + if damageReductionSensitivity is None: + damageReductionSensitivity = ability.fighter.getModifiedItemAttr( + "{}DamageReductionSensitivity".format(prefix)) + + targetSigRad = explosionRadius if targetSigRad is None else targetSigRad + sigRadiusFactor = targetSigRad / explosionRadius + + if targetVelocity: + velocityFactor = (explosionVelocity / explosionRadius * targetSigRad / targetVelocity) ** ( + log(damageReductionFactor) / log(damageReductionSensitivity)) + else: + velocityFactor = 1 + + return min(sigRadiusFactor, velocityFactor, 1) + + def calculateTurretChanceToHit(self, mod, data): + distance = data["distance"] * 1000 + tracking = mod.getModifiedItemAttr("trackingSpeed") + turretOptimal = mod.maxRange + turretFalloff = mod.falloff + turretSigRes = mod.getModifiedItemAttr("optimalSigRadius") + targetSigRad = data["signatureRadius"] + targetSigRad = turretSigRes if targetSigRad is None else targetSigRad + transversal = sin(radians(data["angle"])) * data["velocity"] + trackingEq = (((transversal / (distance * tracking)) * + (turretSigRes / targetSigRad)) ** 2) + rangeEq = ((max(0, distance - turretOptimal)) / turretFalloff) ** 2 + + return 0.5 ** (trackingEq + rangeEq) + + def calculateModuleMultiplier(self, mod, data): + # Simplified formula, we make some assumptions about the module + # This is basically the calculateTurretChanceToHit without tracking values + distance = data["distance"] * 1000 + turretOptimal = mod.maxRange + turretFalloff = mod.falloff + rangeEq = ((max(0, distance - turretOptimal)) / turretFalloff) ** 2 + + return 0.5 ** (rangeEq) diff --git a/eos/modifiedAttributeDict.py b/eos/modifiedAttributeDict.py index c0f778263..d060eb425 100644 --- a/eos/modifiedAttributeDict.py +++ b/eos/modifiedAttributeDict.py @@ -132,8 +132,8 @@ class ModifiedAttributeDict(collections.MutableMapping): return (key for key in all) def __contains__(self, key): - return ( - self.__original is not None and key in self.__original) or key in self.__modified or key in self.__intermediary + return (self.__original is not None and key in self.__original) or \ + key in self.__modified or key in self.__intermediary def __placehold(self, key): """Create calculation placeholder in item's modified attribute dict""" diff --git a/eos/saveddata/booster.py b/eos/saveddata/booster.py index 3be3845d0..93f0a4bc3 100644 --- a/eos/saveddata/booster.py +++ b/eos/saveddata/booster.py @@ -159,6 +159,7 @@ class Booster(HandledItem, ItemAttrShortcut): return copy + # Legacy booster side effect code, disabling as not currently implemented ''' class SideEffect(object): @@ -194,4 +195,4 @@ class Booster(HandledItem, ItemAttrShortcut): raise TypeError("Need an effect with a handler") self.__effect = effect -''' \ No newline at end of file +''' diff --git a/eos/saveddata/character.py b/eos/saveddata/character.py index 9657c7d04..cd5e278fd 100644 --- a/eos/saveddata/character.py +++ b/eos/saveddata/character.py @@ -99,6 +99,7 @@ class Character(object): self.__skills = [] self.__skillIdMap = {} self.dirtySkills = set() + self.alphaClone = None if initSkills: for item in self.getSkillList(): @@ -109,11 +110,17 @@ class Character(object): @reconstructor def init(self): + self.__skillIdMap = {} for skill in self.__skills: self.__skillIdMap[skill.itemID] = skill self.dirtySkills = set() + self.alphaClone = None + + if self.alphaCloneID: + self.alphaClone = eos.db.getAlphaClone(self.alphaCloneID) + def apiUpdateCharSheet(self, skills): del self.__skills[:] self.__skillIdMap.clear() @@ -140,6 +147,15 @@ class Character(object): def name(self, name): self.savedName = name + @property + def alphaCloneID(self): + return self.__alphaCloneID + + @alphaCloneID.setter + def alphaCloneID(self, cloneID): + self.__alphaCloneID = cloneID + self.alphaClone = eos.db.getAlphaClone(cloneID) if cloneID is not None else None + @property def skills(self): return self.__skills @@ -294,6 +310,9 @@ class Skill(HandledItem): @property def level(self): + if self.character.alphaClone: + return min(self.activeLevel, self.character.alphaClone.getSkillLevel(self)) or 0 + return self.activeLevel or 0 @level.setter diff --git a/eos/saveddata/fighter.py b/eos/saveddata/fighter.py index 66dd9af89..d46b1a6fe 100644 --- a/eos/saveddata/fighter.py +++ b/eos/saveddata/fighter.py @@ -273,8 +273,7 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): for ability in self.abilities: if ability.active: effect = ability.effect - if effect.runTime == runTime and \ - effect.activeByDefault and \ + if effect.runTime == runTime and effect.activeByDefault and \ ((projected and effect.isType("projected")) or not projected): if ability.grouped: effect.handler(fit, self, context) diff --git a/eos/saveddata/fighterAbility.py b/eos/saveddata/fighterAbility.py index 38a21a27e..cb7c34912 100644 --- a/eos/saveddata/fighterAbility.py +++ b/eos/saveddata/fighterAbility.py @@ -95,14 +95,12 @@ class FighterAbility(object): @property def reloadTime(self): - return self.fighter.getModifiedItemAttr("fighterRefuelingTime") + \ - (self.REARM_TIME_MAPPING[self.fighter.getModifiedItemAttr( - "fighterSquadronRole")] or 0 if self.hasCharges else 0) * self.numShots + rearm_time = (self.REARM_TIME_MAPPING[self.fighter.getModifiedItemAttr("fighterSquadronRole")] or 0 if self.hasCharges else 0) + return self.fighter.getModifiedItemAttr("fighterRefuelingTime") + rearm_time * self.numShots @property def numShots(self): - return self.NUM_SHOTS_MAPPING[ - self.fighter.getModifiedItemAttr("fighterSquadronRole")] or 0 if self.hasCharges else 0 + return self.NUM_SHOTS_MAPPING[self.fighter.getModifiedItemAttr("fighterSquadronRole")] or 0 if self.hasCharges else 0 @property def cycleTime(self): diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index 2e9f8bfe9..f338564f2 100644 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -28,10 +28,12 @@ from sqlalchemy.orm import validates, reconstructor import eos.db from eos import capSim from eos.effectHandlerHelpers import * +from eos.effectHandlerHelpers import HandledModuleList, HandledDroneCargoList, HandledImplantBoosterList, HandledProjectedDroneList, HandledProjectedModList from eos.enum import Enum from eos.saveddata.module import State, Hardpoint from eos.types import Ship, Character, Slot, Module, Citadel from utils.timer import Timer +import logging logger = logging.getLogger(__name__) @@ -740,7 +742,7 @@ class Fit(object): if not withBoosters and self.commandBonuses: self.__runCommandBoosts(runTime) - timer.checkpoint('Done with runtime: %s'%runTime) + timer.checkpoint('Done with runtime: %s' % runTime) # Mark fit as calculated self.__calculated = True diff --git a/eos/saveddata/module.py b/eos/saveddata/module.py index 6b597a904..d04065233 100644 --- a/eos/saveddata/module.py +++ b/eos/saveddata/module.py @@ -1,734 +1,726 @@ -# =============================================================================== -# Copyright (C) 2010 Diego Duclos -# -# This file is part of eos. -# -# eos is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# eos is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with eos. If not, see . -# =============================================================================== - -import logging - -from sqlalchemy.orm import validates, reconstructor - -import eos.db -from eos.effectHandlerHelpers import HandledItem, HandledCharge -from eos.enum import Enum -from eos.mathUtils import floorFloat -from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut, ChargeAttrShortcut -from eos.types import Citadel - -logger = logging.getLogger(__name__) - - -class State(Enum): - def __init__(self): - pass - - OFFLINE = -1 - ONLINE = 0 - ACTIVE = 1 - OVERHEATED = 2 - - -class Slot(Enum): - def __init__(self): - pass - - # These are self-explanatory - LOW = 1 - MED = 2 - HIGH = 3 - RIG = 4 - SUBSYSTEM = 5 - # not a real slot, need for pyfa display rack separation - MODE = 6 - # system effects. They are projected "modules" and pyfa assumes all modules - # have a slot. In this case, make one up. - SYSTEM = 7 - # used for citadel services - SERVICE = 8 - # fighter 'slots'. Just easier to put them here... - F_LIGHT = 10 - F_SUPPORT = 11 - F_HEAVY = 12 - - -class Hardpoint(Enum): - def __init__(self): - pass - - NONE = 0 - MISSILE = 1 - TURRET = 2 - - -class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): - """An instance of this class represents a module together with its charge and modified attributes""" - DAMAGE_TYPES = ("em", "thermal", "kinetic", "explosive") - MINING_ATTRIBUTES = ("miningAmount",) - - def __init__(self, item): - """Initialize a module from the program""" - self.__item = item - - if item is not None and self.isInvalid: - raise ValueError("Passed item is not a Module") - - self.__charge = None - self.itemID = item.ID if item is not None else None - self.projected = False - self.state = State.ONLINE - self.build() - - @reconstructor - def init(self): - """Initialize a module from the database and validate""" - self.__item = None - self.__charge = None - - # we need this early if module is invalid and returns early - self.__slot = self.dummySlot - - if self.itemID: - self.__item = eos.db.getItem(self.itemID) - if self.__item is None: - logger.error("Item (id: %d) does not exist", self.itemID) - return - - if self.isInvalid: - logger.error("Item (id: %d) is not a Module", self.itemID) - return - - if self.chargeID: - self.__charge = eos.db.getItem(self.chargeID) - - self.build() - - def build(self): - """ Builds internal module variables from both init's """ - - if self.__charge and self.__charge.category.name != "Charge": - self.__charge = None - - self.__dps = None - self.__miningyield = None - self.__volley = None - self.__reloadTime = None - self.__reloadForce = None - self.__chargeCycles = None - self.__hardpoint = Hardpoint.NONE - self.__itemModifiedAttributes = ModifiedAttributeDict(parent=self) - self.__chargeModifiedAttributes = ModifiedAttributeDict(parent=self) - self.__slot = self.dummySlot # defaults to None - - if self.__item: - self.__itemModifiedAttributes.original = self.__item.attributes - self.__itemModifiedAttributes.overrides = self.__item.overrides - self.__hardpoint = self.__calculateHardpoint(self.__item) - self.__slot = self.__calculateSlot(self.__item) - if self.__charge: - self.__chargeModifiedAttributes.original = self.__charge.attributes - self.__chargeModifiedAttributes.overrides = self.__charge.overrides - - @classmethod - def buildEmpty(cls, slot): - empty = Module(None) - empty.__slot = slot - empty.dummySlot = slot - return empty - - @classmethod - def buildRack(cls, slot): - empty = Rack(None) - empty.__slot = slot - empty.dummySlot = slot - return empty - - @property - def isEmpty(self): - return self.dummySlot is not None - - @property - def hardpoint(self): - return self.__hardpoint - - @property - def isInvalid(self): - if self.isEmpty: - return False - return self.__item is None or (self.__item.category.name not in ("Module", "Subsystem", "Structure Module") and self.__item.group.name != "Effect Beacon") - - @property - def numCharges(self): - if self.charge is None: - charges = 0 - else: - chargeVolume = self.charge.volume - containerCapacity = self.item.capacity - if chargeVolume is None or containerCapacity is None: - charges = 0 - else: - charges = floorFloat(float(containerCapacity) / chargeVolume) - return charges - - @property - def numShots(self): - if self.charge is None: - return None - if self.__chargeCycles is None and self.charge: - numCharges = self.numCharges - # Usual ammo like projectiles and missiles - if numCharges > 0 and "chargeRate" in self.itemModifiedAttributes: - self.__chargeCycles = self.__calculateAmmoShots() - # Frequency crystals (combat and mining lasers) - elif numCharges > 0 and "crystalsGetDamaged" in self.chargeModifiedAttributes: - self.__chargeCycles = self.__calculateCrystalShots() - # Scripts and stuff - else: - self.__chargeCycles = 0 - return self.__chargeCycles - else: - return self.__chargeCycles - - @property - def modPosition(self): - if self.owner: - return self.owner.modules.index(self) - - @property - def hpBeforeReload(self): - """ - If item is some kind of repairer with charges, calculate - HP it reps before going into reload. - """ - cycles = self.numShots - armorRep = self.getModifiedItemAttr("armorDamageAmount") or 0 - shieldRep = self.getModifiedItemAttr("shieldBonus") or 0 - if not cycles or (not armorRep and not shieldRep): - return None - hp = round((armorRep + shieldRep) * cycles) - return hp - - def __calculateAmmoShots(self): - if self.charge is not None: - # Set number of cycles before reload is needed - chargeRate = self.getModifiedItemAttr("chargeRate") - numCharges = self.numCharges - numShots = floorFloat(float(numCharges) / chargeRate) - else: - numShots = None - return numShots - - def __calculateCrystalShots(self): - if self.charge is not None: - if self.getModifiedChargeAttr("crystalsGetDamaged") == 1: - # For depletable crystals, calculate average amount of shots before it's destroyed - hp = self.getModifiedChargeAttr("hp") - chance = self.getModifiedChargeAttr("crystalVolatilityChance") - damage = self.getModifiedChargeAttr("crystalVolatilityDamage") - crystals = self.numCharges - numShots = floorFloat(float(crystals * hp) / (damage * chance)) - else: - # Set 0 (infinite) for permanent crystals like t1 laser crystals - numShots = 0 - else: - numShots = None - return numShots - - @property - def maxRange(self): - attrs = ("maxRange", "shieldTransferRange", "powerTransferRange", - "energyDestabilizationRange", "empFieldRange", - "ecmBurstRange", "warpScrambleRange", "cargoScanRange", - "shipScanRange", "surveyScanRange") - for attr in attrs: - maxRange = self.getModifiedItemAttr(attr) - if maxRange is not None: - return maxRange - if self.charge is not None: - try: - chargeName = self.charge.group.name - except AttributeError: - pass - else: - if chargeName in ("Scanner Probe", "Survey Probe"): - return None - # Source: http://www.eveonline.com/ingameboard.asp?a=topic&threadID=1307419&page=1#15 - # D_m = V_m * (T_m + T_0*[exp(- T_m/T_0)-1]) - maxVelocity = self.getModifiedChargeAttr("maxVelocity") - flightTime = self.getModifiedChargeAttr("explosionDelay") / 1000.0 - mass = self.getModifiedChargeAttr("mass") - agility = self.getModifiedChargeAttr("agility") - if maxVelocity and (flightTime or mass or agility): - accelTime = min(flightTime, mass * agility / 1000000) - # Average distance done during acceleration - duringAcceleration = maxVelocity / 2 * accelTime - # Distance done after being at full speed - fullSpeed = maxVelocity * (flightTime - accelTime) - return duringAcceleration + fullSpeed - - @property - def falloff(self): - attrs = ("falloffEffectiveness", "falloff", "shipScanFalloff") - for attr in attrs: - falloff = self.getModifiedItemAttr(attr) - if falloff is not None: - return falloff - - @property - def slot(self): - return self.__slot - - @property - def itemModifiedAttributes(self): - return self.__itemModifiedAttributes - - @property - def chargeModifiedAttributes(self): - return self.__chargeModifiedAttributes - - @property - def item(self): - return self.__item if self.__item != 0 else None - - @property - def charge(self): - return self.__charge if self.__charge != 0 else None - - @charge.setter - def charge(self, charge): - self.__charge = charge - if charge is not None: - self.chargeID = charge.ID - self.__chargeModifiedAttributes.original = charge.attributes - self.__chargeModifiedAttributes.overrides = charge.overrides - else: - self.chargeID = None - self.__chargeModifiedAttributes.original = None - self.__chargeModifiedAttributes.overrides = {} - - self.__itemModifiedAttributes.clear() - - def damageStats(self, targetResists): - if self.__dps is None: - self.__dps = 0 - self.__volley = 0 - - if not self.isEmpty and self.state >= State.ACTIVE: - if self.charge: - func = self.getModifiedChargeAttr - else: - func = self.getModifiedItemAttr - - volley = sum(map( - lambda attr: (func("%sDamage" % attr) or 0) * (1 - getattr(targetResists, "%sAmount" % attr, 0)), - self.DAMAGE_TYPES)) - volley *= self.getModifiedItemAttr("damageMultiplier") or 1 - if volley: - cycleTime = self.cycleTime - self.__volley = volley - self.__dps = volley / (cycleTime / 1000.0) - - return self.__dps, self.__volley - - @property - def miningStats(self): - if self.__miningyield is None: - if self.isEmpty: - self.__miningyield = 0 - else: - if self.state >= State.ACTIVE: - volley = self.getModifiedItemAttr("specialtyMiningAmount") or self.getModifiedItemAttr( - "miningAmount") or 0 - if volley: - cycleTime = self.cycleTime - self.__miningyield = volley / (cycleTime / 1000.0) - else: - self.__miningyield = 0 - else: - self.__miningyield = 0 - - return self.__miningyield - - @property - def dps(self): - return self.damageStats(None)[0] - - @property - def volley(self): - return self.damageStats(None)[1] - - @property - def reloadTime(self): - # Get reload time from attrs first, then use - # custom value specified otherwise (e.g. in effects) - moduleReloadTime = self.getModifiedItemAttr("reloadTime") - if moduleReloadTime is None: - moduleReloadTime = self.__reloadTime - return moduleReloadTime - - @reloadTime.setter - def reloadTime(self, milliseconds): - self.__reloadTime = milliseconds - - @property - def forceReload(self): - return self.__reloadForce - - @forceReload.setter - def forceReload(self, type): - self.__reloadForce = type - - def fits(self, fit, hardpointLimit=True): - slot = self.slot - if fit.getSlotsFree(slot) <= (0 if self.owner != fit else -1): - return False - - # Check ship type restrictions - fitsOnType = set() - fitsOnGroup = set() - - shipType = self.getModifiedItemAttr("fitsToShipType") - if shipType is not None: - fitsOnType.add(shipType) - - for attr in self.itemModifiedAttributes.keys(): - if attr.startswith("canFitShipType"): - shipType = self.getModifiedItemAttr(attr) - if shipType is not None: - fitsOnType.add(shipType) - - for attr in self.itemModifiedAttributes.keys(): - if attr.startswith("canFitShipGroup"): - shipGroup = self.getModifiedItemAttr(attr) - if shipGroup is not None: - fitsOnGroup.add(shipGroup) - - if (len(fitsOnGroup) > 0 or len( - fitsOnType) > 0) and fit.ship.item.group.ID not in fitsOnGroup and fit.ship.item.ID not in fitsOnType: - return False - - # AFAIK Citadel modules will always be restricted based on canFitShipType/Group. If we are fitting to a Citadel - # and the module does not have these properties, return false to prevent regular ship modules from being used - if isinstance(fit.ship, Citadel) and len(fitsOnGroup) == 0 and len(fitsOnType) == 0: - return False - - # If the mod is a subsystem, don't let two subs in the same slot fit - if self.slot == Slot.SUBSYSTEM: - subSlot = self.getModifiedItemAttr("subSystemSlot") - for mod in fit.modules: - if mod.getModifiedItemAttr("subSystemSlot") == subSlot: - return False - - # Check rig sizes - if self.slot == Slot.RIG: - if self.getModifiedItemAttr("rigSize") != fit.ship.getModifiedItemAttr("rigSize"): - return False - - # Check max group fitted - max = self.getModifiedItemAttr("maxGroupFitted") - if max is not None: - current = 0 if self.owner != fit else -1 - for mod in fit.modules: - if mod.item and mod.item.groupID == self.item.groupID: - current += 1 - - if current >= max: - return False - - # Check this only if we're told to do so - if hardpointLimit: - if self.hardpoint == Hardpoint.TURRET: - if (fit.ship.getModifiedItemAttr('turretSlotsLeft') or 0) - fit.getHardpointsUsed(Hardpoint.TURRET) < 1: - return False - elif self.hardpoint == Hardpoint.MISSILE: - if (fit.ship.getModifiedItemAttr('launcherSlotsLeft') or 0) - fit.getHardpointsUsed( - Hardpoint.MISSILE) < 1: - return False - - return True - - def isValidState(self, state): - """ - Check if the state is valid for this module, without considering other modules at all - """ - # Check if we're within bounds - if state < -1 or state > 2: - return False - elif state >= State.ACTIVE and not self.item.isType("active"): - return False - elif state == State.OVERHEATED and not self.item.isType("overheat"): - return False - else: - return True - - def canHaveState(self, state=None, projectedOnto=None): - """ - Check with other modules if there are restrictions that might not allow this module to be activated - """ - # If we're going to set module to offline or online for local modules or offline for projected, - # it should be fine for all cases - item = self.item - if (state <= State.ONLINE and projectedOnto is None) or (state <= State.OFFLINE): - return True - - # Check if the local module is over it's max limit; if it's not, we're fine - maxGroupActive = self.getModifiedItemAttr("maxGroupActive") - if maxGroupActive is None and projectedOnto is None: - return True - - # Following is applicable only to local modules, we do not want to limit projected - if projectedOnto is None: - currActive = 0 - group = item.group.name - for mod in self.owner.modules: - currItem = getattr(mod, "item", None) - if mod.state >= State.ACTIVE and currItem is not None and currItem.group.name == group: - currActive += 1 - if currActive > maxGroupActive: - break - return currActive <= maxGroupActive - # For projected, we're checking if ship is vulnerable to given item - else: - # Do not allow to apply offensive modules on ship with offensive module immunite, with few exceptions - # (all effects which apply instant modification are exception, generally speaking) - if item.offensive and projectedOnto.ship.getModifiedItemAttr("disallowOffensiveModifiers") == 1: - offensiveNonModifiers = {"energyDestabilizationNew", - "leech", - "energyNosferatuFalloff", - "energyNeutralizerFalloff"} - if not offensiveNonModifiers.intersection(set(item.effects)): - return False - # If assistive modules are not allowed, do not let to apply these altogether - if item.assistive and projectedOnto.ship.getModifiedItemAttr("disallowAssistance") == 1: - return False - return True - - def isValidCharge(self, charge): - # Check sizes, if 'charge size > module volume' it won't fit - if charge is None: - return True - chargeVolume = charge.volume - moduleCapacity = self.item.capacity - if chargeVolume is not None and moduleCapacity is not None and chargeVolume > moduleCapacity: - return False - - itemChargeSize = self.getModifiedItemAttr("chargeSize") - if itemChargeSize > 0: - chargeSize = charge.getAttribute('chargeSize') - if itemChargeSize != chargeSize: - return False - - chargeGroup = charge.groupID - for i in range(5): - itemChargeGroup = self.getModifiedItemAttr('chargeGroup' + str(i)) - if itemChargeGroup is None: - continue - if itemChargeGroup == chargeGroup: - return True - - return False - - def getValidCharges(self): - validCharges = set() - for i in range(5): - itemChargeGroup = self.getModifiedItemAttr('chargeGroup' + str(i)) - if itemChargeGroup is not None: - g = eos.db.getGroup(int(itemChargeGroup), eager=("items.icon", "items.attributes")) - if g is None: - continue - for singleItem in g.items: - if singleItem.published and self.isValidCharge(singleItem): - validCharges.add(singleItem) - - return validCharges - - def __calculateHardpoint(self, item): - effectHardpointMap = {"turretFitted": Hardpoint.TURRET, - "launcherFitted": Hardpoint.MISSILE} - - if item is None: - return Hardpoint.NONE - - for effectName, slot in effectHardpointMap.iteritems(): - if effectName in item.effects: - return slot - - return Hardpoint.NONE - - def __calculateSlot(self, item): - effectSlotMap = {"rigSlot": Slot.RIG, - "loPower": Slot.LOW, - "medPower": Slot.MED, - "hiPower": Slot.HIGH, - "subSystem": Slot.SUBSYSTEM, - "serviceSlot": Slot.SERVICE} - if item is None: - return None - for effectName, slot in effectSlotMap.iteritems(): - if effectName in item.effects: - return slot - if item.group.name == "Effect Beacon": - return Slot.SYSTEM - - raise ValueError("Passed item does not fit in any known slot") - - @validates("ID", "itemID", "ammoID") - def validator(self, key, val): - map = {"ID": lambda val: isinstance(val, int), - "itemID": lambda val: val is None or isinstance(val, int), - "ammoID": lambda val: isinstance(val, int)} - - if not map[key](val): - raise ValueError(str(val) + " is not a valid value for " + key) - else: - return val - - def clear(self): - self.__dps = None - self.__miningyield = None - self.__volley = None - self.__reloadTime = None - self.__reloadForce = None - self.__chargeCycles = None - self.itemModifiedAttributes.clear() - self.chargeModifiedAttributes.clear() - - def calculateModifiedAttributes(self, fit, runTime, forceProjected = False, gang = False): - #We will run the effect when two conditions are met: - #1: It makes sense to run the effect - # The effect is either offline - # or the effect is passive and the module is in the online state (or higher) - - # or the effect is active and the module is in the active state (or higher) - # or the effect is overheat and the module is in the overheated state (or higher) - # 2: the runtimes match - - if self.projected or forceProjected: - context = "projected", "module" - projected = True - else: - context = ("module",) - projected = False - - # if gang: - # context += ("commandRun",) - - if self.charge is not None: - # fix for #82 and it's regression #106 - if not projected or (self.projected and not forceProjected) or gang: - for effect in self.charge.effects.itervalues(): - if effect.runTime == runTime and \ - effect.activeByDefault and \ - (effect.isType("offline") or - (effect.isType("passive") and self.state >= State.ONLINE) or - (effect.isType("active") and self.state >= State.ACTIVE)) and \ - (not gang or (gang and effect.isType("gang"))): - - chargeContext = ("moduleCharge",) - # For gang effects, we pass in the effect itself as an argument. However, to avoid going through - # all the effect files and defining this argument, do a simple try/catch here and be done with it. - # @todo: possibly fix this - try: - effect.handler(fit, self, chargeContext, effect=effect) - except: - effect.handler(fit, self, chargeContext) - - if self.item: - if self.state >= State.OVERHEATED: - for effect in self.item.effects.itervalues(): - if effect.runTime == runTime and \ - effect.isType("overheat") \ - and not forceProjected \ - and effect.activeByDefault \ - and ((gang and effect.isType("gang")) or not gang): - effect.handler(fit, self, context) - - for effect in self.item.effects.itervalues(): - if effect.runTime == runTime and \ - effect.activeByDefault and \ - (effect.isType("offline") or - (effect.isType("passive") and self.state >= State.ONLINE) or - - (effect.isType("active") and self.state >= State.ACTIVE))\ - and ((projected and effect.isType("projected")) or not projected)\ - and ((gang and effect.isType("gang")) or not gang): - try: - effect.handler(fit, self, context, effect=effect) - except: - effect.handler(fit, self, context) - - @property - def cycleTime(self): - reactivation = (self.getModifiedItemAttr("moduleReactivationDelay") or 0) - # Reactivation time starts counting after end of module cycle - speed = self.rawCycleTime + reactivation - if self.charge: - reload = self.reloadTime - else: - reload = 0.0 - # Determine if we'll take into account reload time or not - factorReload = self.owner.factorReload if self.forceReload is None else self.forceReload - # If reactivation is longer than 10 seconds then module can be reloaded - # during reactivation time, thus we may ignore reload - if factorReload and reactivation < reload: - numShots = self.numShots - # Time it takes to reload module after end of reactivation time, - # given that we started when module cycle has just over - additionalReloadTime = (reload - reactivation) - # Speed here already takes into consideration reactivation time - speed = (speed * numShots + additionalReloadTime) / numShots if numShots > 0 else speed - - return speed - - @property - def rawCycleTime(self): - speed = self.getModifiedItemAttr("speed") or self.getModifiedItemAttr("duration") - return speed - - @property - def capUse(self): - capNeed = self.getModifiedItemAttr("capacitorNeed") - if capNeed and self.state >= State.ACTIVE: - cycleTime = self.cycleTime - capUsed = capNeed / (cycleTime / 1000.0) - return capUsed - else: - return 0 - - def __deepcopy__(self, memo): - item = self.item - if item is None: - copy = Module.buildEmpty(self.slot) - else: - copy = Module(self.item) - copy.charge = self.charge - copy.state = self.state - return copy - - def __repr__(self): - if self.item: - return "Module(ID={}, name={}) at {}".format( - self.item.ID, self.item.name, hex(id(self)) - ) - else: - return "EmptyModule() at {}".format(hex(id(self))) - - -class Rack(Module): - """ - This is simply the Module class named something else to differentiate - it for app logic. This class does not do anything special - """ - pass +# =============================================================================== +# Copyright (C) 2010 Diego Duclos +# +# This file is part of eos. +# +# eos is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# eos is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with eos. If not, see . +# =============================================================================== + +import logging + +from sqlalchemy.orm import validates, reconstructor + +import eos.db +from eos.effectHandlerHelpers import HandledItem, HandledCharge +from eos.enum import Enum +from eos.mathUtils import floorFloat +from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut, ChargeAttrShortcut +from eos.types import Citadel + +logger = logging.getLogger(__name__) + + +class State(Enum): + OFFLINE = -1 + ONLINE = 0 + ACTIVE = 1 + OVERHEATED = 2 + + +class Slot(Enum): + # These are self-explanatory + LOW = 1 + MED = 2 + HIGH = 3 + RIG = 4 + SUBSYSTEM = 5 + # not a real slot, need for pyfa display rack separation + MODE = 6 + # system effects. They are projected "modules" and pyfa assumes all modules + # have a slot. In this case, make one up. + SYSTEM = 7 + # used for citadel services + SERVICE = 8 + # fighter 'slots'. Just easier to put them here... + F_LIGHT = 10 + F_SUPPORT = 11 + F_HEAVY = 12 + + +class Hardpoint(Enum): + NONE = 0 + MISSILE = 1 + TURRET = 2 + + +class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): + """An instance of this class represents a module together with its charge and modified attributes""" + DAMAGE_TYPES = ("em", "thermal", "kinetic", "explosive") + MINING_ATTRIBUTES = ("miningAmount",) + + def __init__(self, item): + """Initialize a module from the program""" + self.__item = item + + if item is not None and self.isInvalid: + raise ValueError("Passed item is not a Module") + + self.__charge = None + self.itemID = item.ID if item is not None else None + self.projected = False + self.state = State.ONLINE + self.build() + + @reconstructor + def init(self): + """Initialize a module from the database and validate""" + self.__item = None + self.__charge = None + + # we need this early if module is invalid and returns early + self.__slot = self.dummySlot + + if self.itemID: + self.__item = eos.db.getItem(self.itemID) + if self.__item is None: + logger.error("Item (id: %d) does not exist", self.itemID) + return + + if self.isInvalid: + logger.error("Item (id: %d) is not a Module", self.itemID) + return + + if self.chargeID: + self.__charge = eos.db.getItem(self.chargeID) + + self.build() + + def build(self): + """ Builds internal module variables from both init's """ + + if self.__charge and self.__charge.category.name != "Charge": + self.__charge = None + + self.__dps = None + self.__miningyield = None + self.__volley = None + self.__reloadTime = None + self.__reloadForce = None + self.__chargeCycles = None + self.__hardpoint = Hardpoint.NONE + self.__itemModifiedAttributes = ModifiedAttributeDict(parent=self) + self.__chargeModifiedAttributes = ModifiedAttributeDict(parent=self) + self.__slot = self.dummySlot # defaults to None + + if self.__item: + self.__itemModifiedAttributes.original = self.__item.attributes + self.__itemModifiedAttributes.overrides = self.__item.overrides + self.__hardpoint = self.__calculateHardpoint(self.__item) + self.__slot = self.__calculateSlot(self.__item) + if self.__charge: + self.__chargeModifiedAttributes.original = self.__charge.attributes + self.__chargeModifiedAttributes.overrides = self.__charge.overrides + + @classmethod + def buildEmpty(cls, slot): + empty = Module(None) + empty.__slot = slot + empty.dummySlot = slot + return empty + + @classmethod + def buildRack(cls, slot): + empty = Rack(None) + empty.__slot = slot + empty.dummySlot = slot + return empty + + @property + def isEmpty(self): + return self.dummySlot is not None + + @property + def hardpoint(self): + return self.__hardpoint + + @property + def isInvalid(self): + if self.isEmpty: + return False + return self.__item is None or \ + (self.__item.category.name not in ("Module", "Subsystem", "Structure Module") and + self.__item.group.name != "Effect Beacon") + + @property + def numCharges(self): + if self.charge is None: + charges = 0 + else: + chargeVolume = self.charge.volume + containerCapacity = self.item.capacity + if chargeVolume is None or containerCapacity is None: + charges = 0 + else: + charges = floorFloat(float(containerCapacity) / chargeVolume) + return charges + + @property + def numShots(self): + if self.charge is None: + return None + if self.__chargeCycles is None and self.charge: + numCharges = self.numCharges + # Usual ammo like projectiles and missiles + if numCharges > 0 and "chargeRate" in self.itemModifiedAttributes: + self.__chargeCycles = self.__calculateAmmoShots() + # Frequency crystals (combat and mining lasers) + elif numCharges > 0 and "crystalsGetDamaged" in self.chargeModifiedAttributes: + self.__chargeCycles = self.__calculateCrystalShots() + # Scripts and stuff + else: + self.__chargeCycles = 0 + return self.__chargeCycles + else: + return self.__chargeCycles + + @property + def modPosition(self): + if self.owner: + return self.owner.modules.index(self) + + @property + def hpBeforeReload(self): + """ + If item is some kind of repairer with charges, calculate + HP it reps before going into reload. + """ + cycles = self.numShots + armorRep = self.getModifiedItemAttr("armorDamageAmount") or 0 + shieldRep = self.getModifiedItemAttr("shieldBonus") or 0 + if not cycles or (not armorRep and not shieldRep): + return None + hp = round((armorRep + shieldRep) * cycles) + return hp + + def __calculateAmmoShots(self): + if self.charge is not None: + # Set number of cycles before reload is needed + chargeRate = self.getModifiedItemAttr("chargeRate") + numCharges = self.numCharges + numShots = floorFloat(float(numCharges) / chargeRate) + else: + numShots = None + return numShots + + def __calculateCrystalShots(self): + if self.charge is not None: + if self.getModifiedChargeAttr("crystalsGetDamaged") == 1: + # For depletable crystals, calculate average amount of shots before it's destroyed + hp = self.getModifiedChargeAttr("hp") + chance = self.getModifiedChargeAttr("crystalVolatilityChance") + damage = self.getModifiedChargeAttr("crystalVolatilityDamage") + crystals = self.numCharges + numShots = floorFloat(float(crystals * hp) / (damage * chance)) + else: + # Set 0 (infinite) for permanent crystals like t1 laser crystals + numShots = 0 + else: + numShots = None + return numShots + + @property + def maxRange(self): + attrs = ("maxRange", "shieldTransferRange", "powerTransferRange", + "energyDestabilizationRange", "empFieldRange", + "ecmBurstRange", "warpScrambleRange", "cargoScanRange", + "shipScanRange", "surveyScanRange") + for attr in attrs: + maxRange = self.getModifiedItemAttr(attr) + if maxRange is not None: + return maxRange + if self.charge is not None: + try: + chargeName = self.charge.group.name + except AttributeError: + pass + else: + if chargeName in ("Scanner Probe", "Survey Probe"): + return None + # Source: http://www.eveonline.com/ingameboard.asp?a=topic&threadID=1307419&page=1#15 + # D_m = V_m * (T_m + T_0*[exp(- T_m/T_0)-1]) + maxVelocity = self.getModifiedChargeAttr("maxVelocity") + flightTime = self.getModifiedChargeAttr("explosionDelay") / 1000.0 + mass = self.getModifiedChargeAttr("mass") + agility = self.getModifiedChargeAttr("agility") + if maxVelocity and (flightTime or mass or agility): + accelTime = min(flightTime, mass * agility / 1000000) + # Average distance done during acceleration + duringAcceleration = maxVelocity / 2 * accelTime + # Distance done after being at full speed + fullSpeed = maxVelocity * (flightTime - accelTime) + return duringAcceleration + fullSpeed + + @property + def falloff(self): + attrs = ("falloffEffectiveness", "falloff", "shipScanFalloff") + for attr in attrs: + falloff = self.getModifiedItemAttr(attr) + if falloff is not None: + return falloff + + @property + def slot(self): + return self.__slot + + @property + def itemModifiedAttributes(self): + return self.__itemModifiedAttributes + + @property + def chargeModifiedAttributes(self): + return self.__chargeModifiedAttributes + + @property + def item(self): + return self.__item if self.__item != 0 else None + + @property + def charge(self): + return self.__charge if self.__charge != 0 else None + + @charge.setter + def charge(self, charge): + self.__charge = charge + if charge is not None: + self.chargeID = charge.ID + self.__chargeModifiedAttributes.original = charge.attributes + self.__chargeModifiedAttributes.overrides = charge.overrides + else: + self.chargeID = None + self.__chargeModifiedAttributes.original = None + self.__chargeModifiedAttributes.overrides = {} + + self.__itemModifiedAttributes.clear() + + def damageStats(self, targetResists): + if self.__dps is None: + self.__dps = 0 + self.__volley = 0 + + if not self.isEmpty and self.state >= State.ACTIVE: + if self.charge: + func = self.getModifiedChargeAttr + else: + func = self.getModifiedItemAttr + + volley = sum(map( + lambda attr: (func("%sDamage" % attr) or 0) * (1 - getattr(targetResists, "%sAmount" % attr, 0)), + self.DAMAGE_TYPES)) + volley *= self.getModifiedItemAttr("damageMultiplier") or 1 + if volley: + cycleTime = self.cycleTime + self.__volley = volley + self.__dps = volley / (cycleTime / 1000.0) + + return self.__dps, self.__volley + + @property + def miningStats(self): + if self.__miningyield is None: + if self.isEmpty: + self.__miningyield = 0 + else: + if self.state >= State.ACTIVE: + volley = self.getModifiedItemAttr("specialtyMiningAmount") or self.getModifiedItemAttr( + "miningAmount") or 0 + if volley: + cycleTime = self.cycleTime + self.__miningyield = volley / (cycleTime / 1000.0) + else: + self.__miningyield = 0 + else: + self.__miningyield = 0 + + return self.__miningyield + + @property + def dps(self): + return self.damageStats(None)[0] + + @property + def volley(self): + return self.damageStats(None)[1] + + @property + def reloadTime(self): + # Get reload time from attrs first, then use + # custom value specified otherwise (e.g. in effects) + moduleReloadTime = self.getModifiedItemAttr("reloadTime") + if moduleReloadTime is None: + moduleReloadTime = self.__reloadTime + return moduleReloadTime + + @reloadTime.setter + def reloadTime(self, milliseconds): + self.__reloadTime = milliseconds + + @property + def forceReload(self): + return self.__reloadForce + + @forceReload.setter + def forceReload(self, type): + self.__reloadForce = type + + def fits(self, fit, hardpointLimit=True): + slot = self.slot + if fit.getSlotsFree(slot) <= (0 if self.owner != fit else -1): + return False + + # Check ship type restrictions + fitsOnType = set() + fitsOnGroup = set() + + shipType = self.getModifiedItemAttr("fitsToShipType") + if shipType is not None: + fitsOnType.add(shipType) + + for attr in self.itemModifiedAttributes.keys(): + if attr.startswith("canFitShipType"): + shipType = self.getModifiedItemAttr(attr) + if shipType is not None: + fitsOnType.add(shipType) + + for attr in self.itemModifiedAttributes.keys(): + if attr.startswith("canFitShipGroup"): + shipGroup = self.getModifiedItemAttr(attr) + if shipGroup is not None: + fitsOnGroup.add(shipGroup) + + if (len(fitsOnGroup) > 0 or len( + fitsOnType) > 0) and fit.ship.item.group.ID not in fitsOnGroup and fit.ship.item.ID not in fitsOnType: + return False + + # AFAIK Citadel modules will always be restricted based on canFitShipType/Group. If we are fitting to a Citadel + # and the module does not have these properties, return false to prevent regular ship modules from being used + if isinstance(fit.ship, Citadel) and len(fitsOnGroup) == 0 and len(fitsOnType) == 0: + return False + + # If the mod is a subsystem, don't let two subs in the same slot fit + if self.slot == Slot.SUBSYSTEM: + subSlot = self.getModifiedItemAttr("subSystemSlot") + for mod in fit.modules: + if mod.getModifiedItemAttr("subSystemSlot") == subSlot: + return False + + # Check rig sizes + if self.slot == Slot.RIG: + if self.getModifiedItemAttr("rigSize") != fit.ship.getModifiedItemAttr("rigSize"): + return False + + # Check max group fitted + max = self.getModifiedItemAttr("maxGroupFitted") + if max is not None: + current = 0 if self.owner != fit else -1 + for mod in fit.modules: + if mod.item and mod.item.groupID == self.item.groupID: + current += 1 + + if current >= max: + return False + + # Check this only if we're told to do so + if hardpointLimit: + if self.hardpoint == Hardpoint.TURRET: + if (fit.ship.getModifiedItemAttr('turretSlotsLeft') or 0) - fit.getHardpointsUsed(Hardpoint.TURRET) < 1: + return False + elif self.hardpoint == Hardpoint.MISSILE: + if (fit.ship.getModifiedItemAttr('launcherSlotsLeft') or 0) - fit.getHardpointsUsed( + Hardpoint.MISSILE) < 1: + return False + + return True + + def isValidState(self, state): + """ + Check if the state is valid for this module, without considering other modules at all + """ + # Check if we're within bounds + if state < -1 or state > 2: + return False + elif state >= State.ACTIVE and not self.item.isType("active"): + return False + elif state == State.OVERHEATED and not self.item.isType("overheat"): + return False + else: + return True + + def canHaveState(self, state=None, projectedOnto=None): + """ + Check with other modules if there are restrictions that might not allow this module to be activated + """ + # If we're going to set module to offline or online for local modules or offline for projected, + # it should be fine for all cases + item = self.item + if (state <= State.ONLINE and projectedOnto is None) or (state <= State.OFFLINE): + return True + + # Check if the local module is over it's max limit; if it's not, we're fine + maxGroupActive = self.getModifiedItemAttr("maxGroupActive") + if maxGroupActive is None and projectedOnto is None: + return True + + # Following is applicable only to local modules, we do not want to limit projected + if projectedOnto is None: + currActive = 0 + group = item.group.name + for mod in self.owner.modules: + currItem = getattr(mod, "item", None) + if mod.state >= State.ACTIVE and currItem is not None and currItem.group.name == group: + currActive += 1 + if currActive > maxGroupActive: + break + return currActive <= maxGroupActive + # For projected, we're checking if ship is vulnerable to given item + else: + # Do not allow to apply offensive modules on ship with offensive module immunite, with few exceptions + # (all effects which apply instant modification are exception, generally speaking) + if item.offensive and projectedOnto.ship.getModifiedItemAttr("disallowOffensiveModifiers") == 1: + offensiveNonModifiers = {"energyDestabilizationNew", + "leech", + "energyNosferatuFalloff", + "energyNeutralizerFalloff"} + if not offensiveNonModifiers.intersection(set(item.effects)): + return False + # If assistive modules are not allowed, do not let to apply these altogether + if item.assistive and projectedOnto.ship.getModifiedItemAttr("disallowAssistance") == 1: + return False + return True + + def isValidCharge(self, charge): + # Check sizes, if 'charge size > module volume' it won't fit + if charge is None: + return True + chargeVolume = charge.volume + moduleCapacity = self.item.capacity + if chargeVolume is not None and moduleCapacity is not None and chargeVolume > moduleCapacity: + return False + + itemChargeSize = self.getModifiedItemAttr("chargeSize") + if itemChargeSize > 0: + chargeSize = charge.getAttribute('chargeSize') + if itemChargeSize != chargeSize: + return False + + chargeGroup = charge.groupID + for i in range(5): + itemChargeGroup = self.getModifiedItemAttr('chargeGroup' + str(i)) + if itemChargeGroup is None: + continue + if itemChargeGroup == chargeGroup: + return True + + return False + + def getValidCharges(self): + validCharges = set() + for i in range(5): + itemChargeGroup = self.getModifiedItemAttr('chargeGroup' + str(i)) + if itemChargeGroup is not None: + g = eos.db.getGroup(int(itemChargeGroup), eager=("items.icon", "items.attributes")) + if g is None: + continue + for singleItem in g.items: + if singleItem.published and self.isValidCharge(singleItem): + validCharges.add(singleItem) + + return validCharges + + def __calculateHardpoint(self, item): + effectHardpointMap = {"turretFitted": Hardpoint.TURRET, + "launcherFitted": Hardpoint.MISSILE} + + if item is None: + return Hardpoint.NONE + + for effectName, slot in effectHardpointMap.iteritems(): + if effectName in item.effects: + return slot + + return Hardpoint.NONE + + def __calculateSlot(self, item): + effectSlotMap = {"rigSlot": Slot.RIG, + "loPower": Slot.LOW, + "medPower": Slot.MED, + "hiPower": Slot.HIGH, + "subSystem": Slot.SUBSYSTEM, + "serviceSlot": Slot.SERVICE} + if item is None: + return None + for effectName, slot in effectSlotMap.iteritems(): + if effectName in item.effects: + return slot + if item.group.name == "Effect Beacon": + return Slot.SYSTEM + + raise ValueError("Passed item does not fit in any known slot") + + @validates("ID", "itemID", "ammoID") + def validator(self, key, val): + map = {"ID": lambda val: isinstance(val, int), + "itemID": lambda val: val is None or isinstance(val, int), + "ammoID": lambda val: isinstance(val, int)} + + if not map[key](val): + raise ValueError(str(val) + " is not a valid value for " + key) + else: + return val + + def clear(self): + self.__dps = None + self.__miningyield = None + self.__volley = None + self.__reloadTime = None + self.__reloadForce = None + self.__chargeCycles = None + self.itemModifiedAttributes.clear() + self.chargeModifiedAttributes.clear() + + def calculateModifiedAttributes(self, fit, runTime, forceProjected=False, gang=False): + # We will run the effect when two conditions are met: + # 1: It makes sense to run the effect + # The effect is either offline + # or the effect is passive and the module is in the online state (or higher) + + # or the effect is active and the module is in the active state (or higher) + # or the effect is overheat and the module is in the overheated state (or higher) + # 2: the runtimes match + + if self.projected or forceProjected: + context = "projected", "module" + projected = True + else: + context = ("module",) + projected = False + + # if gang: + # context += ("commandRun",) + + if self.charge is not None: + # fix for #82 and it's regression #106 + if not projected or (self.projected and not forceProjected) or gang: + for effect in self.charge.effects.itervalues(): + if effect.runTime == runTime and \ + effect.activeByDefault and \ + (effect.isType("offline") or + (effect.isType("passive") and self.state >= State.ONLINE) or + (effect.isType("active") and self.state >= State.ACTIVE)) and \ + (not gang or (gang and effect.isType("gang"))): + + chargeContext = ("moduleCharge",) + # For gang effects, we pass in the effect itself as an argument. However, to avoid going through + # all the effect files and defining this argument, do a simple try/catch here and be done with it. + # @todo: possibly fix this + try: + effect.handler(fit, self, chargeContext, effect=effect) + except: + effect.handler(fit, self, chargeContext) + + if self.item: + if self.state >= State.OVERHEATED: + for effect in self.item.effects.itervalues(): + if effect.runTime == runTime and \ + effect.isType("overheat") \ + and not forceProjected \ + and effect.activeByDefault \ + and ((gang and effect.isType("gang")) or not gang): + effect.handler(fit, self, context) + + for effect in self.item.effects.itervalues(): + if effect.runTime == runTime and \ + effect.activeByDefault and \ + (effect.isType("offline") or + (effect.isType("passive") and self.state >= State.ONLINE) or + (effect.isType("active") and self.state >= State.ACTIVE)) \ + and ((projected and effect.isType("projected")) or not projected) \ + and ((gang and effect.isType("gang")) or not gang): + try: + effect.handler(fit, self, context, effect=effect) + except: + effect.handler(fit, self, context) + + @property + def cycleTime(self): + reactivation = (self.getModifiedItemAttr("moduleReactivationDelay") or 0) + # Reactivation time starts counting after end of module cycle + speed = self.rawCycleTime + reactivation + if self.charge: + reload = self.reloadTime + else: + reload = 0.0 + # Determine if we'll take into account reload time or not + factorReload = self.owner.factorReload if self.forceReload is None else self.forceReload + # If reactivation is longer than 10 seconds then module can be reloaded + # during reactivation time, thus we may ignore reload + if factorReload and reactivation < reload: + numShots = self.numShots + # Time it takes to reload module after end of reactivation time, + # given that we started when module cycle has just over + additionalReloadTime = (reload - reactivation) + # Speed here already takes into consideration reactivation time + speed = (speed * numShots + additionalReloadTime) / numShots if numShots > 0 else speed + + return speed + + @property + def rawCycleTime(self): + speed = self.getModifiedItemAttr("speed") or self.getModifiedItemAttr("duration") + return speed + + @property + def capUse(self): + capNeed = self.getModifiedItemAttr("capacitorNeed") + if capNeed and self.state >= State.ACTIVE: + cycleTime = self.cycleTime + capUsed = capNeed / (cycleTime / 1000.0) + return capUsed + else: + return 0 + + def __deepcopy__(self, memo): + item = self.item + if item is None: + copy = Module.buildEmpty(self.slot) + else: + copy = Module(self.item) + copy.charge = self.charge + copy.state = self.state + return copy + + def __repr__(self): + if self.item: + return "Module(ID={}, name={}) at {}".format( + self.item.ID, self.item.name, hex(id(self)) + ) + else: + return "EmptyModule() at {}".format(hex(id(self))) + + +class Rack(Module): + """ + This is simply the Module class named something else to differentiate + it for app logic. This class does not do anything special + """ + pass diff --git a/eos/saveddata/targetResists.py b/eos/saveddata/targetResists.py index 8b286b3f6..67cd323a8 100644 --- a/eos/saveddata/targetResists.py +++ b/eos/saveddata/targetResists.py @@ -77,7 +77,12 @@ class TargetResists(object): out += "# TargetResists = [name],[EM %],[Thermal %],[Kinetic %],[Explosive %]\n\n" for dp in patterns: out += cls.EXPORT_FORMAT % ( - dp.name, dp.emAmount * 100, dp.thermalAmount * 100, dp.kineticAmount * 100, dp.explosiveAmount * 100) + dp.name, + dp.emAmount * 100, + dp.thermalAmount * 100, + dp.kineticAmount * 100, + dp.explosiveAmount * 100 + ) return out.strip() diff --git a/eos/types.py b/eos/types.py index 1fbf2676b..e6663689f 100644 --- a/eos/types.py +++ b/eos/types.py @@ -18,7 +18,8 @@ # =============================================================================== from eos.gamedata import Attribute, Category, Effect, Group, Icon, Item, MarketGroup, \ - MetaGroup, AttributeInfo, Unit, EffectInfo, MetaType, MetaData, Traits + MetaGroup, AttributeInfo, Unit, EffectInfo, MetaType, MetaData, Traits, AlphaClone, \ + AlphaCloneSkill from eos.saveddata.price import Price from eos.saveddata.user import User from eos.saveddata.crestchar import CrestChar diff --git a/gui/PFListPane.py b/gui/PFListPane.py index 9385dbc75..556b97638 100644 --- a/gui/PFListPane.py +++ b/gui/PFListPane.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,13 +15,15 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx + class PFListPane(wx.ScrolledWindow): def __init__(self, parent): - wx.ScrolledWindow.__init__ (self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(1, 1), style=wx.TAB_TRAVERSAL) + wx.ScrolledWindow.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(1, 1), + style=wx.TAB_TRAVERSAL) self._wList = [] self._wCount = 0 @@ -29,19 +31,18 @@ class PFListPane(wx.ScrolledWindow): self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) - self.SetVirtualSize((1, 1)) self.SetScrollRate(0, 1) self.Bind(wx.EVT_SCROLLWIN_LINEUP, self.MScrollUp) self.Bind(wx.EVT_SCROLLWIN_LINEDOWN, self.MScrollDown) -# self.Bind(wx.EVT_CHILD_FOCUS, self.OnChildFocus) -# self.Bind(wx.EVT_LEFT_DOWN, self.ForceFocus) + # self.Bind(wx.EVT_CHILD_FOCUS, self.OnChildFocus) + # self.Bind(wx.EVT_LEFT_DOWN, self.ForceFocus) self.SetFocus() -# self.Bind(wx.EVT_MOUSE_CAPTURE_CHANGED, self.ForceFocus) + # self.Bind(wx.EVT_MOUSE_CAPTURE_CHANGED, self.ForceFocus) self.Bind(wx.EVT_SCROLLWIN_THUMBRELEASE, self.ForceFocus) - def ForceFocus(self,event): + def ForceFocus(self, event): if self.FindFocus() and self.FindFocus().Parent != self: self.SetFocus() event.Skip() @@ -67,13 +68,12 @@ class PFListPane(wx.ScrolledWindow): event.Skip() - def ScrollChildIntoView(self, child): """ Scrolls the panel such that the specified child window is in view. """ sppu_x, sppu_y = self.GetScrollPixelsPerUnit() - vs_x, vs_y = self.GetViewStart() + vs_x, vs_y = self.GetViewStart() cr = child.GetRect() clntsz = self.GetSize() new_vs_x, new_vs_y = -1, -1 @@ -110,8 +110,6 @@ class PFListPane(wx.ScrolledWindow): if new_vs_x != -1 or new_vs_y != -1: self.Scroll(new_vs_x, new_vs_y) - - def AddWidget(self, widget): widget.Reparent(self) self._wList.append(widget) @@ -124,13 +122,11 @@ class PFListPane(wx.ScrolledWindow): def IsWidgetSelectedByContext(self, widget): return False - def RefreshList(self, doRefresh = False, doFocus = False): - ypos = 0 + def RefreshList(self, doRefresh=False, doFocus=False): maxy = 0 - scrollTo = 0 selected = None - for i in xrange( len(self._wList) ): + for i in xrange(len(self._wList)): iwidth, iheight = self._wList[i].GetSize() xa, ya = self.CalcScrolledPosition((0, maxy)) self._wList[i].SetPosition((xa, ya)) @@ -143,16 +139,16 @@ class PFListPane(wx.ScrolledWindow): if selected: self.ScrollChildIntoView(selected) - #selected.SetFocus() + # selected.SetFocus() elif doFocus: self.SetFocus() - clientW,clientH = self.GetSize() - for i in xrange( len(self._wList) ): + clientW, clientH = self.GetSize() + for i in xrange(len(self._wList)): iwidth, iheight = self._wList[i].GetSize() - itemX,itemY = self._wList[i].GetPosition() + itemX, itemY = self._wList[i].GetPosition() self._wList[i].SetSize((cwidth, iheight)) - if doRefresh == True: + if doRefresh is True: self._wList[i].Refresh() self.itemsHeight = max(self.itemsHeight, iheight - 1) @@ -160,7 +156,6 @@ class PFListPane(wx.ScrolledWindow): child.Destroy() self._wList.remove(child) - def RemoveAllChildren(self): for widget in self._wList: widget.Destroy() diff --git a/gui/PFSearchBox.py b/gui/PFSearchBox.py index 7fff91e9b..ece5cef5f 100644 --- a/gui/PFSearchBox.py +++ b/gui/PFSearchBox.py @@ -1,17 +1,16 @@ import wx import gui.utils.colorUtils as colorUtils import gui.utils.drawUtils as drawUtils -from gui.bitmapLoader import BitmapLoader - SearchButton, EVT_SEARCH_BTN = wx.lib.newevent.NewEvent() CancelButton, EVT_CANCEL_BTN = wx.lib.newevent.NewEvent() TextEnter, EVT_TEXT_ENTER = wx.lib.newevent.NewEvent() TextTyped, EVT_TEXT = wx.lib.newevent.NewEvent() + class PFSearchBox(wx.Window): - def __init__(self, parent, id = wx.ID_ANY, value = "", pos = wx.DefaultPosition, size = wx.Size(-1,24), style = 0): - wx.Window.__init__(self, parent, id, pos, size, style = style) + def __init__(self, parent, id=wx.ID_ANY, value="", pos=wx.DefaultPosition, size=wx.Size(-1, 24), style=0): + wx.Window.__init__(self, parent, id, pos, size, style=style) self.isSearchButtonVisible = False self.isCancelButtonVisible = False @@ -35,13 +34,14 @@ class PFSearchBox(wx.Window): self.editX = 0 self.editY = 0 - self.padding = 4 self._hl = False - w,h = size - self.EditBox = wx.TextCtrl(self, wx.ID_ANY, "", wx.DefaultPosition, (-1, h - 2 if 'wxGTK' in wx.PlatformInfo else -1 ), wx.TE_PROCESS_ENTER | (wx.BORDER_NONE if 'wxGTK' in wx.PlatformInfo else 0)) + w, h = size + self.EditBox = wx.TextCtrl(self, wx.ID_ANY, "", wx.DefaultPosition, + (-1, h - 2 if 'wxGTK' in wx.PlatformInfo else -1), + wx.TE_PROCESS_ENTER | (wx.BORDER_NONE if 'wxGTK' in wx.PlatformInfo else 0)) self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBk) @@ -50,7 +50,7 @@ class PFSearchBox(wx.Window): self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) -# self.EditBox.ChangeValue(self.descriptiveText) + # self.EditBox.ChangeValue(self.descriptiveText) self.EditBox.Bind(wx.EVT_SET_FOCUS, self.OnEditSetFocus) self.EditBox.Bind(wx.EVT_KILL_FOCUS, self.OnEditKillFocus) @@ -68,11 +68,10 @@ class PFSearchBox(wx.Window): wx.PostEvent(self, TextEnter()) event.Skip() - def OnEditSetFocus(self, event): -# value = self.EditBox.GetValue() -# if value == self.descriptiveText: -# self.EditBox.ChangeValue("") + # value = self.EditBox.GetValue() + # if value == self.descriptiveText: + # self.EditBox.ChangeValue("") event.Skip() def OnEditKillFocus(self, event): @@ -80,10 +79,9 @@ class PFSearchBox(wx.Window): self.Clear() event.Skip() - def Clear(self): self.EditBox.Clear() -# self.EditBox.ChangeValue(self.descriptiveText) + # self.EditBox.ChangeValue(self.descriptiveText) def Focus(self): self.EditBox.SetFocus() @@ -110,8 +108,8 @@ class PFSearchBox(wx.Window): def GetButtonsPos(self): btnpos = [] - btnpos.append( (self.searchButtonX, self.searchButtonY) ) - btnpos.append( (self.cancelButtonX, self.cancelButtonY) ) + btnpos.append((self.searchButtonX, self.searchButtonY)) + btnpos.append((self.cancelButtonX, self.cancelButtonY)) return btnpos def GetButtonsSize(self): @@ -131,8 +129,8 @@ class PFSearchBox(wx.Window): cw = 0 ch = 0 - btnsize.append( (sw,sh)) - btnsize.append( (cw,ch)) + btnsize.append((sw, sh)) + btnsize.append((cw, ch)) return btnsize def OnLeftDown(self, event): @@ -140,7 +138,7 @@ class PFSearchBox(wx.Window): btnsize = self.GetButtonsSize() self.CaptureMouse() - for btn in xrange(2): + for btn in range(2): if self.HitTest(btnpos[btn], event.GetPosition(), btnsize[btn]): if btn == 0: if not self.searchButtonPressed: @@ -158,7 +156,7 @@ class PFSearchBox(wx.Window): if self.HasCapture(): self.ReleaseMouse() - for btn in xrange(2): + for btn in range(2): if self.HitTest(btnpos[btn], event.GetPosition(), btnsize[btn]): if btn == 0: if self.searchButtonPressed: @@ -218,9 +216,9 @@ class PFSearchBox(wx.Window): editWidth, editHeight = self.EditBox.GetSize() - self.editY = (cheight - editHeight)/2 + self.editY = (cheight - editHeight) / 2 self.EditBox.SetPosition((self.editX, self.editY)) - self.EditBox.SetSize( (self.cancelButtonX - self.padding - self.editX, -1)) + self.EditBox.SetSize((self.cancelButtonX - self.padding - self.editX, -1)) def OnPaint(self, event): dc = wx.BufferedPaintDC(self) @@ -246,7 +244,6 @@ class PFSearchBox(wx.Window): dc.DrawBitmap(self.searchBitmapShadow, self.searchButtonX + 1, self.searchButtonY + 1) dc.DrawBitmap(self.searchBitmap, self.searchButtonX + spad, self.searchButtonY + spad) - if self.isCancelButtonVisible: if self.cancelBitmap: if self.cancelButtonPressed: @@ -256,8 +253,8 @@ class PFSearchBox(wx.Window): dc.DrawBitmap(self.cancelBitmapShadow, self.cancelButtonX + 1, self.cancelButtonY + 1) dc.DrawBitmap(self.cancelBitmap, self.cancelButtonX + cpad, self.cancelButtonY + cpad) - dc.SetPen(wx.Pen(sepColor,1)) - dc.DrawLine(0,rect.height - 1, rect.width, rect.height - 1) + dc.SetPen(wx.Pen(sepColor, 1)) + dc.DrawLine(0, rect.height - 1, rect.width, rect.height - 1) def SetSearchBitmap(self, bitmap): self.searchBitmap = bitmap @@ -273,10 +270,10 @@ class PFSearchBox(wx.Window): def IsCancelButtonVisible(self): return self.isCancelButtonVisible - def ShowSearchButton(self, show = True): + def ShowSearchButton(self, show=True): self.isSearchButtonVisible = show - def ShowCancelButton(self, show = True): + def ShowCancelButton(self, show=True): self.isCancelButtonVisible = show def SetDescriptiveText(self, text): @@ -284,4 +281,3 @@ class PFSearchBox(wx.Window): def GetDescriptiveText(self): return self.descriptiveText - diff --git a/gui/aboutData.py b/gui/aboutData.py index be29b6298..6e8ce07bc 100644 --- a/gui/aboutData.py +++ b/gui/aboutData.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,7 +15,8 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= + import config versionString = "{0} {1} - {2} {3}".format(config.version, config.tag, config.expansionName, config.expansionVersion) @@ -27,7 +28,7 @@ licenses = ( ) developers = ( "blitzmann \tSable Blitzmann (maintainer)", - "cncfanatics \tSakari Orisi (retired)" , + "cncfanatics \tSakari Orisi (retired)", "DarkPhoenix \tKadesh Priestess (retired)", "Darriele \t\tDarriele (retired)", "Ebag333 \t\tEbag Trescientas" diff --git a/gui/additionsPane.py b/gui/additionsPane.py index e67963ee1..c0616f597 100644 --- a/gui/additionsPane.py +++ b/gui/additionsPane.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,7 +15,7 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx import gui.mainFrame @@ -33,11 +33,11 @@ from gui.bitmapLoader import BitmapLoader import gui.chromeTabs -class AdditionsPane(TogglePanel): +class AdditionsPane(TogglePanel): def __init__(self, parent): - TogglePanel.__init__(self, parent, forceLayout = 1) + TogglePanel.__init__(self, parent, forceLayout=1) self.SetLabel("Additions") pane = self.GetContentPane() @@ -62,28 +62,28 @@ class AdditionsPane(TogglePanel): notesImg = BitmapLoader.getImage("skill_small", "gui") self.drone = DroneView(self.notebook) - self.notebook.AddPage(self.drone, "Drones", tabImage = droneImg, showClose = False) + self.notebook.AddPage(self.drone, "Drones", tabImage=droneImg, showClose=False) self.fighter = FighterView(self.notebook) - self.notebook.AddPage(self.fighter, "Fighters", tabImage = fighterImg, showClose = False) + self.notebook.AddPage(self.fighter, "Fighters", tabImage=fighterImg, showClose=False) self.cargo = CargoView(self.notebook) - self.notebook.AddPage(self.cargo, "Cargo", tabImage = cargoImg, showClose = False) + self.notebook.AddPage(self.cargo, "Cargo", tabImage=cargoImg, showClose=False) self.implant = ImplantView(self.notebook) - self.notebook.AddPage(self.implant, "Implants", tabImage = implantImg, showClose = False) + self.notebook.AddPage(self.implant, "Implants", tabImage=implantImg, showClose=False) self.booster = BoosterView(self.notebook) - self.notebook.AddPage(self.booster, "Boosters", tabImage = boosterImg, showClose = False) + self.notebook.AddPage(self.booster, "Boosters", tabImage=boosterImg, showClose=False) self.projectedPage = ProjectedView(self.notebook) - self.notebook.AddPage(self.projectedPage, "Projected", tabImage = projectedImg, showClose = False) + self.notebook.AddPage(self.projectedPage, "Projected", tabImage=projectedImg, showClose=False) self.gangPage = CommandView(self.notebook) - self.notebook.AddPage(self.gangPage, "Command", tabImage = gangImg, showClose = False) + self.notebook.AddPage(self.gangPage, "Command", tabImage=gangImg, showClose=False) self.notes = NotesView(self.notebook) - self.notebook.AddPage(self.notes, "Notes", tabImage = notesImg, showClose = False) + self.notebook.AddPage(self.notes, "Notes", tabImage=notesImg, showClose=False) self.notebook.SetSelection(0) @@ -100,12 +100,12 @@ class AdditionsPane(TogglePanel): def toggleContent(self, event): TogglePanel.toggleContent(self, event) - h = self.headerPanel.GetSize()[1]+4 + h = self.headerPanel.GetSize()[1] + 4 if self.IsCollapsed(): self.old_pos = self.parent.GetSashPosition() self.parent.SetMinimumPaneSize(h) - self.parent.SetSashPosition(h*-1, True) + self.parent.SetSashPosition(h * -1, True) # only available in >= wx2.9 if getattr(self.parent, "SetSashInvisible", None): self.parent.SetSashInvisible(True) @@ -114,4 +114,3 @@ class AdditionsPane(TogglePanel): self.parent.SetSashInvisible(False) self.parent.SetMinimumPaneSize(200) self.parent.SetSashPosition(self.old_pos, True) - diff --git a/gui/bitmapLoader.py b/gui/bitmapLoader.py index 45026bedb..066fc0c5f 100644 --- a/gui/bitmapLoader.py +++ b/gui/bitmapLoader.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,23 +15,26 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= -import os.path -import config -import wx -import zipfile import cStringIO +import os.path +import zipfile +from config import parsePath + +import wx + +import config try: from collections import OrderedDict except ImportError: from utils.compat import OrderedDict -class BitmapLoader(): +class BitmapLoader(): try: - archive = zipfile.ZipFile(os.path.join(config.pyfaPath, 'imgs.zip'), 'r') + archive = zipfile.ZipFile(config.getPyfaPath('imgs.zip'), 'r') except IOError: archive = None @@ -42,7 +45,7 @@ class BitmapLoader(): @classmethod def getStaticBitmap(cls, name, parent, location): static = wx.StaticBitmap(parent) - static.SetBitmap(cls.getBitmap(name,location)) + static.SetBitmap(cls.getBitmap(name, location)) return static @classmethod @@ -74,7 +77,7 @@ class BitmapLoader(): filename = "{0}.png".format(name) if cls.archive: - path = os.path.join(location, filename) + path = parsePath(location, filename) if os.sep != "/" and os.sep in path: path = path.replace(os.sep, "/") @@ -83,11 +86,11 @@ class BitmapLoader(): sbuf = cStringIO.StringIO(img_data) return wx.ImageFromStream(sbuf) except KeyError: - print "Missing icon file from zip: {0}".format(path) + print("Missing icon file from zip: {0}".format(path)) else: - path = os.path.join(config.pyfaPath, 'imgs', location, filename) + path = config.getPyfaPath('imgs' + os.sep + location + os.sep + filename) if os.path.exists(path): return wx.Image(path) else: - print "Missing icon file: {0}".format(path) + print("Missing icon file: {0}".format(path)) diff --git a/gui/boosterView.py b/gui/boosterView.py index 5c8dca993..d4d631942 100644 --- a/gui/boosterView.py +++ b/gui/boosterView.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,29 +15,31 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx -import service import gui.display as d import gui.globalEvents as GE import gui.marketBrowser as mb from gui.builtinViewColumns.state import State from gui.contextMenu import ContextMenu +from service.fit import Fit + class BoosterViewDrop(wx.PyDropTarget): - def __init__(self, dropFn): - wx.PyDropTarget.__init__(self) - self.dropFn = dropFn - # this is really transferring an EVE itemID - self.dropData = wx.PyTextDataObject() - self.SetDataObject(self.dropData) + def __init__(self, dropFn): + wx.PyDropTarget.__init__(self) + self.dropFn = dropFn + # this is really transferring an EVE itemID + self.dropData = wx.PyTextDataObject() + self.SetDataObject(self.dropData) + + def OnData(self, x, y, t): + if self.GetData(): + data = self.dropData.GetText().split(':') + self.dropFn(x, y, data) + return t - def OnData(self, x, y, t): - if self.GetData(): - data = self.dropData.GetText().split(':') - self.dropFn(x, y, data) - return t class BoosterView(d.Display): DEFAULT_COLS = ["State", @@ -58,7 +60,7 @@ class BoosterView(d.Display): self.SetDropTarget(BoosterViewDrop(self.handleListDrag)) - if "__WXGTK__" in wx.PlatformInfo: + if "__WXGTK__" in wx.PlatformInfo: self.Bind(wx.EVT_RIGHT_UP, self.scheduleMenu) else: self.Bind(wx.EVT_RIGHT_DOWN, self.scheduleMenu) @@ -75,7 +77,7 @@ class BoosterView(d.Display): if data[0] == "market": wx.PostEvent(self.mainFrame, mb.ItemSelected(itemID=int(data[1]))) - def kbEvent(self,event): + def kbEvent(self, event): keycode = event.GetKeyCode() if keycode == wx.WXK_DELETE or keycode == wx.WXK_NUMPAD_DELETE: row = self.GetFirstSelected() @@ -85,12 +87,12 @@ class BoosterView(d.Display): event.Skip() def fitChanged(self, event): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(event.fitID) self.Parent.Parent.DisablePage(self, not fit or fit.isStructure) - #Clear list and get out if current fitId is None + # Clear list and get out if current fitId is None if event.fitID is None and self.lastFitId is not None: self.DeleteAllItems() self.lastFitId = None @@ -115,7 +117,7 @@ class BoosterView(d.Display): event.Skip() def addItem(self, event): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() fit = sFit.getFit(fitID) @@ -139,7 +141,7 @@ class BoosterView(d.Display): def removeBooster(self, booster): fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() sFit.removeBooster(fitID, self.origional.index(booster)) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) @@ -150,11 +152,10 @@ class BoosterView(d.Display): col = self.getColumn(event.Position) if col == self.getColIndex(State): fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() sFit.toggleBooster(fitID, row) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) - def scheduleMenu(self, event): event.Skip() if self.getColumn(event.Position) != self.getColIndex(State): @@ -163,7 +164,7 @@ class BoosterView(d.Display): def spawnMenu(self): sel = self.GetFirstSelected() if sel != -1: - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(self.mainFrame.getActiveFit()) item = fit.boosters[sel] diff --git a/gui/builtinContextMenus/__init__.py b/gui/builtinContextMenus/__init__.py index 55f26256a..c6a41c112 100644 --- a/gui/builtinContextMenus/__init__.py +++ b/gui/builtinContextMenus/__init__.py @@ -1,6 +1,6 @@ __all__ = [ "openFit", - #"moduleGlobalAmmoPicker", + # "moduleGlobalAmmoPicker", "moduleAmmoPicker", "itemStats", "damagePattern", diff --git a/gui/builtinContextMenus/ammoPattern.py b/gui/builtinContextMenus/ammoPattern.py index d8d789b68..be2833d9e 100644 --- a/gui/builtinContextMenus/ammoPattern.py +++ b/gui/builtinContextMenus/ammoPattern.py @@ -1,35 +1,37 @@ -from gui.contextMenu import ContextMenu -import gui.mainFrame -import service -import wx -import gui.globalEvents as GE - -class AmmoPattern(ContextMenu): - def __init__(self): - self.mainFrame = gui.mainFrame.MainFrame.getInstance() - - def display(self, srcContext, selection): - if srcContext not in ("marketItemGroup", "marketItemMisc") or self.mainFrame.getActiveFit() is None: - return False - - item = selection[0] - for attr in ("emDamage", "thermalDamage", "explosiveDamage", "kineticDamage"): - if item.getAttribute(attr) is not None: - return True - - return False - - def getText(self, itmContext, selection): - return "Set {0} as Damage Pattern".format(itmContext if itmContext is not None else "Item") - - def activate(self, fullContext, selection, i): - item = selection[0] - fit = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() - sFit.setAsPattern(fit, item) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fit)) - - def getBitmap(self, context, selection): - return None - -AmmoPattern.register() +from gui.contextMenu import ContextMenu +import gui.mainFrame +import wx +import gui.globalEvents as GE +from service.fit import Fit + + +class AmmoPattern(ContextMenu): + def __init__(self): + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + + def display(self, srcContext, selection): + if srcContext not in ("marketItemGroup", "marketItemMisc") or self.mainFrame.getActiveFit() is None: + return False + + item = selection[0] + for attr in ("emDamage", "thermalDamage", "explosiveDamage", "kineticDamage"): + if item.getAttribute(attr) is not None: + return True + + return False + + def getText(self, itmContext, selection): + return "Set {0} as Damage Pattern".format(itmContext if itmContext is not None else "Item") + + def activate(self, fullContext, selection, i): + item = selection[0] + fit = self.mainFrame.getActiveFit() + sFit = Fit.getInstance() + sFit.setAsPattern(fit, item) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fit)) + + def getBitmap(self, context, selection): + return None + + +AmmoPattern.register() diff --git a/gui/builtinContextMenus/amount.py b/gui/builtinContextMenus/amount.py index 79467e3a0..a4984a635 100644 --- a/gui/builtinContextMenus/amount.py +++ b/gui/builtinContextMenus/amount.py @@ -1,17 +1,19 @@ from gui.contextMenu import ContextMenu -from gui.itemStats import ItemStatsDialog import eos.types import gui.mainFrame -import service import gui.globalEvents as GE import wx +from service.fit import Fit +from eos.saveddata.cargo import Cargo as es_Cargo +from eos.saveddata.fighter import Fighter as es_Fighter + class ChangeAmount(ContextMenu): def __init__(self): self.mainFrame = gui.mainFrame.MainFrame.getInstance() def display(self, srcContext, selection): - return srcContext in ("cargoItem","projectedFit","fighterItem","projectedFighter") + return srcContext in ("cargoItem", "projectedFit", "fighterItem", "projectedFighter") def getText(self, itmContext, selection): return "Change {0} Quantity".format(itmContext) @@ -21,10 +23,11 @@ class ChangeAmount(ContextMenu): dlg = AmountChanger(self.mainFrame, selection[0], srcContext) dlg.ShowModal() + ChangeAmount.register() -class AmountChanger(wx.Dialog): +class AmountChanger(wx.Dialog): def __init__(self, parent, thing, context): wx.Dialog.__init__(self, parent, title="Select Amount", size=wx.Size(220, 60)) self.thing = thing @@ -46,35 +49,34 @@ class AmountChanger(wx.Dialog): self.button.Bind(wx.EVT_BUTTON, self.change) def change(self, event): + sFit = Fit.getInstance() if self.input.GetLineText(0).strip() == '': event.Skip() return - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() mainFrame = gui.mainFrame.MainFrame.getInstance() fitID = mainFrame.getActiveFit() - print self.input.GetLineText(0), type(self.input.GetLineText(0)) - if isinstance(self.thing, eos.types.Cargo): + if isinstance(self.thing, es_Cargo): sFit.addCargo(fitID, self.thing.item.ID, int(float(self.input.GetLineText(0))), replace=True) elif isinstance(self.thing, eos.types.Fit): sFit.changeAmount(fitID, self.thing, int(float(self.input.GetLineText(0)))) - elif isinstance(self.thing, eos.types.Fighter): + elif isinstance(self.thing, es_Fighter): sFit.changeActiveFighters(fitID, self.thing, int(float(self.input.GetLineText(0)))) wx.PostEvent(mainFrame, GE.FitChanged(fitID=fitID)) event.Skip() - ## checks to make sure it's valid number + # checks to make sure it's valid number def onChar(self, event): key = event.GetKeyCode() acceptable_characters = "1234567890" - acceptable_keycode = [3, 22, 13, 8, 127] # modifiers like delete, copy, paste + 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 - diff --git a/gui/builtinContextMenus/cargo.py b/gui/builtinContextMenus/cargo.py index 0b4c031b4..1f5ad4202 100644 --- a/gui/builtinContextMenus/cargo.py +++ b/gui/builtinContextMenus/cargo.py @@ -1,17 +1,16 @@ from gui.contextMenu import ContextMenu -from gui.itemStats import ItemStatsDialog -import eos.types import gui.mainFrame -import service import gui.globalEvents as GE import wx +from service.fit import Fit + class Cargo(ContextMenu): def __init__(self): self.mainFrame = gui.mainFrame.MainFrame.getInstance() def display(self, srcContext, selection): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() fit = sFit.getFit(fitID) @@ -24,7 +23,7 @@ class Cargo(ContextMenu): return "Add {0} to Cargo".format(itmContext) def activate(self, fullContext, selection, i): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() typeID = int(selection[0].ID) @@ -32,4 +31,5 @@ class Cargo(ContextMenu): self.mainFrame.additionsPane.select("Cargo") wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + Cargo.register() diff --git a/gui/builtinContextMenus/changeAffectingSkills.py b/gui/builtinContextMenus/changeAffectingSkills.py index 5111a8d27..79b7bd3bd 100644 --- a/gui/builtinContextMenus/changeAffectingSkills.py +++ b/gui/builtinContextMenus/changeAffectingSkills.py @@ -1,11 +1,13 @@ # -*- coding: utf-8 -*- from gui.contextMenu import ContextMenu import gui.mainFrame -import service import wx from gui.bitmapLoader import BitmapLoader from eos.types import Skill import gui.globalEvents as GE +from service.fit import Fit +from service.character import Character + class ChangeAffectingSkills(ContextMenu): def __init__(self): @@ -15,18 +17,18 @@ class ChangeAffectingSkills(ContextMenu): if self.mainFrame.getActiveFit() is None or srcContext not in ("fittingModule", "fittingCharge", "fittingShip"): return False - self.sChar = service.Character.getInstance() - self.sFit = service.Fit.getInstance() + self.sChar = Character.getInstance() + self.sFit = Fit.getInstance() fit = self.sFit.getFit(self.mainFrame.getActiveFit()) self.charID = fit.character.ID - #if self.sChar.getCharName(self.charID) in ("All 0", "All 5"): + # if self.sChar.getCharName(self.charID) in ("All 0", "All 5"): # return False if srcContext == "fittingShip": fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() self.stuff = sFit.getFit(fitID).ship cont = sFit.getFit(fitID).ship.itemModifiedAttributes elif srcContext == "fittingCharge": @@ -99,4 +101,5 @@ class ChangeAffectingSkills(ContextMenu): wx.PostEvent(self.mainFrame, GE.CharListUpdated()) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + ChangeAffectingSkills.register() diff --git a/gui/builtinContextMenus/damagePattern.py b/gui/builtinContextMenus/damagePattern.py index 8d9b6be32..b2089e9c0 100644 --- a/gui/builtinContextMenus/damagePattern.py +++ b/gui/builtinContextMenus/damagePattern.py @@ -1,15 +1,17 @@ from gui.contextMenu import ContextMenu import gui.mainFrame -import service import gui.globalEvents as GE import wx from gui.bitmapLoader import BitmapLoader +from service.fit import Fit +from service.damagePattern import DamagePattern as import_DamagePattern try: from collections import OrderedDict except ImportError: from gui.utils.compat import OrderedDict + class DamagePattern(ContextMenu): def __init__(self): self.mainFrame = gui.mainFrame.MainFrame.getInstance() @@ -18,8 +20,8 @@ class DamagePattern(ContextMenu): return srcContext == "resistancesViewFull" and self.mainFrame.getActiveFit() is not None def getText(self, itmContext, selection): - sDP = service.DamagePattern.getInstance() - sFit = service.Fit.getInstance() + sDP = import_DamagePattern.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() self.fit = sFit.getFit(fitID) @@ -34,9 +36,9 @@ class DamagePattern(ContextMenu): for pattern in self.patterns: start, end = pattern.name.find('['), pattern.name.find(']') if start is not -1 and end is not -1: - currBase = pattern.name[start+1:end] + currBase = pattern.name[start + 1:end] # set helper attr - setattr(pattern, "_name", pattern.name[end+1:].strip()) + setattr(pattern, "_name", pattern.name[end + 1:].strip()) if currBase not in self.subMenus: self.subMenus[currBase] = [] self.subMenus[currBase].append(pattern) @@ -59,7 +61,7 @@ class DamagePattern(ContextMenu): menuItem.pattern = pattern # determine active pattern - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() f = sFit.getFit(fitID) dp = f.damagePattern @@ -98,10 +100,11 @@ class DamagePattern(ContextMenu): event.Skip() return - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() sFit.setDamagePattern(fitID, pattern) - setattr(self.mainFrame,"_activeDmgPattern", pattern) + setattr(self.mainFrame, "_activeDmgPattern", pattern) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + DamagePattern.register() diff --git a/gui/builtinContextMenus/droneRemoveStack.py b/gui/builtinContextMenus/droneRemoveStack.py index f5c94853b..8132a8fc9 100644 --- a/gui/builtinContextMenus/droneRemoveStack.py +++ b/gui/builtinContextMenus/droneRemoveStack.py @@ -1,8 +1,9 @@ from gui.contextMenu import ContextMenu import gui.mainFrame -import service import wx import gui.globalEvents as GE +from service.fit import Fit + class ItemRemove(ContextMenu): def __init__(self): @@ -15,7 +16,7 @@ class ItemRemove(ContextMenu): return "Remove {0} Stack".format(itmContext) def activate(self, fullContext, selection, i): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() fit = sFit.getFit(fitID) @@ -24,4 +25,5 @@ class ItemRemove(ContextMenu): wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + ItemRemove.register() diff --git a/gui/builtinContextMenus/droneSplit.py b/gui/builtinContextMenus/droneSplit.py index f4d2b5a44..2f2ec923e 100644 --- a/gui/builtinContextMenus/droneSplit.py +++ b/gui/builtinContextMenus/droneSplit.py @@ -1,59 +1,59 @@ -from gui.contextMenu import ContextMenu -from gui.itemStats import ItemStatsDialog -import gui.mainFrame -import gui.globalEvents as GE -import service -import wx - -class DroneSplit(ContextMenu): - def __init__(self): - self.mainFrame = gui.mainFrame.MainFrame.getInstance() - - def display(self, srcContext, selection): - return srcContext in ("droneItem", "projectedDrone") and selection[0].amount > 1 - - def getText(self, itmContext, selection): - return "Split {0} Stack".format(itmContext) - - def activate(self, fullContext, selection, i): - srcContext = fullContext[0] - dlg = DroneSpinner(self.mainFrame, selection[0], srcContext) - dlg.ShowModal() - dlg.Destroy() - -DroneSplit.register() - - -class DroneSpinner(wx.Dialog): - - def __init__(self, parent, drone, context): - wx.Dialog.__init__(self, parent, title="Select Amount", size=wx.Size(220, 60)) - self.drone = drone - self.context = context - - bSizer1 = wx.BoxSizer(wx.HORIZONTAL) - - self.spinner = wx.SpinCtrl(self) - self.spinner.SetRange(1, drone.amount - 1) - self.spinner.SetValue(1) - - bSizer1.Add(self.spinner, 0, wx.ALL, 5) - - self.button = wx.Button(self, wx.ID_OK, u"Split") - bSizer1.Add(self.button, 0, wx.ALL, 5) - - self.SetSizer(bSizer1) - self.Layout() - self.Centre(wx.BOTH) - self.button.Bind(wx.EVT_BUTTON, self.split) - - def split(self, event): - sFit = service.Fit.getInstance() - mainFrame = gui.mainFrame.MainFrame.getInstance() - fitID = mainFrame.getActiveFit() - if self.context == "droneItem": - sFit.splitDroneStack(fitID, self.drone, self.spinner.GetValue()) - else: - sFit.splitProjectedDroneStack(fitID, self.drone, self.spinner.GetValue()) - wx.PostEvent(mainFrame, GE.FitChanged(fitID=fitID)) - event.Skip() +from gui.contextMenu import ContextMenu +import gui.mainFrame +import gui.globalEvents as GE +from service.fit import Fit +import wx + + +class DroneSplit(ContextMenu): + def __init__(self): + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + + def display(self, srcContext, selection): + return srcContext in ("droneItem", "projectedDrone") and selection[0].amount > 1 + + def getText(self, itmContext, selection): + return "Split {0} Stack".format(itmContext) + + def activate(self, fullContext, selection, i): + srcContext = fullContext[0] + dlg = DroneSpinner(self.mainFrame, selection[0], srcContext) + dlg.ShowModal() + dlg.Destroy() + + +DroneSplit.register() + + +class DroneSpinner(wx.Dialog): + def __init__(self, parent, drone, context): + wx.Dialog.__init__(self, parent, title="Select Amount", size=wx.Size(220, 60)) + self.drone = drone + self.context = context + + bSizer1 = wx.BoxSizer(wx.HORIZONTAL) + + self.spinner = wx.SpinCtrl(self) + self.spinner.SetRange(1, drone.amount - 1) + self.spinner.SetValue(1) + + bSizer1.Add(self.spinner, 0, wx.ALL, 5) + + self.button = wx.Button(self, wx.ID_OK, u"Split") + bSizer1.Add(self.button, 0, wx.ALL, 5) + + self.SetSizer(bSizer1) + self.Layout() + self.Centre(wx.BOTH) + self.button.Bind(wx.EVT_BUTTON, self.split) + + def split(self, event): + sFit = Fit.getInstance() + mainFrame = gui.mainFrame.MainFrame.getInstance() + fitID = mainFrame.getActiveFit() + if self.context == "droneItem": + sFit.splitDroneStack(fitID, self.drone, self.spinner.GetValue()) + else: + sFit.splitProjectedDroneStack(fitID, self.drone, self.spinner.GetValue()) + wx.PostEvent(mainFrame, GE.FitChanged(fitID=fitID)) + event.Skip() diff --git a/gui/builtinContextMenus/factorReload.py b/gui/builtinContextMenus/factorReload.py index c258240ea..d7b33658d 100644 --- a/gui/builtinContextMenus/factorReload.py +++ b/gui/builtinContextMenus/factorReload.py @@ -1,35 +1,36 @@ -from gui.contextMenu import ContextMenu -import gui.mainFrame -import service -import gui.globalEvents as GE -import wx -from gui.bitmapLoader import BitmapLoader - -class FactorReload(ContextMenu): - def __init__(self): - self.mainFrame = gui.mainFrame.MainFrame.getInstance() - - def display(self, srcContext, selection): - return srcContext == "firepowerViewFull" and self.mainFrame.getActiveFit() is not None - - def getText(self, itmContext, selection): - return "Factor in Reload Time" - - def activate(self, fullContext, selection, i): - sFit = service.Fit.getInstance() - sFit.serviceFittingOptions["useGlobalForceReload"] = not sFit.serviceFittingOptions["useGlobalForceReload"] - fitID = self.mainFrame.getActiveFit() - sFit.refreshFit(fitID) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) - - def getBitmap(self, context, selection): - sFit = service.Fit.getInstance() - fitID = self.mainFrame.getActiveFit() - fit = sFit.getFit(fitID) - if fit.factorReload: - return BitmapLoader.getBitmap("state_active_small", "gui") - else: - return None - - -FactorReload.register() +from gui.contextMenu import ContextMenu +import gui.mainFrame +import gui.globalEvents as GE +import wx +from gui.bitmapLoader import BitmapLoader +from service.fit import Fit + + +class FactorReload(ContextMenu): + def __init__(self): + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + + def display(self, srcContext, selection): + return srcContext == "firepowerViewFull" and self.mainFrame.getActiveFit() is not None + + def getText(self, itmContext, selection): + return "Factor in Reload Time" + + def activate(self, fullContext, selection, i): + sFit = Fit.getInstance() + sFit.serviceFittingOptions["useGlobalForceReload"] = not sFit.serviceFittingOptions["useGlobalForceReload"] + fitID = self.mainFrame.getActiveFit() + sFit.refreshFit(fitID) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + + def getBitmap(self, context, selection): + sFit = Fit.getInstance() + fitID = self.mainFrame.getActiveFit() + fit = sFit.getFit(fitID) + if fit.factorReload: + return BitmapLoader.getBitmap("state_active_small", "gui") + else: + return None + + +FactorReload.register() diff --git a/gui/builtinContextMenus/fighterAbilities.py b/gui/builtinContextMenus/fighterAbilities.py index 9a86c23b1..d262cb052 100644 --- a/gui/builtinContextMenus/fighterAbilities.py +++ b/gui/builtinContextMenus/fighterAbilities.py @@ -1,8 +1,9 @@ import wx from gui.contextMenu import ContextMenu import gui.mainFrame -import service import gui.globalEvents as GE +from service.fit import Fit + class FighterAbility(ContextMenu): def __init__(self): @@ -48,9 +49,10 @@ class FighterAbility(ContextMenu): event.Skip() return - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() sFit.toggleFighterAbility(fitID, ability) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + FighterAbility.register() diff --git a/gui/builtinContextMenus/implantSets.py b/gui/builtinContextMenus/implantSets.py index 8dcf6dd1f..490f52ef2 100644 --- a/gui/builtinContextMenus/implantSets.py +++ b/gui/builtinContextMenus/implantSets.py @@ -1,8 +1,11 @@ from gui.contextMenu import ContextMenu import gui.mainFrame -import service import gui.globalEvents as GE import wx +from service.implantSet import ImplantSets as s_ImplantSets +from service.character import Character +from service.fit import Fit + class ImplantSets(ContextMenu): def __init__(self): @@ -32,7 +35,7 @@ class ImplantSets(ContextMenu): m = wx.Menu() bindmenu = rootMenu if "wxMSW" in wx.PlatformInfo else m - sIS = service.ImplantSets.getInstance() + sIS = s_ImplantSets.getInstance() implantSets = sIS.getImplantSetList() self.context = context @@ -59,7 +62,7 @@ class ImplantSets(ContextMenu): if self.context == "implantEditor": # we are calling from character editor, the implant source is different - sChar = service.Character.getInstance() + sChar = Character.getInstance() charID = self.selection.getActiveCharacter() for implant in set.implants: @@ -67,7 +70,7 @@ class ImplantSets(ContextMenu): wx.PostEvent(self.selection, GE.CharChanged()) else: - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() for implant in set.implants: sFit.addImplant(fitID, implant.item.ID, recalc=implant == set.implants[-1]) diff --git a/gui/builtinContextMenus/itemRemove.py b/gui/builtinContextMenus/itemRemove.py index c355d98b5..400890b1a 100644 --- a/gui/builtinContextMenus/itemRemove.py +++ b/gui/builtinContextMenus/itemRemove.py @@ -1,8 +1,9 @@ from gui.contextMenu import ContextMenu import gui.mainFrame -import service import wx import gui.globalEvents as GE +from service.fit import Fit + class ItemRemove(ContextMenu): def __init__(self): @@ -21,15 +22,15 @@ class ItemRemove(ContextMenu): def activate(self, fullContext, selection, i): srcContext = fullContext[0] - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() fit = sFit.getFit(fitID) if srcContext == "fittingModule": for module in selection: if module is not None: - sFit.removeModule(fitID,fit.modules.index(module)) - elif srcContext in ("fittingCharge" , "projectedCharge"): + sFit.removeModule(fitID, fit.modules.index(module)) + elif srcContext in ("fittingCharge", "projectedCharge"): sFit.setAmmo(fitID, None, selection) elif srcContext == "droneItem": sFit.removeDrone(fitID, fit.drones.index(selection[0])) @@ -47,6 +48,4 @@ class ItemRemove(ContextMenu): wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) - - ItemRemove.register() diff --git a/gui/builtinContextMenus/itemStats.py b/gui/builtinContextMenus/itemStats.py index df059e782..2ccc3d364 100644 --- a/gui/builtinContextMenus/itemStats.py +++ b/gui/builtinContextMenus/itemStats.py @@ -1,65 +1,67 @@ -from gui.contextMenu import ContextMenu -from gui.itemStats import ItemStatsDialog -import gui.mainFrame -import service -import wx - -class ItemStats(ContextMenu): - def __init__(self): - self.mainFrame = gui.mainFrame.MainFrame.getInstance() - - def display(self, srcContext, selection): - - return srcContext in ("marketItemGroup", "marketItemMisc", - "fittingModule", "fittingCharge", - "fittingShip", "baseShip", - "cargoItem", "droneItem", - "implantItem", "boosterItem", - "skillItem", "projectedModule", - "projectedDrone", "projectedCharge", - "itemStats", "fighterItem", - "implantItemChar", "projectedFighter", - "fittingMode") - - def getText(self, itmContext, selection): - return "{0} Stats".format(itmContext if itmContext is not None else "Item") - - def activate(self, fullContext, selection, i): - srcContext = fullContext[0] - if srcContext == "fittingShip": - fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() - stuff = sFit.getFit(fitID).ship - elif srcContext == "fittingMode": - stuff = selection[0].item - else: - stuff = selection[0] - - if srcContext == "fittingModule" and stuff.isEmpty: - return - - mstate = wx.GetMouseState() - reuse = False - - if mstate.CmdDown(): - reuse = True - - if self.mainFrame.GetActiveStatsWindow() is None and reuse: - ItemStatsDialog(stuff, fullContext) - - elif reuse: - lastWnd = self.mainFrame.GetActiveStatsWindow() - pos = lastWnd.GetPosition() - maximized = lastWnd.IsMaximized() - if not maximized: - size = lastWnd.GetSize() - else: - size = wx.DefaultSize - pos = wx.DefaultPosition - ItemStatsDialog(stuff, fullContext, pos, size, maximized) - lastWnd.closeEvent(None) - - else: - ItemStatsDialog(stuff, fullContext) - -ItemStats.register() +from gui.contextMenu import ContextMenu +from gui.itemStats import ItemStatsDialog +import gui.mainFrame +import wx +from service.fit import Fit + + +class ItemStats(ContextMenu): + def __init__(self): + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + + def display(self, srcContext, selection): + + return srcContext in ("marketItemGroup", "marketItemMisc", + "fittingModule", "fittingCharge", + "fittingShip", "baseShip", + "cargoItem", "droneItem", + "implantItem", "boosterItem", + "skillItem", "projectedModule", + "projectedDrone", "projectedCharge", + "itemStats", "fighterItem", + "implantItemChar", "projectedFighter", + "fittingMode") + + def getText(self, itmContext, selection): + return "{0} Stats".format(itmContext if itmContext is not None else "Item") + + def activate(self, fullContext, selection, i): + srcContext = fullContext[0] + if srcContext == "fittingShip": + fitID = self.mainFrame.getActiveFit() + sFit = Fit.getInstance() + stuff = sFit.getFit(fitID).ship + elif srcContext == "fittingMode": + stuff = selection[0].item + else: + stuff = selection[0] + + if srcContext == "fittingModule" and stuff.isEmpty: + return + + mstate = wx.GetMouseState() + reuse = False + + if mstate.CmdDown(): + reuse = True + + if self.mainFrame.GetActiveStatsWindow() is None and reuse: + ItemStatsDialog(stuff, fullContext) + + elif reuse: + lastWnd = self.mainFrame.GetActiveStatsWindow() + pos = lastWnd.GetPosition() + maximized = lastWnd.IsMaximized() + if not maximized: + size = lastWnd.GetSize() + else: + size = wx.DefaultSize + pos = wx.DefaultPosition + ItemStatsDialog(stuff, fullContext, pos, size, maximized) + lastWnd.closeEvent(None) + + else: + ItemStatsDialog(stuff, fullContext) + + +ItemStats.register() diff --git a/gui/builtinContextMenus/marketJump.py b/gui/builtinContextMenus/marketJump.py index 75884576d..e96292b41 100644 --- a/gui/builtinContextMenus/marketJump.py +++ b/gui/builtinContextMenus/marketJump.py @@ -1,48 +1,49 @@ -from gui.contextMenu import ContextMenu -from gui.itemStats import ItemStatsDialog -import gui.mainFrame -import service - -class MarketJump(ContextMenu): - def __init__(self): - self.mainFrame = gui.mainFrame.MainFrame.getInstance() - - def display(self, srcContext, selection): - validContexts = ("marketItemMisc", "fittingModule", - "fittingCharge", "droneItem", - "implantItem", "boosterItem", - "projectedModule", "projectedDrone", - "projectedCharge", "cargoItem", - "implantItemChar", "fighterItem", - "projectedDrone") - - if not srcContext in validContexts or selection is None or len(selection) < 1: - return False - - sMkt = service.Market.getInstance() - item = getattr(selection[0], "item", selection[0]) - mktGrp = sMkt.getMarketGroupByItem(item) - - # 1663 is Special Edition Festival Assets, we don't have root group for it - if mktGrp is None or mktGrp.ID == 1663: - return False - - doit = not selection[0].isEmpty if srcContext == "fittingModule" else True - return doit - - def getText(self, itmContext, selection): - return "{0} Market Group".format(itmContext if itmContext is not None else "Item") - - def activate(self, fullContext, selection, i): - srcContext = fullContext[0] - if srcContext in ("fittingCharge", "projectedCharge"): - item = selection[0].charge - elif hasattr(selection[0], "item"): - item = selection[0].item - else: - item = selection[0] - - self.mainFrame.notebookBrowsers.SetSelection(0) - self.mainFrame.marketBrowser.jump(item) - -MarketJump.register() +from gui.contextMenu import ContextMenu +import gui.mainFrame +from service.market import Market + + +class MarketJump(ContextMenu): + def __init__(self): + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + + def display(self, srcContext, selection): + validContexts = ("marketItemMisc", "fittingModule", + "fittingCharge", "droneItem", + "implantItem", "boosterItem", + "projectedModule", "projectedDrone", + "projectedCharge", "cargoItem", + "implantItemChar", "fighterItem", + "projectedDrone") + + if srcContext not in validContexts or selection is None or len(selection) < 1: + return False + + sMkt = Market.getInstance() + item = getattr(selection[0], "item", selection[0]) + mktGrp = sMkt.getMarketGroupByItem(item) + + # 1663 is Special Edition Festival Assets, we don't have root group for it + if mktGrp is None or mktGrp.ID == 1663: + return False + + doit = not selection[0].isEmpty if srcContext == "fittingModule" else True + return doit + + def getText(self, itmContext, selection): + return "{0} Market Group".format(itmContext if itmContext is not None else "Item") + + def activate(self, fullContext, selection, i): + srcContext = fullContext[0] + if srcContext in ("fittingCharge", "projectedCharge"): + item = selection[0].charge + elif hasattr(selection[0], "item"): + item = selection[0].item + else: + item = selection[0] + + self.mainFrame.notebookBrowsers.SetSelection(0) + self.mainFrame.marketBrowser.jump(item) + + +MarketJump.register() diff --git a/gui/builtinContextMenus/metaSwap.py b/gui/builtinContextMenus/metaSwap.py index 0b2d847ac..3462410e5 100644 --- a/gui/builtinContextMenus/metaSwap.py +++ b/gui/builtinContextMenus/metaSwap.py @@ -1,10 +1,13 @@ -# -*- coding: utf-8 -*- -from gui.contextMenu import ContextMenu -from gui.itemStats import ItemStatsDialog -import gui.mainFrame -import service +# coding: utf-8 + 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 + class MetaSwap(ContextMenu): def __init__(self): @@ -17,7 +20,7 @@ class MetaSwap(ContextMenu): # Check if list of variations is same for all of selection # If not - don't show the menu - mkt = service.Market.getInstance() + mkt = Market.getInstance() self.variations = None for i in selection: variations = mkt.getVariationsByItems([i.item]) @@ -41,7 +44,8 @@ class MetaSwap(ContextMenu): self.moduleLookup = {} def get_metalevel(x): - if "metaLevel" not in x.attributes: return 0 + if "metaLevel" not in x.attributes: + return 0 return x.attributes["metaLevel"].value def get_metagroup(x): @@ -88,14 +92,15 @@ class MetaSwap(ContextMenu): event.Skip() return - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() fit = sFit.getFit(fitID) - + for mod in self.selection: pos = fit.modules.index(mod) sFit.changeModule(fitID, pos, item.ID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + MetaSwap.register() diff --git a/gui/builtinContextMenus/moduleAmmoPicker.py b/gui/builtinContextMenus/moduleAmmoPicker.py index 3e7ee02cd..e69aac4cd 100644 --- a/gui/builtinContextMenus/moduleAmmoPicker.py +++ b/gui/builtinContextMenus/moduleAmmoPicker.py @@ -1,223 +1,230 @@ -# -*- coding: utf-8 -*- -from gui.contextMenu import ContextMenu -import gui.mainFrame -import service -import wx -from gui.bitmapLoader import BitmapLoader -from eos.types import Hardpoint -import gui.globalEvents as GE - -class ModuleAmmoPicker(ContextMenu): - DAMAGE_TYPES = ("em", "explosive", "kinetic", "thermal") - MISSILE_ORDER = ("em", "thermal", "kinetic", "explosive", "mixed") - - def __init__(self): - self.mainFrame = gui.mainFrame.MainFrame.getInstance() - - def display(self, srcContext, selection): - if self.mainFrame.getActiveFit() is None or srcContext not in ("fittingModule", "projectedModule"): - return False - - modules = selection if srcContext == "fittingModule" else (selection[0],) - - validCharges = None - checkedTypes = set() - - for mod in modules: - # loop through modules and gather list of valid charges - if mod.item.ID in checkedTypes: - continue - checkedTypes.add(mod.item.ID) - currCharges = mod.getValidCharges() - if len(currCharges) > 0: - if validCharges is not None and validCharges != currCharges: - return False - - validCharges = currCharges - self.module = mod - - if validCharges is None: - return False - - self.modules = modules - self.charges = list(filter(lambda charge: service.Market.getInstance().getPublicityByItem(charge), validCharges)) - return len(self.charges) > 0 - - def getText(self, itmContext, selection): - return "Charge" - - def turretSorter(self, charge): - damage = 0 - range = (self.module.getModifiedItemAttr("maxRange") or 0) * (charge.getAttribute("weaponRangeMultiplier") or 1) - falloff = (self.module.getModifiedItemAttr("falloff") or 0) * (charge.getAttribute("fallofMultiplier") or 1) - for type in self.DAMAGE_TYPES: - d = charge.getAttribute("%sDamage" % type) - if d > 0: - damage += d - - # Take optimal and half falloff as range factor - rangeFactor = range + falloff / 2 - - return - rangeFactor, charge.name.rsplit()[-2:], damage, charge.name - - def missileSorter(self, charge): - # Get charge damage type and total damage - chargeDamageType, totalDamage = self.damageInfo(charge) - # Find its position in sort list - position = self.MISSILE_ORDER.index(chargeDamageType) - return position, totalDamage, charge.name - - def damageInfo(self, charge): - # Set up data storage for missile damage stuff - damageMap = {} - totalDamage = 0 - # Fill them with the data about charge - for damageType in self.DAMAGE_TYPES: - currentDamage = charge.getAttribute("{0}Damage".format(damageType)) or 0 - damageMap[damageType] = currentDamage - totalDamage += currentDamage - # Detect type of ammo - chargeDamageType = None - for damageType in damageMap: - # If all damage belongs to certain type purely, set appropriate - # ammoType - if damageMap[damageType] == totalDamage: - chargeDamageType = damageType - break - # Else consider ammo as mixed damage - if chargeDamageType is None: - chargeDamageType = "mixed" - - return chargeDamageType, totalDamage - - def numericConverter(self, string): - return int(string) if string.isdigit() else string - - def nameSorter(self, charge): - parts = charge.name.split(" ") - return map(self.numericConverter, parts) - - def addCharge(self, menu, charge): - id = ContextMenu.nextID() - name = charge.name if charge is not None else "Empty" - self.chargeIds[id] = charge - item = wx.MenuItem(menu, id, name) - menu.Bind(wx.EVT_MENU, self.handleAmmoSwitch, item) - item.charge = charge - if charge is not None and charge.icon is not None: - bitmap = BitmapLoader.getBitmap(charge.icon.iconFile, "icons") - if bitmap is not None: - item.SetBitmap(bitmap) - - return item - - def addSeperator(self, m, text): - id = ContextMenu.nextID() - m.Append(id, u'─ %s ─' % text) - m.Enable(id, False) - - def getSubMenu(self, context, selection, rootMenu, i, pitem): - msw = True if "wxMSW" in wx.PlatformInfo else False - m = wx.Menu() - self.chargeIds = {} - hardpoint = self.module.hardpoint - moduleName = self.module.item.name - # Make sure we do not consider mining turrets as combat turrets - if hardpoint == Hardpoint.TURRET and self.module.getModifiedItemAttr("miningAmount") is None: - self.addSeperator(m, "Long Range") - items = [] - range = None - nameBase = None - 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: - # uncomment if we ever want to include Oribital ammo in ammo picker - see issue #71 - # This allows us to hide the ammo, but it's still loadable from the market - #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: - if sub is not None: - self.addSeperator(sub, "More Damage") - - sub = None - base = charge - nameBase = currBase - range = currRange - item = self.addCharge(rootMenu if msw else m, charge) - items.append(item) - else: - if sub is None: - sub = wx.Menu() - sub.Bind(wx.EVT_MENU, self.handleAmmoSwitch) - self.addSeperator(sub, "Less Damage") - item.SetSubMenu(sub) - sub.AppendItem(self.addCharge(rootMenu if msw else sub, base)) - - sub.AppendItem(self.addCharge(rootMenu if msw else sub, charge)) - - if sub is not None: - self.addSeperator(sub, "More Damage") - - for item in items: - m.AppendItem(item) - - self.addSeperator(m, "Short Range") - elif hardpoint == Hardpoint.MISSILE and moduleName != 'Festival Launcher': - self.charges.sort(key=self.missileSorter) - type = None - sub = None - defender = None - for charge in self.charges: - currType = self.damageInfo(charge)[0] - - if currType != type or type is None: - if sub is not None: - self.addSeperator(sub, "More Damage") - - type = currType - item = wx.MenuItem(m, wx.ID_ANY, type.capitalize()) - bitmap = BitmapLoader.getBitmap("%s_small" % type, "gui") - if bitmap is not None: - item.SetBitmap(bitmap) - - sub = wx.Menu() - sub.Bind(wx.EVT_MENU, self.handleAmmoSwitch) - self.addSeperator(sub, "Less Damage") - item.SetSubMenu(sub) - m.AppendItem(item) - - if charge.name not in ("Light Defender Missile I", "Heavy Defender Missile I"): - sub.AppendItem(self.addCharge(rootMenu if msw else sub, charge)) - else: - defender = charge - - if defender is not None: - m.AppendItem(self.addCharge(rootMenu if msw else m, defender)) - if sub is not None: - self.addSeperator(sub, "More Damage") - else: - self.charges.sort(key=self.nameSorter) - for charge in self.charges: - m.AppendItem(self.addCharge(rootMenu if msw else m, charge)) - - m.AppendItem(self.addCharge(rootMenu if msw else m, None)) - return m - - def handleAmmoSwitch(self, event): - charge = self.chargeIds.get(event.Id, False) - if charge is False: - event.Skip() - return - - sFit = service.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)) - -ModuleAmmoPicker.register() +# coding: utf-8 + +import wx + +from service.fit import Fit +from service.market import Market +from eos.types import Hardpoint +import gui.mainFrame +import gui.globalEvents as GE +from gui.contextMenu import ContextMenu +from gui.bitmapLoader import BitmapLoader + + +class ModuleAmmoPicker(ContextMenu): + DAMAGE_TYPES = ("em", "explosive", "kinetic", "thermal") + MISSILE_ORDER = ("em", "thermal", "kinetic", "explosive", "mixed") + + def __init__(self): + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + + def display(self, srcContext, selection): + if self.mainFrame.getActiveFit() is None or srcContext not in ("fittingModule", "projectedModule"): + return False + + modules = selection if srcContext == "fittingModule" else (selection[0],) + + validCharges = None + checkedTypes = set() + + for mod in modules: + # loop through modules and gather list of valid charges + if mod.item.ID in checkedTypes: + continue + checkedTypes.add(mod.item.ID) + currCharges = mod.getValidCharges() + if len(currCharges) > 0: + if validCharges is not None and validCharges != currCharges: + return False + + validCharges = currCharges + self.module = mod + + if validCharges is None: + return False + + self.modules = modules + self.charges = list(filter(lambda charge: Market.getInstance().getPublicityByItem(charge), validCharges)) + return len(self.charges) > 0 + + def getText(self, itmContext, selection): + return "Charge" + + def turretSorter(self, charge): + damage = 0 + range_ = (self.module.getModifiedItemAttr("maxRange") or 0) * \ + (charge.getAttribute("weaponRangeMultiplier") or 1) + falloff = (self.module.getModifiedItemAttr("falloff") or 0) * \ + (charge.getAttribute("fallofMultiplier") or 1) + for type_ in self.DAMAGE_TYPES: + d = charge.getAttribute("%sDamage" % type_) + if d > 0: + damage += d + + # Take optimal and half falloff as range factor + rangeFactor = range_ + falloff / 2 + + return - rangeFactor, charge.name.rsplit()[-2:], damage, charge.name + + def missileSorter(self, charge): + # Get charge damage type and total damage + chargeDamageType, totalDamage = self.damageInfo(charge) + # Find its position in sort list + position = self.MISSILE_ORDER.index(chargeDamageType) + return position, totalDamage, charge.name + + def damageInfo(self, charge): + # Set up data storage for missile damage stuff + damageMap = {} + totalDamage = 0 + # Fill them with the data about charge + for damageType in self.DAMAGE_TYPES: + currentDamage = charge.getAttribute("{0}Damage".format(damageType)) or 0 + damageMap[damageType] = currentDamage + totalDamage += currentDamage + # Detect type of ammo + chargeDamageType = None + for damageType in damageMap: + # If all damage belongs to certain type purely, set appropriate + # ammoType + if damageMap[damageType] == totalDamage: + chargeDamageType = damageType + break + # Else consider ammo as mixed damage + if chargeDamageType is None: + chargeDamageType = "mixed" + + return chargeDamageType, totalDamage + + def numericConverter(self, string): + return int(string) if string.isdigit() else string + + def nameSorter(self, charge): + parts = charge.name.split(" ") + return map(self.numericConverter, parts) + + def addCharge(self, menu, charge): + id_ = ContextMenu.nextID() + name = charge.name if charge is not None else "Empty" + self.chargeIds[id_] = charge + item = wx.MenuItem(menu, id_, name) + menu.Bind(wx.EVT_MENU, self.handleAmmoSwitch, item) + item.charge = charge + if charge is not None and charge.icon is not None: + bitmap = BitmapLoader.getBitmap(charge.icon.iconFile, "icons") + if bitmap is not None: + item.SetBitmap(bitmap) + + return item + + def addSeperator(self, m, text): + id_ = ContextMenu.nextID() + m.Append(id_, u'─ %s ─' % text) + m.Enable(id_, False) + + def getSubMenu(self, context, selection, rootMenu, i, pitem): + msw = True if "wxMSW" in wx.PlatformInfo else False + m = wx.Menu() + self.chargeIds = {} + hardpoint = self.module.hardpoint + moduleName = self.module.item.name + # Make sure we do not consider mining turrets as combat turrets + if hardpoint == Hardpoint.TURRET and self.module.getModifiedItemAttr("miningAmount") is None: + self.addSeperator(m, "Long Range") + items = [] + range_ = None + nameBase = None + 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: + # uncomment if we ever want to include Oribital ammo in ammo picker - see issue #71 + # This allows us to hide the ammo, but it's still loadable from the market + # 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: + if sub is not None: + self.addSeperator(sub, "More Damage") + + sub = None + base = charge + nameBase = currBase + range_ = currRange + item = self.addCharge(rootMenu if msw else m, charge) + items.append(item) + else: + if sub is None: + sub = wx.Menu() + sub.Bind(wx.EVT_MENU, self.handleAmmoSwitch) + self.addSeperator(sub, "Less Damage") + item.SetSubMenu(sub) + sub.AppendItem(self.addCharge(rootMenu if msw else sub, base)) + + sub.AppendItem(self.addCharge(rootMenu if msw else sub, charge)) + + if sub is not None: + self.addSeperator(sub, "More Damage") + + for item in items: + m.AppendItem(item) + + self.addSeperator(m, "Short Range") + elif hardpoint == Hardpoint.MISSILE and moduleName != 'Festival Launcher': + self.charges.sort(key=self.missileSorter) + type_ = None + sub = None + defender = None + for charge in self.charges: + currType = self.damageInfo(charge)[0] + + if currType != type_ or type_ is None: + if sub is not None: + self.addSeperator(sub, "More Damage") + + type_ = currType + item = wx.MenuItem(m, wx.ID_ANY, type_.capitalize()) + bitmap = BitmapLoader.getBitmap("%s_small" % type, "gui") + if bitmap is not None: + item.SetBitmap(bitmap) + + sub = wx.Menu() + sub.Bind(wx.EVT_MENU, self.handleAmmoSwitch) + self.addSeperator(sub, "Less Damage") + item.SetSubMenu(sub) + m.AppendItem(item) + + if charge.name not in ("Light Defender Missile I", "Heavy Defender Missile I"): + sub.AppendItem(self.addCharge(rootMenu if msw else sub, charge)) + else: + defender = charge + + if defender is not None: + m.AppendItem(self.addCharge(rootMenu if msw else m, defender)) + if sub is not None: + self.addSeperator(sub, "More Damage") + else: + self.charges.sort(key=self.nameSorter) + for charge in self.charges: + m.AppendItem(self.addCharge(rootMenu if msw else m, charge)) + + m.AppendItem(self.addCharge(rootMenu if msw else m, None)) + return m + + def handleAmmoSwitch(self, event): + charge = self.chargeIds.get(event.Id, False) + if charge is False: + 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)) + + +ModuleAmmoPicker.register() diff --git a/gui/builtinContextMenus/moduleGlobalAmmoPicker.py b/gui/builtinContextMenus/moduleGlobalAmmoPicker.py index 41f969b35..035109320 100644 --- a/gui/builtinContextMenus/moduleGlobalAmmoPicker.py +++ b/gui/builtinContextMenus/moduleGlobalAmmoPicker.py @@ -1,13 +1,11 @@ # -*- coding: utf-8 -*- -from gui.contextMenu import ContextMenu import gui.mainFrame -import service import wx -from gui.bitmapLoader import BitmapLoader -from eos.types import Hardpoint import gui.globalEvents as GE from gui.builtinContextMenus.moduleAmmoPicker import ModuleAmmoPicker import eos.db +from service.fit import Fit + class ModuleGlobalAmmoPicker(ModuleAmmoPicker): def __init__(self): @@ -26,7 +24,7 @@ class ModuleGlobalAmmoPicker(ModuleAmmoPicker): event.Skip() return - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() fit = eos.db.getFit(fitID) diff --git a/gui/builtinContextMenus/openFit.py b/gui/builtinContextMenus/openFit.py index eaf38832e..fad0c2640 100644 --- a/gui/builtinContextMenus/openFit.py +++ b/gui/builtinContextMenus/openFit.py @@ -3,6 +3,7 @@ import gui.mainFrame import wx from gui.shipBrowser import FitSelected + class OpenFit(ContextMenu): def __init__(self): self.mainFrame = gui.mainFrame.MainFrame.getInstance() @@ -17,4 +18,5 @@ class OpenFit(ContextMenu): fit = selection[0] wx.PostEvent(self.mainFrame, FitSelected(fitID=fit.ID, startup=2)) + OpenFit.register() diff --git a/gui/builtinContextMenus/priceClear.py b/gui/builtinContextMenus/priceClear.py index da33bfc21..e61b7df7f 100644 --- a/gui/builtinContextMenus/priceClear.py +++ b/gui/builtinContextMenus/priceClear.py @@ -2,7 +2,8 @@ from gui.contextMenu import ContextMenu import gui.mainFrame import wx import gui.globalEvents as GE -import service +from service.market import Market + class PriceClear(ContextMenu): def __init__(self): @@ -15,8 +16,9 @@ class PriceClear(ContextMenu): return "Reset Price Cache" def activate(self, fullContext, selection, i): - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() sMkt.clearPriceCache() wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit())) + PriceClear.register() diff --git a/gui/builtinContextMenus/project.py b/gui/builtinContextMenus/project.py index 4299f67b6..0fcae7864 100644 --- a/gui/builtinContextMenus/project.py +++ b/gui/builtinContextMenus/project.py @@ -1,37 +1,38 @@ -from gui.contextMenu import ContextMenu -import gui.mainFrame -import service -import gui.globalEvents as GE -import wx -import eos.db - -class Project(ContextMenu): - def __init__(self): - self.mainFrame = gui.mainFrame.MainFrame.getInstance() - - def display(self, srcContext, selection): - if srcContext not in ("marketItemGroup", "marketItemMisc") or self.mainFrame.getActiveFit() is None: - return False - - sFit = service.Fit.getInstance() - fitID = self.mainFrame.getActiveFit() - fit = sFit.getFit(fitID) - - if fit.isStructure: - return False - - item = selection[0] - return item.isType("projected") - - def getText(self, itmContext, selection): - return "Project {0} onto Fit".format(itmContext) - - def activate(self, fullContext, selection, i): - sFit = service.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") - -Project.register() +from gui.contextMenu import ContextMenu +import gui.mainFrame +import gui.globalEvents as GE +import wx +from service.fit import Fit + + +class Project(ContextMenu): + def __init__(self): + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + + def display(self, srcContext, selection): + if srcContext not in ("marketItemGroup", "marketItemMisc") or self.mainFrame.getActiveFit() is None: + return False + + sFit = Fit.getInstance() + fitID = self.mainFrame.getActiveFit() + fit = sFit.getFit(fitID) + + if fit.isStructure: + return False + + item = selection[0] + return item.isType("projected") + + def getText(self, itmContext, selection): + return "Project {0} onto Fit".format(itmContext) + + 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") + + +Project.register() diff --git a/gui/builtinContextMenus/shipJump.py b/gui/builtinContextMenus/shipJump.py index bc332e4a4..b743201a3 100644 --- a/gui/builtinContextMenus/shipJump.py +++ b/gui/builtinContextMenus/shipJump.py @@ -1,8 +1,9 @@ import wx from gui.contextMenu import ContextMenu import gui.mainFrame -import service from gui.shipBrowser import Stage3Selected +from service.fit import Fit + class ShipJump(ContextMenu): def __init__(self): @@ -16,11 +17,12 @@ class ShipJump(ContextMenu): def activate(self, fullContext, selection, i): fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() stuff = sFit.getFit(fitID).ship groupID = stuff.item.group.ID self.mainFrame.notebookBrowsers.SetSelection(1) - wx.PostEvent(self.mainFrame.shipBrowser,Stage3Selected(shipID=stuff.item.ID, back=groupID)) + wx.PostEvent(self.mainFrame.shipBrowser, Stage3Selected(shipID=stuff.item.ID, back=groupID)) + ShipJump.register() diff --git a/gui/builtinContextMenus/tacticalMode.py b/gui/builtinContextMenus/tacticalMode.py index 3b5cc5043..62abf309d 100644 --- a/gui/builtinContextMenus/tacticalMode.py +++ b/gui/builtinContextMenus/tacticalMode.py @@ -1,8 +1,10 @@ import wx from gui.contextMenu import ContextMenu import gui.mainFrame -import service + import gui.globalEvents as GE +from service.fit import Fit + class TacticalMode(ContextMenu): def __init__(self): @@ -12,7 +14,7 @@ class TacticalMode(ContextMenu): if self.mainFrame.getActiveFit() is None or srcContext != "fittingShip": return False - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() fit = sFit.getFit(fitID) @@ -52,9 +54,10 @@ class TacticalMode(ContextMenu): event.Skip() return - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() sFit.setMode(fitID, self.modeIds[event.Id]) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + TacticalMode.register() diff --git a/gui/builtinContextMenus/targetResists.py b/gui/builtinContextMenus/targetResists.py index c0f9bf00c..f23125f43 100644 --- a/gui/builtinContextMenus/targetResists.py +++ b/gui/builtinContextMenus/targetResists.py @@ -1,15 +1,17 @@ from gui.contextMenu import ContextMenu import gui.mainFrame -import service import gui.globalEvents as GE import wx from gui.bitmapLoader import BitmapLoader +from service.targetResists import TargetResists as svc_TargetResists +from service.fit import Fit try: from collections import OrderedDict except ImportError: from gui.utils.compat import OrderedDict + class TargetResists(ContextMenu): def __init__(self): self.mainFrame = gui.mainFrame.MainFrame.getInstance() @@ -18,7 +20,7 @@ class TargetResists(ContextMenu): if self.mainFrame.getActiveFit() is None or srcContext != "firepowerViewFull": return False - sTR = service.TargetResists.getInstance() + sTR = svc_TargetResists.getInstance() self.patterns = sTR.getTargetResistsList() self.patterns.sort(key=lambda p: (p.name in ["None"], p.name)) @@ -33,7 +35,7 @@ class TargetResists(ContextMenu): event.Skip() return - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() sFit.setTargetResists(fitID, pattern) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) @@ -50,7 +52,7 @@ class TargetResists(ContextMenu): item.pattern = pattern # determine active pattern - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() f = sFit.getFit(fitID) tr = f.targetResists @@ -64,15 +66,15 @@ class TargetResists(ContextMenu): msw = True if "wxMSW" in wx.PlatformInfo else False self.patternIds = {} self.subMenus = OrderedDict() - self.singles = [] + self.singles = [] sub = wx.Menu() for pattern in self.patterns: start, end = pattern.name.find('['), pattern.name.find(']') if start is not -1 and end is not -1: - currBase = pattern.name[start+1:end] + currBase = pattern.name[start + 1:end] # set helper attr - setattr(pattern, "_name", pattern.name[end+1:].strip()) + setattr(pattern, "_name", pattern.name[end + 1:].strip()) if currBase not in self.subMenus: self.subMenus[currBase] = [] self.subMenus[currBase].append(pattern) @@ -93,7 +95,7 @@ class TargetResists(ContextMenu): # Create menu for child items grandSub = wx.Menu() - #sub.Bind(wx.EVT_MENU, self.handleResistSwitch) + # sub.Bind(wx.EVT_MENU, self.handleResistSwitch) # Apply child menu to parent item item.SetSubMenu(grandSub) @@ -101,8 +103,9 @@ class TargetResists(ContextMenu): # Append child items to child menu for pattern in patterns: grandSub.AppendItem(self.addPattern(rootMenu if msw else grandSub, pattern)) - sub.AppendItem(item) #finally, append parent item to root menu + sub.AppendItem(item) # finally, append parent item to root menu return sub + TargetResists.register() diff --git a/gui/builtinContextMenus/whProjector.py b/gui/builtinContextMenus/whProjector.py index ba0677e20..0e3bfed93 100644 --- a/gui/builtinContextMenus/whProjector.py +++ b/gui/builtinContextMenus/whProjector.py @@ -1,8 +1,10 @@ from gui.contextMenu import ContextMenu import gui.mainFrame import gui.globalEvents as GE -import service import wx +from service.market import Market +from service.fit import Fit + class WhProjector(ContextMenu): def __init__(self): @@ -16,7 +18,7 @@ class WhProjector(ContextMenu): def getSubMenu(self, context, selection, rootMenu, i, pitem): msw = True if "wxMSW" in wx.PlatformInfo else False - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() effdata = sMkt.getSystemWideEffects() self.idmap = {} @@ -41,16 +43,17 @@ class WhProjector(ContextMenu): return sub def handleSelection(self, event): - #Skip events ids that aren't mapped + # Skip events ids that aren't mapped swObj, swName = self.idmap.get(event.Id, (False, False)) if not swObj and not swName: event.Skip() return - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() sFit.project(fitID, swObj) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + WhProjector.register() diff --git a/gui/builtinGraphs/fitDps.py b/gui/builtinGraphs/fitDps.py index ef2782674..fcbfa68fa 100644 --- a/gui/builtinGraphs/fitDps.py +++ b/gui/builtinGraphs/fitDps.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,15 +15,15 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= from gui.graph import Graph -import service from gui.bitmapLoader import BitmapLoader from eos.graph.fitDps import FitDpsGraph as FitDps from eos.graph import Data import gui.mainFrame -import service +from service.attribute import Attribute + class FitDpsGraph(Graph): propertyAttributeMap = {"angle": "maxVelocity", @@ -53,7 +53,7 @@ class FitDpsGraph(Graph): def getIcons(self): icons = {} - sAttr = service.Attribute.getInstance() + sAttr = Attribute.getInstance() for key, attrName in self.propertyAttributeMap.iteritems(): iconFile = sAttr.getAttributeInfo(attrName).icon.iconFile bitmap = BitmapLoader.getBitmap(iconFile, "icons") @@ -75,7 +75,7 @@ class FitDpsGraph(Graph): if variable is None: variable = fieldName else: - #We can't handle more then one variable atm, OOPS FUCK OUT + # We can't handle more then one variable atm, OOPS FUCK OUT return False, "Can only handle 1 variable" fitDps.setData(d) @@ -91,4 +91,5 @@ class FitDpsGraph(Graph): return x, y + FitDpsGraph.register() diff --git a/gui/builtinPreferenceViews/__init__.py b/gui/builtinPreferenceViews/__init__.py index 9d29c75ff..eb7f3c970 100644 --- a/gui/builtinPreferenceViews/__init__.py +++ b/gui/builtinPreferenceViews/__init__.py @@ -1,6 +1,7 @@ -__all__ = ["pyfaGeneralPreferences","pyfaHTMLExportPreferences","pyfaUpdatePreferences","pyfaNetworkPreferences"] - import wx -if not 'wxMac' in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3,0)): +__all__ = ["pyfaGeneralPreferences", "pyfaHTMLExportPreferences", "pyfaUpdatePreferences", + "pyfaNetworkPreferences"] # noqa + +if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3, 0)): __all__.append("pyfaCrestPreferences") diff --git a/gui/builtinPreferenceViews/dummyView.py b/gui/builtinPreferenceViews/dummyView.py index 5b8822d1c..fb46db87e 100644 --- a/gui/builtinPreferenceViews/dummyView.py +++ b/gui/builtinPreferenceViews/dummyView.py @@ -1,94 +1,94 @@ -#=============================================================================== -# 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 wx -from gui.preferenceView import PreferenceView -from gui.bitmapLoader import BitmapLoader -class DummyView(PreferenceView): - title = "Dummy" - - def populatePanel(self, panel): - - mainSizer = wx.BoxSizer( wx.VERTICAL ) - - headerSizer = self.initHeader(panel) - mainSizer.Add( headerSizer, 0, wx.EXPAND, 5 ) - - self.stline1 = wx.StaticLine( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) - mainSizer.Add( self.stline1, 0, wx.EXPAND, 5 ) - - contentSizer = self.initContent(panel) - mainSizer.Add( contentSizer, 1, wx.EXPAND|wx.TOP|wx.BOTTOM|wx.LEFT, 10 ) - - self.stline2 = wx.StaticLine( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) - mainSizer.Add( self.stline2, 0, wx.EXPAND, 5 ) - - - footerSizer = self.initFooter(panel) - mainSizer.Add( footerSizer, 0, wx.EXPAND, 5 ) - panel.SetSizer( mainSizer ) - panel.Layout() - - def refreshPanel(self, fit): - pass - - def initHeader(self, panel): - headerSizer = wx.BoxSizer( wx.VERTICAL ) - self.stTitle = wx.StaticText( panel, wx.ID_ANY, u"Dummy", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.stTitle.Wrap( -1 ) - self.stTitle.SetFont( wx.Font( 14, 70, 90, 90, False, wx.EmptyString ) ) - headerSizer.Add( self.stTitle, 0, wx.ALL, 5) - - return headerSizer - - def initContent(self, panel): - contentSizer = wx.BoxSizer( wx.VERTICAL ) - - self.m_checkBox2 = wx.CheckBox( panel, wx.ID_ANY, u"Check Me!", wx.DefaultPosition, wx.DefaultSize, 0 ) - contentSizer.Add( self.m_checkBox2, 0, wx.ALL, 5 ) - - self.m_radioBtn2 = wx.RadioButton( panel, wx.ID_ANY, u"RadioBtn", wx.DefaultPosition, wx.DefaultSize, 0 ) - contentSizer.Add( self.m_radioBtn2, 0, wx.ALL, 5 ) - - self.m_slider2 = wx.Slider( panel, wx.ID_ANY, 50, 0, 100, wx.DefaultPosition, wx.DefaultSize, wx.SL_HORIZONTAL ) - contentSizer.Add( self.m_slider2, 0, wx.ALL, 5 ) - - self.m_gauge1 = wx.Gauge( panel, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, wx.GA_HORIZONTAL ) - contentSizer.Add( self.m_gauge1, 0, wx.ALL, 5 ) - - self.m_textCtrl2 = wx.TextCtrl( panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - contentSizer.Add( self.m_textCtrl2, 0, wx.ALL, 5 ) - - return contentSizer - - def initFooter(self, panel): - footerSizer = wx.BoxSizer( wx.HORIZONTAL ) - - - footerSizer.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - - self.btnRestore = wx.Button( panel, wx.ID_ANY, u"Restore", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.btnRestore.Enable( False ) - - footerSizer.Add( self.btnRestore, 0, wx.ALL, 5 ) - - self.btnApply = wx.Button( panel, wx.ID_ANY, u"Apply", wx.DefaultPosition, wx.DefaultSize, 0 ) - footerSizer.Add( self.btnApply, 0, wx.ALL, 5 ) - return footerSizer -DummyView.register() +# ============================================================================= +# 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 wx +from gui.preferenceView import PreferenceView + + +class DummyView(PreferenceView): + title = "Dummy" + + def populatePanel(self, panel): + mainSizer = wx.BoxSizer(wx.VERTICAL) + + headerSizer = self.initHeader(panel) + mainSizer.Add(headerSizer, 0, wx.EXPAND, 5) + + self.stline1 = wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) + mainSizer.Add(self.stline1, 0, wx.EXPAND, 5) + + contentSizer = self.initContent(panel) + mainSizer.Add(contentSizer, 1, wx.EXPAND | wx.TOP | wx.BOTTOM | wx.LEFT, 10) + + self.stline2 = wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) + mainSizer.Add(self.stline2, 0, wx.EXPAND, 5) + + footerSizer = self.initFooter(panel) + mainSizer.Add(footerSizer, 0, wx.EXPAND, 5) + panel.SetSizer(mainSizer) + panel.Layout() + + def refreshPanel(self, fit): + pass + + def initHeader(self, panel): + headerSizer = wx.BoxSizer(wx.VERTICAL) + self.stTitle = wx.StaticText(panel, wx.ID_ANY, u"Dummy", wx.DefaultPosition, wx.DefaultSize, 0) + self.stTitle.Wrap(-1) + self.stTitle.SetFont(wx.Font(14, 70, 90, 90, False, wx.EmptyString)) + headerSizer.Add(self.stTitle, 0, wx.ALL, 5) + + return headerSizer + + def initContent(self, panel): + contentSizer = wx.BoxSizer(wx.VERTICAL) + + self.m_checkBox2 = wx.CheckBox(panel, wx.ID_ANY, u"Check Me!", wx.DefaultPosition, wx.DefaultSize, 0) + contentSizer.Add(self.m_checkBox2, 0, wx.ALL, 5) + + self.m_radioBtn2 = wx.RadioButton(panel, wx.ID_ANY, u"RadioBtn", wx.DefaultPosition, wx.DefaultSize, 0) + contentSizer.Add(self.m_radioBtn2, 0, wx.ALL, 5) + + self.m_slider2 = wx.Slider(panel, wx.ID_ANY, 50, 0, 100, wx.DefaultPosition, wx.DefaultSize, wx.SL_HORIZONTAL) + contentSizer.Add(self.m_slider2, 0, wx.ALL, 5) + + self.m_gauge1 = wx.Gauge(panel, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, wx.GA_HORIZONTAL) + contentSizer.Add(self.m_gauge1, 0, wx.ALL, 5) + + self.m_textCtrl2 = wx.TextCtrl(panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0) + contentSizer.Add(self.m_textCtrl2, 0, wx.ALL, 5) + + return contentSizer + + def initFooter(self, panel): + footerSizer = wx.BoxSizer(wx.HORIZONTAL) + + footerSizer.AddSpacer((0, 0), 1, wx.EXPAND, 5) + + self.btnRestore = wx.Button(panel, wx.ID_ANY, u"Restore", wx.DefaultPosition, wx.DefaultSize, 0) + self.btnRestore.Enable(False) + + footerSizer.Add(self.btnRestore, 0, wx.ALL, 5) + + self.btnApply = wx.Button(panel, wx.ID_ANY, u"Apply", wx.DefaultPosition, wx.DefaultSize, 0) + footerSizer.Add(self.btnApply, 0, wx.ALL, 5) + return footerSizer + + +DummyView.register() diff --git a/gui/builtinPreferenceViews/pyfaCrestPreferences.py b/gui/builtinPreferenceViews/pyfaCrestPreferences.py index 081ccf871..6e73f4ce6 100644 --- a/gui/builtinPreferenceViews/pyfaCrestPreferences.py +++ b/gui/builtinPreferenceViews/pyfaCrestPreferences.py @@ -4,101 +4,112 @@ from gui.preferenceView import PreferenceView from gui.bitmapLoader import BitmapLoader import gui.mainFrame -import service -from service.crest import CrestModes + +if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3, 0)): + from service.crest import Crest + +from service.settings import CRESTSettings from wx.lib.intctrl import IntCtrl -class PFCrestPref ( PreferenceView): + +class PFCrestPref(PreferenceView): title = "CREST" - def populatePanel( self, panel ): + def populatePanel(self, panel): self.mainFrame = gui.mainFrame.MainFrame.getInstance() - self.settings = service.settings.CRESTSettings.getInstance() + self.settings = CRESTSettings.getInstance() self.dirtySettings = False dlgWidth = panel.GetParent().GetParent().ClientSize.width - mainSizer = wx.BoxSizer( wx.VERTICAL ) + mainSizer = wx.BoxSizer(wx.VERTICAL) - self.stTitle = wx.StaticText( panel, wx.ID_ANY, self.title, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.stTitle.Wrap( -1 ) - self.stTitle.SetFont( wx.Font( 12, 70, 90, 90, False, wx.EmptyString ) ) + self.stTitle = wx.StaticText(panel, wx.ID_ANY, self.title, wx.DefaultPosition, wx.DefaultSize, 0) + self.stTitle.Wrap(-1) + self.stTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString)) - mainSizer.Add( self.stTitle, 0, wx.ALL, 5 ) + mainSizer.Add(self.stTitle, 0, wx.ALL, 5) - self.m_staticline1 = wx.StaticLine( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) - mainSizer.Add( self.m_staticline1, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5 ) + self.m_staticline1 = wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) + mainSizer.Add(self.m_staticline1, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5) - self.stInfo = wx.StaticText( panel, wx.ID_ANY, u"Please see the pyfa wiki on GitHub for information regarding these options.", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.stInfo = wx.StaticText(panel, wx.ID_ANY, + u"Please see the pyfa wiki on GitHub for information regarding these options.", + wx.DefaultPosition, wx.DefaultSize, 0) self.stInfo.Wrap(dlgWidth - 50) - mainSizer.Add( self.stInfo, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5 ) + mainSizer.Add(self.stInfo, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5) rbSizer = wx.BoxSizer(wx.HORIZONTAL) - self.rbMode = wx.RadioBox(panel, -1, "Mode", wx.DefaultPosition, wx.DefaultSize, ['Implicit', 'User-supplied details'], 1, wx.RA_SPECIFY_COLS) - self.rbServer = wx.RadioBox(panel, -1, "Server", wx.DefaultPosition, wx.DefaultSize, ['Tranquility', 'Singularity'], 1, wx.RA_SPECIFY_COLS) + self.rbMode = wx.RadioBox(panel, -1, "Mode", wx.DefaultPosition, wx.DefaultSize, + ['Implicit', 'User-supplied details'], 1, wx.RA_SPECIFY_COLS) + self.rbServer = wx.RadioBox(panel, -1, "Server", wx.DefaultPosition, wx.DefaultSize, + ['Tranquility', 'Singularity'], 1, wx.RA_SPECIFY_COLS) self.rbMode.SetSelection(self.settings.get('mode')) self.rbServer.SetSelection(self.settings.get('server')) - rbSizer.Add(self.rbMode, 1, wx.TOP | wx.RIGHT, 5 ) - rbSizer.Add(self.rbServer, 1, wx.ALL, 5 ) + rbSizer.Add(self.rbMode, 1, wx.TOP | wx.RIGHT, 5) + rbSizer.Add(self.rbServer, 1, wx.ALL, 5) self.rbMode.Bind(wx.EVT_RADIOBOX, self.OnModeChange) self.rbServer.Bind(wx.EVT_RADIOBOX, self.OnServerChange) - mainSizer.Add(rbSizer, 1, wx.ALL|wx.EXPAND, 0) + mainSizer.Add(rbSizer, 1, wx.ALL | wx.EXPAND, 0) timeoutSizer = wx.BoxSizer(wx.HORIZONTAL) - self.stTimout = wx.StaticText( panel, wx.ID_ANY, u"Timeout (seconds):", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.stTimout.Wrap( -1 ) + self.stTimout = wx.StaticText(panel, wx.ID_ANY, u"Timeout (seconds):", wx.DefaultPosition, wx.DefaultSize, 0) + self.stTimout.Wrap(-1) - timeoutSizer.Add( self.stTimout, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5 ) + timeoutSizer.Add(self.stTimout, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) self.intTimeout = IntCtrl(panel, max=300000, limited=True, value=self.settings.get('timeout')) - timeoutSizer.Add(self.intTimeout, 0, wx.ALL, 5 ) + timeoutSizer.Add(self.intTimeout, 0, wx.ALL, 5) self.intTimeout.Bind(wx.lib.intctrl.EVT_INT, self.OnTimeoutChange) - mainSizer.Add(timeoutSizer, 0, wx.ALL|wx.EXPAND, 0) + mainSizer.Add(timeoutSizer, 0, wx.ALL | wx.EXPAND, 0) - detailsTitle = wx.StaticText( panel, wx.ID_ANY, "CREST client details", wx.DefaultPosition, wx.DefaultSize, 0 ) - detailsTitle.Wrap( -1 ) - detailsTitle.SetFont( wx.Font( 12, 70, 90, 90, False, wx.EmptyString ) ) + detailsTitle = wx.StaticText(panel, wx.ID_ANY, "CREST client details", wx.DefaultPosition, wx.DefaultSize, 0) + detailsTitle.Wrap(-1) + detailsTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString)) - mainSizer.Add( detailsTitle, 0, wx.ALL, 5 ) - mainSizer.Add( wx.StaticLine( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ), 0, wx.EXPAND, 5 ) + mainSizer.Add(detailsTitle, 0, wx.ALL, 5) + mainSizer.Add(wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0, + wx.EXPAND, 5) - fgAddrSizer = wx.FlexGridSizer( 2, 2, 0, 0 ) - fgAddrSizer.AddGrowableCol( 1 ) - fgAddrSizer.SetFlexibleDirection( wx.BOTH ) - fgAddrSizer.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED ) + fgAddrSizer = wx.FlexGridSizer(2, 2, 0, 0) + fgAddrSizer.AddGrowableCol(1) + fgAddrSizer.SetFlexibleDirection(wx.BOTH) + fgAddrSizer.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) - self.stSetID = wx.StaticText( panel, wx.ID_ANY, u"Client ID:", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.stSetID.Wrap( -1 ) - fgAddrSizer.Add( self.stSetID, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + self.stSetID = wx.StaticText(panel, wx.ID_ANY, u"Client ID:", wx.DefaultPosition, wx.DefaultSize, 0) + self.stSetID.Wrap(-1) + fgAddrSizer.Add(self.stSetID, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - self.inputClientID = wx.TextCtrl( panel, wx.ID_ANY, self.settings.get('clientID'), wx.DefaultPosition, wx.DefaultSize, 0 ) + self.inputClientID = wx.TextCtrl(panel, wx.ID_ANY, self.settings.get('clientID'), wx.DefaultPosition, + wx.DefaultSize, 0) - fgAddrSizer.Add( self.inputClientID, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5 ) + fgAddrSizer.Add(self.inputClientID, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5) - self.stSetSecret = wx.StaticText( panel, wx.ID_ANY, u"Client Secret:", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.stSetSecret.Wrap( -1 ) + self.stSetSecret = wx.StaticText(panel, wx.ID_ANY, u"Client Secret:", wx.DefaultPosition, wx.DefaultSize, 0) + self.stSetSecret.Wrap(-1) - fgAddrSizer.Add( self.stSetSecret, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + fgAddrSizer.Add(self.stSetSecret, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - self.inputClientSecret = wx.TextCtrl( panel, wx.ID_ANY, self.settings.get('clientSecret'), wx.DefaultPosition, wx.DefaultSize, 0 ) + self.inputClientSecret = wx.TextCtrl(panel, wx.ID_ANY, self.settings.get('clientSecret'), wx.DefaultPosition, + wx.DefaultSize, 0) - fgAddrSizer.Add( self.inputClientSecret, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5 ) + fgAddrSizer.Add(self.inputClientSecret, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5) - self.btnApply = wx.Button( panel, wx.ID_ANY, u"Save Client Settings", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.btnApply = wx.Button(panel, wx.ID_ANY, u"Save Client Settings", wx.DefaultPosition, wx.DefaultSize, 0) self.btnApply.Bind(wx.EVT_BUTTON, self.OnBtnApply) - mainSizer.Add( fgAddrSizer, 0, wx.EXPAND, 5) - mainSizer.Add( self.btnApply, 0, wx.ALIGN_RIGHT, 5) + mainSizer.Add(fgAddrSizer, 0, wx.EXPAND, 5) + mainSizer.Add(self.btnApply, 0, wx.ALIGN_RIGHT, 5) self.ToggleProxySettings(self.settings.get('mode')) - panel.SetSizer( mainSizer ) + panel.SetSizer(mainSizer) panel.Layout() def OnTimeoutChange(self, event): @@ -107,16 +118,16 @@ class PFCrestPref ( PreferenceView): def OnModeChange(self, event): self.settings.set('mode', event.GetInt()) self.ToggleProxySettings(self.settings.get('mode')) - service.Crest.restartService() + Crest.restartService() def OnServerChange(self, event): self.settings.set('server', event.GetInt()) - service.Crest.restartService() + Crest.restartService() def OnBtnApply(self, event): self.settings.set('clientID', self.inputClientID.GetValue().strip()) self.settings.set('clientSecret', self.inputClientSecret.GetValue().strip()) - sCrest = service.Crest.getInstance() + sCrest = Crest.getInstance() sCrest.delAllCharacters() def ToggleProxySettings(self, mode): @@ -134,4 +145,5 @@ class PFCrestPref ( PreferenceView): def getImage(self): return BitmapLoader.getBitmap("eve", "gui") + PFCrestPref.register() diff --git a/gui/builtinPreferenceViews/pyfaGaugePreferences.py b/gui/builtinPreferenceViews/pyfaGaugePreferences.py index 4163eeaf4..88c1e1313 100644 --- a/gui/builtinPreferenceViews/pyfaGaugePreferences.py +++ b/gui/builtinPreferenceViews/pyfaGaugePreferences.py @@ -10,13 +10,15 @@ from gui.bitmapLoader import BitmapLoader from gui.utils import colorUtils import gui.utils.drawUtils as drawUtils + ########################################################################### -## Class PFGaugePref +# Class PFGaugePref ########################################################################### + class PFGaugePreview(wx.Window): - def __init__ (self, parent, id = wx.ID_ANY, value = 0, pos = wx.DefaultPosition, size = wx.DefaultSize, style = 0): - wx.Window.__init__(self, parent, id, pos = pos, size = size, style = style) + def __init__(self, parent, id=wx.ID_ANY, value=0, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0): + wx.Window.__init__(self, parent, id, pos=pos, size=size, style=style) self.value = float(value) self.oldValue = self.value @@ -28,14 +30,14 @@ class PFGaugePreview(wx.Window): self.animDir = 1 self._fractionDigits = 2 - self.colorS = wx.Colour(0,0,0,255) - self.colorE = wx.Colour(0,0,0,255) + self.colorS = wx.Colour(0, 0, 0, 255) + self.colorE = wx.Colour(0, 0, 0, 255) self.gradientStart = 0 - self.bkColor = wx.Colour(0,0,0,255) - self.SetMinSize((100,-1)) + self.bkColor = wx.Colour(0, 0, 0, 255) + self.SetMinSize((100, -1)) - self.font = wx.FontFromPixelSize((0,13),wx.SWISS, wx.NORMAL, wx.NORMAL, False) + self.font = wx.FontFromPixelSize((0, 13), wx.SWISS, wx.NORMAL, wx.NORMAL, False) self.timerID = wx.NewId() self.timer = wx.Timer(self, self.timerID) @@ -56,7 +58,7 @@ class PFGaugePreview(wx.Window): if self.value > 100: self.value = 100 self.animDir = -1 - if self.value <0: + if self.value < 0: self.value = 0 self.animDir = 1 self.Refresh() @@ -79,7 +81,7 @@ class PFGaugePreview(wx.Window): self.Refresh() event.Skip() - def CanAnimate(self, anim = True): + def CanAnimate(self, anim=True): self.animate = anim if self.timer.IsRunning(): self.timer.Stop() @@ -97,7 +99,7 @@ class PFGaugePreview(wx.Window): self.Refresh() def SetValue(self, value): - self.value = min(max(value,0),100) + self.value = min(max(value, 0), 100) self.Refresh() def SetPercentages(self, start, end): @@ -119,198 +121,210 @@ class PFGaugePreview(wx.Window): r = copy.copy(rect) r.width = w - color = colorUtils.CalculateTransitionColor(self.colorS, self.colorE, float(value)/100) + color = colorUtils.CalculateTransitionColor(self.colorS, self.colorE, float(value) / 100) if self.gradientStart > 0: - gcolor = colorUtils.BrightenColor(color, float(self.gradientStart) / 100) - gMid = colorUtils.BrightenColor(color, float(self.gradientStart/2) / 100) + gcolor = colorUtils.BrightenColor(color, float(self.gradientStart) / 100) + gMid = colorUtils.BrightenColor(color, float(self.gradientStart / 2) / 100) else: - gcolor = colorUtils.DarkenColor(color, float(-self.gradientStart) / 100) - gMid = colorUtils.DarkenColor(color, float(-self.gradientStart/2) / 100) + gcolor = colorUtils.DarkenColor(color, float(-self.gradientStart) / 100) + gMid = colorUtils.DarkenColor(color, float(-self.gradientStart / 2) / 100) gBmp = drawUtils.DrawGradientBar(r.width, r.height, gMid, color, gcolor) - dc.DrawBitmap(gBmp,0,0) + dc.DrawBitmap(gBmp, 0, 0) dc.SetFont(self.font) r = copy.copy(rect) - r.left +=1 - r.top +=1 - + r.left += 1 + r.top += 1 formatStr = "{0:." + str(self._fractionDigits) + "f}%" value = (self.percE - self.percS) * value / (self.percE - self.percS) value = self.percS + (self.percE - self.percS) * value / 100 - dc.SetTextForeground(wx.Colour(80,80,80)) + dc.SetTextForeground(wx.Colour(80, 80, 80)) dc.DrawLabel(formatStr.format(value), r, wx.ALIGN_CENTER) - dc.SetTextForeground(wx.Colour(255,255,255)) + dc.SetTextForeground(wx.Colour(255, 255, 255)) dc.DrawLabel(formatStr.format(value), rect, wx.ALIGN_CENTER) -class PFGaugePref ( PreferenceView): +class PFGaugePref(PreferenceView): title = "Pyfa Gauge Theme" - def populatePanel( self, panel ): + + def populatePanel(self, panel): self.InitDefaultColours() - mainSizer = wx.BoxSizer( wx.VERTICAL ) + mainSizer = wx.BoxSizer(wx.VERTICAL) - gSizer1 = wx.BoxSizer( wx.HORIZONTAL ) + gSizer1 = wx.BoxSizer(wx.HORIZONTAL) - self.st0100 = wx.StaticText( panel, wx.ID_ANY, u"0 - 100", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_RIGHT ) - self.st0100.Wrap( -1 ) - gSizer1.Add( self.st0100, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + self.st0100 = wx.StaticText(panel, wx.ID_ANY, u"0 - 100", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_RIGHT) + self.st0100.Wrap(-1) + gSizer1.Add(self.st0100, 1, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - self.cp0100S = wx.ColourPickerCtrl( panel, wx.ID_ANY, wx.BLACK, wx.DefaultPosition, wx.DefaultSize, wx.CLRP_DEFAULT_STYLE | wx.CLRP_SHOW_LABEL ) - gSizer1.Add( self.cp0100S, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + self.cp0100S = wx.ColourPickerCtrl(panel, wx.ID_ANY, wx.BLACK, wx.DefaultPosition, wx.DefaultSize, + wx.CLRP_DEFAULT_STYLE | wx.CLRP_SHOW_LABEL) + gSizer1.Add(self.cp0100S, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - self.cp0100E = wx.ColourPickerCtrl( panel, wx.ID_ANY, wx.BLACK, wx.DefaultPosition, wx.DefaultSize, wx.CLRP_DEFAULT_STYLE | wx.CLRP_SHOW_LABEL ) - gSizer1.Add( self.cp0100E, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + self.cp0100E = wx.ColourPickerCtrl(panel, wx.ID_ANY, wx.BLACK, wx.DefaultPosition, wx.DefaultSize, + wx.CLRP_DEFAULT_STYLE | wx.CLRP_SHOW_LABEL) + gSizer1.Add(self.cp0100E, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - self.gauge0100S = PFGaugePreview( panel, wx.ID_ANY, 33, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER ) - gSizer1.Add( self.gauge0100S, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5 ) + self.gauge0100S = PFGaugePreview(panel, wx.ID_ANY, 33, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER) + gSizer1.Add(self.gauge0100S, 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 5) - self.gauge0100M = PFGaugePreview( panel, wx.ID_ANY, 66, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER ) - gSizer1.Add( self.gauge0100M, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5 ) + self.gauge0100M = PFGaugePreview(panel, wx.ID_ANY, 66, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER) + gSizer1.Add(self.gauge0100M, 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 5) - self.gauge0100E = PFGaugePreview( panel, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER ) - gSizer1.Add( self.gauge0100E, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) + self.gauge0100E = PFGaugePreview(panel, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER) + gSizer1.Add(self.gauge0100E, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.LEFT, 5) - mainSizer.Add( gSizer1, 0, wx.EXPAND, 5 ) + mainSizer.Add(gSizer1, 0, wx.EXPAND, 5) - gSizer2 = wx.BoxSizer( wx.HORIZONTAL ) + gSizer2 = wx.BoxSizer(wx.HORIZONTAL) - self.st100101 = wx.StaticText( panel, wx.ID_ANY, u"100 - 101", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_RIGHT ) - self.st100101.Wrap( -1 ) - gSizer2.Add( self.st100101, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + self.st100101 = wx.StaticText(panel, wx.ID_ANY, u"100 - 101", wx.DefaultPosition, wx.DefaultSize, + wx.ALIGN_RIGHT) + self.st100101.Wrap(-1) + gSizer2.Add(self.st100101, 1, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - self.cp100101S = wx.ColourPickerCtrl( panel, wx.ID_ANY, wx.BLACK, wx.DefaultPosition, wx.DefaultSize, wx.CLRP_DEFAULT_STYLE | wx.CLRP_SHOW_LABEL ) - gSizer2.Add( self.cp100101S, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + self.cp100101S = wx.ColourPickerCtrl(panel, wx.ID_ANY, wx.BLACK, wx.DefaultPosition, wx.DefaultSize, + wx.CLRP_DEFAULT_STYLE | wx.CLRP_SHOW_LABEL) + gSizer2.Add(self.cp100101S, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - self.cp100101E = wx.ColourPickerCtrl( panel, wx.ID_ANY, wx.BLACK, wx.DefaultPosition, wx.DefaultSize, wx.CLRP_DEFAULT_STYLE | wx.CLRP_SHOW_LABEL ) - gSizer2.Add( self.cp100101E, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + self.cp100101E = wx.ColourPickerCtrl(panel, wx.ID_ANY, wx.BLACK, wx.DefaultPosition, wx.DefaultSize, + wx.CLRP_DEFAULT_STYLE | wx.CLRP_SHOW_LABEL) + gSizer2.Add(self.cp100101E, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - self.gauge100101S = PFGaugePreview( panel, wx.ID_ANY, 33, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER ) - gSizer2.Add( self.gauge100101S, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5 ) + self.gauge100101S = PFGaugePreview(panel, wx.ID_ANY, 33, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER) + gSizer2.Add(self.gauge100101S, 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 5) - self.gauge100101M = PFGaugePreview( panel, wx.ID_ANY, 66, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER ) - gSizer2.Add( self.gauge100101M, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5 ) + self.gauge100101M = PFGaugePreview(panel, wx.ID_ANY, 66, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER) + gSizer2.Add(self.gauge100101M, 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 5) - self.gauge100101E = PFGaugePreview( panel, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER ) - gSizer2.Add( self.gauge100101E, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) + self.gauge100101E = PFGaugePreview(panel, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER) + gSizer2.Add(self.gauge100101E, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.LEFT, 5) - mainSizer.Add( gSizer2, 0, wx.EXPAND, 5 ) + mainSizer.Add(gSizer2, 0, wx.EXPAND, 5) - gSizer3 = wx.BoxSizer( wx.HORIZONTAL ) + gSizer3 = wx.BoxSizer(wx.HORIZONTAL) - self.st101103 = wx.StaticText( panel, wx.ID_ANY, u"101 - 103", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_RIGHT ) - self.st101103.Wrap( -1 ) - gSizer3.Add( self.st101103, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + self.st101103 = wx.StaticText(panel, wx.ID_ANY, u"101 - 103", wx.DefaultPosition, wx.DefaultSize, + wx.ALIGN_RIGHT) + self.st101103.Wrap(-1) + gSizer3.Add(self.st101103, 1, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - self.cp101103S = wx.ColourPickerCtrl( panel, wx.ID_ANY, wx.BLACK, wx.DefaultPosition, wx.DefaultSize, wx.CLRP_DEFAULT_STYLE | wx.CLRP_SHOW_LABEL ) - gSizer3.Add( self.cp101103S, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + self.cp101103S = wx.ColourPickerCtrl(panel, wx.ID_ANY, wx.BLACK, wx.DefaultPosition, wx.DefaultSize, + wx.CLRP_DEFAULT_STYLE | wx.CLRP_SHOW_LABEL) + gSizer3.Add(self.cp101103S, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - self.cp101103E = wx.ColourPickerCtrl( panel, wx.ID_ANY, wx.BLACK, wx.DefaultPosition, wx.DefaultSize, wx.CLRP_DEFAULT_STYLE | wx.CLRP_SHOW_LABEL ) - gSizer3.Add( self.cp101103E, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + self.cp101103E = wx.ColourPickerCtrl(panel, wx.ID_ANY, wx.BLACK, wx.DefaultPosition, wx.DefaultSize, + wx.CLRP_DEFAULT_STYLE | wx.CLRP_SHOW_LABEL) + gSizer3.Add(self.cp101103E, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - self.gauge101103S = PFGaugePreview( panel, wx.ID_ANY, 33, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER ) - gSizer3.Add( self.gauge101103S, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5 ) + self.gauge101103S = PFGaugePreview(panel, wx.ID_ANY, 33, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER) + gSizer3.Add(self.gauge101103S, 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 5) - self.gauge101103M = PFGaugePreview( panel, wx.ID_ANY, 66, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER ) - gSizer3.Add( self.gauge101103M, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5 ) + self.gauge101103M = PFGaugePreview(panel, wx.ID_ANY, 66, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER) + gSizer3.Add(self.gauge101103M, 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 5) - self.gauge101103E = PFGaugePreview( panel, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER ) - gSizer3.Add( self.gauge101103E, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) + self.gauge101103E = PFGaugePreview(panel, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER) + gSizer3.Add(self.gauge101103E, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.LEFT, 5) - mainSizer.Add( gSizer3, 0, wx.EXPAND, 5 ) + mainSizer.Add(gSizer3, 0, wx.EXPAND, 5) - gSizer4 = wx.BoxSizer( wx.HORIZONTAL ) + gSizer4 = wx.BoxSizer(wx.HORIZONTAL) - self.st103105 = wx.StaticText( panel, wx.ID_ANY, u"103 - 105", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_RIGHT ) - self.st103105.Wrap( -1 ) - gSizer4.Add( self.st103105, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + self.st103105 = wx.StaticText(panel, wx.ID_ANY, u"103 - 105", wx.DefaultPosition, wx.DefaultSize, + wx.ALIGN_RIGHT) + self.st103105.Wrap(-1) + gSizer4.Add(self.st103105, 1, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - self.cp103105S = wx.ColourPickerCtrl( panel, wx.ID_ANY, wx.BLACK, wx.DefaultPosition, wx.DefaultSize, wx.CLRP_DEFAULT_STYLE | wx.CLRP_SHOW_LABEL ) - gSizer4.Add( self.cp103105S, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + self.cp103105S = wx.ColourPickerCtrl(panel, wx.ID_ANY, wx.BLACK, wx.DefaultPosition, wx.DefaultSize, + wx.CLRP_DEFAULT_STYLE | wx.CLRP_SHOW_LABEL) + gSizer4.Add(self.cp103105S, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - self.cp103105E = wx.ColourPickerCtrl( panel, wx.ID_ANY, wx.BLACK, wx.DefaultPosition, wx.DefaultSize, wx.CLRP_DEFAULT_STYLE | wx.CLRP_SHOW_LABEL ) - gSizer4.Add( self.cp103105E, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + self.cp103105E = wx.ColourPickerCtrl(panel, wx.ID_ANY, wx.BLACK, wx.DefaultPosition, wx.DefaultSize, + wx.CLRP_DEFAULT_STYLE | wx.CLRP_SHOW_LABEL) + gSizer4.Add(self.cp103105E, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - self.gauge103105S = PFGaugePreview( panel, wx.ID_ANY, 33, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER ) - gSizer4.Add( self.gauge103105S, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5 ) + self.gauge103105S = PFGaugePreview(panel, wx.ID_ANY, 33, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER) + gSizer4.Add(self.gauge103105S, 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 5) - self.gauge103105M = PFGaugePreview( panel, wx.ID_ANY, 66, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER ) - gSizer4.Add( self.gauge103105M, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5 ) + self.gauge103105M = PFGaugePreview(panel, wx.ID_ANY, 66, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER) + gSizer4.Add(self.gauge103105M, 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 5) - self.gauge103105E = PFGaugePreview( panel, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER ) - gSizer4.Add( self.gauge103105E, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) + self.gauge103105E = PFGaugePreview(panel, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, wx.SIMPLE_BORDER) + gSizer4.Add(self.gauge103105E, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.LEFT, 5) - mainSizer.Add( gSizer4, 0, wx.EXPAND, 5 ) + mainSizer.Add(gSizer4, 0, wx.EXPAND, 5) - footerSizer = wx.BoxSizer( wx.VERTICAL ) + footerSizer = wx.BoxSizer(wx.VERTICAL) - self.sl1 = wx.StaticLine( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) - footerSizer.Add( self.sl1, 0, wx.EXPAND |wx.ALL, 5 ) + self.sl1 = wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) + footerSizer.Add(self.sl1, 0, wx.EXPAND | wx.ALL, 5) - previewSizer = wx.BoxSizer( wx.HORIZONTAL ) + previewSizer = wx.BoxSizer(wx.HORIZONTAL) - self.wndPreview0100 = PFGaugePreview( panel, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, 0) - previewSizer.Add( self.wndPreview0100, 1, wx.ALIGN_CENTER_VERTICAL, 5 ) + self.wndPreview0100 = PFGaugePreview(panel, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, 0) + previewSizer.Add(self.wndPreview0100, 1, wx.ALIGN_CENTER_VERTICAL, 5) - self.wndPreview100101 = PFGaugePreview( panel, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, 0) - previewSizer.Add( self.wndPreview100101, 1, wx.ALIGN_CENTER_VERTICAL, 5 ) + self.wndPreview100101 = PFGaugePreview(panel, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, 0) + previewSizer.Add(self.wndPreview100101, 1, wx.ALIGN_CENTER_VERTICAL, 5) - self.wndPreview101103 = PFGaugePreview( panel, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, 0) - previewSizer.Add( self.wndPreview101103, 1, wx.ALIGN_CENTER_VERTICAL, 5 ) + self.wndPreview101103 = PFGaugePreview(panel, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, 0) + previewSizer.Add(self.wndPreview101103, 1, wx.ALIGN_CENTER_VERTICAL, 5) - self.wndPreview103105 = PFGaugePreview( panel, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, 0) - previewSizer.Add( self.wndPreview103105, 1, wx.ALIGN_CENTER_VERTICAL, 5 ) + self.wndPreview103105 = PFGaugePreview(panel, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, 0) + previewSizer.Add(self.wndPreview103105, 1, wx.ALIGN_CENTER_VERTICAL, 5) - footerSizer.Add( previewSizer, 1, wx.EXPAND | wx.ALL, 5 ) + footerSizer.Add(previewSizer, 1, wx.EXPAND | wx.ALL, 5) - buttonsSizer = wx.BoxSizer( wx.HORIZONTAL ) + buttonsSizer = wx.BoxSizer(wx.HORIZONTAL) - self.cbLink = wx.CheckBox( panel, wx.ID_ANY, u"Link Colors", wx.DefaultPosition, wx.DefaultSize, 0 ) - buttonsSizer.Add( self.cbLink, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.LEFT, 5 ) + self.cbLink = wx.CheckBox(panel, wx.ID_ANY, u"Link Colors", wx.DefaultPosition, wx.DefaultSize, 0) + buttonsSizer.Add(self.cbLink, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.LEFT, 5) - self.sliderGradientStart = wx.Slider( panel, wx.ID_ANY, self.gradientStart, -100, 100, wx.DefaultPosition, (127,-1), wx.SL_HORIZONTAL|wx.SL_LABELS ) - buttonsSizer.Add( self.sliderGradientStart, 1, wx.EXPAND | wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5 ) + self.sliderGradientStart = wx.Slider(panel, wx.ID_ANY, self.gradientStart, -100, 100, wx.DefaultPosition, + (127, -1), wx.SL_HORIZONTAL | wx.SL_LABELS) + buttonsSizer.Add(self.sliderGradientStart, 1, wx.EXPAND | wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - self.btnRestore = wx.Button( panel, wx.ID_ANY, u"Restore Defaults", wx.DefaultPosition, wx.DefaultSize, 0 ) - buttonsSizer.Add( self.btnRestore, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5 ) + self.btnRestore = wx.Button(panel, wx.ID_ANY, u"Restore Defaults", wx.DefaultPosition, wx.DefaultSize, 0) + buttonsSizer.Add(self.btnRestore, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - self.btnDump = wx.Button( panel, wx.ID_ANY, u"Dump Colors", wx.DefaultPosition, wx.DefaultSize, 0 ) - buttonsSizer.Add( self.btnDump, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5 ) + self.btnDump = wx.Button(panel, wx.ID_ANY, u"Dump Colors", wx.DefaultPosition, wx.DefaultSize, 0) + buttonsSizer.Add(self.btnDump, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - self.btnOk = wx.Button( panel, wx.ID_ANY, u"Apply", wx.DefaultPosition, wx.DefaultSize, 0 ) - buttonsSizer.Add( self.btnOk, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5 ) + self.btnOk = wx.Button(panel, wx.ID_ANY, u"Apply", wx.DefaultPosition, wx.DefaultSize, 0) + buttonsSizer.Add(self.btnOk, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - footerSizer.Add( buttonsSizer, 1, wx.ALIGN_RIGHT, 5 ) - mainSizer.Add( footerSizer, 0, wx.EXPAND, 5 ) + footerSizer.Add(buttonsSizer, 1, wx.ALIGN_RIGHT, 5) + mainSizer.Add(footerSizer, 0, wx.EXPAND, 5) - panel.SetSizer( mainSizer ) + panel.SetSizer(mainSizer) self.SetColours() -# self.Fit() -# self.Layout() + # self.Fit() + # self.Layout() self.sliderGradientStart.Bind(wx.EVT_SCROLL, self.OnGradientStartScroll) self.btnRestore.Bind(wx.EVT_BUTTON, self.RestoreDefaults) self.btnDump.Bind(wx.EVT_BUTTON, self.DumpColours) self.btnOk.Bind(wx.EVT_BUTTON, self.OnOk) - self.cp0100S.Bind( wx.EVT_COLOURPICKER_CHANGED, self.OnColourChanged ) - self.cp0100E.Bind( wx.EVT_COLOURPICKER_CHANGED, self.OnColourChanged ) + self.cp0100S.Bind(wx.EVT_COLOURPICKER_CHANGED, self.OnColourChanged) + self.cp0100E.Bind(wx.EVT_COLOURPICKER_CHANGED, self.OnColourChanged) - self.cp100101S.Bind( wx.EVT_COLOURPICKER_CHANGED, self.OnColourChanged ) - self.cp100101E.Bind( wx.EVT_COLOURPICKER_CHANGED, self.OnColourChanged ) + self.cp100101S.Bind(wx.EVT_COLOURPICKER_CHANGED, self.OnColourChanged) + self.cp100101E.Bind(wx.EVT_COLOURPICKER_CHANGED, self.OnColourChanged) - self.cp101103S.Bind( wx.EVT_COLOURPICKER_CHANGED, self.OnColourChanged ) - self.cp101103E.Bind( wx.EVT_COLOURPICKER_CHANGED, self.OnColourChanged ) + self.cp101103S.Bind(wx.EVT_COLOURPICKER_CHANGED, self.OnColourChanged) + self.cp101103E.Bind(wx.EVT_COLOURPICKER_CHANGED, self.OnColourChanged) - self.cp103105S.Bind( wx.EVT_COLOURPICKER_CHANGED, self.OnColourChanged ) - self.cp103105E.Bind( wx.EVT_COLOURPICKER_CHANGED, self.OnColourChanged ) + self.cp103105S.Bind(wx.EVT_COLOURPICKER_CHANGED, self.OnColourChanged) + self.cp103105E.Bind(wx.EVT_COLOURPICKER_CHANGED, self.OnColourChanged) def getImage(self): return BitmapLoader.getBitmap("pref-gauges_big", "gui") @@ -344,7 +358,6 @@ class PFGaugePref ( PreferenceView): self.gauge0100M.SetGradientStart(self.sliderGradientStart.GetValue()) self.gauge0100E.SetGradientStart(self.sliderGradientStart.GetValue()) - self.cp100101S.SetColour(self.c100101S) self.cp100101E.SetColour(self.c100101E) self.gauge100101S.SetColour(self.c100101S, self.c100101E) @@ -363,7 +376,6 @@ class PFGaugePref ( PreferenceView): self.gauge100101M.SetGradientStart(self.sliderGradientStart.GetValue()) self.gauge100101E.SetGradientStart(self.sliderGradientStart.GetValue()) - self.cp101103S.SetColour(self.c101103S) self.cp101103E.SetColour(self.c101103E) self.gauge101103S.SetColour(self.c101103S, self.c101103E) @@ -378,7 +390,6 @@ class PFGaugePref ( PreferenceView): self.gauge101103M.SetGradientStart(self.sliderGradientStart.GetValue()) self.gauge101103E.SetGradientStart(self.sliderGradientStart.GetValue()) - self.cp103105S.SetColour(self.c103105S) self.cp103105E.SetColour(self.c103105E) self.gauge103105S.SetColour(self.c103105S, self.c103105E) @@ -406,7 +417,7 @@ class PFGaugePref ( PreferenceView): self.wndPreview101103.SetGradientStart(self.sliderGradientStart.GetValue()) self.wndPreview103105.SetColour(self.c103105S, self.c103105E) - self.wndPreview103105.SetPercentages(103,104.99) + self.wndPreview103105.SetPercentages(103, 104.99) self.wndPreview103105.SetGradientStart(self.sliderGradientStart.GetValue()) def OnGradientStartScroll(self, event): @@ -415,15 +426,15 @@ class PFGaugePref ( PreferenceView): event.Skip() def OnOk(self, event): - #Apply New Settings + # Apply New Settings event.Skip() def DumpColours(self, event): - print "Gradient start: %d" % self.sliderGradientStart.GetValue() - print " 0 <-> 100 Start: ", self.c0100S, " End: ", self.c0100E - print "100 <-> 101 Start: ", self.c100101S, " End: ", self.c100101E - print "101 <-> 103 Start: ", self.c101103S, " End: ", self.c101103E - print "103 <-> 105 Start: ", self.c103105S, " End: ", self.c103105E + print("Gradient start: %d" % self.sliderGradientStart.GetValue()) + print(" 0 <-> 100 Start: ", self.c0100S, " End: ", self.c0100E) + print("100 <-> 101 Start: ", self.c100101S, " End: ", self.c100101E) + print("101 <-> 103 Start: ", self.c101103S, " End: ", self.c101103E) + print("103 <-> 105 Start: ", self.c103105S, " End: ", self.c103105E) event.Skip() @@ -478,7 +489,8 @@ class PFGaugePref ( PreferenceView): self.SetColours() event.Skip() - def __del__( self ): + def __del__(self): pass + PFGaugePref.register() diff --git a/gui/builtinPreferenceViews/pyfaGeneralPreferences.py b/gui/builtinPreferenceViews/pyfaGeneralPreferences.py index 2d8104bdd..0e5a18f93 100644 --- a/gui/builtinPreferenceViews/pyfaGeneralPreferences.py +++ b/gui/builtinPreferenceViews/pyfaGeneralPreferences.py @@ -4,73 +4,84 @@ from gui.preferenceView import PreferenceView from gui.bitmapLoader import BitmapLoader import gui.mainFrame -import service import gui.globalEvents as GE +from service.settings import SettingsProvider +from service.fit import Fit -class PFGeneralPref ( PreferenceView): +class PFGeneralPref(PreferenceView): title = "General" - def populatePanel( self, panel ): + def populatePanel(self, panel): self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.dirtySettings = False - self.openFitsSettings = service.SettingsProvider.getInstance().getSettings("pyfaPrevOpenFits", {"enabled": False, "pyfaOpenFits": []}) + self.openFitsSettings = SettingsProvider.getInstance().getSettings("pyfaPrevOpenFits", + {"enabled": False, "pyfaOpenFits": []}) - mainSizer = wx.BoxSizer( wx.VERTICAL ) + mainSizer = wx.BoxSizer(wx.VERTICAL) - self.stTitle = wx.StaticText( panel, wx.ID_ANY, self.title, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.stTitle.Wrap( -1 ) - self.stTitle.SetFont( wx.Font( 12, 70, 90, 90, False, wx.EmptyString ) ) + self.stTitle = wx.StaticText(panel, wx.ID_ANY, self.title, wx.DefaultPosition, wx.DefaultSize, 0) + self.stTitle.Wrap(-1) + self.stTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString)) - mainSizer.Add( self.stTitle, 0, wx.ALL, 5 ) + mainSizer.Add(self.stTitle, 0, wx.ALL, 5) - self.m_staticline1 = wx.StaticLine( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) - mainSizer.Add( self.m_staticline1, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5 ) + self.m_staticline1 = wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) + mainSizer.Add(self.m_staticline1, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5) - self.cbGlobalChar = wx.CheckBox( panel, wx.ID_ANY, u"Use global character", wx.DefaultPosition, wx.DefaultSize, 0 ) - mainSizer.Add( self.cbGlobalChar, 0, wx.ALL|wx.EXPAND, 5 ) + self.cbGlobalChar = wx.CheckBox(panel, wx.ID_ANY, u"Use global character", wx.DefaultPosition, wx.DefaultSize, + 0) + mainSizer.Add(self.cbGlobalChar, 0, wx.ALL | wx.EXPAND, 5) - self.cbGlobalDmgPattern = wx.CheckBox( panel, wx.ID_ANY, u"Use global damage pattern", wx.DefaultPosition, wx.DefaultSize, 0 ) - mainSizer.Add( self.cbGlobalDmgPattern, 0, wx.ALL|wx.EXPAND, 5 ) + self.cbGlobalDmgPattern = wx.CheckBox(panel, wx.ID_ANY, u"Use global damage pattern", wx.DefaultPosition, + wx.DefaultSize, 0) + mainSizer.Add(self.cbGlobalDmgPattern, 0, wx.ALL | wx.EXPAND, 5) - self.cbGlobalForceReload = wx.CheckBox( panel, wx.ID_ANY, u"Factor in reload time", wx.DefaultPosition, wx.DefaultSize, 0 ) - mainSizer.Add( self.cbGlobalForceReload, 0, wx.ALL|wx.EXPAND, 5 ) + self.cbGlobalForceReload = wx.CheckBox(panel, wx.ID_ANY, u"Factor in reload time", wx.DefaultPosition, + wx.DefaultSize, 0) + mainSizer.Add(self.cbGlobalForceReload, 0, wx.ALL | wx.EXPAND, 5) - self.cbCompactSkills = wx.CheckBox( panel, wx.ID_ANY, u"Compact skills needed tooltip", wx.DefaultPosition, wx.DefaultSize, 0 ) - mainSizer.Add( self.cbCompactSkills, 0, wx.ALL|wx.EXPAND, 5 ) + self.cbCompactSkills = wx.CheckBox(panel, wx.ID_ANY, u"Compact skills needed tooltip", wx.DefaultPosition, + wx.DefaultSize, 0) + mainSizer.Add(self.cbCompactSkills, 0, wx.ALL | wx.EXPAND, 5) - self.cbFitColorSlots = wx.CheckBox( panel, wx.ID_ANY, u"Color fitting view by slot", wx.DefaultPosition, wx.DefaultSize, 0 ) - mainSizer.Add( self.cbFitColorSlots, 0, wx.ALL|wx.EXPAND, 5 ) + self.cbFitColorSlots = wx.CheckBox(panel, wx.ID_ANY, u"Color fitting view by slot", wx.DefaultPosition, + wx.DefaultSize, 0) + mainSizer.Add(self.cbFitColorSlots, 0, wx.ALL | wx.EXPAND, 5) - self.cbReopenFits = wx.CheckBox( panel, wx.ID_ANY, u"Reopen previous fits on startup", wx.DefaultPosition, wx.DefaultSize, 0 ) - mainSizer.Add( self.cbReopenFits, 0, wx.ALL|wx.EXPAND, 5 ) + self.cbReopenFits = wx.CheckBox(panel, wx.ID_ANY, u"Reopen previous fits on startup", wx.DefaultPosition, + wx.DefaultSize, 0) + mainSizer.Add(self.cbReopenFits, 0, wx.ALL | wx.EXPAND, 5) - self.cbRackSlots = wx.CheckBox( panel, wx.ID_ANY, u"Separate Racks", wx.DefaultPosition, wx.DefaultSize, 0 ) - mainSizer.Add( self.cbRackSlots, 0, wx.ALL|wx.EXPAND, 5 ) + self.cbRackSlots = wx.CheckBox(panel, wx.ID_ANY, u"Separate Racks", wx.DefaultPosition, wx.DefaultSize, 0) + mainSizer.Add(self.cbRackSlots, 0, wx.ALL | wx.EXPAND, 5) - labelSizer = wx.BoxSizer( wx.VERTICAL ) - self.cbRackLabels = wx.CheckBox( panel, wx.ID_ANY, u"Show Rack Labels", wx.DefaultPosition, wx.DefaultSize, 0 ) - labelSizer.Add( self.cbRackLabels, 0, wx.ALL|wx.EXPAND, 5 ) - mainSizer.Add( labelSizer, 0, wx.LEFT|wx.EXPAND, 30 ) + labelSizer = wx.BoxSizer(wx.VERTICAL) + self.cbRackLabels = wx.CheckBox(panel, wx.ID_ANY, u"Show Rack Labels", wx.DefaultPosition, wx.DefaultSize, 0) + labelSizer.Add(self.cbRackLabels, 0, wx.ALL | wx.EXPAND, 5) + mainSizer.Add(labelSizer, 0, wx.LEFT | wx.EXPAND, 30) - self.cbShowTooltip = wx.CheckBox( panel, wx.ID_ANY, u"Show tab tooltips", wx.DefaultPosition, wx.DefaultSize, 0 ) - mainSizer.Add( self.cbShowTooltip, 0, wx.ALL|wx.EXPAND, 5 ) + self.cbShowTooltip = wx.CheckBox(panel, wx.ID_ANY, u"Show tab tooltips", wx.DefaultPosition, wx.DefaultSize, 0) + mainSizer.Add(self.cbShowTooltip, 0, wx.ALL | wx.EXPAND, 5) - self.cbMarketShortcuts = wx.CheckBox( panel, wx.ID_ANY, u"Show market shortcuts", wx.DefaultPosition, wx.DefaultSize, 0 ) - mainSizer.Add( self.cbMarketShortcuts, 0, wx.ALL|wx.EXPAND, 5 ) + self.cbMarketShortcuts = wx.CheckBox(panel, wx.ID_ANY, u"Show market shortcuts", wx.DefaultPosition, + wx.DefaultSize, 0) + mainSizer.Add(self.cbMarketShortcuts, 0, wx.ALL | wx.EXPAND, 5) - self.cbGaugeAnimation = wx.CheckBox( panel, wx.ID_ANY, u"Animate gauges", wx.DefaultPosition, wx.DefaultSize, 0 ) - mainSizer.Add( self.cbGaugeAnimation, 0, wx.ALL|wx.EXPAND, 5 ) + self.cbGaugeAnimation = wx.CheckBox(panel, wx.ID_ANY, u"Animate gauges", wx.DefaultPosition, wx.DefaultSize, 0) + mainSizer.Add(self.cbGaugeAnimation, 0, wx.ALL | wx.EXPAND, 5) - self.cbExportCharges = wx.CheckBox( panel, wx.ID_ANY, u"Export loaded charges", wx.DefaultPosition, wx.DefaultSize, 0 ) - mainSizer.Add( self.cbExportCharges, 0, wx.ALL|wx.EXPAND, 5 ) - - self.cbOpenFitInNew = wx.CheckBox( panel, wx.ID_ANY, u"Open fittings in a new page by default", wx.DefaultPosition, wx.DefaultSize, 0 ) - mainSizer.Add( self.cbOpenFitInNew, 0, wx.ALL|wx.EXPAND, 5 ) + self.cbExportCharges = wx.CheckBox(panel, wx.ID_ANY, u"Export loaded charges", wx.DefaultPosition, + wx.DefaultSize, 0) + mainSizer.Add(self.cbExportCharges, 0, wx.ALL | wx.EXPAND, 5) - defCharSizer = wx.BoxSizer( wx.HORIZONTAL ) + self.cbOpenFitInNew = wx.CheckBox(panel, wx.ID_ANY, u"Open fittings in a new page by default", + wx.DefaultPosition, wx.DefaultSize, 0) + mainSizer.Add(self.cbOpenFitInNew, 0, wx.ALL | wx.EXPAND, 5) - self.sFit = service.Fit.getInstance() + wx.BoxSizer(wx.HORIZONTAL) + + self.sFit = Fit.getInstance() self.cbGlobalChar.SetValue(self.sFit.serviceFittingOptions["useGlobalCharacter"]) self.cbGlobalDmgPattern.SetValue(self.sFit.serviceFittingOptions["useGlobalDamagePattern"]) @@ -102,7 +113,7 @@ class PFGeneralPref ( PreferenceView): self.cbRackLabels.Enable(self.sFit.serviceFittingOptions["rackSlots"] or False) - panel.SetSizer( mainSizer ) + panel.SetSizer(mainSizer) panel.Layout() def onCBGlobalColorBySlot(self, event): @@ -163,11 +174,12 @@ class PFGeneralPref ( PreferenceView): def onCBExportCharges(self, event): self.sFit.serviceFittingOptions["exportCharges"] = self.cbExportCharges.GetValue() - + def onCBOpenFitInNew(self, event): self.sFit.serviceFittingOptions["openFitInNew"] = self.cbOpenFitInNew.GetValue() def getImage(self): return BitmapLoader.getBitmap("prefs_settings", "gui") -PFGeneralPref.register() \ No newline at end of file + +PFGeneralPref.register() diff --git a/gui/builtinPreferenceViews/pyfaHTMLExportPreferences.py b/gui/builtinPreferenceViews/pyfaHTMLExportPreferences.py index c80a7a33e..c6428d8b7 100644 --- a/gui/builtinPreferenceViews/pyfaHTMLExportPreferences.py +++ b/gui/builtinPreferenceViews/pyfaHTMLExportPreferences.py @@ -5,78 +5,82 @@ from gui.preferenceView import PreferenceView from gui.bitmapLoader import BitmapLoader import gui.mainFrame -import service -import gui.globalEvents as GE + +from service.settings import HTMLExportSettings -class PFHTMLExportPref ( PreferenceView): +class PFHTMLExportPref(PreferenceView): title = "HTML Export" - desc = "HTML Export (File > Export HTML) allows you to export your entire fitting "+\ - "database into an HTML file at the specified location. This file can be "+\ - "used in the in-game browser to easily open and import your fits, or used "+\ - "in a regular web browser to open them at NULL-SEC.com or Osmium." - desc2 = "Enabling automatic exporting will update the HTML file after any change "+\ - "to a fit is made. Under certain circumstance, this may cause performance issues." - desc4 = "Export Fittings in a minmal HTML Version, just containing the Fittingslinks " +\ - "without any visual styling or javscript features" + desc = ("HTML Export (File > Export HTML) allows you to export your entire fitting " + "database into an HTML file at the specified location. This file can be " + "used in the in-game browser to easily open and import your fits, or used " + "in a regular web browser to open them at NULL-SEC.com or Osmium.") + desc2 = ("Enabling automatic exporting will update the HTML file after any change " + "to a fit is made. Under certain circumstance, this may cause performance issues.") + desc4 = ("Export Fittings in a minmal HTML Version, just containing the Fittingslinks " + "without any visual styling or javscript features") - def populatePanel( self, panel ): + def populatePanel(self, panel): self.mainFrame = gui.mainFrame.MainFrame.getInstance() - self.HTMLExportSettings = service.settings.HTMLExportSettings.getInstance() + self.HTMLExportSettings = HTMLExportSettings.getInstance() self.dirtySettings = False dlgWidth = panel.GetParent().GetParent().ClientSize.width - mainSizer = wx.BoxSizer( wx.VERTICAL ) + mainSizer = wx.BoxSizer(wx.VERTICAL) - self.stTitle = wx.StaticText( panel, wx.ID_ANY, self.title, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.stTitle.Wrap( -1 ) - self.stTitle.SetFont( wx.Font( 12, 70, 90, 90, False, wx.EmptyString ) ) - mainSizer.Add( self.stTitle, 0, wx.ALL, 5 ) + self.stTitle = wx.StaticText(panel, wx.ID_ANY, self.title, wx.DefaultPosition, wx.DefaultSize, 0) + self.stTitle.Wrap(-1) + self.stTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString)) + mainSizer.Add(self.stTitle, 0, wx.ALL, 5) - self.m_staticline1 = wx.StaticLine( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) - mainSizer.Add( self.m_staticline1, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5 ) + self.m_staticline1 = wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) + mainSizer.Add(self.m_staticline1, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5) - self.stDesc = wx.StaticText( panel, wx.ID_ANY, self.desc, wx.DefaultPosition, wx.DefaultSize, 0 ) + self.stDesc = wx.StaticText(panel, wx.ID_ANY, self.desc, wx.DefaultPosition, wx.DefaultSize, 0) self.stDesc.Wrap(dlgWidth - 50) - mainSizer.Add( self.stDesc, 0, wx.ALL, 5 ) + mainSizer.Add(self.stDesc, 0, wx.ALL, 5) - self.PathLinkCtrl = wx.HyperlinkCtrl( panel, wx.ID_ANY, self.HTMLExportSettings.getPath(), u'file:///{}'.format(self.HTMLExportSettings.getPath()), wx.DefaultPosition, wx.DefaultSize, wx.HL_ALIGN_LEFT|wx.NO_BORDER|wx.HL_CONTEXTMENU ) - mainSizer.Add( self.PathLinkCtrl, 0, wx.ALL|wx.EXPAND, 5) + self.PathLinkCtrl = wx.HyperlinkCtrl(panel, wx.ID_ANY, self.HTMLExportSettings.getPath(), + u'file:///{}'.format(self.HTMLExportSettings.getPath()), + wx.DefaultPosition, wx.DefaultSize, + wx.HL_ALIGN_LEFT | wx.NO_BORDER | wx.HL_CONTEXTMENU) + mainSizer.Add(self.PathLinkCtrl, 0, wx.ALL | wx.EXPAND, 5) - self.fileSelectDialog = wx.FileDialog(None, "Save Fitting As...", wildcard = "EVE IGB HTML fitting file (*.html)|*.html", style = wx.FD_SAVE) + self.fileSelectDialog = wx.FileDialog(None, "Save Fitting As...", + wildcard="EVE IGB HTML fitting file (*.html)|*.html", style=wx.FD_SAVE) self.fileSelectDialog.SetPath(self.HTMLExportSettings.getPath()) - self.fileSelectDialog.SetFilename(os.path.basename(self.HTMLExportSettings.getPath())); + self.fileSelectDialog.SetFilename(os.path.basename(self.HTMLExportSettings.getPath())) - self.fileSelectButton = wx.Button(panel, -1, "Set export destination", pos=(0,0)) + self.fileSelectButton = wx.Button(panel, -1, "Set export destination", pos=(0, 0)) self.fileSelectButton.Bind(wx.EVT_BUTTON, self.selectHTMLExportFilePath) - mainSizer.Add( self.fileSelectButton, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5) + mainSizer.Add(self.fileSelectButton, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - self.stDesc2 = wx.StaticText( panel, wx.ID_ANY, self.desc2, wx.DefaultPosition, wx.DefaultSize, 0 ) + self.stDesc2 = wx.StaticText(panel, wx.ID_ANY, self.desc2, wx.DefaultPosition, wx.DefaultSize, 0) self.stDesc2.Wrap(dlgWidth - 50) - mainSizer.Add( self.stDesc2, 0, wx.ALL, 5 ) + mainSizer.Add(self.stDesc2, 0, wx.ALL, 5) - self.exportEnabled = wx.CheckBox( panel, wx.ID_ANY, u"Enable automatic HTML export", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.exportEnabled = wx.CheckBox(panel, wx.ID_ANY, u"Enable automatic HTML export", wx.DefaultPosition, + wx.DefaultSize, 0) self.exportEnabled.SetValue(self.HTMLExportSettings.getEnabled()) self.exportEnabled.Bind(wx.EVT_CHECKBOX, self.OnExportEnabledChange) - mainSizer.Add( self.exportEnabled, 0, wx.ALL|wx.EXPAND, 5 ) + mainSizer.Add(self.exportEnabled, 0, wx.ALL | wx.EXPAND, 5) - - - self.stDesc4 = wx.StaticText( panel, wx.ID_ANY, self.desc4, wx.DefaultPosition, wx.DefaultSize, 0 ) + self.stDesc4 = wx.StaticText(panel, wx.ID_ANY, self.desc4, wx.DefaultPosition, wx.DefaultSize, 0) self.stDesc4.Wrap(dlgWidth - 50) - mainSizer.Add( self.stDesc4, 0, wx.ALL, 5 ) + mainSizer.Add(self.stDesc4, 0, wx.ALL, 5) - self.exportMinimal = wx.CheckBox( panel, wx.ID_ANY, u"Enable minimal export Format", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.exportMinimal = wx.CheckBox(panel, wx.ID_ANY, u"Enable minimal export Format", wx.DefaultPosition, + wx.DefaultSize, 0) self.exportMinimal.SetValue(self.HTMLExportSettings.getMinimalEnabled()) self.exportMinimal.Bind(wx.EVT_CHECKBOX, self.OnMinimalEnabledChange) - mainSizer.Add( self.exportMinimal, 0, wx.ALL|wx.EXPAND, 5 ) + mainSizer.Add(self.exportMinimal, 0, wx.ALL | wx.EXPAND, 5) - panel.SetSizer( mainSizer ) + panel.SetSizer(mainSizer) panel.Layout() def setPathLinkCtrlValues(self, path): self.PathLinkCtrl.SetLabel(self.HTMLExportSettings.getPath()) self.PathLinkCtrl.SetURL(u'file:///{}'.format(self.HTMLExportSettings.getPath())) - self.PathLinkCtrl.SetSize(wx.DefaultSize); + self.PathLinkCtrl.SetSize(wx.DefaultSize) self.PathLinkCtrl.Refresh() def selectHTMLExportFilePath(self, event): @@ -94,4 +98,5 @@ class PFHTMLExportPref ( PreferenceView): def getImage(self): return BitmapLoader.getBitmap("prefs_html", "gui") + PFHTMLExportPref.register() diff --git a/gui/builtinPreferenceViews/pyfaNetworkPreferences.py b/gui/builtinPreferenceViews/pyfaNetworkPreferences.py index bd79dd88c..8c93b1a5f 100644 --- a/gui/builtinPreferenceViews/pyfaNetworkPreferences.py +++ b/gui/builtinPreferenceViews/pyfaNetworkPreferences.py @@ -4,50 +4,54 @@ from gui.preferenceView import PreferenceView from gui.bitmapLoader import BitmapLoader import gui.mainFrame -import service +from service.settings import NetworkSettings +from service.network import Network -class PFNetworkPref ( PreferenceView): + +class PFNetworkPref(PreferenceView): title = "Network" - def populatePanel( self, panel ): + def populatePanel(self, panel): self.mainFrame = gui.mainFrame.MainFrame.getInstance() - self.settings = service.settings.NetworkSettings.getInstance() - self.network = service.Network.getInstance() + self.settings = NetworkSettings.getInstance() + self.network = Network.getInstance() self.dirtySettings = False - mainSizer = wx.BoxSizer( wx.VERTICAL ) + mainSizer = wx.BoxSizer(wx.VERTICAL) - self.stTitle = wx.StaticText( panel, wx.ID_ANY, self.title, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.stTitle.Wrap( -1 ) - self.stTitle.SetFont( wx.Font( 12, 70, 90, 90, False, wx.EmptyString ) ) + self.stTitle = wx.StaticText(panel, wx.ID_ANY, self.title, wx.DefaultPosition, wx.DefaultSize, 0) + self.stTitle.Wrap(-1) + self.stTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString)) - mainSizer.Add( self.stTitle, 0, wx.ALL, 5 ) + mainSizer.Add(self.stTitle, 0, wx.ALL, 5) - self.m_staticline1 = wx.StaticLine( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) - mainSizer.Add( self.m_staticline1, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5 ) + self.m_staticline1 = wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) + mainSizer.Add(self.m_staticline1, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5) - self.cbEnableNetwork = wx.CheckBox( panel, wx.ID_ANY, u"Enable Network", wx.DefaultPosition, wx.DefaultSize, 0 ) - mainSizer.Add( self.cbEnableNetwork, 0, wx.ALL|wx.EXPAND, 5 ) + self.cbEnableNetwork = wx.CheckBox(panel, wx.ID_ANY, u"Enable Network", wx.DefaultPosition, wx.DefaultSize, 0) + mainSizer.Add(self.cbEnableNetwork, 0, wx.ALL | wx.EXPAND, 5) - subSizer = wx.BoxSizer( wx.VERTICAL ) - self.cbEve = wx.CheckBox( panel, wx.ID_ANY, u"EVE Servers (API && CREST import)", wx.DefaultPosition, wx.DefaultSize, 0 ) - subSizer.Add( self.cbEve, 0, wx.ALL|wx.EXPAND, 5 ) + subSizer = wx.BoxSizer(wx.VERTICAL) + self.cbEve = wx.CheckBox(panel, wx.ID_ANY, u"EVE Servers (API && CREST import)", wx.DefaultPosition, + wx.DefaultSize, 0) + subSizer.Add(self.cbEve, 0, wx.ALL | wx.EXPAND, 5) - self.cbPricing = wx.CheckBox( panel, wx.ID_ANY, u"Pricing updates", wx.DefaultPosition, wx.DefaultSize, 0 ) - subSizer.Add( self.cbPricing, 0, wx.ALL|wx.EXPAND, 5 ) + self.cbPricing = wx.CheckBox(panel, wx.ID_ANY, u"Pricing updates", wx.DefaultPosition, wx.DefaultSize, 0) + subSizer.Add(self.cbPricing, 0, wx.ALL | wx.EXPAND, 5) - self.cbPyfaUpdate = wx.CheckBox( panel, wx.ID_ANY, u"Pyfa Update checks", wx.DefaultPosition, wx.DefaultSize, 0 ) - subSizer.Add( self.cbPyfaUpdate, 0, wx.ALL|wx.EXPAND, 5 ) + self.cbPyfaUpdate = wx.CheckBox(panel, wx.ID_ANY, u"Pyfa Update checks", wx.DefaultPosition, wx.DefaultSize, 0) + subSizer.Add(self.cbPyfaUpdate, 0, wx.ALL | wx.EXPAND, 5) - mainSizer.Add( subSizer, 0, wx.LEFT|wx.EXPAND, 30 ) + mainSizer.Add(subSizer, 0, wx.LEFT | wx.EXPAND, 30) - proxyTitle = wx.StaticText( panel, wx.ID_ANY, "Proxy settings", wx.DefaultPosition, wx.DefaultSize, 0 ) - proxyTitle.Wrap( -1 ) - proxyTitle.SetFont( wx.Font( 12, 70, 90, 90, False, wx.EmptyString ) ) + proxyTitle = wx.StaticText(panel, wx.ID_ANY, "Proxy settings", wx.DefaultPosition, wx.DefaultSize, 0) + proxyTitle.Wrap(-1) + proxyTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString)) - mainSizer.Add( proxyTitle, 0, wx.ALL, 5 ) - mainSizer.Add( wx.StaticLine( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ), 0, wx.EXPAND, 5 ) + mainSizer.Add(proxyTitle, 0, wx.ALL, 5) + mainSizer.Add(wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0, + wx.EXPAND, 5) self.cbEnableNetwork.SetValue(self.settings.isEnabled(self.network.ENABLED)) self.cbEve.SetValue(self.settings.isEnabled(self.network.EVE)) @@ -61,9 +65,9 @@ class PFNetworkPref ( PreferenceView): self.toggleNetworks(self.cbEnableNetwork.GetValue()) - #--------------- + # --------------- # Proxy - #--------------- + # --------------- self.nMode = self.settings.getMode() self.nAddr = self.settings.getAddress() @@ -73,51 +77,50 @@ class PFNetworkPref ( PreferenceView): if self.nAuth is None: self.nAuth = ("", "") # we don't want None here, it should be a tuple - ptypeSizer = wx.BoxSizer( wx.HORIZONTAL ) + ptypeSizer = wx.BoxSizer(wx.HORIZONTAL) - self.stPType = wx.StaticText( panel, wx.ID_ANY, u"Mode:", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.stPType.Wrap( -1 ) - ptypeSizer.Add( self.stPType, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + self.stPType = wx.StaticText(panel, wx.ID_ANY, u"Mode:", wx.DefaultPosition, wx.DefaultSize, 0) + self.stPType.Wrap(-1) + ptypeSizer.Add(self.stPType, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - self.chProxyTypeChoices = [ u"No proxy", u"Auto-detected proxy settings", u"Manual proxy settings" ] - self.chProxyType = wx.Choice( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, self.chProxyTypeChoices, 0 ) + self.chProxyTypeChoices = [u"No proxy", u"Auto-detected proxy settings", u"Manual proxy settings"] + self.chProxyType = wx.Choice(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, self.chProxyTypeChoices, 0) + self.chProxyType.SetSelection(self.nMode) - self.chProxyType.SetSelection( self.nMode ) + ptypeSizer.Add(self.chProxyType, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - ptypeSizer.Add( self.chProxyType, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + mainSizer.Add(ptypeSizer, 0, wx.EXPAND, 5) - mainSizer.Add( ptypeSizer, 0, wx.EXPAND, 5 ) + fgAddrSizer = wx.FlexGridSizer(2, 2, 0, 0) + fgAddrSizer.AddGrowableCol(1) + fgAddrSizer.SetFlexibleDirection(wx.BOTH) + fgAddrSizer.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) - fgAddrSizer = wx.FlexGridSizer( 2, 2, 0, 0 ) - fgAddrSizer.AddGrowableCol( 1 ) - fgAddrSizer.SetFlexibleDirection( wx.BOTH ) - fgAddrSizer.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED ) + self.stPSetAddr = wx.StaticText(panel, wx.ID_ANY, u"Addr:", wx.DefaultPosition, wx.DefaultSize, 0) + self.stPSetAddr.Wrap(-1) + fgAddrSizer.Add(self.stPSetAddr, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) + self.editProxySettingsAddr = wx.TextCtrl(panel, wx.ID_ANY, self.nAddr, wx.DefaultPosition, wx.DefaultSize, 0) - self.stPSetAddr = wx.StaticText( panel, wx.ID_ANY, u"Addr:", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.stPSetAddr.Wrap( -1 ) - fgAddrSizer.Add( self.stPSetAddr, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + fgAddrSizer.Add(self.editProxySettingsAddr, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5) - self.editProxySettingsAddr = wx.TextCtrl( panel, wx.ID_ANY, self.nAddr, wx.DefaultPosition, wx.DefaultSize, 0 ) + self.stPSetPort = wx.StaticText(panel, wx.ID_ANY, u"Port:", wx.DefaultPosition, wx.DefaultSize, 0) + self.stPSetPort.Wrap(-1) - fgAddrSizer.Add( self.editProxySettingsAddr, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5 ) + fgAddrSizer.Add(self.stPSetPort, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - self.stPSetPort = wx.StaticText( panel, wx.ID_ANY, u"Port:", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.stPSetPort.Wrap( -1 ) + self.editProxySettingsPort = wx.TextCtrl(panel, wx.ID_ANY, self.nPort, wx.DefaultPosition, wx.DefaultSize, 0) - fgAddrSizer.Add( self.stPSetPort, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + fgAddrSizer.Add(self.editProxySettingsPort, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5) - self.editProxySettingsPort = wx.TextCtrl( panel, wx.ID_ANY, self.nPort, wx.DefaultPosition, wx.DefaultSize, 0 ) - - fgAddrSizer.Add( self.editProxySettingsPort, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5 ) - - mainSizer.Add( fgAddrSizer, 0, wx.EXPAND, 5) + mainSizer.Add(fgAddrSizer, 0, wx.EXPAND, 5) # proxy auth information: login and pass self.stPSetLogin = wx.StaticText(panel, wx.ID_ANY, u"Username:", wx.DefaultPosition, wx.DefaultSize, 0) self.stPSetLogin.Wrap(-1) - self.editProxySettingsLogin = wx.TextCtrl(panel, wx.ID_ANY, self.nAuth[0], wx.DefaultPosition, wx.DefaultSize, 0) + self.editProxySettingsLogin = wx.TextCtrl(panel, wx.ID_ANY, self.nAuth[0], wx.DefaultPosition, wx.DefaultSize, + 0) self.stPSetPassword = wx.StaticText(panel, wx.ID_ANY, u"Password:", wx.DefaultPosition, wx.DefaultSize, 0) self.stPSetPassword.Wrap(-1) self.editProxySettingsPassword = wx.TextCtrl(panel, wx.ID_ANY, self.nAuth[1], wx.DefaultPosition, @@ -129,23 +132,24 @@ class PFNetworkPref ( PreferenceView): pAuthSizer.Add(self.editProxySettingsPassword, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) mainSizer.Add(pAuthSizer, 0, wx.EXPAND, 5) - self.stPSAutoDetected = wx.StaticText( panel, wx.ID_ANY, u"Auto-detected: ", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.stPSAutoDetected.Wrap( -1 ) - mainSizer.Add( self.stPSAutoDetected, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + self.stPSAutoDetected = wx.StaticText(panel, wx.ID_ANY, u"Auto-detected: ", wx.DefaultPosition, wx.DefaultSize, + 0) + self.stPSAutoDetected.Wrap(-1) + mainSizer.Add(self.stPSAutoDetected, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) - btnSizer = wx.BoxSizer( wx.HORIZONTAL ) - btnSizer.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + btnSizer.AddSpacer((0, 0), 1, wx.EXPAND, 5) - self.btnApply = wx.Button( panel, wx.ID_ANY, u"Apply Proxy Settings", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.btnApply = wx.Button(panel, wx.ID_ANY, u"Apply Proxy Settings", wx.DefaultPosition, wx.DefaultSize, 0) - btnSizer.Add( self.btnApply, 0, wx.ALL, 5 ) + btnSizer.Add(self.btnApply, 0, wx.ALL, 5) - mainSizer.Add(btnSizer, 0, wx.EXPAND,5) + mainSizer.Add(btnSizer, 0, wx.EXPAND, 5) proxy = self.settings.autodetect() if proxy is not None: - addr,port = proxy + addr, port = proxy txt = addr + ":" + str(port) else: txt = "None" @@ -159,17 +163,16 @@ class PFNetworkPref ( PreferenceView): self.editProxySettingsLogin.Bind(wx.EVT_TEXT, self.OnEditPSLoginText) self.editProxySettingsPassword.Bind(wx.EVT_TEXT, self.OnEditPSPasswordText) - self.btnApply.Bind(wx.EVT_BUTTON, self.OnBtnApply) self.UpdateApplyButtonState() - if self.nMode is not service.settings.NetworkSettings.PROXY_MODE_MANUAL: # == 2 + if self.nMode is not NetworkSettings.PROXY_MODE_MANUAL: # == 2 self.ToggleProxySettings(False) else: self.ToggleProxySettings(True) - panel.SetSizer( mainSizer ) + panel.SetSizer(mainSizer) panel.Layout() def toggleNetworks(self, toggle): @@ -236,7 +239,7 @@ class PFNetworkPref ( PreferenceView): self.UpdateApplyButtonState() - if choice is not service.settings.NetworkSettings.PROXY_MODE_MANUAL: + if choice is not NetworkSettings.PROXY_MODE_MANUAL: self.ToggleProxySettings(False) else: self.ToggleProxySettings(True) @@ -264,4 +267,5 @@ class PFNetworkPref ( PreferenceView): def getImage(self): return BitmapLoader.getBitmap("prefs_proxy", "gui") + PFNetworkPref.register() diff --git a/gui/builtinPreferenceViews/pyfaUpdatePreferences.py b/gui/builtinPreferenceViews/pyfaUpdatePreferences.py index c49bd0c94..48e2a79cc 100644 --- a/gui/builtinPreferenceViews/pyfaUpdatePreferences.py +++ b/gui/builtinPreferenceViews/pyfaUpdatePreferences.py @@ -1,84 +1,82 @@ import wx -import service -import os from gui.preferenceView import PreferenceView from gui.bitmapLoader import BitmapLoader - -import service -import gui.globalEvents as GE +from service.settings import UpdateSettings -class PFUpdatePref (PreferenceView): +class PFUpdatePref(PreferenceView): title = "Updates" - desc = "Pyfa can automatically check and notify you of new releases. "+\ - "This feature is toggled in the Network settings. "+\ - "Here, you may allow pre-release notifications and view "+\ - "suppressed release notifications, if any." + desc = ("Pyfa can automatically check and notify you of new releases. " + "This feature is toggled in the Network settings. " + "Here, you may allow pre-release notifications and view " + "suppressed release notifications, if any.") - def populatePanel( self, panel ): - self.UpdateSettings = service.settings.UpdateSettings.getInstance() + def populatePanel(self, panel): + self.UpdateSettings = UpdateSettings.getInstance() self.dirtySettings = False dlgWidth = panel.GetParent().GetParent().ClientSize.width - mainSizer = wx.BoxSizer( wx.VERTICAL ) + mainSizer = wx.BoxSizer(wx.VERTICAL) - self.stTitle = wx.StaticText( panel, wx.ID_ANY, self.title, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.stTitle.Wrap( -1 ) - self.stTitle.SetFont( wx.Font( 12, 70, 90, 90, False, wx.EmptyString ) ) - mainSizer.Add( self.stTitle, 0, wx.ALL, 5 ) + self.stTitle = wx.StaticText(panel, wx.ID_ANY, self.title, wx.DefaultPosition, wx.DefaultSize, 0) + self.stTitle.Wrap(-1) + self.stTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString)) + mainSizer.Add(self.stTitle, 0, wx.ALL, 5) - self.m_staticline1 = wx.StaticLine( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) - mainSizer.Add( self.m_staticline1, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5 ) + self.m_staticline1 = wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) + mainSizer.Add(self.m_staticline1, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5) - self.stDesc = wx.StaticText( panel, wx.ID_ANY, self.desc, wx.DefaultPosition, wx.DefaultSize, 0 ) + self.stDesc = wx.StaticText(panel, wx.ID_ANY, self.desc, wx.DefaultPosition, wx.DefaultSize, 0) self.stDesc.Wrap(dlgWidth - 50) - mainSizer.Add( self.stDesc, 0, wx.ALL, 5 ) + mainSizer.Add(self.stDesc, 0, wx.ALL, 5) - self.suppressPrerelease = wx.CheckBox( panel, wx.ID_ANY, u"Allow pre-release notifications", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.suppressPrerelease = wx.CheckBox(panel, wx.ID_ANY, u"Allow pre-release notifications", wx.DefaultPosition, + wx.DefaultSize, 0) self.suppressPrerelease.Bind(wx.EVT_CHECKBOX, self.OnPrereleaseStateChange) self.suppressPrerelease.SetValue(not self.UpdateSettings.get('prerelease')) - mainSizer.Add( self.suppressPrerelease, 0, wx.ALL|wx.EXPAND, 5 ) + mainSizer.Add(self.suppressPrerelease, 0, wx.ALL | wx.EXPAND, 5) if (self.UpdateSettings.get('version')): - self.versionSizer = wx.BoxSizer( wx.VERTICAL ) + self.versionSizer = wx.BoxSizer(wx.VERTICAL) + self.versionTitle = wx.StaticText(panel, wx.ID_ANY, "Suppressing {0} Notifications".format( + self.UpdateSettings.get('version')), wx.DefaultPosition, wx.DefaultSize, 0) + self.versionTitle.Wrap(-1) + self.versionTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString)) - self.versionTitle = wx.StaticText( panel, wx.ID_ANY, "Suppressing "+self.UpdateSettings.get('version')+" Notifications", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.versionTitle.Wrap( -1 ) - self.versionTitle.SetFont( wx.Font( 12, 70, 90, 90, False, wx.EmptyString ) ) + self.versionInfo = ("There is a release available which you have chosen to suppress. " + "You can choose to reset notification suppression for this release, " + "or download the new release from GitHub.") - self.versionInfo = "There is a release available which you have chosen to suppress. "+\ - "You can choose to reset notification suppression for this release, "+\ - "or download the new release from GitHub." + self.versionSizer.AddSpacer((5, 5), 0, wx.EXPAND, 5) - self.versionSizer.AddSpacer( ( 5, 5), 0, wx.EXPAND, 5 ) + self.versionSizer.Add(wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), + 0, wx.EXPAND, 5) + self.versionSizer.AddSpacer((5, 5), 0, wx.EXPAND, 5) - self.versionSizer.Add( wx.StaticLine( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ), 0, wx.EXPAND, 5 ) - self.versionSizer.AddSpacer( ( 5, 5), 0, wx.EXPAND, 5 ) - - self.versionSizer.Add( self.versionTitle, 0, wx.EXPAND, 5 ) - self.versionDesc = wx.StaticText( panel, wx.ID_ANY, self.versionInfo, wx.DefaultPosition, wx.DefaultSize, 0 ) + self.versionSizer.Add(self.versionTitle, 0, wx.EXPAND, 5) + self.versionDesc = wx.StaticText(panel, wx.ID_ANY, self.versionInfo, wx.DefaultPosition, wx.DefaultSize, 0) self.versionDesc.Wrap(dlgWidth - 50) - self.versionSizer.Add( self.versionDesc, 0, wx.ALL, 5 ) + self.versionSizer.Add(self.versionDesc, 0, wx.ALL, 5) - actionSizer = wx.BoxSizer( wx.HORIZONTAL ) - resetSizer = wx.BoxSizer( wx.VERTICAL ) + actionSizer = wx.BoxSizer(wx.HORIZONTAL) + resetSizer = wx.BoxSizer(wx.VERTICAL) - self.downloadButton = wx.Button( panel, wx.ID_ANY, "Download", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.downloadButton = wx.Button(panel, wx.ID_ANY, "Download", wx.DefaultPosition, wx.DefaultSize, 0) self.downloadButton.Bind(wx.EVT_BUTTON, self.OnDownload) - resetSizer.Add( self.downloadButton, 0, wx.ALL, 5 ) - actionSizer.Add( resetSizer, 1, wx.EXPAND, 5 ) + resetSizer.Add(self.downloadButton, 0, wx.ALL, 5) + actionSizer.Add(resetSizer, 1, wx.EXPAND, 5) - self.resetButton = wx.Button( panel, wx.ID_ANY, "Reset Suppression", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.resetButton = wx.Button(panel, wx.ID_ANY, "Reset Suppression", wx.DefaultPosition, wx.DefaultSize, 0) self.resetButton.Bind(wx.EVT_BUTTON, self.ResetSuppression) - actionSizer.Add( self.resetButton, 0, wx.ALL, 5 ) - self.versionSizer.Add( actionSizer, 0, wx.EXPAND, 5 ) - mainSizer.Add( self.versionSizer, 0, wx.EXPAND, 5 ) + actionSizer.Add(self.resetButton, 0, wx.ALL, 5) + self.versionSizer.Add(actionSizer, 0, wx.EXPAND, 5) + mainSizer.Add(self.versionSizer, 0, wx.EXPAND, 5) - panel.SetSizer( mainSizer ) + panel.SetSizer(mainSizer) panel.Layout() def OnPrereleaseStateChange(self, event): @@ -96,9 +94,10 @@ class PFUpdatePref (PreferenceView): self.resetButton.Hide() def OnDownload(self, event): - wx.LaunchDefaultBrowser('https://github.com/pyfa-org/Pyfa/releases/tag/'+self.UpdateSettings.get('version')) + wx.LaunchDefaultBrowser('https://github.com/pyfa-org/Pyfa/releases/tag/' + self.UpdateSettings.get('version')) def getImage(self): return BitmapLoader.getBitmap("prefs_update", "gui") + PFUpdatePref.register() diff --git a/gui/builtinStatsViews/capacitorViewFull.py b/gui/builtinStatsViews/capacitorViewFull.py index c07045199..a09b2ff91 100644 --- a/gui/builtinStatsViews/capacitorViewFull.py +++ b/gui/builtinStatsViews/capacitorViewFull.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,24 +15,26 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx from gui.statsView import StatsView -from gui import builtinStatsViews from gui.bitmapLoader import BitmapLoader from gui.utils.numberFormatter import formatAmount + class CapacitorViewFull(StatsView): name = "capacitorViewFull" + def __init__(self, parent): StatsView.__init__(self) self.parent = parent + def getHeaderText(self, fit): return "Capacitor" def getTextExtentW(self, text): - width, height = self.parent.GetTextExtent( text ) + width, height = self.parent.GetTextExtent(text) return width def populatePanel(self, contentPanel, headerPanel): @@ -104,12 +106,13 @@ class CapacitorViewFull(StatsView): chargeSizer.Add(lbl, 0, wx.ALIGN_CENTER) chargeSizer.Add(wx.StaticText(parent, wx.ID_ANY, " GJ/s"), 0, wx.ALIGN_CENTER) - def refreshPanel(self, fit): - #If we did anything intresting, we'd update our labels to reflect the new fit's stats here - stats= (("label%sCapacitorCapacity", lambda: fit.ship.getModifiedItemAttr("capacitorCapacity"), 3, 0, 9), - ("label%sCapacitorRecharge", lambda: fit.capRecharge, 3, 0, 0), - ("label%sCapacitorDischarge", lambda: fit.capUsed, 3, 0, 0)) + # If we did anything intresting, we'd update our labels to reflect the new fit's stats here + stats = ( + ("label%sCapacitorCapacity", lambda: fit.ship.getModifiedItemAttr("capacitorCapacity"), 3, 0, 9), + ("label%sCapacitorRecharge", lambda: fit.capRecharge, 3, 0, 0), + ("label%sCapacitorDischarge", lambda: fit.capUsed, 3, 0, 0), + ) panel = "Full" for labelName, value, prec, lowest, highest in stats: @@ -147,4 +150,5 @@ class CapacitorViewFull(StatsView): self.panel.Layout() self.headerPanel.Layout() + CapacitorViewFull.register() diff --git a/gui/builtinStatsViews/firepowerViewFull.py b/gui/builtinStatsViews/firepowerViewFull.py index 0e8d1c070..9c31fefe2 100644 --- a/gui/builtinStatsViews/firepowerViewFull.py +++ b/gui/builtinStatsViews/firepowerViewFull.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,17 +15,19 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx -import service import gui.mainFrame from gui.statsView import StatsView from gui.bitmapLoader import BitmapLoader from gui.utils.numberFormatter import formatAmount +from service.fit import Fit + class FirepowerViewFull(StatsView): name = "firepowerViewFull" + def __init__(self, parent): StatsView.__init__(self) self.parent = parent @@ -35,7 +37,7 @@ class FirepowerViewFull(StatsView): return "Firepower" def getTextExtentW(self, text): - width, height = self.parent.GetTextExtent( text ) + width, height = self.parent.GetTextExtent(text) return width def populatePanel(self, contentPanel, headerPanel): @@ -84,7 +86,7 @@ class FirepowerViewFull(StatsView): baseBox.Add(BitmapLoader.getStaticBitmap("volley_big", parent, "gui"), 0, wx.ALIGN_CENTER) - gridS = wx.GridSizer(2,2,0,0) + gridS = wx.GridSizer(2, 2, 0, 0) baseBox.Add(gridS, 0) @@ -114,7 +116,7 @@ class FirepowerViewFull(StatsView): def switchToMiningYieldView(self, event): # Getting the active fit mainFrame = gui.mainFrame.MainFrame.getInstance() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(mainFrame.getActiveFit()) # Remove ourselves from statsPane's view list self.parent.views.remove(self) @@ -139,20 +141,20 @@ class FirepowerViewFull(StatsView): view.refreshPanel(fit) def refreshPanel(self, fit): - #If we did anything intresting, we'd update our labels to reflect the new fit's stats here + # If we did anything intresting, we'd update our labels to reflect the new fit's stats here if fit is not None and fit.targetResists is not None: self.stEff.Show() else: self.stEff.Hide() - stats = (("labelFullDpsWeapon", lambda: fit.weaponDPS, 3, 0, 0, "%s DPS",None), + stats = (("labelFullDpsWeapon", lambda: fit.weaponDPS, 3, 0, 0, "%s DPS", None), ("labelFullDpsDrone", lambda: fit.droneDPS, 3, 0, 0, "%s DPS", None), ("labelFullVolleyTotal", lambda: fit.totalVolley, 3, 0, 0, "%s", "Volley: %.1f"), ("labelFullDpsTotal", lambda: fit.totalDPS, 3, 0, 0, "%s", None)) # See GH issue # - #if fit is not None and fit.totalYield > 0: + # if fit is not None and fit.totalYield > 0: # self.miningyield.Show() - #else: + # else: # self.miningyield.Hide() counter = 0 @@ -166,9 +168,10 @@ class FirepowerViewFull(StatsView): tipStr = valueFormat % valueStr if altFormat is None else altFormat % value label.SetToolTip(wx.ToolTip(tipStr)) self._cachedValues[counter] = value - counter +=1 + counter += 1 self.panel.Layout() self.headerPanel.Layout() + FirepowerViewFull.register() diff --git a/gui/builtinStatsViews/miningyieldViewFull.py b/gui/builtinStatsViews/miningyieldViewFull.py index 65ce9ae96..eed6e5d85 100644 --- a/gui/builtinStatsViews/miningyieldViewFull.py +++ b/gui/builtinStatsViews/miningyieldViewFull.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2014 Alexandros Kosiaris # # This file is part of pyfa. @@ -15,26 +15,29 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx -import service import gui.mainFrame from gui.statsView import StatsView from gui.bitmapLoader import BitmapLoader from gui.utils.numberFormatter import formatAmount +from service.fit import Fit + class MiningYieldViewFull(StatsView): name = "miningyieldViewFull" + def __init__(self, parent): StatsView.__init__(self) self.parent = parent self._cachedValues = [] + def getHeaderText(self, fit): return "Mining Yield" def getTextExtentW(self, text): - width, height = self.parent.GetTextExtent( text ) + width, height = self.parent.GetTextExtent(text) return width def populatePanel(self, contentPanel, headerPanel): @@ -47,11 +50,11 @@ class MiningYieldViewFull(StatsView): sizerMiningYield = wx.FlexGridSizer(1, 4) sizerMiningYield.AddGrowableCol(1) - contentSizer.Add( sizerMiningYield, 0, wx.EXPAND, 0) + contentSizer.Add(sizerMiningYield, 0, wx.EXPAND, 0) counter = 0 - for miningType, image in (("miner", "mining") , ("drone", "drones")): + for miningType, image in (("miner", "mining"), ("drone", "drones")): baseBox = wx.BoxSizer(wx.HORIZONTAL) sizerMiningYield.Add(baseBox, 1, wx.ALIGN_LEFT if counter == 0 else wx.ALIGN_CENTER_HORIZONTAL) @@ -66,7 +69,7 @@ class MiningYieldViewFull(StatsView): box.Add(hbox, 1, wx.ALIGN_CENTER) lbl = wx.StaticText(parent, wx.ID_ANY, u"0.0 m\u00B3/s") - setattr(self, "label%sminingyield%s" % (panel.capitalize() ,miningType.capitalize()), lbl) + setattr(self, "label%sminingyield%s" % (panel.capitalize(), miningType.capitalize()), lbl) hbox.Add(lbl, 0, wx.ALIGN_CENTER) self._cachedValues.append(0) @@ -103,7 +106,7 @@ class MiningYieldViewFull(StatsView): def switchToFirepowerView(self, event): # Getting the active fit mainFrame = gui.mainFrame.MainFrame.getInstance() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(mainFrame.getActiveFit()) # Remove ourselves from statsPane's view list self.parent.views.remove(self) @@ -122,11 +125,11 @@ class MiningYieldViewFull(StatsView): view.refreshPanel(fit) def refreshPanel(self, fit): - #If we did anything intresting, we'd update our labels to reflect the new fit's stats here + # If we did anything intresting, we'd update our labels to reflect the new fit's stats here - stats = (("labelFullminingyieldMiner", lambda: fit.minerYield * 3600, 3, 0, 0, u"%s m\u00B3/h",None), - ("labelFullminingyieldDrone", lambda: fit.droneYield * 3600, 3, 0, 0, u"%s m\u00B3/h", None), - ("labelFullminingyieldTotal", lambda: fit.totalYield * 3600, 3, 0, 0, u"%s m\u00B3/h", None)) + stats = (("labelFullminingyieldMiner", lambda: fit.minerYield, 3, 0, 0, u"%s m\u00B3/s",None), + ("labelFullminingyieldDrone", lambda: fit.droneYield, 3, 0, 0, u"%s m\u00B3/s", None), + ("labelFullminingyieldTotal", lambda: fit.totalYield, 3, 0, 0, u"%s m\u00B3/s", None)) counter = 0 for labelName, value, prec, lowest, highest, valueFormat, altFormat in stats: @@ -136,11 +139,12 @@ class MiningYieldViewFull(StatsView): if self._cachedValues[counter] != value: valueStr = formatAmount(value, prec, lowest, highest) label.SetLabel(valueFormat % valueStr) - tipStr = valueFormat % valueStr if altFormat is None else altFormat % value + tipStr = "Mining Yield per second ({0} per hour)".format(formatAmount(value * 3600, 3, 0, 3)) label.SetToolTip(wx.ToolTip(tipStr)) self._cachedValues[counter] = value - counter +=1 + counter += 1 self.panel.Layout() self.headerPanel.Layout() + MiningYieldViewFull.register() diff --git a/gui/builtinStatsViews/priceViewFull.py b/gui/builtinStatsViews/priceViewFull.py index aae611ac6..bb222d94a 100644 --- a/gui/builtinStatsViews/priceViewFull.py +++ b/gui/builtinStatsViews/priceViewFull.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,17 +15,18 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx from gui.statsView import StatsView -from gui import builtinStatsViews from gui.bitmapLoader import BitmapLoader from gui.utils.numberFormatter import formatAmount -import service +from service.market import Market + class PriceViewFull(StatsView): name = "priceViewFull" + def __init__(self, parent): StatsView.__init__(self) self.parent = parent @@ -90,7 +91,7 @@ class PriceViewFull(StatsView): for cargo in fit.cargo: typeIDs.append(cargo.itemID) - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() sMkt.getPrices(typeIDs, self.processPrices) self.labelEMStatus.SetLabel("Updating prices...") else: @@ -115,10 +116,11 @@ class PriceViewFull(StatsView): self.labelPriceFittings.SetLabel("%s ISK" % formatAmount(modPrice, 3, 3, 9, currency=True)) self.labelPriceFittings.SetToolTip(wx.ToolTip('{:,.2f}'.format(modPrice))) self._cachedFittings = modPrice - if self._cachedTotal != (shipPrice+modPrice): + if self._cachedTotal != (shipPrice + modPrice): self.labelPriceTotal.SetLabel("%s ISK" % formatAmount(shipPrice + modPrice, 3, 3, 9, currency=True)) self.labelPriceTotal.SetToolTip(wx.ToolTip('{:,.2f}'.format(shipPrice + modPrice))) self._cachedTotal = shipPrice + modPrice self.panel.Layout() + PriceViewFull.register() diff --git a/gui/builtinStatsViews/rechargeViewFull.py b/gui/builtinStatsViews/rechargeViewFull.py index c73aaf0b4..a285c04cb 100644 --- a/gui/builtinStatsViews/rechargeViewFull.py +++ b/gui/builtinStatsViews/rechargeViewFull.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,7 +15,7 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx from gui.statsView import StatsView @@ -23,10 +23,12 @@ from gui.bitmapLoader import BitmapLoader from gui.utils.numberFormatter import formatAmount import gui.mainFrame import gui.builtinStatsViews.resistancesViewFull as rvf -import service +from service.fit import Fit + class RechargeViewFull(StatsView): name = "rechargeViewFull" + def __init__(self, parent): StatsView.__init__(self) self.parent = parent @@ -38,12 +40,12 @@ class RechargeViewFull(StatsView): return "Recharge rates" def getTextExtentW(self, text): - width, height = self.parent.GetTextExtent( text ) + width, height = self.parent.GetTextExtent(text) return width def toggleEffective(self, event): self.effective = event.effective - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() self.refreshPanel(sFit.getFit(self.mainFrame.getActiveFit())) event.Skip() @@ -53,21 +55,22 @@ class RechargeViewFull(StatsView): self.panel = contentPanel self.headerPanel = headerPanel sizerTankStats = wx.FlexGridSizer(3, 5) - for i in xrange(4): + for i in range(4): sizerTankStats.AddGrowableCol(i + 1) contentSizer.Add(sizerTankStats, 0, wx.EXPAND, 0) - #Add an empty label first for correct alignment. + # Add an empty label first for correct alignment. sizerTankStats.Add(wx.StaticText(contentPanel, wx.ID_ANY, ""), 0) - toolTipText = {"shieldPassive" : "Passive shield recharge", "shieldActive" : "Active shield boost", "armorActive" : "Armor repair amount", "hullActive" : "Hull repair amount"} + toolTipText = {"shieldPassive": "Passive shield recharge", "shieldActive": "Active shield boost", + "armorActive": "Armor repair amount", "hullActive": "Hull repair amount"} for tankType in ("shieldPassive", "shieldActive", "armorActive", "hullActive"): bitmap = BitmapLoader.getStaticBitmap("%s_big" % tankType, contentPanel, "gui") tooltip = wx.ToolTip(toolTipText[tankType]) bitmap.SetToolTip(tooltip) sizerTankStats.Add(bitmap, 0, wx.ALIGN_CENTER) - toolTipText = {"reinforced" : "Reinforced", "sustained" : "Sustained"} + toolTipText = {"reinforced": "Reinforced", "sustained": "Sustained"} for stability in ("reinforced", "sustained"): bitmap = BitmapLoader.getStaticBitmap("regen%s_big" % stability.capitalize(), contentPanel, "gui") tooltip = wx.ToolTip(toolTipText[stability]) @@ -79,7 +82,7 @@ class RechargeViewFull(StatsView): continue tankTypeCap = tankType[0].capitalize() + tankType[1:] - lbl = wx.StaticText(contentPanel, wx.ID_ANY, "0.0", style = wx.ALIGN_RIGHT) + lbl = wx.StaticText(contentPanel, wx.ID_ANY, "0.0", style=wx.ALIGN_RIGHT) setattr(self, "labelTank%s%s" % (stability.capitalize(), tankTypeCap), lbl) box = wx.BoxSizer(wx.HORIZONTAL) @@ -91,12 +94,12 @@ class RechargeViewFull(StatsView): contentPanel.Layout() def refreshPanel(self, fit): - #If we did anything intresting, we'd update our labels to reflect the new fit's stats here + # If we did anything intresting, we'd update our labels to reflect the new fit's stats here for stability in ("reinforced", "sustained"): - if stability == "reinforced" and fit != None: + if stability == "reinforced" and fit is not None: tank = fit.effectiveTank if self.effective else fit.tank - elif stability == "sustained" and fit != None: + elif stability == "sustained" and fit is not None: tank = fit.effectiveSustainableTank if self.effective else fit.sustainableTank else: tank = None @@ -122,4 +125,5 @@ class RechargeViewFull(StatsView): self.panel.Layout() self.headerPanel.Layout() + RechargeViewFull.register() diff --git a/gui/builtinStatsViews/resistancesViewFull.py b/gui/builtinStatsViews/resistancesViewFull.py index 55daa813d..16f8cb5a5 100644 --- a/gui/builtinStatsViews/resistancesViewFull.py +++ b/gui/builtinStatsViews/resistancesViewFull.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,23 +15,22 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx from gui.statsView import StatsView -from gui import builtinStatsViews from gui.bitmapLoader import BitmapLoader from gui import pygauge as PG from gui.utils.numberFormatter import formatAmount -import service import gui.mainFrame -import gui.builtinViews.fittingView as fv import gui.globalEvents as GE EffectiveHpToggled, EFFECTIVE_HP_TOGGLED = wx.lib.newevent.NewEvent() + class ResistancesViewFull(StatsView): name = "resistancesViewFull" + def __init__(self, parent): StatsView.__init__(self) self.parent = parent @@ -45,7 +44,7 @@ class ResistancesViewFull(StatsView): return "Resistances" def getTextExtentW(self, text): - width, height = self.parent.GetTextExtent( text ) + width, height = self.parent.GetTextExtent(text) return width def populatePanel(self, contentPanel, headerPanel): @@ -56,7 +55,7 @@ class ResistancesViewFull(StatsView): # Custom header EHP headerContentSizer = wx.BoxSizer(wx.HORIZONTAL) hsizer = headerPanel.GetSizer() - hsizer.Add(headerContentSizer,0,0,0) + hsizer.Add(headerContentSizer, 0, 0, 0) self.stEff = wx.StaticText(headerPanel, wx.ID_ANY, "( Effective HP: ") headerContentSizer.Add(self.stEff) headerPanel.GetParent().AddToggleItem(self.stEff) @@ -67,81 +66,83 @@ class ResistancesViewFull(StatsView): stCls = wx.StaticText(headerPanel, wx.ID_ANY, " )") - headerPanel.GetParent().AddToggleItem( stCls ) - headerContentSizer.Add( stCls ) -# headerContentSizer.Add(wx.StaticLine(headerPanel, wx.ID_ANY), 1, wx.ALIGN_CENTER) + headerPanel.GetParent().AddToggleItem(stCls) + headerContentSizer.Add(stCls) + # headerContentSizer.Add(wx.StaticLine(headerPanel, wx.ID_ANY), 1, wx.ALIGN_CENTER) # Display table col = 0 row = 0 sizerResistances = wx.GridBagSizer() - contentSizer.Add( sizerResistances, 0, wx.EXPAND , 0) + contentSizer.Add(sizerResistances, 0, wx.EXPAND, 0) # Add an empty label, then the rest. - sizerResistances.Add(wx.StaticText(contentPanel, wx.ID_ANY), wx.GBPosition( row, col ), wx.GBSpan( 1, 1 )) - col+=1 - toolTipText = {"em" : "Electromagnetic resistance", "thermal" : "Thermal resistance", "kinetic" : "Kinetic resistance", "explosive" : "Explosive resistance"} + sizerResistances.Add(wx.StaticText(contentPanel, wx.ID_ANY), wx.GBPosition(row, col), wx.GBSpan(1, 1)) + col += 1 + toolTipText = {"em": "Electromagnetic resistance", "thermal": "Thermal resistance", + "kinetic": "Kinetic resistance", "explosive": "Explosive resistance"} for damageType in ("em", "thermal", "kinetic", "explosive"): bitmap = BitmapLoader.getStaticBitmap("%s_big" % damageType, contentPanel, "gui") tooltip = wx.ToolTip(toolTipText[damageType]) bitmap.SetToolTip(tooltip) - sizerResistances.Add(bitmap, wx.GBPosition( row, col ), wx.GBSpan( 1, 1 ), wx.ALIGN_CENTER) - col+=1 - self.stEHPs = wx.Button(contentPanel, style = wx.BU_EXACTFIT, label = "EHP") + sizerResistances.Add(bitmap, wx.GBPosition(row, col), wx.GBSpan(1, 1), wx.ALIGN_CENTER) + col += 1 + self.stEHPs = wx.Button(contentPanel, style=wx.BU_EXACTFIT, label="EHP") self.stEHPs.SetToolTip(wx.ToolTip("Click to toggle between effective HP and raw HP")) self.stEHPs.Bind(wx.EVT_BUTTON, self.toggleEHP) for i in xrange(4): - sizerResistances.AddGrowableCol(i+1) + sizerResistances.AddGrowableCol(i + 1) - sizerResistances.Add(self.stEHPs, wx.GBPosition( row, col ), wx.GBSpan( 1, 1 ), wx.ALIGN_CENTER) - col=0 - row+=1 + sizerResistances.Add(self.stEHPs, wx.GBPosition(row, col), wx.GBSpan(1, 1), wx.ALIGN_CENTER) + col = 0 + row += 1 - gaugeColours=( ((38,133,198),(52,86,98)), ((198,38,38),(83,65,67)), ((163,163,163),(74,90,93)), ((198,133,38),(81,83,67)) ) + gaugeColours = (((38, 133, 198), (52, 86, 98)), ((198, 38, 38), (83, 65, 67)), ((163, 163, 163), (74, 90, 93)), + ((198, 133, 38), (81, 83, 67))) - toolTipText = {"shield" : "Shield resistance", "armor" : "Armor resistance", "hull" : "Hull resistance", "damagePattern" : "Incoming damage pattern"} + toolTipText = {"shield": "Shield resistance", "armor": "Armor resistance", "hull": "Hull resistance", + "damagePattern": "Incoming damage pattern"} for tankType in ("shield", "armor", "hull", "separator", "damagePattern"): if tankType != "separator": bitmap = BitmapLoader.getStaticBitmap("%s_big" % tankType, contentPanel, "gui") tooltip = wx.ToolTip(toolTipText[tankType]) bitmap.SetToolTip(tooltip) - sizerResistances.Add(bitmap, wx.GBPosition( row, col ), wx.GBSpan( 1, 1 ), wx.ALIGN_CENTER) - col+=1 + sizerResistances.Add(bitmap, wx.GBPosition(row, col), wx.GBSpan(1, 1), wx.ALIGN_CENTER) + col += 1 else: - sizerResistances.Add(wx.StaticLine(contentPanel, wx.ID_ANY), wx.GBPosition( row, col ), wx.GBSpan( 1, 6 ), wx.EXPAND|wx.ALIGN_CENTER) - row+=1 - col=0 + sizerResistances.Add(wx.StaticLine(contentPanel, wx.ID_ANY), wx.GBPosition(row, col), wx.GBSpan(1, 6), + wx.EXPAND | wx.ALIGN_CENTER) + row += 1 + col = 0 continue - currGColour=0 + currGColour = 0 for damageType in ("em", "thermal", "kinetic", "explosive"): - box = wx.BoxSizer(wx.HORIZONTAL) - sizerResistances.Add(box, wx.GBPosition( row, col ), wx.GBSpan( 1, 1 ), wx.ALIGN_CENTER) + sizerResistances.Add(box, wx.GBPosition(row, col), wx.GBSpan(1, 1), wx.ALIGN_CENTER) + # Fancy gauges addon - #Fancy gauges addon - - pgColour= gaugeColours[currGColour] + pgColour = gaugeColours[currGColour] fc = pgColour[0] bc = pgColour[1] - currGColour+=1 + currGColour += 1 lbl = PG.PyGauge(contentPanel, wx.ID_ANY, 100) lbl.SetMinSize((48, 16)) - lbl.SetBackgroundColour(wx.Colour(bc[0],bc[1],bc[2])) - lbl.SetBarColour(wx.Colour(fc[0],fc[1],fc[2])) + lbl.SetBackgroundColour(wx.Colour(bc[0], bc[1], bc[2])) + lbl.SetBarColour(wx.Colour(fc[0], fc[1], fc[2])) lbl.SetBarGradient() lbl.SetFractionDigits(1) setattr(self, "gaugeResistance%s%s" % (tankType.capitalize(), damageType.capitalize()), lbl) box.Add(lbl, 0, wx.ALIGN_CENTER) - col+=1 + col += 1 box = wx.BoxSizer(wx.VERTICAL) box.SetMinSize(wx.Size(self.getTextExtentW("WWWWk"), -1)) @@ -149,9 +150,9 @@ class ResistancesViewFull(StatsView): box.Add(lbl, 0, wx.ALIGN_CENTER) setattr(self, "labelResistance%sEhp" % tankType.capitalize(), lbl) - sizerResistances.Add(box, wx.GBPosition( row, col ), wx.GBSpan( 1, 1 ), wx.ALIGN_CENTER) - row+=1 - col=0 + sizerResistances.Add(box, wx.GBPosition(row, col), wx.GBSpan(1, 1), wx.ALIGN_CENTER) + row += 1 + col = 0 self.stEHPs.SetToolTip(wx.ToolTip("Click to toggle between effective HP and raw HP")) @@ -163,7 +164,7 @@ class ResistancesViewFull(StatsView): wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit())) def refreshPanel(self, fit): - #If we did anything intresting, we'd update our labels to reflect the new fit's stats here + # If we did anything intresting, we'd update our labels to reflect the new fit's stats here if fit is None and not self.showEffective: self.showEffective = True wx.PostEvent(self.mainFrame, EffectiveHpToggled(effective=True)) @@ -194,11 +195,11 @@ class ResistancesViewFull(StatsView): total += ehp[tankType] rrFactor = fit.ehp[tankType] / fit.hp[tankType] lbl.SetLabel(formatAmount(ehp[tankType], 3, 0, 9)) - lbl.SetToolTip(wx.ToolTip("%s: %d\nResist Multiplier: x%.2f" % (tankType.capitalize(), ehp[tankType], rrFactor))) + lbl.SetToolTip( + wx.ToolTip("%s: %d\nResist Multiplier: x%.2f" % (tankType.capitalize(), ehp[tankType], rrFactor))) else: lbl.SetLabel("0") - self.labelEhp.SetLabel("%s" % formatAmount(total, 3, 0, 9)) if self.showEffective: self.stEff.SetLabel("( Effective HP: ") @@ -207,10 +208,9 @@ class ResistancesViewFull(StatsView): self.stEff.SetLabel("( Raw HP: ") self.labelEhp.SetToolTip(wx.ToolTip("Raw: %d HP" % total)) - - damagePattern = fit.damagePattern if fit is not None and self.showEffective else None + damagePattern = fit.damagePattern if fit is not None and self.showEffective else None total = sum((damagePattern.emAmount, damagePattern.thermalAmount, - damagePattern.kineticAmount, damagePattern.explosiveAmount)) if damagePattern is not None else 0 + damagePattern.kineticAmount, damagePattern.explosiveAmount)) if damagePattern is not None else 0 for damageType in ("em", "thermal", "kinetic", "explosive"): lbl = getattr(self, "gaugeResistanceDamagepattern%s" % damageType.capitalize()) @@ -223,5 +223,5 @@ class ResistancesViewFull(StatsView): self.panel.Layout() self.headerPanel.Layout() -ResistancesViewFull.register() +ResistancesViewFull.register() diff --git a/gui/builtinStatsViews/resourcesViewFull.py b/gui/builtinStatsViews/resourcesViewFull.py index e0ac0da52..39bb0b62a 100644 --- a/gui/builtinStatsViews/resourcesViewFull.py +++ b/gui/builtinStatsViews/resourcesViewFull.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,11 +15,10 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx from gui.statsView import StatsView -from gui import builtinStatsViews from gui.bitmapLoader import BitmapLoader from gui import pygauge as PG import gui.mainFrame @@ -29,6 +28,7 @@ from eos.types import Hardpoint from gui.utils.numberFormatter import formatAmount + class ResourcesViewFull(StatsView): name = "resourcesViewFull" contexts = ["drone", "fighter", "cargo"] @@ -79,7 +79,7 @@ class ResourcesViewFull(StatsView): return "Resources" def getTextExtentW(self, text): - width, height = self.parent.GetTextExtent( text ) + width, height = self.parent.GetTextExtent(text) return width def populatePanel(self, contentPanel, headerPanel): @@ -99,54 +99,56 @@ class ResourcesViewFull(StatsView): self.headerPanel = headerPanel panel = "full" - base = sizerResources sizer.AddSpacer((0, 0), 1, wx.EXPAND, 5) - #Turrets & launcher hardslots display - tooltipText = {"turret":"Turret hardpoints", "launcher":"Launcher hardpoints", "drones":"Drones active", "fighter": "Fighter squadrons active", "calibration":"Calibration"} - for type in ("turret", "launcher", "drones", "fighter", "calibration"): + # Turrets & launcher hardslots display + tooltipText = {"turret": "Turret hardpoints", "launcher": "Launcher hardpoints", "drones": "Drones active", + "fighter": "Fighter squadrons active", "calibration": "Calibration"} + for type_ in ("turret", "launcher", "drones", "fighter", "calibration"): box = wx.BoxSizer(wx.HORIZONTAL) - bitmap = BitmapLoader.getStaticBitmap("%s_big" % type, parent, "gui") - tooltip = wx.ToolTip(tooltipText[type]) + bitmap = BitmapLoader.getStaticBitmap("%s_big" % type_, parent, "gui") + tooltip = wx.ToolTip(tooltipText[type_]) bitmap.SetToolTip(tooltip) box.Add(bitmap, 0, wx.ALIGN_CENTER) sizer.Add(box, 0, wx.ALIGN_CENTER) - suffix = {'turret':'Hardpoints', 'launcher':'Hardpoints', 'drones':'Active', 'fighter':'Tubes', 'calibration':'Points'} + suffix = {'turret': 'Hardpoints', 'launcher': 'Hardpoints', 'drones': 'Active', 'fighter': 'Tubes', + 'calibration': 'Points'} lbl = wx.StaticText(parent, wx.ID_ANY, "0") - setattr(self, "label%sUsed%s%s" % (panel.capitalize(), type.capitalize(), suffix[type].capitalize()), lbl) + setattr(self, "label%sUsed%s%s" % (panel.capitalize(), type_.capitalize(), suffix[type_].capitalize()), lbl) box.Add(lbl, 0, wx.ALIGN_CENTER | wx.LEFT, 5) box.Add(wx.StaticText(parent, wx.ID_ANY, "/"), 0, wx.ALIGN_CENTER) lbl = wx.StaticText(parent, wx.ID_ANY, "0") - setattr(self, "label%sTotal%s%s" % (panel.capitalize(), type.capitalize(), suffix[type].capitalize()), lbl) + setattr(self, "label%sTotal%s%s" % (panel.capitalize(), type_.capitalize(), suffix[type_].capitalize()), + lbl) box.Add(lbl, 0, wx.ALIGN_CENTER) - setattr(self, "boxSizer{}".format(type.capitalize()), box) + setattr(self, "boxSizer{}".format(type_.capitalize()), box) # Hack - We add a spacer after each thing, but we are always hiding something. The spacer is stil there. # This way, we only have one space after the drones/fighters - if type != "drones": + if type_ != "drones": sizer.AddSpacer((0, 0), 1, wx.EXPAND, 5) - - #PG, Cpu & drone stuff - tooltipText = {"cpu":"CPU", "pg":"PowerGrid", "droneBay":"Drone bay", "fighterBay": "Fighter bay", "droneBandwidth":"Drone bandwidth", "cargoBay":"Cargo bay"} + # PG, Cpu & drone stuff + tooltipText = {"cpu": "CPU", "pg": "PowerGrid", "droneBay": "Drone bay", "fighterBay": "Fighter bay", + "droneBandwidth": "Drone bandwidth", "cargoBay": "Cargo bay"} for i, group in enumerate((("cpu", "pg"), ("cargoBay", "droneBay", "fighterBay", "droneBandwidth"))): main = wx.BoxSizer(wx.VERTICAL) - base.Add(main, 1 , wx.ALIGN_CENTER) + base.Add(main, 1, wx.ALIGN_CENTER) - for type in group: - capitalizedType = type[0].capitalize() + type[1:] - bitmap = BitmapLoader.getStaticBitmap(type + "_big", parent, "gui") - tooltip = wx.ToolTip(tooltipText[type]) + for type_ in group: + capitalizedType = type_[0].capitalize() + type_[1:] + bitmap = BitmapLoader.getStaticBitmap(type_ + "_big", parent, "gui") + tooltip = wx.ToolTip(tooltipText[type_]) bitmap.SetToolTip(tooltip) stats = wx.BoxSizer(wx.VERTICAL) - absolute = wx.BoxSizer(wx.HORIZONTAL) + absolute = wx.BoxSizer(wx.HORIZONTAL) stats.Add(absolute, 0, wx.EXPAND) b = wx.BoxSizer(wx.HORIZONTAL) @@ -166,8 +168,9 @@ class ResourcesViewFull(StatsView): setattr(self, "label%sTotal%s" % (panel.capitalize(), capitalizedType), lbl) absolute.Add(lbl, 0, wx.ALIGN_LEFT) - units = {"cpu":" tf", "pg":" MW", "droneBandwidth":" mbit/s", "droneBay":u" m\u00B3", "fighterBay":u" m\u00B3", "cargoBay":u" m\u00B3"} - lbl = wx.StaticText(parent, wx.ID_ANY, "%s" % units[type]) + units = {"cpu": " tf", "pg": " MW", "droneBandwidth": " mbit/s", "droneBay": u" m\u00B3", + "fighterBay": u" m\u00B3", "cargoBay": u" m\u00B3"} + lbl = wx.StaticText(parent, wx.ID_ANY, "%s" % units[type_]) absolute.Add(lbl, 0, wx.ALIGN_LEFT) # Gauges modif. - Darriele @@ -177,7 +180,7 @@ class ResourcesViewFull(StatsView): gauge.SetMinSize((self.getTextExtentW("1.999M/1.99M MW"), 23)) gauge.SetFractionDigits(2) - setattr(self, "gauge%s%s" % (panel.capitalize(),capitalizedType), gauge) + setattr(self, "gauge%s%s" % (panel.capitalize(), capitalizedType), gauge) stats.Add(gauge, 0, wx.ALIGN_CENTER) setattr(self, "base%s%s" % (panel.capitalize(), capitalizedType), b) @@ -186,30 +189,32 @@ class ResourcesViewFull(StatsView): self.toggleContext("drone") def refreshPanel(self, fit): - #If we did anything intresting, we'd update our labels to reflect the new fit's stats here + # If we did anything intresting, we'd update our labels to reflect the new fit's stats here - stats = (("label%sUsedTurretHardpoints", lambda: fit.getHardpointsUsed(Hardpoint.TURRET), 0, 0, 0), - ("label%sTotalTurretHardpoints", lambda: fit.ship.getModifiedItemAttr('turretSlotsLeft'), 0, 0, 0), - ("label%sUsedLauncherHardpoints", lambda: fit.getHardpointsUsed(Hardpoint.MISSILE), 0, 0, 0), - ("label%sTotalLauncherHardpoints", lambda: fit.ship.getModifiedItemAttr('launcherSlotsLeft'), 0, 0, 0), - ("label%sUsedDronesActive", lambda: fit.activeDrones, 0, 0, 0), - ("label%sTotalDronesActive", lambda: fit.extraAttributes["maxActiveDrones"], 0, 0, 0), - ("label%sUsedFighterTubes", lambda: fit.fighterTubesUsed, 3, 0, 9), - ("label%sTotalFighterTubes", lambda: fit.ship.getModifiedItemAttr("fighterTubes"), 3, 0, 9), - ("label%sUsedCalibrationPoints", lambda: fit.calibrationUsed, 0, 0, 0), - ("label%sTotalCalibrationPoints", lambda: fit.ship.getModifiedItemAttr('upgradeCapacity'), 0, 0, 0), - ("label%sUsedPg", lambda: fit.pgUsed, 4, 0, 9), - ("label%sUsedCpu", lambda: fit.cpuUsed, 4, 0, 9), - ("label%sTotalPg", lambda: fit.ship.getModifiedItemAttr("powerOutput"), 4, 0, 9), - ("label%sTotalCpu", lambda: fit.ship.getModifiedItemAttr("cpuOutput"), 4, 0, 9), - ("label%sUsedDroneBay", lambda: fit.droneBayUsed, 3, 0, 9), - ("label%sUsedFighterBay", lambda: fit.fighterBayUsed, 3, 0, 9), - ("label%sUsedDroneBandwidth", lambda: fit.droneBandwidthUsed, 3, 0, 9), - ("label%sTotalDroneBay", lambda: fit.ship.getModifiedItemAttr("droneCapacity"), 3, 0, 9), - ("label%sTotalDroneBandwidth", lambda: fit.ship.getModifiedItemAttr("droneBandwidth"), 3, 0, 9), - ("label%sTotalFighterBay", lambda: fit.ship.getModifiedItemAttr("fighterCapacity"), 3, 0, 9), - ("label%sUsedCargoBay", lambda: fit.cargoBayUsed, 3, 0, 9), - ("label%sTotalCargoBay", lambda: fit.ship.getModifiedItemAttr("capacity"), 3, 0, 9)) + stats = ( + ("label%sUsedTurretHardpoints", lambda: fit.getHardpointsUsed(Hardpoint.TURRET), 0, 0, 0), + ("label%sTotalTurretHardpoints", lambda: fit.ship.getModifiedItemAttr('turretSlotsLeft'), 0, 0, 0), + ("label%sUsedLauncherHardpoints", lambda: fit.getHardpointsUsed(Hardpoint.MISSILE), 0, 0, 0), + ("label%sTotalLauncherHardpoints", lambda: fit.ship.getModifiedItemAttr('launcherSlotsLeft'), 0, 0, 0), + ("label%sUsedDronesActive", lambda: fit.activeDrones, 0, 0, 0), + ("label%sTotalDronesActive", lambda: fit.extraAttributes["maxActiveDrones"], 0, 0, 0), + ("label%sUsedFighterTubes", lambda: fit.fighterTubesUsed, 3, 0, 9), + ("label%sTotalFighterTubes", lambda: fit.ship.getModifiedItemAttr("fighterTubes"), 3, 0, 9), + ("label%sUsedCalibrationPoints", lambda: fit.calibrationUsed, 0, 0, 0), + ("label%sTotalCalibrationPoints", lambda: fit.ship.getModifiedItemAttr('upgradeCapacity'), 0, 0, 0), + ("label%sUsedPg", lambda: fit.pgUsed, 4, 0, 9), + ("label%sUsedCpu", lambda: fit.cpuUsed, 4, 0, 9), + ("label%sTotalPg", lambda: fit.ship.getModifiedItemAttr("powerOutput"), 4, 0, 9), + ("label%sTotalCpu", lambda: fit.ship.getModifiedItemAttr("cpuOutput"), 4, 0, 9), + ("label%sUsedDroneBay", lambda: fit.droneBayUsed, 3, 0, 9), + ("label%sUsedFighterBay", lambda: fit.fighterBayUsed, 3, 0, 9), + ("label%sUsedDroneBandwidth", lambda: fit.droneBandwidthUsed, 3, 0, 9), + ("label%sTotalDroneBay", lambda: fit.ship.getModifiedItemAttr("droneCapacity"), 3, 0, 9), + ("label%sTotalDroneBandwidth", lambda: fit.ship.getModifiedItemAttr("droneBandwidth"), 3, 0, 9), + ("label%sTotalFighterBay", lambda: fit.ship.getModifiedItemAttr("fighterCapacity"), 3, 0, 9), + ("label%sUsedCargoBay", lambda: fit.cargoBayUsed, 3, 0, 9), + ("label%sTotalCargoBay", lambda: fit.ship.getModifiedItemAttr("capacity"), 3, 0, 9), + ) panel = "Full" usedTurretHardpoints = 0 totalTurretHardpoints = 0 @@ -303,12 +308,14 @@ class ResourcesViewFull(StatsView): labelTCP.SetForegroundColour(colorC) if fit is not None: - resMax = (lambda: fit.ship.getModifiedItemAttr("cpuOutput"), - lambda: fit.ship.getModifiedItemAttr("powerOutput"), - lambda: fit.ship.getModifiedItemAttr("droneCapacity"), - lambda: fit.ship.getModifiedItemAttr("fighterCapacity"), - lambda: fit.ship.getModifiedItemAttr("droneBandwidth"), - lambda: fit.ship.getModifiedItemAttr("capacity")) + resMax = ( + lambda: fit.ship.getModifiedItemAttr("cpuOutput"), + lambda: fit.ship.getModifiedItemAttr("powerOutput"), + lambda: fit.ship.getModifiedItemAttr("droneCapacity"), + lambda: fit.ship.getModifiedItemAttr("fighterCapacity"), + lambda: fit.ship.getModifiedItemAttr("droneBandwidth"), + lambda: fit.ship.getModifiedItemAttr("capacity"), + ) i = 0 for resourceType in ("cpu", "pg", "droneBay", "fighterBay", "droneBandwidth", "cargoBay"): @@ -316,11 +323,11 @@ class ResourcesViewFull(StatsView): capitalizedType = resourceType[0].capitalize() + resourceType[1:] gauge = getattr(self, "gauge%s%s" % (panel, capitalizedType)) - resUsed = getattr(fit,"%sUsed" % resourceType) + resUsed = getattr(fit, "%sUsed" % resourceType) gauge.SetValueRange(resUsed or 0, resMax[i]() or 0) - i+=1 + i += 1 else: capitalizedType = resourceType[0].capitalize() + resourceType[1:] @@ -328,9 +335,10 @@ class ResourcesViewFull(StatsView): gauge.SetValueRange(0, 0) - i+=1 + i += 1 self.panel.Layout() self.headerPanel.Layout() + ResourcesViewFull.register() diff --git a/gui/builtinStatsViews/targetingMiscViewFull.py b/gui/builtinStatsViews/targetingMiscViewFull.py index 207fe46c5..aab2bf25e 100644 --- a/gui/builtinStatsViews/targetingMiscViewFull.py +++ b/gui/builtinStatsViews/targetingMiscViewFull.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,29 +15,31 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx from gui.statsView import StatsView -from gui import builtinStatsViews from gui.utils.numberFormatter import formatAmount -import locale + try: from collections import OrderedDict except ImportError: from utils.compat import OrderedDict + class TargetingMiscViewFull(StatsView): name = "targetingmiscViewFull" + def __init__(self, parent): StatsView.__init__(self) self.parent = parent self._cachedValues = [] + def getHeaderText(self, fit): return "Targeting && Misc" def getTextExtentW(self, text): - width, height = self.parent.GetTextExtent( text ) + width, height = self.parent.GetTextExtent(text) return width def populatePanel(self, contentPanel, headerPanel): @@ -46,7 +48,7 @@ class TargetingMiscViewFull(StatsView): self.panel = contentPanel self.headerPanel = headerPanel gridTargetingMisc = wx.FlexGridSizer(1, 3) - contentSizer.Add( gridTargetingMisc, 0, wx.EXPAND | wx.ALL, 0) + contentSizer.Add(gridTargetingMisc, 0, wx.EXPAND | wx.ALL, 0) gridTargetingMisc.AddGrowableCol(0) gridTargetingMisc.AddGrowableCol(2) # Targeting @@ -68,17 +70,17 @@ class TargetingMiscViewFull(StatsView): box = wx.BoxSizer(wx.HORIZONTAL) gridTargeting.Add(box, 0, wx.ALIGN_LEFT) - lbl = wx.StaticText(contentPanel, wx.ID_ANY, "0 %s" %unit) + lbl = wx.StaticText(contentPanel, wx.ID_ANY, "0 %s" % unit) setattr(self, "label%s" % labelShort, lbl) box.Add(lbl, 0, wx.ALIGN_LEFT) self._cachedValues.append({"main": 0}) # Misc - gridTargetingMisc.Add( wx.StaticLine( contentPanel, wx.ID_ANY, style = wx.VERTICAL),0, wx.EXPAND, 3 ) + gridTargetingMisc.Add(wx.StaticLine(contentPanel, wx.ID_ANY, style=wx.VERTICAL), 0, wx.EXPAND, 3) gridMisc = wx.FlexGridSizer(5, 2) gridMisc.AddGrowableCol(1) - gridTargetingMisc.Add(gridMisc,0 , wx.ALIGN_LEFT | wx.ALL, 5) + gridTargetingMisc.Add(gridMisc, 0, wx.ALIGN_LEFT | wx.ALL, 5) labels = (("Speed", "Speed", "m/s"), ("Align time", "AlignTime", "s"), @@ -98,9 +100,8 @@ class TargetingMiscViewFull(StatsView): self._cachedValues.append({"main": 0}) - def refreshPanel(self, fit): - #If we did anything interesting, we'd update our labels to reflect the new fit's stats here + # If we did anything interesting, we'd update our labels to reflect the new fit's stats here cargoNamesOrder = OrderedDict(( ("fleetHangarCapacity", "Fleet hangar"), @@ -132,14 +133,17 @@ class TargetingMiscViewFull(StatsView): "specialSmallShipHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialSmallShipHoldCapacity"), "specialMediumShipHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialMediumShipHoldCapacity"), "specialLargeShipHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialLargeShipHoldCapacity"), - "specialIndustrialShipHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialIndustrialShipHoldCapacity"), + "specialIndustrialShipHoldCapacity": lambda: fit.ship.getModifiedItemAttr( + "specialIndustrialShipHoldCapacity"), "specialOreHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialOreHoldCapacity"), "specialMineralHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialMineralHoldCapacity"), "specialMaterialBayCapacity": lambda: fit.ship.getModifiedItemAttr("specialMaterialBayCapacity"), "specialGasHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialGasHoldCapacity"), "specialSalvageHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialSalvageHoldCapacity"), - "specialCommandCenterHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialCommandCenterHoldCapacity"), - "specialPlanetaryCommoditiesHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialPlanetaryCommoditiesHoldCapacity"), + "specialCommandCenterHoldCapacity": lambda: fit.ship.getModifiedItemAttr( + "specialCommandCenterHoldCapacity"), + "specialPlanetaryCommoditiesHoldCapacity": lambda: fit.ship.getModifiedItemAttr( + "specialPlanetaryCommoditiesHoldCapacity"), "specialQuafeHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialQuafeHoldCapacity") } @@ -155,9 +159,9 @@ class TargetingMiscViewFull(StatsView): ("labelFullCargo", cargoValues, 4, 0, 9, u"m\u00B3")) counter = 0 - RADII = [("Pod",25), ("Interceptor",33), ("Frigate",38), + RADII = [("Pod", 25), ("Interceptor", 33), ("Frigate", 38), ("Destroyer", 83), ("Cruiser", 130), - ("Battlecruiser", 265), ("Battleship",420), + ("Battlecruiser", 265), ("Battleship", 420), ("Carrier", 3000)] for labelName, valueDict, prec, lowest, highest, unit in stats: label = getattr(self, labelName) @@ -173,13 +177,13 @@ class TargetingMiscViewFull(StatsView): # Get sum of all cargoholds except for maintenance bay additionalCargo = sum(otherValues.values()) if additionalCargo > 0: - label.SetLabel("%s+%s %s" %(formatAmount(mainValue, prec, lowest, highest), - formatAmount(additionalCargo, prec, lowest, highest), - unit)) + label.SetLabel("%s+%s %s" % (formatAmount(mainValue, prec, lowest, highest), + formatAmount(additionalCargo, prec, lowest, highest), + unit)) else: - label.SetLabel("%s %s" %(formatAmount(mainValue, prec, lowest, highest), unit)) + label.SetLabel("%s %s" % (formatAmount(mainValue, prec, lowest, highest), unit)) else: - label.SetLabel("%s %s" %(formatAmount(mainValue, prec, lowest, highest), unit)) + label.SetLabel("%s %s" % (formatAmount(mainValue, prec, lowest, highest), unit)) # Tooltip stuff if fit: if labelName == "labelScanRes": @@ -187,25 +191,27 @@ class TargetingMiscViewFull(StatsView): for size, radius in RADII: left = "%.1fs" % fit.calculateLockTime(radius) right = "%s [%d]" % (size, radius) - lockTime += "%5s\t%s\n" % (left,right) + lockTime += "%5s\t%s\n" % (left, right) label.SetToolTip(wx.ToolTip(lockTime)) elif labelName == "labelFullSigRadius": - label.SetToolTip(wx.ToolTip("Probe Size: %.3f" % (fit.probeSize or 0) )) + label.SetToolTip(wx.ToolTip("Probe Size: %.3f" % (fit.probeSize or 0))) elif labelName == "labelFullWarpSpeed": label.SetToolTip(wx.ToolTip("Max Warp Distance: %.1f AU" % fit.maxWarpDistance)) elif labelName == "labelSensorStr": if fit.jamChance > 0: - label.SetToolTip(wx.ToolTip("Type: %s\n%.1f%% Chance of Jam" % (fit.scanType, fit.jamChance))) + label.SetToolTip( + wx.ToolTip("Type: %s\n%.1f%% Chance of Jam" % (fit.scanType, fit.jamChance))) else: - label.SetToolTip(wx.ToolTip("Type: %s" % (fit.scanType))) + label.SetToolTip(wx.ToolTip("Type: %s" % (fit.scanType))) elif labelName == "labelFullAlignTime": - alignTime = "Align:\t%.3fs"%mainValue + alignTime = "Align:\t%.3fs" % mainValue mass = 'Mass:\t{:,.0f}kg'.format(fit.ship.getModifiedItemAttr("mass")) - agility = "Agility:\t%.3fx"%(fit.ship.getModifiedItemAttr("agility") or 0) + agility = "Agility:\t%.3fx" % (fit.ship.getModifiedItemAttr("agility") or 0) label.SetToolTip(wx.ToolTip("%s\n%s\n%s" % (alignTime, mass, agility))) elif labelName == "labelFullCargo": tipLines = [] - tipLines.append(u"Cargohold: {:,.2f}m\u00B3 / {:,.2f}m\u00B3".format(fit.cargoBayUsed, newValues["main"])) + tipLines.append( + u"Cargohold: {:,.2f}m\u00B3 / {:,.2f}m\u00B3".format(fit.cargoBayUsed, newValues["main"])) for attrName, tipAlias in cargoNamesOrder.items(): if newValues[attrName] > 0: tipLines.append(u"{}: {:,.2f}m\u00B3".format(tipAlias, newValues[attrName])) @@ -234,7 +240,8 @@ class TargetingMiscViewFull(StatsView): # if you add stuff to cargo, the capacity doesn't change and thus it is still cached # This assures us that we force refresh of cargo tooltip tipLines = [] - tipLines.append(u"Cargohold: {:,.2f}m\u00B3 / {:,.2f}m\u00B3".format(fit.cargoBayUsed, cachedCargo["main"])) + tipLines.append( + u"Cargohold: {:,.2f}m\u00B3 / {:,.2f}m\u00B3".format(fit.cargoBayUsed, cachedCargo["main"])) for attrName, tipAlias in cargoNamesOrder.items(): if cachedCargo[attrName] > 0: tipLines.append(u"{}: {:,.2f}m\u00B3".format(tipAlias, cachedCargo[attrName])) @@ -247,4 +254,5 @@ class TargetingMiscViewFull(StatsView): self.panel.Layout() self.headerPanel.Layout() + TargetingMiscViewFull.register() diff --git a/gui/builtinViewColumns/abilities.py b/gui/builtinViewColumns/abilities.py index f61557446..e42a2eed3 100644 --- a/gui/builtinViewColumns/abilities.py +++ b/gui/builtinViewColumns/abilities.py @@ -1,5 +1,4 @@ -# -*- coding: utf-8 -*- -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -16,17 +15,18 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= -from gui.viewColumn import ViewColumn -import gui.mainFrame import wx from eos.types import Fighter +from gui.viewColumn import ViewColumn +import gui.mainFrame class Abilities(ViewColumn): name = "Fighter Abilities" + def __init__(self, fittingView, params): ViewColumn.__init__(self, fittingView) @@ -41,4 +41,5 @@ class Abilities(ViewColumn): return "None" return ", ".join(active) + Abilities.register() diff --git a/gui/builtinViewColumns/ammo.py b/gui/builtinViewColumns/ammo.py index 698e8595b..27a742bce 100644 --- a/gui/builtinViewColumns/ammo.py +++ b/gui/builtinViewColumns/ammo.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,17 +15,17 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= -from gui import builtinViewColumns -from gui.viewColumn import ViewColumn -from gui.bitmapLoader import BitmapLoader import wx from eos.types import Fighter +from gui.viewColumn import ViewColumn +from gui.bitmapLoader import BitmapLoader class Ammo(ViewColumn): name = "Ammo" + def __init__(self, fittingView, params): ViewColumn.__init__(self, fittingView) self.mask = wx.LIST_MASK_IMAGE @@ -43,7 +43,7 @@ class Ammo(ViewColumn): charges = stuff.numCharges if charges > 0: cycles = stuff.numShots - if cycles !=0 and charges != cycles: + if cycles != 0 and charges != cycles: return "%s (%d, %d cycles)" % (stuff.charge.name, charges, cycles) else: return "%s (%d)" % (stuff.charge.name, charges) @@ -54,5 +54,5 @@ class Ammo(ViewColumn): def getImageId(self, mod): return -1 -Ammo.register() +Ammo.register() diff --git a/gui/builtinViewColumns/ammoIcon.py b/gui/builtinViewColumns/ammoIcon.py index 2403077bd..1dc6906e3 100644 --- a/gui/builtinViewColumns/ammoIcon.py +++ b/gui/builtinViewColumns/ammoIcon.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,16 +15,16 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= -from gui import builtinViewColumns from gui.viewColumn import ViewColumn -from gui.bitmapLoader import BitmapLoader import wx from eos.types import Module + class AmmoIcon(ViewColumn): name = "Ammo Icon" + def __init__(self, fittingView, params): ViewColumn.__init__(self, fittingView) self.size = 24 @@ -52,4 +52,5 @@ class AmmoIcon(ViewColumn): if isinstance(mod, Module) and mod.charge is not None: return mod.charge.name + AmmoIcon.register() diff --git a/gui/builtinViewColumns/attributeDisplay.py b/gui/builtinViewColumns/attributeDisplay.py index 47d9aa043..26994a956 100644 --- a/gui/builtinViewColumns/attributeDisplay.py +++ b/gui/builtinViewColumns/attributeDisplay.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,21 +15,24 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= + +import wx -from gui import builtinViewColumns from gui.viewColumn import ViewColumn from gui.bitmapLoader import BitmapLoader from gui.utils.numberFormatter import formatAmount -import service -import wx +from service.attribute import Attribute +from service.market import Market + class AttributeDisplay(ViewColumn): name = "attr" + def __init__(self, fittingView, params): ViewColumn.__init__(self, fittingView) - sAttr = service.Attribute.getInstance() + sAttr = Attribute.getInstance() info = sAttr.getAttributeInfo(params["attribute"]) self.info = info if params["showIcon"]: @@ -57,9 +60,10 @@ class AttributeDisplay(ViewColumn): self.direct = True self.view = fittingView originalRefresh = fittingView.refresh - sMkt = service.Market.getInstance() - #Hack into our master view and add a callback for ourselves to know when to query + sMkt = Market.getInstance() + def refresh(stuff): + # Hack into our master view and add a callback for ourselves to know when to query self.directInfo = sMkt.directAttrRequest(stuff, info) if stuff else None originalRefresh(stuff) @@ -76,10 +80,10 @@ class AttributeDisplay(ViewColumn): attr = mod.getAttribute(self.info.name) if self.info.name == "volume": - str = (formatAmount(attr, 3, 0, 3)) + str_ = (formatAmount(attr, 3, 0, 3)) if hasattr(mod, "amount"): - str = str + u"m\u00B3 (%s m\u00B3)"%(formatAmount(attr*mod.amount, 3, 0, 3)) - attr = str + str_ = str_ + u"m\u00B3 (%s m\u00B3)" % (formatAmount(attr * mod.amount, 3, 0, 3)) + attr = str_ if isinstance(attr, (float, int)): attr = (formatAmount(attr, 3, 0, 3)) @@ -102,4 +106,5 @@ class AttributeDisplay(ViewColumn): ("showIcon", bool, True), ("direct", bool, False)) + AttributeDisplay.register() diff --git a/gui/builtinViewColumns/baseIcon.py b/gui/builtinViewColumns/baseIcon.py index 868c73a21..7f9b16296 100644 --- a/gui/builtinViewColumns/baseIcon.py +++ b/gui/builtinViewColumns/baseIcon.py @@ -1,44 +1,46 @@ -from gui import builtinViewColumns -from gui.viewColumn import ViewColumn -from gui.bitmapLoader import BitmapLoader -import wx -from eos.types import Drone, Fit, Module, Slot, Rack, Implant - -class BaseIcon(ViewColumn): - name = "Base Icon" - def __init__(self, fittingView, params): - ViewColumn.__init__(self, fittingView) - self.size = 24 - self.maxsize = self.size - self.mask = wx.LIST_MASK_IMAGE - self.columnText = "" - self.shipImage = fittingView.imageList.GetImageIndex("ship_small", "gui") - - def getImageId(self, stuff): - if isinstance(stuff, Drone): - return -1 - if isinstance(stuff, Fit): - return self.shipImage - if isinstance(stuff, Rack): - return -1 - if isinstance(stuff, Implant): - if stuff.character: # if it has a character as it's parent - return self.fittingView.imageList.GetImageIndex("character_small", "gui") - else: - return self.shipImage - if isinstance(stuff, Module): - if stuff.isEmpty: - return self.fittingView.imageList.GetImageIndex("slot_%s_small" % Slot.getName(stuff.slot).lower(), "gui") - else: - return self.loadIconFile(stuff.item.icon.iconFile if stuff.item.icon else "") - - item = getattr(stuff, "item", stuff) - return self.loadIconFile(item.icon.iconFile if item.icon else "") - - def loadIconFile(self, iconFile): - if iconFile: - return self.fittingView.imageList.GetImageIndex(iconFile, "icons") - else: - return -1 - -BaseIcon.register() +import wx +from eos.types import Drone, Fit, Module, Slot, Rack, Implant +from gui.viewColumn import ViewColumn + + +class BaseIcon(ViewColumn): + name = "Base Icon" + + def __init__(self, fittingView, params): + ViewColumn.__init__(self, fittingView) + self.size = 24 + self.maxsize = self.size + self.mask = wx.LIST_MASK_IMAGE + self.columnText = "" + self.shipImage = fittingView.imageList.GetImageIndex("ship_small", "gui") + + def getImageId(self, stuff): + if isinstance(stuff, Drone): + return -1 + elif isinstance(stuff, Fit): + return self.shipImage + elif isinstance(stuff, Rack): + return -1 + elif isinstance(stuff, Implant): + if stuff.character: # if it has a character as it's parent + return self.fittingView.imageList.GetImageIndex("character_small", "gui") + else: + return self.shipImage + elif isinstance(stuff, Module): + if stuff.isEmpty: + return self.fittingView.imageList.GetImageIndex("slot_%s_small" % Slot.getName(stuff.slot).lower(), + "gui") + else: + return self.loadIconFile(stuff.item.icon.iconFile if stuff.item.icon else "") + + item = getattr(stuff, "item", stuff) + return self.loadIconFile(item.icon.iconFile if item.icon else "") + + def loadIconFile(self, iconFile): + if iconFile: + return self.fittingView.imageList.GetImageIndex(iconFile, "icons") + else: + return -1 + + +BaseIcon.register() diff --git a/gui/builtinViewColumns/baseName.py b/gui/builtinViewColumns/baseName.py index 77b4698bd..973219b2c 100644 --- a/gui/builtinViewColumns/baseName.py +++ b/gui/builtinViewColumns/baseName.py @@ -1,5 +1,5 @@ -# -*- coding: utf-8 -*- -#=============================================================================== +# coding: utf-8 +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -16,17 +16,18 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= +import wx +from eos.types import Drone, Cargo, Module, Slot, Rack, Implant, Fighter +from service.fit import Fit from gui.viewColumn import ViewColumn import gui.mainFrame -import wx -from eos.types import Drone, Cargo, Fit, Module, Slot, Rack, Implant, Fighter -import service class BaseName(ViewColumn): name = "Base Name" + def __init__(self, fittingView, params): ViewColumn.__init__(self, fittingView) @@ -39,8 +40,9 @@ class BaseName(ViewColumn): def getText(self, stuff): if isinstance(stuff, Drone): return "%dx %s" % (stuff.amount, stuff.item.name) - if isinstance(stuff, Fighter): - return "%d/%d %s" % (stuff.amountActive, stuff.getModifiedItemAttr("fighterSquadronMaxSize"), stuff.item.name) + elif isinstance(stuff, Fighter): + return "%d/%d %s" % \ + (stuff.amountActive, stuff.getModifiedItemAttr("fighterSquadronMaxSize"), stuff.item.name) elif isinstance(stuff, Cargo): return "%dx %s" % (stuff.amount, stuff.item.name) elif isinstance(stuff, Fit): @@ -51,7 +53,7 @@ class BaseName(ViewColumn): else: return "%s (%s)" % (stuff.name, stuff.ship.item.name) elif isinstance(stuff, Rack): - if service.Fit.getInstance().serviceFittingOptions["rackLabels"]: + if Fit.getInstance().serviceFittingOptions["rackLabels"]: if stuff.slot == Slot.MODE: return u'─ Tactical Mode ─' else: @@ -68,15 +70,16 @@ class BaseName(ViewColumn): else: item = getattr(stuff, "item", stuff) - if service.Fit.getInstance().serviceFittingOptions["showMarketShortcuts"]: + if Fit.getInstance().serviceFittingOptions["showMarketShortcuts"]: marketShortcut = getattr(item, "marketShortcut", None) if marketShortcut: # use unicode subscript to display shortcut value - shortcut = unichr(marketShortcut+8320)+u" " + shortcut = unichr(marketShortcut + 8320) + u" " del item.marketShortcut - return shortcut+item.name + return shortcut + item.name return item.name + BaseName.register() diff --git a/gui/builtinViewColumns/capacitorUse.py b/gui/builtinViewColumns/capacitorUse.py index 4a3407ab9..cc5efa16c 100644 --- a/gui/builtinViewColumns/capacitorUse.py +++ b/gui/builtinViewColumns/capacitorUse.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,25 +15,26 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx -import service +from eos.types import Mode +from service.attribute import Attribute from gui.utils.numberFormatter import formatAmount from gui.viewColumn import ViewColumn from gui.bitmapLoader import BitmapLoader -from eos.types import Mode + class CapacitorUse(ViewColumn): name = "Capacitor Usage" + def __init__(self, fittingView, params): ViewColumn.__init__(self, fittingView) self.mask = wx.LIST_MASK_IMAGE - sAttr = service.Attribute.getInstance() - info = sAttr.getAttributeInfo("capacitorNeed") + Attribute.getInstance().getAttributeInfo("capacitorNeed") self.imageId = fittingView.imageList.GetImageIndex("capacitorRecharge_small", "gui") self.bitmap = BitmapLoader.getBitmap("capacitorRecharge_small", "gui") @@ -53,4 +54,5 @@ class CapacitorUse(ViewColumn): def getToolTip(self, mod): return self.name + CapacitorUse.register() diff --git a/gui/builtinViewColumns/maxRange.py b/gui/builtinViewColumns/maxRange.py index eb8f8d693..ea26d4d67 100644 --- a/gui/builtinViewColumns/maxRange.py +++ b/gui/builtinViewColumns/maxRange.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,25 +15,27 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= -from gui import builtinViewColumns +import wx + +from eos.types import Mode +from service.attribute import Attribute from gui.viewColumn import ViewColumn from gui.bitmapLoader import BitmapLoader -import service from gui.utils.numberFormatter import formatAmount -import wx -from eos.types import Mode + class MaxRange(ViewColumn): name = "Max Range" - def __init__(self, fittingView, params = None): - if params == None: - params = {"showIcon": True, - "displayName": False} + + def __init__(self, fittingView, params=None): + if params is None: + params = {"showIcon": True, "displayName": False} + ViewColumn.__init__(self, fittingView) - sAttr = service.Attribute.getInstance() + sAttr = Attribute.getInstance() info = sAttr.getAttributeInfo("maxRange") self.info = info if params["showIcon"]: @@ -71,10 +73,10 @@ class MaxRange(ViewColumn): return -1 def getParameters(self): - return (("displayName", bool, False), - ("showIcon", bool, True)) + return (("displayName", bool, False), ("showIcon", bool, True)) def getToolTip(self, mod): return "Optimal + Falloff" + MaxRange.register() diff --git a/gui/builtinViewColumns/misc.py b/gui/builtinViewColumns/misc.py index 69e7beebb..080614a3b 100644 --- a/gui/builtinViewColumns/misc.py +++ b/gui/builtinViewColumns/misc.py @@ -1,543 +1,549 @@ -#=============================================================================== -# 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 gui.mainFrame -from gui.viewColumn import ViewColumn -from gui.bitmapLoader import BitmapLoader -from gui.utils.numberFormatter import formatAmount -from gui.utils.listFormatter import formatList -from service.fit import Fit, Market - -import wx - -class Miscellanea(ViewColumn): - name = "Miscellanea" - def __init__(self, fittingView, params = None): - if params == None: - params = {"showIcon": True, - "displayName": False} - ViewColumn.__init__(self, fittingView) - if params["showIcon"]: - self.imageId = fittingView.imageList.GetImageIndex("column_misc", "gui") - self.bitmap = BitmapLoader.getBitmap("column_misc", "gui") - self.mask = wx.LIST_MASK_IMAGE - else: - self.imageId = -1 - - if params["displayName"] or self.imageId == -1: - self.columnText = "Misc data" - self.mask |= wx.LIST_MASK_TEXT - self.mainFrame = gui.mainFrame.MainFrame.getInstance() - - def getText(self, stuff): - text = self.__getData(stuff)[0] - return text - - def getToolTip(self, mod): - text = self.__getData(mod)[1] - return text - - def getImageId(self, mod): - return -1 - - def getParameters(self): - return (("displayName", bool, False), - ("showIcon", bool, True)) - - def __getData(self, stuff): - item = stuff.item - if item is None: - return "", None - itemGroup = item.group.name - itemCategory = item.category.name - - if itemGroup == "Ship Modifiers": - return "", None - elif itemGroup in ("Energy Weapon", "Hybrid Weapon", "Projectile Weapon", "Combat Drone", "Fighter Drone"): - trackingSpeed = stuff.getModifiedItemAttr("trackingSpeed") - if not trackingSpeed: - return "", None - text = "{0}".format(formatAmount(trackingSpeed, 3, 0, 3)) - tooltip = "Tracking speed" - return text, tooltip - elif itemCategory == "Subsystem": - slots = ("hi", "med", "low") - info = [] - for slot in slots: - n = int(stuff.getModifiedItemAttr("%sSlotModifier"%slot)) - if n > 0: - info.append("{0}{1}".format(n, slot[0].upper())) - return "+ "+", ".join(info), "Slot Modifiers" - elif itemGroup == "Energy Neutralizer": - neutAmount = stuff.getModifiedItemAttr("energyNeutralizerAmount") - cycleTime = stuff.cycleTime - if not neutAmount or not cycleTime: - return "", None - capPerSec = float(-neutAmount) * 1000 / cycleTime - text = "{0}/s".format(formatAmount(capPerSec, 3, 0, 3)) - tooltip = "Energy neutralization per second" - return text, tooltip - elif itemGroup == "Energy Nosferatu": - neutAmount = stuff.getModifiedItemAttr("powerTransferAmount") - cycleTime = stuff.cycleTime - if not neutAmount or not cycleTime: - return "", None - capPerSec = float(-neutAmount) * 1000 / cycleTime - text = "{0}/s".format(formatAmount(capPerSec, 3, 0, 3)) - tooltip = "Energy neutralization per second" - return text, tooltip - elif itemGroup == "Salvager": - chance = stuff.getModifiedItemAttr("accessDifficultyBonus") - if not chance: - return "", None - text = "{0}%".format(formatAmount(chance, 3, 0, 3)) - tooltip = "Item retrieval chance" - return text, tooltip - elif itemGroup == "Data Miners": - strength = stuff.getModifiedItemAttr("virusStrength") - coherence = stuff.getModifiedItemAttr("virusCoherence") - if not strength or not coherence: - return "", None - text = "{0} | {1}".format(formatAmount(strength, 3, 0, 3), formatAmount(coherence, 3, 0, 3)) - tooltip = "Virus strength and coherence" - return text, tooltip - elif itemGroup in ("Warp Scrambler", "Warp Core Stabilizer"): - scramStr = stuff.getModifiedItemAttr("warpScrambleStrength") - if not scramStr: - return "", None - text = "{0}".format(formatAmount(-scramStr, 3, 0, 3, forceSign=True)) - tooltip = "Warp core strength modification" - return text, tooltip - elif itemGroup in ("Stasis Web", "Stasis Webifying Drone"): - speedFactor = stuff.getModifiedItemAttr("speedFactor") - if not speedFactor: - return "", None - text = "{0}%".format(formatAmount(speedFactor, 3, 0, 3)) - tooltip = "Speed reduction" - return text, tooltip - elif itemGroup == "Target Painter": - sigRadBonus = stuff.getModifiedItemAttr("signatureRadiusBonus") - if not sigRadBonus: - return "", None - text = "{0}%".format(formatAmount(sigRadBonus, 3, 0, 3, forceSign=True)) - tooltip = "Signature radius increase" - return text, tooltip - elif itemGroup == "Sensor Dampener": - lockRangeBonus = stuff.getModifiedItemAttr("maxTargetRangeBonus") - scanResBonus = stuff.getModifiedItemAttr("scanResolutionBonus") - if lockRangeBonus is None or scanResBonus is None: - return "", None - display = 0 - for bonus in (lockRangeBonus, scanResBonus): - if abs(bonus) > abs(display): - display = bonus - if not display: - return "", None - text = "{0}%".format(formatAmount(display, 3, 0, 3, forceSign=True)) - ttEntries = [] - if display == lockRangeBonus: - ttEntries.append("lock range") - if display == scanResBonus: - ttEntries.append("scan resolution") - tooltip = "{0} dampening".format(formatList(ttEntries)).capitalize() - return text, tooltip - elif itemGroup == "Weapon Disruptor": - # Weapon disruption now covers both tracking and guidance (missile) disruptors - # First get the attributes for tracking disruptors - optimalRangeBonus = stuff.getModifiedItemAttr("maxRangeBonus") - falloffRangeBonus = stuff.getModifiedItemAttr("falloffBonus") - trackingSpeedBonus = stuff.getModifiedItemAttr("trackingSpeedBonus") - - trackingDisruptorAttributes = { - "optimal range": optimalRangeBonus, - "falloff range": falloffRangeBonus, - "tracking speed": trackingSpeedBonus} - - isTrackingDisruptor = any(map(lambda x: x is not None and x != 0, trackingDisruptorAttributes.values())) - - # Then get the attributes for guidance disruptors - explosionVelocityBonus = stuff.getModifiedItemAttr("aoeVelocityBonus") - explosionRadiusBonus = stuff.getModifiedItemAttr("aoeCloudSizeBonus") - - flightTimeBonus = stuff.getModifiedItemAttr("explosionDelayBonus") - missileVelocityBonus = stuff.getModifiedItemAttr("missileVelocityBonus") - - guidanceDisruptorAttributes = { - "explosion velocity": explosionVelocityBonus, - "explosion radius": explosionRadiusBonus, - "flight time": flightTimeBonus, - "missile velocity": missileVelocityBonus} - - isGuidanceDisruptor = any(map(lambda x: x is not None and x != 0, guidanceDisruptorAttributes.values())) - - if isTrackingDisruptor: - attributes = trackingDisruptorAttributes - elif isGuidanceDisruptor: - attributes = guidanceDisruptorAttributes - else: - return "", None - - display = max(attributes.values(), key=lambda x: abs(x)) - - text = "{0}%".format(formatAmount(display, 3, 0, 3, forceSign=True)) - - ttEntries = [] - for attributeName, attributeValue in attributes.items(): - if attributeValue == display: - ttEntries.append(attributeName) - - tooltip = "{0} disruption".format(formatList(ttEntries)).capitalize() - return text, tooltip - elif itemGroup in ("ECM", "Burst Jammer", "Burst Projectors"): - grav = stuff.getModifiedItemAttr("scanGravimetricStrengthBonus") - ladar = stuff.getModifiedItemAttr("scanLadarStrengthBonus") - radar = stuff.getModifiedItemAttr("scanRadarStrengthBonus") - magnet = stuff.getModifiedItemAttr("scanMagnetometricStrengthBonus") - displayMax = max(grav, ladar, radar, magnet) - displayMin = min(grav, ladar, radar, magnet) - if grav is None or ladar is None or radar is None or magnet is None or displayMax is None: - return "", None - - if displayMax == displayMin or displayMin is None: - text = "{0}".format( - formatAmount(displayMax, 3, 0, 3), - ) - else: - text = "{0} | {1}".format( - formatAmount(displayMax, 3, 0, 3), - formatAmount(displayMin, 3, 0, 3), - ) - tooltip = "ECM Jammer Strength:\n{0} Gravimetric | {1} Ladar | {2} Magnetometric | {3} Radar".format( - formatAmount(grav, 3, 0, 3), - formatAmount(ladar, 3, 0, 3), - formatAmount(magnet, 3, 0, 3), - formatAmount(radar, 3, 0, 3), - ) - return text, tooltip - elif itemGroup in ("Remote Sensor Booster", "Sensor Booster", "Signal Amplifier"): - scanResBonus = stuff.getModifiedItemAttr("scanResolutionBonus") - lockRangeBonus = stuff.getModifiedItemAttr("maxTargetRangeBonus") - gravBonus = stuff.getModifiedItemAttr("scanGravimetricStrengthPercent") - if scanResBonus is None or lockRangeBonus is None or gravBonus is None: - return "", None - - text = "{0}% | {1}% | {2}%".format( - formatAmount(scanResBonus, 3, 0, 3), - formatAmount(lockRangeBonus, 3, 0, 3), - formatAmount(gravBonus, 3, 0, 3), - ) - tooltip = "Applied bonuses:\n{0}% scan resolution | {1}% lock range | {2}% sensor strength".format( - formatAmount(scanResBonus, 3, 0, 3), - formatAmount(lockRangeBonus, 3, 0, 3), - formatAmount(gravBonus, 3, 0, 3), - ) - return text, tooltip - elif itemGroup in ("Projected ECCM", "ECCM", "Sensor Backup Array"): - grav = stuff.getModifiedItemAttr("scanGravimetricStrengthPercent") - ladar = stuff.getModifiedItemAttr("scanLadarStrengthPercent") - radar = stuff.getModifiedItemAttr("scanRadarStrengthPercent") - magnet = stuff.getModifiedItemAttr("scanMagnetometricStrengthPercent") - if grav is None or ladar is None or radar is None or magnet is None: - return "", None - display = max(grav, ladar, radar, magnet) - if not display: - return "", None - text = "{0}%".format(formatAmount(display, 3, 0, 3, forceSign=True)) - ttEntries = [] - if display == grav: - ttEntries.append("gravimetric") - if display == ladar: - ttEntries.append("ladar") - if display == magnet: - ttEntries.append("magnetometric") - if display == radar: - ttEntries.append("radar") - plu = "" if len(ttEntries) == 1 else "s" - tooltip = "{0} strength{1} bonus".format(formatList(ttEntries), plu).capitalize() - return text, tooltip - elif itemGroup == "Cloaking Device": - recalibration = stuff.getModifiedItemAttr("cloakingTargetingDelay") - if recalibration is None: - return "", None - text = "{0}s".format(formatAmount(float(recalibration)/1000, 3, 0, 3)) - tooltip = "Sensor recalibration time" - return text, tooltip - elif itemGroup == "Remote Armor Repairer": - repAmount = stuff.getModifiedItemAttr("armorDamageAmount") - cycleTime = stuff.getModifiedItemAttr("duration") - if not repAmount or not cycleTime: - return "", None - repPerSec = float(repAmount) * 1000 / cycleTime - text = "{0}/s".format(formatAmount(repPerSec, 3, 0, 3, forceSign=True)) - tooltip = "Armor repaired per second" - return text, tooltip - elif itemGroup == "Remote Shield Booster": - repAmount = stuff.getModifiedItemAttr("shieldBonus") - cycleTime = stuff.cycleTime - if not repAmount or not cycleTime: - return "", None - repPerSec = float(repAmount) * 1000 / cycleTime - text = "{0}/s".format(formatAmount(repPerSec, 3, 0, 3, forceSign=True)) - tooltip = "Shield transferred per second" - return text, tooltip - elif itemGroup == "Remote Capacitor Transmitter": - repAmount = stuff.getModifiedItemAttr("powerTransferAmount") - cycleTime = stuff.cycleTime - if not repAmount or not cycleTime: - return "", None - repPerSec = float(repAmount) * 1000 / cycleTime - text = "{0}/s".format(formatAmount(repPerSec, 3, 0, 3, forceSign=True)) - tooltip = "Energy transferred per second" - return text, tooltip - elif itemGroup == "Remote Hull Repairer": - repAmount = stuff.getModifiedItemAttr("structureDamageAmount") - cycleTime = stuff.cycleTime - if not repAmount or not cycleTime: - return "", None - repPerSec = float(repAmount) * 1000 / cycleTime - text = "{0}/s".format(formatAmount(repPerSec, 3, 0, 3, forceSign=True)) - tooltip = "Structure repaired per second" - return text, tooltip - elif itemGroup == "Gang Coordinator": - command = stuff.getModifiedItemAttr("commandBonus") or stuff.getModifiedItemAttr("commandBonusHidden") - if not command: - return "", None - text = "{0}%".format(formatAmount(command, 3, 0, 3, forceSign=True)) - tooltip = "Gang bonus strength" - return text, tooltip - elif itemGroup == "Electronic Warfare Drone": - sigRadBonus = stuff.getModifiedItemAttr("signatureRadiusBonus") - lockRangeMult = stuff.getModifiedItemAttr("maxTargetRangeMultiplier") - scanResMult = stuff.getModifiedItemAttr("scanResolutionMultiplier") - falloffRangeMult = stuff.getModifiedItemAttr("fallofMultiplier") - optimalRangeMult = stuff.getModifiedItemAttr("maxRangeMultiplier") - trackingSpeedMult = stuff.getModifiedItemAttr("trackingSpeedMultiplier") - grav = stuff.getModifiedItemAttr("scanGravimetricStrengthBonus") - ladar = stuff.getModifiedItemAttr("scanLadarStrengthBonus") - radar = stuff.getModifiedItemAttr("scanRadarStrengthBonus") - magnet = stuff.getModifiedItemAttr("scanMagnetometricStrengthBonus") - if sigRadBonus: - text = "{0}%".format(formatAmount(sigRadBonus, 3, 0, 3, forceSign=True)) - tooltip = "Signature radius increase" - return text, tooltip - if lockRangeMult is not None and scanResMult is not None: - lockRangeBonus = (lockRangeMult - 1) * 100 - scanResBonus = (scanResMult - 1) * 100 - display = 0 - for bonus in (lockRangeBonus, scanResBonus): - if abs(bonus) > abs(display): - display = bonus - if not display: - return "", None - text = "{0}%".format(formatAmount(display, 3, 0, 3, forceSign=True)) - ttEntries = [] - if display == lockRangeBonus: - ttEntries.append("lock range") - if display == scanResBonus: - ttEntries.append("scan resolution") - tooltip = "{0} dampening".format(formatList(ttEntries)).capitalize() - return text, tooltip - if falloffRangeMult is not None and optimalRangeMult is not None and trackingSpeedMult is not None: - falloffRangeBonus = (falloffRangeMult - 1) * 100 - optimalRangeBonus = (optimalRangeMult - 1) * 100 - trackingSpeedBonus = (trackingSpeedMult - 1) * 100 - display = 0 - for bonus in (falloffRangeBonus, optimalRangeBonus, trackingSpeedBonus): - if abs(bonus) > abs(display): - display = bonus - if not display: - return "", None - text = "{0}%".format(formatAmount(display, 3, 0, 3), forceSign=True) - ttEntries = [] - if display == optimalRangeBonus: - ttEntries.append("optimal range") - if display == falloffRangeBonus: - ttEntries.append("falloff range") - if display == trackingSpeedBonus: - ttEntries.append("tracking speed") - tooltip = "{0} disruption".format(formatList(ttEntries)).capitalize() - return text, tooltip - if grav is not None and ladar is not None and radar is not None and magnet is not None: - display = max(grav, ladar, radar, magnet) - if not display: - return "", None - text = "{0}".format(formatAmount(display, 3, 0, 3)) - ttEntries = [] - if display == grav: - ttEntries.append("gravimetric") - if display == ladar: - ttEntries.append("ladar") - if display == magnet: - ttEntries.append("magnetometric") - if display == radar: - ttEntries.append("radar") - plu = "" if len(ttEntries) == 1 else "s" - tooltip = "{0} strength{1}".format(formatList(ttEntries), plu).capitalize() - return text, tooltip - else: - return "", None - elif itemGroup == "Fighter Bomber": - optimalSig = stuff.getModifiedItemAttr("optimalSigRadius") - if not optimalSig: - return "", None - text = "{0}m".format(formatAmount(optimalSig, 3, 0, 3)) - tooltip = "Optimal signature radius" - return text, tooltip - elif itemGroup in ("Frequency Mining Laser", "Strip Miner", "Mining Laser", "Gas Cloud Harvester"): - miningAmount = stuff.getModifiedItemAttr("specialtyMiningAmount") or stuff.getModifiedItemAttr("miningAmount") - cycleTime = stuff.cycleTime - if not miningAmount or not cycleTime: - return "", None - minePerHour = (float(miningAmount) * 1000 / cycleTime) * 3600 - text = "{0}/h".format(formatAmount(minePerHour, 3, 0, 3)) - tooltip = "Mining Yield per hour" - return text, tooltip - elif itemGroup == "Logistic Drone": - armorAmount = stuff.getModifiedItemAttr("armorDamageAmount") - shieldAmount = stuff.getModifiedItemAttr("shieldBonus") - hullAmount = stuff.getModifiedItemAttr("structureDamageAmount") - repAmount = armorAmount or shieldAmount or hullAmount - cycleTime = stuff.getModifiedItemAttr("duration") - if not repAmount or not cycleTime: - return "", None - repPerSec = float(repAmount) * 1000 / cycleTime - text = "{0}/s".format(formatAmount(repPerSec, 3, 0, 3)) - ttEntries = [] - if hullAmount is not None and repAmount == hullAmount: - ttEntries.append("structure") - if armorAmount is not None and repAmount == armorAmount: - ttEntries.append("armor") - if shieldAmount is not None and repAmount == shieldAmount: - ttEntries.append("shield") - tooltip = "{0} repaired per second".format(formatList(ttEntries)).capitalize() - return text, tooltip - elif itemGroup == "Energy Neutralizer Drone": - neutAmount = stuff.getModifiedItemAttr("energyNeutralizerAmount") - cycleTime = stuff.getModifiedItemAttr("energyNeutralizerDuration") - if not neutAmount or not cycleTime: - return "", None - capPerSec = float(-neutAmount) * 1000 / cycleTime - text = "{0}/s".format(formatAmount(capPerSec, 3, 0, 3)) - tooltip = "Energy neutralization per second" - return text, tooltip - elif itemGroup == "Mining Drone": - miningAmount = stuff.getModifiedItemAttr("miningAmount") - cycleTime = stuff.getModifiedItemAttr("duration") - if not miningAmount or not cycleTime: - return "", None - minePerHour = (float(miningAmount) * 1000 / cycleTime) * 3600 - text = "{0}/h".format(formatAmount(minePerHour, 3, 0, 3)) - tooltip = "Mining Yield per hour" - return text, tooltip - elif itemGroup == "Micro Jump Drive": - cycleTime = stuff.getModifiedItemAttr("duration") / 1000 - text = "{0}s".format(cycleTime) - tooltip = "Spoolup time" - return text, tooltip - elif itemGroup in ("Siege Module", "Cynosural Field"): - amt = stuff.getModifiedItemAttr("consumptionQuantity") - if amt: - typeID = stuff.getModifiedItemAttr("consumptionType") - item = Market.getInstance().getItem(typeID) - text = "{0} units".format(formatAmount(amt, 3, 0, 3)) - return text, item.name - else: - return "", None - elif itemGroup in ("Ancillary Armor Repairer", "Ancillary Shield Booster"): - hp = stuff.hpBeforeReload - cycles = stuff.numShots - cycleTime = stuff.rawCycleTime - if not hp or not cycleTime or not cycles: - return "", None - fit = Fit.getInstance().getFit(self.mainFrame.getActiveFit()) - ehpTotal = fit.ehp - hpTotal = fit.hp - useEhp = self.mainFrame.statsPane.nameViewMap["resistancesViewFull"].showEffective - tooltip = "HP restored over duration using charges" - if useEhp: - if itemGroup == "Ancillary Armor Repairer": - hpRatio = ehpTotal["armor"] / hpTotal["armor"] - else: - hpRatio = ehpTotal["shield"] / hpTotal["shield"] - tooltip = "E{0}".format(tooltip) - else: - hpRatio = 1 - if itemGroup == "Ancillary Armor Repairer": - hpRatio *= 3 - ehp = hp * hpRatio - duration = cycles * cycleTime / 1000 - text = "{0} / {1}s".format(formatAmount(ehp, 3, 0, 9), formatAmount(duration, 3, 0, 3)) - - return text, tooltip - elif itemGroup == "Armor Resistance Shift Hardener": - itemArmorResistanceShiftHardenerEM = (1-stuff.getModifiedItemAttr("armorEmDamageResonance"))*100 - itemArmorResistanceShiftHardenerTherm = (1-stuff.getModifiedItemAttr("armorThermalDamageResonance")) * 100 - itemArmorResistanceShiftHardenerKin = (1-stuff.getModifiedItemAttr("armorKineticDamageResonance")) * 100 - itemArmorResistanceShiftHardenerExp = (1-stuff.getModifiedItemAttr("armorExplosiveDamageResonance")) * 100 - - text = "{0}% | {1}% | {2}% | {3}%".format( - formatAmount(itemArmorResistanceShiftHardenerEM, 3, 0, 3), - formatAmount(itemArmorResistanceShiftHardenerTherm, 3, 0, 3), - formatAmount(itemArmorResistanceShiftHardenerKin, 3, 0, 3), - formatAmount(itemArmorResistanceShiftHardenerExp, 3, 0, 3), - ) - tooltip = "Resistances Shifted to Damage Profile:\n{0}% EM | {1}% Therm | {2}% Kin | {3}% Exp".format( - formatAmount(itemArmorResistanceShiftHardenerEM, 3, 0, 3), - formatAmount(itemArmorResistanceShiftHardenerTherm, 3, 0, 3), - formatAmount(itemArmorResistanceShiftHardenerKin, 3, 0, 3), - formatAmount(itemArmorResistanceShiftHardenerExp, 3, 0, 3), - ) - return text, tooltip - elif stuff.charge is not None: - chargeGroup = stuff.charge.group.name - if chargeGroup in ("Rocket", "Advanced Rocket", "Light Missile", "Advanced Light Missile", "FoF Light Missile", - "Heavy Assault Missile", "Advanced Heavy Assault Missile", "Heavy Missile", "Advanced Heavy Missile", "FoF Heavy Missile", - "Torpedo", "Advanced Torpedo", "Cruise Missile", "Advanced Cruise Missile", "FoF Cruise Missile", - "XL Torpedo", "XL Cruise Missile"): - cloudSize = stuff.getModifiedChargeAttr("aoeCloudSize") - aoeVelocity = stuff.getModifiedChargeAttr("aoeVelocity") - if not cloudSize or not aoeVelocity: - return "", None - text = "{0}{1} | {2}{3}".format(formatAmount(cloudSize, 3, 0, 3), "m", - formatAmount(aoeVelocity, 3, 0, 3), "m/s") - tooltip = "Explosion radius and explosion velocity" - return text, tooltip - elif chargeGroup == "Bomb": - cloudSize = stuff.getModifiedChargeAttr("aoeCloudSize") - if not cloudSize: - return "", None - text = "{0}{1}".format(formatAmount(cloudSize, 3, 0, 3), "m") - tooltip = "Explosion radius" - return text, tooltip - elif chargeGroup in ("Scanner Probe",): - scanStr = stuff.getModifiedChargeAttr("baseSensorStrength") - baseRange = stuff.getModifiedChargeAttr("baseScanRange") - if not scanStr or not baseRange: - return "", None - strTwoAu = scanStr / (2.0 / baseRange) - text = "{0}".format(formatAmount(strTwoAu, 3, 0, 3)) - tooltip = "Scan strength with 2 AU scan range" - return text, tooltip - else: - return "", None - else: - return "", None - -Miscellanea.register() +# ============================================================================= +# 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 wx + +from service.fit import Fit +from service.market import Market +import gui.mainFrame +from gui.viewColumn import ViewColumn +from gui.bitmapLoader import BitmapLoader +from gui.utils.numberFormatter import formatAmount +from gui.utils.listFormatter import formatList + + +class Miscellanea(ViewColumn): + name = "Miscellanea" + + def __init__(self, fittingView, params=None): + if params is None: + params = {"showIcon": True, "displayName": False} + + ViewColumn.__init__(self, fittingView) + if params["showIcon"]: + self.imageId = fittingView.imageList.GetImageIndex("column_misc", "gui") + self.bitmap = BitmapLoader.getBitmap("column_misc", "gui") + self.mask = wx.LIST_MASK_IMAGE + else: + self.imageId = -1 + + if params["displayName"] or self.imageId == -1: + self.columnText = "Misc data" + self.mask |= wx.LIST_MASK_TEXT + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + + def getText(self, stuff): + return self.__getData(stuff)[0] + + def getToolTip(self, mod): + return self.__getData(mod)[1] + + def getImageId(self, mod): + return -1 + + def getParameters(self): + return (("displayName", bool, False), ("showIcon", bool, True)) + + def __getData(self, stuff): + item = stuff.item + if item is None: + return "", None + itemGroup = item.group.name + itemCategory = item.category.name + + if itemGroup == "Ship Modifiers": + return "", None + elif itemGroup in ("Energy Weapon", "Hybrid Weapon", "Projectile Weapon", "Combat Drone", "Fighter Drone"): + trackingSpeed = stuff.getModifiedItemAttr("trackingSpeed") + if not trackingSpeed: + return "", None + text = "{0}".format(formatAmount(trackingSpeed, 3, 0, 3)) + tooltip = "Tracking speed" + return text, tooltip + elif itemCategory == "Subsystem": + slots = ("hi", "med", "low") + info = [] + for slot in slots: + n = int(stuff.getModifiedItemAttr("%sSlotModifier" % slot)) + if n > 0: + info.append("{0}{1}".format(n, slot[0].upper())) + return "+ " + ", ".join(info), "Slot Modifiers" + elif itemGroup == "Energy Neutralizer": + neutAmount = stuff.getModifiedItemAttr("energyNeutralizerAmount") + cycleTime = stuff.cycleTime + if not neutAmount or not cycleTime: + return "", None + capPerSec = float(-neutAmount) * 1000 / cycleTime + text = "{0}/s".format(formatAmount(capPerSec, 3, 0, 3)) + tooltip = "Energy neutralization per second" + return text, tooltip + elif itemGroup == "Energy Nosferatu": + neutAmount = stuff.getModifiedItemAttr("powerTransferAmount") + cycleTime = stuff.cycleTime + if not neutAmount or not cycleTime: + return "", None + capPerSec = float(-neutAmount) * 1000 / cycleTime + text = "{0}/s".format(formatAmount(capPerSec, 3, 0, 3)) + tooltip = "Energy neutralization per second" + return text, tooltip + elif itemGroup == "Salvager": + chance = stuff.getModifiedItemAttr("accessDifficultyBonus") + if not chance: + return "", None + text = "{0}%".format(formatAmount(chance, 3, 0, 3)) + tooltip = "Item retrieval chance" + return text, tooltip + elif itemGroup == "Data Miners": + strength = stuff.getModifiedItemAttr("virusStrength") + coherence = stuff.getModifiedItemAttr("virusCoherence") + if not strength or not coherence: + return "", None + text = "{0} | {1}".format(formatAmount(strength, 3, 0, 3), formatAmount(coherence, 3, 0, 3)) + tooltip = "Virus strength and coherence" + return text, tooltip + elif itemGroup in ("Warp Scrambler", "Warp Core Stabilizer"): + scramStr = stuff.getModifiedItemAttr("warpScrambleStrength") + if not scramStr: + return "", None + text = "{0}".format(formatAmount(-scramStr, 3, 0, 3, forceSign=True)) + tooltip = "Warp core strength modification" + return text, tooltip + elif itemGroup in ("Stasis Web", "Stasis Webifying Drone"): + speedFactor = stuff.getModifiedItemAttr("speedFactor") + if not speedFactor: + return "", None + text = "{0}%".format(formatAmount(speedFactor, 3, 0, 3)) + tooltip = "Speed reduction" + return text, tooltip + elif itemGroup == "Target Painter": + sigRadBonus = stuff.getModifiedItemAttr("signatureRadiusBonus") + if not sigRadBonus: + return "", None + text = "{0}%".format(formatAmount(sigRadBonus, 3, 0, 3, forceSign=True)) + tooltip = "Signature radius increase" + return text, tooltip + elif itemGroup == "Sensor Dampener": + lockRangeBonus = stuff.getModifiedItemAttr("maxTargetRangeBonus") + scanResBonus = stuff.getModifiedItemAttr("scanResolutionBonus") + if lockRangeBonus is None or scanResBonus is None: + return "", None + display = 0 + for bonus in (lockRangeBonus, scanResBonus): + if abs(bonus) > abs(display): + display = bonus + if not display: + return "", None + text = "{0}%".format(formatAmount(display, 3, 0, 3, forceSign=True)) + ttEntries = [] + if display == lockRangeBonus: + ttEntries.append("lock range") + if display == scanResBonus: + ttEntries.append("scan resolution") + tooltip = "{0} dampening".format(formatList(ttEntries)).capitalize() + return text, tooltip + elif itemGroup == "Weapon Disruptor": + # Weapon disruption now covers both tracking and guidance (missile) disruptors + # First get the attributes for tracking disruptors + optimalRangeBonus = stuff.getModifiedItemAttr("maxRangeBonus") + falloffRangeBonus = stuff.getModifiedItemAttr("falloffBonus") + trackingSpeedBonus = stuff.getModifiedItemAttr("trackingSpeedBonus") + + trackingDisruptorAttributes = { + "optimal range": optimalRangeBonus, + "falloff range": falloffRangeBonus, + "tracking speed": trackingSpeedBonus} + + isTrackingDisruptor = any(map(lambda x: x is not None and x != 0, trackingDisruptorAttributes.values())) + + # Then get the attributes for guidance disruptors + explosionVelocityBonus = stuff.getModifiedItemAttr("aoeVelocityBonus") + explosionRadiusBonus = stuff.getModifiedItemAttr("aoeCloudSizeBonus") + + flightTimeBonus = stuff.getModifiedItemAttr("explosionDelayBonus") + missileVelocityBonus = stuff.getModifiedItemAttr("missileVelocityBonus") + + guidanceDisruptorAttributes = { + "explosion velocity": explosionVelocityBonus, + "explosion radius": explosionRadiusBonus, + "flight time": flightTimeBonus, + "missile velocity": missileVelocityBonus} + + isGuidanceDisruptor = any(map(lambda x: x is not None and x != 0, guidanceDisruptorAttributes.values())) + + if isTrackingDisruptor: + attributes = trackingDisruptorAttributes + elif isGuidanceDisruptor: + attributes = guidanceDisruptorAttributes + else: + return "", None + + display = max(attributes.values(), key=lambda x: abs(x)) + + text = "{0}%".format(formatAmount(display, 3, 0, 3, forceSign=True)) + + ttEntries = [] + for attributeName, attributeValue in attributes.items(): + if attributeValue == display: + ttEntries.append(attributeName) + + tooltip = "{0} disruption".format(formatList(ttEntries)).capitalize() + return text, tooltip + elif itemGroup in ("ECM", "Burst Jammer", "Burst Projectors"): + grav = stuff.getModifiedItemAttr("scanGravimetricStrengthBonus") + ladar = stuff.getModifiedItemAttr("scanLadarStrengthBonus") + radar = stuff.getModifiedItemAttr("scanRadarStrengthBonus") + magnet = stuff.getModifiedItemAttr("scanMagnetometricStrengthBonus") + displayMax = max(grav, ladar, radar, magnet) + displayMin = min(grav, ladar, radar, magnet) + if grav is None or ladar is None or radar is None or magnet is None or displayMax is None: + return "", None + + if displayMax == displayMin or displayMin is None: + text = "{0}".format( + formatAmount(displayMax, 3, 0, 3), + ) + else: + text = "{0} | {1}".format( + formatAmount(displayMax, 3, 0, 3), + formatAmount(displayMin, 3, 0, 3), + ) + tooltip = "ECM Jammer Strength:\n{0} Gravimetric | {1} Ladar | {2} Magnetometric | {3} Radar".format( + formatAmount(grav, 3, 0, 3), + formatAmount(ladar, 3, 0, 3), + formatAmount(magnet, 3, 0, 3), + formatAmount(radar, 3, 0, 3), + ) + return text, tooltip + elif itemGroup in ("Remote Sensor Booster", "Sensor Booster", "Signal Amplifier"): + scanResBonus = stuff.getModifiedItemAttr("scanResolutionBonus") + lockRangeBonus = stuff.getModifiedItemAttr("maxTargetRangeBonus") + gravBonus = stuff.getModifiedItemAttr("scanGravimetricStrengthPercent") + if scanResBonus is None or lockRangeBonus is None or gravBonus is None: + return "", None + + text = "{0}% | {1}% | {2}%".format( + formatAmount(scanResBonus, 3, 0, 3), + formatAmount(lockRangeBonus, 3, 0, 3), + formatAmount(gravBonus, 3, 0, 3), + ) + tooltip = "Applied bonuses:\n{0}% scan resolution | {1}% lock range | {2}% sensor strength".format( + formatAmount(scanResBonus, 3, 0, 3), + formatAmount(lockRangeBonus, 3, 0, 3), + formatAmount(gravBonus, 3, 0, 3), + ) + return text, tooltip + elif itemGroup in ("Projected ECCM", "ECCM", "Sensor Backup Array"): + grav = stuff.getModifiedItemAttr("scanGravimetricStrengthPercent") + ladar = stuff.getModifiedItemAttr("scanLadarStrengthPercent") + radar = stuff.getModifiedItemAttr("scanRadarStrengthPercent") + magnet = stuff.getModifiedItemAttr("scanMagnetometricStrengthPercent") + if grav is None or ladar is None or radar is None or magnet is None: + return "", None + display = max(grav, ladar, radar, magnet) + if not display: + return "", None + text = "{0}%".format(formatAmount(display, 3, 0, 3, forceSign=True)) + ttEntries = [] + if display == grav: + ttEntries.append("gravimetric") + if display == ladar: + ttEntries.append("ladar") + if display == magnet: + ttEntries.append("magnetometric") + if display == radar: + ttEntries.append("radar") + plu = "" if len(ttEntries) == 1 else "s" + tooltip = "{0} strength{1} bonus".format(formatList(ttEntries), plu).capitalize() + return text, tooltip + elif itemGroup == "Cloaking Device": + recalibration = stuff.getModifiedItemAttr("cloakingTargetingDelay") + if recalibration is None: + return "", None + text = "{0}s".format(formatAmount(float(recalibration) / 1000, 3, 0, 3)) + tooltip = "Sensor recalibration time" + return text, tooltip + elif itemGroup == "Remote Armor Repairer": + repAmount = stuff.getModifiedItemAttr("armorDamageAmount") + cycleTime = stuff.getModifiedItemAttr("duration") + if not repAmount or not cycleTime: + return "", None + repPerSec = float(repAmount) * 1000 / cycleTime + text = "{0}/s".format(formatAmount(repPerSec, 3, 0, 3, forceSign=True)) + tooltip = "Armor repaired per second" + return text, tooltip + elif itemGroup == "Remote Shield Booster": + repAmount = stuff.getModifiedItemAttr("shieldBonus") + cycleTime = stuff.cycleTime + if not repAmount or not cycleTime: + return "", None + repPerSec = float(repAmount) * 1000 / cycleTime + text = "{0}/s".format(formatAmount(repPerSec, 3, 0, 3, forceSign=True)) + tooltip = "Shield transferred per second" + return text, tooltip + elif itemGroup == "Remote Capacitor Transmitter": + repAmount = stuff.getModifiedItemAttr("powerTransferAmount") + cycleTime = stuff.cycleTime + if not repAmount or not cycleTime: + return "", None + repPerSec = float(repAmount) * 1000 / cycleTime + text = "{0}/s".format(formatAmount(repPerSec, 3, 0, 3, forceSign=True)) + tooltip = "Energy transferred per second" + return text, tooltip + elif itemGroup == "Remote Hull Repairer": + repAmount = stuff.getModifiedItemAttr("structureDamageAmount") + cycleTime = stuff.cycleTime + if not repAmount or not cycleTime: + return "", None + repPerSec = float(repAmount) * 1000 / cycleTime + text = "{0}/s".format(formatAmount(repPerSec, 3, 0, 3, forceSign=True)) + tooltip = "Structure repaired per second" + return text, tooltip + elif itemGroup == "Gang Coordinator": + command = stuff.getModifiedItemAttr("commandBonus") or stuff.getModifiedItemAttr("commandBonusHidden") + if not command: + return "", None + text = "{0}%".format(formatAmount(command, 3, 0, 3, forceSign=True)) + tooltip = "Gang bonus strength" + return text, tooltip + elif itemGroup == "Electronic Warfare Drone": + sigRadBonus = stuff.getModifiedItemAttr("signatureRadiusBonus") + lockRangeMult = stuff.getModifiedItemAttr("maxTargetRangeMultiplier") + scanResMult = stuff.getModifiedItemAttr("scanResolutionMultiplier") + falloffRangeMult = stuff.getModifiedItemAttr("fallofMultiplier") + optimalRangeMult = stuff.getModifiedItemAttr("maxRangeMultiplier") + trackingSpeedMult = stuff.getModifiedItemAttr("trackingSpeedMultiplier") + grav = stuff.getModifiedItemAttr("scanGravimetricStrengthBonus") + ladar = stuff.getModifiedItemAttr("scanLadarStrengthBonus") + radar = stuff.getModifiedItemAttr("scanRadarStrengthBonus") + magnet = stuff.getModifiedItemAttr("scanMagnetometricStrengthBonus") + if sigRadBonus: + text = "{0}%".format(formatAmount(sigRadBonus, 3, 0, 3, forceSign=True)) + tooltip = "Signature radius increase" + return text, tooltip + if lockRangeMult is not None and scanResMult is not None: + lockRangeBonus = (lockRangeMult - 1) * 100 + scanResBonus = (scanResMult - 1) * 100 + display = 0 + for bonus in (lockRangeBonus, scanResBonus): + if abs(bonus) > abs(display): + display = bonus + if not display: + return "", None + text = "{0}%".format(formatAmount(display, 3, 0, 3, forceSign=True)) + ttEntries = [] + if display == lockRangeBonus: + ttEntries.append("lock range") + if display == scanResBonus: + ttEntries.append("scan resolution") + tooltip = "{0} dampening".format(formatList(ttEntries)).capitalize() + return text, tooltip + if falloffRangeMult is not None and optimalRangeMult is not None and trackingSpeedMult is not None: + falloffRangeBonus = (falloffRangeMult - 1) * 100 + optimalRangeBonus = (optimalRangeMult - 1) * 100 + trackingSpeedBonus = (trackingSpeedMult - 1) * 100 + display = 0 + for bonus in (falloffRangeBonus, optimalRangeBonus, trackingSpeedBonus): + if abs(bonus) > abs(display): + display = bonus + if not display: + return "", None + text = "{0}%".format(formatAmount(display, 3, 0, 3), forceSign=True) + ttEntries = [] + if display == optimalRangeBonus: + ttEntries.append("optimal range") + if display == falloffRangeBonus: + ttEntries.append("falloff range") + if display == trackingSpeedBonus: + ttEntries.append("tracking speed") + tooltip = "{0} disruption".format(formatList(ttEntries)).capitalize() + return text, tooltip + if grav is not None and ladar is not None and radar is not None and magnet is not None: + display = max(grav, ladar, radar, magnet) + if not display: + return "", None + text = "{0}".format(formatAmount(display, 3, 0, 3)) + ttEntries = [] + if display == grav: + ttEntries.append("gravimetric") + if display == ladar: + ttEntries.append("ladar") + if display == magnet: + ttEntries.append("magnetometric") + if display == radar: + ttEntries.append("radar") + plu = "" if len(ttEntries) == 1 else "s" + tooltip = "{0} strength{1}".format(formatList(ttEntries), plu).capitalize() + return text, tooltip + else: + return "", None + elif itemGroup == "Fighter Bomber": + optimalSig = stuff.getModifiedItemAttr("optimalSigRadius") + if not optimalSig: + return "", None + text = "{0}m".format(formatAmount(optimalSig, 3, 0, 3)) + tooltip = "Optimal signature radius" + return text, tooltip + elif itemGroup in ("Frequency Mining Laser", "Strip Miner", "Mining Laser", "Gas Cloud Harvester", "Mining Drone"): + miningAmount = stuff.getModifiedItemAttr("specialtyMiningAmount") or stuff.getModifiedItemAttr("miningAmount") + cycleTime = getattr(stuff, 'cycleTime', stuff.getModifiedItemAttr("duration")) + if not miningAmount or not cycleTime: + return "", None + minePerSec = (float(miningAmount) * 1000 / cycleTime) + text = "{0} m3/s".format(formatAmount(minePerSec, 3, 0, 3)) + tooltip = "Mining Yield per second ({0} per hour)".format(formatAmount(minePerSec * 3600, 3, 0, 3)) + return text, tooltip + elif itemGroup == "Logistic Drone": + armorAmount = stuff.getModifiedItemAttr("armorDamageAmount") + shieldAmount = stuff.getModifiedItemAttr("shieldBonus") + hullAmount = stuff.getModifiedItemAttr("structureDamageAmount") + repAmount = armorAmount or shieldAmount or hullAmount + cycleTime = stuff.getModifiedItemAttr("duration") + if not repAmount or not cycleTime: + return "", None + repPerSec = float(repAmount) * 1000 / cycleTime + text = "{0}/s".format(formatAmount(repPerSec, 3, 0, 3)) + ttEntries = [] + if hullAmount is not None and repAmount == hullAmount: + ttEntries.append("structure") + if armorAmount is not None and repAmount == armorAmount: + ttEntries.append("armor") + if shieldAmount is not None and repAmount == shieldAmount: + ttEntries.append("shield") + tooltip = "{0} repaired per second".format(formatList(ttEntries)).capitalize() + return text, tooltip + elif itemGroup == "Energy Neutralizer Drone": + neutAmount = stuff.getModifiedItemAttr("energyNeutralizerAmount") + cycleTime = stuff.getModifiedItemAttr("energyNeutralizerDuration") + if not neutAmount or not cycleTime: + return "", None + capPerSec = float(-neutAmount) * 1000 / cycleTime + text = "{0}/s".format(formatAmount(capPerSec, 3, 0, 3)) + tooltip = "Energy neutralization per second" + return text, tooltip + elif itemGroup == "Micro Jump Drive": + cycleTime = stuff.getModifiedItemAttr("duration") / 1000 + text = "{0}s".format(cycleTime) + tooltip = "Spoolup time" + return text, tooltip + elif itemGroup in ("Siege Module", "Cynosural Field"): + amt = stuff.getModifiedItemAttr("consumptionQuantity") + if amt: + typeID = stuff.getModifiedItemAttr("consumptionType") + item = Market.getInstance().getItem(typeID) + text = "{0} units".format(formatAmount(amt, 3, 0, 3)) + return text, item.name + else: + return "", None + elif itemGroup in ("Ancillary Armor Repairer", "Ancillary Shield Booster"): + hp = stuff.hpBeforeReload + cycles = stuff.numShots + cycleTime = stuff.rawCycleTime + if not hp or not cycleTime or not cycles: + return "", None + fit = Fit.getInstance().getFit(self.mainFrame.getActiveFit()) + ehpTotal = fit.ehp + hpTotal = fit.hp + useEhp = self.mainFrame.statsPane.nameViewMap["resistancesViewFull"].showEffective + tooltip = "HP restored over duration using charges" + if useEhp: + if itemGroup == "Ancillary Armor Repairer": + hpRatio = ehpTotal["armor"] / hpTotal["armor"] + else: + hpRatio = ehpTotal["shield"] / hpTotal["shield"] + tooltip = "E{0}".format(tooltip) + else: + hpRatio = 1 + if itemGroup == "Ancillary Armor Repairer": + hpRatio *= 3 + ehp = hp * hpRatio + duration = cycles * cycleTime / 1000 + text = "{0} / {1}s".format(formatAmount(ehp, 3, 0, 9), formatAmount(duration, 3, 0, 3)) + + return text, tooltip + elif itemGroup == "Armor Resistance Shift Hardener": + itemArmorResistanceShiftHardenerEM = (1 - stuff.getModifiedItemAttr("armorEmDamageResonance")) * 100 + itemArmorResistanceShiftHardenerTherm = (1 - stuff.getModifiedItemAttr("armorThermalDamageResonance")) * 100 + itemArmorResistanceShiftHardenerKin = (1 - stuff.getModifiedItemAttr("armorKineticDamageResonance")) * 100 + itemArmorResistanceShiftHardenerExp = (1 - stuff.getModifiedItemAttr("armorExplosiveDamageResonance")) * 100 + + text = "{0}% | {1}% | {2}% | {3}%".format( + formatAmount(itemArmorResistanceShiftHardenerEM, 3, 0, 3), + formatAmount(itemArmorResistanceShiftHardenerTherm, 3, 0, 3), + formatAmount(itemArmorResistanceShiftHardenerKin, 3, 0, 3), + formatAmount(itemArmorResistanceShiftHardenerExp, 3, 0, 3), + ) + tooltip = "Resistances Shifted to Damage Profile:\n{0}% EM | {1}% Therm | {2}% Kin | {3}% Exp".format( + formatAmount(itemArmorResistanceShiftHardenerEM, 3, 0, 3), + formatAmount(itemArmorResistanceShiftHardenerTherm, 3, 0, 3), + formatAmount(itemArmorResistanceShiftHardenerKin, 3, 0, 3), + formatAmount(itemArmorResistanceShiftHardenerExp, 3, 0, 3), + ) + return text, tooltip + elif stuff.charge is not None: + chargeGroup = stuff.charge.group.name + if chargeGroup in ( + "Rocket", + "Advanced Rocket", + "Light Missile", + "Advanced Light Missile", + "FoF Light Missile", + "Heavy Assault Missile", + "Advanced Heavy Assault Missile", + "Heavy Missile", + "Advanced Heavy Missile", + "FoF Heavy Missile", + "Torpedo", + "Advanced Torpedo", + "Cruise Missile", + "Advanced Cruise Missile", + "FoF Cruise Missile", + "XL Torpedo", + "XL Cruise Missile" + ): + cloudSize = stuff.getModifiedChargeAttr("aoeCloudSize") + aoeVelocity = stuff.getModifiedChargeAttr("aoeVelocity") + if not cloudSize or not aoeVelocity: + return "", None + text = "{0}{1} | {2}{3}".format(formatAmount(cloudSize, 3, 0, 3), "m", + formatAmount(aoeVelocity, 3, 0, 3), "m/s") + tooltip = "Explosion radius and explosion velocity" + return text, tooltip + elif chargeGroup == "Bomb": + cloudSize = stuff.getModifiedChargeAttr("aoeCloudSize") + if not cloudSize: + return "", None + text = "{0}{1}".format(formatAmount(cloudSize, 3, 0, 3), "m") + tooltip = "Explosion radius" + return text, tooltip + elif chargeGroup in ("Scanner Probe",): + scanStr = stuff.getModifiedChargeAttr("baseSensorStrength") + baseRange = stuff.getModifiedChargeAttr("baseScanRange") + if not scanStr or not baseRange: + return "", None + strTwoAu = scanStr / (2.0 / baseRange) + text = "{0}".format(formatAmount(strTwoAu, 3, 0, 3)) + tooltip = "Scan strength with 2 AU scan range" + return text, tooltip + else: + return "", None + else: + return "", None + + +Miscellanea.register() diff --git a/gui/builtinViewColumns/price.py b/gui/builtinViewColumns/price.py index 74d2fc890..68ad87e1e 100644 --- a/gui/builtinViewColumns/price.py +++ b/gui/builtinViewColumns/price.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos, Lucas Thode # # This file is part of pyfa. @@ -15,17 +15,20 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= +import wx + +from eos.types import Drone, Cargo +from service.market import Market from gui.viewColumn import ViewColumn from gui.bitmapLoader import BitmapLoader from gui.utils.numberFormatter import formatAmount -from eos.types import Drone, Cargo -import wx -import service + class Price(ViewColumn): name = "Price" + def __init__(self, fittingView, params): ViewColumn.__init__(self, fittingView) self.mask = wx.LIST_MASK_IMAGE @@ -36,7 +39,7 @@ class Price(ViewColumn): if stuff.item is None or stuff.item.group.name == "Ship Modifiers": return "" - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() price = sMkt.getPriceNow(stuff.item.ID) if not price or not price.price or not price.isValid: @@ -45,21 +48,22 @@ class Price(ViewColumn): price = price.price # Set new price variable with what we need if isinstance(stuff, Drone) or isinstance(stuff, Cargo): - price *= stuff.amount + price *= stuff.amount return formatAmount(price, 3, 3, 9, currency=True) def delayedText(self, mod, display, colItem): - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() + def callback(item): price = sMkt.getPriceNow(item.ID) text = formatAmount(price.price, 3, 3, 9, currency=True) if price.price else "" - if price.failed: text += " (!)" + if price.failed: + text += " (!)" colItem.SetText(text) display.SetItem(colItem) - sMkt.waitForPrice(mod.item, callback) def getImageId(self, mod): @@ -68,4 +72,5 @@ class Price(ViewColumn): def getToolTip(self, mod): return self.name + Price.register() diff --git a/gui/builtinViewColumns/propertyDisplay.py b/gui/builtinViewColumns/propertyDisplay.py index 0bfee5899..1972cfae1 100644 --- a/gui/builtinViewColumns/propertyDisplay.py +++ b/gui/builtinViewColumns/propertyDisplay.py @@ -1,70 +1,71 @@ -#=============================================================================== -# 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 . -#=============================================================================== - -from gui.viewColumn import ViewColumn -from gui.bitmapLoader import BitmapLoader -from gui.utils.numberFormatter import formatAmount -import wx -import service - -class PropertyDisplay(ViewColumn): - name = "prop" - def __init__(self, fittingView, params): - ViewColumn.__init__(self, fittingView) - sAttr = service.Attribute.getInstance() - attributeSlave = params["attributeSlave"] or params["property"] - # This function can throw an exception if the database isn't sane - # We need to do a sanity check before this runs - info = sAttr.getAttributeInfo(attributeSlave) - - self.mask = 0 - self.propertyName = params["property"] - self.info = info - if params["showIcon"]: - if info.name == "power": - iconFile = "pg_small" - iconType = "gui" - else: - iconFile = info.icon.iconFile if info.icon else None - iconType = "icons" - if iconFile: - self.imageId = fittingView.imageList.GetImageIndex(iconFile, iconType) - else: - self.imageId = -1 - else: - self.imageId = -1 - - if params["displayName"] or self.imageId == -1: - self.columnText = info.displayName if info.displayName != "" else info.name - - def getText(self, stuff): - attr = getattr(stuff, self.propertyName, None) - if attr: - return (formatAmount(attr, 3, 0, 3)) - else: - return "" - - @staticmethod - def getParameters(): - return (("property", str, None), - ("attributeSlave", str, None), - ("displayName", bool, False), - ("showIcon", bool, True)) - -PropertyDisplay.register() +# ============================================================================= +# 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 . +# ============================================================================= + +from gui.viewColumn import ViewColumn +from gui.utils.numberFormatter import formatAmount +from service.attribute import Attribute + + +class PropertyDisplay(ViewColumn): + name = "prop" + + def __init__(self, fittingView, params): + ViewColumn.__init__(self, fittingView) + sAttr = Attribute.getInstance() + attributeSlave = params["attributeSlave"] or params["property"] + # This function can throw an exception if the database isn't sane + # We need to do a sanity check before this runs + info = sAttr.getAttributeInfo(attributeSlave) + + self.mask = 0 + self.propertyName = params["property"] + self.info = info + if params["showIcon"]: + if info.name == "power": + iconFile = "pg_small" + iconType = "gui" + else: + iconFile = info.icon.iconFile if info.icon else None + iconType = "icons" + if iconFile: + self.imageId = fittingView.imageList.GetImageIndex(iconFile, iconType) + else: + self.imageId = -1 + else: + self.imageId = -1 + + if params["displayName"] or self.imageId == -1: + self.columnText = info.displayName if info.displayName != "" else info.name + + def getText(self, stuff): + attr = getattr(stuff, self.propertyName, None) + if attr: + return (formatAmount(attr, 3, 0, 3)) + else: + return "" + + @staticmethod + def getParameters(): + return (("property", str, None), + ("attributeSlave", str, None), + ("displayName", bool, False), + ("showIcon", bool, True)) + + +PropertyDisplay.register() diff --git a/gui/builtinViewColumns/state.py b/gui/builtinViewColumns/state.py index cc3dee59b..920562087 100644 --- a/gui/builtinViewColumns/state.py +++ b/gui/builtinViewColumns/state.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,18 +15,21 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= -from gui.viewColumn import ViewColumn -from gui.bitmapLoader import BitmapLoader -import gui.mainFrame import wx + from eos.types import Drone, Module, Rack, Fit, Implant from eos.types import State as State_ +from gui.viewColumn import ViewColumn + +import gui.mainFrame + class State(ViewColumn): name = "State" + def __init__(self, fittingView, params): ViewColumn.__init__(self, fittingView) self.mainFrame = gui.mainFrame.MainFrame.getInstance() @@ -44,7 +47,8 @@ class State(ViewColumn): def getImageId(self, stuff): generic_active = self.fittingView.imageList.GetImageIndex("state_%s_small" % State_.getName(1).lower(), "gui") - generic_inactive = self.fittingView.imageList.GetImageIndex("state_%s_small" % State_.getName(-1).lower(), "gui") + generic_inactive = self.fittingView.imageList.GetImageIndex("state_%s_small" % State_.getName(-1).lower(), + "gui") if isinstance(stuff, Drone): if stuff.amountActive > 0: @@ -57,7 +61,8 @@ class State(ViewColumn): if stuff.isEmpty: return -1 else: - return self.fittingView.imageList.GetImageIndex("state_%s_small" % State_.getName(stuff.state).lower(), "gui") + return self.fittingView.imageList.GetImageIndex("state_%s_small" % State_.getName(stuff.state).lower(), + "gui") elif isinstance(stuff, Fit): fitID = self.mainFrame.getActiveFit() projectionInfo = stuff.getProjectionInfo(fitID) @@ -78,4 +83,5 @@ class State(ViewColumn): return generic_active return generic_inactive + State.register() diff --git a/gui/builtinViews/__init__.py b/gui/builtinViews/__init__.py index d51fdbad6..0537a1e16 100644 --- a/gui/builtinViews/__init__.py +++ b/gui/builtinViews/__init__.py @@ -1 +1 @@ -__all__ = ["fittingView", "implantEditor"] +__all__ = ["fittingView", "implantEditor"] diff --git a/gui/builtinViews/emptyView.py b/gui/builtinViews/emptyView.py index 2ea3dbeb1..0dc8d958e 100644 --- a/gui/builtinViews/emptyView.py +++ b/gui/builtinViews/emptyView.py @@ -2,7 +2,7 @@ import wx import gui.globalEvents as GE import gui.chromeTabs import gui.mainFrame -import service + class BlankPage(wx.Panel): def __init__(self, parent): @@ -23,8 +23,8 @@ class BlankPage(wx.Panel): def pageChanged(self, event): if self.parent.IsActive(self): fitID = None -# sFit = service.Fit.getInstance() -# sFit.switchFit(fitID) + # sFit = Fit.getInstance() + # sFit.switchFit(fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) - event.Skip() \ No newline at end of file + event.Skip() diff --git a/gui/builtinViews/entityEditor.py b/gui/builtinViews/entityEditor.py index b62060357..b77efe8a5 100644 --- a/gui/builtinViews/entityEditor.py +++ b/gui/builtinViews/entityEditor.py @@ -1,6 +1,6 @@ import wx from gui.bitmapLoader import BitmapLoader -import service + class BaseValidator(wx.PyValidator): def __init__(self): @@ -15,6 +15,7 @@ class BaseValidator(wx.PyValidator): def TransferFromWindow(self): return True + class TextEntryValidatedDialog(wx.TextEntryDialog): def __init__(self, parent, validator=None, *args, **kargs): wx.TextEntryDialog.__init__(self, parent, *args, **kargs) @@ -24,7 +25,8 @@ class TextEntryValidatedDialog(wx.TextEntryDialog): if validator: self.txtctrl.SetValidator(validator()) -class EntityEditor (wx.Panel): + +class EntityEditor(wx.Panel): """ Entity Editor is a panel that takes some sort of list as a source and populates a drop down with options to add/ rename/clone/delete an entity. Comes with dialogs that take user input. Classes that derive this class must override @@ -52,7 +54,7 @@ class EntityEditor (wx.Panel): bitmap = wx.ArtProvider.GetBitmap(art, wx.ART_BUTTON) if name != "rename" else art btn = wx.BitmapButton(self, wx.ID_ANY, bitmap) if size is None: - size = btn.GetSize() + size = btn.GetSize() btn.SetMinSize(size) btn.SetMaxSize(size) @@ -135,8 +137,9 @@ class EntityEditor (wx.Panel): def OnDelete(self, event): dlg = wx.MessageDialog(self, - "Do you really want to delete the {} {}?".format(self.getActiveEntity().name, self.entityName), - "Confirm Delete", wx.YES | wx.NO | wx.ICON_QUESTION) + "Do you really want to delete the {} {}?".format(self.getActiveEntity().name, + self.entityName), + "Confirm Delete", wx.YES | wx.NO | wx.ICON_QUESTION) dlg.CenterOnParent() if dlg.ShowModal() == wx.ID_YES: @@ -171,4 +174,4 @@ class EntityEditor (wx.Panel): return False self.Parent.Show() - return True \ No newline at end of file + return True diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index e97a176a7..dae6fe86e 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,11 +15,10 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx import wx.lib.newevent -import service import gui.mainFrame import gui.marketBrowser import gui.display as d @@ -33,11 +32,15 @@ import gui.builtinViews.emptyView from gui.utils.exportHtml import exportHtml from logging import getLogger, Formatter +from service.fit import Fit +from service.market import Market + import gui.globalEvents as GE logger = getLogger(__name__) -#Tab spawning handler + +# Tab spawning handler class FitSpawner(gui.multiSwitch.TabSpawner): def __init__(self, multiSwitch): self.multiSwitch = multiSwitch @@ -58,7 +61,7 @@ class FitSpawner(gui.multiSwitch.TabSpawner): pass if count < 0: startup = getattr(event, "startup", False) # see OpenFitsThread in gui.mainFrame - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() openFitInNew = sFit.serviceFittingOptions["openFitInNew"] mstate = wx.GetMouseState() @@ -87,22 +90,25 @@ class FitSpawner(gui.multiSwitch.TabSpawner): self.multiSwitch.AddPage(view) view.handleDrag(type, fitID) + FitSpawner.register() -#Drag'n'drop handler -class FittingViewDrop(wx.PyDropTarget): - def __init__(self, dropFn): - wx.PyDropTarget.__init__(self) - self.dropFn = dropFn - # this is really transferring an EVE itemID - self.dropData = wx.PyTextDataObject() - self.SetDataObject(self.dropData) - def OnData(self, x, y, t): - if self.GetData(): - data = self.dropData.GetText().split(':') - self.dropFn(x, y, data) - return t +# Drag'n'drop handler +class FittingViewDrop(wx.PyDropTarget): + def __init__(self, dropFn): + wx.PyDropTarget.__init__(self) + self.dropFn = dropFn + # this is really transferring an EVE itemID + self.dropData = wx.PyTextDataObject() + self.SetDataObject(self.dropData) + + def OnData(self, x, y, t): + if self.GetData(): + data = self.dropData.GetText().split(':') + self.dropFn(x, y, data) + return t + class FittingView(d.Display): DEFAULT_COLS = ["State", @@ -119,7 +125,7 @@ class FittingView(d.Display): ] def __init__(self, parent): - d.Display.__init__(self, parent, size = (0,0), style = wx.BORDER_NONE) + d.Display.__init__(self, parent, size=(0, 0), style=wx.BORDER_NONE) self.Show(False) self.parent = parent self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) @@ -129,7 +135,7 @@ class FittingView(d.Display): self.Bind(wx.EVT_LEFT_DCLICK, self.removeItem) self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.startDrag) - if "__WXGTK__" in wx.PlatformInfo: + if "__WXGTK__" in wx.PlatformInfo: self.Bind(wx.EVT_RIGHT_UP, self.scheduleMenu) else: self.Bind(wx.EVT_RIGHT_DOWN, self.scheduleMenu) @@ -194,7 +200,7 @@ class FittingView(d.Display): self.addModule(x, y, int(data[1])) def handleDrag(self, type, fitID): - #Those are drags coming from pyfa sources, NOT builtin wx drags + # Those are drags coming from pyfa sources, NOT builtin wx drags if type == "fit": wx.PostEvent(self.mainFrame, gui.shipBrowser.FitSelected(fitID=fitID)) @@ -210,7 +216,7 @@ class FittingView(d.Display): def pageChanged(self, event): if self.parent.IsActive(self): fitID = self.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() sFit.switchFit(fitID) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) @@ -228,7 +234,7 @@ class FittingView(d.Display): dropSource = wx.DropSource(self) dropSource.SetData(data) - res = dropSource.DoDragDrop() + dropSource.DoDragDrop() def getSelectedMods(self): sel = [] @@ -239,15 +245,14 @@ class FittingView(d.Display): return sel - def kbEvent(self,event): + def kbEvent(self, event): keycode = event.GetKeyCode() if keycode == wx.WXK_DELETE or keycode == wx.WXK_NUMPAD_DELETE: row = self.GetFirstSelected() - firstSel = row while row != -1: if row not in self.blanks: self.removeModule(self.mods[row]) - self.Select(row,0) + self.Select(row, 0) row = self.GetNextSelected(row) event.Skip() @@ -265,7 +270,7 @@ class FittingView(d.Display): try: # Sometimes there is no active page after deletion, hence the try block - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() sFit.refreshFit(self.getActiveFit()) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.activeFitID)) except wx._core.PyDeadObjectError: @@ -285,7 +290,7 @@ class FittingView(d.Display): fitID = event.fitID startup = getattr(event, "startup", False) self.activeFitID = fitID - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() self.updateTab() if not startup or startup == 2: # see OpenFitsThread in gui.mainFrame self.Show(fitID is not None) @@ -296,7 +301,7 @@ class FittingView(d.Display): event.Skip() def updateTab(self): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(self.getActiveFit(), basic=True) bitmap = BitmapLoader.getImage("race_%s_small" % fit.ship.item.race, "gui") @@ -310,8 +315,8 @@ class FittingView(d.Display): if self.parent.IsActive(self): itemID = event.itemID fitID = self.activeFitID - if fitID != None: - sFit = service.Fit.getInstance() + if fitID is not None: + sFit = Fit.getInstance() if sFit.isAmmo(itemID): modules = [] sel = self.GetFirstSelected() @@ -340,7 +345,7 @@ class FittingView(d.Display): self.click(event) def removeModule(self, module): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(self.activeFitID) populate = sFit.removeModule(self.activeFitID, fit.modules.index(module)) @@ -350,11 +355,10 @@ class FittingView(d.Display): def addModule(self, x, y, srcIdx): '''Add a module from the market browser''' - mstate = wx.GetMouseState() dstRow, _ = self.HitTest((x, y)) if dstRow != -1 and dstRow not in self.blanks: - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() moduleChanged = sFit.changeModule(fitID, self.mods[dstRow].modPosition, srcIdx) if moduleChanged is None: @@ -370,15 +374,16 @@ class FittingView(d.Display): if dstRow != -1 and dstRow not in self.blanks: module = self.mods[dstRow] - sFit = service.Fit.getInstance() - sFit.moveCargoToModule(self.mainFrame.getActiveFit(), module.modPosition, srcIdx, mstate.CmdDown() and module.isEmpty) + sFit = Fit.getInstance() + sFit.moveCargoToModule(self.mainFrame.getActiveFit(), module.modPosition, srcIdx, + mstate.CmdDown() and module.isEmpty) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit())) def swapItems(self, x, y, srcIdx): '''Swap two modules in fitting window''' mstate = wx.GetMouseState() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(self.activeFitID) if mstate.CmdDown(): @@ -412,7 +417,7 @@ class FittingView(d.Display): known to the display, and not the backend, so it's safe. ''' - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(self.activeFitID) slotOrder = [Slot.SUBSYSTEM, Slot.HIGH, Slot.MED, Slot.LOW, Slot.RIG, Slot.SERVICE] @@ -425,7 +430,7 @@ class FittingView(d.Display): # as Racks and tactical Modes. This allows us to skip over common # module operations such as swapping, removing, copying, etc. that # would otherwise cause complications - self.blanks = [] # preliminary markers where blanks will be inserted + self.blanks = [] # preliminary markers where blanks will be inserted if sFit.serviceFittingOptions["rackSlots"]: # flag to know when to add blanks, based on previous slot @@ -435,12 +440,12 @@ class FittingView(d.Display): for i, mod in enumerate(self.mods): if mod.slot != slotDivider: slotDivider = mod.slot - self.blanks.append((i, slotDivider)) # where and what + self.blanks.append((i, slotDivider)) # where and what # second loop modifies self.mods, rewrites self.blanks to represent actual index of blanks for i, (x, slot) in enumerate(self.blanks): - self.blanks[i] = x+i # modify blanks with actual index - self.mods.insert(x+i, Rack.buildRack(slot)) + self.blanks[i] = x + i # modify blanks with actual index + self.mods.insert(x + i, Rack.buildRack(slot)) if fit.mode: # Modes are special snowflakes and need a little manual loving @@ -484,7 +489,7 @@ class FittingView(d.Display): if self.activeFitID is None: return - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() selection = [] sel = self.GetFirstSelected() contexts = [] @@ -507,22 +512,21 @@ class FittingView(d.Display): srcContext = "fittingModule" itemContext = sMkt.getCategoryByItem(mod.item).name fullContext = (srcContext, itemContext) - if not srcContext in tuple(fCtxt[0] for fCtxt in contexts): + if srcContext not in tuple(fCtxt[0] for fCtxt in contexts): contexts.append(fullContext) - if mod.charge is not None: srcContext = "fittingCharge" itemContext = sMkt.getCategoryByItem(mod.charge).name fullContext = (srcContext, itemContext) - if not srcContext in tuple(fCtxt[0] for fCtxt in contexts): + if srcContext not in tuple(fCtxt[0] for fCtxt in contexts): contexts.append(fullContext) selection.append(mod) sel = self.GetNextSelected(sel) - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(self.activeFitID) contexts.append(("fittingShip", "Ship" if not fit.isStructure else "Citadel")) @@ -545,7 +549,7 @@ class FittingView(d.Display): sel = [] curr = self.GetFirstSelected() - while curr != -1 and row not in self.blanks : + while curr != -1 and row not in self.blanks: sel.append(curr) curr = self.GetNextSelected(curr) @@ -554,7 +558,7 @@ class FittingView(d.Display): else: mods = self.getSelectedMods() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() ctrl = wx.GetMouseState().CmdDown() or wx.GetMouseState().MiddleDown() click = "ctrl" if ctrl is True else "right" if event.GetButton() == 3 else "left" @@ -588,7 +592,7 @@ class FittingView(d.Display): self.Freeze() d.Display.refresh(self, stuff) - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(self.activeFitID) slotMap = {} @@ -626,7 +630,7 @@ class FittingView(d.Display): try: self.MakeSnapshot() except: - pass + pass def OnShow(self, event): if event.GetShow(): @@ -639,22 +643,22 @@ class FittingView(d.Display): def Snapshot(self): return self.FVsnapshot - def MakeSnapshot(self, maxColumns = 1337): + def MakeSnapshot(self, maxColumns=1337): if self.FVsnapshot: del self.FVsnapshot - tbmp = wx.EmptyBitmap(16,16) + tbmp = wx.EmptyBitmap(16, 16) tdc = wx.MemoryDC() tdc.SelectObject(tbmp) font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) tdc.SetFont(font) columnsWidths = [] - for i in xrange(len(self.DEFAULT_COLS)): + for i in range(len(self.DEFAULT_COLS)): columnsWidths.append(0) - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() try: fit = sFit.getFit(self.activeFitID) except: @@ -675,25 +679,25 @@ class FittingView(d.Display): maxWidth = 0 maxRowHeight = isize rows = 0 - for id,st in enumerate(self.mods): + for st in self.mods: for i, col in enumerate(self.activeColumns): - if i>maxColumns: + if i > maxColumns: break name = col.getText(st) if not isinstance(name, basestring): name = "" - nx,ny = tdc.GetTextExtent(name) + nx, ny = tdc.GetTextExtent(name) imgId = col.getImageId(st) cw = 0 if imgId != -1: cw += isize + padding if name != "": - cw += nx + 4*padding + cw += nx + 4 * padding if imgId == -1 and name == "": - cw += isize +padding + cw += isize + padding maxRowHeight = max(ny, maxRowHeight) columnsWidths[i] = max(columnsWidths[i], cw) @@ -702,7 +706,7 @@ class FittingView(d.Display): render = wx.RendererNative.Get() - #Fix column widths (use biggest between header or items) + # Fix column widths (use biggest between header or items) for i, col in enumerate(self.activeColumns): if i > maxColumns: @@ -720,26 +724,23 @@ class FittingView(d.Display): opts.m_labelText = name if imgId != -1: - opts.m_labelBitmap = wx.EmptyBitmap(isize,isize) + opts.m_labelBitmap = wx.EmptyBitmap(isize, isize) - width = render.DrawHeaderButton(self, tdc, (0, 0, 16, 16), - sortArrow = wx.HDR_SORT_ICON_NONE, params = opts) + width = render.DrawHeaderButton(self, tdc, (0, 0, 16, 16), sortArrow=wx.HDR_SORT_ICON_NONE, params=opts) columnsWidths[i] = max(columnsWidths[i], width) tdc.SelectObject(wx.NullBitmap) - maxWidth = padding * 2 - for i in xrange(len(self.DEFAULT_COLS)): + for i in range(len(self.DEFAULT_COLS)): if i > maxColumns: break maxWidth += columnsWidths[i] - mdc = wx.MemoryDC() - mbmp = wx.EmptyBitmap(maxWidth, (maxRowHeight) * rows + padding*4 + headerSize) + mbmp = wx.EmptyBitmap(maxWidth, (maxRowHeight) * rows + padding * 4 + headerSize) mdc.SelectObject(mbmp) @@ -769,8 +770,8 @@ class FittingView(d.Display): bmp = col.bitmap opts.m_labelBitmap = bmp - width = render.DrawHeaderButton (self, mdc, (cx, padding, columnsWidths[i], headerSize), wx.CONTROL_CURRENT, - sortArrow = wx.HDR_SORT_ICON_NONE, params = opts) + width = render.DrawHeaderButton(self, mdc, (cx, padding, columnsWidths[i], headerSize), wx.CONTROL_CURRENT, + sortArrow=wx.HDR_SORT_ICON_NONE, params=opts) cx += columnsWidths[i] @@ -780,15 +781,15 @@ class FittingView(d.Display): mdc.SetPen(pen) mdc.SetBrush(brush) - cy = padding*2 + headerSize - for id,st in enumerate(self.mods): + cy = padding * 2 + headerSize + for st in self.mods: cx = padding if slotMap[st.slot]: - mdc.DrawRectangle(cx,cy,maxWidth - cx,maxRowHeight) + mdc.DrawRectangle(cx, cy, maxWidth - cx, maxRowHeight) for i, col in enumerate(self.activeColumns): - if i>maxColumns: + if i > maxColumns: break name = col.getText(st) @@ -799,14 +800,14 @@ class FittingView(d.Display): tcx = cx if imgId != -1: - self.imageList.Draw(imgId,mdc,cx,cy,wx.IMAGELIST_DRAW_TRANSPARENT,False) + self.imageList.Draw(imgId, mdc, cx, cy, wx.IMAGELIST_DRAW_TRANSPARENT, False) tcx += isize + padding if name != "": - nx,ny = mdc.GetTextExtent(name) + nx, ny = mdc.GetTextExtent(name) rect = wx.Rect() rect.top = cy - rect.left = cx + 2*padding + rect.left = cx + 2 * padding rect.width = nx rect.height = maxRowHeight + padding mdc.DrawLabel(name, rect, wx.ALIGN_CENTER_VERTICAL) @@ -818,4 +819,4 @@ class FittingView(d.Display): mdc.SelectObject(wx.NullBitmap) - self.FVsnapshot = mbmp \ No newline at end of file + self.FVsnapshot = mbmp diff --git a/gui/builtinViews/implantEditor.py b/gui/builtinViews/implantEditor.py index bcdb96c7b..8b56833df 100644 --- a/gui/builtinViews/implantEditor.py +++ b/gui/builtinViews/implantEditor.py @@ -1,12 +1,14 @@ import wx -import service -import gui.display as d -from gui.bitmapLoader import BitmapLoader -import gui.PFSearchBox as SBox -from gui.marketBrowser import SearchBox from wx.lib.buttons import GenBitmapButton -class BaseImplantEditorView (wx.Panel): +from service.market import Market +import gui.display as d +import gui.PFSearchBox as SBox +from gui.bitmapLoader import BitmapLoader +from gui.marketBrowser import SearchBox + + +class BaseImplantEditorView(wx.Panel): def addMarketViewImage(self, iconFile): if iconFile is None: return -1 @@ -17,7 +19,8 @@ class BaseImplantEditorView (wx.Panel): return self.availableImplantsImageList.Add(bitmap) def __init__(self, parent): - wx.Panel.__init__ (self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.TAB_TRAVERSAL) + wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, + style=wx.TAB_TRAVERSAL) self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) pmainSizer = wx.BoxSizer(wx.HORIZONTAL) @@ -46,32 +49,32 @@ class BaseImplantEditorView (wx.Panel): availableSizer.Add(self.availableImplantsTree, 1, wx.EXPAND) - pmainSizer.Add(availableSizer, 1, wx.ALL | wx.EXPAND, 5) - buttonSizer = wx.BoxSizer(wx.VERTICAL) - buttonSizer.AddSpacer(( 0, 0), 1) + buttonSizer.AddSpacer((0, 0), 1) - self.btnAdd = GenBitmapButton(self, wx.ID_ADD, BitmapLoader.getBitmap("fit_add_small", "gui"), style = wx.BORDER_NONE) + self.btnAdd = GenBitmapButton(self, wx.ID_ADD, BitmapLoader.getBitmap("fit_add_small", "gui"), + style=wx.BORDER_NONE) buttonSizer.Add(self.btnAdd, 0) - self.btnRemove = GenBitmapButton(self, wx.ID_REMOVE, BitmapLoader.getBitmap("fit_delete_small", "gui"), style = wx.BORDER_NONE) + self.btnRemove = GenBitmapButton(self, wx.ID_REMOVE, BitmapLoader.getBitmap("fit_delete_small", "gui"), + style=wx.BORDER_NONE) buttonSizer.Add(self.btnRemove, 0) - buttonSizer.AddSpacer(( 0, 0), 1) + buttonSizer.AddSpacer((0, 0), 1) pmainSizer.Add(buttonSizer, 0, wx.EXPAND, 0) characterImplantSizer = wx.BoxSizer(wx.VERTICAL) self.pluggedImplantsTree = AvailableImplantsView(self) - characterImplantSizer.Add(self.pluggedImplantsTree, 1, wx.ALL|wx.EXPAND, 5) + characterImplantSizer.Add(self.pluggedImplantsTree, 1, wx.ALL | wx.EXPAND, 5) pmainSizer.Add(characterImplantSizer, 1, wx.EXPAND, 5) self.SetSizer(pmainSizer) # Populate the market tree - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() for mktGrp in sMkt.getImplantTree(): iconId = self.addMarketViewImage(sMkt.getIconByMarketGroup(mktGrp)) childId = self.availableImplantsTree.AppendItem(root, mktGrp.name, iconId, data=wx.TreeItemData(mktGrp.ID)) @@ -80,13 +83,13 @@ class BaseImplantEditorView (wx.Panel): self.availableImplantsTree.SortChildren(self.availableRoot) - #Bind the event to replace dummies by real data + # Bind the event to replace dummies by real data self.availableImplantsTree.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.expandLookup) self.availableImplantsTree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.itemSelected) self.itemView.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.itemSelected) - #Bind add & remove buttons + # Bind add & remove buttons self.btnAdd.Bind(wx.EVT_BUTTON, self.itemSelected) self.btnRemove.Bind(wx.EVT_BUTTON, self.removeItem) @@ -126,7 +129,7 @@ class BaseImplantEditorView (wx.Panel): def expandLookup(self, event): tree = self.availableImplantsTree - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() parent = event.Item child, _ = tree.GetFirstChild(parent) text = tree.GetItemText(child) @@ -136,7 +139,7 @@ class BaseImplantEditorView (wx.Panel): # if the dummy item is a market group, replace with actual market groups if text == "dummy": - #Add 'real stoof!' instead + # Add 'real stoof!' instead currentMktGrp = sMkt.getMarketGroup(tree.GetPyData(parent), eager="children") for childMktGrp in sMkt.getMarketGroupChildren(currentMktGrp): iconId = self.addMarketViewImage(sMkt.getIconByMarketGroup(childMktGrp)) @@ -194,6 +197,7 @@ class BaseImplantEditorView (wx.Panel): self.removeImplantFromContext(self.implants[pos]) self.update() + class AvailableImplantsView(d.Display): DEFAULT_COLS = ["attr:implantness", "Base Icon", @@ -203,6 +207,7 @@ class AvailableImplantsView(d.Display): d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL) self.Bind(wx.EVT_LEFT_DCLICK, parent.removeItem) + class ItemView(d.Display): DEFAULT_COLS = ["Base Icon", "Base Name", @@ -235,7 +240,7 @@ class ItemView(d.Display): self.update(self.items) def scheduleSearch(self, event=None): - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() search = self.searchBox.GetLineText(0) # Make sure we do not count wildcard as search symbol @@ -255,4 +260,4 @@ class ItemView(d.Display): self.items = sorted(list(items), key=lambda i: i.name) - self.update(self.items) \ No newline at end of file + self.update(self.items) diff --git a/gui/cachingImageList.py b/gui/cachingImageList.py index 4ec0b2f69..aceff6775 100644 --- a/gui/cachingImageList.py +++ b/gui/cachingImageList.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,21 +15,23 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= + import wx from gui.bitmapLoader import BitmapLoader + class CachingImageList(wx.ImageList): def __init__(self, width, height): wx.ImageList.__init__(self, width, height) self.map = {} def GetImageIndex(self, *loaderArgs): - id = self.map.get(loaderArgs) - if id is None: + id_ = self.map.get(loaderArgs) + if id_ is None: bitmap = BitmapLoader.getBitmap(*loaderArgs) if bitmap is None: return -1 - id = self.map[loaderArgs] = wx.ImageList.Add(self,bitmap) - return id + id_ = self.map[loaderArgs] = wx.ImageList.Add(self, bitmap) + return id_ diff --git a/gui/cargoView.py b/gui/cargoView.py index 91bfb2b5f..6fe9e3c9e 100644 --- a/gui/cargoView.py +++ b/gui/cargoView.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,31 +15,33 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx -import service import gui.display as d -import gui.marketBrowser as mb from gui.builtinViewColumns.state import State from gui.contextMenu import ContextMenu import globalEvents as GE +from service.fit import Fit +from service.market import Market + class CargoViewDrop(wx.PyDropTarget): - def __init__(self, dropFn): - wx.PyDropTarget.__init__(self) - self.dropFn = dropFn - # this is really transferring an EVE itemID - self.dropData = wx.PyTextDataObject() - self.SetDataObject(self.dropData) + def __init__(self, dropFn): + wx.PyDropTarget.__init__(self) + self.dropFn = dropFn + # this is really transferring an EVE itemID + self.dropData = wx.PyTextDataObject() + self.SetDataObject(self.dropData) - def OnData(self, x, y, t): - if self.GetData(): - data = self.dropData.GetText().split(':') - self.dropFn(x, y, data) - return t + def OnData(self, x, y, t): + if self.GetData(): + data = self.dropData.GetText().split(':') + self.dropFn(x, y, data) + return t -# @todo: Was copied form another class and modified. Look through entire file, refine + +# @todo: Was copied form another class and modified. Look through entire file, refine class CargoView(d.Display): DEFAULT_COLS = ["Base Icon", "Base Name", @@ -58,7 +60,7 @@ class CargoView(d.Display): self.SetDropTarget(CargoViewDrop(self.handleListDrag)) self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.startDrag) - if "__WXGTK__" in wx.PlatformInfo: + if "__WXGTK__" in wx.PlatformInfo: self.Bind(wx.EVT_RIGHT_UP, self.scheduleMenu) else: self.Bind(wx.EVT_RIGHT_DOWN, self.scheduleMenu) @@ -75,7 +77,7 @@ class CargoView(d.Display): if data[0] == "fitting": self.swapModule(x, y, int(data[1])) elif data[0] == "market": - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() sFit.addCargo(self.mainFrame.getActiveFit(), int(data[1]), 1) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit())) @@ -84,17 +86,17 @@ class CargoView(d.Display): if row != -1: data = wx.PyTextDataObject() - data.SetText("cargo:"+str(row)) + data.SetText("cargo:" + str(row)) dropSource = wx.DropSource(self) dropSource.SetData(data) - res = dropSource.DoDragDrop() + dropSource.DoDragDrop() - def kbEvent(self,event): + def kbEvent(self, event): keycode = event.GetKeyCode() if keycode == wx.WXK_DELETE or keycode == wx.WXK_NUMPAD_DELETE: fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() row = self.GetFirstSelected() if row != -1: sFit.removeCargo(fitID, self.GetItemData(row)) @@ -103,7 +105,7 @@ class CargoView(d.Display): def swapModule(self, x, y, modIdx): '''Swap a module from fitting window with cargo''' - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(self.mainFrame.getActiveFit()) dstRow, _ = self.HitTest((x, y)) mstate = wx.GetMouseState() @@ -111,26 +113,26 @@ class CargoView(d.Display): # Gather module information to get position module = fit.modules[modIdx] - if dstRow != -1: # we're swapping with cargo - if mstate.CmdDown(): # if copying, append to cargo + if dstRow != -1: # we're swapping with cargo + if mstate.CmdDown(): # if copying, append to cargo sFit.addCargo(self.mainFrame.getActiveFit(), module.item.ID) - else: # else, move / swap + else: # else, move / swap sFit.moveCargoToModule(self.mainFrame.getActiveFit(), module.position, dstRow) - else: # dragging to blank spot, append + else: # dragging to blank spot, append sFit.addCargo(self.mainFrame.getActiveFit(), module.item.ID) - if not mstate.CmdDown(): # if not copying, remove module - sFit.removeModule(self.mainFrame.getActiveFit(), module.position) + 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())) def fitChanged(self, event): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(event.fitID) self.Parent.Parent.DisablePage(self, not fit or fit.isStructure) - #Clear list and get out if current fitId is None + # Clear list and get out if current fitId is None if event.fitID is None and self.lastFitId is not None: self.DeleteAllItems() self.lastFitId = None @@ -139,7 +141,8 @@ class CargoView(d.Display): self.original = fit.cargo if fit is not None else None self.cargo = stuff = fit.cargo if fit is not None else None - if stuff is not None: stuff.sort(key=lambda cargo: cargo.itemID) + if stuff is not None: + stuff.sort(key=lambda cargo: cargo.itemID) if event.fitID != self.lastFitId: self.lastFitId = event.fitID @@ -161,7 +164,7 @@ class CargoView(d.Display): col = self.getColumn(event.Position) if col != self.getColIndex(State): fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() cargo = self.cargo[self.GetItemData(row)] sFit.removeCargo(fitID, self.original.index(cargo)) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) @@ -174,11 +177,11 @@ class CargoView(d.Display): def spawnMenu(self): sel = self.GetFirstSelected() if sel != -1: - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(self.mainFrame.getActiveFit()) cargo = fit.cargo[sel] - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() sourceContext = "cargoItem" itemContext = sMkt.getCategoryByItem(cargo.item).name diff --git a/gui/characterEditor.py b/gui/characterEditor.py index 2a8d90afc..421ed8bbc 100644 --- a/gui/characterEditor.py +++ b/gui/characterEditor.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,18 +15,21 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx import wx.lib.newevent import wx.gizmos from gui.bitmapLoader import BitmapLoader -import service from gui.contextMenu import ContextMenu import gui.globalEvents as GE from gui.builtinViews.implantEditor import BaseImplantEditorView from gui.builtinViews.entityEditor import EntityEditor, BaseValidator +from service.fit import Fit +from service.character import Character +from service.network import AuthenticationError, TimeoutError +from service.market import Market class CharacterTextValidor(BaseValidator): @@ -60,7 +63,7 @@ class CharacterEntityEditor(EntityEditor): self.SetEditorValidator(CharacterTextValidor) def getEntitiesFromContext(self): - sChar = service.Character.getInstance() + sChar = Character.getInstance() charList = sorted(sChar.getCharacterList(), key=lambda c: c.name) # Do some processing to ensure that we have All 0 and All 5 at the top @@ -76,35 +79,35 @@ class CharacterEntityEditor(EntityEditor): return charList def DoNew(self, name): - sChar = service.Character.getInstance() + sChar = Character.getInstance() return sChar.new(name) def DoRename(self, entity, name): - sChar = service.Character.getInstance() + sChar = Character.getInstance() sChar.rename(entity, name) def DoCopy(self, entity, name): - sChar = service.Character.getInstance() + sChar = Character.getInstance() copy = sChar.copy(entity) sChar.rename(copy, name) return copy def DoDelete(self, entity): - sChar = service.Character.getInstance() + sChar = Character.getInstance() sChar.delete(entity) class CharacterEditor(wx.Frame): def __init__(self, parent): - wx.Frame.__init__ (self, parent, id=wx.ID_ANY, title=u"pyfa: Character Editor", pos=wx.DefaultPosition, - size=wx.Size(640, 600), style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER) + wx.Frame.__init__(self, parent, id=wx.ID_ANY, title=u"pyfa: Character Editor", pos=wx.DefaultPosition, + size=wx.Size(640, 600), style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER) i = wx.IconFromBitmap(BitmapLoader.getBitmap("character_small", "gui")) self.SetIcon(i) self.mainFrame = parent - #self.disableWin = wx.WindowDisabler(self) - sFit = service.Fit.getInstance() + # self.disableWin = wx.WindowDisabler(self) + sFit = Fit.getInstance() self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE)) @@ -178,12 +181,12 @@ class CharacterEditor(wx.Frame): event.Skip() def editingFinished(self, event): - #del self.disableWin + # del self.disableWin wx.PostEvent(self.mainFrame, GE.CharListUpdated()) self.Destroy() def saveChar(self, event): - sChr = service.Character.getInstance() + sChr = Character.getInstance() char = self.entityEditor.getActiveEntity() sChr.saveCharacter(char.ID) wx.PostEvent(self, GE.CharListUpdated()) @@ -194,13 +197,13 @@ class CharacterEditor(wx.Frame): dlg.ShowModal() def revertChar(self, event): - sChr = service.Character.getInstance() + sChr = Character.getInstance() char = self.entityEditor.getActiveEntity() sChr.revertCharacter(char.ID) wx.PostEvent(self, GE.CharListUpdated()) def closeEvent(self, event): - #del self.disableWin + # del self.disableWin wx.PostEvent(self.mainFrame, GE.CharListUpdated()) self.Destroy() @@ -225,7 +228,7 @@ class CharacterEditor(wx.Frame): event.Skip() def Destroy(self): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() if fitID is not None: sFit.clearFit(fitID) @@ -233,18 +236,35 @@ class CharacterEditor(wx.Frame): wx.Frame.Destroy(self) -class SkillTreeView (wx.Panel): + +class SkillTreeView(wx.Panel): def __init__(self, parent): - wx.Panel.__init__ (self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.TAB_TRAVERSAL) + wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, + style=wx.TAB_TRAVERSAL) self.charEditor = self.Parent.Parent # first parent is Notebook, second is Character Editor self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) pmainSizer = wx.BoxSizer(wx.VERTICAL) + self.clonesChoice = wx.Choice(self, wx.ID_ANY, style=0) + i = self.clonesChoice.Append("Omega Clone", None) + self.clonesChoice.SetSelection(i) + pmainSizer.Add(self.clonesChoice, 0, wx.ALL | wx.EXPAND, 5) + + sChar = Character.getInstance() + self.alphaClones = sChar.getAlphaCloneList() + char = self.charEditor.entityEditor.getActiveEntity() + + for clone in self.alphaClones: + i = self.clonesChoice.Append(clone.alphaCloneName, clone.ID) + if clone.ID == char.alphaCloneID: + self.clonesChoice.SetSelection(i) + + self.clonesChoice.Bind(wx.EVT_CHOICE, self.cloneChanged) + tree = self.skillTreeListCtrl = wx.gizmos.TreeListCtrl(self, wx.ID_ANY, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT) pmainSizer.Add(tree, 1, wx.EXPAND | wx.ALL, 5) - self.imageList = wx.ImageList(16, 16) tree.SetImageList(self.imageList) self.skillBookImageId = self.imageList.Add(BitmapLoader.getBitmap("skill_small", "gui")) @@ -264,7 +284,7 @@ class SkillTreeView (wx.Panel): tree.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.scheduleMenu) # bind the Character selection event - self.charEditor.entityEditor.Bind(wx.EVT_CHOICE, self.populateSkillTree) + self.charEditor.entityEditor.Bind(wx.EVT_CHOICE, self.charChanged) self.charEditor.Bind(GE.CHAR_LIST_UPDATED, self.populateSkillTree) srcContext = "skillItem" @@ -288,7 +308,6 @@ class SkillTreeView (wx.Panel): self.revertID = wx.NewId() self.levelChangeMenu.Append(self.revertID, "Revert") - self.saveID = wx.NewId() self.levelChangeMenu.Append(self.saveID, "Save") @@ -297,11 +316,30 @@ class SkillTreeView (wx.Panel): self.Layout() + def cloneChanged(self, event): + sChar = Character.getInstance() + sChar.setAlphaClone(self.charEditor.entityEditor.getActiveEntity(), event.ClientData) + self.populateSkillTree() + + def charChanged(self, event=None): + char = self.charEditor.entityEditor.getActiveEntity() + for i in range(self.clonesChoice.GetCount()): + cloneID = self.clonesChoice.GetClientData(i) + if char.alphaCloneID == cloneID: + self.clonesChoice.SetSelection(i) + + self.populateSkillTree(event) + def populateSkillTree(self, event=None): - sChar = service.Character.getInstance() + sChar = Character.getInstance() char = self.charEditor.entityEditor.getActiveEntity() dirtyGroups = set([skill.item.group.ID for skill in char.dirtySkills]) + if char.name in ("All 0", "All 5"): + self.clonesChoice.Disable() + else: + self.clonesChoice.Enable() + groups = sChar.getSkillGroups() imageId = self.skillBookImageId root = self.root @@ -327,8 +365,8 @@ class SkillTreeView (wx.Panel): if tree.GetItemText(child) == "dummy": tree.Delete(child) - #Get the real intrestin' stuff - sChar = service.Character.getInstance() + # Get the real intrestin' stuff + sChar = Character.getInstance() char = self.charEditor.entityEditor.getActiveEntity() for id, name in sChar.getSkills(tree.GetPyData(root)): iconId = self.skillBookImageId @@ -350,7 +388,7 @@ class SkillTreeView (wx.Panel): return char = self.charEditor.entityEditor.getActiveEntity() - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() if char.name not in ("All 0", "All 5"): self.levelChangeMenu.selection = sMkt.getItem(self.skillTreeListCtrl.GetPyData(item)) self.PopupMenu(self.levelChangeMenu) @@ -361,7 +399,7 @@ class SkillTreeView (wx.Panel): def changeLevel(self, event): level = self.levelIds.get(event.Id) - sChar = service.Character.getInstance() + sChar = Character.getInstance() char = self.charEditor.entityEditor.getActiveEntity() selection = self.skillTreeListCtrl.GetSelection() skillID = self.skillTreeListCtrl.GetPyData(selection) @@ -390,7 +428,7 @@ class SkillTreeView (wx.Panel): class ImplantEditorView(BaseImplantEditorView): def __init__(self, parent): - BaseImplantEditorView.__init__ (self, parent) + BaseImplantEditorView.__init__(self, parent) self.determineEnabled() @@ -407,19 +445,19 @@ class ImplantEditorView(BaseImplantEditorView): self.determineEnabled() def getImplantsFromContext(self): - sChar = service.Character.getInstance() + sChar = Character.getInstance() char = self.Parent.Parent.entityEditor.getActiveEntity() return sChar.getImplants(char.ID) def addImplantToContext(self, item): - sChar = service.Character.getInstance() + sChar = Character.getInstance() char = self.Parent.Parent.entityEditor.getActiveEntity() sChar.addImplant(char.ID, item.ID) def removeImplantFromContext(self, implant): - sChar = service.Character.getInstance() + sChar = Character.getInstance() char = self.Parent.Parent.entityEditor.getActiveEntity() sChar.removeImplant(char.ID, implant) @@ -444,9 +482,10 @@ class ImplantEditorView(BaseImplantEditorView): self.Enable() -class APIView (wx.Panel): +class APIView(wx.Panel): def __init__(self, parent): - wx.Panel.__init__ (self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(500, 300), style=wx.TAB_TRAVERSAL) + wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(500, 300), + style=wx.TAB_TRAVERSAL) self.charEditor = self.Parent.Parent # first parent is Notebook, second is Character Editor self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) @@ -455,17 +494,17 @@ class APIView (wx.Panel): pmainSizer = wx.BoxSizer(wx.VERTICAL) - hintSizer = wx.BoxSizer( wx.HORIZONTAL ) + hintSizer = wx.BoxSizer(wx.HORIZONTAL) hintSizer.AddStretchSpacer() - self.stDisabledTip = wx.StaticText( self, wx.ID_ANY, u"You cannot add API Details for All 0 and All 5 characters.\n" - u"Please select another character or make a new one.", style=wx.ALIGN_CENTER ) - self.stDisabledTip.Wrap( -1 ) - hintSizer.Add( self.stDisabledTip, 0, wx.TOP | wx.BOTTOM, 10 ) + self.stDisabledTip = wx.StaticText(self, wx.ID_ANY, + u"You cannot add API Details for All 0 and All 5 characters.\n" + u"Please select another character or make a new one.", style=wx.ALIGN_CENTER) + self.stDisabledTip.Wrap(-1) + hintSizer.Add(self.stDisabledTip, 0, wx.TOP | wx.BOTTOM, 10) self.stDisabledTip.Hide() hintSizer.AddStretchSpacer() pmainSizer.Add(hintSizer, 0, wx.EXPAND, 5) - fgSizerInput = wx.FlexGridSizer(3, 2, 0, 0) fgSizerInput.AddGrowableCol(1) fgSizerInput.SetFlexibleDirection(wx.BOTH) @@ -497,39 +536,44 @@ class APIView (wx.Panel): pmainSizer.Add(fgSizerInput, 0, wx.EXPAND, 5) - btnSizer = wx.BoxSizer( wx.HORIZONTAL ) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) btnSizer.AddStretchSpacer() self.btnFetchCharList = wx.Button(self, wx.ID_ANY, u"Get Characters") btnSizer.Add(self.btnFetchCharList, 0, wx.ALL, 2) self.btnFetchCharList.Bind(wx.EVT_BUTTON, self.fetchCharList) - self.btnFetchSkills = wx.Button(self, wx.ID_ANY, u"Fetch Skills") - btnSizer.Add(self.btnFetchSkills, 0, wx.ALL, 2) + self.btnFetchSkills = wx.Button(self, wx.ID_ANY, u"Fetch Skills") + btnSizer.Add(self.btnFetchSkills, 0, wx.ALL, 2) self.btnFetchSkills.Bind(wx.EVT_BUTTON, self.fetchSkills) self.btnFetchSkills.Enable(False) btnSizer.AddStretchSpacer() pmainSizer.Add(btnSizer, 0, wx.EXPAND, 5) - self.stStatus = wx.StaticText(self, wx.ID_ANY, wx.EmptyString) + self.stStatus = wx.StaticText(self, wx.ID_ANY, wx.EmptyString) pmainSizer.Add(self.stStatus, 0, wx.ALL, 5) pmainSizer.AddStretchSpacer() - self.stAPITip = wx.StaticText( self, wx.ID_ANY, u"You can create a pre-defined key here (only CharacterSheet is required):", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.stAPITip.Wrap( -1 ) + self.stAPITip = wx.StaticText(self, wx.ID_ANY, + u"You can create a pre-defined key here (only CharacterSheet is required):", + wx.DefaultPosition, wx.DefaultSize, 0) + self.stAPITip.Wrap(-1) - pmainSizer.Add( self.stAPITip, 0, wx.ALL, 2 ) + pmainSizer.Add(self.stAPITip, 0, wx.ALL, 2) - self.hlEveAPI = wx.HyperlinkCtrl( self, wx.ID_ANY, self.apiUrlCreatePredefined, self.apiUrlCreatePredefined, wx.DefaultPosition, wx.DefaultSize, wx.HL_DEFAULT_STYLE ) - pmainSizer.Add( self.hlEveAPI, 0, wx.ALL, 2 ) + self.hlEveAPI = wx.HyperlinkCtrl(self, wx.ID_ANY, self.apiUrlCreatePredefined, self.apiUrlCreatePredefined, + wx.DefaultPosition, wx.DefaultSize, wx.HL_DEFAULT_STYLE) + pmainSizer.Add(self.hlEveAPI, 0, wx.ALL, 2) - self.stAPITip2 = wx.StaticText( self, wx.ID_ANY, u"Or, you can choose an existing key from:", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.stAPITip2.Wrap( -1 ) - pmainSizer.Add( self.stAPITip2, 0, wx.ALL, 2 ) + self.stAPITip2 = wx.StaticText(self, wx.ID_ANY, u"Or, you can choose an existing key from:", wx.DefaultPosition, + wx.DefaultSize, 0) + self.stAPITip2.Wrap(-1) + pmainSizer.Add(self.stAPITip2, 0, wx.ALL, 2) - self.hlEveAPI2 = wx.HyperlinkCtrl( self, wx.ID_ANY, self.apiUrlKeyList, self.apiUrlKeyList, wx.DefaultPosition, wx.DefaultSize, wx.HL_DEFAULT_STYLE ) - pmainSizer.Add( self.hlEveAPI2, 0, wx.ALL, 2 ) + self.hlEveAPI2 = wx.HyperlinkCtrl(self, wx.ID_ANY, self.apiUrlKeyList, self.apiUrlKeyList, wx.DefaultPosition, + wx.DefaultSize, wx.HL_DEFAULT_STYLE) + pmainSizer.Add(self.hlEveAPI2, 0, wx.ALL, 2) self.charEditor.entityEditor.Bind(wx.EVT_CHOICE, self.charChanged) @@ -538,7 +582,7 @@ class APIView (wx.Panel): self.charChanged(None) def charChanged(self, event): - sChar = service.Character.getInstance() + sChar = Character.getInstance() activeChar = self.charEditor.entityEditor.getActiveEntity() ID, key, char, chars = sChar.getApiDetails(activeChar.ID) @@ -549,7 +593,7 @@ class APIView (wx.Panel): if chars: for charName in chars: - i = self.charChoice.Append(charName) + self.charChoice.Append(charName) self.charChoice.SetStringSelection(char) self.charChoice.Enable(True) self.btnFetchSkills.Enable(True) @@ -577,20 +621,20 @@ class APIView (wx.Panel): self.stStatus.SetLabel("Invalid keyID or vCode!") return - sChar = service.Character.getInstance() + sChar = Character.getInstance() try: activeChar = self.charEditor.entityEditor.getActiveEntity() list = sChar.apiCharList(activeChar.ID, self.inputID.GetLineText(0), self.inputKey.GetLineText(0)) - except service.network.AuthenticationError, e: + except AuthenticationError, e: self.stStatus.SetLabel("Authentication failure. Please check keyID and vCode combination.") - except service.network.TimeoutError, e: + except TimeoutError, e: self.stStatus.SetLabel("Request timed out. Please check network connectivity and/or proxy settings.") except Exception, e: - self.stStatus.SetLabel("Error:\n%s"%e.message) + self.stStatus.SetLabel("Error:\n%s" % e.message) else: self.charChoice.Clear() for charName in list: - i = self.charChoice.Append(charName) + self.charChoice.Append(charName) self.btnFetchSkills.Enable(True) self.charChoice.Enable(True) @@ -603,20 +647,20 @@ class APIView (wx.Panel): charName = self.charChoice.GetString(self.charChoice.GetSelection()) if charName: try: - sChar = service.Character.getInstance() + sChar = Character.getInstance() activeChar = self.charEditor.entityEditor.getActiveEntity() sChar.apiFetch(activeChar.ID, charName) self.stStatus.SetLabel("Successfully fetched %s\'s skills from EVE API." % charName) except Exception, e: self.stStatus.SetLabel("Unable to retrieve %s\'s skills. Error message:\n%s" % (charName, e)) -class SaveCharacterAs(wx.Dialog): +class SaveCharacterAs(wx.Dialog): def __init__(self, parent, charID): wx.Dialog.__init__(self, parent, title="Save Character As...", size=wx.Size(300, 60)) self.charID = charID self.parent = parent - sChar = service.Character.getInstance() + sChar = Character.getInstance() name = sChar.getCharName(charID) bSizer1 = wx.BoxSizer(wx.HORIZONTAL) @@ -633,10 +677,9 @@ class SaveCharacterAs(wx.Dialog): self.button.Bind(wx.EVT_BUTTON, self.change) def change(self, event): - sChar = service.Character.getInstance() + sChar = Character.getInstance() sChar.saveCharacterAs(self.charID, self.input.GetLineText(0)) wx.PostEvent(self.parent, GE.CharListUpdated()) event.Skip() self.Close() - \ No newline at end of file diff --git a/gui/characterSelection.py b/gui/characterSelection.py index 47df7e018..b63f87475 100644 --- a/gui/characterSelection.py +++ b/gui/characterSelection.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,13 +15,15 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx -import service from gui.bitmapLoader import BitmapLoader import gui.globalEvents as GE import gui.mainFrame +from service.character import Character +from service.fit import Fit + class CharacterSelection(wx.Panel): def __init__(self, parent): @@ -42,9 +44,9 @@ class CharacterSelection(wx.Panel): self.refreshCharacterList() self.cleanSkills = BitmapLoader.getBitmap("skill_big", "gui") - self.redSkills = BitmapLoader.getBitmap("skillRed_big", "gui") + self.redSkills = BitmapLoader.getBitmap("skillRed_big", "gui") self.greenSkills = BitmapLoader.getBitmap("skillGreen_big", "gui") - self.refresh = BitmapLoader.getBitmap("refresh", "gui") + self.refresh = BitmapLoader.getBitmap("refresh", "gui") self.btnRefresh = wx.BitmapButton(self, wx.ID_ANY, self.refresh) size = self.btnRefresh.GetSize() @@ -66,7 +68,7 @@ class CharacterSelection(wx.Panel): self.mainFrame.Bind(GE.CHAR_LIST_UPDATED, self.refreshCharacterList) self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) - self.SetMinSize(wx.Size(25,-1)) + self.SetMinSize(wx.Size(25, -1)) self.charChoice.Enable(False) @@ -76,7 +78,7 @@ class CharacterSelection(wx.Panel): def refreshCharacterList(self, event=None): choice = self.charChoice - sChar = service.Character.getInstance() + sChar = Character.getInstance() activeChar = self.getActiveCharacter() choice.Clear() @@ -94,7 +96,7 @@ class CharacterSelection(wx.Panel): charID = sChar.all5ID() self.selectChar(charID) fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() sFit.changeChar(fitID, charID) choice.Append(u"\u2015 Open Character Editor \u2015", -1) @@ -104,7 +106,7 @@ class CharacterSelection(wx.Panel): event.Skip() def refreshApi(self, event): - sChar = service.Character.getInstance() + sChar = Character.getInstance() ID, key, charName, chars = sChar.getApiDetails(self.getActiveCharacter()) if charName: try: @@ -117,7 +119,7 @@ class CharacterSelection(wx.Panel): def charChanged(self, event): fitID = self.mainFrame.getActiveFit() charID = self.getActiveCharacter() - sChar = service.Character.getInstance() + sChar = Character.getInstance() if charID == -1: # revert to previous character @@ -129,7 +131,7 @@ class CharacterSelection(wx.Panel): else: self.btnRefresh.Enable(False) - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() sFit.changeChar(fitID, charID) self.charCache = self.charChoice.GetCurrentSelection() wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) @@ -137,18 +139,18 @@ class CharacterSelection(wx.Panel): def selectChar(self, charID): choice = self.charChoice numItems = len(choice.GetItems()) - for i in xrange(numItems): - id = choice.GetClientData(i) - if id == charID: + for i in range(numItems): + id_ = choice.GetClientData(i) + if id_ == charID: choice.SetSelection(i) return True return False def fitChanged(self, event): - self.charChoice.Enable(event.fitID != None) + self.charChoice.Enable(event.fitID is not None) choice = self.charChoice - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() currCharID = choice.GetClientData(choice.GetCurrentSelection()) fit = sFit.getFit(event.fitID) newCharID = fit.character.ID if fit is not None else None @@ -156,38 +158,37 @@ class CharacterSelection(wx.Panel): self.skillReqsStaticBitmap.SetBitmap(self.cleanSkills) self.skillReqsStaticBitmap.SetToolTipString("No active fit") else: - sCharacter = service.Character.getInstance() + sCharacter = Character.getInstance() reqs = sCharacter.checkRequirements(fit) - sCharacter.skillReqsDict = {'charname':fit.character.name, 'skills':[]} + sCharacter.skillReqsDict = {'charname': fit.character.name, 'skills': []} if len(reqs) == 0: tip = "All skill prerequisites have been met" self.skillReqsStaticBitmap.SetBitmap(self.greenSkills) else: - tip = "Skills required:\n" + tip = "Skills required:\n" condensed = sFit.serviceFittingOptions["compactSkills"] if condensed: - dict = self._buildSkillsTooltipCondensed(reqs, skillsMap = {}) - for key in sorted(dict): - tip += "%s: %d\n" % (key, dict[key]) + dict_ = self._buildSkillsTooltipCondensed(reqs, skillsMap={}) + for key in sorted(dict_): + tip += "%s: %d\n" % (key, dict_[key]) else: tip += self._buildSkillsTooltip(reqs) self.skillReqsStaticBitmap.SetBitmap(self.redSkills) self.skillReqsStaticBitmap.SetToolTipString(tip.strip()) - if newCharID == None: - sChar = service.Character.getInstance() + if newCharID is None: + sChar = Character.getInstance() self.selectChar(sChar.all5ID()) elif currCharID != newCharID: self.selectChar(newCharID) self.charChanged(None) - event.Skip() - def _buildSkillsTooltip(self, reqs, currItem = "", tabulationLevel = 0): + def _buildSkillsTooltip(self, reqs, currItem="", tabulationLevel=0): tip = "" - sCharacter = service.Character.getInstance() + sCharacter = Character.getInstance() if tabulationLevel == 0: for item, subReqs in reqs.iteritems(): @@ -197,11 +198,11 @@ class CharacterSelection(wx.Panel): for name, info in reqs.iteritems(): level, ID, more = info sCharacter.skillReqsDict['skills'].append({ - 'item' : currItem, - 'skillID' : ID, - 'skill' : name, - 'level' : level, - 'indent' : tabulationLevel + 'item': currItem, + 'skillID': ID, + 'skill': name, + 'level': level, + 'indent': tabulationLevel, }) tip += "%s%s: %d\n" % (" " * tabulationLevel, name, level) @@ -209,8 +210,11 @@ class CharacterSelection(wx.Panel): return tip - def _buildSkillsTooltipCondensed(self, reqs, currItem = "", tabulationLevel = 0, skillsMap = {}): - sCharacter = service.Character.getInstance() + def _buildSkillsTooltipCondensed(self, reqs, currItem="", tabulationLevel=0, skillsMap=None): + if skillsMap is None: + skillsMap = {} + + sCharacter = Character.getInstance() if tabulationLevel == 0: for item, subReqs in reqs.iteritems(): @@ -220,11 +224,11 @@ class CharacterSelection(wx.Panel): for name, info in reqs.iteritems(): level, ID, more = info sCharacter.skillReqsDict['skills'].append({ - 'item' : currItem, - 'skillID' : ID, - 'skill' : name, - 'level' : level, - 'indent' : tabulationLevel + 'item': currItem, + 'skillID': ID, + 'skill': name, + 'level': level, + 'indent': tabulationLevel, }) if name not in skillsMap: @@ -232,6 +236,6 @@ class CharacterSelection(wx.Panel): elif skillsMap[name] < level: skillsMap[name] = level - skillMap = self._buildSkillsTooltipCondensed(more, currItem, tabulationLevel + 1, skillsMap) + skillsMap = self._buildSkillsTooltipCondensed(more, currItem, tabulationLevel + 1, skillsMap) return skillsMap diff --git a/gui/chromeTabs.py b/gui/chromeTabs.py index bfc3adeb4..00998eb87 100644 --- a/gui/chromeTabs.py +++ b/gui/chromeTabs.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Darriele # # This file is part of pyfa. @@ -15,7 +15,7 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx import wx.lib.newevent @@ -23,9 +23,8 @@ import gui.utils.colorUtils as colorUtils import gui.utils.drawUtils as drawUtils import gui.utils.fonts as fonts from gui.bitmapLoader import BitmapLoader -import gui.utils.fonts as fonts -import service +from service.fit import Fit _PageChanging, EVT_NOTEBOOK_PAGE_CHANGING = wx.lib.newevent.NewEvent() _PageChanged, EVT_NOTEBOOK_PAGE_CHANGED = wx.lib.newevent.NewEvent() @@ -34,6 +33,7 @@ _PageClosing, EVT_NOTEBOOK_PAGE_CLOSING = wx.lib.newevent.NewEvent() PageAdded, EVT_NOTEBOOK_PAGE_ADDED = wx.lib.newevent.NewEvent() PageClosed, EVT_NOTEBOOK_PAGE_CLOSED = wx.lib.newevent.NewEvent() + class VetoAble(): def __init__(self): self.__vetoed = False @@ -91,7 +91,6 @@ class PageAdding(_PageAdding, VetoAble): class PFNotebook(wx.Panel): - def __init__(self, parent, canAdd=True): """ Instance of Pyfa Notebook. Initializes general layout, includes methods @@ -100,8 +99,8 @@ class PFNotebook(wx.Panel): parent - wx parent element canAdd - True if tabs be deleted and added, passed directly to PFTabsContainer - """ + wx.Panel.__init__(self, parent, wx.ID_ANY, size=(-1, -1)) self.pages = [] @@ -234,7 +233,7 @@ class PFNotebook(wx.Panel): try: # Set page to the first non-disabled page self.SetSelection(next(i for i, _ in enumerate(self.pages) if not self.tabsContainer.tabs[i].disabled)) - except StopIteration, ex: + except StopIteration: self.SetSelection(0) self.tabsContainer.DisableTab(idx, toggle) @@ -337,7 +336,7 @@ class PFNotebook(wx.Panel): class PFTabRenderer: - def __init__(self, size=(36, 24), text=wx.EmptyString, img=None, inclination=6 , closeButton=True): + def __init__(self, size=(36, 24), text=wx.EmptyString, img=None, inclination=6, closeButton=True): """ Renders a new tab @@ -432,7 +431,7 @@ class PFTabRenderer: mdc.SelectObject(ebmp) mdc.SetFont(self.font) textSizeX, textSizeY = mdc.GetTextExtent(self.text) - totalSize = self.leftWidth + self.rightWidth + textSizeX + self.closeBtnWidth/2 + 16 + self.padding*2 + totalSize = self.leftWidth + self.rightWidth + textSizeX + self.closeBtnWidth / 2 + 16 + self.padding * 2 mdc.SelectObject(wx.NullBitmap) return totalSize, self.tabHeight @@ -497,7 +496,7 @@ class PFTabRenderer: mdc = wx.MemoryDC() mdc.SelectObject(bkbmp) - #mdc.SetBackground(wx.Brush((0x12, 0x23, 0x32))) + # mdc.SetBackground(wx.Brush((0x12, 0x23, 0x32))) mdc.Clear() mdc.DrawBitmap(self.ctabLeftBmp, 0, 0) # set the left bitmap @@ -506,14 +505,14 @@ class PFTabRenderer: cm = self.ctabMiddleBmp.ConvertToImage() mimg = cm.Scale(self.contentWidth, self.ctabMiddle.GetHeight(), wx.IMAGE_QUALITY_NORMAL) mbmp = wx.BitmapFromImage(mimg) - mdc.DrawBitmap(mbmp, self.leftWidth, 0 ) # set middle bitmap, offset by left + mdc.DrawBitmap(mbmp, self.leftWidth, 0) # set middle bitmap, offset by left # set right bitmap offset by left + middle mdc.DrawBitmap(self.ctabRightBmp, self.contentWidth + self.leftWidth, 0) mdc.SelectObject(wx.NullBitmap) - #bkbmp.SetMaskColour((0x12, 0x23, 0x32)) + # bkbmp.SetMaskColour((0x12, 0x23, 0x32)) if self.tabBackBitmap: del self.tabBackBitmap @@ -527,7 +526,10 @@ class PFTabRenderer: """ self.tabRegion = wx.RegionFromBitmap(self.tabBackBitmap) self.closeBtnRegion = wx.RegionFromBitmap(self.ctabCloseBmp) - self.closeBtnRegion.Offset(self.contentWidth + self.leftWidth - self.ctabCloseBmp.GetWidth()/2, (self.tabHeight - self.ctabCloseBmp.GetHeight())/2) + self.closeBtnRegion.Offset( + self.contentWidth + self.leftWidth - self.ctabCloseBmp.GetWidth() / 2, + (self.tabHeight - self.ctabCloseBmp.GetHeight()) / 2 + ) def InitColors(self): """Determines colors used for tab, based on system settings""" @@ -545,33 +547,33 @@ class PFTabRenderer: height = self.tabHeight - #rect = wx.Rect(0, 0, self.tabWidth, self.tabHeight) + # rect = wx.Rect(0, 0, self.tabWidth, self.tabHeight) canvas = wx.EmptyBitmap(self.tabWidth, self.tabHeight, 24) mdc = wx.MemoryDC() mdc.SelectObject(canvas) - #mdc.SetBackground(wx.Brush ((0x12,0x23,0x32))) + # mdc.SetBackground(wx.Brush ((0x12,0x23,0x32))) mdc.Clear() - #r = copy.copy(rect) - #r.top = r.left = 0 - #r.height = height + # r = copy.copy(rect) + # r.top = r.left = 0 + # r.height = height mdc.DrawBitmap(self.tabBackBitmap, 0, 0, True) if self.tabImg: bmp = wx.BitmapFromImage(self.tabImg.ConvertToGreyscale() if self.disabled else self.tabImg) if self.contentWidth > 16: # @todo: is this conditional relevant anymore? # Draw tab icon - mdc.DrawBitmap(bmp, self.leftWidth + self.padding - bmp.GetWidth()/2, (height - bmp.GetHeight())/2) - textStart = self.leftWidth + self.padding + bmp.GetWidth()/2 + mdc.DrawBitmap(bmp, self.leftWidth + self.padding - bmp.GetWidth() / 2, (height - bmp.GetHeight()) / 2) + textStart = self.leftWidth + self.padding + bmp.GetWidth() / 2 else: textStart = self.leftWidth mdc.SetFont(self.font) - maxsize = self.tabWidth - textStart - self.rightWidth - self.padding*4 + maxsize = self.tabWidth - textStart - self.rightWidth - self.padding * 4 color = self.selectedColor if self.selected else self.inactiveColor mdc.SetTextForeground(colorUtils.GetSuitableColor(color, 1)) @@ -589,9 +591,10 @@ class PFTabRenderer: cbmp = wx.BitmapFromImage(cimg) mdc.DrawBitmap( - cbmp, - self.contentWidth + self.leftWidth - self.ctabCloseBmp.GetWidth()/2, - (height - self.ctabCloseBmp.GetHeight())/2) + cbmp, + self.contentWidth + self.leftWidth - self.ctabCloseBmp.GetWidth() / 2, + (height - self.ctabCloseBmp.GetHeight()) / 2, + ) mdc.SelectObject(wx.NullBitmap) @@ -609,6 +612,7 @@ class PFTabRenderer: self.text, self.disabled, hex(id(self)) ) + class PFAddRenderer: def __init__(self): """Renders the add tab button""" @@ -628,7 +632,7 @@ class PFAddRenderer: def GetPosition(self): return self.position - def SetPosition(self,pos): + def SetPosition(self, pos): self.position = pos def GetSize(self): @@ -689,7 +693,7 @@ class PFTabsContainer(wx.Panel): """ wx.Panel.__init__(self, parent, id, pos, size) - if wx.VERSION >= (3,0): + if wx.VERSION >= (3, 0): self.SetBackgroundStyle(wx.BG_STYLE_PAINT) self.tabs = [] @@ -699,7 +703,7 @@ class PFTabsContainer(wx.Panel): self.containerHeight = height self.startDrag = False self.dragging = False - self.sFit = service.Fit.getInstance() + self.sFit = Fit.getInstance() self.inclination = 7 if canAdd: @@ -865,7 +869,8 @@ class PFTabsContainer(wx.Panel): return True if self.TabHitTest(tab, x, y): - if tab.disabled: return + if tab.disabled: + return tab.SetSelected(True) oldSelTab.SetSelected(False) @@ -942,7 +947,7 @@ class PFTabsContainer(wx.Panel): closeBtnReg = tab.GetCloseButtonRegion() tabPos = tab.GetPosition() tabPosX, tabPosY = tabPos - closeBtnReg.Offset(tabPosX,tabPosY) + closeBtnReg.Offset(tabPosX, tabPosY) if closeBtnReg.Contains(x, y): if not tab.GetCloseButtonHoverStatus(): @@ -985,7 +990,6 @@ class PFTabsContainer(wx.Panel): def GetTabAtRight(self, tabIndex): return self.tabs[tabIndex + 1] if tabIndex < self.GetTabsCount() - 1 else None - def SwitchTabs(self, src, dest, draggedTab=None): self.tabs[src], self.tabs[dest] = self.tabs[dest], self.tabs[src] self.UpdateTabsPosition(draggedTab) @@ -1110,14 +1114,12 @@ class PFTabsContainer(wx.Panel): def OnPaint(self, event): if "wxGTK" in wx.PlatformInfo: mdc = wx.AutoBufferedPaintDC(self) - else: - rect = self.GetRect() mdc = wx.BufferedPaintDC(self) selected = 0 - if 'wxMac' in wx.PlatformInfo and wx.VERSION < (3,0): + if 'wxMac' in wx.PlatformInfo and wx.VERSION < (3, 0): color = wx.Colour(0, 0, 0) brush = wx.Brush(color) @@ -1128,7 +1130,7 @@ class PFTabsContainer(wx.Panel): brush = wx.Brush(color) if "wxGTK" not in wx.PlatformInfo: - mdc.SetBackground (brush) + mdc.SetBackground(brush) mdc.Clear() selected = None @@ -1136,21 +1138,18 @@ class PFTabsContainer(wx.Panel): tabsWidth = 0 for tab in self.tabs: - tabsWidth += tab.tabWidth - self.inclination*2 - - pos = tabsWidth + tabsWidth += tab.tabWidth - self.inclination * 2 if self.showAddButton: - ax,ay = self.addButton.GetPosition() + ax, ay = self.addButton.GetPosition() mdc.DrawBitmap(self.addButton.Render(), ax, ay, True) - for i in xrange(len(self.tabs) - 1, -1, -1): + for i in range(len(self.tabs) - 1, -1, -1): tab = self.tabs[i] - width = tab.tabWidth - 6 posx, posy = tab.GetPosition() if not tab.IsSelected(): - mdc.DrawBitmap(self.efxBmp, posx, posy, True ) + mdc.DrawBitmap(self.efxBmp, posx, posy, True) bmp = tab.Render() img = bmp.ConvertToImage() img = img.AdjustChannels(1, 1, 1, 0.85) @@ -1265,13 +1264,13 @@ class PFTabsContainer(wx.Panel): def UpdateTabsPosition(self, skipTab=None): tabsWidth = 0 for tab in self.tabs: - tabsWidth += tab.tabWidth - self.inclination*2 + tabsWidth += tab.tabWidth - self.inclination * 2 pos = tabsWidth selected = None - for i in xrange(len(self.tabs) - 1, -1, -1): + for i in range(len(self.tabs) - 1, -1, -1): tab = self.tabs[i] - width = tab.tabWidth - self.inclination*2 + width = tab.tabWidth - self.inclination * 2 pos -= width if not tab.IsSelected(): tab.SetPosition((pos, self.containerHeight - self.height)) @@ -1280,7 +1279,12 @@ class PFTabsContainer(wx.Panel): selpos = pos if selected is not skipTab: selected.SetPosition((selpos, self.containerHeight - self.height)) - self.addButton.SetPosition((round(tabsWidth) + self.inclination*2, self.containerHeight - self.height/2 - self.addButton.GetHeight()/3)) + self.addButton.SetPosition( + ( + round(tabsWidth) + self.inclination * 2, + self.containerHeight - self.height / 2 - self.addButton.GetHeight() / 3 + ) + ) def OnLeaveWindow(self, event): @@ -1305,17 +1309,28 @@ class PFTabsContainer(wx.Panel): if not self.previewTab.GetSelected(): page = self.Parent.GetPage(self.GetTabIndex(self.previewTab)) if page.Snapshot(): - self.previewWnd = PFNotebookPagePreview(self, (mposx+3, mposy+3), page.Snapshot(), self.previewTab.text) + self.previewWnd = PFNotebookPagePreview( + self, + (mposx + 3, mposy + 3), + page.Snapshot(), + self.previewTab.text + ) self.previewWnd.Show() event.Skip() + class PFNotebookPagePreview(wx.Frame): - def __init__ (self,parent, pos, bitmap, title): - wx.Frame.__init__(self, parent, id=wx.ID_ANY, title=wx.EmptyString, pos=pos, size=wx.DefaultSize, style= - wx.NO_BORDER - | wx.FRAME_NO_TASKBAR - | wx.STAY_ON_TOP) + def __init__(self, parent, pos, bitmap, title): + wx.Frame.__init__( + self, + parent, + id=wx.ID_ANY, + title=wx.EmptyString, + pos=pos, + size=wx.DefaultSize, + style=wx.NO_BORDER | wx.FRAME_NO_TASKBAR | wx.STAY_ON_TOP + ) self.title = title self.bitmap = bitmap @@ -1342,13 +1357,13 @@ class PFNotebookPagePreview(wx.Frame): else: width = bitmap.GetWidth() - self.SetSize((width, bitmap.GetHeight()+16)) + self.SetSize((width, bitmap.GetHeight() + 16)) self.SetTransparent(0) self.Refresh() def OnTimer(self, event): - self.transp += 20*self.direction + self.transp += 20 * self.direction if self.transp > 220: self.transp = 220 @@ -1357,7 +1372,7 @@ class PFNotebookPagePreview(wx.Frame): if self.transp < 0: self.transp = 0 self.timer.Stop() - wx.Frame.Show(self,False) + wx.Frame.Show(self, False) self.Destroy() return self.SetTransparent(self.transp) @@ -1381,8 +1396,7 @@ class PFNotebookPagePreview(wx.Frame): self.direction = -1 self.timer.Start(10) - - def OnWindowEraseBk(self,event): + def OnWindowEraseBk(self, event): pass def OnWindowPaint(self, event): @@ -1394,17 +1408,17 @@ class PFNotebookPagePreview(wx.Frame): mdc.SetBackground(wx.Brush(color)) mdc.Clear() - font = wx.Font(fonts.NORMAL, wx.SWISS, wx.NORMAL,wx.NORMAL, False) + font = wx.Font(fonts.NORMAL, wx.SWISS, wx.NORMAL, wx.NORMAL, False) mdc.SetFont(font) - x,y = mdc.GetTextExtent(self.title) + x, y = mdc.GetTextExtent(self.title) mdc.SetBrush(wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT))) mdc.DrawRectangle(0, 0, rect.width, 16) mdc.SetTextForeground(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) - mdc.DrawText(self.title, (rect.width - x)/2, (16 - y)/2) + mdc.DrawText(self.title, (rect.width - x) / 2, (16 - y) / 2) mdc.DrawBitmap(self.bitmap, 0, 16) diff --git a/gui/commandView.py b/gui/commandView.py index 5971e537c..20a7a33a9 100644 --- a/gui/commandView.py +++ b/gui/commandView.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,16 +15,17 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx import gui.display as d import gui.globalEvents as GE -import service + import gui.droneView from gui.builtinViewColumns.state import State from gui.contextMenu import ContextMenu -import eos.types +from service.fit import Fit +from eos.saveddata.drone import Drone as es_Drone class DummyItem: @@ -32,29 +33,32 @@ class DummyItem: self.name = txt self.icon = None + class DummyEntry: def __init__(self, txt): self.item = DummyItem(txt) -class CommandViewDrop(wx.PyDropTarget): - def __init__(self, dropFn): - wx.PyDropTarget.__init__(self) - self.dropFn = dropFn - # this is really transferring an EVE itemID - self.dropData = wx.PyTextDataObject() - self.SetDataObject(self.dropData) - def OnData(self, x, y, t): - if self.GetData(): - data = self.dropData.GetText().split(':') - self.dropFn(x, y, data) - return t +class CommandViewDrop(wx.PyDropTarget): + def __init__(self, dropFn): + wx.PyDropTarget.__init__(self) + self.dropFn = dropFn + # this is really transferring an EVE itemID + self.dropData = wx.PyTextDataObject() + self.SetDataObject(self.dropData) + + def OnData(self, x, y, t): + if self.GetData(): + data = self.dropData.GetText().split(':') + self.dropFn(x, y, data) + return t + class CommandView(d.Display): - DEFAULT_COLS = ["Base Name",] + DEFAULT_COLS = ["Base Name"] def __init__(self, parent): - d.Display.__init__(self, parent, style = wx.LC_SINGLE_SEL | wx.BORDER_NONE) + d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL | wx.BORDER_NONE) self.lastFitId = None @@ -66,7 +70,7 @@ class CommandView(d.Display): self.droneView = gui.droneView.DroneView - if "__WXGTK__" in wx.PlatformInfo: + if "__WXGTK__" in wx.PlatformInfo: self.Bind(wx.EVT_RIGHT_UP, self.scheduleMenu) else: self.Bind(wx.EVT_RIGHT_DOWN, self.scheduleMenu) @@ -84,31 +88,31 @@ class CommandView(d.Display): ''' pass - def kbEvent(self,event): + def kbEvent(self, event): keycode = event.GetKeyCode() if keycode == wx.WXK_DELETE or keycode == wx.WXK_NUMPAD_DELETE: fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() row = self.GetFirstSelected() if row != -1: sFit.removeCommand(fitID, self.get(row)) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) def handleDrag(self, type, fitID): - #Those are drags coming from pyfa sources, NOT builtin wx drags + # Those are drags coming from pyfa sources, NOT builtin wx drags if type == "fit": activeFit = self.mainFrame.getActiveFit() if activeFit: - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() draggedFit = sFit.getFit(fitID) sFit.addCommandFit(activeFit, draggedFit) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFit)) def startDrag(self, event): row = event.GetIndex() - if row != -1 and isinstance(self.get(row), eos.types.Drone): + if row != -1 and isinstance(self.get(row), es_Drone): data = wx.PyTextDataObject() - data.SetText("command:"+str(self.GetItemData(row))) + data.SetText("command:" + str(self.GetItemData(row))) dropSource = wx.DropSource(self) dropSource.SetData(data) @@ -118,12 +122,12 @@ class CommandView(d.Display): return fit.name def fitChanged(self, event): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(event.fitID) self.Parent.Parent.DisablePage(self, not fit or fit.isStructure) - #Clear list and get out if current fitId is None + # Clear list and get out if current fitId is None if event.fitID is None and self.lastFitId is not None: self.DeleteAllItems() self.lastFitId = None @@ -168,7 +172,7 @@ class CommandView(d.Display): col = self.getColumn(event.Position) if col == self.getColIndex(State): fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() sFit.toggleCommandFit(fitID, item) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) @@ -182,11 +186,11 @@ class CommandView(d.Display): menu = None if sel != -1: item = self.get(sel) - if item is None: return - sMkt = service.Market.getInstance() + if item is None: + return fitSrcContext = "commandFit" fitItemContext = item.name - context = ((fitSrcContext,fitItemContext),) + context = ((fitSrcContext, fitItemContext),) context = context + (("command",),) menu = ContextMenu.getMenu((item,), *context) elif sel == -1: @@ -204,6 +208,6 @@ class CommandView(d.Display): col = self.getColumn(event.Position) if col != self.getColIndex(State): fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() sFit.removeCommand(fitID, self.get(row)) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) diff --git a/gui/contextMenu.py b/gui/contextMenu.py index f1e364383..520ad8065 100644 --- a/gui/contextMenu.py +++ b/gui/contextMenu.py @@ -1,179 +1,180 @@ -#=============================================================================== -# 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 wx -import logging - -logger = logging.getLogger(__name__) - -class ContextMenu(object): - menus = [] - _ids = [] #[wx.NewId() for x in xrange(200)] # init with decent amount - _idxid = -1 - - @classmethod - def register(cls): - ContextMenu.menus.append(cls) - - @classmethod - def getMenu(cls, selection, *fullContexts): - """ - getMenu returns a menu that is used with wx.PopupMenu. - - selection: provides a list of what was selected. If only 1 item was - selected, it's is a 1-item list or tuple. Can also be None for - contexts without selection, such as statsPane or projected view - fullContexts: a number of tuples of the following tuple: - srcContext - context were menu was spawned, eg: projectedFit, - cargoItem, etc - itemContext - usually the name of the item's category - - eg: - (('fittingModule', 'Module'), ('fittingShip', 'Ship')) - (('marketItemGroup', 'Implant'),) - (('fittingShip', 'Ship'),) - """ - cls._idxid = -1 - debug_start = len(cls._ids) - - rootMenu = wx.Menu() - rootMenu.info = {} - rootMenu.selection = (selection,) if not hasattr(selection, "__iter__") else selection - empty = True - for i, fullContext in enumerate(fullContexts): - amount = 0 - srcContext = fullContext[0] - try: - itemContext = fullContext[1] - except IndexError: - itemContext = None - for menuHandler in cls.menus: - # loop through registered menus - m = menuHandler() - if m.display(srcContext, selection): - amount += 1 - texts = m.getText(itemContext, selection) - - if isinstance(texts, basestring): - texts = (texts,) - - bitmap = m.getBitmap(srcContext, selection) - multiple = not isinstance(bitmap, wx.Bitmap) - for it, text in enumerate(texts): - id = cls.nextID() - rootItem = wx.MenuItem(rootMenu, id, text) - rootMenu.info[id] = (m, fullContext, it) - - sub = m.getSubMenu(srcContext, selection, rootMenu, it, rootItem) - - if sub is None: - # if there is no sub menu, bind the handler to the rootItem - rootMenu.Bind(wx.EVT_MENU, cls.handler, rootItem) - elif sub: - # If sub exists and is not False, set submenu. - # Sub might return False when we have a mix of - # single menu items and submenus (see: damage profile - # context menu) - # - # If there is a submenu, it is expected that the sub - # logic take care of it's own bindings, including for - # any single root items. No binding is done here - # - # It is important to remember that when binding sub - # menu items, the menu to bind to depends on platform. - # Windows should bind to rootMenu, and all other - # platforms should bind to sub menu. See existing - # implementations for examples. - rootItem.SetSubMenu(sub) - - if bitmap is not None: - if multiple: - bp = bitmap[it] - if bp: - rootItem.SetBitmap(bp) - else: - rootItem.SetBitmap(bitmap) - - rootMenu.AppendItem(rootItem) - - empty = False - - if amount > 0 and i != len(fullContexts) - 1: - rootMenu.AppendSeparator() - - debug_end = len(cls._ids) - if (debug_end - debug_start): - logger.debug("%d new IDs created for this menu" % (debug_end - debug_start)) - - return rootMenu if empty is False else None - - @classmethod - def handler(cls, event): - menu = event.EventObject - stuff = menu.info.get(event.Id) - if stuff is not None: - menuHandler, context, i = stuff - selection = menu.selection - if not hasattr(selection, "__iter__"): - selection = (selection,) - - menuHandler.activate(context, selection, i) - else: - event.Skip() - - def display(self, context, selection): - raise NotImplementedError() - - def activate(self, fullContext, selection, i): - return None - - def getSubMenu(self, context, selection, rootMenu, i, pitem): - return None - - @classmethod - def nextID(cls): - """ - Fetches an ID from the pool of IDs allocated to Context Menu. - If we don't have enough ID's to fulfill request, create new - ID and add it to the pool. - - See GH Issue #589 - """ - cls._idxid += 1 - - if cls._idxid >= len(cls._ids): # We don't ahve an ID for this index, create one - cls._ids.append(wx.NewId()) - - return cls._ids[cls._idxid] - - def getText(self, context, selection): - """ - getText should be implemented in child classes, and should return either - a string that will make up a menu item label or a list of strings which - will make numerous menu items. - - These menu items will be added to the root menu - """ - raise NotImplementedError() - - def getBitmap(self, context, selection): - return None - - -from gui.builtinContextMenus import * +# ============================================================================= +# 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 wx +import logging + +logger = logging.getLogger(__name__) + + +class ContextMenu(object): + menus = [] + _ids = [] # [wx.NewId() for x in xrange(200)] # init with decent amount + _idxid = -1 + + @classmethod + def register(cls): + ContextMenu.menus.append(cls) + + @classmethod + def getMenu(cls, selection, *fullContexts): + """ + getMenu returns a menu that is used with wx.PopupMenu. + + selection: provides a list of what was selected. If only 1 item was + selected, it's is a 1-item list or tuple. Can also be None for + contexts without selection, such as statsPane or projected view + fullContexts: a number of tuples of the following tuple: + srcContext - context were menu was spawned, eg: projectedFit, + cargoItem, etc + itemContext - usually the name of the item's category + + eg: + (('fittingModule', 'Module'), ('fittingShip', 'Ship')) + (('marketItemGroup', 'Implant'),) + (('fittingShip', 'Ship'),) + """ + cls._idxid = -1 + debug_start = len(cls._ids) + + rootMenu = wx.Menu() + rootMenu.info = {} + rootMenu.selection = (selection,) if not hasattr(selection, "__iter__") else selection + empty = True + for i, fullContext in enumerate(fullContexts): + amount = 0 + srcContext = fullContext[0] + try: + itemContext = fullContext[1] + except IndexError: + itemContext = None + for menuHandler in cls.menus: + # loop through registered menus + m = menuHandler() + if m.display(srcContext, selection): + amount += 1 + texts = m.getText(itemContext, selection) + + if isinstance(texts, basestring): + texts = (texts,) + + bitmap = m.getBitmap(srcContext, selection) + multiple = not isinstance(bitmap, wx.Bitmap) + for it, text in enumerate(texts): + id = cls.nextID() + rootItem = wx.MenuItem(rootMenu, id, text) + rootMenu.info[id] = (m, fullContext, it) + + sub = m.getSubMenu(srcContext, selection, rootMenu, it, rootItem) + + if sub is None: + # if there is no sub menu, bind the handler to the rootItem + rootMenu.Bind(wx.EVT_MENU, cls.handler, rootItem) + elif sub: + # If sub exists and is not False, set submenu. + # Sub might return False when we have a mix of + # single menu items and submenus (see: damage profile + # context menu) + # + # If there is a submenu, it is expected that the sub + # logic take care of it's own bindings, including for + # any single root items. No binding is done here + # + # It is important to remember that when binding sub + # menu items, the menu to bind to depends on platform. + # Windows should bind to rootMenu, and all other + # platforms should bind to sub menu. See existing + # implementations for examples. + rootItem.SetSubMenu(sub) + + if bitmap is not None: + if multiple: + bp = bitmap[it] + if bp: + rootItem.SetBitmap(bp) + else: + rootItem.SetBitmap(bitmap) + + rootMenu.AppendItem(rootItem) + + empty = False + + if amount > 0 and i != len(fullContexts) - 1: + rootMenu.AppendSeparator() + + debug_end = len(cls._ids) + if (debug_end - debug_start): + logger.debug("%d new IDs created for this menu" % (debug_end - debug_start)) + + return rootMenu if empty is False else None + + @classmethod + def handler(cls, event): + menu = event.EventObject + stuff = menu.info.get(event.Id) + if stuff is not None: + menuHandler, context, i = stuff + selection = menu.selection + if not hasattr(selection, "__iter__"): + selection = (selection,) + + menuHandler.activate(context, selection, i) + else: + event.Skip() + + def display(self, context, selection): + raise NotImplementedError() + + def activate(self, fullContext, selection, i): + return None + + def getSubMenu(self, context, selection, rootMenu, i, pitem): + return None + + @classmethod + def nextID(cls): + """ + Fetches an ID from the pool of IDs allocated to Context Menu. + If we don't have enough ID's to fulfill request, create new + ID and add it to the pool. + + See GH Issue #589 + """ + cls._idxid += 1 + + if cls._idxid >= len(cls._ids): # We don't ahve an ID for this index, create one + cls._ids.append(wx.NewId()) + + return cls._ids[cls._idxid] + + def getText(self, context, selection): + """ + getText should be implemented in child classes, and should return either + a string that will make up a menu item label or a list of strings which + will make numerous menu items. + + These menu items will be added to the root menu + """ + raise NotImplementedError() + + def getBitmap(self, context, selection): + return None + + +from gui.builtinContextMenus import * # noqa diff --git a/gui/copySelectDialog.py b/gui/copySelectDialog.py index ea2e44620..bb5a6e601 100644 --- a/gui/copySelectDialog.py +++ b/gui/copySelectDialog.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Lucas Thode # # This file is part of pyfa. @@ -15,11 +15,12 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx + class CopySelectDialog(wx.Dialog): copyFormatEft = 0 copyFormatEftImps = 1 @@ -29,7 +30,8 @@ class CopySelectDialog(wx.Dialog): copyFormatMultiBuy = 5 def __init__(self, parent): - wx.Dialog.__init__(self, parent, id = wx.ID_ANY, title = u"Select a format", size = (-1,-1), style = wx.DEFAULT_DIALOG_STYLE) + wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title=u"Select a format", size=(-1, -1), + style=wx.DEFAULT_DIALOG_STYLE) mainSizer = wx.BoxSizer(wx.VERTICAL) copyFormats = [u"EFT", u"EFT (Implants)", u"XML", u"DNA", u"CREST", u"MultiBuy"] @@ -39,7 +41,8 @@ class CopySelectDialog(wx.Dialog): CopySelectDialog.copyFormatDna: u"A one-line text format", CopySelectDialog.copyFormatCrest: u"A JSON format used for EVE CREST", CopySelectDialog.copyFormatMultiBuy: u"MultiBuy text format"} - selector = wx.RadioBox(self, wx.ID_ANY, label = u"Copy to the clipboard using:", choices = copyFormats, style = wx.RA_SPECIFY_ROWS) + selector = wx.RadioBox(self, wx.ID_ANY, label=u"Copy to the clipboard using:", choices=copyFormats, + style=wx.RA_SPECIFY_ROWS) selector.Bind(wx.EVT_RADIOBOX, self.Selected) for format, tooltip in copyFormatTooltips.iteritems(): selector.SetItemToolTip(format, tooltip) @@ -47,21 +50,18 @@ class CopySelectDialog(wx.Dialog): self.copyFormat = CopySelectDialog.copyFormatEft selector.SetSelection(self.copyFormat) - mainSizer.Add(selector,0,wx.EXPAND | wx.ALL, 5) + mainSizer.Add(selector, 0, wx.EXPAND | wx.ALL, 5) buttonSizer = self.CreateButtonSizer(wx.OK | wx.CANCEL) if (buttonSizer): - mainSizer.Add(buttonSizer,0, wx.EXPAND | wx.ALL, 5) + mainSizer.Add(buttonSizer, 0, wx.EXPAND | wx.ALL, 5) self.SetSizer(mainSizer) self.Fit() self.Center() - def Selected(self, event): self.copyFormat = event.GetSelection() def GetSelected(self): return self.copyFormat - - diff --git a/gui/crestFittings.py b/gui/crestFittings.py index 0b2cf54cf..e51c0cd26 100644 --- a/gui/crestFittings.py +++ b/gui/crestFittings.py @@ -4,8 +4,11 @@ import json import wx import requests -import service -from service.crest import CrestModes +if not 'wxMac' in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3,0)): + from service.crest import Crest, CrestModes + +from service.port import Port +from service.fit import Fit from eos.types import Cargo from eos.db import getItem @@ -15,52 +18,53 @@ import gui.globalEvents as GE class CrestFittings(wx.Frame): - def __init__(self, parent): - wx.Frame.__init__(self, parent, id=wx.ID_ANY, title="Browse EVE Fittings", pos=wx.DefaultPosition, size=wx.Size( 550,450 ), style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL) + wx.Frame.__init__(self, parent, id=wx.ID_ANY, title="Browse EVE Fittings", pos=wx.DefaultPosition, + size=wx.Size(550, 450), style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL) self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE)) self.mainFrame = parent mainSizer = wx.BoxSizer(wx.VERTICAL) - sCrest = service.Crest.getInstance() + sCrest = Crest.getInstance() - characterSelectSizer = wx.BoxSizer( wx.HORIZONTAL ) + characterSelectSizer = wx.BoxSizer(wx.HORIZONTAL) if sCrest.settings.get('mode') == CrestModes.IMPLICIT: - self.stLogged = wx.StaticText(self, wx.ID_ANY, "Currently logged in as %s"%sCrest.implicitCharacter.name, wx.DefaultPosition, wx.DefaultSize) - self.stLogged.Wrap( -1 ) + self.stLogged = wx.StaticText(self, wx.ID_ANY, "Currently logged in as %s" % sCrest.implicitCharacter.name, + wx.DefaultPosition, wx.DefaultSize) + self.stLogged.Wrap(-1) - characterSelectSizer.Add( self.stLogged, 1, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + characterSelectSizer.Add(self.stLogged, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) else: self.charChoice = wx.Choice(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, []) - characterSelectSizer.Add( self.charChoice, 1, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + characterSelectSizer.Add(self.charChoice, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) self.updateCharList() - self.fetchBtn = wx.Button( self, wx.ID_ANY, u"Fetch Fits", wx.DefaultPosition, wx.DefaultSize, 5 ) - characterSelectSizer.Add( self.fetchBtn, 0, wx.ALL, 5 ) - mainSizer.Add( characterSelectSizer, 0, wx.EXPAND, 5 ) + self.fetchBtn = wx.Button(self, wx.ID_ANY, u"Fetch Fits", wx.DefaultPosition, wx.DefaultSize, 5) + characterSelectSizer.Add(self.fetchBtn, 0, wx.ALL, 5) + mainSizer.Add(characterSelectSizer, 0, wx.EXPAND, 5) - self.sl = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) - mainSizer.Add( self.sl, 0, wx.EXPAND |wx.ALL, 5 ) + self.sl = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) + mainSizer.Add(self.sl, 0, wx.EXPAND | wx.ALL, 5) - contentSizer = wx.BoxSizer( wx.HORIZONTAL ) - browserSizer = wx.BoxSizer( wx.VERTICAL ) + contentSizer = wx.BoxSizer(wx.HORIZONTAL) + browserSizer = wx.BoxSizer(wx.VERTICAL) self.fitTree = FittingsTreeView(self) - browserSizer.Add( self.fitTree, 1, wx.ALL|wx.EXPAND, 5 ) - contentSizer.Add( browserSizer, 1, wx.EXPAND, 0 ) - fitSizer = wx.BoxSizer( wx.VERTICAL ) + browserSizer.Add(self.fitTree, 1, wx.ALL | wx.EXPAND, 5) + contentSizer.Add(browserSizer, 1, wx.EXPAND, 0) + fitSizer = wx.BoxSizer(wx.VERTICAL) self.fitView = FitView(self) - fitSizer.Add( self.fitView, 1, wx.ALL|wx.EXPAND, 5 ) + fitSizer.Add(self.fitView, 1, wx.ALL | wx.EXPAND, 5) - btnSizer = wx.BoxSizer( wx.HORIZONTAL ) - self.importBtn = wx.Button( self, wx.ID_ANY, u"Import to pyfa", wx.DefaultPosition, wx.DefaultSize, 5 ) - self.deleteBtn = wx.Button( self, wx.ID_ANY, u"Delete from EVE", wx.DefaultPosition, wx.DefaultSize, 5 ) - btnSizer.Add( self.importBtn, 1, wx.ALL, 5 ) - btnSizer.Add( self.deleteBtn, 1, wx.ALL, 5 ) - fitSizer.Add( btnSizer, 0, wx.EXPAND ) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + self.importBtn = wx.Button(self, wx.ID_ANY, u"Import to pyfa", wx.DefaultPosition, wx.DefaultSize, 5) + self.deleteBtn = wx.Button(self, wx.ID_ANY, u"Delete from EVE", wx.DefaultPosition, wx.DefaultSize, 5) + btnSizer.Add(self.importBtn, 1, wx.ALL, 5) + btnSizer.Add(self.deleteBtn, 1, wx.ALL, 5) + fitSizer.Add(btnSizer, 0, wx.EXPAND) contentSizer.Add(fitSizer, 1, wx.EXPAND, 0) mainSizer.Add(contentSizer, 1, wx.EXPAND, 5) @@ -90,7 +94,7 @@ class CrestFittings(wx.Frame): event.Skip() def updateCharList(self): - sCrest = service.Crest.getInstance() + sCrest = Crest.getInstance() chars = sCrest.getCrestCharacters() if len(chars) == 0: @@ -103,12 +107,12 @@ class CrestFittings(wx.Frame): self.charChoice.SetSelection(0) def updateCacheStatus(self, event): - t = time.gmtime(self.cacheTime-time.time()) + t = time.gmtime(self.cacheTime - time.time()) if t < 0: self.cacheTimer.Stop() else: sTime = time.strftime("%H:%M:%S", t) - self.statusbar.SetStatusText("Cached for %s"%sTime, 0) + self.statusbar.SetStatusText("Cached for %s" % sTime, 0) def ssoLogout(self, event): if event.type == CrestModes.IMPLICIT: @@ -123,7 +127,7 @@ class CrestFittings(wx.Frame): event.Skip() def getActiveCharacter(self): - sCrest = service.Crest.getInstance() + sCrest = Crest.getInstance() if sCrest.settings.get('mode') == CrestModes.IMPLICIT: return sCrest.implicitCharacter.ID @@ -132,7 +136,7 @@ class CrestFittings(wx.Frame): return self.charChoice.GetClientData(selection) if selection is not None else None def fetchFittings(self, event): - sCrest = service.Crest.getInstance() + sCrest = Crest.getInstance() try: waitDialog = wx.BusyInfo("Fetching fits, please wait...", parent=self) fittings = sCrest.getFittings(self.getActiveCharacter()) @@ -150,20 +154,20 @@ class CrestFittings(wx.Frame): if not selection: return data = self.fitTree.fittingsTreeCtrl.GetPyData(selection) - sFit = service.Fit.getInstance() - fits = sFit.importFitFromBuffer(data) + sPort = Port.getInstance() + fits = sPort.importFitFromBuffer(data) self.mainFrame._openAfterImport(fits) def deleteFitting(self, event): - sCrest = service.Crest.getInstance() + sCrest = Crest.getInstance() selection = self.fitView.fitSelection if not selection: return data = json.loads(self.fitTree.fittingsTreeCtrl.GetPyData(selection)) dlg = wx.MessageDialog(self, - "Do you really want to delete %s (%s) from EVE?"%(data['name'], data['ship']['name']), - "Confirm Delete", wx.YES | wx.NO | wx.ICON_QUESTION) + "Do you really want to delete %s (%s) from EVE?" % (data['name'], data['ship']['name']), + "Confirm Delete", wx.YES | wx.NO | wx.ICON_QUESTION) if dlg.ShowModal() == wx.ID_YES: try: @@ -173,32 +177,33 @@ class CrestFittings(wx.Frame): class ExportToEve(wx.Frame): - def __init__(self, parent): - wx.Frame.__init__(self, parent, id=wx.ID_ANY, title="Export fit to EVE", pos=wx.DefaultPosition, size=(wx.Size(350,100)), style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL) + wx.Frame.__init__(self, parent, id=wx.ID_ANY, title="Export fit to EVE", pos=wx.DefaultPosition, + size=(wx.Size(350, 100)), style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL) self.mainFrame = parent self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE)) - sCrest = service.Crest.getInstance() + sCrest = Crest.getInstance() mainSizer = wx.BoxSizer(wx.VERTICAL) hSizer = wx.BoxSizer(wx.HORIZONTAL) if sCrest.settings.get('mode') == CrestModes.IMPLICIT: - self.stLogged = wx.StaticText(self, wx.ID_ANY, "Currently logged in as %s"%sCrest.implicitCharacter.name, wx.DefaultPosition, wx.DefaultSize) - self.stLogged.Wrap( -1 ) + self.stLogged = wx.StaticText(self, wx.ID_ANY, "Currently logged in as %s" % sCrest.implicitCharacter.name, + wx.DefaultPosition, wx.DefaultSize) + self.stLogged.Wrap(-1) - hSizer.Add( self.stLogged, 1, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + hSizer.Add(self.stLogged, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) else: self.charChoice = wx.Choice(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, []) - hSizer.Add( self.charChoice, 1, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + hSizer.Add(self.charChoice, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) self.updateCharList() self.charChoice.SetSelection(0) - self.exportBtn = wx.Button( self, wx.ID_ANY, u"Export Fit", wx.DefaultPosition, wx.DefaultSize, 5 ) - hSizer.Add( self.exportBtn, 0, wx.ALL, 5 ) + self.exportBtn = wx.Button(self, wx.ID_ANY, u"Export Fit", wx.DefaultPosition, wx.DefaultSize, 5) + hSizer.Add(self.exportBtn, 0, wx.ALL, 5) - mainSizer.Add( hSizer, 0, wx.EXPAND, 5 ) + mainSizer.Add(hSizer, 0, wx.EXPAND, 5) self.exportBtn.Bind(wx.EVT_BUTTON, self.exportFitting) @@ -217,7 +222,7 @@ class ExportToEve(wx.Frame): self.Centre(wx.BOTH) def updateCharList(self): - sCrest = service.Crest.getInstance() + sCrest = Crest.getInstance() chars = sCrest.getCrestCharacters() if len(chars) == 0: @@ -245,7 +250,7 @@ class ExportToEve(wx.Frame): event.Skip() def getActiveCharacter(self): - sCrest = service.Crest.getInstance() + sCrest = Crest.getInstance() if sCrest.settings.get('mode') == CrestModes.IMPLICIT: return sCrest.implicitCharacter.ID @@ -254,7 +259,7 @@ class ExportToEve(wx.Frame): return self.charChoice.GetClientData(selection) if selection is not None else None def exportFitting(self, event): - sFit = service.Fit.getInstance() + sPort = Port.getInstance() fitID = self.mainFrame.getActiveFit() self.statusbar.SetStatusText("", 0) @@ -264,13 +269,14 @@ class ExportToEve(wx.Frame): return self.statusbar.SetStatusText("Sending request and awaiting response", 1) - sCrest = service.Crest.getInstance() + sCrest = Crest.getInstance() try: - data = sFit.exportCrest(fitID) + sFit = Fit.getInstance() + data = sPort.exportCrest(sFit.getFit(fitID)) res = sCrest.postFitting(self.getActiveCharacter(), data) - self.statusbar.SetStatusText("%d: %s"%(res.status_code, res.reason), 0) + self.statusbar.SetStatusText("%d: %s" % (res.status_code, res.reason), 0) try: text = json.loads(res.text) self.statusbar.SetStatusText(text['message'], 1) @@ -281,47 +287,47 @@ class ExportToEve(wx.Frame): class CrestMgmt(wx.Dialog): - - def __init__( self, parent ): - wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = "CREST Character Management", pos = wx.DefaultPosition, size = wx.Size( 550,250 ), style = wx.DEFAULT_DIALOG_STYLE ) + def __init__(self, parent): + wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title="CREST Character Management", pos=wx.DefaultPosition, + size=wx.Size(550, 250), style=wx.DEFAULT_DIALOG_STYLE) self.mainFrame = parent - mainSizer = wx.BoxSizer( wx.HORIZONTAL ) + mainSizer = wx.BoxSizer(wx.HORIZONTAL) - self.lcCharacters = wx.ListCtrl( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LC_REPORT) + self.lcCharacters = wx.ListCtrl(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LC_REPORT) self.lcCharacters.InsertColumn(0, heading='Character') self.lcCharacters.InsertColumn(1, heading='Refresh Token') self.popCharList() - mainSizer.Add( self.lcCharacters, 1, wx.ALL|wx.EXPAND, 5 ) + mainSizer.Add(self.lcCharacters, 1, wx.ALL | wx.EXPAND, 5) - btnSizer = wx.BoxSizer( wx.VERTICAL ) + btnSizer = wx.BoxSizer(wx.VERTICAL) - self.addBtn = wx.Button( self, wx.ID_ANY, u"Add Character", wx.DefaultPosition, wx.DefaultSize, 0 ) - btnSizer.Add( self.addBtn, 0, wx.ALL | wx.EXPAND, 5 ) + self.addBtn = wx.Button(self, wx.ID_ANY, u"Add Character", wx.DefaultPosition, wx.DefaultSize, 0) + btnSizer.Add(self.addBtn, 0, wx.ALL | wx.EXPAND, 5) - self.deleteBtn = wx.Button( self, wx.ID_ANY, u"Revoke Character", wx.DefaultPosition, wx.DefaultSize, 0 ) - btnSizer.Add( self.deleteBtn, 0, wx.ALL | wx.EXPAND, 5 ) + self.deleteBtn = wx.Button(self, wx.ID_ANY, u"Revoke Character", wx.DefaultPosition, wx.DefaultSize, 0) + btnSizer.Add(self.deleteBtn, 0, wx.ALL | wx.EXPAND, 5) - mainSizer.Add( btnSizer, 0, wx.EXPAND, 5 ) + mainSizer.Add(btnSizer, 0, wx.EXPAND, 5) self.addBtn.Bind(wx.EVT_BUTTON, self.addChar) self.deleteBtn.Bind(wx.EVT_BUTTON, self.delChar) self.mainFrame.Bind(GE.EVT_SSO_LOGIN, self.ssoLogin) - self.SetSizer( mainSizer ) + self.SetSizer(mainSizer) self.Layout() - self.Centre( wx.BOTH ) + self.Centre(wx.BOTH) def ssoLogin(self, event): self.popCharList() event.Skip() def popCharList(self): - sCrest = service.Crest.getInstance() + sCrest = Crest.getInstance() chars = sCrest.getCrestCharacters() self.lcCharacters.DeleteAllItems() @@ -335,7 +341,7 @@ class CrestMgmt(wx.Dialog): self.lcCharacters.SetColumnWidth(1, wx.LIST_AUTOSIZE) def addChar(self, event): - sCrest = service.Crest.getInstance() + sCrest = Crest.getInstance() uri = sCrest.startServer() webbrowser.open(uri) @@ -343,7 +349,7 @@ class CrestMgmt(wx.Dialog): item = self.lcCharacters.GetFirstSelected() if item > -1: charID = self.lcCharacters.GetItemData(item) - sCrest = service.Crest.getInstance() + sCrest = Crest.getInstance() sCrest.delCrestCharacter(charID) self.popCharList() diff --git a/gui/display.py b/gui/display.py index 707623581..0d9e0308f 100644 --- a/gui/display.py +++ b/gui/display.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,19 +15,19 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import sys import wx import gui.mainFrame - from gui.viewColumn import ViewColumn from gui.cachingImageList import CachingImageList -class Display(wx.ListCtrl): - def __init__(self, parent, size = wx.DefaultSize, style = 0): - wx.ListCtrl.__init__(self, parent,size = size, style=wx.LC_REPORT | style ) +class Display(wx.ListCtrl): + def __init__(self, parent, size=wx.DefaultSize, style=0): + + wx.ListCtrl.__init__(self, parent, size=size, style=wx.LC_REPORT | style) self.imageList = CachingImageList(16, 16) self.SetImageList(self.imageList, wx.IMAGE_LIST_SMALL) self.activeColumns = [] @@ -70,9 +70,8 @@ class Display(wx.ListCtrl): self.imageListBase = self.imageList.ImageCount - -# Override native HitTestSubItem (doesn't work as it should on GTK) -# Source: ObjectListView + # Override native HitTestSubItem (doesn't work as it should on GTK) + # Source: ObjectListView def HitTestSubItem(self, pt): """ @@ -110,15 +109,14 @@ class Display(wx.ListCtrl): return (rowIndex, 0, -1) - - def OnEraseBk(self,event): - if self.GetItemCount() >0: + def OnEraseBk(self, event): + if self.GetItemCount() > 0: width, height = self.GetClientSize() dc = event.GetDC() dc.DestroyClippingRegion() dc.SetClippingRegion(0, 0, width, height) - x,y,w,h = dc.GetClippingBox() + x, y, w, h = dc.GetClippingBox() topItem = self.GetTopItem() bottomItem = topItem + self.GetCountPerPage() @@ -129,10 +127,9 @@ class Display(wx.ListCtrl): topRect = self.GetItemRect(topItem, wx.LIST_RECT_LABEL) bottomRect = self.GetItemRect(bottomItem, wx.LIST_RECT_BOUNDS) + items_rect = wx.Rect(topRect.left, 0, bottomRect.right - topRect.left, bottomRect.bottom) - items_rect = wx.Rect(topRect.left, 0, bottomRect.right - topRect.left, bottomRect.bottom ) - - updateRegion = wx.Region(x,y,w,h) + updateRegion = wx.Region(x, y, w, h) updateRegion.SubtractRect(items_rect) dc.DestroyClippingRegion() @@ -171,41 +168,37 @@ class Display(wx.ListCtrl): # we veto header cell resize by default till we find a way # to assure a minimal size for the resized header cell column = event.GetColumn() - wx.CallAfter(self.checkColumnSize,column) + wx.CallAfter(self.checkColumnSize, column) event.Skip() def resizeSkip(self, event): column = event.GetColumn() - if column > len (self.activeColumns)-1: + if column > len(self.activeColumns) - 1: self.SetColumnWidth(column, 0) event.Veto() return - colItem = self.activeColumns[column] + # colItem = self.activeColumns[column] if self.activeColumns[column].maxsize != -1: event.Veto() else: event.Skip() - def checkColumnSize(self,column): + def checkColumnSize(self, column): colItem = self.activeColumns[column] if self.GetColumnWidth(column) < self.columnsMinWidth[column]: - self.SetColumnWidth(column,self.columnsMinWidth[column]) + self.SetColumnWidth(column, self.columnsMinWidth[column]) colItem.resized = True - def getLastItem( self, state = wx.LIST_STATE_DONTCARE): - lastFound = -1 - while True: - index = self.GetNextItem( - lastFound, - wx.LIST_NEXT_ALL, - state, - ) - if index == -1: - break - else: - lastFound = index + def getLastItem(self, state=wx.LIST_STATE_DONTCARE): + lastFound = -1 + while True: + index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state) + if index == -1: + break + else: + lastFound = index - return lastFound + return lastFound def deselectItems(self): sel = self.GetFirstSelected() @@ -220,26 +213,25 @@ class Display(wx.ListCtrl): stuffItemCount = len(stuff) if listItemCount < stuffItemCount: - for i in xrange(stuffItemCount - listItemCount): - index = self.InsertStringItem(sys.maxint, "") + for i in range(stuffItemCount - listItemCount): + self.InsertStringItem(sys.maxint, "") if listItemCount > stuffItemCount: if listItemCount - stuffItemCount > 20 and stuffItemCount < 20: self.DeleteAllItems() - for i in xrange(stuffItemCount): - index = self.InsertStringItem(sys.maxint, "") + for i in range(stuffItemCount): + self.InsertStringItem(sys.maxint, "") else: - for i in xrange(listItemCount - stuffItemCount): + for i in range(listItemCount - stuffItemCount): self.DeleteItem(self.getLastItem()) self.Refresh() - def refresh(self, stuff): - if stuff == None: + if stuff is None: return item = -1 - for id, st in enumerate(stuff): + for id_, st in enumerate(stuff): item = self.GetNextItem(item) @@ -270,11 +262,11 @@ class Display(wx.ListCtrl): colItem.SetMask(mask) self.SetItem(colItem) - self.SetItemData(item, id) + self.SetItemData(item, id_) -# self.Freeze() + # self.Freeze() if 'wxMSW' in wx.PlatformInfo: - for i,col in enumerate(self.activeColumns): + for i, col in enumerate(self.activeColumns): if not col.resized: self.SetColumnWidth(i, col.size) else: @@ -289,9 +281,7 @@ class Display(wx.ListCtrl): self.SetColumnWidth(i, headerWidth) else: self.SetColumnWidth(i, col.size) -# self.Thaw() - - + # self.Thaw() def update(self, stuff): self.populate(stuff) diff --git a/gui/droneView.py b/gui/droneView.py index 531c28d05..4d389e8ea 100644 --- a/gui/droneView.py +++ b/gui/droneView.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,40 +15,45 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx -import service import gui.globalEvents as GE import gui.marketBrowser as mb import gui.display as d from gui.builtinViewColumns.state import State from gui.contextMenu import ContextMenu +from service.fit import Fit +from service.market import Market + class DroneViewDrop(wx.PyDropTarget): - def __init__(self, dropFn): - wx.PyDropTarget.__init__(self) - self.dropFn = dropFn - # this is really transferring an EVE itemID - self.dropData = wx.PyTextDataObject() - self.SetDataObject(self.dropData) + def __init__(self, dropFn): + wx.PyDropTarget.__init__(self) + self.dropFn = dropFn + # this is really transferring an EVE itemID + self.dropData = wx.PyTextDataObject() + self.SetDataObject(self.dropData) + + def OnData(self, x, y, t): + if self.GetData(): + data = self.dropData.GetText().split(':') + self.dropFn(x, y, data) + return t - def OnData(self, x, y, t): - if self.GetData(): - data = self.dropData.GetText().split(':') - self.dropFn(x, y, data) - return t class DroneView(d.Display): - DEFAULT_COLS = ["State", - #"Base Icon", - "Base Name", - # "prop:droneDps,droneBandwidth", - "Max Range", - "Miscellanea", - "attr:maxVelocity", - "Price",] + DEFAULT_COLS = [ + "State", + # "Base Icon", + "Base Name", + # "prop:droneDps,droneBandwidth", + "Max Range", + "Miscellanea", + "attr:maxVelocity", + "Price", + ] def __init__(self, parent): d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL | wx.BORDER_NONE) @@ -66,12 +71,11 @@ class DroneView(d.Display): self.Bind(wx.EVT_MOTION, self.OnMouseMove) self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow) - if "__WXGTK__" in wx.PlatformInfo: + if "__WXGTK__" in wx.PlatformInfo: self.Bind(wx.EVT_RIGHT_UP, self.scheduleMenu) else: self.Bind(wx.EVT_RIGHT_DOWN, self.scheduleMenu) - self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.startDrag) self.SetDropTarget(DroneViewDrop(self.handleDragDrop)) @@ -107,7 +111,6 @@ class DroneView(d.Display): keycode = event.GetKeyCode() if keycode == wx.WXK_DELETE or keycode == wx.WXK_NUMPAD_DELETE: row = self.GetFirstSelected() - firstSel = row if row != -1: drone = self.drones[self.GetItemData(row)] self.removeDrone(drone) @@ -118,11 +121,11 @@ class DroneView(d.Display): row = event.GetIndex() if row != -1: data = wx.PyTextDataObject() - data.SetText("drone:"+str(row)) + data.SetText("drone:" + str(row)) dropSource = wx.DropSource(self) dropSource.SetData(data) - res = dropSource.DoDragDrop() + dropSource.DoDragDrop() def handleDragDrop(self, x, y, data): ''' @@ -141,7 +144,7 @@ class DroneView(d.Display): wx.PostEvent(self.mainFrame, mb.ItemSelected(itemID=int(data[1]))) def _merge(self, src, dst): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() if sFit.mergeDrones(fitID, self.drones[src], self.drones[dst]): wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) @@ -150,8 +153,9 @@ class DroneView(d.Display): 'Heavy Attack Drones', 'Sentry Drones', 'Fighters', 'Fighter Bombers', 'Combat Utility Drones', 'Electronic Warfare Drones', 'Logistic Drones', 'Mining Drones', 'Salvage Drones') + def droneKey(self, drone): - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() groupName = sMkt.getMarketGroupByItem(drone.item).name @@ -159,12 +163,12 @@ class DroneView(d.Display): drone.item.name) def fitChanged(self, event): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(event.fitID) self.Parent.Parent.DisablePage(self, not fit or fit.isStructure) - #Clear list and get out if current fitId is None + # Clear list and get out if current fitId is None if event.fitID is None and self.lastFitId is not None: self.DeleteAllItems() self.lastFitId = None @@ -177,7 +181,6 @@ class DroneView(d.Display): if stuff is not None: stuff.sort(key=self.droneKey) - if event.fitID != self.lastFitId: self.lastFitId = event.fitID @@ -191,9 +194,8 @@ class DroneView(d.Display): self.update(stuff) event.Skip() - def addItem(self, event): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() fit = sFit.getFit(fitID) @@ -218,7 +220,7 @@ class DroneView(d.Display): def removeDrone(self, drone): fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() sFit.removeDrone(fitID, self.original.index(drone)) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) @@ -229,7 +231,7 @@ class DroneView(d.Display): col = self.getColumn(event.Position) if col == self.getColIndex(State): fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() drone = self.drones[row] sFit.toggleDrone(fitID, self.original.index(drone)) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) @@ -244,7 +246,7 @@ class DroneView(d.Display): if sel != -1: drone = self.drones[sel] - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() sourceContext = "droneItem" itemContext = sMkt.getCategoryByItem(drone.item).name menu = ContextMenu.getMenu((drone,), (sourceContext, itemContext)) diff --git a/gui/fighterView.py b/gui/fighterView.py index b4468c94f..083901460 100644 --- a/gui/fighterView.py +++ b/gui/fighterView.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,11 +15,10 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx -import service import gui.globalEvents as GE import gui.marketBrowser as mb import gui.mainFrame @@ -27,25 +26,28 @@ import gui.display as d from gui.builtinViewColumns.state import State from eos.types import Slot from gui.contextMenu import ContextMenu +from service.fit import Fit +from service.market import Market + class FighterViewDrop(wx.PyDropTarget): - def __init__(self, dropFn): - wx.PyDropTarget.__init__(self) - self.dropFn = dropFn - # this is really transferring an EVE itemID - self.dropData = wx.PyTextDataObject() - self.SetDataObject(self.dropData) + def __init__(self, dropFn): + wx.PyDropTarget.__init__(self) + self.dropFn = dropFn + # this is really transferring an EVE itemID + self.dropData = wx.PyTextDataObject() + self.SetDataObject(self.dropData) - def OnData(self, x, y, t): - if self.GetData(): - data = self.dropData.GetText().split(':') - self.dropFn(x, y, data) - return t + def OnData(self, x, y, t): + if self.GetData(): + data = self.dropData.GetText().split(':') + self.dropFn(x, y, data) + return t class FighterView(wx.Panel): def __init__(self, parent): - wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, style=wx.TAB_TRAVERSAL ) + wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, style=wx.TAB_TRAVERSAL) self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.labels = ["Light", "Heavy", "Support"] @@ -55,7 +57,7 @@ class FighterView(wx.Panel): mainSizer.Add(self.fighterDisplay, 1, wx.EXPAND, 0) textSizer = wx.BoxSizer(wx.HORIZONTAL) - textSizer.AddSpacer(( 0, 0), 1, wx.EXPAND, 5) + textSizer.AddSpacer((0, 0), 1, wx.EXPAND, 5) for x in self.labels: lbl = wx.StaticText(self, wx.ID_ANY, x.capitalize()) @@ -74,14 +76,13 @@ class FighterView(wx.Panel): mainSizer.Add(textSizer, 0, wx.EXPAND, 5) - self.SetSizer( mainSizer ) + self.SetSizer(mainSizer) self.SetAutoLayout(True) - self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) def fitChanged(self, event): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() activeFitID = self.mainFrame.getActiveFit() fit = sFit.getFit(activeFitID) @@ -90,7 +91,8 @@ class FighterView(wx.Panel): slot = getattr(Slot, "F_{}".format(x.upper())) used = fit.getSlotsUsed(slot) total = fit.getNumSlots(slot) - color = wx.Colour(204, 51, 51) if used > total else wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT) + color = wx.Colour(204, 51, 51) if used > total else wx.SystemSettings_GetColour( + wx.SYS_COLOUR_WINDOWTEXT) lbl = getattr(self, "label%sUsed" % x.capitalize()) lbl.SetLabel(str(int(used))) @@ -105,15 +107,15 @@ class FighterView(wx.Panel): class FighterDisplay(d.Display): DEFAULT_COLS = ["State", - #"Base Icon", + # "Base Icon", "Base Name", # "prop:droneDps,droneBandwidth", - #"Max Range", - #"Miscellanea", + # "Max Range", + # "Miscellanea", "attr:maxVelocity", "Fighter Abilities" - #"Price", - ] + # "Price", + ] def __init__(self, parent): d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL | wx.BORDER_NONE) @@ -131,12 +133,11 @@ class FighterDisplay(d.Display): self.Bind(wx.EVT_MOTION, self.OnMouseMove) self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow) - if "__WXGTK__" in wx.PlatformInfo: + if "__WXGTK__" in wx.PlatformInfo: self.Bind(wx.EVT_RIGHT_UP, self.scheduleMenu) else: self.Bind(wx.EVT_RIGHT_DOWN, self.scheduleMenu) - self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.startDrag) self.SetDropTarget(FighterViewDrop(self.handleDragDrop)) @@ -172,7 +173,6 @@ class FighterDisplay(d.Display): keycode = event.GetKeyCode() if keycode == wx.WXK_DELETE or keycode == wx.WXK_NUMPAD_DELETE: row = self.GetFirstSelected() - firstSel = row if row != -1: fighter = self.fighters[self.GetItemData(row)] self.removeFighter(fighter) @@ -183,11 +183,11 @@ class FighterDisplay(d.Display): row = event.GetIndex() if row != -1: data = wx.PyTextDataObject() - data.SetText("fighter:"+str(row)) + data.SetText("fighter:" + str(row)) dropSource = wx.DropSource(self) dropSource.SetData(data) - res = dropSource.DoDragDrop() + dropSource.DoDragDrop() def handleDragDrop(self, x, y, data): ''' @@ -215,7 +215,7 @@ class FighterDisplay(d.Display): 'Electronic Warfare Drones', 'Logistic Drones', 'Mining Drones', 'Salvage Drones', 'Light Fighters', 'Heavy Fighters', 'Support Fighters') def droneKey(self, drone): - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() groupName = sMkt.getMarketGroupByItem(drone.item).name print groupName @@ -224,12 +224,12 @@ class FighterDisplay(d.Display): ''' def fitChanged(self, event): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(event.fitID) self.Parent.Parent.Parent.DisablePage(self.Parent, not fit) - #Clear list and get out if current fitId is None + # Clear list and get out if current fitId is None if event.fitID is None and self.lastFitId is not None: self.DeleteAllItems() self.lastFitId = None @@ -257,9 +257,8 @@ class FighterDisplay(d.Display): self.update(stuff) event.Skip() - def addItem(self, event): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() trigger = sFit.addFighter(fitID, event.itemID) if trigger: @@ -278,7 +277,7 @@ class FighterDisplay(d.Display): def removeFighter(self, fighter): fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() sFit.removeFighter(fitID, self.original.index(fighter)) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) @@ -289,7 +288,7 @@ class FighterDisplay(d.Display): col = self.getColumn(event.Position) if col == self.getColIndex(State): fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fighter = self.fighters[row] sFit.toggleFighter(fitID, self.original.index(fighter)) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) @@ -304,7 +303,7 @@ class FighterDisplay(d.Display): if sel != -1: fighter = self.fighters[sel] - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() sourceContext = "fighterItem" itemContext = sMkt.getCategoryByItem(fighter.item).name menu = ContextMenu.getMenu((fighter,), (sourceContext, itemContext)) diff --git a/gui/graph.py b/gui/graph.py index 53d66f6a5..0b40902c2 100644 --- a/gui/graph.py +++ b/gui/graph.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,7 +15,8 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= + class Graph(object): views = [] @@ -33,4 +34,5 @@ class Graph(object): def getIcons(self): return None -from gui.builtinGraphs import * + +from gui.builtinGraphs import * # noqa diff --git a/gui/graphFrame.py b/gui/graphFrame.py index 2cedc84d1..1a538f01d 100644 --- a/gui/graphFrame.py +++ b/gui/graphFrame.py @@ -1,278 +1,285 @@ -#=============================================================================== -# 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 wx -import os -from gui.bitmapLoader import BitmapLoader -import gui.display -import gui.globalEvents as GE - -from gui.graph import Graph -import service -import gui.mainFrame - -enabled = True -mplImported = False - -class GraphFrame(wx.Frame): - def __init__(self, parent, style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE | wx.FRAME_FLOAT_ON_PARENT): - - global enabled - global mplImported - - self.legendFix = False - if not enabled: - return - - try: - import matplotlib as mpl - - try: - cache_dir = mpl._get_cachedir() - except: - cache_dir = unicode(os.path.expanduser(os.path.join("~", ".matplotlib"))) - - cache_file = os.path.join(cache_dir, 'fontList.cache') - if os.access(cache_dir, os.W_OK | os.X_OK) and os.path.isfile(cache_file): - # remove matplotlib font cache, see #234 - os.remove(cache_file) - if not mplImported: - mpl.use('wxagg') - from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas - from matplotlib.figure import Figure - enabled = True - if mpl.__version__[0] != "1": - print "pyfa: Found matplotlib version ",mpl.__version__, " - activating OVER9000 workarounds" - print "pyfa: Recommended minimum matplotlib version is 1.0.0" - self.legendFix = True - except: - print "Problems importing matplotlib; continuing without graphs" - enabled = False - return - - mplImported = True - - wx.Frame.__init__(self, parent, title=u"pyfa: Graph Generator", style=style, size=(520, 390)) - - i = wx.IconFromBitmap(BitmapLoader.getBitmap("graphs_small", "gui")) - self.SetIcon(i) - self.mainFrame = gui.mainFrame.MainFrame.getInstance() - self.CreateStatusBar() - - self.mainSizer = wx.BoxSizer(wx.VERTICAL) - self.SetSizer(self.mainSizer) - - sFit = service.Fit.getInstance() - fit = sFit.getFit(self.mainFrame.getActiveFit()) - self.fits = [fit] if fit is not None else [] - self.fitList = FitList(self) - self.fitList.SetMinSize((270, -1)) - - self.fitList.fitList.update(self.fits) - - self.graphSelection = wx.Choice(self, wx.ID_ANY, style=0) - self.mainSizer.Add(self.graphSelection, 0, wx.EXPAND) - - self.figure = Figure(figsize=(4, 3)) - - rgbtuple = wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ).Get() - clr = [c/255. for c in rgbtuple] - self.figure.set_facecolor( clr ) - self.figure.set_edgecolor( clr ) - - self.canvas = Canvas(self, -1, self.figure) - self.canvas.SetBackgroundColour( wx.Colour( *rgbtuple ) ) - - self.subplot = self.figure.add_subplot(111) - self.subplot.grid(True) - - self.mainSizer.Add(self.canvas, 1, wx.EXPAND) - self.mainSizer.Add(wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ), 0 , wx.EXPAND) - - self.gridPanel = wx.Panel(self) - self.mainSizer.Add(self.gridPanel, 0, wx.EXPAND) - - dummyBox = wx.BoxSizer(wx.VERTICAL) - self.gridPanel.SetSizer(dummyBox) - - self.gridSizer = wx.FlexGridSizer(0, 4) - self.gridSizer.AddGrowableCol(1) - dummyBox.Add(self.gridSizer, 0, wx.EXPAND) - - for view in Graph.views: - view = view() - self.graphSelection.Append(view.name, view) - - self.graphSelection.SetSelection(0) - self.fields = {} - self.select(0) - self.sl1 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) - self.mainSizer.Add(self.sl1,0, wx.EXPAND) - self.mainSizer.Add(self.fitList, 0, wx.EXPAND) - - self.fitList.fitList.Bind(wx.EVT_LEFT_DCLICK, self.removeItem) - self.mainFrame.Bind(GE.FIT_CHANGED, self.draw) - self.Bind(wx.EVT_CLOSE, self.close) - - self.Fit() - self.SetMinSize(self.GetSize()) - - def handleDrag(self, type, fitID): - if type == "fit": - self.AppendFitToList(fitID) - - def close(self, event): - self.fitList.fitList.Unbind(wx.EVT_LEFT_DCLICK, handler=self.removeItem) - self.mainFrame.Unbind(GE.FIT_CHANGED, handler=self.draw) - event.Skip() - - def getView(self): - return self.graphSelection.GetClientData(self.graphSelection.GetSelection()) - - def getValues(self): - values = {} - for fieldName, field in self.fields.iteritems(): - values[fieldName] = field.GetValue() - - return values - - def select(self, index): - view = self.getView() - icons = view.getIcons() - labels = view.getLabels() - sizer = self.gridSizer - self.gridPanel.DestroyChildren() - self.fields.clear() - - #Setup textboxes - for field, defaultVal in view.getFields().iteritems(): - - textBox = wx.TextCtrl(self.gridPanel, wx.ID_ANY, style=0) - self.fields[field] = textBox - textBox.Bind(wx.EVT_TEXT, self.onFieldChanged) - sizer.Add(textBox, 1, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 3) - if defaultVal is not None: - if not isinstance(defaultVal, basestring): - defaultVal = ("%f" % defaultVal).rstrip("0") - if defaultVal[-1:] == ".": - defaultVal = defaultVal + "0" - - textBox.ChangeValue(defaultVal) - - imgLabelSizer = wx.BoxSizer(wx.HORIZONTAL) - if icons: - icon = icons.get(field) - if icon is not None: - static = wx.StaticBitmap(self.gridPanel) - static.SetBitmap(icon) - imgLabelSizer.Add(static, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 1) - - if labels: - label = labels.get(field) - label = label if label is not None else field - else: - label = field - - imgLabelSizer.Add(wx.StaticText(self.gridPanel, wx.ID_ANY, label), 0, wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 3) - sizer.Add(imgLabelSizer, 0, wx.ALIGN_CENTER_VERTICAL) - self.draw() - - def draw(self, event=None): - values = self.getValues() - view = self.getView() - self.subplot.clear() - self.subplot.grid(True) - legend = [] - - for fit in self.fits: - try: - success, status = view.getPoints(fit, values) - if not success: - #TODO: Add a pwetty statys bar to report errors with - self.SetStatusText(status) - return - - x, y = success, status - - self.subplot.plot(x, y) - legend.append(fit.name) - except: - self.SetStatusText("Invalid values in '%s'" % fit.name) - self.canvas.draw() - return - - if self.legendFix and len(legend) > 0: - leg = self.subplot.legend(tuple(legend), "upper right" , shadow = False) - for t in leg.get_texts(): - t.set_fontsize('small') - - for l in leg.get_lines(): - l.set_linewidth(1) - - elif not self.legendFix and len(legend) >0: - leg = self.subplot.legend(tuple(legend), "upper right" , shadow = False, frameon = False) - for t in leg.get_texts(): - t.set_fontsize('small') - - for l in leg.get_lines(): - l.set_linewidth(1) - - self.canvas.draw() - self.SetStatusText("") - if event is not None: - event.Skip() - - def onFieldChanged(self, event): - self.draw() - - def AppendFitToList(self, fitID): - sFit = service.Fit.getInstance() - fit = sFit.getFit(fitID) - if fit not in self.fits: - self.fits.append(fit) - - self.fitList.fitList.update(self.fits) - self.draw() - - def removeItem(self, event): - row, _ = self.fitList.fitList.HitTest(event.Position) - if row != -1: - del self.fits[row] - self.fitList.fitList.update(self.fits) - self.draw() - - -class FitList(wx.Panel): - def __init__(self, parent): - wx.Panel.__init__(self, parent) - self.mainSizer = wx.BoxSizer(wx.VERTICAL) - self.SetSizer(self.mainSizer) - - self.fitList = FitDisplay(self) - self.mainSizer.Add(self.fitList, 1, wx.EXPAND) - fitToolTip = wx.ToolTip("Drag a fit into this list to graph it") - self.fitList.SetToolTip(fitToolTip) - -class FitDisplay(gui.display.Display): - DEFAULT_COLS = ["Base Icon", - "Base Name"] - - def __init__(self, parent): - gui.display.Display.__init__(self, parent) - +# ============================================================================= +# 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 os +import logging +logger = logging.getLogger(__name__) + +import wx + +from service.fit import Fit +import gui.display +import gui.mainFrame +import gui.globalEvents as GE +from gui.graph import Graph +from gui.bitmapLoader import BitmapLoader +from config import parsePath + +try: + import matplotlib as mpl + from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas + from matplotlib.figure import Figure + enabled = True + mplImported = False +except ImportError: + enabled = False + logger.info("Problems importing matplotlib; continuing without graphs") + + +class GraphFrame(wx.Frame): + def __init__(self, parent, style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE | wx.FRAME_FLOAT_ON_PARENT): + + global enabled + global mplImported + + self.legendFix = False + if not enabled: + return + + try: + cache_dir = mpl._get_cachedir() + except: + cache_dir = os.path.expanduser(os.path.join("~", ".matplotlib")) + + cache_file = parsePath(cache_dir, 'fontList.cache') + + if os.access(cache_dir, os.W_OK | os.X_OK) and os.path.isfile(cache_file): + # remove matplotlib font cache, see #234 + os.remove(cache_file) + if not mplImported: + mpl.use('wxagg') + + enabled = True + if mpl.__version__[0] != "1": + print("pyfa: Found matplotlib version ", mpl.__version__, " - activating OVER9000 workarounds") + print("pyfa: Recommended minimum matplotlib version is 1.0.0") + self.legendFix = True + + mplImported = True + + wx.Frame.__init__(self, parent, title=u"pyfa: Graph Generator", style=style, size=(520, 390)) + + i = wx.IconFromBitmap(BitmapLoader.getBitmap("graphs_small", "gui")) + self.SetIcon(i) + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + self.CreateStatusBar() + + self.mainSizer = wx.BoxSizer(wx.VERTICAL) + self.SetSizer(self.mainSizer) + + sFit = Fit.getInstance() + fit = sFit.getFit(self.mainFrame.getActiveFit()) + self.fits = [fit] if fit is not None else [] + self.fitList = FitList(self) + self.fitList.SetMinSize((270, -1)) + + self.fitList.fitList.update(self.fits) + + self.graphSelection = wx.Choice(self, wx.ID_ANY, style=0) + self.mainSizer.Add(self.graphSelection, 0, wx.EXPAND) + + self.figure = Figure(figsize=(4, 3)) + + rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get() + clr = [c / 255. for c in rgbtuple] + self.figure.set_facecolor(clr) + self.figure.set_edgecolor(clr) + + self.canvas = Canvas(self, -1, self.figure) + self.canvas.SetBackgroundColour(wx.Colour(*rgbtuple)) + + self.subplot = self.figure.add_subplot(111) + self.subplot.grid(True) + + self.mainSizer.Add(self.canvas, 1, wx.EXPAND) + self.mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0, + wx.EXPAND) + + self.gridPanel = wx.Panel(self) + self.mainSizer.Add(self.gridPanel, 0, wx.EXPAND) + + dummyBox = wx.BoxSizer(wx.VERTICAL) + self.gridPanel.SetSizer(dummyBox) + + self.gridSizer = wx.FlexGridSizer(0, 4) + self.gridSizer.AddGrowableCol(1) + dummyBox.Add(self.gridSizer, 0, wx.EXPAND) + + for view in Graph.views: + view = view() + self.graphSelection.Append(view.name, view) + + self.graphSelection.SetSelection(0) + self.fields = {} + self.select(0) + self.sl1 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) + self.mainSizer.Add(self.sl1, 0, wx.EXPAND) + self.mainSizer.Add(self.fitList, 0, wx.EXPAND) + + self.fitList.fitList.Bind(wx.EVT_LEFT_DCLICK, self.removeItem) + self.mainFrame.Bind(GE.FIT_CHANGED, self.draw) + self.Bind(wx.EVT_CLOSE, self.close) + + self.Fit() + self.SetMinSize(self.GetSize()) + + def handleDrag(self, type, fitID): + if type == "fit": + self.AppendFitToList(fitID) + + def close(self, event): + self.fitList.fitList.Unbind(wx.EVT_LEFT_DCLICK, handler=self.removeItem) + self.mainFrame.Unbind(GE.FIT_CHANGED, handler=self.draw) + event.Skip() + + def getView(self): + return self.graphSelection.GetClientData(self.graphSelection.GetSelection()) + + def getValues(self): + values = {} + for fieldName, field in self.fields.iteritems(): + values[fieldName] = field.GetValue() + + return values + + def select(self, index): + view = self.getView() + icons = view.getIcons() + labels = view.getLabels() + sizer = self.gridSizer + self.gridPanel.DestroyChildren() + self.fields.clear() + + # Setup textboxes + for field, defaultVal in view.getFields().iteritems(): + + textBox = wx.TextCtrl(self.gridPanel, wx.ID_ANY, style=0) + self.fields[field] = textBox + textBox.Bind(wx.EVT_TEXT, self.onFieldChanged) + sizer.Add(textBox, 1, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 3) + if defaultVal is not None: + if not isinstance(defaultVal, basestring): + defaultVal = ("%f" % defaultVal).rstrip("0") + if defaultVal[-1:] == ".": + defaultVal += "0" + + textBox.ChangeValue(defaultVal) + + imgLabelSizer = wx.BoxSizer(wx.HORIZONTAL) + if icons: + icon = icons.get(field) + if icon is not None: + static = wx.StaticBitmap(self.gridPanel) + static.SetBitmap(icon) + imgLabelSizer.Add(static, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 1) + + if labels: + label = labels.get(field) + label = label if label is not None else field + else: + label = field + + imgLabelSizer.Add(wx.StaticText(self.gridPanel, wx.ID_ANY, label), 0, + wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 3) + sizer.Add(imgLabelSizer, 0, wx.ALIGN_CENTER_VERTICAL) + self.draw() + + def draw(self, event=None): + values = self.getValues() + view = self.getView() + self.subplot.clear() + self.subplot.grid(True) + legend = [] + + for fit in self.fits: + try: + success, status = view.getPoints(fit, values) + if not success: + # TODO: Add a pwetty statys bar to report errors with + self.SetStatusText(status) + return + + x, y = success, status + + self.subplot.plot(x, y) + legend.append(fit.name) + except: + self.SetStatusText("Invalid values in '%s'" % fit.name) + self.canvas.draw() + return + + if self.legendFix and len(legend) > 0: + leg = self.subplot.legend(tuple(legend), "upper right", shadow=False) + for t in leg.get_texts(): + t.set_fontsize('small') + + for l in leg.get_lines(): + l.set_linewidth(1) + + elif not self.legendFix and len(legend) > 0: + leg = self.subplot.legend(tuple(legend), "upper right", shadow=False, frameon=False) + for t in leg.get_texts(): + t.set_fontsize('small') + + for l in leg.get_lines(): + l.set_linewidth(1) + + self.canvas.draw() + self.SetStatusText("") + if event is not None: + event.Skip() + + def onFieldChanged(self, event): + self.draw() + + def AppendFitToList(self, fitID): + sFit = Fit.getInstance() + fit = sFit.getFit(fitID) + if fit not in self.fits: + self.fits.append(fit) + + self.fitList.fitList.update(self.fits) + self.draw() + + def removeItem(self, event): + row, _ = self.fitList.fitList.HitTest(event.Position) + if row != -1: + del self.fits[row] + self.fitList.fitList.update(self.fits) + self.draw() + + +class FitList(wx.Panel): + def __init__(self, parent): + wx.Panel.__init__(self, parent) + self.mainSizer = wx.BoxSizer(wx.VERTICAL) + self.SetSizer(self.mainSizer) + + self.fitList = FitDisplay(self) + self.mainSizer.Add(self.fitList, 1, wx.EXPAND) + fitToolTip = wx.ToolTip("Drag a fit into this list to graph it") + self.fitList.SetToolTip(fitToolTip) + + +class FitDisplay(gui.display.Display): + DEFAULT_COLS = ["Base Icon", + "Base Name"] + + def __init__(self, parent): + gui.display.Display.__init__(self, parent) diff --git a/gui/implantView.py b/gui/implantView.py index 15da4d097..3de27f1bc 100644 --- a/gui/implantView.py +++ b/gui/implantView.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,10 +15,9 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx -import service import gui.display as d import gui.marketBrowser as mb import gui.mainFrame @@ -26,20 +25,22 @@ from gui.builtinViewColumns.state import State from gui.contextMenu import ContextMenu import globalEvents as GE from eos.types import ImplantLocation +from service.fit import Fit +from service.market import Market class ImplantView(wx.Panel): def __init__(self, parent): - wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, style=wx.TAB_TRAVERSAL ) + wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, style=wx.TAB_TRAVERSAL) self.mainFrame = gui.mainFrame.MainFrame.getInstance() mainSizer = wx.BoxSizer(wx.VERTICAL) self.implantDisplay = ImplantDisplay(self) - mainSizer.Add(self.implantDisplay, 1, wx.EXPAND, 0 ) + mainSizer.Add(self.implantDisplay, 1, wx.EXPAND, 0) radioSizer = wx.BoxSizer(wx.HORIZONTAL) - radioSizer.AddSpacer(( 0, 0), 1, wx.EXPAND, 5) + radioSizer.AddSpacer((0, 0), 1, wx.EXPAND, 5) self.rbFit = wx.RadioButton(self, id=wx.ID_ANY, label="Use Fit-specific Implants", style=wx.RB_GROUP) self.rbChar = wx.RadioButton(self, id=wx.ID_ANY, label="Use Character Implants") radioSizer.Add(self.rbFit, 0, wx.ALL, 5) @@ -48,7 +49,7 @@ class ImplantView(wx.Panel): mainSizer.Add(radioSizer, 0, wx.EXPAND, 5) - self.SetSizer( mainSizer ) + self.SetSizer(mainSizer) self.SetAutoLayout(True) self.Bind(wx.EVT_RADIOBUTTON, self.OnRadioSelect, self.rbFit) @@ -56,7 +57,7 @@ class ImplantView(wx.Panel): self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) def fitChanged(self, event): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() activeFitID = self.mainFrame.getActiveFit() fit = sFit.getFit(activeFitID) if fit: @@ -70,7 +71,7 @@ class ImplantView(wx.Panel): def OnRadioSelect(self, event): fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() sFit.toggleImplantSource(fitID, ImplantLocation.FIT if self.rbFit.GetValue() else ImplantLocation.CHARACTER) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) @@ -93,12 +94,12 @@ class ImplantDisplay(d.Display): self.Bind(wx.EVT_LEFT_DOWN, self.click) self.Bind(wx.EVT_KEY_UP, self.kbEvent) - if "__WXGTK__" in wx.PlatformInfo: + if "__WXGTK__" in wx.PlatformInfo: self.Bind(wx.EVT_RIGHT_UP, self.scheduleMenu) else: self.Bind(wx.EVT_RIGHT_DOWN, self.scheduleMenu) - def kbEvent(self,event): + def kbEvent(self, event): keycode = event.GetKeyCode() if keycode == wx.WXK_DELETE or keycode == wx.WXK_NUMPAD_DELETE: row = self.GetFirstSelected() @@ -107,12 +108,12 @@ class ImplantDisplay(d.Display): event.Skip() def fitChanged(self, event): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(event.fitID) self.Parent.Parent.Parent.DisablePage(self.Parent, not fit or fit.isStructure) - #Clear list and get out if current fitId is None + # Clear list and get out if current fitId is None if event.fitID is None and self.lastFitId is not None: self.DeleteAllItems() self.lastFitId = None @@ -121,7 +122,8 @@ class ImplantDisplay(d.Display): self.original = fit.implants if fit is not None else None self.implants = stuff = fit.appliedImplants if fit is not None else None - if stuff is not None: stuff.sort(key=lambda implant: implant.slot) + if stuff is not None: + stuff.sort(key=lambda implant: implant.slot) if event.fitID != self.lastFitId: self.lastFitId = event.fitID @@ -137,7 +139,7 @@ class ImplantDisplay(d.Display): event.Skip() def addItem(self, event): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() fit = sFit.getFit(fitID) @@ -161,7 +163,7 @@ class ImplantDisplay(d.Display): def removeImplant(self, implant): fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() sFit.removeImplant(fitID, self.original.index(implant)) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) @@ -172,7 +174,7 @@ class ImplantDisplay(d.Display): col = self.getColumn(event.Position) if col == self.getColIndex(State): fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() sFit.toggleImplant(fitID, row) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) @@ -185,7 +187,7 @@ class ImplantDisplay(d.Display): sel = self.GetFirstSelected() menu = None - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(self.mainFrame.getActiveFit()) if not fit: @@ -194,7 +196,7 @@ class ImplantDisplay(d.Display): if sel != -1: implant = fit.appliedImplants[sel] - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() sourceContext = "implantItem" if fit.implantSource == ImplantLocation.FIT else "implantItemChar" itemContext = sMkt.getCategoryByItem(implant.item).name diff --git a/gui/itemStats.py b/gui/itemStats.py index 35fb48355..b51b4e38c 100644 --- a/gui/itemStats.py +++ b/gui/itemStats.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,38 +15,39 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= + +import re +import os +import csv +import sys +import subprocess import wx -import re +import wx.html +import wx.lib.mixins.listctrl as listmix + +import config +from eos.types import Fit, Ship, Citadel, Module, Skill, Booster, Implant, Drone, Mode, Fighter +from service.market import Market +from service.attribute import Attribute import gui.mainFrame from gui.bitmapLoader import BitmapLoader -import sys -import wx.lib.mixins.listctrl as listmix -import wx.html -from eos.types import Fit, Ship, Citadel, Module, Skill, Booster, Implant, Drone, Mode, Fighter from gui.utils.numberFormatter import formatAmount -import service -import config from gui.contextMenu import ContextMenu -from gui.utils.numberFormatter import formatAmount -import csv -try: - from collections import OrderedDict -except ImportError: - from utils.compat import OrderedDict class ItemStatsDialog(wx.Dialog): counter = 0 + def __init__( self, victim, fullContext=None, pos=wx.DefaultPosition, size=wx.DefaultSize, - maximized = False - ): + maximized=False + ): wx.Dialog.__init__( self, @@ -55,7 +56,7 @@ class ItemStatsDialog(wx.Dialog): title="Item stats", pos=pos, size=size, - style=wx.CAPTION | wx.CLOSE_BOX | wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER| wx.SYSTEM_MENU + style=wx.CAPTION | wx.CLOSE_BOX | wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU ) empty = getattr(victim, "isEmpty", False) @@ -70,33 +71,37 @@ class ItemStatsDialog(wx.Dialog): itmContext = fullContext[1] except IndexError: itmContext = None - item = getattr(victim, "item", None) if srcContext.lower() not in ("projectedcharge", "fittingcharge") else getattr(victim, "charge", None) + item = getattr(victim, "item", None) if srcContext.lower() not in ( + "projectedcharge", + "fittingcharge" + ) else getattr(victim, "charge", None) if item is None: - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() item = sMkt.getItem(victim.ID) victim = None self.context = itmContext if item.icon is not None: - before,sep,after = item.icon.iconFile.rpartition("_") - iconFile = "%s%s%s" % (before,sep,"0%s" % after if len(after) < 2 else after) + before, sep, after = item.icon.iconFile.rpartition("_") + iconFile = "%s%s%s" % (before, sep, "0%s" % after if len(after) < 2 else after) itemImg = BitmapLoader.getBitmap(iconFile, "icons") if itemImg is not None: self.SetIcon(wx.IconFromBitmap(itemImg)) - self.SetTitle("%s: %s%s" % ("%s Stats" % itmContext if itmContext is not None else "Stats", item.name, " (%d)"%item.ID if config.debug else "")) + self.SetTitle("%s: %s%s" % ("%s Stats" % itmContext if itmContext is not None else "Stats", item.name, + " (%d)" % item.ID if config.debug else "")) self.SetMinSize((300, 200)) if "wxGTK" in wx.PlatformInfo: # GTK has huge tab widgets, give it a bit more room self.SetSize((580, 500)) else: self.SetSize((550, 500)) - #self.SetMaxSize((500, -1)) + # self.SetMaxSize((500, -1)) self.mainSizer = wx.BoxSizer(wx.VERTICAL) self.container = ItemStatsContainer(self, victim, item, itmContext) self.mainSizer.Add(self.container, 1, wx.EXPAND) if "wxGTK" in wx.PlatformInfo: - self.closeBtn = wx.Button( self, wx.ID_ANY, u"Close", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.mainSizer.Add( self.closeBtn, 0, wx.ALL|wx.ALIGN_RIGHT, 5 ) + self.closeBtn = wx.Button(self, wx.ID_ANY, u"Close", wx.DefaultPosition, wx.DefaultSize, 0) + self.mainSizer.Add(self.closeBtn, 0, wx.ALL | wx.ALIGN_RIGHT, 5) self.closeBtn.Bind(wx.EVT_BUTTON, self.closeEvent) self.SetSizer(self.mainSizer) @@ -112,13 +117,13 @@ class ItemStatsDialog(wx.Dialog): counter = ItemStatsDialog.counter dlgStep = 30 - if counter * dlgStep > ppos.x+psize.width-dlgsize.x or counter * dlgStep > ppos.y+psize.height-dlgsize.y: + if counter * dlgStep > ppos.x + psize.width - dlgsize.x or counter * dlgStep > ppos.y + psize.height - dlgsize.y: ItemStatsDialog.counter = 1 dlgx = ppos.x + counter * dlgStep dlgy = ppos.y + counter * dlgStep if pos == wx.DefaultPosition: - self.SetPosition((dlgx,dlgy)) + self.SetPosition((dlgx, dlgy)) else: self.SetPosition(pos) if maximized: @@ -138,26 +143,22 @@ class ItemStatsDialog(wx.Dialog): def closeEvent(self, event): - if self.dlgOrder==ItemStatsDialog.counter: + if self.dlgOrder == ItemStatsDialog.counter: ItemStatsDialog.counter -= 1 self.parentWnd.UnregisterStatsWindow(self) self.Destroy() -########################################################################### -## Class ItemStatsContainer -########################################################################### -class ItemStatsContainer ( wx.Panel ): +class ItemStatsContainer(wx.Panel): + def __init__(self, parent, stuff, item, context=None): + wx.Panel.__init__(self, parent) + sMkt = Market.getInstance() - def __init__( self, parent, stuff, item, context = None): - wx.Panel.__init__ ( self, parent ) - sMkt = service.Market.getInstance() + mainSizer = wx.BoxSizer(wx.VERTICAL) - mainSizer = wx.BoxSizer( wx.VERTICAL ) - - self.nbContainer = wx.Notebook( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0 ) - mainSizer.Add( self.nbContainer, 1, wx.EXPAND |wx.ALL, 2 ) + self.nbContainer = wx.Notebook(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0) + mainSizer.Add(self.nbContainer, 1, wx.EXPAND | wx.ALL, 2) if item.traits is not None: self.traits = ItemTraits(self.nbContainer, stuff, item) @@ -188,7 +189,7 @@ class ItemStatsContainer ( wx.Panel ): self.SetSizer(mainSizer) self.Layout() - def __del__( self ): + def __del__(self): pass def mouseHit(self, event): @@ -196,54 +197,36 @@ class ItemStatsContainer ( wx.Panel ): if tab != -1: self.nbContainer.SetSelection(tab) -########################################################################### -## Class AutoListCtrl -########################################################################### class AutoListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.ListRowHighlighter): - - def __init__(self, parent, ID, pos=wx.DefaultPosition, - size=wx.DefaultSize, style=0): + def __init__(self, parent, ID, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0): wx.ListCtrl.__init__(self, parent, ID, pos, size, style) listmix.ListCtrlAutoWidthMixin.__init__(self) listmix.ListRowHighlighter.__init__(self) -########################################################################### -## Class AutoListCtrl -########################################################################### class AutoListCtrlNoHighlight(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.ListRowHighlighter): - - def __init__(self, parent, ID, pos=wx.DefaultPosition, - size=wx.DefaultSize, style=0): + def __init__(self, parent, ID, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0): wx.ListCtrl.__init__(self, parent, ID, pos, size, style) listmix.ListCtrlAutoWidthMixin.__init__(self) -########################################################################### -## Class ItemTraits -########################################################################### - -class ItemTraits ( wx.Panel ): +class ItemTraits(wx.Panel): def __init__(self, parent, stuff, item): - wx.Panel.__init__ (self, parent) + wx.Panel.__init__(self, parent) mainSizer = wx.BoxSizer(wx.VERTICAL) self.SetSizer(mainSizer) self.traits = wx.html.HtmlWindow(self) self.traits.SetPage(item.traits.traitText) - mainSizer.Add(self.traits, 1, wx.ALL|wx.EXPAND, 0) + mainSizer.Add(self.traits, 1, wx.ALL | wx.EXPAND, 0) self.Layout() -########################################################################### -## Class ItemDescription -########################################################################### - -class ItemDescription ( wx.Panel ): +class ItemDescription(wx.Panel): def __init__(self, parent, stuff, item): - wx.Panel.__init__ (self, parent) + wx.Panel.__init__(self, parent) mainSizer = wx.BoxSizer(wx.VERTICAL) self.SetSizer(mainSizer) @@ -260,28 +243,24 @@ class ItemDescription ( wx.Panel ): desc = re.sub("<( *)font( *)color( *)=(.*?)>(?P.*?)<( *)/( *)font( *)>", "\g", desc) # Strip URLs desc = re.sub("<( *)a(.*?)>(?P.*?)<( *)/( *)a( *)>", "\g", desc) - desc = "" + desc + "" + desc = "" + desc + "" self.description.SetPage(desc) - mainSizer.Add(self.description, 1, wx.ALL|wx.EXPAND, 0) + mainSizer.Add(self.description, 1, wx.ALL | wx.EXPAND, 0) self.Layout() -########################################################################### -## Class ItemParams -########################################################################### -class ItemParams (wx.Panel): - def __init__(self, parent, stuff, item, context = None): - wx.Panel.__init__ (self, parent) - mainSizer = wx.BoxSizer( wx.VERTICAL ) +class ItemParams(wx.Panel): + def __init__(self, parent, stuff, item, context=None): + wx.Panel.__init__(self, parent) + mainSizer = wx.BoxSizer(wx.VERTICAL) self.paramList = AutoListCtrl(self, wx.ID_ANY, - style = #wx.LC_HRULES | - #wx.LC_NO_HEADER | - wx.LC_REPORT |wx.LC_SINGLE_SEL |wx.LC_VRULES |wx.NO_BORDER) - mainSizer.Add( self.paramList, 1, wx.ALL|wx.EXPAND, 0 ) - self.SetSizer( mainSizer ) + style=wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES | wx.NO_BORDER) + mainSizer.Add(self.paramList, 1, wx.ALL | wx.EXPAND, 0) + self.SetSizer(mainSizer) self.toggleView = 1 self.stuff = stuff @@ -290,29 +269,31 @@ class ItemParams (wx.Panel): self.attrValues = {} self._fetchValues() - self.m_staticline = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) - mainSizer.Add( self.m_staticline, 0, wx.EXPAND) - bSizer = wx.BoxSizer( wx.HORIZONTAL ) + self.m_staticline = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) + mainSizer.Add(self.m_staticline, 0, wx.EXPAND) + bSizer = wx.BoxSizer(wx.HORIZONTAL) - self.totalAttrsLabel = wx.StaticText( self, wx.ID_ANY, u" ", wx.DefaultPosition, wx.DefaultSize, 0 ) - bSizer.Add( self.totalAttrsLabel, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT) + self.totalAttrsLabel = wx.StaticText(self, wx.ID_ANY, u" ", wx.DefaultPosition, wx.DefaultSize, 0) + bSizer.Add(self.totalAttrsLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT) - self.toggleViewBtn = wx.ToggleButton( self, wx.ID_ANY, u"Toggle view mode", wx.DefaultPosition, wx.DefaultSize, 0 ) - bSizer.Add( self.toggleViewBtn, 0, wx.ALIGN_CENTER_VERTICAL) + self.toggleViewBtn = wx.ToggleButton(self, wx.ID_ANY, u"Toggle view mode", wx.DefaultPosition, wx.DefaultSize, + 0) + bSizer.Add(self.toggleViewBtn, 0, wx.ALIGN_CENTER_VERTICAL) - self.exportStatsBtn = wx.ToggleButton( self, wx.ID_ANY, u"Export Item Stats", wx.DefaultPosition, wx.DefaultSize, 0 ) - bSizer.Add( self.exportStatsBtn, 0, wx.ALIGN_CENTER_VERTICAL) + self.exportStatsBtn = wx.ToggleButton(self, wx.ID_ANY, u"Export Item Stats", wx.DefaultPosition, wx.DefaultSize, + 0) + bSizer.Add(self.exportStatsBtn, 0, wx.ALIGN_CENTER_VERTICAL) if stuff is not None: - self.refreshBtn = wx.Button( self, wx.ID_ANY, u"Refresh", wx.DefaultPosition, wx.DefaultSize, wx.BU_EXACTFIT ) - bSizer.Add( self.refreshBtn, 0, wx.ALIGN_CENTER_VERTICAL) - self.refreshBtn.Bind( wx.EVT_BUTTON, self.RefreshValues ) + self.refreshBtn = wx.Button(self, wx.ID_ANY, u"Refresh", wx.DefaultPosition, wx.DefaultSize, wx.BU_EXACTFIT) + bSizer.Add(self.refreshBtn, 0, wx.ALIGN_CENTER_VERTICAL) + self.refreshBtn.Bind(wx.EVT_BUTTON, self.RefreshValues) - mainSizer.Add( bSizer, 0, wx.ALIGN_RIGHT) + mainSizer.Add(bSizer, 0, wx.ALIGN_RIGHT) self.PopulateList() - self.toggleViewBtn.Bind(wx.EVT_TOGGLEBUTTON,self.ToggleViewMode) + self.toggleViewBtn.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleViewMode) self.exportStatsBtn.Bind(wx.EVT_TOGGLEBUTTON, self.ExportItemStats) def _fetchValues(self): @@ -348,7 +329,7 @@ class ItemParams (wx.Panel): event.Skip() def ToggleViewMode(self, event): - self.toggleView *=-1 + self.toggleView *= -1 self.UpdateList() event.Skip() @@ -412,17 +393,17 @@ class ItemParams (wx.Panel): ) def PopulateList(self): - self.paramList.InsertColumn(0,"Attribute") - self.paramList.InsertColumn(1,"Current Value") + self.paramList.InsertColumn(0, "Attribute") + self.paramList.InsertColumn(1, "Current Value") if self.stuff is not None: - self.paramList.InsertColumn(2,"Base Value") - self.paramList.SetColumnWidth(0,110) - self.paramList.SetColumnWidth(1,90) + self.paramList.InsertColumn(2, "Base Value") + self.paramList.SetColumnWidth(0, 110) + self.paramList.SetColumnWidth(1, 90) if self.stuff is not None: - self.paramList.SetColumnWidth(2,90) + self.paramList.SetColumnWidth(2, 90) self.paramList.setResizeColumn(0) self.imageList = wx.ImageList(16, 16) - self.paramList.SetImageList(self.imageList,wx.IMAGE_LIST_SMALL) + self.paramList.SetImageList(self.imageList, wx.IMAGE_LIST_SMALL) names = list(self.attrValues.iterkeys()) names.sort() @@ -461,7 +442,6 @@ class ItemParams (wx.Panel): else: attrIcon = self.imageList.Add(BitmapLoader.getBitmap("7_15", "icons")) - index = self.paramList.InsertImageStringItem(sys.maxint, attrName, attrIcon) idNameMap[idCount] = attrName self.paramList.SetItemData(index, idCount) @@ -485,51 +465,49 @@ class ItemParams (wx.Panel): if self.stuff is not None: self.paramList.SetStringItem(index, 2, valueUnitDefault) - - self.paramList.SortItems(lambda id1, id2: cmp(idNameMap[id1], idNameMap[id2])) self.paramList.RefreshRows() - self.totalAttrsLabel.SetLabel("%d attributes. " %idCount) + self.totalAttrsLabel.SetLabel("%d attributes. " % idCount) self.Layout() def TranslateValueUnit(self, value, unitName, unitDisplayName): def itemIDCallback(): - item = service.Market.getInstance().getItem(value) + item = Market.getInstance().getItem(value) return "%s (%d)" % (item.name, value) if item is not None else str(value) def groupIDCallback(): - group = service.Market.getInstance().getGroup(value) + group = Market.getInstance().getGroup(value) return "%s (%d)" % (group.name, value) if group is not None else str(value) def attributeIDCallback(): - attribute = service.Attribute.getInstance().getAttributeInfo(value) + attribute = Attribute.getInstance().getAttributeInfo(value) return "%s (%d)" % (attribute.name.capitalize(), value) - trans = {"Inverse Absolute Percent": (lambda: (1-value)*100, unitName), - "Inversed Modifier Percent": (lambda: (1-value) * 100, unitName), - "Modifier Percent": (lambda: ("%+.2f" if ((value - 1) * 100) % 1 else "%+d") % ((value - 1) * 100), unitName), + trans = {"Inverse Absolute Percent": (lambda: (1 - value) * 100, unitName), + "Inversed Modifier Percent": (lambda: (1 - value) * 100, unitName), + "Modifier Percent": ( + lambda: ("%+.2f" if ((value - 1) * 100) % 1 else "%+d") % ((value - 1) * 100), unitName), "Volume": (lambda: value, u"m\u00B3"), "Sizeclass": (lambda: value, ""), - "Absolute Percent": (lambda: (value * 100) , unitName), + "Absolute Percent": (lambda: (value * 100), unitName), "Milliseconds": (lambda: value / 1000.0, unitName), "typeID": (itemIDCallback, ""), - "groupID": (groupIDCallback,""), + "groupID": (groupIDCallback, ""), "attributeID": (attributeIDCallback, "")} override = trans.get(unitDisplayName) if override is not None: - - if type(override[0]()) == type(str()): - fvalue = override[0]() + v = override[0]() + if isinstance(v, str): + fvalue = v + elif isinstance(v, (int, float, long)): + fvalue = formatAmount(v, 3, 0, 0) else: - v = override[0]() - if isinstance(v, (int, float, long)): - fvalue = formatAmount(v, 3, 0, 0) - else: - fvalue = v - return "%s %s" % (fvalue , override[1]) + fvalue = v + return "%s %s" % (fvalue, override[1]) else: - return "%s %s" % (formatAmount(value, 3, 0),unitName) + return "%s %s" % (formatAmount(value, 3, 0), unitName) + class ItemCompare(wx.Panel): def __init__(self, parent, stuff, item, items, context=None): @@ -537,9 +515,7 @@ class ItemCompare(wx.Panel): mainSizer = wx.BoxSizer(wx.VERTICAL) self.paramList = AutoListCtrl(self, wx.ID_ANY, - style= # wx.LC_HRULES | - # wx.LC_NO_HEADER | - wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES | wx.NO_BORDER) + style=wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES | wx.NO_BORDER) mainSizer.Add(self.paramList, 1, wx.ALL | wx.EXPAND, 0) self.SetSizer(mainSizer) @@ -548,7 +524,8 @@ class ItemCompare(wx.Panel): self.currentSort = None self.sortReverse = False self.item = item - self.items = sorted(items, key=lambda x: x.attributes['metaLevel'].value if 'metaLevel' in x.attributes else None) + self.items = sorted(items, + key=lambda x: x.attributes['metaLevel'].value if 'metaLevel' in x.attributes else None) self.attrs = {} # get a dict of attrName: attrInfo of all unique attributes across all items @@ -603,7 +580,7 @@ class ItemCompare(wx.Panel): self.toggleViewBtn.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleViewMode) self.Bind(wx.EVT_LIST_COL_CLICK, self.SortCompareCols) - def SortCompareCols(self,event): + def SortCompareCols(self, event): self.Freeze() self.paramList.ClearAll() self.PopulateList(event.Column) @@ -627,7 +604,7 @@ class ItemCompare(wx.Panel): def processPrices(self, prices): for i, price in enumerate(prices): - self.paramList.SetStringItem(i, len(self.attrs)+1, formatAmount(price.price, 3, 3, 9, currency=True)) + self.paramList.SetStringItem(i, len(self.attrs) + 1, formatAmount(price.price, 3, 3, 9, currency=True)) def PopulateList(self, sort=None): @@ -658,13 +635,13 @@ class ItemCompare(wx.Panel): for i, attr in enumerate(self.attrs.keys()): name = self.attrs[attr].displayName if self.attrs[attr].displayName else attr - self.paramList.InsertColumn(i+1, name) - self.paramList.SetColumnWidth(i+1, 120) + self.paramList.InsertColumn(i + 1, name) + self.paramList.SetColumnWidth(i + 1, 120) - self.paramList.InsertColumn(len(self.attrs)+1, "Price") - self.paramList.SetColumnWidth(len(self.attrs)+1, 60) + self.paramList.InsertColumn(len(self.attrs) + 1, "Price") + self.paramList.SetColumnWidth(len(self.attrs) + 1, 60) - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() sMkt.getPrices([x.ID for x in self.items], self.processPrices) for item in self.items: @@ -680,28 +657,28 @@ class ItemCompare(wx.Panel): else: valueUnit = formatAmount(value, 3, 0, 0) - self.paramList.SetStringItem(i, x+1, valueUnit) + self.paramList.SetStringItem(i, x + 1, valueUnit) self.paramList.RefreshRows() self.Layout() def TranslateValueUnit(self, value, unitName, unitDisplayName): def itemIDCallback(): - item = service.Market.getInstance().getItem(value) + item = Market.getInstance().getItem(value) return "%s (%d)" % (item.name, value) if item is not None else str(value) def groupIDCallback(): - group = service.Market.getInstance().getGroup(value) + group = Market.getInstance().getGroup(value) return "%s (%d)" % (group.name, value) if group is not None else str(value) def attributeIDCallback(): - attribute = service.Attribute.getInstance().getAttributeInfo(value) + attribute = Attribute.getInstance().getAttributeInfo(value) return "%s (%d)" % (attribute.name.capitalize(), value) trans = {"Inverse Absolute Percent": (lambda: (1 - value) * 100, unitName), "Inversed Modifier Percent": (lambda: (1 - value) * 100, unitName), "Modifier Percent": ( - lambda: ("%+.2f" if ((value - 1) * 100) % 1 else "%+d") % ((value - 1) * 100), unitName), + lambda: ("%+.2f" if ((value - 1) * 100) % 1 else "%+d") % ((value - 1) * 100), unitName), "Volume": (lambda: value, u"m\u00B3"), "Sizeclass": (lambda: value, ""), "Absolute Percent": (lambda: (value * 100), unitName), @@ -712,37 +689,30 @@ class ItemCompare(wx.Panel): override = trans.get(unitDisplayName) if override is not None: - - if type(override[0]()) == type(str()): - fvalue = override[0]() + v = override[0]() + if isinstance(v, str): + fvalue = v + elif isinstance(v, (int, float, long)): + fvalue = formatAmount(v, 3, 0, 0) else: - v = override[0]() - if isinstance(v, (int, float, long)): - fvalue = formatAmount(v, 3, 0, 0) - else: - fvalue = v + fvalue = v return "%s %s" % (fvalue, override[1]) else: return "%s %s" % (formatAmount(value, 3, 0), unitName) -########################################################################### -## Class ItemRequirements -########################################################################### - -class ItemRequirements ( wx.Panel ): - +class ItemRequirements(wx.Panel): def __init__(self, parent, stuff, item): - wx.Panel.__init__ (self, parent, style = wx.TAB_TRAVERSAL) + wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL) - #itemId is set by the parent. - self.romanNb = ["0","I","II","III","IV","V","VI","VII","VIII","IX","X"] - self.skillIdHistory=[] - mainSizer = wx.BoxSizer( wx.VERTICAL ) + # itemId is set by the parent. + self.romanNb = ["0", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X"] + self.skillIdHistory = [] + mainSizer = wx.BoxSizer(wx.VERTICAL) - self.reqTree = wx.TreeCtrl(self, style = wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT | wx.NO_BORDER) + self.reqTree = wx.TreeCtrl(self, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT | wx.NO_BORDER) - mainSizer.Add(self.reqTree, 1, wx.ALL|wx.EXPAND, 0) + mainSizer.Add(self.reqTree, 1, wx.ALL | wx.EXPAND, 0) self.SetSizer(mainSizer) self.root = self.reqTree.AddRoot("WINRARZOR") @@ -752,25 +722,21 @@ class ItemRequirements ( wx.Panel ): self.reqTree.SetImageList(self.imageList) skillBookId = self.imageList.Add(BitmapLoader.getBitmap("skill_small", "gui")) - self.getFullSkillTree(item,self.root,skillBookId) + self.getFullSkillTree(item, self.root, skillBookId) self.reqTree.ExpandAll() self.Layout() - def getFullSkillTree(self,parentSkill,parent,sbIconId): + def getFullSkillTree(self, parentSkill, parent, sbIconId): for skill, level in parentSkill.requiredSkills.iteritems(): - child = self.reqTree.AppendItem(parent,"%s %s" %(skill.name,self.romanNb[int(level)]), sbIconId) + child = self.reqTree.AppendItem(parent, "%s %s" % (skill.name, self.romanNb[int(level)]), sbIconId) if skill.ID not in self.skillIdHistory: - self.getFullSkillTree(skill,child,sbIconId) + self.getFullSkillTree(skill, child, sbIconId) self.skillIdHistory.append(skill.ID) -########################################################################### -## Class ItemEffects -########################################################################### - -class ItemEffects (wx.Panel): +class ItemEffects(wx.Panel): def __init__(self, parent, stuff, item): wx.Panel.__init__(self, parent) self.item = item @@ -778,10 +744,7 @@ class ItemEffects (wx.Panel): mainSizer = wx.BoxSizer(wx.VERTICAL) self.effectList = AutoListCtrl(self, wx.ID_ANY, - style= - # wx.LC_HRULES | - # wx.LC_NO_HEADER | - wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES | wx.NO_BORDER) + style=wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.LC_VRULES | wx.NO_BORDER) mainSizer.Add(self.effectList, 1, wx.ALL | wx.EXPAND, 0) self.SetSizer(mainSizer) @@ -793,17 +756,17 @@ class ItemEffects (wx.Panel): def PopulateList(self): - self.effectList.InsertColumn(0,"Name") - self.effectList.InsertColumn(1,"Active") + self.effectList.InsertColumn(0, "Name") + self.effectList.InsertColumn(1, "Active") self.effectList.InsertColumn(2, "Type") if config.debug: self.effectList.InsertColumn(3, "Run Time") - self.effectList.InsertColumn(4,"ID") + self.effectList.InsertColumn(4, "ID") - #self.effectList.SetColumnWidth(0,385) + # self.effectList.SetColumnWidth(0,385) self.effectList.setResizeColumn(0) - self.effectList.SetColumnWidth(1,50) + self.effectList.SetColumnWidth(1, 50) self.effectList.SetColumnWidth(2, 80) if config.debug: self.effectList.SetColumnWidth(3, 65) @@ -872,18 +835,17 @@ class ItemEffects (wx.Panel): """ import os - file = os.path.join(config.pyfaPath, "eos", "effects", "%s.py"%event.GetText().lower()) + file_ = config.getPyfaPath(os.path.join("eos", "effects", "%s.py" % event.GetText().lower())) - if not os.path.isfile(file): - open(file, 'a').close() + if not os.path.isfile(file_): + open(file_, 'a').close() if 'wxMSW' in wx.PlatformInfo: - os.startfile(file) + os.startfile(file_) elif 'wxMac' in wx.PlatformInfo: - os.system("open "+file) + os.system("open " + file_) else: - import subprocess - subprocess.call(["xdg-open", file]) + subprocess.call(["xdg-open", file_]) def RefreshValues(self, event): self.Freeze() @@ -894,13 +856,10 @@ class ItemEffects (wx.Panel): self.Thaw() event.Skip() -########################################################################### -## Class ItemAffectedBy -########################################################################### - -class ItemAffectedBy (wx.Panel): +class ItemAffectedBy(wx.Panel): ORDER = [Fit, Ship, Citadel, Mode, Module, Drone, Fighter, Implant, Booster, Skill] + def __init__(self, parent, stuff, item): wx.Panel.__init__(self, parent) self.stuff = stuff @@ -916,33 +875,33 @@ class ItemAffectedBy (wx.Panel): mainSizer = wx.BoxSizer(wx.VERTICAL) - self.affectedBy = wx.TreeCtrl(self, style = wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT | wx.NO_BORDER) - mainSizer.Add(self.affectedBy, 1, wx.ALL|wx.EXPAND, 0) + self.affectedBy = wx.TreeCtrl(self, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT | wx.NO_BORDER) + mainSizer.Add(self.affectedBy, 1, wx.ALL | wx.EXPAND, 0) - self.m_staticline = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) + self.m_staticline = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) - mainSizer.Add( self.m_staticline, 0, wx.EXPAND) - bSizer = wx.BoxSizer( wx.HORIZONTAL ) + mainSizer.Add(self.m_staticline, 0, wx.EXPAND) + bSizer = wx.BoxSizer(wx.HORIZONTAL) - self.toggleExpandBtn = wx.ToggleButton( self, wx.ID_ANY, u"Expand All", wx.DefaultPosition, wx.DefaultSize, 0 ) - bSizer.Add( self.toggleExpandBtn, 0, wx.ALIGN_CENTER_VERTICAL) + self.toggleExpandBtn = wx.ToggleButton(self, wx.ID_ANY, u"Expand All", wx.DefaultPosition, wx.DefaultSize, 0) + bSizer.Add(self.toggleExpandBtn, 0, wx.ALIGN_CENTER_VERTICAL) - self.toggleNameBtn = wx.ToggleButton( self, wx.ID_ANY, u"Toggle Names", wx.DefaultPosition, wx.DefaultSize, 0 ) - bSizer.Add( self.toggleNameBtn, 0, wx.ALIGN_CENTER_VERTICAL) + self.toggleNameBtn = wx.ToggleButton(self, wx.ID_ANY, u"Toggle Names", wx.DefaultPosition, wx.DefaultSize, 0) + bSizer.Add(self.toggleNameBtn, 0, wx.ALIGN_CENTER_VERTICAL) - self.toggleViewBtn = wx.ToggleButton( self, wx.ID_ANY, u"Toggle View", wx.DefaultPosition, wx.DefaultSize, 0 ) - bSizer.Add( self.toggleViewBtn, 0, wx.ALIGN_CENTER_VERTICAL) + self.toggleViewBtn = wx.ToggleButton(self, wx.ID_ANY, u"Toggle View", wx.DefaultPosition, wx.DefaultSize, 0) + bSizer.Add(self.toggleViewBtn, 0, wx.ALIGN_CENTER_VERTICAL) if stuff is not None: - self.refreshBtn = wx.Button( self, wx.ID_ANY, u"Refresh", wx.DefaultPosition, wx.DefaultSize, wx.BU_EXACTFIT ) - bSizer.Add( self.refreshBtn, 0, wx.ALIGN_CENTER_VERTICAL) - self.refreshBtn.Bind( wx.EVT_BUTTON, self.RefreshTree ) + self.refreshBtn = wx.Button(self, wx.ID_ANY, u"Refresh", wx.DefaultPosition, wx.DefaultSize, wx.BU_EXACTFIT) + bSizer.Add(self.refreshBtn, 0, wx.ALIGN_CENTER_VERTICAL) + self.refreshBtn.Bind(wx.EVT_BUTTON, self.RefreshTree) - self.toggleNameBtn.Bind(wx.EVT_TOGGLEBUTTON,self.ToggleNameMode) - self.toggleExpandBtn.Bind(wx.EVT_TOGGLEBUTTON,self.ToggleExpand) - self.toggleViewBtn.Bind(wx.EVT_TOGGLEBUTTON,self.ToggleViewMode) + self.toggleNameBtn.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleNameMode) + self.toggleExpandBtn.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleExpand) + self.toggleViewBtn.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleViewMode) - mainSizer.Add( bSizer, 0, wx.ALIGN_RIGHT) + mainSizer.Add(bSizer, 0, wx.ALIGN_RIGHT) self.SetSizer(mainSizer) self.PopulateTree() self.Layout() @@ -964,9 +923,9 @@ class ItemAffectedBy (wx.Panel): # Skills are different in that they don't have itemModifiedAttributes, # which is needed if we send the container to itemStats dialog. So # instead, we send the item. - type = stuff.__class__.__name__ - contexts.append(("itemStats", type)) - menu = ContextMenu.getMenu(stuff if type != "Skill" else stuff.item, *contexts) + type_ = stuff.__class__.__name__ + contexts.append(("itemStats", type_)) + menu = ContextMenu.getMenu(stuff if type_ != "Skill" else stuff.item, *contexts) self.PopupMenu(menu) def ExpandCollapseTree(self): @@ -982,7 +941,7 @@ class ItemAffectedBy (wx.Panel): self.Thaw() - def ToggleExpand(self,event): + def ToggleExpand(self, event): self.expand *= -1 self.ExpandCollapseTree() @@ -1042,20 +1001,22 @@ class ItemAffectedBy (wx.Panel): return attr def buildAttributeView(self, root): - # We first build a usable dictionary of items. The key is either a fit - # if the afflictions stem from a projected fit, or self.stuff if they - # are local afflictions (everything else, even gang boosts at this time) - # The value of this is yet another dictionary in the following format: - # - # "attribute name": { - # "Module Name": [ - # class of affliction, - # affliction item (required due to GH issue #335) - # modifier type - # amount of modification - # whether this affliction was projected - # ] - # } + """ + We first build a usable dictionary of items. The key is either a fit + if the afflictions stem from a projected fit, or self.stuff if they + are local afflictions (everything else, even gang boosts at this time) + The value of this is yet another dictionary in the following format: + + "attribute name": { + "Module Name": [ + class of affliction, + affliction item (required due to GH issue #335) + modifier type + amount of modification + whether this affliction was projected + ] + } + """ attributes = self.stuff.itemModifiedAttributes if self.item == self.stuff.item else self.stuff.chargeModifiedAttributes container = {} @@ -1091,7 +1052,8 @@ class ItemAffectedBy (wx.Panel): else: item = afflictor.item - items[attrName].append((type(afflictor), afflictor, item, modifier, amount, getattr(afflictor, "projected", False))) + items[attrName].append( + (type(afflictor), afflictor, item, modifier, amount, getattr(afflictor, "projected", False))) # Make sure projected fits are on top rootOrder = container.keys() @@ -1167,20 +1129,21 @@ class ItemAffectedBy (wx.Panel): treeItem = self.affectedBy.AppendItem(child, display, itemIcon) self.affectedBy.SetPyData(treeItem, afflictor) - def buildModuleView(self, root): - # We first build a usable dictionary of items. The key is either a fit - # if the afflictions stem from a projected fit, or self.stuff if they - # are local afflictions (everything else, even gang boosts at this time) - # The value of this is yet another dictionary in the following format: - # - # "Module Name": [ - # class of affliction, - # set of afflictors (such as 2 of the same module), - # info on affliction (attribute name, modifier, and modification amount), - # item that will be used to determine icon (required due to GH issue #335) - # whether this affliction is actually used (unlearned skills are not used) - # ] + """ + We first build a usable dictionary of items. The key is either a fit + if the afflictions stem from a projected fit, or self.stuff if they + are local afflictions (everything else, even gang boosts at this time) + The value of this is yet another dictionary in the following format: + + "Module Name": [ + class of affliction, + set of afflictors (such as 2 of the same module), + info on affliction (attribute name, modifier, and modification amount), + item that will be used to determine icon (required due to GH issue #335) + whether this affliction is actually used (unlearned skills are not used) + ] + """ attributes = self.stuff.itemModifiedAttributes if self.item == self.stuff.item else self.stuff.chargeModifiedAttributes container = {} @@ -1291,17 +1254,28 @@ class ItemAffectedBy (wx.Panel): else: penalized = "" - attributes.append((attrName, (displayName if displayName != "" else attrName), attrModifier, attrAmount, penalized, attrIcon)) + attributes.append((attrName, (displayName if displayName != "" else attrName), attrModifier, + attrAmount, penalized, attrIcon)) - attrSorted = sorted(attributes, key = lambda attribName: attribName[0]) + attrSorted = sorted(attributes, key=lambda attribName: attribName[0]) for attr in attrSorted: attrName, displayName, attrModifier, attrAmount, penalized, attrIcon = attr if self.showRealNames: display = "%s %s %.2f %s" % (attrName, attrModifier, attrAmount, penalized) - saved = "%s %s %.2f %s" % ((displayName if displayName != "" else attrName), attrModifier, attrAmount, penalized) + saved = "%s %s %.2f %s" % ( + displayName if displayName != "" else attrName, + attrModifier, + attrAmount, + penalized + ) else: - display = "%s %s %.2f %s" % ((displayName if displayName != "" else attrName), attrModifier, attrAmount, penalized) + display = "%s %s %.2f %s" % ( + displayName if displayName != "" else attrName, + attrModifier, + attrAmount, + penalized + ) saved = "%s %s %.2f %s" % (attrName, attrModifier, attrAmount, penalized) treeitem = self.affectedBy.AppendItem(child, display, attrIcon) diff --git a/gui/mainFrame.py b/gui/mainFrame.py index efde1a3ab..244ac215b 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,10 +15,11 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import sys import os.path +import logging import sqlalchemy import wx @@ -26,17 +27,14 @@ import time from codecs import open -from wx._core import PyDeadObjectError from wx.lib.wordwrap import wordwrap -import service import config -import threading -import webbrowser + +from eos.config import gamedata_version import gui.aboutData import gui.chromeTabs -import gui.utils.animUtils as animUtils import gui.globalEvents as GE from gui.bitmapLoader import BitmapLoader @@ -56,37 +54,56 @@ from gui.graphFrame import GraphFrame from gui.copySelectDialog import CopySelectDialog from gui.utils.clipboard import toClipboard, fromClipboard from gui.updateDialog import UpdateDialog -from gui.builtinViews import * +from gui.builtinViews import * # TODO: unsure if this is needed here +from gui import graphFrame + +from service.settings import SettingsProvider +from service.fit import Fit +from service.character import Character +from service.update import Update # import this to access override setting from eos.modifiedAttributeDict import ModifiedAttributeDict from eos.db.saveddata.loadDefaultDatabaseValues import DefaultDatabaseValues +from eos import db +from service.port import Port +from service.settings import HTMLExportSettings from time import gmtime, strftime -if not 'wxMac' in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3,0)): +import threading +import webbrowser + +if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3, 0)): + from service.crest import Crest from service.crest import CrestModes from gui.crestFittings import CrestFittings, ExportToEve, CrestMgmt try: from gui.propertyEditor import AttributeEditor + disableOverrideEditor = False - except ImportError, e: - print "Error loading Attribute Editor: %s.\nAccess to Attribute Editor is disabled."%e.message + except ImportError as e: + print("Error loading Attribute Editor: %s.\nAccess to Attribute Editor is disabled." % e.message) disableOverrideEditor = True -#dummy panel(no paint no erasebk) +logger = logging.getLogger("pyfa.gui.mainFrame") + + +# dummy panel(no paint no erasebk) class PFPanel(wx.Panel): - def __init__(self,parent): - wx.Panel.__init__(self,parent) + def __init__(self, parent): + wx.Panel.__init__(self, parent) self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnBkErase) def OnPaint(self, event): event.Skip() + def OnBkErase(self, event): pass + class OpenFitsThread(threading.Thread): def __init__(self, fits, callback): threading.Thread.__init__(self) @@ -112,34 +129,36 @@ class OpenFitsThread(threading.Thread): wx.PostEvent(self.mainFrame, FitSelected(fitID=self.fits[-1], startup=2)) wx.CallAfter(self.callback) + class MainFrame(wx.Frame): __instance = None + @classmethod def getInstance(cls): return cls.__instance if cls.__instance is not None else MainFrame() def __init__(self, title): - self.title=title + self.title = title wx.Frame.__init__(self, None, wx.ID_ANY, self.title) MainFrame.__instance = self - #Load stored settings (width/height/maximized..) + # Load stored settings (width/height/maximized..) self.LoadMainFrameAttribs() - #Fix for msw (have the frame background color match panel color + # Fix for msw (have the frame background color match panel color if 'wxMSW' in wx.PlatformInfo: - self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) ) + self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE)) - #Load and set the icon for pyfa main window + # Load and set the icon for pyfa main window i = wx.IconFromBitmap(BitmapLoader.getBitmap("pyfa", "gui")) self.SetIcon(i) - #Create the layout and windows + # Create the layout and windows mainSizer = wx.BoxSizer(wx.HORIZONTAL) - self.browser_fitting_split = wx.SplitterWindow(self, style = wx.SP_LIVE_UPDATE) - self.fitting_additions_split = wx.SplitterWindow(self.browser_fitting_split, style = wx.SP_LIVE_UPDATE) + self.browser_fitting_split = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE) + self.fitting_additions_split = wx.SplitterWindow(self.browser_fitting_split, style=wx.SP_LIVE_UPDATE) mainSizer.Add(self.browser_fitting_split, 1, wx.EXPAND | wx.LEFT, 2) @@ -152,11 +171,11 @@ class MainFrame(wx.Frame): shipBrowserImg = BitmapLoader.getImage("ship_small", "gui") self.marketBrowser = MarketBrowser(self.notebookBrowsers) - self.notebookBrowsers.AddPage(self.marketBrowser, "Market", tabImage = marketImg, showClose = False) + self.notebookBrowsers.AddPage(self.marketBrowser, "Market", tabImage=marketImg, showClose=False) self.marketBrowser.splitter.SetSashPosition(self.marketHeight) self.shipBrowser = ShipBrowser(self.notebookBrowsers) - self.notebookBrowsers.AddPage(self.shipBrowser, "Fittings", tabImage = shipBrowserImg, showClose = False) + self.notebookBrowsers.AddPage(self.shipBrowser, "Fittings", tabImage=shipBrowserImg, showClose=False) self.notebookBrowsers.SetSelection(1) @@ -181,7 +200,7 @@ class MainFrame(wx.Frame): self.SetSizer(mainSizer) - #Add menu + # Add menu self.addPageId = wx.NewId() self.closePageId = wx.NewId() @@ -189,23 +208,23 @@ class MainFrame(wx.Frame): self.SetMenuBar(MainMenuBar()) self.registerMenu() - #Internal vars to keep track of other windows (graphing/stats) + # Internal vars to keep track of other windows (graphing/stats) self.graphFrame = None self.statsWnds = [] self.activeStatsWnd = None self.Bind(wx.EVT_CLOSE, self.OnClose) - #Show ourselves + # Show ourselves self.Show() self.LoadPreviousOpenFits() - #Check for updates - self.sUpdate = service.Update.getInstance() + # Check for updates + self.sUpdate = Update.getInstance() self.sUpdate.CheckUpdate(self.ShowUpdateBox) - if not 'wxMac' in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3,0)): + if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3, 0)): self.Bind(GE.EVT_SSO_LOGIN, self.onSSOLogin) self.Bind(GE.EVT_SSO_LOGOUT, self.onSSOLogout) @@ -217,9 +236,10 @@ class MainFrame(wx.Frame): dlg.ShowModal() def LoadPreviousOpenFits(self): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() - self.prevOpenFits = service.SettingsProvider.getInstance().getSettings("pyfaPrevOpenFits", {"enabled": False, "pyfaOpenFits": []}) + self.prevOpenFits = SettingsProvider.getInstance().getSettings("pyfaPrevOpenFits", + {"enabled": False, "pyfaOpenFits": []}) fits = self.prevOpenFits['pyfaOpenFits'] # Remove any fits that cause exception when fetching (non-existent fits) @@ -238,8 +258,10 @@ class MainFrame(wx.Frame): OpenFitsThread(fits, self.closeWaitDialog) def LoadMainFrameAttribs(self): - mainFrameDefaultAttribs = {"wnd_width": 1000, "wnd_height": 700, "wnd_maximized": False, "browser_width": 300, "market_height": 0, "fitting_height": -200} - self.mainFrameAttribs = service.SettingsProvider.getInstance().getSettings("pyfaMainWindowAttribs", mainFrameDefaultAttribs) + mainFrameDefaultAttribs = {"wnd_width": 1000, "wnd_height": 700, "wnd_maximized": False, "browser_width": 300, + "market_height": 0, "fitting_height": -200} + self.mainFrameAttribs = SettingsProvider.getInstance().getSettings("pyfaMainWindowAttribs", + mainFrameDefaultAttribs) if self.mainFrameAttribs["wnd_maximized"]: width = mainFrameDefaultAttribs["wnd_width"] @@ -259,7 +281,7 @@ class MainFrame(wx.Frame): def UpdateMainFrameAttribs(self): if self.IsIconized(): return - width,height = self.GetSize() + width, height = self.GetSize() self.mainFrameAttribs["wnd_width"] = width self.mainFrameAttribs["wnd_height"] = height @@ -293,7 +315,7 @@ class MainFrame(wx.Frame): return m() if m is not None else None def getActiveView(self): - sel = self.fitMultiSwitch.GetSelectedPage() + self.fitMultiSwitch.GetSelectedPage() def CloseCurrentPage(self, evt): ms = self.fitMultiSwitch @@ -306,14 +328,14 @@ class MainFrame(wx.Frame): self.UpdateMainFrameAttribs() # save open fits - self.prevOpenFits['pyfaOpenFits'] = [] # clear old list + self.prevOpenFits['pyfaOpenFits'] = [] # clear old list for page in self.fitMultiSwitch.pages: m = getattr(page, "getActiveFit", None) if m is not None: - self.prevOpenFits['pyfaOpenFits'].append(m()) + self.prevOpenFits['pyfaOpenFits'].append(m()) # save all teh settingz - service.SettingsProvider.getInstance().saveAll() + SettingsProvider.getInstance().saveAll() event.Skip() def ExitApp(self, event): @@ -321,43 +343,41 @@ class MainFrame(wx.Frame): event.Skip() def ShowAboutBox(self, evt): - import eos.config v = sys.version_info info = wx.AboutDialogInfo() info.Name = "pyfa" info.Version = gui.aboutData.versionString 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\nLicenses:\n\t" + - "\n\t".join(gui.aboutData.licenses) + - "\n\nEVE Data: \t" + eos.config.gamedata_version + - "\nPython: \t\t" + '{}.{}.{}'.format(v.major, v.minor, v.micro) + - "\nwxPython: \t" + wx.__version__ + - "\nSQLAlchemy: \t" + sqlalchemy.__version__, - 500, wx.ClientDC(self)) - if "__WXGTK__" in wx.PlatformInfo: + "\n\t".join(gui.aboutData.developers) + + "\n\nAdditional credits:\n\t" + + "\n\t".join(gui.aboutData.credits) + + "\n\nLicenses:\n\t" + + "\n\t".join(gui.aboutData.licenses) + + "\n\nEVE Data: \t" + gamedata_version + + "\nPython: \t\t" + '{}.{}.{}'.format(v.major, v.minor, v.micro) + + "\nwxPython: \t" + wx.__version__ + + "\nSQLAlchemy: \t" + sqlalchemy.__version__, + 500, wx.ClientDC(self)) + if "__WXGTK__" in wx.PlatformInfo: forumUrl = "http://forums.eveonline.com/default.aspx?g=posts&t=466425" else: forumUrl = "http://forums.eveonline.com/default.aspx?g=posts&t=466425" info.WebSite = (forumUrl, "pyfa thread at EVE Online forum") wx.AboutBox(info) - def showCharacterEditor(self, event): - dlg=CharacterEditor(self) + dlg = CharacterEditor(self) dlg.Show() def showAttrEditor(self, event): - dlg=AttributeEditor(self) + dlg = AttributeEditor(self) dlg.Show() def showTargetResistsEditor(self, event): ResistsEditorDlg(self) def showDamagePatternEditor(self, event): - dlg=DmgPatternEditorDlg(self) + dlg = DmgPatternEditorDlg(self) dlg.ShowModal() dlg.Destroy() @@ -366,28 +386,31 @@ class MainFrame(wx.Frame): def showExportDialog(self, event): """ Export active fit """ - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(self.getActiveFit()) - defaultFile = "%s - %s.xml"%(fit.ship.item.name, fit.name) if fit else None + defaultFile = "%s - %s.xml" % (fit.ship.item.name, fit.name) if fit else None dlg = wx.FileDialog(self, "Save Fitting As...", - wildcard = "EVE XML fitting files (*.xml)|*.xml", - style = wx.FD_SAVE, + wildcard="EVE XML fitting files (*.xml)|*.xml", + style=wx.FD_SAVE, defaultFile=defaultFile) if dlg.ShowModal() == wx.ID_OK: - format = dlg.GetFilterIndex() + format_ = dlg.GetFilterIndex() path = dlg.GetPath() - if format == 0: - output = sFit.exportXml(None, self.getActiveFit()) + if format_ == 0: + sPort = Port.getInstance() + output = sPort.exportXml(None, fit) if '.' not in os.path.basename(path): path += ".xml" else: - print "oops, invalid fit format %d" % format + print("oops, invalid fit format %d" % format_) dlg.Destroy() return - file = open(path, "w", encoding="utf-8") - file.write(output) - file.close() + + with open(path, "w", encoding="utf-8") as openfile: + openfile.write(output) + openfile.close() + dlg.Destroy() def showPreferenceDialog(self, event): @@ -416,7 +439,7 @@ class MainFrame(wx.Frame): self.Bind(wx.EVT_MENU, self.loadDatabaseDefaults, id=menuBar.importDatabaseDefaultsId) # Widgets Inspector if config.debug: - self.Bind(wx.EVT_MENU, self.openWXInspectTool, id = self.widgetInspectMenuID) + self.Bind(wx.EVT_MENU, self.openWXInspectTool, id=self.widgetInspectMenuID) # About self.Bind(wx.EVT_MENU, self.ShowAboutBox, id=wx.ID_ABOUT) # Char editor @@ -444,32 +467,32 @@ class MainFrame(wx.Frame): # Preference dialog 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, self.goWiki, id=menuBar.wikiId) # EVE Forums - self.Bind(wx.EVT_MENU, self.goForums, id = menuBar.forumId) + self.Bind(wx.EVT_MENU, self.goForums, id=menuBar.forumId) # Save current character - self.Bind(wx.EVT_MENU, self.saveChar, id = menuBar.saveCharId) + self.Bind(wx.EVT_MENU, self.saveChar, id=menuBar.saveCharId) # Save current character as another character - self.Bind(wx.EVT_MENU, self.saveCharAs, id = menuBar.saveCharAsId) + self.Bind(wx.EVT_MENU, self.saveCharAs, id=menuBar.saveCharAsId) # Save current character - self.Bind(wx.EVT_MENU, self.revertChar, id = menuBar.revertCharId) + self.Bind(wx.EVT_MENU, self.revertChar, id=menuBar.revertCharId) # Browse fittings - self.Bind(wx.EVT_MENU, self.eveFittings, id = menuBar.eveFittingsId) + self.Bind(wx.EVT_MENU, self.eveFittings, id=menuBar.eveFittingsId) # Export to EVE - self.Bind(wx.EVT_MENU, self.exportToEve, id = menuBar.exportToEveId) + self.Bind(wx.EVT_MENU, self.exportToEve, id=menuBar.exportToEveId) # Handle SSO event (login/logout/manage characters, depending on mode and current state) - self.Bind(wx.EVT_MENU, self.ssoHandler, id = menuBar.ssoLoginId) + self.Bind(wx.EVT_MENU, self.ssoHandler, id=menuBar.ssoLoginId) # Open attribute editor - self.Bind(wx.EVT_MENU, self.showAttrEditor, id = menuBar.attrEditorId) + self.Bind(wx.EVT_MENU, self.showAttrEditor, id=menuBar.attrEditorId) # Toggle Overrides - self.Bind(wx.EVT_MENU, self.toggleOverrides, id = menuBar.toggleOverridesId) + self.Bind(wx.EVT_MENU, self.toggleOverrides, id=menuBar.toggleOverridesId) - #Clipboard exports + # Clipboard exports self.Bind(wx.EVT_MENU, self.exportToClipboard, id=wx.ID_COPY) - #Graphs + # Graphs self.Bind(wx.EVT_MENU, self.openGraphFrame, id=menuBar.graphFrameId) toggleSearchBoxId = wx.NewId() @@ -479,11 +502,11 @@ class MainFrame(wx.Frame): # Close Page self.Bind(wx.EVT_MENU, self.CloseCurrentPage, id=self.closePageId) - self.Bind(wx.EVT_MENU, self.HAddPage, id = self.addPageId) - self.Bind(wx.EVT_MENU, self.toggleSearchBox, id = toggleSearchBoxId) - self.Bind(wx.EVT_MENU, self.toggleShipMarket, id = toggleShipMarketId) - self.Bind(wx.EVT_MENU, self.CTabNext, id = ctabnext) - self.Bind(wx.EVT_MENU, self.CTabPrev, id = ctabprev) + self.Bind(wx.EVT_MENU, self.HAddPage, id=self.addPageId) + self.Bind(wx.EVT_MENU, self.toggleSearchBox, id=toggleSearchBoxId) + self.Bind(wx.EVT_MENU, self.toggleShipMarket, id=toggleShipMarketId) + self.Bind(wx.EVT_MENU, self.CTabNext, id=ctabnext) + self.Bind(wx.EVT_MENU, self.CTabPrev, id=ctabprev) actb = [(wx.ACCEL_CTRL, ord('T'), self.addPageId), (wx.ACCEL_CMD, ord('T'), self.addPageId), @@ -516,30 +539,30 @@ class MainFrame(wx.Frame): for i in range(0, self.additionsPane.notebook.GetPageCount()): self.additionsSelect.append(wx.NewId()) self.Bind(wx.EVT_MENU, self.AdditionsTabSelect, id=self.additionsSelect[i]) - actb.append((wx.ACCEL_CMD, i+49, self.additionsSelect[i])) - actb.append((wx.ACCEL_CTRL, i+49, self.additionsSelect[i])) + actb.append((wx.ACCEL_CMD, i + 49, self.additionsSelect[i])) + actb.append((wx.ACCEL_CTRL, i + 49, self.additionsSelect[i])) # Alt+1-9 for market item selection self.itemSelect = [] for i in range(0, 9): self.itemSelect.append(wx.NewId()) - self.Bind(wx.EVT_MENU, self.ItemSelect, id = self.itemSelect[i]) + self.Bind(wx.EVT_MENU, self.ItemSelect, id=self.itemSelect[i]) actb.append((wx.ACCEL_ALT, i + 49, self.itemSelect[i])) atable = wx.AcceleratorTable(actb) self.SetAcceleratorTable(atable) def eveFittings(self, event): - dlg=CrestFittings(self) + dlg = CrestFittings(self) dlg.Show() def updateTitle(self, event): - sCrest = service.Crest.getInstance() + sCrest = Crest.getInstance() char = sCrest.implicitCharacter if char: - t = time.gmtime(char.eve.expires-time.time()) + t = time.gmtime(char.eve.expires - time.time()) sTime = time.strftime("%H:%M:%S", t if t >= 0 else 0) - newTitle = "%s | %s - %s"%(self.title, char.name, sTime) + newTitle = "%s | %s - %s" % (self.title, char.name, sTime) self.SetTitle(newTitle) def onSSOLogin(self, event): @@ -569,7 +592,7 @@ class MainFrame(wx.Frame): self.SetTitle(self.title) menu = self.GetMenuBar() - sCrest = service.Crest.getInstance() + sCrest = Crest.getInstance() if type == CrestModes.IMPLICIT: menu.SetLabel(menu.ssoLoginId, "Login to EVE") @@ -582,7 +605,7 @@ class MainFrame(wx.Frame): menu.Enable(menu.exportToEveId, not enable) def ssoHandler(self, event): - sCrest = service.Crest.getInstance() + sCrest = Crest.getInstance() if sCrest.settings.get('mode') == CrestModes.IMPLICIT: if sCrest.implicitCharacter is not None: sCrest.logout() @@ -590,21 +613,22 @@ class MainFrame(wx.Frame): uri = sCrest.startServer() webbrowser.open(uri) else: - dlg=CrestMgmt(self) + dlg = CrestMgmt(self) dlg.Show() def exportToEve(self, event): - dlg=ExportToEve(self) + dlg = ExportToEve(self) dlg.Show() def toggleOverrides(self, event): ModifiedAttributeDict.OVERRIDES = not ModifiedAttributeDict.OVERRIDES wx.PostEvent(self, GE.FitChanged(fitID=self.getActiveFit())) menu = self.GetMenuBar() - menu.SetLabel(menu.toggleOverridesId, "Turn Overrides Off" if ModifiedAttributeDict.OVERRIDES else "Turn Overrides On") + menu.SetLabel(menu.toggleOverridesId, + "Turn Overrides Off" if ModifiedAttributeDict.OVERRIDES else "Turn Overrides On") def saveChar(self, event): - sChr = service.Character.getInstance() + sChr = Character.getInstance() charID = self.charSelection.getActiveCharacter() sChr.saveCharacter(charID) wx.PostEvent(self, GE.CharListUpdated()) @@ -615,7 +639,7 @@ class MainFrame(wx.Frame): dlg.ShowModal() def revertChar(self, event): - sChr = service.Character.getInstance() + sChr = Character.getInstance() charID = self.charSelection.getActiveCharacter() sChr.revertCharacter(charID) wx.PostEvent(self, GE.CharListUpdated()) @@ -638,7 +662,7 @@ class MainFrame(wx.Frame): def CTabPrev(self, event): self.fitMultiSwitch.PrevPage() - def HAddPage(self,event): + def HAddPage(self, event): self.fitMultiSwitch.AddPage() def toggleShipMarket(self, event): @@ -653,35 +677,35 @@ class MainFrame(wx.Frame): self.marketBrowser.search.Focus() def clipboardEft(self): - sFit = service.Fit.getInstance() - toClipboard(sFit.exportFit(self.getActiveFit())) + fit = db.getFit(self.getActiveFit()) + toClipboard(Port.exportEft(fit)) def clipboardEftImps(self): - sFit = service.Fit.getInstance() - toClipboard(sFit.exportEftImps(self.getActiveFit())) + fit = db.getFit(self.getActiveFit()) + toClipboard(Port.exportEftImps(fit)) def clipboardDna(self): - sFit = service.Fit.getInstance() - toClipboard(sFit.exportDna(self.getActiveFit())) + fit = db.getFit(self.getActiveFit()) + toClipboard(Port.exportDna(fit)) def clipboardCrest(self): - sFit = service.Fit.getInstance() - toClipboard(sFit.exportCrest(self.getActiveFit())) + fit = db.getFit(self.getActiveFit()) + toClipboard(Port.exportCrest(fit)) def clipboardXml(self): - sFit = service.Fit.getInstance() - toClipboard(sFit.exportXml(None, self.getActiveFit())) + fit = db.getFit(self.getActiveFit()) + toClipboard(Port.exportXml(None, fit)) def clipboardMultiBuy(self): - sFit = service.Fit.getInstance() - toClipboard(sFit.exportMultiBuy(self.getActiveFit())) + fit = db.getFit(self.getActiveFit()) + toClipboard(Port.exportMultiBuy(fit)) def importFromClipboard(self, event): - sFit = service.Fit.getInstance() + clipboard = fromClipboard() try: - fits = sFit.importFitFromBuffer(fromClipboard(), self.getActiveFit()) + fits = Port().importFitFromBuffer(clipboard, self.getActiveFit()) except: - pass + logger.error("Attempt to import failed:\n%s", clipboard) else: self._openAfterImport(fits) @@ -698,17 +722,19 @@ class MainFrame(wx.Frame): CopySelectDict[selected]() - dlg.Destroy() def exportSkillsNeeded(self, event): """ Exports skills needed for active fit and active character """ - sCharacter = service.Character.getInstance() - saveDialog = wx.FileDialog(self, "Export Skills Needed As...", - wildcard = "EVEMon skills training file (*.emp)|*.emp|" \ - "EVEMon skills training XML file (*.xml)|*.xml|" \ - "Text skills training file (*.txt)|*.txt", - style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) + sCharacter = Character.getInstance() + saveDialog = wx.FileDialog( + self, + "Export Skills Needed As...", + wildcard=("EVEMon skills training file (*.emp)|*.emp|" + "EVEMon skills training XML file (*.xml)|*.xml|" + "Text skills training file (*.txt)|*.txt"), + style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT, + ) if saveDialog.ShowModal() == wx.ID_OK: saveFmtInt = saveDialog.GetFilterIndex() @@ -731,66 +757,82 @@ class MainFrame(wx.Frame): def fileImportDialog(self, event): """Handles importing single/multiple EVE XML / EFT cfg fit files""" - sFit = service.Fit.getInstance() - dlg = wx.FileDialog(self, "Open One Or More Fitting Files", - wildcard = "EVE XML fitting files (*.xml)|*.xml|" \ - "EFT text fitting files (*.cfg)|*.cfg|" \ - "All Files (*)|*", - style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE) + sPort = Port.getInstance() + dlg = wx.FileDialog( + self, + "Open One Or More Fitting Files", + wildcard=("EVE XML fitting files (*.xml)|*.xml|" + "EFT text fitting files (*.cfg)|*.cfg|" + "All Files (*)|*"), + style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE + ) if (dlg.ShowModal() == wx.ID_OK): self.progressDialog = wx.ProgressDialog( - "Importing fits", - " "*100, # set some arbitrary spacing to create width in window - parent=self, style = wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME) + "Importing fits", + " " * 100, # set some arbitrary spacing to create width in window + parent=self, + style=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME + ) self.progressDialog.message = None - sFit.importFitsThreaded(dlg.GetPaths(), self.fileImportCallback) + sPort.importFitsThreaded(dlg.GetPaths(), self.fileImportCallback) self.progressDialog.ShowModal() dlg.Destroy() def backupToXml(self, event): """ Back up all fits to EVE XML file """ - defaultFile = "pyfa-fits-%s.xml"%strftime("%Y%m%d_%H%M%S", gmtime()) + defaultFile = "pyfa-fits-%s.xml" % strftime("%Y%m%d_%H%M%S", gmtime()) - saveDialog = wx.FileDialog(self, "Save Backup As...", - wildcard = "EVE XML fitting file (*.xml)|*.xml", - style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT, - defaultFile=defaultFile) + saveDialog = wx.FileDialog( + self, + "Save Backup As...", + wildcard="EVE XML fitting file (*.xml)|*.xml", + style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT, + defaultFile=defaultFile, + ) if saveDialog.ShowModal() == wx.ID_OK: filePath = saveDialog.GetPath() if '.' not in os.path.basename(filePath): filePath += ".xml" - sFit = service.Fit.getInstance() - max = sFit.countAllFits() + sFit = Fit.getInstance() + max_ = sFit.countAllFits() - self.progressDialog = wx.ProgressDialog("Backup fits", - "Backing up %d fits to: %s"%(max, filePath), - maximum=max, parent=self, - style=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME) - sFit.backupFits(filePath, self.backupCallback) + self.progressDialog = wx.ProgressDialog( + "Backup fits", + "Backing up %d fits to: %s" % (max_, filePath), + maximum=max_, + parent=self, + style=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME, + ) + Port().backupFits(filePath, self.backupCallback) self.progressDialog.ShowModal() def exportHtml(self, event): from gui.utils.exportHtml import exportHtml - sFit = service.Fit.getInstance() - settings = service.settings.HTMLExportSettings.getInstance() + sFit = Fit.getInstance() + settings = HTMLExportSettings.getInstance() - max = sFit.countAllFits() + max_ = sFit.countAllFits() path = settings.getPath() if not os.path.isdir(os.path.dirname(path)): - dlg = wx.MessageDialog(self, - "Invalid Path\n\nThe following path is invalid or does not exist: \n%s\n\nPlease verify path location pyfa's preferences."%path, - "Error", wx.OK | wx.ICON_ERROR) + dlg = wx.MessageDialog( + self, + "Invalid Path\n\nThe following path is invalid or does not exist: \n%s\n\nPlease verify path location pyfa's preferences." % path, + "Error", + wx.OK | wx.ICON_ERROR + ) if dlg.ShowModal() == wx.ID_OK: return - self.progressDialog = wx.ProgressDialog("Backup fits", - "Generating HTML file at: %s"%path, - maximum=max, parent=self, - style=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME) + self.progressDialog = wx.ProgressDialog( + "Backup fits", + "Generating HTML file at: %s" % path, + maximum=max_, parent=self, + style=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME + ) exportHtml.getInstance().refreshFittingHtml(True, self.backupCallback) self.progressDialog.ShowModal() @@ -827,7 +869,7 @@ class MainFrame(wx.Frame): self._openAfterImport(data) elif action == -2: dlg = wx.MessageDialog(self, - "The following error was generated\n\n%s\n\nBe aware that already processed fits were not saved"%data, + "The following error was generated\n\n%s\n\nBe aware that already processed fits were not saved" % data, "Import Error", wx.OK | wx.ICON_ERROR) if dlg.ShowModal() == wx.ID_OK: return @@ -852,14 +894,16 @@ class MainFrame(wx.Frame): def importCharacter(self, event): """ Imports character XML file from EVE API """ - dlg = wx.FileDialog(self, "Open One Or More Character Files", - wildcard="EVE API XML character files (*.xml)|*.xml|" \ - "All Files (*)|*", - style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE) + dlg = wx.FileDialog( + self, + "Open One Or More Character Files", + wildcard="EVE API XML character files (*.xml)|*.xml|All Files (*)|*", + style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE + ) if dlg.ShowModal() == wx.ID_OK: self.waitDialog = wx.BusyInfo("Importing Character...") - sCharacter = service.Character.getInstance() + sCharacter = Character.getInstance() sCharacter.importCharacter(dlg.GetPaths(), self.importCharacterCallback) def importCharacterCallback(self): @@ -872,7 +916,8 @@ class MainFrame(wx.Frame): def openGraphFrame(self, event): if not self.graphFrame: self.graphFrame = GraphFrame(self) - if gui.graphFrame.enabled: + + if graphFrame.enabled: self.graphFrame.Show() else: self.graphFrame.SetFocus() @@ -888,4 +933,3 @@ class MainFrame(wx.Frame): if not wnd: wnd = self InspectionTool().Show(wnd, True) - diff --git a/gui/mainMenuBar.py b/gui/mainMenuBar.py index 287866909..b543998c2 100644 --- a/gui/mainMenuBar.py +++ b/gui/mainMenuBar.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,19 +15,22 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx + import config -from gui.bitmapLoader import BitmapLoader +from service.character import Character import gui.mainFrame import gui.graphFrame import gui.globalEvents as GE -import service +from gui.bitmapLoader import BitmapLoader -if not 'wxMac' in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3,0)): +if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3, 0)): + from service.crest import Crest from service.crest import CrestModes + class MainMenuBar(wx.MenuBar): def __init__(self): self.characterEditorId = wx.NewId() @@ -51,7 +54,7 @@ class MainMenuBar(wx.MenuBar): self.toggleOverridesId = wx.NewId() self.importDatabaseDefaultsId = wx.NewId() - if 'wxMac' in wx.PlatformInfo and wx.VERSION >= (3,0): + if 'wxMac' in wx.PlatformInfo and wx.VERSION >= (3, 0): wx.ID_COPY = wx.NewId() wx.ID_PASTE = wx.NewId() @@ -80,8 +83,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") @@ -115,12 +118,12 @@ class MainMenuBar(wx.MenuBar): windowMenu.AppendItem(graphFrameItem) preferencesShortCut = "CTRL+," if 'wxMac' in wx.PlatformInfo else "CTRL+P" - preferencesItem = wx.MenuItem(windowMenu, wx.ID_PREFERENCES, "Preferences\t"+preferencesShortCut) + preferencesItem = wx.MenuItem(windowMenu, wx.ID_PREFERENCES, "Preferences\t" + preferencesShortCut) preferencesItem.SetBitmap(BitmapLoader.getBitmap("preferences_small", "gui")) windowMenu.AppendItem(preferencesItem) - if not 'wxMac' in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3,0)): - self.sCrest = service.Crest.getInstance() + if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3, 0)): + self.sCrest = Crest.getInstance() # CREST Menu crestMenu = wx.Menu() @@ -154,7 +157,8 @@ class MainMenuBar(wx.MenuBar): helpMenu.Append(wx.ID_ABOUT) if config.debug: - helpMenu.Append( self.mainFrame.widgetInspectMenuID, "Open Widgets Inspect tool", "Open Widgets Inspect tool") + helpMenu.Append(self.mainFrame.widgetInspectMenuID, "Open Widgets Inspect tool", + "Open Widgets Inspect tool") self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) @@ -164,7 +168,7 @@ class MainMenuBar(wx.MenuBar): self.Enable(wx.ID_COPY, enable) self.Enable(self.exportSkillsNeededId, enable) - sChar = service.Character.getInstance() + sChar = Character.getInstance() charID = self.mainFrame.charSelection.getActiveCharacter() char = sChar.getCharacter(charID) @@ -174,5 +178,3 @@ class MainMenuBar(wx.MenuBar): self.Enable(self.revertCharId, char.isDirty) event.Skip() - - diff --git a/gui/marketBrowser.py b/gui/marketBrowser.py index 14dea666c..0a4b9c25f 100644 --- a/gui/marketBrowser.py +++ b/gui/marketBrowser.py @@ -1,458 +1,458 @@ -#=============================================================================== -# 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 wx -import service -import gui.display as d -from gui.cachingImageList import CachingImageList -from gui.contextMenu import ContextMenu -import gui.PFSearchBox as SBox - -from gui.bitmapLoader import BitmapLoader - -ItemSelected, ITEM_SELECTED = wx.lib.newevent.NewEvent() - -RECENTLY_USED_MODULES = -2 -MAX_RECENTLY_USED_MODULES = 20 - -class MarketBrowser(wx.Panel): - def __init__(self, parent): - wx.Panel.__init__(self, parent) - vbox = wx.BoxSizer(wx.VERTICAL) - self.SetSizer(vbox) - - # Add a search box on top - self.search = SearchBox(self) - vbox.Add(self.search, 0, wx.EXPAND) - - self.splitter = wx.SplitterWindow(self, style = wx.SP_LIVE_UPDATE) - vbox.Add(self.splitter, 1, wx.EXPAND) - - # Grab market service instance and create child objects - self.sMkt = service.Market.getInstance() - self.searchMode = False - self.marketView = MarketTree(self.splitter, self) - self.itemView = ItemView(self.splitter, self) - - self.splitter.SplitHorizontally(self.marketView, self.itemView) - self.splitter.SetMinimumPaneSize(250) - - # Setup our buttons for metaGroup selection - # Same fix as for search box on macs, - # need some pixels of extra space or everything clips and is ugly - p = wx.Panel(self) - box = wx.BoxSizer(wx.HORIZONTAL) - p.SetSizer(box) - vbox.Add(p, 0, wx.EXPAND) - self.metaButtons = [] - for name in self.sMkt.META_MAP.keys(): - btn = wx.ToggleButton(p, wx.ID_ANY, name.capitalize(), style=wx.BU_EXACTFIT) - setattr(self, name, btn) - box.Add(btn, 1, wx.ALIGN_CENTER) - btn.Bind(wx.EVT_TOGGLEBUTTON, self.toggleMetaButton) - btn.metaName = name - self.metaButtons.append(btn) - # Make itemview to set toggles according to list contents - self.itemView.setToggles() - - p.SetMinSize((wx.SIZE_AUTO_WIDTH, btn.GetSize()[1] + 5)) - - def toggleMetaButton(self, event): - """Process clicks on toggle buttons""" - ctrl = wx.GetMouseState().CmdDown() - ebtn = event.EventObject - if not ctrl: - for btn in self.metaButtons: - if btn.Enabled: - if btn == ebtn: - btn.SetValue(True) - else: - btn.SetValue(False) - else: - # Note: using the 'wrong' value for clicked button might seem weird, - # But the button is toggled by wx and we should deal with it - activeBtns = set() - for btn in self.metaButtons: - if (btn.GetValue() is True and btn != ebtn) or (btn.GetValue() is False and btn == ebtn): - activeBtns.add(btn) - # Do 'nothing' if we're trying to turn last active button off - if len(activeBtns) == 1 and activeBtns.pop() == ebtn: - # Keep button in the same state - ebtn.SetValue(True) - return - # Leave old unfiltered list contents, just re-filter them and show - self.itemView.filterItemStore() - - def jump(self, item): - self.marketView.jump(item) - -class SearchBox(SBox.PFSearchBox): - def __init__(self, parent, **kwargs): - SBox.PFSearchBox.__init__(self, parent, **kwargs) - cancelBitmap = BitmapLoader.getBitmap("fit_delete_small","gui") - searchBitmap = BitmapLoader.getBitmap("fsearch_small","gui") - self.SetSearchBitmap(searchBitmap) - self.SetCancelBitmap(cancelBitmap) - self.ShowSearchButton() - self.ShowCancelButton() - -class MarketTree(wx.TreeCtrl): - def __init__(self, parent, marketBrowser): - wx.TreeCtrl.__init__(self, parent, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT) - self.root = self.AddRoot("root") - - self.imageList = CachingImageList(16, 16) - self.SetImageList(self.imageList) - - self.sMkt = marketBrowser.sMkt - self.marketBrowser = marketBrowser - - # Form market tree root - sMkt = self.sMkt - for mktGrp in sMkt.getMarketRoot(): - iconId = self.addImage(sMkt.getIconByMarketGroup(mktGrp)) - childId = self.AppendItem(self.root, mktGrp.name, iconId, data=wx.TreeItemData(mktGrp.ID)) - # All market groups which were never expanded are dummies, here we assume - # that all root market groups are expandable - self.AppendItem(childId, "dummy") - self.SortChildren(self.root) - - # Add recently used modules node - rumIconId = self.addImage("market_small", "gui") - self.AppendItem(self.root, "Recently Used Modules", rumIconId, data = wx.TreeItemData(RECENTLY_USED_MODULES)) - - # Bind our lookup method to when the tree gets expanded - self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.expandLookup) - - def addImage(self, iconFile, location="icons"): - if iconFile is None: - return -1 - return self.imageList.GetImageIndex(iconFile, location) - - def expandLookup(self, event): - """Process market tree expands""" - root = event.Item - child = self.GetFirstChild(root)[0] - # If child of given market group is a dummy - if self.GetItemText(child) == "dummy": - # Delete it - self.Delete(child) - # And add real market group contents - sMkt = self.sMkt - currentMktGrp = sMkt.getMarketGroup(self.GetPyData(root), eager="children") - for childMktGrp in sMkt.getMarketGroupChildren(currentMktGrp): - # If market should have items but it doesn't, do not show it - if sMkt.marketGroupValidityCheck(childMktGrp) is False: - continue - iconId = self.addImage(sMkt.getIconByMarketGroup(childMktGrp)) - try: - childId = self.AppendItem(root, childMktGrp.name, iconId, data=wx.TreeItemData(childMktGrp.ID)) - except: - continue - if sMkt.marketGroupHasTypesCheck(childMktGrp) is False: - self.AppendItem(childId, "dummy") - - self.SortChildren(root) - - def jump(self, item): - """Open market group and meta tab of given item""" - self.marketBrowser.searchMode = False - sMkt = self.sMkt - mg = sMkt.getMarketGroupByItem(item) - metaId = sMkt.getMetaGroupIdByItem(item) - - jumpList = [] - while mg is not None: - jumpList.append(mg.ID) - mg = mg.parent - - for id in sMkt.ROOT_MARKET_GROUPS: - if id in jumpList: - jumpList = jumpList[:jumpList.index(id)+1] - - item = self.root - for i in range(len(jumpList) -1, -1, -1): - target = jumpList[i] - child, cookie = self.GetFirstChild(item) - while self.GetItemPyData(child) != target: - child, cookie = self.GetNextChild(item, cookie) - - item = child - self.Expand(item) - - self.SelectItem(item) - self.marketBrowser.itemView.selectionMade(forcedMetaSelect=metaId) - -class ItemView(d.Display): - DEFAULT_COLS = ["Base Icon", - "Base Name", - "attr:power,,,True", - "attr:cpu,,,True"] - - def __init__(self, parent, marketBrowser): - d.Display.__init__(self, parent) - marketBrowser.Bind(wx.EVT_TREE_SEL_CHANGED, self.selectionMade) - - self.unfilteredStore = set() - self.filteredStore = set() - self.recentlyUsedModules = set() - self.sMkt = marketBrowser.sMkt - self.searchMode = marketBrowser.searchMode - - self.marketBrowser = marketBrowser - self.marketView = marketBrowser.marketView - - # Make sure our search actually does interesting stuff - self.marketBrowser.search.Bind(SBox.EVT_TEXT_ENTER, self.scheduleSearch) - self.marketBrowser.search.Bind(SBox.EVT_SEARCH_BTN, self.scheduleSearch) - self.marketBrowser.search.Bind(SBox.EVT_CANCEL_BTN, self.clearSearch) - self.marketBrowser.search.Bind(SBox.EVT_TEXT, self.scheduleSearch) - - # Make sure WE do interesting stuff too - self.Bind(wx.EVT_CONTEXT_MENU, self.contextMenu) - self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.itemActivated) - self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.startDrag) - - # Make reverse map, used by sorter - self.metaMap = self.makeReverseMetaMap() - - # Fill up recently used modules set - for itemID in self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"]: - self.recentlyUsedModules.add(self.sMkt.getItem(itemID)) - - def startDrag(self, event): - row = self.GetFirstSelected() - - if row != -1: - data = wx.PyTextDataObject() - data.SetText("market:"+str(self.active[row].ID)) - - dropSource = wx.DropSource(self) - dropSource.SetData(data) - res = dropSource.DoDragDrop() - - - def itemActivated(self, event=None): - # Check if something is selected, if so, spawn the menu for it - sel = self.GetFirstSelected() - if sel == -1: - return - - if self.mainFrame.getActiveFit(): - - self.storeRecentlyUsedMarketItem(self.active[sel].ID) - self.recentlyUsedModules = set() - for itemID in self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"]: - self.recentlyUsedModules.add(self.sMkt.getItem(itemID)) - - wx.PostEvent(self.mainFrame, ItemSelected(itemID=self.active[sel].ID)) - - def storeRecentlyUsedMarketItem(self, itemID): - if len(self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"]) > MAX_RECENTLY_USED_MODULES: - self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"].pop(0) - - self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"].append(itemID) - - def selectionMade(self, event=None, forcedMetaSelect=None): - self.marketBrowser.searchMode = False - # Grab the threeview selection and check if it's fine - sel = self.marketView.GetSelection() - if sel.IsOk(): - # Get data field of the selected item (which is a marketGroup ID if anything was selected) - seldata = self.marketView.GetPyData(sel) - if seldata is not None and seldata != RECENTLY_USED_MODULES: - # If market group treeview item doesn't have children (other market groups or dummies), - # then it should have items in it and we want to request them - if self.marketView.ItemHasChildren(sel) is False: - sMkt = self.sMkt - # Get current market group - mg = sMkt.getMarketGroup(seldata, eager=("items", "items.metaGroup")) - # Get all its items - items = sMkt.getItemsByMarketGroup(mg) - else: - items = set() - else: - # If method was called but selection wasn't actually made or we have a hit on recently used modules - if seldata == RECENTLY_USED_MODULES: - items = self.recentlyUsedModules - else: - items = set() - - # Fill store - self.updateItemStore(items) - - # Set toggle buttons / use search mode flag if recently used modules category is selected (in order to have all modules listed and not filtered) - if seldata is not RECENTLY_USED_MODULES: - self.setToggles(forcedMetaSelect=forcedMetaSelect) - else: - self.marketBrowser.searchMode = True - self.setToggles() - - # Update filtered items - self.filterItemStore() - - def updateItemStore(self, items): - self.unfilteredStore = items - - def filterItemStore(self): - sMkt = self.sMkt - selectedMetas = set() - for btn in self.marketBrowser.metaButtons: - if btn.GetValue(): - selectedMetas.update(sMkt.META_MAP[btn.metaName]) - self.filteredStore = sMkt.filterItemsByMeta(self.unfilteredStore, selectedMetas) - self.update(list(self.filteredStore)) - - def setToggles(self, forcedMetaSelect=None): - metaIDs = set() - sMkt = self.sMkt - for item in self.unfilteredStore: - metaIDs.add(sMkt.getMetaGroupIdByItem(item)) - anySelection = False - for btn in self.marketBrowser.metaButtons: - btnMetas = sMkt.META_MAP[btn.metaName] - if len(metaIDs.intersection(btnMetas)) > 0: - btn.Enable(True) - # Select all available buttons if we're searching - if self.marketBrowser.searchMode is True: - btn.SetValue(True) - # Select explicitly requested button - if forcedMetaSelect is not None: - btn.SetValue(True if forcedMetaSelect in btnMetas else False) - else: - btn.Enable(False) - btn.SetValue(False) - if btn.GetValue(): - anySelection = True - # If no buttons are pressed, press first active - if anySelection is False: - for btn in self.marketBrowser.metaButtons: - if btn.Enabled: - btn.SetValue(True) - break - - def scheduleSearch(self, event=None): - search = self.marketBrowser.search.GetLineText(0) - # Make sure we do not count wildcard as search symbol - realsearch = search.replace("*", "") - # Re-select market group if search query has zero length - if len(realsearch) == 0: - self.selectionMade() - return - # Show nothing if query is too short - elif len(realsearch) < 3: - self.clearSearch() - return - - self.marketBrowser.searchMode = True - self.sMkt.searchItems(search, self.populateSearch) - - def clearSearch(self, event=None): - # Wipe item store and update everything to accomodate with it - # If clearSearch was generated by SearchCtrl's Cancel button, clear the content also - - if event: - self.marketBrowser.search.Clear() - - self.marketBrowser.searchMode = False - self.updateItemStore(set()) - self.setToggles() - self.filterItemStore() - - def populateSearch(self, items): - # If we're no longer searching, dump the results - if self.marketBrowser.searchMode is False: - return - self.updateItemStore(items) - self.setToggles() - self.filterItemStore() - - def itemSort(self, item): - sMkt = self.sMkt - catname = sMkt.getCategoryByItem(item).name - try: - mktgrpid = sMkt.getMarketGroupByItem(item).ID - except AttributeError: - mktgrpid = None - print "unable to find market group for", item.name - parentname = sMkt.getParentItemByItem(item).name - # Get position of market group - metagrpid = sMkt.getMetaGroupIdByItem(item) - metatab = self.metaMap.get(metagrpid) - metalvl = self.metalvls.get(item.ID, 0) - return (catname, mktgrpid, parentname, metatab, metalvl, item.name) - - def contextMenu(self, event): - # Check if something is selected, if so, spawn the menu for it - sel = self.GetFirstSelected() - if sel == -1: - return - - item = self.active[sel] - - sMkt = self.sMkt - sourceContext = "marketItemGroup" if self.marketBrowser.searchMode is False else "marketItemMisc" - itemContext = sMkt.getCategoryByItem(item).name - - menu = ContextMenu.getMenu((item,), (sourceContext, itemContext)) - self.PopupMenu(menu) - - def populate(self, items): - if len(items) > 0: - # Get dictionary with meta level attribute - sAttr = service.Attribute.getInstance() - attrs = sAttr.getAttributeInfo("metaLevel") - sMkt = self.sMkt - self.metalvls = sMkt.directAttrRequest(items, attrs) - # Clear selection - self.deselectItems() - # Perform sorting, using item's meta levels besides other stuff - items.sort(key=self.itemSort) - # Mark current item list as active - self.active = items - # Show them - d.Display.populate(self, items) - - def refresh(self, items): - if len(items) > 1: - # Get dictionary with meta level attribute - sAttr = service.Attribute.getInstance() - attrs = sAttr.getAttributeInfo("metaLevel") - sMkt = self.sMkt - self.metalvls = sMkt.directAttrRequest(items, attrs) - # Re-sort stuff - items.sort(key=self.itemSort) - - for i, item in enumerate(items[:9]): - # set shortcut info for first 9 modules - item.marketShortcut = i+1 - - d.Display.refresh(self, items) - - def makeReverseMetaMap(self): - """ - Form map which tells in which tab items of given metagroup are located - """ - revmap = {} - i = 0 - for mgids in self.sMkt.META_MAP.itervalues(): - for mgid in mgids: - revmap[mgid] = i - i += 1 - return revmap +# ============================================================================= +# 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 wx +from service.market import Market +from service.attribute import Attribute +import gui.display as d +import gui.PFSearchBox as SBox +from gui.cachingImageList import CachingImageList +from gui.contextMenu import ContextMenu +from gui.bitmapLoader import BitmapLoader + +ItemSelected, ITEM_SELECTED = wx.lib.newevent.NewEvent() + +RECENTLY_USED_MODULES = -2 +MAX_RECENTLY_USED_MODULES = 20 + +class MetaButton(wx.ToggleButton): + def __init__(self, *args, **kwargs): + super(MetaButton, self).__init__(*args, **kwargs) + self.setUserSelection(True) + + def setUserSelection(self, isSelected): + self.userSelected = isSelected + self.SetValue(isSelected) + + def setMetaAvailable(self, isAvailable): + self.Enable(isAvailable) + # need to also SetValue(False) for windows because Enabled=False AND SetValue(True) looks enabled. + if not isAvailable: + self.SetValue(False) + + def reset(self): + self.Enable(True) + self.SetValue(self.userSelected) + +class MarketBrowser(wx.Panel): + def __init__(self, parent): + wx.Panel.__init__(self, parent) + vbox = wx.BoxSizer(wx.VERTICAL) + self.SetSizer(vbox) + + # Add a search box on top + self.search = SearchBox(self) + vbox.Add(self.search, 0, wx.EXPAND) + + self.splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE) + vbox.Add(self.splitter, 1, wx.EXPAND) + + # Grab market service instance and create child objects + self.sMkt = Market.getInstance() + self.searchMode = False + self.marketView = MarketTree(self.splitter, self) + self.itemView = ItemView(self.splitter, self) + + self.splitter.SplitHorizontally(self.marketView, self.itemView) + self.splitter.SetMinimumPaneSize(250) + + # Setup our buttons for metaGroup selection + # Same fix as for search box on macs, + # need some pixels of extra space or everything clips and is ugly + p = wx.Panel(self) + box = wx.BoxSizer(wx.HORIZONTAL) + p.SetSizer(box) + vbox.Add(p, 0, wx.EXPAND) + self.metaButtons = [] + for name in self.sMkt.META_MAP.keys(): + btn = MetaButton(p, wx.ID_ANY, name.capitalize(), style=wx.BU_EXACTFIT) + setattr(self, name, btn) + box.Add(btn, 1, wx.ALIGN_CENTER) + btn.Bind(wx.EVT_TOGGLEBUTTON, self.toggleMetaButton) + btn.metaName = name + self.metaButtons.append(btn) + # Make itemview to set toggles according to list contents + self.itemView.setToggles() + + p.SetMinSize((wx.SIZE_AUTO_WIDTH, btn.GetSize()[1] + 5)) + + def toggleMetaButton(self, event): + """Process clicks on toggle buttons""" + appendMeta = wx.GetMouseState().CmdDown() + clickedBtn = event.EventObject + + if appendMeta: + activeBtns = [btn for btn in self.metaButtons if btn.GetValue()] + if activeBtns: + clickedBtn.setUserSelection(clickedBtn.GetValue()) + self.itemView.filterItemStore() + else: + # Do 'nothing' if we're trying to turn last active button off + # Keep button in the same state + clickedBtn.setUserSelection(True) + else: + for btn in self.metaButtons: + btn.setUserSelection(btn == clickedBtn) + + self.itemView.filterItemStore() + + def jump(self, item): + self.marketView.jump(item) + + +class SearchBox(SBox.PFSearchBox): + def __init__(self, parent, **kwargs): + SBox.PFSearchBox.__init__(self, parent, **kwargs) + cancelBitmap = BitmapLoader.getBitmap("fit_delete_small", "gui") + searchBitmap = BitmapLoader.getBitmap("fsearch_small", "gui") + self.SetSearchBitmap(searchBitmap) + self.SetCancelBitmap(cancelBitmap) + self.ShowSearchButton() + self.ShowCancelButton() + + +class MarketTree(wx.TreeCtrl): + def __init__(self, parent, marketBrowser): + wx.TreeCtrl.__init__(self, parent, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT) + self.root = self.AddRoot("root") + + self.imageList = CachingImageList(16, 16) + self.SetImageList(self.imageList) + + self.sMkt = marketBrowser.sMkt + self.marketBrowser = marketBrowser + + # Form market tree root + sMkt = self.sMkt + for mktGrp in sMkt.getMarketRoot(): + iconId = self.addImage(sMkt.getIconByMarketGroup(mktGrp)) + childId = self.AppendItem(self.root, mktGrp.name, iconId, data=wx.TreeItemData(mktGrp.ID)) + # All market groups which were never expanded are dummies, here we assume + # that all root market groups are expandable + self.AppendItem(childId, "dummy") + self.SortChildren(self.root) + + # Add recently used modules node + rumIconId = self.addImage("market_small", "gui") + self.AppendItem(self.root, "Recently Used Modules", rumIconId, data=wx.TreeItemData(RECENTLY_USED_MODULES)) + + # Bind our lookup method to when the tree gets expanded + self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.expandLookup) + + def addImage(self, iconFile, location="icons"): + if iconFile is None: + return -1 + return self.imageList.GetImageIndex(iconFile, location) + + def expandLookup(self, event): + """Process market tree expands""" + root = event.Item + child = self.GetFirstChild(root)[0] + # If child of given market group is a dummy + if self.GetItemText(child) == "dummy": + # Delete it + self.Delete(child) + # And add real market group contents + sMkt = self.sMkt + currentMktGrp = sMkt.getMarketGroup(self.GetPyData(root), eager="children") + for childMktGrp in sMkt.getMarketGroupChildren(currentMktGrp): + # If market should have items but it doesn't, do not show it + if sMkt.marketGroupValidityCheck(childMktGrp) is False: + continue + iconId = self.addImage(sMkt.getIconByMarketGroup(childMktGrp)) + try: + childId = self.AppendItem(root, childMktGrp.name, iconId, data=wx.TreeItemData(childMktGrp.ID)) + except: + continue + if sMkt.marketGroupHasTypesCheck(childMktGrp) is False: + self.AppendItem(childId, "dummy") + + self.SortChildren(root) + + def jump(self, item): + """Open market group and meta tab of given item""" + self.marketBrowser.searchMode = False + sMkt = self.sMkt + mg = sMkt.getMarketGroupByItem(item) + + jumpList = [] + while mg is not None: + jumpList.append(mg.ID) + mg = mg.parent + + for id in sMkt.ROOT_MARKET_GROUPS: + if id in jumpList: + jumpList = jumpList[:jumpList.index(id) + 1] + + item = self.root + for i in range(len(jumpList) - 1, -1, -1): + target = jumpList[i] + child, cookie = self.GetFirstChild(item) + while self.GetItemPyData(child) != target: + child, cookie = self.GetNextChild(item, cookie) + + item = child + self.Expand(item) + + self.SelectItem(item) + self.marketBrowser.itemView.selectionMade() + + +class ItemView(d.Display): + DEFAULT_COLS = ["Base Icon", + "Base Name", + "attr:power,,,True", + "attr:cpu,,,True"] + + def __init__(self, parent, marketBrowser): + d.Display.__init__(self, parent) + marketBrowser.Bind(wx.EVT_TREE_SEL_CHANGED, self.selectionMade) + + self.unfilteredStore = set() + self.filteredStore = set() + self.recentlyUsedModules = set() + self.sMkt = marketBrowser.sMkt + self.searchMode = marketBrowser.searchMode + + self.marketBrowser = marketBrowser + self.marketView = marketBrowser.marketView + + # Make sure our search actually does interesting stuff + self.marketBrowser.search.Bind(SBox.EVT_TEXT_ENTER, self.scheduleSearch) + self.marketBrowser.search.Bind(SBox.EVT_SEARCH_BTN, self.scheduleSearch) + self.marketBrowser.search.Bind(SBox.EVT_CANCEL_BTN, self.clearSearch) + self.marketBrowser.search.Bind(SBox.EVT_TEXT, self.scheduleSearch) + + # Make sure WE do interesting stuff too + self.Bind(wx.EVT_CONTEXT_MENU, self.contextMenu) + self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.itemActivated) + self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.startDrag) + + # Make reverse map, used by sorter + self.metaMap = self.makeReverseMetaMap() + + # Fill up recently used modules set + for itemID in self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"]: + self.recentlyUsedModules.add(self.sMkt.getItem(itemID)) + + def startDrag(self, event): + row = self.GetFirstSelected() + + if row != -1: + data = wx.PyTextDataObject() + data.SetText("market:" + str(self.active[row].ID)) + + dropSource = wx.DropSource(self) + dropSource.SetData(data) + dropSource.DoDragDrop() + + def itemActivated(self, event=None): + # Check if something is selected, if so, spawn the menu for it + sel = self.GetFirstSelected() + if sel == -1: + return + + if self.mainFrame.getActiveFit(): + + self.storeRecentlyUsedMarketItem(self.active[sel].ID) + self.recentlyUsedModules = set() + for itemID in self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"]: + self.recentlyUsedModules.add(self.sMkt.getItem(itemID)) + + wx.PostEvent(self.mainFrame, ItemSelected(itemID=self.active[sel].ID)) + + def storeRecentlyUsedMarketItem(self, itemID): + if len(self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"]) > MAX_RECENTLY_USED_MODULES: + self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"].pop(0) + + self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"].append(itemID) + + def selectionMade(self, event=None): + self.marketBrowser.searchMode = False + # Grab the threeview selection and check if it's fine + sel = self.marketView.GetSelection() + if sel.IsOk(): + # Get data field of the selected item (which is a marketGroup ID if anything was selected) + seldata = self.marketView.GetPyData(sel) + if seldata is not None and seldata != RECENTLY_USED_MODULES: + # If market group treeview item doesn't have children (other market groups or dummies), + # then it should have items in it and we want to request them + if self.marketView.ItemHasChildren(sel) is False: + sMkt = self.sMkt + # Get current market group + mg = sMkt.getMarketGroup(seldata, eager=("items", "items.metaGroup")) + # Get all its items + items = sMkt.getItemsByMarketGroup(mg) + else: + items = set() + else: + # If method was called but selection wasn't actually made or we have a hit on recently used modules + if seldata == RECENTLY_USED_MODULES: + items = self.recentlyUsedModules + else: + items = set() + + # Fill store + self.updateItemStore(items) + + # Set toggle buttons / use search mode flag if recently used modules category is selected (in order to have all modules listed and not filtered) + if seldata is not RECENTLY_USED_MODULES: + self.setToggles() + else: + self.marketBrowser.searchMode = True + self.setToggles() + + # Update filtered items + self.filterItemStore() + + def updateItemStore(self, items): + self.unfilteredStore = items + + def filterItemStore(self): + sMkt = self.sMkt + selectedMetas = set() + for btn in self.marketBrowser.metaButtons: + if btn.GetValue(): + selectedMetas.update(sMkt.META_MAP[btn.metaName]) + self.filteredStore = sMkt.filterItemsByMeta(self.unfilteredStore, selectedMetas) + self.update(list(self.filteredStore)) + + def setToggles(self): + metaIDs = set() + sMkt = self.sMkt + for item in self.unfilteredStore: + metaIDs.add(sMkt.getMetaGroupIdByItem(item)) + + for btn in self.marketBrowser.metaButtons: + btn.reset() + btnMetas = sMkt.META_MAP[btn.metaName] + if len(metaIDs.intersection(btnMetas)) > 0: + btn.setMetaAvailable(True) + else: + btn.setMetaAvailable(False) + + def scheduleSearch(self, event=None): + search = self.marketBrowser.search.GetLineText(0) + # Make sure we do not count wildcard as search symbol + realsearch = search.replace("*", "") + # Re-select market group if search query has zero length + if len(realsearch) == 0: + self.selectionMade() + return + # Show nothing if query is too short + elif len(realsearch) < 3: + self.clearSearch() + return + + self.marketBrowser.searchMode = True + self.sMkt.searchItems(search, self.populateSearch) + + def clearSearch(self, event=None): + # Wipe item store and update everything to accomodate with it + # If clearSearch was generated by SearchCtrl's Cancel button, clear the content also + + if event: + self.marketBrowser.search.Clear() + + self.marketBrowser.searchMode = False + self.updateItemStore(set()) + self.setToggles() + self.filterItemStore() + + def populateSearch(self, items): + # If we're no longer searching, dump the results + if self.marketBrowser.searchMode is False: + return + self.updateItemStore(items) + self.setToggles() + self.filterItemStore() + + def itemSort(self, item): + sMkt = self.sMkt + catname = sMkt.getCategoryByItem(item).name + try: + mktgrpid = sMkt.getMarketGroupByItem(item).ID + except AttributeError: + mktgrpid = None + print("unable to find market group for", item.name) + parentname = sMkt.getParentItemByItem(item).name + # Get position of market group + metagrpid = sMkt.getMetaGroupIdByItem(item) + metatab = self.metaMap.get(metagrpid) + metalvl = self.metalvls.get(item.ID, 0) + return (catname, mktgrpid, parentname, metatab, metalvl, item.name) + + def contextMenu(self, event): + # Check if something is selected, if so, spawn the menu for it + sel = self.GetFirstSelected() + if sel == -1: + return + + item = self.active[sel] + + sMkt = self.sMkt + sourceContext = "marketItemGroup" if self.marketBrowser.searchMode is False else "marketItemMisc" + itemContext = sMkt.getCategoryByItem(item).name + + menu = ContextMenu.getMenu((item,), (sourceContext, itemContext)) + self.PopupMenu(menu) + + def populate(self, items): + if len(items) > 0: + # Get dictionary with meta level attribute + sAttr = Attribute.getInstance() + attrs = sAttr.getAttributeInfo("metaLevel") + sMkt = self.sMkt + self.metalvls = sMkt.directAttrRequest(items, attrs) + # Clear selection + self.deselectItems() + # Perform sorting, using item's meta levels besides other stuff + items.sort(key=self.itemSort) + # Mark current item list as active + self.active = items + # Show them + d.Display.populate(self, items) + + def refresh(self, items): + if len(items) > 1: + # Get dictionary with meta level attribute + sAttr = Attribute.getInstance() + attrs = sAttr.getAttributeInfo("metaLevel") + sMkt = self.sMkt + self.metalvls = sMkt.directAttrRequest(items, attrs) + # Re-sort stuff + items.sort(key=self.itemSort) + + for i, item in enumerate(items[:9]): + # set shortcut info for first 9 modules + item.marketShortcut = i + 1 + + d.Display.refresh(self, items) + + def makeReverseMetaMap(self): + """ + Form map which tells in which tab items of given metagroup are located + """ + revmap = {} + i = 0 + for mgids in self.sMkt.META_MAP.itervalues(): + for mgid in mgids: + revmap[mgid] = i + i += 1 + return revmap diff --git a/gui/multiSwitch.py b/gui/multiSwitch.py index 91532785d..766524a61 100644 --- a/gui/multiSwitch.py +++ b/gui/multiSwitch.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,7 +15,7 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import gui.chromeTabs import gui.builtinViews.emptyView @@ -24,7 +24,7 @@ import gui.builtinViews.emptyView class MultiSwitch(gui.chromeTabs.PFNotebook): def __init__(self, parent): gui.chromeTabs.PFNotebook.__init__(self, parent) - #self.AddPage() # now handled by mainFrame + # self.AddPage() # now handled by mainFrame self.handlers = handlers = [] for type in TabSpawner.tabTypes: handlers.append(type(self)) diff --git a/gui/notesView.py b/gui/notesView.py index efa933bb9..f607efb0b 100644 --- a/gui/notesView.py +++ b/gui/notesView.py @@ -1,9 +1,10 @@ import wx -import service +from service.fit import Fit import gui.globalEvents as GE import gui.mainFrame + class NotesView(wx.Panel): def __init__(self, parent): wx.Panel.__init__(self, parent) @@ -19,7 +20,7 @@ class NotesView(wx.Panel): self.Bind(wx.EVT_TIMER, self.delayedSave, self.saveTimer) def fitChanged(self, event): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(event.fitID) self.Parent.Parent.DisablePage(self, not fit or fit.isStructure) @@ -34,11 +35,11 @@ class NotesView(wx.Panel): def onText(self, event): # delay the save so we're not writing to sqlite on every keystroke - self.saveTimer.Stop() # cancel the existing timer + self.saveTimer.Stop() # cancel the existing timer self.saveTimer.Start(1000, True) def delayedSave(self, event): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(self.lastFitId) newNotes = self.editNotes.GetValue() fit.notes = newNotes diff --git a/gui/patternEditor.py b/gui/patternEditor.py index 171eed7a5..9d11a5ab9 100644 --- a/gui/patternEditor.py +++ b/gui/patternEditor.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,18 +15,15 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx from gui.bitmapLoader import BitmapLoader -import service from wx.lib.intctrl import IntCtrl from gui.utils.clipboard import toClipboard, fromClipboard -from service.damagePattern import ImportError from gui.builtinViews.entityEditor import EntityEditor, BaseValidator -########################################################################### -## Class DmgPatternEditorDlg -########################################################################### +from service.damagePattern import DamagePattern, ImportError + class DmgPatternTextValidor(BaseValidator): def __init__(self): @@ -47,7 +44,7 @@ class DmgPatternTextValidor(BaseValidator): raise ValueError("Damage Profile name already in use, please choose another.") return True - except ValueError, e: + except ValueError as e: wx.MessageBox(u"{}".format(e), "Error") textCtrl.SetFocus() return False @@ -59,33 +56,34 @@ class DmgPatternEntityEditor(EntityEditor): self.SetEditorValidator(DmgPatternTextValidor) def getEntitiesFromContext(self): - sDP = service.DamagePattern.getInstance() + sDP = DamagePattern.getInstance() choices = sorted(sDP.getDamagePatternList(), key=lambda p: p.name) return [c for c in choices if c.name != "Selected Ammo"] def DoNew(self, name): - sDP = service.DamagePattern.getInstance() + sDP = DamagePattern.getInstance() return sDP.newPattern(name) def DoRename(self, entity, name): - sDP = service.DamagePattern.getInstance() + sDP = DamagePattern.getInstance() sDP.renamePattern(entity, name) def DoCopy(self, entity, name): - sDP = service.DamagePattern.getInstance() + sDP = DamagePattern.getInstance() copy = sDP.copyPattern(entity) sDP.renamePattern(copy, name) return copy def DoDelete(self, entity): - sDP = service.DamagePattern.getInstance() + sDP = DamagePattern.getInstance() sDP.deletePattern(entity) + class DmgPatternEditorDlg(wx.Dialog): DAMAGE_TYPES = ("em", "thermal", "kinetic", "explosive") def __init__(self, parent): - wx.Dialog.__init__(self, parent, id = wx.ID_ANY, title = u"Damage Pattern Editor", size = wx.Size( 400,240 )) + wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title=u"Damage Pattern Editor", size=wx.Size(400, 240)) self.block = False self.SetSizeHintsSz(wx.DefaultSize, wx.DefaultSize) @@ -111,11 +109,11 @@ class DmgPatternEditorDlg(wx.Dialog): dmgeditSizer.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) width = -1 - defSize = wx.Size(width,-1) + defSize = wx.Size(width, -1) - for i, type in enumerate(self.DAMAGE_TYPES): - bmp = wx.StaticBitmap(self, wx.ID_ANY, BitmapLoader.getBitmap("%s_big"%type, "gui")) - if i%2: + for i, type_ in enumerate(self.DAMAGE_TYPES): + bmp = wx.StaticBitmap(self, wx.ID_ANY, BitmapLoader.getBitmap("%s_big" % type_, "gui")) + if i % 2: style = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT border = 20 else: @@ -123,13 +121,13 @@ class DmgPatternEditorDlg(wx.Dialog): border = 5 # set text edit - setattr(self, "%sEdit"%type, IntCtrl(self, wx.ID_ANY, 0, wx.DefaultPosition, defSize)) - setattr(self, "%sPerc"%type, wx.StaticText(self, wx.ID_ANY, u"0%")) - editObj = getattr(self, "%sEdit"%type) + setattr(self, "%sEdit" % type_, IntCtrl(self, wx.ID_ANY, 0, wx.DefaultPosition, defSize)) + setattr(self, "%sPerc" % type_, wx.StaticText(self, wx.ID_ANY, u"0%")) + editObj = getattr(self, "%sEdit" % type_) dmgeditSizer.Add(bmp, 0, style, border) dmgeditSizer.Add(editObj, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5) - dmgeditSizer.Add(getattr(self, "%sPerc"%type), 0, wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 5) + dmgeditSizer.Add(getattr(self, "%sPerc" % type_), 0, wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 5) editObj.Bind(wx.EVT_TEXT, self.ValuesUpdated) editObj.SetLimited(True) @@ -147,7 +145,7 @@ class DmgPatternEditorDlg(wx.Dialog): self.stNotice.Wrap(-1) perSizer.Add(self.stNotice, 0, wx.BOTTOM | wx.TOP | wx.LEFT, 5) - footerSizer.Add(perSizer, 1, wx.ALIGN_CENTER_VERTICAL, 5) + footerSizer.Add(perSizer, 1, wx.ALIGN_CENTER_VERTICAL, 5) self.totSizer = wx.BoxSizer(wx.VERTICAL) @@ -156,8 +154,8 @@ class DmgPatternEditorDlg(wx.Dialog): mainSizer.Add(contentSizer, 1, wx.EXPAND, 0) if "wxGTK" in wx.PlatformInfo: - self.closeBtn = wx.Button( self, wx.ID_ANY, u"Close", wx.DefaultPosition, wx.DefaultSize, 0 ) - mainSizer.Add( self.closeBtn, 0, wx.ALL|wx.ALIGN_RIGHT, 5 ) + self.closeBtn = wx.Button(self, wx.ID_ANY, u"Close", wx.DefaultPosition, wx.DefaultSize, 0) + mainSizer.Add(self.closeBtn, 0, wx.ALL | wx.ALIGN_RIGHT, 5) self.closeBtn.Bind(wx.EVT_BUTTON, self.closeEvent) self.SetSizer(mainSizer) @@ -166,18 +164,18 @@ class DmgPatternEditorDlg(wx.Dialog): ("Export", wx.ART_FILE_SAVE_AS, "to")) for name, art, direction in importExport: - bitmap = wx.ArtProvider.GetBitmap(art, wx.ART_BUTTON) - btn = wx.BitmapButton(self, wx.ID_ANY, bitmap) + bitmap = wx.ArtProvider.GetBitmap(art, wx.ART_BUTTON) + btn = wx.BitmapButton(self, wx.ID_ANY, bitmap) - btn.SetMinSize( btn.GetSize() ) - btn.SetMaxSize( btn.GetSize() ) + btn.SetMinSize(btn.GetSize()) + btn.SetMaxSize(btn.GetSize()) - btn.Layout() - setattr(self, name, btn) - btn.Enable(True) - btn.SetToolTipString("%s patterns %s clipboard" % (name, direction) ) - footerSizer.Add(btn, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_RIGHT) - btn.Bind(wx.EVT_BUTTON, getattr(self, "{}Patterns".format(name.lower()))) + btn.Layout() + setattr(self, name, btn) + btn.Enable(True) + btn.SetToolTipString("%s patterns %s clipboard" % (name, direction)) + footerSizer.Add(btn, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_RIGHT) + btn.Bind(wx.EVT_BUTTON, getattr(self, "{}Patterns".format(name.lower()))) self.Layout() bsize = self.GetBestSize() @@ -196,30 +194,30 @@ class DmgPatternEditorDlg(wx.Dialog): return p = self.entityEditor.getActiveEntity() - total = sum(map(lambda attr: getattr(self, "%sEdit"%attr).GetValue(), self.DAMAGE_TYPES)) - for type in self.DAMAGE_TYPES: - editObj = getattr(self, "%sEdit"%type) - percObj = getattr(self, "%sPerc"%type) - setattr(p, "%sAmount"%type, editObj.GetValue()) - percObj.SetLabel("%.1f%%"%(float(editObj.GetValue())*100/total if total > 0 else 0)) + total = sum(map(lambda attr: getattr(self, "%sEdit" % attr).GetValue(), self.DAMAGE_TYPES)) + for type_ in self.DAMAGE_TYPES: + editObj = getattr(self, "%sEdit" % type_) + percObj = getattr(self, "%sPerc" % type_) + setattr(p, "%sAmount" % type_, editObj.GetValue()) + percObj.SetLabel("%.1f%%" % (float(editObj.GetValue()) * 100 / total if total > 0 else 0)) self.totSizer.Layout() if event is not None: event.Skip() - service.DamagePattern.getInstance().saveChanges(p) + DamagePattern.getInstance().saveChanges(p) def restrict(self): - for type in self.DAMAGE_TYPES: - editObj = getattr(self, "%sEdit"%type) + for type_ in self.DAMAGE_TYPES: + editObj = getattr(self, "%sEdit" % type_) editObj.Enable(False) self.entityEditor.btnRename.Enable(False) self.entityEditor.btnDelete.Enable(False) def unrestrict(self): - for type in self.DAMAGE_TYPES: - editObj = getattr(self, "%sEdit"%type) + for type_ in self.DAMAGE_TYPES: + editObj = getattr(self, "%sEdit" % type_) editObj.Enable() self.entityEditor.btnRename.Enable() self.entityEditor.btnDelete.Enable() @@ -251,13 +249,13 @@ class DmgPatternEditorDlg(wx.Dialog): def importPatterns(self, event): text = fromClipboard() if text: - sDP = service.DamagePattern.getInstance() + sDP = DamagePattern.getInstance() try: sDP.importPatterns(text) self.stNotice.SetLabel("Patterns successfully imported from clipboard") - except service.damagePattern.ImportError, e: + except ImportError as e: self.stNotice.SetLabel(str(e)) - except Exception, e: + except Exception: self.stNotice.SetLabel("Could not import from clipboard: unknown errors") finally: self.entityEditor.refreshEntityList() @@ -265,6 +263,6 @@ class DmgPatternEditorDlg(wx.Dialog): self.stNotice.SetLabel("Could not import from clipboard") def exportPatterns(self, event): - sDP = service.DamagePattern.getInstance() - toClipboard( sDP.exportPatterns() ) + sDP = DamagePattern.getInstance() + toClipboard(sDP.exportPatterns()) self.stNotice.SetLabel("Patterns exported to clipboard") diff --git a/gui/preferenceDialog.py b/gui/preferenceDialog.py index ada936114..1d1146c85 100644 --- a/gui/preferenceDialog.py +++ b/gui/preferenceDialog.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,14 +15,14 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx from gui.preferenceView import PreferenceView from gui.bitmapLoader import BitmapLoader -class PreferenceDialog(wx.Dialog): +class PreferenceDialog(wx.Dialog): def __init__(self, parent): wx.Dialog.__init__(self, parent, id=wx.ID_ANY, size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE) self.SetTitle("pyfa - Preferences") @@ -33,22 +33,22 @@ class PreferenceDialog(wx.Dialog): self.listbook = wx.Listbook(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LB_DEFAULT) self.listview = self.listbook.GetListView() - #self.listview.SetMinSize((500, -1)) - #self.listview.SetSize((500, -1)) + # self.listview.SetMinSize((500, -1)) + # self.listview.SetSize((500, -1)) - self.imageList = wx.ImageList(32,32) + self.imageList = wx.ImageList(32, 32) self.listbook.SetImageList(self.imageList) - mainSizer.Add(self.listbook, 1, wx.EXPAND | wx.TOP|wx.BOTTOM|wx.LEFT, 5) + mainSizer.Add(self.listbook, 1, wx.EXPAND | wx.TOP | wx.BOTTOM | wx.LEFT, 5) - self.m_staticline2 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) - mainSizer.Add( self.m_staticline2, 0, wx.EXPAND, 5 ) + self.m_staticline2 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL) + mainSizer.Add(self.m_staticline2, 0, wx.EXPAND, 5) - btnSizer = wx.BoxSizer( wx.HORIZONTAL ) - btnSizer.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) - self.btnOK = wx.Button( self, wx.ID_ANY, u"OK", wx.DefaultPosition, wx.DefaultSize, 0 ) - btnSizer.Add( self.btnOK, 0, wx.ALL, 5 ) - mainSizer.Add(btnSizer,0 , wx.EXPAND, 5) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + btnSizer.AddSpacer((0, 0), 1, wx.EXPAND, 5) + self.btnOK = wx.Button(self, wx.ID_ANY, u"OK", wx.DefaultPosition, wx.DefaultSize, 0) + btnSizer.Add(self.btnOK, 0, wx.ALL, 5) + mainSizer.Add(btnSizer, 0, wx.EXPAND, 5) self.SetSizer(mainSizer) self.Centre(wx.BOTH) @@ -61,12 +61,12 @@ class PreferenceDialog(wx.Dialog): else: imgID = -1 prefView.populatePanel(page) - self.listbook.AddPage(page, prefView.title, imageId = imgID) + self.listbook.AddPage(page, prefView.title, imageId=imgID) # Set the height based on a condition. Can all the panels fit in the current height? # If not, use the .GetBestVirtualSize() to ensure that all content is available. minHeight = 360 - bestFit = self.GetBestVirtualSize() + bestFit = self.GetBestVirtualSize() if minHeight > bestFit[1]: self.SetSizeWH(450, minHeight) else: diff --git a/gui/preferenceView.py b/gui/preferenceView.py index bf1ba76ed..9dd58c9e9 100644 --- a/gui/preferenceView.py +++ b/gui/preferenceView.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,14 +15,13 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx + class PreferenceView(object): views = [] - def __init__(self): - pass @classmethod def register(cls): @@ -37,5 +36,5 @@ class PreferenceView(object): def getImage(self): return wx.NullBitmap -from gui.builtinPreferenceViews import * +from gui.builtinPreferenceViews import * # noqa diff --git a/gui/projectedView.py b/gui/projectedView.py index f805ead1c..f9c666f60 100644 --- a/gui/projectedView.py +++ b/gui/projectedView.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,16 +15,19 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx import gui.display as d import gui.globalEvents as GE -import service import gui.droneView from gui.builtinViewColumns.state import State from gui.contextMenu import ContextMenu -import eos.types +from service.fit import Fit +from service.market import Market +from eos.saveddata.drone import Drone as es_Drone +from eos.saveddata.fighter import Fighter as es_Fighter +from eos.saveddata.module import Module as es_Module class DummyItem: @@ -32,23 +35,26 @@ class DummyItem: self.name = txt self.icon = None + class DummyEntry: def __init__(self, txt): self.item = DummyItem(txt) -class ProjectedViewDrop(wx.PyDropTarget): - def __init__(self, dropFn): - wx.PyDropTarget.__init__(self) - self.dropFn = dropFn - # this is really transferring an EVE itemID - self.dropData = wx.PyTextDataObject() - self.SetDataObject(self.dropData) - def OnData(self, x, y, t): - if self.GetData(): - data = self.dropData.GetText().split(':') - self.dropFn(x, y, data) - return t +class ProjectedViewDrop(wx.PyDropTarget): + def __init__(self, dropFn): + wx.PyDropTarget.__init__(self) + self.dropFn = dropFn + # this is really transferring an EVE itemID + self.dropData = wx.PyTextDataObject() + self.SetDataObject(self.dropData) + + def OnData(self, x, y, t): + if self.GetData(): + data = self.dropData.GetText().split(':') + self.dropFn(x, y, data) + return t + class ProjectedView(d.Display): DEFAULT_COLS = ["State", @@ -58,7 +64,7 @@ class ProjectedView(d.Display): "Ammo"] def __init__(self, parent): - d.Display.__init__(self, parent, style = wx.LC_SINGLE_SEL | wx.BORDER_NONE) + d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL | wx.BORDER_NONE) self.lastFitId = None @@ -70,7 +76,7 @@ class ProjectedView(d.Display): self.droneView = gui.droneView.DroneView - if "__WXGTK__" in wx.PlatformInfo: + if "__WXGTK__" in wx.PlatformInfo: self.Bind(wx.EVT_RIGHT_UP, self.scheduleMenu) else: self.Bind(wx.EVT_RIGHT_DOWN, self.scheduleMenu) @@ -91,56 +97,55 @@ class ProjectedView(d.Display): # if source is coming from projected, we are trying to combine drones. self.mergeDrones(x, y, int(data[1])) elif data[0] == "market": - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() sFit.project(fitID, int(data[1])) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit())) - def kbEvent(self,event): + def kbEvent(self, event): keycode = event.GetKeyCode() if keycode == wx.WXK_DELETE or keycode == wx.WXK_NUMPAD_DELETE: fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() row = self.GetFirstSelected() if row != -1: sFit.removeProjected(fitID, self.get(row)) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) def handleDrag(self, type, fitID): - #Those are drags coming from pyfa sources, NOT builtin wx drags + # Those are drags coming from pyfa sources, NOT builtin wx drags if type == "fit": activeFit = self.mainFrame.getActiveFit() if activeFit: - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() draggedFit = sFit.getFit(fitID) sFit.project(activeFit, draggedFit) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFit)) def startDrag(self, event): row = event.GetIndex() - if row != -1 and isinstance(self.get(row), eos.types.Drone): + if row != -1 and isinstance(self.get(row), es_Drone): data = wx.PyTextDataObject() - data.SetText("projected:"+str(self.GetItemData(row))) + data.SetText("projected:" + str(self.GetItemData(row))) dropSource = wx.DropSource(self) dropSource.SetData(data) dropSource.DoDragDrop() def mergeDrones(self, x, y, itemID): - srcRow = self.FindItemData(-1,itemID) + srcRow = self.FindItemData(-1, itemID) dstRow, _ = self.HitTest((x, y)) if srcRow != -1 and dstRow != -1: self._merge(srcRow, dstRow) def _merge(self, src, dst): dstDrone = self.get(dst) - if isinstance(dstDrone, eos.types.Drone): - sFit = service.Fit.getInstance() + if isinstance(dstDrone, es_Drone): + sFit = Fit.getInstance() fitID = self.mainFrame.getActiveFit() if sFit.mergeDrones(fitID, self.get(src), dstDrone, True): wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) - def moduleSort(self, module): return module.item.name @@ -159,12 +164,12 @@ class ProjectedView(d.Display): return fit.name def fitChanged(self, event): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(event.fitID) self.Parent.Parent.DisablePage(self, not fit or fit.isStructure) - #Clear list and get out if current fitId is None + # Clear list and get out if current fitId is None if event.fitID is None and self.lastFitId is not None: self.DeleteAllItems() self.lastFitId = None @@ -231,7 +236,7 @@ class ProjectedView(d.Display): col = self.getColumn(event.Position) if col == self.getColIndex(State): fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() sFit.toggleProjected(fitID, item, "right" if event.Button == 3 else "left") wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) @@ -245,17 +250,18 @@ class ProjectedView(d.Display): menu = None if sel != -1: item = self.get(sel) - if item is None: return - sMkt = service.Market.getInstance() - if isinstance(item, eos.types.Drone): + if item is None: + return + sMkt = Market.getInstance() + if isinstance(item, es_Drone): srcContext = "projectedDrone" itemContext = sMkt.getCategoryByItem(item.item).name context = ((srcContext, itemContext),) - elif isinstance(item, eos.types.Fighter): + elif isinstance(item, es_Fighter): srcContext = "projectedFighter" itemContext = sMkt.getCategoryByItem(item.item).name context = ((srcContext, itemContext),) - elif isinstance(item, eos.types.Module): + elif isinstance(item, es_Module): modSrcContext = "projectedModule" modItemContext = sMkt.getCategoryByItem(item.item).name modFullContext = (modSrcContext, modItemContext) @@ -269,7 +275,7 @@ class ProjectedView(d.Display): else: fitSrcContext = "projectedFit" fitItemContext = item.name - context = ((fitSrcContext,fitItemContext),) + context = ((fitSrcContext, fitItemContext),) context = context + (("projected",),) menu = ContextMenu.getMenu((item,), *context) elif sel == -1: @@ -287,6 +293,6 @@ class ProjectedView(d.Display): col = self.getColumn(event.Position) if col != self.getColIndex(State): fitID = self.mainFrame.getActiveFit() - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() sFit.removeProjected(fitID, self.get(row)) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) diff --git a/gui/propertyEditor.py b/gui/propertyEditor.py index 48c2689cd..1129545a6 100644 --- a/gui/propertyEditor.py +++ b/gui/propertyEditor.py @@ -1,3 +1,6 @@ +import csv +import logging + import wx try: @@ -8,24 +11,22 @@ except: else: raise -import gui.PFSearchBox as SBox -from gui.marketBrowser import SearchBox +import eos.db +from service.market import Market import gui.display as d import gui.globalEvents as GE +import gui.PFSearchBox as SBox +from gui.marketBrowser import SearchBox from gui.bitmapLoader import BitmapLoader -import service -import csv -import eos.db - -import logging logger = logging.getLogger(__name__) -class AttributeEditor( wx.Frame ): - def __init__( self, parent ): +class AttributeEditor(wx.Frame): + def __init__(self, parent): wx.Frame.__init__(self, parent, wx.ID_ANY, title="Attribute Editor", pos=wx.DefaultPosition, - size=wx.Size(650, 600), style=wx.DEFAULT_FRAME_STYLE|wx.FRAME_FLOAT_ON_PARENT|wx.TAB_TRAVERSAL) + size=wx.Size(650, 600), + style=wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT | wx.TAB_TRAVERSAL) i = wx.IconFromBitmap(BitmapLoader.getBitmap("fit_rename_small", "gui")) self.SetIcon(i) @@ -45,7 +46,6 @@ class AttributeEditor( wx.Frame ): self.Bind(wx.EVT_MENU, self.OnExport, fileExport) self.Bind(wx.EVT_MENU, self.OnClear, fileClear) - i = wx.IconFromBitmap(BitmapLoader.getBitmap("fit_rename_small", "gui")) self.SetIcon(i) @@ -55,7 +55,8 @@ class AttributeEditor( wx.Frame ): mainSizer = wx.BoxSizer(wx.HORIZONTAL) leftSizer = wx.BoxSizer(wx.VERTICAL) - leftPanel = wx.Panel(panel, wx.ID_ANY, style=wx.DOUBLE_BORDER if 'wxMSW' in wx.PlatformInfo else wx.SIMPLE_BORDER) + leftPanel = wx.Panel(panel, wx.ID_ANY, + style=wx.DOUBLE_BORDER if 'wxMSW' in wx.PlatformInfo else wx.SIMPLE_BORDER) self.searchBox = SearchBox(leftPanel) self.itemView = ItemView(leftPanel) @@ -67,10 +68,11 @@ class AttributeEditor( wx.Frame ): mainSizer.Add(leftPanel, 1, wx.ALL | wx.EXPAND, 5) rightSizer = wx.BoxSizer(wx.VERTICAL) - self.btnRemoveOverrides = wx.Button( panel, wx.ID_ANY, u"Remove Overides for Item", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.btnRemoveOverrides = wx.Button(panel, wx.ID_ANY, u"Remove Overides for Item", wx.DefaultPosition, + wx.DefaultSize, 0) self.pg = AttributeGrid(panel) - rightSizer.Add(self.pg, 1, wx.ALL|wx.EXPAND, 5) - rightSizer.Add(self.btnRemoveOverrides, 0, wx.ALL | wx.EXPAND, 5 ) + rightSizer.Add(self.pg, 1, wx.ALL | wx.EXPAND, 5) + rightSizer.Add(self.btnRemoveOverrides, 0, wx.ALL | wx.EXPAND, 5) self.btnRemoveOverrides.Bind(wx.EVT_BUTTON, self.pg.removeOverrides) self.btnRemoveOverrides.Enable(False) @@ -94,8 +96,8 @@ class AttributeEditor( wx.Frame ): def OnImport(self, event): dlg = wx.FileDialog(self, "Import pyfa override file", - wildcard = "pyfa override file (*.csv)|*.csv", - style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) + wildcard="pyfa override file (*.csv)|*.csv", + style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) if (dlg.ShowModal() == wx.ID_OK): path = dlg.GetPath() with open(path, 'rb') as csvfile: @@ -108,13 +110,13 @@ class AttributeEditor( wx.Frame ): self.itemView.updateItems(True) def OnExport(self, event): - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() items = sMkt.getItemsWithOverrides() defaultFile = "pyfa_overrides.csv" dlg = wx.FileDialog(self, "Save Overrides As...", - wildcard = "pyfa overrides (*.csv)|*.csv", - style = wx.FD_SAVE, + wildcard="pyfa overrides (*.csv)|*.csv", + style=wx.FD_SAVE, defaultFile=defaultFile) if dlg.ShowModal() == wx.ID_OK: @@ -126,12 +128,15 @@ class AttributeEditor( wx.Frame ): writer.writerow([item.ID, override.attrID, override.value]) def OnClear(self, event): - dlg = wx.MessageDialog(self, - "Are you sure you want to delete all overrides?", - "Confirm Delete", wx.YES | wx.NO | wx.ICON_EXCLAMATION) + dlg = wx.MessageDialog( + self, + "Are you sure you want to delete all overrides?", + "Confirm Delete", + wx.YES | wx.NO | wx.ICON_EXCLAMATION + ) if dlg.ShowModal() == wx.ID_YES: - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() items = sMkt.getItemsWithOverrides() # We can't just delete overrides, as loaded items will still have # them assigned. Deleting them from the database won't propagate @@ -143,6 +148,7 @@ class AttributeEditor( wx.Frame ): self.itemView.updateItems(True) self.pg.Clear() + # This is literally a stripped down version of the market. class ItemView(d.Display): DEFAULT_COLS = ["Base Icon", @@ -152,7 +158,7 @@ class ItemView(d.Display): def __init__(self, parent): d.Display.__init__(self, parent) - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() self.things = sMkt.getItemsWithOverrides() self.items = self.things @@ -173,14 +179,14 @@ class ItemView(d.Display): self.update(self.items) def updateItems(self, updateDisplay=False): - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() self.things = sMkt.getItemsWithOverrides() self.items = self.things if updateDisplay: self.update(self.things) def scheduleSearch(self, event=None): - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() search = self.searchBox.GetLineText(0) # Make sure we do not count wildcard as search symbol @@ -198,9 +204,9 @@ class ItemView(d.Display): class AttributeGrid(wxpg.PropertyGrid): - def __init__(self, parent): - wxpg.PropertyGrid.__init__(self, parent, style=wxpg.PG_HIDE_MARGIN|wxpg.PG_HIDE_CATEGORIES|wxpg.PG_BOLD_MODIFIED|wxpg.PG_TOOLTIPS) + wxpg.PropertyGrid.__init__(self, parent, + style=wxpg.PG_HIDE_MARGIN | wxpg.PG_HIDE_CATEGORIES | wxpg.PG_BOLD_MODIFIED | wxpg.PG_TOOLTIPS) self.SetExtraStyle(wxpg.PG_EX_HELP_AS_TOOLTIPS) self.item = None @@ -209,9 +215,9 @@ class AttributeGrid(wxpg.PropertyGrid): self.btn = parent.Parent.btnRemoveOverrides - self.Bind( wxpg.EVT_PG_CHANGED, self.OnPropGridChange ) - self.Bind( wxpg.EVT_PG_SELECTED, self.OnPropGridSelect ) - self.Bind( wxpg.EVT_PG_RIGHT_CLICK, self.OnPropGridRightClick ) + self.Bind(wxpg.EVT_PG_CHANGED, self.OnPropGridChange) + self.Bind(wxpg.EVT_PG_SELECTED, self.OnPropGridSelect) + self.Bind(wxpg.EVT_PG_RIGHT_CLICK, self.OnPropGridRightClick) self.itemView.Bind(wx.EVT_LIST_ITEM_SELECTED, self.itemActivated) self.itemView.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.itemActivated) @@ -232,14 +238,14 @@ class AttributeGrid(wxpg.PropertyGrid): prop = wxpg.FloatProperty(key, value=default) prop.SetClientData(item.attributes[key]) # set this so that we may access it later - prop.SetHelpString("%s\n%s"%(item.attributes[key].displayName or key, "Default Value: %0.3f"%default)) + prop.SetHelpString("%s\n%s" % (item.attributes[key].displayName or key, "Default Value: %0.3f" % default)) self.Append(prop) def removeOverrides(self, event): if self.item is None: return - for _, x in self.item.overrides.items(): + for x in self.item.overrides.values(): self.item.deleteOverride(x.attr) self.itemView.updateItems(True) self.ClearModifiedStatus() diff --git a/gui/pyfatogglepanel.py b/gui/pyfatogglepanel.py index 765a07727..db37216ba 100644 --- a/gui/pyfatogglepanel.py +++ b/gui/pyfatogglepanel.py @@ -1,65 +1,55 @@ -# -*- coding: utf-8 -*- - ########################################################################### -## pyfatogllepanel.py -## -## Author: Darriele - HomeWorld -## -## Project home: https://github.com/pyfa-org/Pyfa - pyfa project -## Some portions of code are based on -## AGW:pycollapsiblepane generic implementation of wx.CollapsiblePane -## AGW:pycollapsiblepane credits ( from the original source file used ): -## Andrea Gavana, @ 09 Aug 2007 -## Latest Revision: 12 Apr 2010, 12.00 GMT -## -## Module description: -## TogglePanel class is a wx.collipsablepane like implementation that uses -## some optimization from awg::pycollipsablepane to provide certain -## features tailored for PYFA needs. -## -## This module is part of PYFA (PYthon Fitting Assitant) and it shares the same -## licence ( read PYFA licence notice: gpl.txt ) -## -## Notes: leave the commented code as it is, those line will be removed someday +# pyfatogllepanel.py +# +# Author: Darriele - HomeWorld +# +# Project home: https://github.com/pyfa-org/Pyfa - pyfa project +# Some portions of code are based on +# AGW:pycollapsiblepane generic implementation of wx.CollapsiblePane +# AGW:pycollapsiblepane credits ( from the original source file used ): +# Andrea Gavana, @ 09 Aug 2007 +# Latest Revision: 12 Apr 2010, 12.00 GMT +# +# Module description: +# TogglePanel class is a wx.collipsablepane like implementation that uses +# some optimization from awg::pycollipsablepane to provide certain +# features tailored for PYFA needs. +# +# This module is part of PYFA (PYthon Fitting Assitant) and it shares the same +# licence ( read PYFA licence notice: gpl.txt ) +# +# Notes: leave the commented code as it is, those line will be removed someday ########################################################################### import wx from gui.bitmapLoader import BitmapLoader -########################################################################### -## Class TogglePanel -########################################################################### -class TogglePanel ( wx.Panel ): - - def __init__( self, parent , forceLayout = -1): - wx.Panel.__init__ ( self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = wx.Size( -1,-1 ), style = wx.TAB_TRAVERSAL ) +class TogglePanel(wx.Panel): + def __init__(self, parent, forceLayout=-1): + wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(-1, -1), + style=wx.TAB_TRAVERSAL) self._toggle = 1 self.parent = parent self.forceLayout = forceLayout self.bkColour = self.GetBackgroundColour() - # Create the main sizer of this panel - - self.mainSizer = wx.BoxSizer( wx.VERTICAL ) - self.SetSizer( self.mainSizer ) - parentSize = parent.GetMinSize() - - # Create the header panel + # Create the main sizer of this panel + self.mainSizer = wx.BoxSizer(wx.VERTICAL) + self.SetSizer(self.mainSizer) + # parentSize = parent.GetMinSize() + # Create the header panel self.headerPanel = wx.Panel(self) + self.mainSizer.Add(self.headerPanel, 0, wx.EXPAND | wx.TOP | wx.BOTTOM | wx.RIGHT, 1) - self.mainSizer.Add(self.headerPanel,0,wx.EXPAND | wx.TOP|wx.BOTTOM|wx.RIGHT, 1) + # Load expanded/collapsed bitmaps from the icons folder + self.bmpExpanded = BitmapLoader.getBitmap("down-arrow2", "gui") + self.bmpCollapsed = BitmapLoader.getBitmap("up-arrow2", "gui") - # Load expanded/collapsed bitmaps from the icons folder - - self.bmpExpanded = BitmapLoader.getBitmap("down-arrow2","gui") - self.bmpCollapsed = BitmapLoader.getBitmap("up-arrow2","gui") - - # Make the bitmaps have the same color as window text - - sysTextColour = wx.SystemSettings.GetColour( wx.SYS_COLOUR_WINDOWTEXT ) + # Make the bitmaps have the same color as window text + sysTextColour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT) img = self.bmpExpanded.ConvertToImage() img.Replace(0, 0, 0, sysTextColour[0], sysTextColour[1], sysTextColour[2]) @@ -69,55 +59,53 @@ class TogglePanel ( wx.Panel ): img.Replace(0, 0, 0, sysTextColour[0], sysTextColour[1], sysTextColour[2]) self.bmpCollapsed = wx.BitmapFromImage(img) - self.headerBmp = wx.StaticBitmap(self.headerPanel ) - self.headerBmp.SetBitmap( self.bmpExpanded) + self.headerBmp = wx.StaticBitmap(self.headerPanel) + self.headerBmp.SetBitmap(self.bmpExpanded) - # Create the header sizer and add static bitmap and static text controls to it + # Create the header sizer and add static bitmap and static text controls to it - headerSizer = wx.BoxSizer( wx.HORIZONTAL ) - self.headerPanel.SetSizer( headerSizer) + headerSizer = wx.BoxSizer(wx.HORIZONTAL) + self.headerPanel.SetSizer(headerSizer) - hbmpSizer = wx.BoxSizer( wx.HORIZONTAL ) - hlblSizer = wx.BoxSizer( wx.HORIZONTAL ) - self.hcntSizer = wx.BoxSizer( wx.HORIZONTAL) + hbmpSizer = wx.BoxSizer(wx.HORIZONTAL) + hlblSizer = wx.BoxSizer(wx.HORIZONTAL) + self.hcntSizer = wx.BoxSizer(wx.HORIZONTAL) - hbmpSizer.Add( self.headerBmp, 0,0, 5 ) + hbmpSizer.Add(self.headerBmp, 0, 0, 5) - self.headerLabel = wx.StaticText( self.headerPanel, wx.ID_ANY, u"PYFA", wx.DefaultPosition, wx.DefaultSize, 0 ) - hlblSizer.Add( self.headerLabel, 0, wx.EXPAND , 5 ) + self.headerLabel = wx.StaticText(self.headerPanel, wx.ID_ANY, u"PYFA", wx.DefaultPosition, wx.DefaultSize, 0) + hlblSizer.Add(self.headerLabel, 0, wx.EXPAND, 5) - headerSizer.Add( hbmpSizer, 0, wx.RIGHT, 5 ) - headerSizer.Add( hlblSizer, 0, wx.RIGHT, 5 ) - headerSizer.Add( self.hcntSizer, 0, wx.RIGHT, 5) + headerSizer.Add(hbmpSizer, 0, wx.RIGHT, 5) + headerSizer.Add(hlblSizer, 0, wx.RIGHT, 5) + headerSizer.Add(self.hcntSizer, 0, wx.RIGHT, 5) - # Set the static text font weight to BOLD + # Set the static text font weight to BOLD - headerFont=parent.GetFont() + headerFont = parent.GetFont() headerFont.SetWeight(wx.BOLD) self.headerLabel.SetFont(headerFont) - # Create the content panel and its main sizer + # Create the content panel and its main sizer - self.contentSizer = wx.BoxSizer( wx.VERTICAL ) + self.contentSizer = wx.BoxSizer(wx.VERTICAL) self.contentPanel = wx.Panel(self) self.contentPanel.SetSizer(self.contentSizer) - self.mainSizer.Add( self.contentPanel, 0, wx.EXPAND | wx.RIGHT | wx.LEFT , 5) - + self.mainSizer.Add(self.contentPanel, 0, wx.EXPAND | wx.RIGHT | wx.LEFT, 5) self.Layout() - # Connect Events + # Connect Events + self.headerLabel.Bind(wx.EVT_LEFT_UP, self.toggleContent) + self.headerBmp.Bind(wx.EVT_LEFT_UP, self.toggleContent) + self.headerPanel.Bind(wx.EVT_LEFT_UP, self.toggleContent) - self.headerLabel.Bind( wx.EVT_LEFT_UP, self.toggleContent ) - self.headerBmp.Bind( wx.EVT_LEFT_UP, self.toggleContent ) - self.headerPanel.Bind( wx.EVT_LEFT_UP, self.toggleContent ) - - def __del__( self ): + def __del__(self): pass def AddToggleItem(self, hitem): - hitem.Bind( wx.EVT_LEFT_UP, self.toggleContent ) + hitem.Bind(wx.EVT_LEFT_UP, self.toggleContent) def GetHeaderContentSizer(self): return self.hcntSizer @@ -126,7 +114,7 @@ class TogglePanel ( wx.Panel ): return self.headerPanel def InsertItemInHeader(self, item): - self.hcntSizer.Add(item,0,0,0) + self.hcntSizer.Add(item, 0, 0, 0) self.Layout() def AddSizer(self, sizer): diff --git a/gui/pygauge.py b/gui/pygauge.py index b63f4fea8..602304e13 100644 --- a/gui/pygauge.py +++ b/gui/pygauge.py @@ -13,14 +13,14 @@ It uses the easeOutQuad equation from caurina.transitions.Tweener to do the anim import wx import copy -import math from gui.utils import colorUtils import gui.utils.drawUtils as drawUtils import gui.utils.animEffects as animEffects import gui.utils.fonts as fonts -from service import fit +from service.fit import Fit + class PyGauge(wx.PyWindow): """ @@ -29,7 +29,7 @@ class PyGauge(wx.PyWindow): """ def __init__(self, parent, id=wx.ID_ANY, range=100, pos=wx.DefaultPosition, - size=(-1,30), style=0): + size=(-1, 30), style=0): """ Default class constructor. @@ -46,8 +46,8 @@ class PyGauge(wx.PyWindow): self._size = size self._border_colour = wx.BLACK - self._barColour = self._barColourSorted = [wx.Colour(212,228,255)] - self._barGradient = self._barGradientSorted = None + self._barColour = self._barColourSorted = [wx.Colour(212, 228, 255)] + self._barGradient = self._barGradientSorted = None self._border_padding = 0 self._range = range @@ -67,10 +67,10 @@ class PyGauge(wx.PyWindow): self._animDirection = 0 self.animEffect = animEffects.OUT_QUAD - self.transitionsColors = [( wx.Colour(191, 191, 191, 255) , wx.Colour(96, 191, 0, 255) ), - ( wx.Colour(191, 167, 96, 255) , wx.Colour(255, 191, 0, 255) ), - ( wx.Colour(255, 191, 0, 255) , wx.Colour(255, 128, 0, 255) ), - ( wx.Colour(255, 128, 0, 255) , wx.Colour(255, 0, 0, 255) )] + self.transitionsColors = [(wx.Colour(191, 191, 191, 255), wx.Colour(96, 191, 0, 255)), + (wx.Colour(191, 167, 96, 255), wx.Colour(255, 191, 0, 255)), + (wx.Colour(255, 191, 0, 255), wx.Colour(255, 128, 0, 255)), + (wx.Colour(255, 128, 0, 255), wx.Colour(255, 0, 0, 255))] self.gradientEffect = -35 self._percentage = 0 @@ -79,8 +79,8 @@ class PyGauge(wx.PyWindow): self.font = wx.Font(fonts.NORMAL, wx.SWISS, wx.NORMAL, wx.NORMAL, False) - self.SetBarGradient((wx.Colour(119,119,119),wx.Colour(153,153,153))) - self.SetBackgroundColour(wx.Colour(51,51,51)) + self.SetBarGradient((wx.Colour(119, 119, 119), wx.Colour(153, 153, 153))) + self.SetBackgroundColour(wx.Colour(51, 51, 51)) self._tooltip = wx.ToolTip("") self.SetToolTip(self._tooltip) self._tooltip.SetTip("0.00/100.00") @@ -107,7 +107,6 @@ class PyGauge(wx.PyWindow): return wx.Size(self._size[0], self._size[1]) - def GetBorderColour(self): return self._border_colour @@ -121,7 +120,7 @@ class PyGauge(wx.PyWindow): return self._barColour[0] def SetBarColour(self, colour): - if type(colour) != type([]): + if not isinstance(colour, list): self._barColour = [colour] else: self._barColour = list(colour) @@ -130,31 +129,30 @@ class PyGauge(wx.PyWindow): GetBarColor = GetBarColour def SetFractionDigits(self, digits): - self._fractionDigits=digits + self._fractionDigits = digits def GetBarGradient(self): """ Returns a tuple containing the gradient start and end colours. """ - if self._barGradient == None: + if self._barGradient is None: return None return self._barGradient[0] - def SetBarGradient(self, gradient = None): + def SetBarGradient(self, gradient=None): """ Sets the bar gradient. This overrides the BarColour. :param `gradient`: a tuple containing the gradient start and end colours. """ - if gradient == None: + if gradient is None: self._barGradient = None else: - if type(gradient) != type([]): + if not isinstance(gradient, list): self._barGradient = [gradient] else: self._barGradient = list(gradient) - def GetBorderPadding(self): """ Gets the border padding. """ @@ -169,14 +167,13 @@ class PyGauge(wx.PyWindow): self._border_padding = padding - def GetRange(self): """ Returns the maximum value of the gauge. """ return self._range def Animate(self): - sFit = fit.Fit.getInstance() + sFit = Fit.getInstance() if sFit.serviceFittingOptions["enableGaugeAnimation"]: if not self._timer: self._timer = wx.Timer(self, self._timerId) @@ -186,7 +183,7 @@ class PyGauge(wx.PyWindow): self._animValue = self._percentage self.Refresh() - def SetRange(self, range, reinit = False): + def SetRange(self, range, reinit=False): """ Sets the range of the gauge. The gauge length is its value as a proportion of the range. @@ -197,16 +194,16 @@ class PyGauge(wx.PyWindow): if self._range == range: return - range = float(range) + range_ = float(range) - if range <= 0: + if range_ <= 0: self._range = 0.01 else: - self._range = range + self._range = range_ if reinit is False: self._oldPercentage = self._percentage - self._percentage = (self._value/self._range) * 100 + self._percentage = (self._value / self._range) * 100 else: self._oldPercentage = self._percentage self._percentage = 0 @@ -214,9 +211,7 @@ class PyGauge(wx.PyWindow): self.Animate() - - self._tooltip.SetTip("%.2f/%.2f" % (self._value, self._range if self._range >0.01 else 0)) - + self._tooltip.SetTip("%.2f/%.2f" % (self._value, self._range if self._range > 0.01 else 0)) def GetValue(self): """ Returns the current position of the gauge. """ @@ -233,22 +228,22 @@ class PyGauge(wx.PyWindow): self._value = value if value < 0: self._value = 0 - self._percentage = (self._value/self._range) * 100 + self._percentage = (self._value / self._range) * 100 self.Animate() self._tooltip.SetTip("%.2f/%.2f" % (self._value, self._range)) - def SetValueRange(self, value, range, reinit = False): + def SetValueRange(self, value, range, reinit=False): if self._value == value and self._range == range: return - range = float(range) + range_ = float(range) - if range <= 0: + if range_ <= 0: self._range = 0.01 else: - self._range = range + self._range = range_ value = float(value) @@ -258,15 +253,14 @@ class PyGauge(wx.PyWindow): if reinit is False: self._oldPercentage = self._percentage - self._percentage = (self._value/self._range) * 100 + self._percentage = (self._value / self._range) * 100 else: self._oldPercentage = self._percentage self._percentage = 0 - self.Animate() - self._tooltip.SetTip("%.2f/%.2f" % (self._value, self._range if self._range >0.01 else 0)) + self._tooltip.SetTip("%.2f/%.2f" % (self._value, self._range if self._range > 0.01 else 0)) def OnEraseBackground(self, event): """ @@ -308,7 +302,7 @@ class PyGauge(wx.PyWindow): dc.SetPen(wx.Pen(self.GetBorderColour())) dc.DrawRectangleRect(rect) pad = 1 + self.GetBorderPadding() - rect.Deflate(pad,pad) + rect.Deflate(pad, pad) if self.GetBarGradient(): @@ -326,48 +320,48 @@ class PyGauge(wx.PyWindow): # time on them if not needed. See GH issue #282 pv = value - xv=1 + xv = 1 transition = 0 if pv <= 100: - xv = pv/100 + xv = pv / 100 transition = 0 - elif pv <=101: - xv = pv -100 + elif pv <= 101: + xv = pv - 100 transition = 1 elif pv <= 103: - xv = (pv -101)/2 + xv = (pv - 101) / 2 transition = 2 elif pv <= 105: - xv = (pv -103)/2 + xv = (pv - 103) / 2 transition = 3 else: pv = 106 - xv = pv -100 + xv = pv - 100 transition = -1 if transition != -1: - colorS,colorE = self.transitionsColors[transition] + colorS, colorE = self.transitionsColors[transition] color = colorUtils.CalculateTransitionColor(colorS, colorE, xv) else: - color = wx.Colour(191,48,48) + color = wx.Colour(191, 48, 48) if self.gradientEffect > 0: - gcolor = colorUtils.BrightenColor(color, float(self.gradientEffect) / 100) - gMid = colorUtils.BrightenColor(color, float(self.gradientEffect/2) / 100) + gcolor = colorUtils.BrightenColor(color, float(self.gradientEffect) / 100) + gMid = colorUtils.BrightenColor(color, float(self.gradientEffect / 2) / 100) else: - gcolor = colorUtils.DarkenColor(color, float(-self.gradientEffect) / 100) - gMid = colorUtils.DarkenColor(color, float(-self.gradientEffect/2) / 100) + gcolor = colorUtils.DarkenColor(color, float(-self.gradientEffect) / 100) + gMid = colorUtils.DarkenColor(color, float(-self.gradientEffect / 2) / 100) gBmp = drawUtils.DrawGradientBar(r.width, r.height, gMid, color, gcolor) dc.DrawBitmap(gBmp, r.left, r.top) else: - colour=self.GetBarColour() + colour = self.GetBarColour() dc.SetBrush(wx.Brush(colour)) dc.SetPen(wx.Pen(colour)) if value > 100: @@ -381,14 +375,14 @@ class PyGauge(wx.PyWindow): dc.SetFont(self.font) r = copy.copy(rect) - r.left +=1 - r.top +=1 + r.left += 1 + r.top += 1 if self._range == 0.01 and self._value > 0: - formatStr = u'\u221e' - dc.SetTextForeground(wx.Colour(80,80,80)) + formatStr = u'\u221e' + dc.SetTextForeground(wx.Colour(80, 80, 80)) dc.DrawLabel(formatStr, r, wx.ALIGN_CENTER) - dc.SetTextForeground(wx.Colour(255,255,255)) + dc.SetTextForeground(wx.Colour(255, 255, 255)) dc.DrawLabel(formatStr, rect, wx.ALIGN_CENTER) else: if self.GetBarGradient() and self._showRemaining: @@ -404,20 +398,20 @@ class PyGauge(wx.PyWindow): else: formatStr = "{0:." + str(self._fractionDigits) + "f}%" - dc.SetTextForeground(wx.Colour(80,80,80)) + dc.SetTextForeground(wx.Colour(80, 80, 80)) dc.DrawLabel(formatStr.format(value), r, wx.ALIGN_CENTER) - dc.SetTextForeground(wx.Colour(255,255,255)) + dc.SetTextForeground(wx.Colour(255, 255, 255)) dc.DrawLabel(formatStr.format(value), rect, wx.ALIGN_CENTER) - def OnTimer(self,event): + def OnTimer(self, event): """ Handles the ``wx.EVT_TIMER`` event for L{PyfaGauge}. :param `event`: a timer event """ - oldValue=self._oldPercentage - value=self._percentage + oldValue = self._oldPercentage + value = self._percentage start = 0 direction = 1 if oldValue < value else -1 @@ -436,13 +430,13 @@ class PyGauge(wx.PyWindow): stop_timer = True if direction == 1: - if (oldValue+step) < value: - self._animValue = oldValue+step + if (oldValue + step) < value: + self._animValue = oldValue + step else: stop_timer = True else: - if (oldValue-step) > value: - self._animValue = oldValue-step + if (oldValue - step) > value: + self._animValue = oldValue - step else: stop_timer = True @@ -451,4 +445,3 @@ class PyGauge(wx.PyWindow): self._timer.Stop() self.Refresh() - diff --git a/gui/resistsEditor.py b/gui/resistsEditor.py index 37d04b032..84f7bf98b 100644 --- a/gui/resistsEditor.py +++ b/gui/resistsEditor.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2014 Ryan Holmes # # This file is part of pyfa. @@ -15,13 +15,12 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx +from service.targetResists import TargetResists from gui.bitmapLoader import BitmapLoader -import service from gui.utils.clipboard import toClipboard, fromClipboard -from service.targetResists import ImportError from gui.builtinViews.entityEditor import EntityEditor, BaseValidator @@ -44,7 +43,7 @@ class TargetResistsTextValidor(BaseValidator): raise ValueError("Target Resist Profile name already in use, please choose another.") return True - except ValueError, e: + except ValueError as e: wx.MessageBox(u"{}".format(e), "Error") textCtrl.SetFocus() return False @@ -56,34 +55,34 @@ class TargetResistsEntityEditor(EntityEditor): self.SetEditorValidator(TargetResistsTextValidor) def getEntitiesFromContext(self): - sTR = service.TargetResists.getInstance() + sTR = TargetResists.getInstance() choices = sorted(sTR.getTargetResistsList(), key=lambda p: p.name) return choices def DoNew(self, name): - sTR = service.TargetResists.getInstance() + sTR = TargetResists.getInstance() return sTR.newPattern(name) def DoRename(self, entity, name): - sTR = service.TargetResists.getInstance() + sTR = TargetResists.getInstance() sTR.renamePattern(entity, name) def DoCopy(self, entity, name): - sTR = service.TargetResists.getInstance() + sTR = TargetResists.getInstance() copy = sTR.copyPattern(entity) sTR.renamePattern(copy, name) return copy def DoDelete(self, entity): - sTR = service.TargetResists.getInstance() + sTR = TargetResists.getInstance() sTR.deletePattern(entity) -class ResistsEditorDlg(wx.Dialog): +class ResistsEditorDlg(wx.Dialog): DAMAGE_TYPES = ("em", "thermal", "kinetic", "explosive") def __init__(self, parent): - wx.Dialog.__init__(self, parent, id = wx.ID_ANY, title = u"Target Resists Editor", size = wx.Size( 350,240 )) + wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title=u"Target Resists Editor", size=wx.Size(350, 240)) self.block = False self.SetSizeHintsSz(wx.DefaultSize, wx.DefaultSize) @@ -104,24 +103,24 @@ class ResistsEditorDlg(wx.Dialog): resistEditSizer.SetFlexibleDirection(wx.BOTH) resistEditSizer.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) - width = -1 - defSize = wx.Size(50,-1) + defSize = wx.Size(50, -1) - for i, type in enumerate(self.DAMAGE_TYPES): - if i%2: + for i, type_ in enumerate(self.DAMAGE_TYPES): + if i % 2: style = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT border = 25 else: style = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT border = 5 - bmp = wx.StaticBitmap(self, wx.ID_ANY, BitmapLoader.getBitmap("%s_big"%type, "gui")) + bmp = wx.StaticBitmap(self, wx.ID_ANY, BitmapLoader.getBitmap("%s_big" % type_, "gui")) resistEditSizer.Add(bmp, 0, style, border) # set text edit - setattr(self, "%sEdit"%type, wx.TextCtrl(self, wx.ID_ANY, "", wx.DefaultPosition, defSize)) - editObj = getattr(self, "%sEdit"%type) + setattr(self, "%sEdit" % type_, wx.TextCtrl(self, wx.ID_ANY, "", wx.DefaultPosition, defSize)) + editObj = getattr(self, "%sEdit" % type_) resistEditSizer.Add(editObj, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5) - resistEditSizer.Add(wx.StaticText( self, wx.ID_ANY, u"%", wx.DefaultPosition, wx.DefaultSize, 0 ), 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5) + resistEditSizer.Add(wx.StaticText(self, wx.ID_ANY, u"%", wx.DefaultPosition, wx.DefaultSize, 0), 0, + wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5) editObj.Bind(wx.EVT_TEXT, self.ValuesUpdated) # Color we use to reset invalid value color @@ -138,7 +137,7 @@ class ResistsEditorDlg(wx.Dialog): self.stNotice.Wrap(-1) perSizer.Add(self.stNotice, 0, wx.BOTTOM | wx.TOP | wx.LEFT, 5) - footerSizer.Add(perSizer, 1, wx.ALIGN_CENTER_VERTICAL, 5) + footerSizer.Add(perSizer, 1, wx.ALIGN_CENTER_VERTICAL, 5) self.totSizer = wx.BoxSizer(wx.VERTICAL) @@ -147,8 +146,8 @@ class ResistsEditorDlg(wx.Dialog): mainSizer.Add(contentSizer, 1, wx.EXPAND, 0) if "wxGTK" in wx.PlatformInfo: - self.closeBtn = wx.Button( self, wx.ID_ANY, u"Close", wx.DefaultPosition, wx.DefaultSize, 0 ) - mainSizer.Add( self.closeBtn, 0, wx.ALL|wx.ALIGN_RIGHT, 5 ) + self.closeBtn = wx.Button(self, wx.ID_ANY, u"Close", wx.DefaultPosition, wx.DefaultSize, 0) + mainSizer.Add(self.closeBtn, 0, wx.ALL | wx.ALIGN_RIGHT, 5) self.closeBtn.Bind(wx.EVT_BUTTON, self.closeEvent) self.SetSizer(mainSizer) @@ -160,13 +159,13 @@ class ResistsEditorDlg(wx.Dialog): bitmap = wx.ArtProvider.GetBitmap(art, wx.ART_BUTTON) btn = wx.BitmapButton(self, wx.ID_ANY, bitmap) - btn.SetMinSize( btn.GetSize() ) - btn.SetMaxSize( btn.GetSize() ) + btn.SetMinSize(btn.GetSize()) + btn.SetMaxSize(btn.GetSize()) btn.Layout() setattr(self, name, btn) btn.Enable(True) - btn.SetToolTipString("%s patterns %s clipboard" % (name, direction) ) + btn.SetToolTipString("%s patterns %s clipboard" % (name, direction)) footerSizer.Add(btn, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_RIGHT) btn.Bind(wx.EVT_BUTTON, getattr(self, "{}Patterns".format(name.lower()))) @@ -201,8 +200,8 @@ class ResistsEditorDlg(wx.Dialog): try: p = self.entityEditor.getActiveEntity() - for type in self.DAMAGE_TYPES: - editObj = getattr(self, "%sEdit"%type) + for type_ in self.DAMAGE_TYPES: + editObj = getattr(self, "%sEdit" % type_) if editObj.GetValue() == "": # if we are blank, overwrite with 0 @@ -215,7 +214,7 @@ class ResistsEditorDlg(wx.Dialog): assert 0 <= value <= 100 # if everything checks out, set resist attribute - setattr(p, "%sAmount"%type, value/100) + setattr(p, "%sAmount" % type_, value / 100) editObj.SetForegroundColour(self.colorReset) self.stNotice.SetLabel("") @@ -224,7 +223,7 @@ class ResistsEditorDlg(wx.Dialog): if event is not None: event.Skip() - service.TargetResists.getInstance().saveChanges(p) + TargetResists.getInstance().saveChanges(p) except ValueError: editObj.SetForegroundColour(wx.RED) @@ -250,13 +249,13 @@ class ResistsEditorDlg(wx.Dialog): # Set new values for field in self.DAMAGE_TYPES: edit = getattr(self, "%sEdit" % field) - amount = getattr(p, "%sAmount" % field)*100 + amount = getattr(p, "%sAmount" % field) * 100 edit.ChangeValue(str(amount)) self.block = False self.ValuesUpdated() - def __del__( self ): + def __del__(self): pass def importPatterns(self, event): @@ -264,13 +263,13 @@ class ResistsEditorDlg(wx.Dialog): text = fromClipboard() if text: - sTR = service.TargetResists.getInstance() + sTR = TargetResists.getInstance() try: sTR.importPatterns(text) self.stNotice.SetLabel("Patterns successfully imported from clipboard") - except service.targetResists.ImportError, e: + except ImportError as e: self.stNotice.SetLabel(str(e)) - except Exception, e: + except Exception: self.stNotice.SetLabel("Could not import from clipboard: unknown errors") finally: self.entityEditor.refreshEntityList() @@ -279,6 +278,6 @@ class ResistsEditorDlg(wx.Dialog): def exportPatterns(self, event): "Event fired when export to clipboard button is clicked" - sTR = service.TargetResists.getInstance() - toClipboard( sTR.exportPatterns() ) + sTR = TargetResists.getInstance() + toClipboard(sTR.exportPatterns()) self.stNotice.SetLabel("Patterns exported to clipboard") diff --git a/gui/setEditor.py b/gui/setEditor.py index 84090f6ff..0118fbe03 100644 --- a/gui/setEditor.py +++ b/gui/setEditor.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2016 Ryan Holmes # # This file is part of pyfa. @@ -15,19 +15,19 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= -import wx -from gui.bitmapLoader import BitmapLoader -from gui.builtinViews.implantEditor import BaseImplantEditorView -import service -from gui.utils.clipboard import toClipboard, fromClipboard -from service.implantSet import ImportError import logging +import wx + +from service.implantSet import ImplantSets +from gui.builtinViews.implantEditor import BaseImplantEditorView +from gui.utils.clipboard import toClipboard, fromClipboard from gui.builtinViews.entityEditor import EntityEditor, BaseValidator logger = logging.getLogger(__name__) + class ImplantTextValidor(BaseValidator): def __init__(self): BaseValidator.__init__(self) @@ -47,7 +47,7 @@ class ImplantTextValidor(BaseValidator): raise ValueError("Imlplant Set name already in use, please choose another.") return True - except ValueError, e: + except ValueError as e: wx.MessageBox(u"{}".format(e), "Error") textCtrl.SetFocus() return False @@ -59,25 +59,25 @@ class ImplantSetEntityEditor(EntityEditor): self.SetEditorValidator(ImplantTextValidor) def getEntitiesFromContext(self): - sIS = service.ImplantSets.getInstance() + sIS = ImplantSets.getInstance() return sorted(sIS.getImplantSetList(), key=lambda c: c.name) def DoNew(self, name): - sIS = service.ImplantSets.getInstance() + sIS = ImplantSets.getInstance() return sIS.newSet(name) def DoRename(self, entity, name): - sIS = service.ImplantSets.getInstance() + sIS = ImplantSets.getInstance() sIS.renameSet(entity, name) def DoCopy(self, entity, name): - sIS = service.ImplantSets.getInstance() + sIS = ImplantSets.getInstance() copy = sIS.copySet(entity) sIS.renameSet(copy, name) return copy def DoDelete(self, entity): - sIS = service.ImplantSets.getInstance() + sIS = ImplantSets.getInstance() sIS.deleteSet(entity) @@ -91,28 +91,28 @@ class ImplantSetEditor(BaseImplantEditorView): self.Parent.entityEditor.Bind(wx.EVT_CHOICE, self.contextChanged) def getImplantsFromContext(self): - sIS = service.ImplantSets.getInstance() - set = self.Parent.entityEditor.getActiveEntity() - if set: - return sIS.getImplants(set.ID) + sIS = ImplantSets.getInstance() + set_ = self.Parent.entityEditor.getActiveEntity() + if set_: + return sIS.getImplants(set_.ID) return [] def addImplantToContext(self, item): - sIS = service.ImplantSets.getInstance() - set = self.Parent.entityEditor.getActiveEntity() + sIS = ImplantSets.getInstance() + set_ = self.Parent.entityEditor.getActiveEntity() - sIS.addImplant(set.ID, item.ID) + sIS.addImplant(set_.ID, item.ID) def removeImplantFromContext(self, implant): - sIS = service.ImplantSets.getInstance() - set = self.Parent.entityEditor.getActiveEntity() + sIS = ImplantSets.getInstance() + set_ = self.Parent.entityEditor.getActiveEntity() + + sIS.removeImplant(set_.ID, implant) - sIS.removeImplant(set.ID, implant) class ImplantSetEditorDlg(wx.Dialog): - def __init__(self, parent): - wx.Dialog.__init__(self, parent, id = wx.ID_ANY, title = u"Implant Set Editor", size = wx.Size(640, 600)) + wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title=u"Implant Set Editor", size=wx.Size(640, 600)) self.block = False self.SetSizeHintsSz(wx.DefaultSize, wx.DefaultSize) @@ -138,25 +138,25 @@ class ImplantSetEditorDlg(wx.Dialog): footerSizer.Add(self.stNotice, 1, wx.BOTTOM | wx.TOP | wx.LEFT, 5) if "wxGTK" in wx.PlatformInfo: - self.closeBtn = wx.Button( self, wx.ID_ANY, u"Close", wx.DefaultPosition, wx.DefaultSize, 0 ) - mainSizer.Add( self.closeBtn, 0, wx.ALL|wx.ALIGN_RIGHT, 5 ) + self.closeBtn = wx.Button(self, wx.ID_ANY, u"Close", wx.DefaultPosition, wx.DefaultSize, 0) + mainSizer.Add(self.closeBtn, 0, wx.ALL | wx.ALIGN_RIGHT, 5) self.closeBtn.Bind(wx.EVT_BUTTON, self.closeEvent) importExport = (("Import", wx.ART_FILE_OPEN, "from"), ("Export", wx.ART_FILE_SAVE_AS, "to")) for name, art, direction in importExport: - bitmap = wx.ArtProvider.GetBitmap(art, wx.ART_BUTTON) - btn = wx.BitmapButton(self, wx.ID_ANY, bitmap) + bitmap = wx.ArtProvider.GetBitmap(art, wx.ART_BUTTON) + btn = wx.BitmapButton(self, wx.ID_ANY, bitmap) - btn.SetMinSize( btn.GetSize() ) - btn.SetMaxSize( btn.GetSize() ) + btn.SetMinSize(btn.GetSize()) + btn.SetMaxSize(btn.GetSize()) - btn.Layout() - setattr(self, name, btn) - btn.Enable(True) - btn.SetToolTipString("%s implant sets %s clipboard" % (name, direction) ) - footerSizer.Add(btn, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_RIGHT) + btn.Layout() + setattr(self, name, btn) + btn.Enable(True) + btn.SetToolTipString("%s implant sets %s clipboard" % (name, direction)) + footerSizer.Add(btn, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_RIGHT) mainSizer.Add(footerSizer, 0, wx.ALL | wx.EXPAND, 5) @@ -183,7 +183,7 @@ class ImplantSetEditorDlg(wx.Dialog): def closeEvent(self, event): self.Destroy() - def __del__( self ): + def __del__(self): pass def importPatterns(self, event): @@ -191,14 +191,14 @@ class ImplantSetEditorDlg(wx.Dialog): text = fromClipboard() if text: - sIS = service.ImplantSets.getInstance() + sIS = ImplantSets.getInstance() try: sIS.importSets(text) self.stNotice.SetLabel("Patterns successfully imported from clipboard") self.showInput(False) - except ImportError, e: + except ImportError as e: self.stNotice.SetLabel(str(e)) - except Exception, e: + except Exception as e: logging.exception("Unhandled Exception") self.stNotice.SetLabel("Could not import from clipboard: unknown errors") finally: @@ -209,6 +209,6 @@ class ImplantSetEditorDlg(wx.Dialog): def exportPatterns(self, event): "Event fired when export to clipboard button is clicked" - sIS = service.ImplantSets.getInstance() + sIS = ImplantSets.getInstance() toClipboard(sIS.exportSets()) self.stNotice.SetLabel("Sets exported to clipboard") diff --git a/gui/sfBrowserItem.py b/gui/sfBrowserItem.py index 81294cba3..047c04bc6 100644 --- a/gui/sfBrowserItem.py +++ b/gui/sfBrowserItem.py @@ -1,5 +1,4 @@ import wx -import gui.utils.colorUtils as colorUtils import gui.utils.drawUtils as drawUtils SB_ITEM_NORMAL = 0 @@ -7,14 +6,15 @@ SB_ITEM_SELECTED = 1 SB_ITEM_HIGHLIGHTED = 2 SB_ITEM_DISABLED = 4 -BTN_NORMAL = 1 -BTN_PRESSED = 2 -BTN_HOVER = 4 +BTN_NORMAL = 1 +BTN_PRESSED = 2 +BTN_HOVER = 4 BTN_DISABLED = 8 class PFBaseButton(object): - def __init__(self, normalBitmap = wx.NullBitmap,label = "", callback = None, hoverBitmap = None, disabledBitmap = None, show = True): + def __init__(self, normalBitmap=wx.NullBitmap, label="", callback=None, hoverBitmap=None, disabledBitmap=None, + show=True): self.normalBmp = normalBitmap self.dropShadowOpacity = 0.2 @@ -48,7 +48,7 @@ class PFBaseButton(object): if self.callback: self.callback() - def SetState(self, state = BTN_NORMAL): + def SetState(self, state=BTN_NORMAL): self.state = state def GetState(self): @@ -57,7 +57,7 @@ class PFBaseButton(object): def GetSize(self): w = self.normalBmp.GetWidth() h = self.normalBmp.GetHeight() - return (w,h) + return (w, h) def GetBitmap(self): return self.normalBmp @@ -70,22 +70,23 @@ class PFBaseButton(object): return self.label def GetHoverBitmap(self): - if self.hoverBmp == None: + if self.hoverBmp is None: return self.normalBmp return self.hoverBmp def GetDisabledBitmap(self): - if self.disabledBmp == None: + if self.disabledBmp is None: return self.normalBmp return self.disabledBmp def GetDropShadowBitmap(self): return self.dropShadowBmp + class PFToolbar(object): def __init__(self, parent): self.Parent = parent - self.buttons =[] + self.buttons = [] self.toolbarX = 0 self.toolbarY = 0 self.padding = 2 @@ -94,7 +95,7 @@ class PFToolbar(object): def SetPosition(self, pos): self.toolbarX, self.toolbarY = pos - def AddButton(self, btnBitmap, label = "", clickCallback = None, hoverBitmap = None, disabledBitmap = None, show = True): + def AddButton(self, btnBitmap, label="", clickCallback=None, hoverBitmap=None, disabledBitmap=None, show=True): btn = PFBaseButton(btnBitmap, label, clickCallback, hoverBitmap, disabledBitmap, show) self.buttons.append(btn) return btn @@ -115,7 +116,7 @@ class PFToolbar(object): continue state = button.GetState() - if self.HitTest( (bx, self.toolbarY), event.GetPosition(), button.GetSize()): + if self.HitTest((bx, self.toolbarY), event.GetPosition(), button.GetSize()): changeCursor = True if not state & BTN_HOVER: button.SetState(state | BTN_HOVER) @@ -135,7 +136,7 @@ class PFToolbar(object): return doRefresh def MouseClick(self, event): - mx,my = event.GetPosition() + mx, my = event.GetPosition() bx = self.toolbarX for button in self.buttons: if not button.IsVisible(): @@ -143,8 +144,8 @@ class PFToolbar(object): state = button.GetState() if state & BTN_PRESSED: - button.SetState(state ^ BTN_PRESSED ) - if self.HitTest( (bx, self.toolbarY), event.GetPosition(), button.GetSize()): + button.SetState(state ^ BTN_PRESSED) + if self.HitTest((bx, self.toolbarY), event.GetPosition(), button.GetSize()): return button else: return False @@ -158,7 +159,7 @@ class PFToolbar(object): state = button.GetState() - if self.HitTest( (bx, self.toolbarY), event.GetPosition(), button.GetSize()): + if self.HitTest((bx, self.toolbarY), event.GetPosition(), button.GetSize()): if event.LeftDown() or event.LeftDClick(): button.SetState(state | BTN_PRESSED) @@ -230,14 +231,14 @@ class PFToolbar(object): bmpWidth = bmp.GetWidth() - pdc.DrawBitmap(dropShadowBmp,bx + self.padding / 2, self.toolbarY + self.padding / 2) + pdc.DrawBitmap(dropShadowBmp, bx + self.padding / 2, self.toolbarY + self.padding / 2) pdc.DrawBitmap(bmp, tbx, by) bx += bmpWidth + self.padding class SFBrowserItem(wx.Window): - def __init__(self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = (0,16), style = 0): + def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=(0, 16), style=0): wx.Window.__init__(self, parent, id, pos, size, style) self.highlighted = False @@ -248,7 +249,6 @@ class SFBrowserItem(wx.Window): self.toolbar = PFToolbar(self) - self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) @@ -256,8 +256,7 @@ class SFBrowserItem(wx.Window): if "wxMSW" in wx.PlatformInfo: self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDown) - - self.Bind(wx.EVT_LEFT_DOWN,self.OnLeftDown) + self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow) self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow) self.Bind(wx.EVT_MOTION, self.OnMotion) @@ -271,7 +270,7 @@ class SFBrowserItem(wx.Window): self.RenderBackground() - mdc.DrawBitmap(self.bkBitmap, 0,0) + mdc.DrawBitmap(self.bkBitmap, 0, 0) self.DrawItem(mdc) self.toolbar.Render(mdc) @@ -291,7 +290,7 @@ class SFBrowserItem(wx.Window): def MouseMove(self, event): pass - def SetDraggable(self, mode = True): + def SetDraggable(self, mode=True): self.canBeDragged = mode def OnLeftUp(self, event): @@ -302,14 +301,13 @@ class SFBrowserItem(wx.Window): mposx, mposy = wx.GetMousePosition() rect = self.GetRect() rect.top = rect.left = 0 - cx,cy = self.ScreenToClient((mposx,mposy)) - if not rect.Contains((cx,cy)): + cx, cy = self.ScreenToClient((mposx, mposy)) + if not rect.Contains((cx, cy)): self.SetHighlighted(False) self.toolbar.ClearState() self.Refresh() return - btn = self.toolbar.MouseClick(event) if btn is not None: @@ -323,7 +321,6 @@ class SFBrowserItem(wx.Window): self.MouseLeftUp(event) - def OnLeftDown(self, event): if not self.HasCapture(): self.CaptureMouse() @@ -360,10 +357,10 @@ class SFBrowserItem(wx.Window): def GetType(self): return -1 - def SetSelected(self, select = True): + def SetSelected(self, select=True): self.selected = select - def SetHighlighted(self, highlight = True): + def SetHighlighted(self, highlight=True): self.highlighted = highlight def GetState(self): @@ -373,7 +370,7 @@ class SFBrowserItem(wx.Window): elif self.selected: if self.highlighted: - state = SB_ITEM_SELECTED | SB_ITEM_HIGHLIGHTED + state = SB_ITEM_SELECTED | SB_ITEM_HIGHLIGHTED else: state = SB_ITEM_SELECTED else: @@ -396,7 +393,7 @@ class SFBrowserItem(wx.Window): mFactor = 0.45 eFactor = 0.30 - elif state == SB_ITEM_SELECTED | SB_ITEM_HIGHLIGHTED: + elif state == SB_ITEM_SELECTED | SB_ITEM_HIGHLIGHTED: eFactor = 0.3 elif state == SB_ITEM_SELECTED: eFactor = 0.15 @@ -405,7 +402,7 @@ class SFBrowserItem(wx.Window): if self.bkBitmap: if self.bkBitmap.eFactor == eFactor and self.bkBitmap.sFactor == sFactor and self.bkBitmap.mFactor == mFactor \ - and rect.width == self.bkBitmap.GetWidth() and rect.height == self.bkBitmap.GetHeight() : + and rect.width == self.bkBitmap.GetWidth() and rect.height == self.bkBitmap.GetHeight(): return else: del self.bkBitmap diff --git a/gui/shipBrowser.py b/gui/shipBrowser.py index 96bfb7ad5..a9e12a110 100644 --- a/gui/shipBrowser.py +++ b/gui/shipBrowser.py @@ -1,26 +1,24 @@ -# -*- coding: utf-8 -*- -import wx -import re -import copy -from gui.bitmapLoader import BitmapLoader -import gui.mainFrame -import gui.globalEvents as GE -import time -from gui.PFListPane import PFListPane +# coding: utf-8 +import re +import time + +import wx from wx.lib.buttons import GenBitmapButton +from service.fit import Fit +from service.market import Market +import gui.mainFrame +import gui.utils.fonts as fonts +import gui.globalEvents as GE +import gui.sfBrowserItem as SFItem import gui.utils.colorUtils as colorUtils import gui.utils.drawUtils as drawUtils import gui.utils.animUtils as animUtils import gui.utils.animEffects as animEffects - -import gui.sfBrowserItem as SFItem +from gui.PFListPane import PFListPane from gui.contextMenu import ContextMenu -import gui.utils.fonts as fonts - -import service -import gui.utils.fonts as fonts +from gui.bitmapLoader import BitmapLoader FitRenamed, EVT_FIT_RENAMED = wx.lib.newevent.NewEvent() FitSelected, EVT_FIT_SELECTED = wx.lib.newevent.NewEvent() @@ -36,20 +34,20 @@ ImportSelected, EVT_SB_IMPORT_SEL = wx.lib.newevent.NewEvent() class PFWidgetsContainer(PFListPane): - def __init__(self,parent): - PFListPane.__init__(self,parent) + def __init__(self, parent): + PFListPane.__init__(self, parent) - self.anim = animUtils.LoadAnimation(self,label = "", size=(100,12)) + self.anim = animUtils.LoadAnimation(self, label="", size=(100, 12)) self.anim.Stop() self.anim.Show(False) - def ShowLoading(self, mode = True): + def ShowLoading(self, mode=True): if mode: - aweight,aheight = self.anim.GetSize() - cweight,cheight = self.GetSize() - ax = (cweight - aweight)/2 - ay = (cheight - aheight)/2 - self.anim.SetPosition((ax,ay)) + aweight, aheight = self.anim.GetSize() + cweight, cheight = self.GetSize() + ax = (cweight - aweight) / 2 + ay = (cheight - aheight) / 2 + self.anim.SetPosition((ax, ay)) self.anim.Show() self.anim.Play() else: @@ -68,8 +66,9 @@ class PFWidgetsContainer(PFListPane): class RaceSelector(wx.Window): - def __init__ (self, parent, id = wx.ID_ANY, label = "", pos = wx.DefaultPosition, size = wx.DefaultSize, style = 0, layout = wx.VERTICAL, animate = False): - wx.Window.__init__(self, parent, id, pos = pos, size = size, style = style) + def __init__(self, parent, id=wx.ID_ANY, label="", pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, + layout=wx.VERTICAL, animate=False): + wx.Window.__init__(self, parent, id, pos=pos, size=size, style=style) self.animTimerID = wx.NewId() self.animTimer = wx.Timer(self, self.animTimerID) @@ -92,7 +91,6 @@ class RaceSelector(wx.Window): self.SetSize(wx.Size(-1, self.minHeight)) self.SetMinSize(wx.Size(-1, self.minHeight)) - self.checkTimerID = wx.NewId() self.checkTimer = wx.Timer(self, self.checkTimerID) self.checkPeriod = 250 @@ -103,20 +101,20 @@ class RaceSelector(wx.Window): self.hoveredItem = None if layout == wx.VERTICAL: - self.buttonsBarPos = (4,0) + self.buttonsBarPos = (4, 0) else: - self.buttonsBarPos = (0,4) + self.buttonsBarPos = (0, 4) self.buttonsPadding = 4 if layout == wx.VERTICAL: - self.bmpArrow = BitmapLoader.getBitmap("down-arrow2","gui") + self.bmpArrow = BitmapLoader.getBitmap("down-arrow2", "gui") else: - self.bmpArrow = BitmapLoader.getBitmap("up-arrow2","gui") + self.bmpArrow = BitmapLoader.getBitmap("up-arrow2", "gui") - # Make the bitmaps have the same color as window text + # Make the bitmaps have the same color as window text - sysTextColour = wx.SystemSettings.GetColour( wx.SYS_COLOUR_WINDOWTEXT ) + sysTextColour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT) img = self.bmpArrow.ConvertToImage() if layout == wx.VERTICAL: @@ -141,9 +139,9 @@ class RaceSelector(wx.Window): self.Layout() def OnMouseMove(self, event): - mx,my = event.GetPosition() + mx, my = event.GetPosition() - location = self.HitTest(mx,my) + location = self.HitTest(mx, my) if location != self.hoveredItem: self.hoveredItem = location self.Refresh() @@ -152,7 +150,7 @@ class RaceSelector(wx.Window): else: self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW)) - def OnSizeUpdate(self,event): + def OnSizeUpdate(self, event): self.CalcButtonsBarPos() self.Refresh() @@ -176,9 +174,9 @@ class RaceSelector(wx.Window): def OnLeftUp(self, event): - mx,my = event.GetPosition() + mx, my = event.GetPosition() - toggle = self.HitTest(mx,my) + toggle = self.HitTest(mx, my) if toggle is not None: self.Refresh() @@ -189,11 +187,11 @@ class RaceSelector(wx.Window): if stage == 2: categoryID = self.shipBrowser.GetStageData(stage) - wx.PostEvent(self.shipBrowser,Stage2Selected(categoryID=categoryID, back = True)) + wx.PostEvent(self.shipBrowser, Stage2Selected(categoryID=categoryID, back=True)) event.Skip() - def HitTest(self, mx,my): - x,y = self.buttonsBarPos + def HitTest(self, mx, my): + x, y = self.buttonsBarPos padding = self.buttonsPadding for bmp in self.raceBmps: @@ -222,16 +220,15 @@ class RaceSelector(wx.Window): rect = self.GetRect() windowColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW) - bkColor = colorUtils.GetSuitableColor(windowColor, 0.1) + # bkColor = colorUtils.GetSuitableColor(windowColor, 0.1) sepColor = colorUtils.GetSuitableColor(windowColor, 0.2) mdc = wx.BufferedPaintDC(self) bkBitmap = drawUtils.RenderGradientBar(windowColor, rect.width, rect.height, 0.1, 0.1, 0.2, 2) - mdc.DrawBitmap(bkBitmap,0,0,True) + mdc.DrawBitmap(bkBitmap, 0, 0, True) - - x ,y = self.buttonsBarPos + x, y = self.buttonsBarPos if self.direction == 1: for raceBmp in self.raceBmps: @@ -250,27 +247,25 @@ class RaceSelector(wx.Window): if self.layout == wx.VERTICAL: mdc.DrawBitmap(dropShadow, rect.width - self.buttonsPadding - bmp.GetWidth() + 1, y + 1) mdc.DrawBitmap(bmp, rect.width - self.buttonsPadding - bmp.GetWidth(), y) - y+=raceBmp.GetHeight() + self.buttonsPadding - mdc.SetPen(wx.Pen(sepColor,1)) - mdc.DrawLine(rect.width - 1, 0, rect.width -1, rect.height) + y += raceBmp.GetHeight() + self.buttonsPadding + mdc.SetPen(wx.Pen(sepColor, 1)) + mdc.DrawLine(rect.width - 1, 0, rect.width - 1, rect.height) else: mdc.DrawBitmap(dropShadow, x + 1, self.buttonsPadding + 1) mdc.DrawBitmap(bmp, x, self.buttonsPadding) - x+=raceBmp.GetWidth() + self.buttonsPadding - mdc.SetPen(wx.Pen(sepColor,1)) + x += raceBmp.GetWidth() + self.buttonsPadding + mdc.SetPen(wx.Pen(sepColor, 1)) mdc.DrawLine(0, 0, rect.width, 0) if self.direction < 1: if self.layout == wx.VERTICAL: mdc.DrawBitmap(self.bmpArrow, -2, (rect.height - self.bmpArrow.GetHeight()) / 2) else: - mdc.SetPen(wx.Pen(sepColor,1)) + mdc.SetPen(wx.Pen(sepColor, 1)) mdc.DrawLine(0, 0, rect.width, 0) mdc.DrawBitmap(self.bmpArrow, (rect.width - self.bmpArrow.GetWidth()) / 2, -2) - - - def OnTimer(self,event): + def OnTimer(self, event): if event.GetId() == self.animTimerID: start = 0 if self.layout == wx.VERTICAL: @@ -298,7 +293,7 @@ class RaceSelector(wx.Window): self.animTimer.Start(self.animPeriod) def AdjustSize(self, delta): - self.SetMinSize(wx.Size(delta,-1) if self.layout == wx.VERTICAL else wx.Size(-1, delta)) + self.SetMinSize(wx.Size(delta, -1) if self.layout == wx.VERTICAL else wx.Size(-1, delta)) self.Parent.Layout() self.Refresh() @@ -327,19 +322,20 @@ class RaceSelector(wx.Window): event.Skip() + class NavigationPanel(SFItem.SFBrowserItem): - def __init__(self,parent, size = (-1, 24)): - SFItem.SFBrowserItem.__init__(self,parent,size = size) + def __init__(self, parent, size=(-1, 24)): + SFItem.SFBrowserItem.__init__(self, parent, size=size) - self.rewBmpH = BitmapLoader.getBitmap("frewind_small","gui") - self.forwBmp = BitmapLoader.getBitmap("fforward_small","gui") - self.searchBmpH = BitmapLoader.getBitmap("fsearch_small","gui") - self.newBmpH = BitmapLoader.getBitmap("fit_add_small","gui") - self.resetBmpH = BitmapLoader.getBitmap("freset_small","gui") - self.switchBmpH = BitmapLoader.getBitmap("fit_switch_view_mode_small","gui") + self.rewBmpH = BitmapLoader.getBitmap("frewind_small", "gui") + self.forwBmp = BitmapLoader.getBitmap("fforward_small", "gui") + self.searchBmpH = BitmapLoader.getBitmap("fsearch_small", "gui") + self.newBmpH = BitmapLoader.getBitmap("fit_add_small", "gui") + self.resetBmpH = BitmapLoader.getBitmap("freset_small", "gui") + self.switchBmpH = BitmapLoader.getBitmap("fit_switch_view_mode_small", "gui") - switchImg = BitmapLoader.getImage("fit_switch_view_mode_small","gui") - switchImg = switchImg.AdjustChannels(1,1,1,0.4) + switchImg = BitmapLoader.getImage("fit_switch_view_mode_small", "gui") + switchImg = switchImg.AdjustChannels(1, 1, 1, 0.4) self.switchBmpD = wx.BitmapFromImage(switchImg) self.resetBmp = self.AdjustChannels(self.resetBmpH) @@ -348,11 +344,16 @@ class NavigationPanel(SFItem.SFBrowserItem): self.switchBmp = self.AdjustChannels(self.switchBmpH) self.newBmp = self.AdjustChannels(self.newBmpH) - self.toolbar.AddButton(self.resetBmp, "Ship groups", clickCallback = self.OnHistoryReset, hoverBitmap = self.resetBmpH) - self.toolbar.AddButton(self.rewBmp, "Back", clickCallback = self.OnHistoryBack, hoverBitmap = self.rewBmpH) - self.btnNew = self.toolbar.AddButton(self.newBmp, "New fitting", clickCallback = self.OnNewFitting, hoverBitmap = self.newBmpH, show = False) - self.btnSwitch = self.toolbar.AddButton(self.switchBmpD, "Hide empty ship groups", clickCallback = self.ToggleEmptyGroupsView, hoverBitmap = self.switchBmpH, show = False) - self.toolbar.AddButton(self.searchBmp, "Search fittings", clickCallback = self.ToggleSearchBox, hoverBitmap = self.searchBmpH) + self.toolbar.AddButton(self.resetBmp, "Ship groups", clickCallback=self.OnHistoryReset, + hoverBitmap=self.resetBmpH) + self.toolbar.AddButton(self.rewBmp, "Back", clickCallback=self.OnHistoryBack, hoverBitmap=self.rewBmpH) + self.btnNew = self.toolbar.AddButton(self.newBmp, "New fitting", clickCallback=self.OnNewFitting, + hoverBitmap=self.newBmpH, show=False) + self.btnSwitch = self.toolbar.AddButton(self.switchBmpD, "Hide empty ship groups", + clickCallback=self.ToggleEmptyGroupsView, hoverBitmap=self.switchBmpH, + show=False) + self.toolbar.AddButton(self.searchBmp, "Search fittings", clickCallback=self.ToggleSearchBox, + hoverBitmap=self.searchBmpH) self.padding = 4 self.lastSearch = "" @@ -360,8 +361,10 @@ class NavigationPanel(SFItem.SFBrowserItem): self.inSearch = False self.fontSmall = wx.Font(fonts.SMALL, wx.SWISS, wx.NORMAL, wx.NORMAL) - w,h = size - self.BrowserSearchBox = wx.TextCtrl(self, wx.ID_ANY, "", wx.DefaultPosition, (-1, h - 2 if 'wxGTK' in wx.PlatformInfo else -1 ), wx.TE_PROCESS_ENTER | (wx.BORDER_NONE if 'wxGTK' in wx.PlatformInfo else 0)) + w, h = size + self.BrowserSearchBox = wx.TextCtrl(self, wx.ID_ANY, "", wx.DefaultPosition, + (-1, h - 2 if 'wxGTK' in wx.PlatformInfo else -1), + wx.TE_PROCESS_ENTER | (wx.BORDER_NONE if 'wxGTK' in wx.PlatformInfo else 0)) self.BrowserSearchBox.Show(False) self.BrowserSearchBox.Bind(wx.EVT_TEXT_ENTER, self.OnBrowserSearchBoxEnter) @@ -381,8 +384,7 @@ class NavigationPanel(SFItem.SFBrowserItem): realsearch = search.replace("*", "") if len(realsearch) >= 3: self.lastSearch = search - wx.PostEvent(self.shipBrowser,SearchSelected(text=search, back = False)) - + wx.PostEvent(self.shipBrowser, SearchSelected(text=search, back=False)) def ToggleSearchBox(self): if self.BrowserSearchBox.IsShown(): @@ -420,10 +422,10 @@ class NavigationPanel(SFItem.SFBrowserItem): stage = self.shipBrowser.GetActiveStage() if stage == 1: - wx.PostEvent(self.shipBrowser,Stage1Selected()) + wx.PostEvent(self.shipBrowser, Stage1Selected()) elif stage == 2: categoryID = self.shipBrowser.GetStageData(stage) - wx.PostEvent(self.shipBrowser,Stage2Selected(categoryID=categoryID, back = True)) + wx.PostEvent(self.shipBrowser, Stage2Selected(categoryID=categoryID, back=True)) def ShowNewFitButton(self, show): self.btnNew.Show(show) @@ -438,20 +440,20 @@ class NavigationPanel(SFItem.SFBrowserItem): if stage == 3: shipID = self.Parent.GetStageData(stage) shipName = self.Parent.GetStage3ShipName() - sFit = service.Fit.getInstance() - fitID = sFit.newFit(shipID, "%s fit" %shipName) + sFit = Fit.getInstance() + fitID = sFit.newFit(shipID, "%s fit" % shipName) self.shipBrowser.fitIDMustEditName = fitID - wx.PostEvent(self.Parent,Stage3Selected(shipID=shipID)) + wx.PostEvent(self.Parent, Stage3Selected(shipID=shipID)) wx.PostEvent(self.mainFrame, FitSelected(fitID=fitID)) def OnHistoryReset(self): if self.shipBrowser.browseHist: self.shipBrowser.browseHist = [] - self.gotoStage(1,0) + self.gotoStage(1, 0) def OnHistoryBack(self): if len(self.shipBrowser.browseHist) > 0: - stage,data = self.shipBrowser.browseHist.pop() + stage, data = self.shipBrowser.browseHist.pop() self.gotoStage(stage, data) def AdjustChannels(self, bitmap): @@ -467,10 +469,10 @@ class NavigationPanel(SFItem.SFBrowserItem): mdc.SetFont(self.fontSmall) - wlabel,hlabel = mdc.GetTextExtent(self.toolbar.hoverLabel) + wlabel, hlabel = mdc.GetTextExtent(self.toolbar.hoverLabel) self.thoverx = self.toolbar.GetWidth() + self.padding - self.thovery = (rect.height - hlabel)/2 + self.thovery = (rect.height - hlabel) / 2 self.thoverw = wlabel self.browserBoxX = self.thoverx @@ -495,8 +497,8 @@ class NavigationPanel(SFItem.SFBrowserItem): self.toolbar.SetPosition((self.toolbarx, self.toolbary)) mdc.SetFont(self.fontSmall) mdc.DrawText(self.toolbar.hoverLabel, self.thoverx, self.thovery) - mdc.SetPen(wx.Pen(sepColor,1)) - mdc.DrawLine(0,rect.height - 1, rect.width, rect.height - 1) + mdc.SetPen(wx.Pen(sepColor, 1)) + mdc.DrawLine(0, rect.height - 1, rect.width, rect.height - 1) def RenderBackground(self): rect = self.GetRect() @@ -505,7 +507,7 @@ class NavigationPanel(SFItem.SFBrowserItem): sFactor = 0.1 - shipGroupsFilter = getattr(self.shipBrowser,"filterShipsWithNoFits", None) + shipGroupsFilter = getattr(self.shipBrowser, "filterShipsWithNoFits", None) if shipGroupsFilter: sFactor = 0.15 mFactor = 0.25 @@ -516,7 +518,7 @@ class NavigationPanel(SFItem.SFBrowserItem): if self.bkBitmap: if self.bkBitmap.eFactor == eFactor and self.bkBitmap.sFactor == sFactor and self.bkBitmap.mFactor == mFactor \ - and rect.width == self.bkBitmap.GetWidth() and rect.height == self.bkBitmap.GetHeight() : + and rect.width == self.bkBitmap.GetWidth() and rect.height == self.bkBitmap.GetHeight(): return else: del self.bkBitmap @@ -527,7 +529,6 @@ class NavigationPanel(SFItem.SFBrowserItem): self.bkBitmap.eFactor = eFactor self.bkBitmap.mFactor = mFactor - def gotoStage(self, stage, data=None): if stage == 1: wx.PostEvent(self.Parent, Stage1Selected()) @@ -546,16 +547,16 @@ class NavigationPanel(SFItem.SFBrowserItem): class ShipBrowser(wx.Panel): def __init__(self, parent): - wx.Panel.__init__ (self, parent,style = 0) + wx.Panel.__init__(self, parent, style=0) self._lastWidth = 0 self._activeStage = 1 self._lastStage = 0 self.browseHist = [] - self.lastStage = (0,0) + self.lastStage = (0, 0) self.mainFrame = gui.mainFrame.MainFrame.getInstance() - self.categoryList=[] + self.categoryList = [] self.categoryFitCache = {} self._stage1Data = -1 @@ -581,16 +582,16 @@ class ShipBrowser(wx.Panel): layout = wx.HORIZONTAL self.navpanel = NavigationPanel(self) - mainSizer.Add(self.navpanel, 0 , wx.EXPAND) - self.raceselect = RaceSelector(self, layout = layout, animate = False) + mainSizer.Add(self.navpanel, 0, wx.EXPAND) + self.raceselect = RaceSelector(self, layout=layout, animate=False) container = wx.BoxSizer(wx.VERTICAL if layout == wx.HORIZONTAL else wx.HORIZONTAL) if layout == wx.HORIZONTAL: - container.Add(self.lpane,1,wx.EXPAND) - container.Add(self.raceselect,0,wx.EXPAND) + container.Add(self.lpane, 1, wx.EXPAND) + container.Add(self.raceselect, 0, wx.EXPAND) else: - container.Add(self.raceselect,0,wx.EXPAND) - container.Add(self.lpane,1,wx.EXPAND) + container.Add(self.raceselect, 0, wx.EXPAND) + container.Add(self.lpane, 1, wx.EXPAND) mainSizer.Add(container, 1, wx.EXPAND) self.SetSizer(mainSizer) @@ -667,13 +668,13 @@ class ShipBrowser(wx.Panel): self._lastStage = self._activeStage self._activeStage = 1 self.lastdata = 0 - self.browseHist = [(1,0)] + self.browseHist = [(1, 0)] self.navpanel.ShowNewFitButton(False) self.navpanel.ShowSwitchEmptyGroupsButton(False) - sMkt = service.Market.getInstance() - sFit = service.Fit.getInstance() + sMkt = Market.getInstance() + sFit = Fit.getInstance() self.lpane.ShowLoading(False) self.lpane.Freeze() @@ -720,7 +721,7 @@ class ShipBrowser(wx.Panel): categoryID = self._stage2Data ships = list(data[1]) - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() ships.sort(key=self.raceNameKey) racesList = [] @@ -732,7 +733,7 @@ class ShipBrowser(wx.Panel): if ship.race not in racesList: racesList.append(ship.race) - for race,state in self.racesFilter.iteritems(): + for race, state in self.racesFilter.iteritems(): if race in racesList: subRacesFilter[race] = self.racesFilter[race] @@ -745,18 +746,18 @@ class ShipBrowser(wx.Panel): for ship in ships: fits = sFit.countFitsWithShip(ship.ID) t_fits += fits - filter = subRacesFilter[ship.race] if ship.race else True + filter_ = subRacesFilter[ship.race] if ship.race else True if override: - filter = True + filter_ = True shipTrait = ship.traits.traitText if (ship.traits is not None) else "" # empty string if no traits - + if self.filterShipsWithNoFits: - if fits>0: - if filter: + if fits > 0: + if filter_: self.lpane.AddWidget(ShipItem(self.lpane, ship.ID, (ship.name, shipTrait, fits), ship.race)) else: - if filter: + if filter_: self.lpane.AddWidget(ShipItem(self.lpane, ship.ID, (ship.name, shipTrait, fits), ship.race)) self.raceselect.RebuildRaces(racesList) @@ -776,9 +777,8 @@ class ShipBrowser(wx.Panel): self.Layout() def stage2(self, event): - back = event.back - - #if not back: + # back = event.back + # if not back: # self.browseHist.append( (1,0) ) self._lastStage = self._activeStage @@ -790,8 +790,7 @@ class ShipBrowser(wx.Panel): self.lpane.RemoveAllChildren() - - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() sMkt.getShipListDelayed(categoryID, self.stage2Callback) self._stage2Data = categoryID @@ -821,8 +820,8 @@ class ShipBrowser(wx.Panel): self._lastStage = self._activeStage self._activeStage = 3 - sFit = service.Fit.getInstance() - sMkt = service.Market.getInstance() + sFit = Fit.getInstance() + sMkt = Market.getInstance() ship = sMkt.getItem(shipID) categoryID = ship.group.ID @@ -832,9 +831,9 @@ class ShipBrowser(wx.Panel): fitList = sFit.getFitsWithShip(shipID) if len(fitList) == 0: - stage,data = self.browseHist.pop() + stage, data = self.browseHist.pop() self.lpane.Thaw() - self.navpanel.gotoStage(stage,data) + self.navpanel.gotoStage(stage, data) return self.categoryFitCache[categoryID] = True @@ -855,7 +854,7 @@ class ShipBrowser(wx.Panel): shipTrait = ship.traits.traitText if (ship.traits is not None) else "" # empty string if no traits for ID, name, booster, timestamp in fitList: - self.lpane.AddWidget(FitItem(self.lpane, ID, (shipName, shipTrait, name, booster, timestamp),shipID)) + self.lpane.AddWidget(FitItem(self.lpane, ID, (shipName, shipTrait, name, booster, timestamp), shipID)) self.lpane.RefreshList() self.lpane.Thaw() @@ -877,8 +876,8 @@ class ShipBrowser(wx.Panel): self._lastStage = self._activeStage self._activeStage = 4 - sMkt = service.Market.getInstance() - sFit = service.Fit.getInstance() + sMkt = Market.getInstance() + sFit = Fit.getInstance() query = event.text self.lpane.Freeze() @@ -887,20 +886,22 @@ class ShipBrowser(wx.Panel): if query: ships = sMkt.searchShips(query) fitList = sFit.searchFits(query) - - for ship in ships: - shipTrait = ship.traits.traitText if (ship.traits is not None) else "" # empty string if no traits - self.lpane.AddWidget(ShipItem(self.lpane, ship.ID, (ship.name, shipTrait, len(sFit.getFitsWithShip(ship.ID))), ship.race)) - + for ship in ships: + shipTrait = ship.traits.traitText if (ship.traits is not None) else "" # empty string if no traits + + self.lpane.AddWidget( + ShipItem(self.lpane, ship.ID, (ship.name, shipTrait, len(sFit.getFitsWithShip(ship.ID))), + ship.race)) + for ID, name, shipID, shipName, booster, timestamp in fitList: ship = sMkt.getItem(shipID) shipTrait = ship.traits.traitText if (ship.traits is not None) else "" # empty string if no traits self.lpane.AddWidget(FitItem(self.lpane, ID, (shipName, shipTrait, name, booster, timestamp), shipID)) - if len(ships) == 0 and len(fitList) == 0 : - self.lpane.AddWidget(PFStaticText(self.lpane, label = u"No matching results.")) - self.lpane.RefreshList(doFocus = False) + if len(ships) == 0 and len(fitList) == 0: + self.lpane.AddWidget(PFStaticText(self.lpane, label=u"No matching results.")) + self.lpane.RefreshList(doFocus=False) self.lpane.Thaw() self.raceselect.RebuildRaces(self.RACE_ORDER) @@ -932,17 +933,21 @@ class ShipBrowser(wx.Panel): if fits: for fit in fits: - shipTrait = fit.ship.traits.traitText if (fit.ship.traits is not None) else "" # empty string if no traits + shipTrait = fit.ship.traits.traitText if (fit.ship.traits is not None) else "" + # empty string if no traits self.lpane.AddWidget(FitItem( self.lpane, - fit.ID, ( + fit.ID, + ( fit.ship.item.name, shipTrait, fit.name, fit.booster, - fit.timestamp), - fit.ship.item.ID)) + fit.timestamp, + ), + fit.ship.item.ID, + )) self.lpane.RefreshList(doFocus=False) self.lpane.Thaw() @@ -952,20 +957,23 @@ class ShipBrowser(wx.Panel): self.raceselect.Show(False) self.Layout() + class PFStaticText(wx.Panel): def __init__(self, parent, label=wx.EmptyString): - wx.Panel.__init__ (self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size = parent.GetSize()) + wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=parent.GetSize()) self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) mainSizer = wx.BoxSizer(wx.VERTICAL) - text = wx.StaticText( self, wx.ID_ANY, label, wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) - text.Wrap( -1 ) - mainSizer.Add( text, 1, wx.ALL, 10 ) + text = wx.StaticText(self, wx.ID_ANY, label, wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE) + text.Wrap(-1) + mainSizer.Add(text, 1, wx.ALL, 10) self.SetSizer(mainSizer) self.Layout() + def GetType(self): return -1 + class PFGenBitmapButton(GenBitmapButton): def __init__(self, parent, id, bitmap, pos, size, style): GenBitmapButton.__init__(self, parent, id, bitmap, pos, size, style) @@ -977,14 +985,15 @@ class PFGenBitmapButton(GenBitmapButton): def GetBackgroundBrush(self, dc): return self.bgcolor + class CategoryItem(SFItem.SFBrowserItem): - def __init__(self,parent, categoryID, fittingInfo, size = (0,16)): - SFItem.SFBrowserItem.__init__(self,parent,size = size) + def __init__(self, parent, categoryID, fittingInfo, size=(0, 16)): + SFItem.SFBrowserItem.__init__(self, parent, size=size) if categoryID: - self.shipBmp = BitmapLoader.getBitmap("ship_small","gui") + self.shipBmp = BitmapLoader.getBitmap("ship_small", "gui") else: - self.shipBmp = wx.EmptyBitmap(16,16) + self.shipBmp = wx.EmptyBitmap(16, 16) self.dropShadowBitmap = drawUtils.CreateDropShadowBitmap(self.shipBmp, 0.2) @@ -1005,31 +1014,30 @@ class CategoryItem(SFItem.SFBrowserItem): self.Bind(wx.EVT_TIMER, self.OnTimer) - #======================================================================= + # ===================================================================== # Disabled - it will be added as an option to Preferences self.animCount = 0 # self.animTimer.Start(self.animPeriod) - #======================================================================= - + # ===================================================================== def OnTimer(self, event): step = self.OUT_QUAD(self.animStep, 0, 10, self.animDuration) self.animCount = 10 - step self.animStep += self.animPeriod - if self.animStep > self.animDuration or self.animCount < 0 : + if self.animStep > self.animDuration or self.animCount < 0: self.animCount = 0 self.animTimer.Stop() self.Refresh() - def OUT_QUAD (self, t, b, c, d): - t=float(t) - b=float(b) - c=float(c) - d=float(d) + def OUT_QUAD(self, t, b, c, d): + t = float(t) + b = float(b) + c = float(c) + d = float(d) - t/=d + t /= d - return -c *(t)*(t-2) + b + return -c * t * (t - 2) + b def GetType(self): return 1 @@ -1037,12 +1045,12 @@ class CategoryItem(SFItem.SFBrowserItem): def MouseLeftUp(self, event): categoryID = self.categoryID - wx.PostEvent(self.shipBrowser,Stage2Selected(categoryID=categoryID, back=False)) + wx.PostEvent(self.shipBrowser, Stage2Selected(categoryID=categoryID, back=False)) def UpdateElementsPos(self, mdc): rect = self.GetRect() self.shipBmpx = self.padding - self.shipBmpy = (rect.height-self.shipBmp.GetWidth())/2 + self.shipBmpy = (rect.height - self.shipBmp.GetWidth()) / 2 self.shipBmpx -= self.animCount @@ -1050,13 +1058,11 @@ class CategoryItem(SFItem.SFBrowserItem): categoryName, fittings = self.fittingInfo wtext, htext = mdc.GetTextExtent(categoryName) - self.catx = self.shipBmpx + self.shipBmp.GetWidth() + self.padding self.caty = (rect.height - htext) / 2 def DrawItem(self, mdc): - rect = self.GetRect() - + # rect = self.GetRect() self.UpdateElementsPos(mdc) windowColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW) @@ -1064,7 +1070,7 @@ class CategoryItem(SFItem.SFBrowserItem): mdc.SetTextForeground(textColor) mdc.DrawBitmap(self.dropShadowBitmap, self.shipBmpx + 1, self.shipBmpy + 1) - mdc.DrawBitmap(self.shipBmp,self.shipBmpx,self.shipBmpy,0) + mdc.DrawBitmap(self.shipBmp, self.shipBmpx, self.shipBmpy, 0) mdc.SetFont(self.fontBig) @@ -1072,7 +1078,8 @@ class CategoryItem(SFItem.SFBrowserItem): mdc.DrawText(categoryName, self.catx, self.caty) -#=============================================================================== + +# ============================================================================= # Waiting for total #fits impl in eos/service # # mdc.SetFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL, False)) @@ -1091,14 +1098,14 @@ class CategoryItem(SFItem.SFBrowserItem): # else: # xtext, ytext = mdc.GetTextExtent(fformat) # ypos = (rect.height - ytext)/2 -#=============================================================================== +# ============================================================================= class ShipItem(SFItem.SFBrowserItem): - def __init__(self, parent, shipID=None, shipFittingInfo=("Test","TestTrait", 2), itemData=None, + def __init__(self, parent, shipID=None, shipFittingInfo=("Test", "TestTrait", 2), itemData=None, id=wx.ID_ANY, pos=wx.DefaultPosition, size=(0, 40), style=0): - SFItem.SFBrowserItem.__init__(self, parent, size = size) + SFItem.SFBrowserItem.__init__(self, parent, size=size) self.mainFrame = gui.mainFrame.MainFrame.getInstance() @@ -1125,7 +1132,7 @@ class ShipItem(SFItem.SFBrowserItem): self.newBmp = BitmapLoader.getBitmap("fit_add_small", "gui") self.acceptBmp = BitmapLoader.getBitmap("faccept_small", "gui") - self.shipEffBk = BitmapLoader.getBitmap("fshipbk_big","gui") + self.shipEffBk = BitmapLoader.getBitmap("fshipbk_big", "gui") img = wx.ImageFromBitmap(self.shipEffBk) img = img.Mirror(False) @@ -1134,7 +1141,7 @@ class ShipItem(SFItem.SFBrowserItem): self.raceBmp = BitmapLoader.getBitmap("race_%s_small" % self.shipRace, "gui") if not self.raceBmp: - self.raceBmp = BitmapLoader.getBitmap("fit_delete_small","gui") + self.raceBmp = BitmapLoader.getBitmap("fit_delete_small", "gui") self.raceDropShadowBmp = drawUtils.CreateDropShadowBitmap(self.raceBmp, 0.2) @@ -1145,11 +1152,11 @@ class ShipItem(SFItem.SFBrowserItem): self.editWidth = 150 self.padding = 4 - self.tcFitName = wx.TextCtrl(self, wx.ID_ANY, "%s fit" % self.shipName, wx.DefaultPosition, (120,-1), wx.TE_PROCESS_ENTER) + self.tcFitName = wx.TextCtrl(self, wx.ID_ANY, "%s fit" % self.shipName, wx.DefaultPosition, (120, -1), + wx.TE_PROCESS_ENTER) self.tcFitName.Show(False) - - self.newBtn = self.toolbar.AddButton(self.newBmp,"New", self.newBtnCB) + self.newBtn = self.toolbar.AddButton(self.newBmp, "New", self.newBtnCB) self.tcFitName.Bind(wx.EVT_TEXT_ENTER, self.createNewFit) self.tcFitName.Bind(wx.EVT_KILL_FOCUS, self.editLostFocus) @@ -1164,10 +1171,10 @@ class ShipItem(SFItem.SFBrowserItem): self.Bind(wx.EVT_CONTEXT_MENU, self.OnShowPopup) - self.marketInstance = service.Market.getInstance() + self.marketInstance = Market.getInstance() self.baseItem = self.marketInstance.getItem(self.shipID) - #=======================================================================\ + # ===================================================================== # DISABLED - it will be added as an option in PREFERENCES self.animCount = 0 @@ -1177,8 +1184,7 @@ class ShipItem(SFItem.SFBrowserItem): # self.animTimer.Start(self.animPeriod) # else: # self.animCount = 0 - #======================================================================= - + # ===================================================================== def OnShowPopup(self, event): pos = event.GetPosition() @@ -1192,20 +1198,20 @@ class ShipItem(SFItem.SFBrowserItem): step = self.OUT_QUAD(self.animStep, 0, 10, self.animDuration) self.animCount = 10 - step self.animStep += self.animPeriod - if self.animStep > self.animDuration or self.animCount < 0 : + if self.animStep > self.animDuration or self.animCount < 0: self.animCount = 0 self.animTimer.Stop() self.Refresh() - def OUT_QUAD (self, t, b, c, d): - t=float(t) - b=float(b) - c=float(c) - d=float(d) + def OUT_QUAD(self, t, b, c, d): + t = float(t) + b = float(b) + c = float(c) + d = float(d) - t/=d + t /= d - return -c *(t)*(t-2) + b + return -c * t * (t - 2) + b def GetType(self): return 2 @@ -1251,10 +1257,10 @@ class ShipItem(SFItem.SFBrowserItem): def createNewFit(self, event=None): self.tcFitName.Show(False) - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = sFit.newFit(self.shipID, self.tcFitName.GetValue()) - wx.PostEvent(self.shipBrowser,Stage3Selected(shipID=self.shipID, back=False)) + wx.PostEvent(self.shipBrowser, Stage3Selected(shipID=self.shipID, back=False)) wx.PostEvent(self.mainFrame, FitSelected(fitID=fitID)) def UpdateElementsPos(self, mdc): @@ -1265,18 +1271,18 @@ class ShipItem(SFItem.SFBrowserItem): self.toolbarx = self.toolbarx + self.animCount - self.shipEffx = self.padding + (rect.height - self.shipEffBk.GetWidth())/2 - self.shipEffy = (rect.height - self.shipEffBk.GetHeight())/2 + self.shipEffx = self.padding + (rect.height - self.shipEffBk.GetWidth()) / 2 + self.shipEffy = (rect.height - self.shipEffBk.GetHeight()) / 2 self.shipEffx = self.shipEffx - self.animCount self.shipBmpx = self.padding + (rect.height - self.shipBmp.GetWidth()) / 2 self.shipBmpy = (rect.height - self.shipBmp.GetHeight()) / 2 - self.shipBmpx= self.shipBmpx - self.animCount + self.shipBmpx = self.shipBmpx - self.animCount self.raceBmpx = self.shipEffx + self.shipEffBk.GetWidth() + self.padding - self.raceBmpy = (rect.height - self.raceBmp.GetHeight())/2 + self.raceBmpy = (rect.height - self.raceBmp.GetHeight()) / 2 self.textStartx = self.raceBmpx + self.raceBmp.GetWidth() + self.padding @@ -1291,14 +1297,14 @@ class ShipItem(SFItem.SFBrowserItem): mdc.SetFont(self.fontSmall) - wlabel,hlabel = mdc.GetTextExtent(self.toolbar.hoverLabel) + wlabel, hlabel = mdc.GetTextExtent(self.toolbar.hoverLabel) self.thoverx = self.toolbarx - self.padding - wlabel - self.thovery = (rect.height - hlabel)/2 + self.thovery = (rect.height - hlabel) / 2 self.thoverw = wlabel def DrawItem(self, mdc): - rect = self.GetRect() + # rect = self.GetRect() windowColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW) textColor = colorUtils.GetSuitableColor(windowColor, 1) @@ -1319,27 +1325,27 @@ class ShipItem(SFItem.SFBrowserItem): mdc.DrawBitmap(self.shipBmp, self.shipBmpx, self.shipBmpy, 0) mdc.DrawBitmap(self.raceDropShadowBmp, self.raceBmpx + 1, self.raceBmpy + 1) - mdc.DrawBitmap(self.raceBmp,self.raceBmpx, self.raceBmpy) + mdc.DrawBitmap(self.raceBmp, self.raceBmpx, self.raceBmpy) shipName, shipTrait, fittings = self.shipFittingInfo - if fittings <1: + if fittings < 1: fformat = "No fits" + elif fittings == 1: + fformat = "%d fit" else: - if fittings == 1: - fformat = "%d fit" - else: - fformat = "%d fits" + fformat = "%d fits" mdc.SetFont(self.fontNormal) - mdc.DrawText(fformat %fittings if fittings >0 else fformat, self.textStartx, self.fittingsy) + mdc.DrawText(fformat % fittings if fittings > 0 else fformat, self.textStartx, self.fittingsy) mdc.SetFont(self.fontSmall) mdc.DrawText(self.toolbar.hoverLabel, self.thoverx, self.thovery) mdc.SetFont(self.fontBig) - psname = drawUtils.GetPartialText(mdc, shipName, self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw) + psname = drawUtils.GetPartialText(mdc, shipName, + self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw) mdc.DrawText(psname, self.textStartx, self.shipNamey) @@ -1350,51 +1356,50 @@ class ShipItem(SFItem.SFBrowserItem): fnEditSize = editCtl.GetSize() wSize = self.GetSize() fnEditPosX = end - fnEditPosY = (wSize.height - fnEditSize.height)/2 + fnEditPosY = (wSize.height - fnEditSize.height) / 2 if fnEditPosX < start: - editCtl.SetSize((self.editWidth + fnEditPosX - start,-1)) - editCtl.SetPosition((start,fnEditPosY)) + editCtl.SetSize((self.editWidth + fnEditPosX - start, -1)) + editCtl.SetPosition((start, fnEditPosY)) else: - editCtl.SetSize((self.editWidth,-1)) - editCtl.SetPosition((fnEditPosX,fnEditPosY)) + editCtl.SetSize((self.editWidth, -1)) + editCtl.SetPosition((fnEditPosX, fnEditPosY)) + class PFBitmapFrame(wx.Frame): - def __init__ (self, parent, pos, bitmap): - wx.Frame.__init__(self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = pos, size = wx.DefaultSize, style = - wx.NO_BORDER - | wx.FRAME_NO_TASKBAR - | wx.STAY_ON_TOP) + def __init__(self, parent, pos, bitmap): + wx.Frame.__init__(self, parent, id=wx.ID_ANY, title=wx.EmptyString, pos=pos, size=wx.DefaultSize, + style=wx.NO_BORDER | wx.FRAME_NO_TASKBAR | wx.STAY_ON_TOP) img = bitmap.ConvertToImage() img = img.ConvertToGreyscale() bitmap = wx.BitmapFromImage(img) self.bitmap = bitmap self.SetSize((bitmap.GetWidth(), bitmap.GetHeight())) - self.Bind(wx.EVT_PAINT,self.OnWindowPaint) + self.Bind(wx.EVT_PAINT, self.OnWindowPaint) self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnWindowEraseBk) self.Bind(wx.EVT_TIMER, self.OnTimer) - self.timer = wx.Timer(self,wx.ID_ANY) + self.timer = wx.Timer(self, wx.ID_ANY) self.direction = 1 self.transp = 0 - self.SetSize((bitmap.GetWidth(),bitmap.GetHeight())) + self.SetSize((bitmap.GetWidth(), bitmap.GetHeight())) self.SetTransparent(0) self.Refresh() def OnTimer(self, event): - self.transp += 20*self.direction + self.transp += 20 * self.direction if self.transp > 200: self.transp = 200 self.timer.Stop() if self.transp < 0: self.transp = 0 self.timer.Stop() - wx.Frame.Show(self,False) + wx.Frame.Show(self, False) self.Destroy() return self.SetTransparent(self.transp) - def Show(self, showWnd = True): + def Show(self, showWnd=True): if showWnd: wx.Frame.Show(self, showWnd) self.Parent.SetFocus() @@ -1404,33 +1409,34 @@ class PFBitmapFrame(wx.Frame): self.direction = -1 self.timer.Start(5) - def OnWindowEraseBk(self,event): + def OnWindowEraseBk(self, event): pass - def OnWindowPaint(self,event): + def OnWindowPaint(self, event): rect = self.GetRect() canvas = wx.EmptyBitmap(rect.width, rect.height) mdc = wx.BufferedPaintDC(self) mdc.SelectObject(canvas) mdc.DrawBitmap(self.bitmap, 0, 0) - mdc.SetPen( wx.Pen("#000000", width = 1 ) ) - mdc.SetBrush( wx.TRANSPARENT_BRUSH ) - mdc.DrawRectangle( 0,0,rect.width,rect.height) + mdc.SetPen(wx.Pen("#000000", width=1)) + mdc.SetBrush(wx.TRANSPARENT_BRUSH) + mdc.DrawRectangle(0, 0, rect.width, rect.height) class FitItem(SFItem.SFBrowserItem): - def __init__(self, parent, fitID=None, shipFittingInfo=("Test", "TestTrait", "cnc's avatar", 0, 0 ), shipID = None, itemData=None, + def __init__(self, parent, fitID=None, shipFittingInfo=("Test", "TestTrait", "cnc's avatar", 0, 0), shipID=None, + itemData=None, id=wx.ID_ANY, pos=wx.DefaultPosition, size=(0, 40), style=0): - #=============================================================================== + # ===================================================================== # animCount should be 10 if we enable animation in Preferences - #=============================================================================== + # ===================================================================== self.animCount = 0 self.selectedDelta = 0 - SFItem.SFBrowserItem.__init__(self,parent,size = size) + SFItem.SFBrowserItem.__init__(self, parent, size=size) self.mainFrame = gui.mainFrame.MainFrame.getInstance() @@ -1447,10 +1453,10 @@ class FitItem(SFItem.SFBrowserItem): self.deleted = False if shipID: - self.shipBmp = BitmapLoader.getBitmap(str(shipID),"renders") + self.shipBmp = BitmapLoader.getBitmap(str(shipID), "renders") if not self.shipBmp: - self.shipBmp = BitmapLoader.getBitmap("ship_no_image_big","gui") + self.shipBmp = BitmapLoader.getBitmap("ship_no_image_big", "gui") self.shipFittingInfo = shipFittingInfo self.shipName, self.shipTrait, self.fitName, self.fitBooster, self.timestamp = shipFittingInfo @@ -1458,16 +1464,15 @@ class FitItem(SFItem.SFBrowserItem): # see GH issue #62 # Disabling this due to change in gang boosts Nov 2016 - #if self.fitBooster is None: self.fitBooster = False + # if self.fitBooster is None: self.fitBooster = False self.fitBooster = False self.boosterBmp = BitmapLoader.getBitmap("fleet_fc_small", "gui") - self.copyBmp = BitmapLoader.getBitmap("fit_add_small", "gui") - self.renameBmp = BitmapLoader.getBitmap("fit_rename_small", "gui") - self.deleteBmp = BitmapLoader.getBitmap("fit_delete_small","gui") - self.acceptBmp = BitmapLoader.getBitmap("faccept_small", "gui") - - self.shipEffBk = BitmapLoader.getBitmap("fshipbk_big","gui") + self.copyBmp = BitmapLoader.getBitmap("fit_add_small", "gui") + self.renameBmp = BitmapLoader.getBitmap("fit_rename_small", "gui") + self.deleteBmp = BitmapLoader.getBitmap("fit_delete_small", "gui") + self.acceptBmp = BitmapLoader.getBitmap("faccept_small", "gui") + self.shipEffBk = BitmapLoader.getBitmap("fshipbk_big", "gui") img = wx.ImageFromBitmap(self.shipEffBk) img = img.Mirror(False) @@ -1476,8 +1481,8 @@ class FitItem(SFItem.SFBrowserItem): self.dragTLFBmp = None self.bkBitmap = None - if self.shipTrait != "": # show no tooltip if no trait available - self.SetToolTip(wx.ToolTip(u'{}\n{}\n{}'.format(self.shipName, u'─'*20, self.shipTrait))) + if self.shipTrait != "": # show no tooltip if no trait available + self.SetToolTip(wx.ToolTip(u'{}\n{}\n{}'.format(self.shipName, u'─' * 20, self.shipTrait))) self.padding = 4 self.editWidth = 150 @@ -1493,12 +1498,13 @@ class FitItem(SFItem.SFBrowserItem): self.SetDraggable() - self.boosterBtn = self.toolbar.AddButton(self.boosterBmp,"Booster", show=self.fitBooster) - self.toolbar.AddButton(self.copyBmp,"Copy", self.copyBtnCB) - self.renameBtn = self.toolbar.AddButton(self.renameBmp,"Rename", self.renameBtnCB) + self.boosterBtn = self.toolbar.AddButton(self.boosterBmp, "Booster", show=self.fitBooster) + self.toolbar.AddButton(self.copyBmp, "Copy", self.copyBtnCB) + self.renameBtn = self.toolbar.AddButton(self.renameBmp, "Rename", self.renameBtnCB) self.toolbar.AddButton(self.deleteBmp, "Delete", self.deleteBtnCB) - self.tcFitName = wx.TextCtrl(self, wx.ID_ANY, "%s" % self.fitName, wx.DefaultPosition, (self.editWidth,-1), wx.TE_PROCESS_ENTER) + self.tcFitName = wx.TextCtrl(self, wx.ID_ANY, "%s" % self.fitName, wx.DefaultPosition, (self.editWidth, -1), + wx.TE_PROCESS_ENTER) if self.shipBrowser.fitIDMustEditName != self.fitID: self.tcFitName.Show(False) @@ -1523,24 +1529,24 @@ class FitItem(SFItem.SFBrowserItem): self.Bind(wx.EVT_TIMER, self.OnTimer) - #======================================================================= + # ===================================================================== # DISABLED - it will be added as an option in PREFERENCES # if self.shipBrowser.GetActiveStage() != 4 and self.shipBrowser.GetLastStage() !=3: # self.animTimer.Start(self.animPeriod) # else: # self.animCount = 0 - #======================================================================= + # ===================================================================== self.selTimerID = wx.NewId() - self.selTimer = wx.Timer(self,self.selTimerID) + self.selTimer = wx.Timer(self, self.selTimerID) self.selTimer.Start(100) self.Bind(wx.EVT_RIGHT_UP, self.OnContextMenu) def OnToggleBooster(self, event): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() sFit.toggleBoostFit(self.fitID) self.fitBooster = not self.fitBooster self.boosterBtn.Show(self.fitBooster) @@ -1551,7 +1557,7 @@ class FitItem(SFItem.SFBrowserItem): def OnProjectToFit(self, event): activeFit = self.mainFrame.getActiveFit() if activeFit: - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() projectedFit = sFit.getFit(self.fitID) sFit.project(activeFit, projectedFit) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFit)) @@ -1560,7 +1566,7 @@ class FitItem(SFItem.SFBrowserItem): def OnAddCommandFit(self, event): activeFit = self.mainFrame.getActiveFit() if activeFit: - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() commandFit = sFit.getFit(self.fitID) sFit.addCommandFit(activeFit, commandFit) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFit)) @@ -1578,7 +1584,7 @@ class FitItem(SFItem.SFBrowserItem): def OnContextMenu(self, event): ''' Handles context menu for fit. Dragging is handled by MouseLeftUp() ''' - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(self.mainFrame.getActiveFit()) if not fit: @@ -1606,7 +1612,7 @@ class FitItem(SFItem.SFBrowserItem): self.Bind(wx.EVT_MENU, self.OnProjectToFit, projectedItem) commandItem = menu.Append(wx.ID_ANY, "Add Command Booster") - self.Bind(wx.EVT_MENU, self.OnAddCommandFit, commandItem ) + self.Bind(wx.EVT_MENU, self.OnAddCommandFit, commandItem) self.PopupMenu(menu, pos) @@ -1622,7 +1628,7 @@ class FitItem(SFItem.SFBrowserItem): interval = 5 if ctimestamp < self.timestamp + interval: delta = (ctimestamp - self.timestamp) / interval - self.selectedDelta = self.CalculateDelta(0x0,self.maxDelta,delta) + self.selectedDelta = self.CalculateDelta(0x0, self.maxDelta, delta) self.Refresh() else: self.selectedDelta = self.maxDelta @@ -1632,23 +1638,23 @@ class FitItem(SFItem.SFBrowserItem): step = self.OUT_QUAD(self.animStep, 0, 10, self.animDuration) self.animCount = 10 - step self.animStep += self.animPeriod - if self.animStep > self.animDuration or self.animCount < 0 : + if self.animStep > self.animDuration or self.animCount < 0: self.animCount = 0 self.animTimer.Stop() self.Refresh() def CalculateDelta(self, start, end, delta): - return start + (end-start)*delta + return start + (end - start) * delta - def OUT_QUAD (self, t, b, c, d): - t=float(t) - b=float(b) - c=float(c) - d=float(d) + def OUT_QUAD(self, t, b, c, d): + t = float(t) + b = float(b) + c = float(c) + d = float(d) - t/=d + t /= d - return -c *(t)*(t-2) + b + return -c * t * (t - 2) + b def editLostFocus(self, event): self.RestoreEditButton() @@ -1668,10 +1674,10 @@ class FitItem(SFItem.SFBrowserItem): self.copyFit() def copyFit(self, event=None): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fitID = sFit.copyFit(self.fitID) self.shipBrowser.fitIDMustEditName = fitID - wx.PostEvent(self.shipBrowser,Stage3Selected(shipID=self.shipID)) + wx.PostEvent(self.shipBrowser, Stage3Selected(shipID=self.shipID)) wx.PostEvent(self.mainFrame, FitSelected(fitID=fitID)) def renameBtnCB(self): @@ -1688,7 +1694,7 @@ class FitItem(SFItem.SFBrowserItem): self.Refresh() def renameFit(self, event=None): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() self.tcFitName.Show(False) self.editWasShown = 0 fitName = self.tcFitName.GetValue() @@ -1709,9 +1715,12 @@ class FitItem(SFItem.SFBrowserItem): if wx.GetMouseState().ShiftDown() or wx.GetMouseState().MiddleDown(): self.deleteFit() else: - dlg = wx.MessageDialog(self, - "Do you really want to delete this fit?", - "Confirm Delete", wx.YES | wx.NO | wx.ICON_QUESTION) + dlg = wx.MessageDialog( + self, + "Do you really want to delete this fit?", + "Confirm Delete", + wx.YES | wx.NO | wx.ICON_QUESTION + ) if dlg.ShowModal() == wx.ID_YES: self.deleteFit() @@ -1722,14 +1731,14 @@ class FitItem(SFItem.SFBrowserItem): else: self.deleted = True - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(self.fitID) sFit.deleteFit(self.fitID) if self.shipBrowser.GetActiveStage() == 5: - if fit in self.shipBrowser.lastdata: # remove fit from import cache - self.shipBrowser.lastdata.remove(fit) + if fit in self.shipBrowser.lastdata: # remove fit from import cache + self.shipBrowser.lastdata.remove(fit) wx.PostEvent(self.shipBrowser, ImportSelected(fits=self.shipBrowser.lastdata)) elif self.shipBrowser.GetActiveStage() == 4: wx.PostEvent(self.shipBrowser, SearchSelected(text=self.shipBrowser.navpanel.lastSearch, back=True)) @@ -1794,9 +1803,9 @@ class FitItem(SFItem.SFBrowserItem): wx.PostEvent(self.mainFrame, FitSelected(fitID=self.fitID)) def RestoreEditButton(self): - self.tcFitName.Show(False) - self.renameBtn.SetBitmap(self.renameBmp) - self.Refresh() + self.tcFitName.Show(False) + self.renameBtn.SetBitmap(self.renameBmp) + self.Refresh() def UpdateElementsPos(self, mdc): rect = self.GetRect() @@ -1806,15 +1815,15 @@ class FitItem(SFItem.SFBrowserItem): self.toolbarx = self.toolbarx + self.animCount - self.shipEffx = self.padding + (rect.height - self.shipEffBk.GetWidth())/2 - self.shipEffy = (rect.height - self.shipEffBk.GetHeight())/2 + self.shipEffx = self.padding + (rect.height - self.shipEffBk.GetWidth()) / 2 + self.shipEffy = (rect.height - self.shipEffBk.GetHeight()) / 2 self.shipEffx = self.shipEffx - self.animCount self.shipBmpx = self.padding + (rect.height - self.shipBmp.GetWidth()) / 2 self.shipBmpy = (rect.height - self.shipBmp.GetHeight()) / 2 - self.shipBmpx= self.shipBmpx - self.animCount + self.shipBmpx = self.shipBmpx - self.animCount self.textStartx = self.shipEffx + self.shipEffBk.GetWidth() + self.padding @@ -1827,10 +1836,10 @@ class FitItem(SFItem.SFBrowserItem): mdc.SetFont(self.fontSmall) - wlabel,hlabel = mdc.GetTextExtent(self.toolbar.hoverLabel) + wlabel, hlabel = mdc.GetTextExtent(self.toolbar.hoverLabel) self.thoverx = self.toolbarx - self.padding - wlabel - self.thovery = (rect.height - hlabel)/2 + self.thovery = (rect.height - hlabel) / 2 self.thoverw = wlabel def DrawItem(self, mdc): @@ -1859,8 +1868,9 @@ class FitItem(SFItem.SFBrowserItem): mdc.SetFont(self.fontNormal) fitDate = time.localtime(self.timestamp) - fitLocalDate = "%d/%02d/%02d %02d:%02d" % ( fitDate[0], fitDate[1], fitDate[2], fitDate[3], fitDate[4]) - pfdate = drawUtils.GetPartialText(mdc, fitLocalDate, self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw) + fitLocalDate = "%d/%02d/%02d %02d:%02d" % (fitDate[0], fitDate[1], fitDate[2], fitDate[3], fitDate[4]) + pfdate = drawUtils.GetPartialText(mdc, fitLocalDate, + self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw) mdc.DrawText(pfdate, self.textStartx, self.timestampy) @@ -1869,7 +1879,8 @@ class FitItem(SFItem.SFBrowserItem): mdc.SetFont(self.fontBig) - psname = drawUtils.GetPartialText(mdc, self.fitName, self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw) + psname = drawUtils.GetPartialText(mdc, self.fitName, + self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw) mdc.DrawText(psname, self.textStartx, self.fitNamey) @@ -1886,13 +1897,13 @@ class FitItem(SFItem.SFBrowserItem): fnEditSize = editCtl.GetSize() wSize = self.GetSize() fnEditPosX = end - fnEditPosY = (wSize.height - fnEditSize.height)/2 + fnEditPosY = (wSize.height - fnEditSize.height) / 2 if fnEditPosX < start: - editCtl.SetSize((self.editWidth + fnEditPosX - start,-1)) - editCtl.SetPosition((start,fnEditPosY)) + editCtl.SetSize((self.editWidth + fnEditPosX - start, -1)) + editCtl.SetPosition((start, fnEditPosY)) else: - editCtl.SetSize((self.editWidth,-1)) - editCtl.SetPosition((fnEditPosX,fnEditPosY)) + editCtl.SetSize((self.editWidth, -1)) + editCtl.SetPosition((fnEditPosX, fnEditPosY)) def GetState(self): activeFitID = self.mainFrame.getActiveFit() @@ -1903,7 +1914,7 @@ class FitItem(SFItem.SFBrowserItem): else: if activeFitID == self.fitID: if self.highlighted: - state = SFItem.SB_ITEM_SELECTED | SFItem.SB_ITEM_HIGHLIGHTED + state = SFItem.SB_ITEM_SELECTED | SFItem.SB_ITEM_HIGHLIGHTED else: state = SFItem.SB_ITEM_SELECTED else: @@ -1915,8 +1926,7 @@ class FitItem(SFItem.SFBrowserItem): windowColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW) - activeFitID = self.mainFrame.getActiveFit() - + # activeFitID = self.mainFrame.getActiveFit() state = self.GetState() sFactor = 0.2 @@ -1927,18 +1937,18 @@ class FitItem(SFItem.SFBrowserItem): mFactor = 0.45 eFactor = 0.30 - elif state == SFItem.SB_ITEM_SELECTED | SFItem.SB_ITEM_HIGHLIGHTED: + elif state == SFItem.SB_ITEM_SELECTED | SFItem.SB_ITEM_HIGHLIGHTED: eFactor = 0.3 mFactor = 0.4 elif state == SFItem.SB_ITEM_SELECTED: - eFactor = (self.maxDelta - self.selectedDelta)/100 + 0.25 + eFactor = (self.maxDelta - self.selectedDelta) / 100 + 0.25 else: sFactor = 0 if self.bkBitmap: if self.bkBitmap.eFactor == eFactor and self.bkBitmap.sFactor == sFactor and self.bkBitmap.mFactor == mFactor \ - and rect.width == self.bkBitmap.GetWidth() and rect.height == self.bkBitmap.GetHeight() : + and rect.width == self.bkBitmap.GetWidth() and rect.height == self.bkBitmap.GetHeight(): return else: del self.bkBitmap @@ -1948,4 +1958,3 @@ class FitItem(SFItem.SFBrowserItem): self.bkBitmap.sFactor = sFactor self.bkBitmap.eFactor = eFactor self.bkBitmap.mFactor = mFactor - diff --git a/gui/statsPane.py b/gui/statsPane.py index 6c378878c..5d20f22ef 100644 --- a/gui/statsPane.py +++ b/gui/statsPane.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,25 +15,27 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx -from gui.statsView import StatsView -import service -from gui.pyfatogglepanel import TogglePanel -import gui.builtinStatsViews -from gui.contextMenu import ContextMenu -#import gui.builtinViews.fittingView as fv + +from service.fit import Fit import gui.mainFrame +import gui.builtinStatsViews import gui.globalEvents as GE +# import gui.builtinViews.fittingView as fv +from gui.statsView import StatsView +from gui.contextMenu import ContextMenu +from gui.pyfatogglepanel import TogglePanel + class StatsPane(wx.Panel): - DEFAULT_VIEWS = ["resourcesViewFull", "resistancesViewFull" ,"rechargeViewFull", "firepowerViewFull", + DEFAULT_VIEWS = ["resourcesViewFull", "resistancesViewFull", "rechargeViewFull", "firepowerViewFull", "capacitorViewFull", "targetingmiscViewFull", - "priceViewFull",] + "priceViewFull"] def fitChanged(self, event): - sFit = service.Fit.getInstance() + sFit = Fit.getInstance() fit = sFit.getFit(event.fitID) for view in self.views: view.refreshPanel(fit) @@ -44,7 +46,7 @@ class StatsPane(wx.Panel): # Use 25% smaller fonts if MAC or force font size to 8 for msw/linux - if "__WXMAC__" in wx.PlatformInfo : + if "__WXMAC__" in wx.PlatformInfo: self.SetWindowVariant(wx.WINDOW_VARIANT_SMALL) else: standardFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) @@ -57,7 +59,7 @@ class StatsPane(wx.Panel): self.views = [] self.nameViewMap = {} maxviews = len(self.DEFAULT_VIEWS) - i=0 + i = 0 for viewName in self.DEFAULT_VIEWS: tp = TogglePanel(self) contentPanel = tp.GetContentPane() @@ -79,19 +81,20 @@ class StatsPane(wx.Panel): mainSizer.Add(tp, 0, wx.EXPAND | wx.LEFT, 3) if i < maxviews - 1: - mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, style=wx.HORIZONTAL), 0, wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, 2) - i+=1 + mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, style=wx.HORIZONTAL), 0, + wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, 2) + i += 1 tp.OnStateChange(tp.GetBestSize()) - width,height = self.GetSize() - self.SetMinSize((width+9,-1)) - + width, height = self.GetSize() + self.SetMinSize((width + 9, -1)) self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) def contextHandler(self, contentPanel): viewName = contentPanel.viewName + def handler(event): menu = ContextMenu.getMenu(None, (viewName,)) if menu is not None: diff --git a/gui/statsView.py b/gui/statsView.py index 33e2a74e9..2cd8db548 100644 --- a/gui/statsView.py +++ b/gui/statsView.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,10 +15,12 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= + class StatsView(object): views = {} + def __init__(self): pass @@ -39,4 +41,5 @@ class StatsView(object): def refreshPanel(self, fit): raise NotImplementedError() -from gui.builtinStatsViews import * \ No newline at end of file + +from gui.builtinStatsViews import * # noqa diff --git a/gui/updateDialog.py b/gui/updateDialog.py index 0febdf3f8..155d5a6a9 100644 --- a/gui/updateDialog.py +++ b/gui/updateDialog.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,87 +15,95 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx -from gui.bitmapLoader import BitmapLoader -import config -import service import dateutil.parser +from service.settings import UpdateSettings as svc_UpdateSettings + class UpdateDialog(wx.Dialog): - def __init__(self, parent, release): - wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = "Pyfa Update", pos = wx.DefaultPosition, size = wx.Size( 400,300 ), style = wx.DEFAULT_DIALOG_STYLE ) + wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title="Pyfa Update", pos=wx.DefaultPosition, + size=wx.Size(400, 300), style=wx.DEFAULT_DIALOG_STYLE) - self.UpdateSettings = service.settings.UpdateSettings.getInstance() + self.UpdateSettings = svc_UpdateSettings.getInstance() self.releaseInfo = release - self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize ) + self.SetSizeHintsSz(wx.DefaultSize, wx.DefaultSize) - mainSizer = wx.BoxSizer( wx.VERTICAL ) + mainSizer = wx.BoxSizer(wx.VERTICAL) - headSizer = wx.BoxSizer( wx.HORIZONTAL ) + headSizer = wx.BoxSizer(wx.HORIZONTAL) - self.headingText = wx.StaticText( self, wx.ID_ANY, "Pyfa Update Available!", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) - self.headingText.Wrap( -1 ) - self.headingText.SetFont( wx.Font( 14, 74, 90, 92, False) ) + self.headingText = wx.StaticText(self, wx.ID_ANY, "Pyfa Update Available!", wx.DefaultPosition, wx.DefaultSize, + wx.ALIGN_CENTRE) + self.headingText.Wrap(-1) + self.headingText.SetFont(wx.Font(14, 74, 90, 92, False)) - headSizer.Add( self.headingText, 1, wx.ALL, 5 ) - mainSizer.Add( headSizer, 0, wx.EXPAND, 5 ) + headSizer.Add(self.headingText, 1, wx.ALL, 5) + mainSizer.Add(headSizer, 0, wx.EXPAND, 5) - mainSizer.Add( wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ), 0, wx.EXPAND |wx.ALL, 5 ) + mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0, + wx.EXPAND | wx.ALL, 5) - versionSizer = wx.BoxSizer( wx.HORIZONTAL ) + versionSizer = wx.BoxSizer(wx.HORIZONTAL) - if(self.releaseInfo['prerelease']): - self.releaseText = wx.StaticText( self, wx.ID_ANY, "Pre-release", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_RIGHT ) - self.releaseText.SetFont( wx.Font( 12, 74, 90, 92, False) ) - self.releaseText.SetForegroundColour( wx.Colour( 230, 0, 0 ) ) + if (self.releaseInfo['prerelease']): + self.releaseText = wx.StaticText(self, wx.ID_ANY, "Pre-release", wx.DefaultPosition, wx.DefaultSize, + wx.ALIGN_RIGHT) + self.releaseText.SetFont(wx.Font(12, 74, 90, 92, False)) + self.releaseText.SetForegroundColour(wx.Colour(230, 0, 0)) else: - self.releaseText = wx.StaticText( self, wx.ID_ANY, "Stable", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_RIGHT ) - self.releaseText.SetFont( wx.Font( 12, 74, 90, 90, False) ) + self.releaseText = wx.StaticText(self, wx.ID_ANY, "Stable", wx.DefaultPosition, wx.DefaultSize, + wx.ALIGN_RIGHT) + self.releaseText.SetFont(wx.Font(12, 74, 90, 90, False)) - self.releaseText.Wrap( -1 ) + self.releaseText.Wrap(-1) - versionSizer.Add( self.releaseText, 1, wx.ALL, 5 ) + versionSizer.Add(self.releaseText, 1, wx.ALL, 5) - self.versionText = wx.StaticText( self, wx.ID_ANY, self.releaseInfo['tag_name'], wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_LEFT ) - self.versionText.Wrap( -1 ) - self.versionText.SetFont( wx.Font( 12, 74, 90, 90, False) ) + self.versionText = wx.StaticText(self, wx.ID_ANY, self.releaseInfo['tag_name'], wx.DefaultPosition, + wx.DefaultSize, wx.ALIGN_LEFT) + self.versionText.Wrap(-1) + self.versionText.SetFont(wx.Font(12, 74, 90, 90, False)) - versionSizer.Add( self.versionText, 1, wx.ALL, 5 ) - versionSizer.AddSpacer( ( 15, 5), 0, wx.EXPAND, 5 ) + versionSizer.Add(self.versionText, 1, wx.ALL, 5) + versionSizer.AddSpacer((15, 5), 0, wx.EXPAND, 5) - mainSizer.Add( versionSizer, 0, wx.EXPAND, 5 ) - mainSizer.AddSpacer( ( 0, 5), 0, wx.EXPAND, 5 ) + mainSizer.Add(versionSizer, 0, wx.EXPAND, 5) + mainSizer.AddSpacer((0, 5), 0, wx.EXPAND, 5) releaseDate = dateutil.parser.parse(self.releaseInfo['published_at']) - notesSizer = wx.BoxSizer( wx.HORIZONTAL ) - self.notesTextCtrl = wx.TextCtrl( self, wx.ID_ANY, str(releaseDate.date())+":\n\n"+self.releaseInfo['body'], wx.DefaultPosition, wx.DefaultSize, wx.TE_AUTO_URL|wx.TE_MULTILINE|wx.TE_READONLY|wx.DOUBLE_BORDER|wx.TRANSPARENT_WINDOW ) + notesSizer = wx.BoxSizer(wx.HORIZONTAL) + self.notesTextCtrl = wx.TextCtrl(self, wx.ID_ANY, str(releaseDate.date()) + ":\n\n" + self.releaseInfo['body'], + wx.DefaultPosition, wx.DefaultSize, + wx.TE_AUTO_URL | wx.TE_MULTILINE | wx.TE_READONLY | wx.DOUBLE_BORDER | wx.TRANSPARENT_WINDOW) - notesSizer.Add( self.notesTextCtrl, 1, wx.EXPAND|wx.LEFT|wx.RIGHT, 5 ) - mainSizer.Add( notesSizer, 1, wx.EXPAND, 5 ) + notesSizer.Add(self.notesTextCtrl, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 5) + mainSizer.Add(notesSizer, 1, wx.EXPAND, 5) - self.supressCheckbox = wx.CheckBox( self, wx.ID_ANY, "Don't remind me again for this release", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.supressCheckbox = wx.CheckBox(self, wx.ID_ANY, "Don't remind me again for this release", + wx.DefaultPosition, wx.DefaultSize, 0) self.supressCheckbox.Bind(wx.EVT_CHECKBOX, self.SuppressChange) - mainSizer.Add( self.supressCheckbox, 0, wx.ALL, 5 ) - mainSizer.Add( wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ), 0, wx.EXPAND |wx.ALL, 5 ) + mainSizer.Add(self.supressCheckbox, 0, wx.ALL, 5) + mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0, + wx.EXPAND | wx.ALL, 5) - actionSizer = wx.BoxSizer( wx.HORIZONTAL ) + actionSizer = wx.BoxSizer(wx.HORIZONTAL) - goSizer = wx.BoxSizer( wx.VERTICAL ) - self.downloadButton = wx.Button( self, wx.ID_ANY, "Download", wx.DefaultPosition, wx.DefaultSize, 0 ) + goSizer = wx.BoxSizer(wx.VERTICAL) + self.downloadButton = wx.Button(self, wx.ID_ANY, "Download", wx.DefaultPosition, wx.DefaultSize, 0) self.downloadButton.Bind(wx.EVT_BUTTON, self.OnDownload) - goSizer.Add( self.downloadButton, 0, wx.ALL, 5 ) - actionSizer.Add( goSizer, 1, wx.EXPAND, 5 ) + goSizer.Add(self.downloadButton, 0, wx.ALL, 5) + actionSizer.Add(goSizer, 1, wx.EXPAND, 5) self.closeButton = wx.Button(self, wx.ID_CLOSE) self.closeButton.Bind(wx.EVT_BUTTON, self.OnClose) - actionSizer.Add( self.closeButton, 0, wx.ALL, 5 ) - mainSizer.Add( actionSizer, 0, wx.EXPAND, 5 ) + actionSizer.Add(self.closeButton, 0, wx.ALL, 5) + mainSizer.Add(actionSizer, 0, wx.EXPAND, 5) - self.SetSizer( mainSizer ) + self.SetSizer(mainSizer) self.Layout() # Handle use-case of suppressing a release, then a new version becoming available. @@ -104,7 +112,7 @@ class UpdateDialog(wx.Dialog): # safely reset this setting self.UpdateSettings.set('version', None) - self.Centre( wx.BOTH ) + self.Centre(wx.BOTH) def OnClose(self, e): self.Close() @@ -116,5 +124,5 @@ class UpdateDialog(wx.Dialog): self.UpdateSettings.set('version', None) def OnDownload(self, e): - wx.LaunchDefaultBrowser('https://github.com/pyfa-org/Pyfa/releases/tag/'+self.releaseInfo['tag_name']) + wx.LaunchDefaultBrowser('https://github.com/pyfa-org/Pyfa/releases/tag/' + self.releaseInfo['tag_name']) self.OnClose(e) diff --git a/gui/utils/animEffects.py b/gui/utils/animEffects.py index 519fe60c4..a705374a0 100644 --- a/gui/utils/animEffects.py +++ b/gui/utils/animEffects.py @@ -1,83 +1,97 @@ - import math -def OUT_CIRC (t, b, c, d): - t=float(t) - b=float(b) - c=float(c) - d=float(d) - t = t/d -1 - return c * math.sqrt(1 - t*t) + b; + +def OUT_CIRC(t, b, c, d): + t = float(t) + b = float(b) + c = float(c) + d = float(d) + + t = t / d - 1 + + return c * math.sqrt(1 - t * t) + b + def OUT_QUART(t, b, c, d): - t=float(t) - b=float(b) - c=float(c) - d=float(d) - t = t/d -1 - return -c * ((t)*t*t*t - 1) + b; + t = float(t) + b = float(b) + c = float(c) + d = float(d) + + t = t / d - 1 + + return -c * (t * t * t * t - 1) + b + def INOUT_CIRC(t, b, c, d): - t=float(t) - b=float(b) - c=float(c) - d=float(d) + t = float(t) + b = float(b) + c = float(c) + d = float(d) t1 = t / (d / 2) - if ((t / (d/2)) < 1): - return -c/2 * (math.sqrt(1 - (t/(d/2))**2) - 1) + b - return c/2 * (math.sqrt(1 - (t1-2)**2) + 1) + b; - -def IN_CUBIC (t, b, c, d): - t=float(t) - b=float(b) - c=float(c) - d=float(d) - t = t/d - return c*t*t*t + b - -def OUT_QUAD (t, b, c, d): - t=float(t) - b=float(b) - c=float(c) - d=float(d) - - t/=d - - return -c *(t)*(t-2) + b - -def OUT_BOUNCE (t, b, c, d): - t=float(t) - b=float(b) - c=float(c) - d=float(d) - - t/=d - - if ((t) < (1/2.75)): - return c*(7.5625*t*t) + b + if (t / (d / 2)) < 1: + return -c / 2 * (math.sqrt(1 - (t / (d / 2)) ** 2) - 1) + b else: - if (t < (2/2.75)): - t-=(1.5/2.75) - return c*(7.5625*t*t + .75) + b - else: - if (t < (2.5/2.75)): - t-=(2.25/2.75) - return c*(7.5625*(t)*t + .9375) + b - else: - t-=(2.625/2.75) - return c*(7.5625*(t)*t + .984375) + b + return c / 2 * (math.sqrt(1 - (t1 - 2) ** 2) + 1) + b + + +def IN_CUBIC(t, b, c, d): + t = float(t) + b = float(b) + c = float(c) + d = float(d) + + t = t / d + + return c * t * t * t + b + + +def OUT_QUAD(t, b, c, d): + t = float(t) + b = float(b) + c = float(c) + d = float(d) + + t /= d + + return -c * t * (t - 2) + b + + +def OUT_BOUNCE(t, b, c, d): + t = float(t) + b = float(b) + c = float(c) + d = float(d) + + t /= d + + if t < (1 / 2.75): + return c * (7.5625 * t * t) + b + elif t < (2 / 2.75): + t -= (1.5 / 2.75) + return c * (7.5625 * t * t + .75) + b + elif t < (2.5 / 2.75): + t -= (2.25 / 2.75) + return c * (7.5625 * t * t + .9375) + b + else: + t -= (2.625 / 2.75) + return c * (7.5625 * t * t + .984375) + b + def INOUT_EXP(t, b, c, d): - t=float(t) - b=float(b) - c=float(c) - d=float(d) - t1 = t / (d/2) - if t==0: - return b - if t==d: - return b+c - if (t1) < 1: - return c/2 * math.pow(2, 10 * (t1 - 1)) + b - c * 0.0005 - return c/2 * 1.0005 * (-math.pow(2, -10 * (t1-1)) + 2) + b + t = float(t) + b = float(b) + c = float(c) + d = float(d) + + t1 = t / (d / 2) + + if t == 0: + return b + elif t == d: + return b + c + elif t1 < 1: + return c / 2 * math.pow(2, 10 * (t1 - 1)) + b - c * 0.0005 + else: + return c / 2 * 1.0005 * (-math.pow(2, -10 * (t1 - 1)) + 2) + b diff --git a/gui/utils/animUtils.py b/gui/utils/animUtils.py index 9ee81b03a..cefd3938b 100644 --- a/gui/utils/animUtils.py +++ b/gui/utils/animUtils.py @@ -1,9 +1,10 @@ import wx import gui.utils.colorUtils as colorUtils + class LoadAnimation(wx.Window): - def __init__ (self, parent, id = wx.ID_ANY, label = "", pos = wx.DefaultPosition, size = wx.DefaultSize, style = 0): - wx.Window.__init__(self, parent, id, pos = pos, size = size, style = style) + def __init__(self, parent, id=wx.ID_ANY, label="", pos=wx.DefaultPosition, size=wx.DefaultSize, style=0): + wx.Window.__init__(self, parent, id, pos=pos, size=size, style=style) self.label = label @@ -16,7 +17,6 @@ class LoadAnimation(wx.Window): self.bars = 10 self.padding = 2 - self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) self.Bind(wx.EVT_TIMER, self.OnTimer) self.Bind(wx.EVT_PAINT, self.OnPaint) @@ -64,14 +64,14 @@ class LoadAnimation(wx.Window): x = self.padding - for bar in xrange(self.bars): + for bar in range(self.bars): if bar != self.animCount: dc.SetPen(wx.Pen(shadeColor)) dc.SetBrush(wx.Brush(shadeColor)) bh = barHeight y = self.padding else: - barColor = colorUtils.GetSuitableColor(barColor,float(self.animCount/2)/10) + barColor = colorUtils.GetSuitableColor(barColor, float(self.animCount / 2) / 10) dc.SetPen(wx.Pen(barColor)) dc.SetBrush(wx.Brush(barColor)) bh = rect.height @@ -82,17 +82,17 @@ class LoadAnimation(wx.Window): textColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT) dc.SetTextForeground(textColor) - dc.DrawLabel(self.label,rect,wx.ALIGN_CENTER) + dc.DrawLabel(self.label, rect, wx.ALIGN_CENTER) + class WaitDialog(wx.Dialog): - def __init__(self, parent, title = "Processing"): - wx.Dialog.__init__ (self, parent, id=wx.ID_ANY, title = title, size=(300,30), + def __init__(self, parent, title="Processing"): + wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title=title, size=(300, 30), style=wx.NO_BORDER) - mainSizer = wx.BoxSizer( wx.HORIZONTAL ) + mainSizer = wx.BoxSizer(wx.HORIZONTAL) - self.progress = LoadAnimation(self,label = title, size=(300,30)) - mainSizer.Add( self.progress, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 0 ) - self.SetSizer( mainSizer ) + self.progress = LoadAnimation(self, label=title, size=(300, 30)) + mainSizer.Add(self.progress, 1, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 0) + self.SetSizer(mainSizer) self.Layout() self.CenterOnParent() - diff --git a/gui/utils/clipboard.py b/gui/utils/clipboard.py index 17427c6e3..4fa05e1f3 100644 --- a/gui/utils/clipboard.py +++ b/gui/utils/clipboard.py @@ -1,5 +1,6 @@ import wx + def toClipboard(text): clip = wx.TheClipboard clip.Open() @@ -7,6 +8,7 @@ def toClipboard(text): clip.SetData(data) clip.Close() + def fromClipboard(): clip = wx.TheClipboard clip.Open() @@ -16,4 +18,4 @@ def fromClipboard(): return data.GetText() else: clip.Close() - return None \ No newline at end of file + return None diff --git a/gui/utils/colorUtils.py b/gui/utils/colorUtils.py index ccf42ec18..a8d560159 100644 --- a/gui/utils/colorUtils.py +++ b/gui/utils/colorUtils.py @@ -1,25 +1,26 @@ import wx import math -#Brightens a color (wx.Colour), factor = [0,1] def BrightenColor(color, factor): + # Brightens a color (wx.Colour), factor = [0,1] - r,g,b = color + r, g, b = color a = color.Alpha() factor = min(max(factor, 0), 1) - r+=(255-r)*factor - b+=(255-b)*factor - g+=(255-g)*factor + r += (255 - r) * factor + b += (255 - b) * factor + g += (255 - g) * factor - return wx.Colour(r,g,b,a) + return wx.Colour(r, g, b, a) -#Darkens a color (wx.Colour), factor = [0, 1] def DarkenColor(color, factor): - bkR ,bkG , bkB = color + # Darkens a color (wx.Colour), factor = [0, 1] + + bkR, bkG, bkB = color alpha = color.Alpha() @@ -30,50 +31,50 @@ def DarkenColor(color, factor): g = float(bkG * factor) b = float(bkB * factor) - r = min(max(r,0),255) - b = min(max(b,0),255) - g = min(max(g,0),255) + r = min(max(r, 0), 255) + b = min(max(b, 0), 255) + g = min(max(g, 0), 255) return wx.Colour(r, g, b, alpha) -#Calculates the brightness of a color, different options - def GetBrightnessO1(color): - r,g,b = color - return (0.299*r + 0.587*g + 0.114*b) + # Calculates the brightness of a color, different options + + r, g, b = color + return (0.299 * r + 0.587 * g + 0.114 * b) + def GetBrightnessO2(color): - r,g,b = color - return math.sqrt( 0.241 * r * r + 0.691 * g * g + 0.068 * b * b ) + r, g, b = color + return math.sqrt(0.241 * r * r + 0.691 * g * g + 0.068 * b * b) - -#Calculates a suitable color based on original color (wx.Colour), its brightness, a factor=[0,1] (darken/brighten by factor depending on calculated brightness) - def GetSuitableColor(color, factor): + # Calculates a suitable color based on original color (wx.Colour), its brightness, a factor=[0,1] (darken/brighten by factor depending on calculated brightness) brightness = GetBrightnessO1(color) - if brightness >129: + if brightness > 129: return DarkenColor(color, factor) else: return BrightenColor(color, factor) - -#Calculates the color between a given start and end colors, delta = [0,1] -#Colors are wx.Colour objects - def CalculateTransitionColor(startColor, endColor, delta): - sR,sG,sB = startColor - eR,eG,eB = endColor + """ + Calculates the color between a given start and end colors, delta = [0,1] + Colors are wx.Colour objects + """ + + sR, sG, sB = startColor + eR, eG, eB = endColor alphaS = startColor.Alpha() alphaE = endColor.Alpha() - tR = sR + (eR - sR) * delta - tG = sG + (eG - sG) * delta - tB = sB + (eB - sB) * delta + tR = sR + (eR - sR) * delta + tG = sG + (eG - sG) * delta + tB = sB + (eB - sB) * delta - return wx.Colour(tR, tG, tB, (alphaS + alphaE)/2) + return wx.Colour(tR, tG, tB, (alphaS + alphaE) / 2) diff --git a/gui/utils/compat.py b/gui/utils/compat.py index d8177973b..e0d336b22 100644 --- a/gui/utils/compat.py +++ b/gui/utils/compat.py @@ -14,6 +14,7 @@ except ImportError: class OrderedDict(dict): 'Dictionary that remembers insertion order' + # An inherited dict maps keys to values. # The inherited dict provides __getitem__, __len__, __contains__, and get. # The remaining methods are order-aware. @@ -35,7 +36,7 @@ class OrderedDict(dict): try: self.__root except AttributeError: - self.__root = root = [] # sentinel node + self.__root = root = [] # sentinel node root[:] = [root, root, None] self.__map = {} self.__update(*args, **kwds) @@ -237,7 +238,7 @@ class OrderedDict(dict): ''' if isinstance(other, OrderedDict): - return len(self)==len(other) and self.items() == other.items() + return len(self) == len(other) and self.items() == other.items() return dict.__eq__(self, other) def __ne__(self, other): diff --git a/gui/utils/drawUtils.py b/gui/utils/drawUtils.py index 91e60eb98..559dac395 100644 --- a/gui/utils/drawUtils.py +++ b/gui/utils/drawUtils.py @@ -2,17 +2,16 @@ import wx import gui.utils.colorUtils as colorUtils -def RenderGradientBar(windowColor, width, height, sFactor, eFactor, mFactor = None , fillRatio = 2): - - if sFactor == 0 and eFactor == 0 and mFactor == None: - return DrawFilledBitmap(width,height, windowColor) +def RenderGradientBar(windowColor, width, height, sFactor, eFactor, mFactor=None, fillRatio=2): + if sFactor == 0 and eFactor == 0 and mFactor is None: + return DrawFilledBitmap(width, height, windowColor) gStart = colorUtils.GetSuitableColor(windowColor, sFactor) if mFactor: gMid = colorUtils.GetSuitableColor(windowColor, mFactor) else: - gMid = colorUtils.GetSuitableColor(windowColor, sFactor + (eFactor - sFactor) / 2) + gMid = colorUtils.GetSuitableColor(windowColor, sFactor + (eFactor - sFactor) / 2) gEnd = colorUtils.GetSuitableColor(windowColor, eFactor) @@ -20,7 +19,7 @@ def RenderGradientBar(windowColor, width, height, sFactor, eFactor, mFactor = No def DrawFilledBitmap(width, height, color): - canvas = wx.EmptyBitmap(width,height) + canvas = wx.EmptyBitmap(width, height) mdc = wx.MemoryDC() mdc.SelectObject(canvas) @@ -32,10 +31,11 @@ def DrawFilledBitmap(width, height, color): return canvas -def DrawGradientBar(width, height, gStart, gEnd, gMid = None, fillRatio = 4): + +def DrawGradientBar(width, height, gStart, gEnd, gMid=None, fillRatio=4): # we need to have dimensions to draw - #assert width > 0 and height > 0 - canvas = wx.EmptyBitmap(width,height) + # assert width > 0 and height > 0 + canvas = wx.EmptyBitmap(width, height) mdc = wx.MemoryDC() mdc.SelectObject(canvas) @@ -48,7 +48,7 @@ def DrawGradientBar(width, height, gStart, gEnd, gMid = None, fillRatio = 4): mdc.GradientFillLinear(r, gStart, gMid, wx.SOUTH) r.top = r.height - r.height = height * (fillRatio - 1)/fillRatio + (1 if height % fillRatio != 0 else 0) + r.height = height * (fillRatio - 1) / fillRatio + (1 if height % fillRatio != 0 else 0) mdc.GradientFillLinear(r, gMid, gEnd, wx.SOUTH) @@ -57,48 +57,51 @@ def DrawGradientBar(width, height, gStart, gEnd, gMid = None, fillRatio = 4): return canvas -def GetPartialText(dc, text , maxWidth, defEllipsis = "..."): - ellipsis = defEllipsis +def GetPartialText(dc, text, maxWidth, defEllipsis="..."): + ellipsis = defEllipsis + base_w, h = dc.GetTextExtent(ellipsis) + + lenText = len(text) + drawntext = text + w, dummy = dc.GetTextExtent(text) + + while lenText > 0: + + if w + base_w <= maxWidth: + break + + w_c, h_c = dc.GetTextExtent(drawntext[-1]) + drawntext = drawntext[0:-1] + lenText -= 1 + w -= w_c + + while len(ellipsis) > 0 and w + base_w > maxWidth: + ellipsis = ellipsis[0:-1] base_w, h = dc.GetTextExtent(ellipsis) + if len(text) > lenText: + return drawntext + ellipsis + else: + return text - lenText = len(text) - drawntext = text - w, dummy = dc.GetTextExtent(text) - while lenText > 0: - - if w + base_w <= maxWidth: - break - - w_c, h_c = dc.GetTextExtent(drawntext[-1]) - drawntext = drawntext[0:-1] - lenText -= 1 - w -= w_c - - while len(ellipsis) > 0 and w + base_w > maxWidth: - ellipsis = ellipsis[0:-1] - base_w, h = dc.GetTextExtent(ellipsis) - if len(text) > lenText: - return drawntext + ellipsis - else: - return text - -def GetRoundBitmap( w, h, r ): - maskColor = wx.Color(0,0,0) - shownColor = wx.Color(5,5,5) - b = wx.EmptyBitmap(w,h) +def GetRoundBitmap(w, h, r): + maskColor = wx.Color(0, 0, 0) + shownColor = wx.Color(5, 5, 5) + b = wx.EmptyBitmap(w, h) dc = wx.MemoryDC(b) dc.SetBrush(wx.Brush(maskColor)) - dc.DrawRectangle(0,0,w,h) + dc.DrawRectangle(0, 0, w, h) dc.SetBrush(wx.Brush(shownColor)) dc.SetPen(wx.Pen(shownColor)) - dc.DrawRoundedRectangle(0,0,w,h,r) + dc.DrawRoundedRectangle(0, 0, w, h, r) dc.SelectObject(wx.NullBitmap) b.SetMaskColour(maskColor) return b -def GetRoundShape( w, h, r ): - return wx.RegionFromBitmap( GetRoundBitmap(w,h,r) ) + +def GetRoundShape(w, h, r): + return wx.RegionFromBitmap(GetRoundBitmap(w, h, r)) + def CreateDropShadowBitmap(bitmap, opacity): img = wx.ImageFromBitmap(bitmap) diff --git a/gui/utils/exportHtml.py b/gui/utils/exportHtml.py index 2e5834403..41fa7584d 100644 --- a/gui/utils/exportHtml.py +++ b/gui/utils/exportHtml.py @@ -1,10 +1,14 @@ import threading import time -import service import wx +from service.settings import HTMLExportSettings +from service.fit import Fit +from service.market import Market + class exportHtml(): _instance = None + @classmethod def getInstance(cls): if cls._instance is None: @@ -16,15 +20,15 @@ class exportHtml(): self.thread = exportHtmlThread() def refreshFittingHtml(self, force=False, callback=False): - settings = service.settings.HTMLExportSettings.getInstance() + settings = HTMLExportSettings.getInstance() if force or settings.getEnabled(): self.thread.stop() self.thread = exportHtmlThread(callback) self.thread.start() -class exportHtmlThread(threading.Thread): +class exportHtmlThread(threading.Thread): def __init__(self, callback=False): threading.Thread.__init__(self) self.name = "HTMLExport" @@ -40,39 +44,34 @@ class exportHtmlThread(threading.Thread): if self.stopRunning: return - sMkt = service.Market.getInstance() - sFit = service.Fit.getInstance() - settings = service.settings.HTMLExportSettings.getInstance() + sMkt = Market.getInstance() + sFit = Fit.getInstance() + settings = HTMLExportSettings.getInstance() - timestamp = time.localtime(time.time()) - localDate = "%d/%02d/%02d %02d:%02d" % (timestamp[0], timestamp[1], timestamp[2], timestamp[3], timestamp[4]) - - minimal = settings.getMinimalEnabled(); + minimal = settings.getMinimalEnabled() dnaUrl = "https://o.smium.org/loadout/dna/" if minimal: - HTML = self.generateMinimalHTML(sMkt,sFit, dnaUrl) + HTML = self.generateMinimalHTML(sMkt, sFit, dnaUrl) else: - HTML = self.generateFullHTML(sMkt,sFit, dnaUrl) + HTML = self.generateFullHTML(sMkt, sFit, dnaUrl) try: FILE = open(settings.getPath(), "w") FILE.write(HTML.encode('utf-8')) FILE.close() except IOError: - print "Failed to write to " + settings.getPath() + print("Failed to write to " + settings.getPath()) pass if self.callback: wx.CallAfter(self.callback, -1) - - - def generateFullHTML(self,sMkt,sFit,dnaUrl): + def generateFullHTML(self, sMkt, sFit, dnaUrl): """ Generate the complete HTML with styling and javascript """ timestamp = time.localtime(time.time()) localDate = "%d/%02d/%02d %02d:%02d" % (timestamp[0], timestamp[1], timestamp[2], timestamp[3], timestamp[4]) - + HTML = """ @@ -151,7 +150,7 @@ class exportHtmlThread(threading.Thread): $('a[data-dna]').each(function( index ) { var dna = $(this).data('dna'); if (typeof CCPEVE !== 'undefined') { // inside IGB - $(this).attr('href', 'javascript:CCPEVE.showFitting("'+dna+'");');} + $(this).attr('href', 'javascript:CCPEVE.showFitting("'+dna+'");');} else { // outside IGB $(this).attr('href', '%s'+dna); } }); @@ -193,8 +192,8 @@ class exportHtmlThread(threading.Thread): fit = fits[0] try: dnaFit = sFit.exportDna(fit[0]) - HTMLgroup += ( - '
  • ' + ship.name + ": " + fit[1] + '
  • \n') + HTMLgroup += '
  • ' + ship.name + ": " + \ + fit[1] + '
  • \n' except: pass finally: @@ -204,16 +203,19 @@ class exportHtmlThread(threading.Thread): else: # Ship group header HTMLship = ( - '
  • \n' - '

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

    \n' - '
      \n') + '
    • \n' + '

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

      \n' + '
        \n' + ) for fit in fits: if self.stopRunning: return try: dnaFit = sFit.exportDna(fit[0]) - HTMLship += '
      • ' + fit[1] + '
      • \n' + HTMLship += '
      • ' + fit[ + 1] + '
      • \n' except: continue finally: @@ -226,12 +228,12 @@ class exportHtmlThread(threading.Thread): if groupFits > 0: # Market group header HTML += ( - '
      • \n' - '

        ' + group.groupName + ' '+str(groupFits)+'

        \n' - '
          \n' - + HTMLgroup + - '
        \n' - '
      • ') + '
      • \n' + '

        ' + group.groupName + ' ' + str(groupFits) + '

        \n' + '
          \n' + HTMLgroup + + '
        \n' + '
      • ' + ) HTML += """
      @@ -242,7 +244,7 @@ class exportHtmlThread(threading.Thread): return HTML - def generateMinimalHTML(self,sMkt,sFit,dnaUrl): + def generateMinimalHTML(self, sMkt, sFit, dnaUrl): """ Generate a minimal HTML version of the fittings, without any javascript or styling""" categoryList = list(sMkt.getShipRoot()) categoryList.sort(key=lambda ship: ship.name) @@ -251,7 +253,6 @@ class exportHtmlThread(threading.Thread): HTML = '' for group in categoryList: # init market group string to give ships something to attach to - ships = list(sMkt.getShipList(group.ID)) ships.sort(key=lambda ship: ship.name) @@ -264,8 +265,9 @@ class exportHtmlThread(threading.Thread): if self.stopRunning: return try: - dnaFit = sFit.exportDna(fit[0]) - HTML += ''+ship.name +': '+ fit[1]+ '
      \n' + dnaFit = sFit.exportDna(fit[0]) + HTML += '' + ship.name + ': ' + \ + fit[1] + '
      \n' except: continue finally: diff --git a/gui/utils/numberFormatter.py b/gui/utils/numberFormatter.py index 8b64d6147..cd8140dce 100644 --- a/gui/utils/numberFormatter.py +++ b/gui/utils/numberFormatter.py @@ -1,5 +1,6 @@ import math + def formatAmount(val, prec=3, lowest=0, highest=0, currency=False, forceSign=False): """ Add suffix to value, transform value to match new suffix and round it. @@ -33,8 +34,8 @@ def formatAmount(val, prec=3, lowest=0, highest=0, currency=False, forceSign=Fal # Start from highest possible suffix for key in posOrders: # Find first suitable suffix and check if it's not above highest order - if abs(val) >= 10**key and key <= highest: - mantissa, suffix = val/float(10**key), posSuffixMap[key] + if abs(val) >= 10 ** key and key <= highest: + mantissa, suffix = val / float(10 ** key), posSuffixMap[key] # Do additional step to eliminate results like 999999 => 1000k # If we're already using our greatest order, we can't do anything useful if posOrders.index(key) == 0: @@ -48,12 +49,12 @@ def formatAmount(val, prec=3, lowest=0, highest=0, currency=False, forceSign=Fal # If it is, bail - we already have acceptable results break # Find multiplier to get from one order to another - orderDiff = 10**(prevKey - key) + orderDiff = 10 ** (prevKey - key) # If rounded mantissa according to our specifications is greater than # or equal to multiplier if roundToPrec(mantissa, prec) >= orderDiff: # Divide mantissa and use suffix of greater order - mantissa, suffix = mantissa/orderDiff, posSuffixMap[prevKey] + mantissa, suffix = mantissa / orderDiff, posSuffixMap[prevKey] # Otherwise consider current results as acceptable break # Take numbers between 0 and 1, and matching/below highest possible negative suffix @@ -66,8 +67,8 @@ def formatAmount(val, prec=3, lowest=0, highest=0, currency=False, forceSign=Fal except IndexError: nextKey = 0 # Check if mantissa with next suffix is in range [1, 1000) - if abs(val) < 10**(nextKey) and key >= lowest: - mantissa, suffix = val/float(10**key), negSuffixMap[key] + if abs(val) < 10 ** (nextKey) and key >= lowest: + mantissa, suffix = val / float(10 ** key), negSuffixMap[key] # Do additional step to eliminate results like 0.9999 => 1000m # Check if the key we're potentially switching to is greater than our # upper boundary @@ -75,13 +76,13 @@ def formatAmount(val, prec=3, lowest=0, highest=0, currency=False, forceSign=Fal # If it is, leave loop with results we already have break # Find the multiplier between current and next order - orderDiff = 10**(nextKey - key) + orderDiff = 10 ** (nextKey - key) # If rounded mantissa according to our specifications is greater than # or equal to multiplier if roundToPrec(mantissa, prec) >= orderDiff: # Divide mantissa and use suffix of greater order # Use special handling of zero key as it's not on the map - mantissa, suffix = mantissa/orderDiff, posSuffixMap[nextKey] if nextKey != 0 else "" + mantissa, suffix = mantissa / orderDiff, posSuffixMap[nextKey] if nextKey != 0 else "" # Otherwise consider current results as acceptable break # Round mantissa according to our prec variable @@ -91,6 +92,7 @@ def formatAmount(val, prec=3, lowest=0, highest=0, currency=False, forceSign=Fal result = u"{0}{1}{2}".format(sign, mantissa, suffix) return result + def roundToPrec(val, prec): # We're not rounding integers anyway # Also make sure that we do not ask to calculate logarithm of zero diff --git a/gui/viewColumn.py b/gui/viewColumn.py index c2ffff612..9afca36e7 100644 --- a/gui/viewColumn.py +++ b/gui/viewColumn.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,10 +15,11 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import wx + class ViewColumn(object): ''' Abstract class that columns can inherit from. @@ -26,6 +27,7 @@ class ViewColumn(object): they can be used as columns in a view. ''' columns = {} + def __init__(self, fittingView): self.fittingView = fittingView self.columnText = "" @@ -62,4 +64,5 @@ class ViewColumn(object): def delayedText(self, display, colItem): raise NotImplementedError() -from gui.builtinViewColumns import * + +from gui.builtinViewColumns import * # noqa diff --git a/pyfa.py b/pyfa.py index 146ea704d..e465b0d5a 100755 --- a/pyfa.py +++ b/pyfa.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -#=============================================================================== +# ============================================================================== # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -16,7 +16,7 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================== import sys import re @@ -24,6 +24,7 @@ import config from optparse import OptionParser, BadOptionError, AmbiguousOptionError + class PassThroughOptionParser(OptionParser): """ An unknown option pass-through implementation of OptionParser. @@ -33,10 +34,11 @@ class PassThroughOptionParser(OptionParser): def _process_args(self, largs, rargs, values): while rargs: try: - OptionParser._process_args(self,largs,rargs,values) - except (BadOptionError,AmbiguousOptionError), e: + OptionParser._process_args(self, largs, rargs, values) + except (BadOptionError, AmbiguousOptionError) as e: largs.append(e.opt_str) + # Parse command line options usage = "usage: %prog [--root]" parser = PassThroughOptionParser(usage=usage) @@ -50,7 +52,7 @@ parser.add_option("-s", "--savepath", action="store", dest="savepath", help="Set if not hasattr(sys, 'frozen'): - if sys.version_info < (2,6) or sys.version_info > (3,0): + if sys.version_info < (2, 6) or sys.version_info > (3, 0): print("Pyfa requires python 2.x branch ( >= 2.6 )\nExiting.") sys.exit(1) @@ -66,13 +68,13 @@ if not hasattr(sys, 'frozen'): else: wxversion.select(['3.0', '2.8']) except wxversion.VersionError: - print "Installed wxPython version doesn't meet requirements.\nYou can download wxPython 2.8 or 3.0 from http://www.wxpython.org/" + print("Installed wxPython version doesn't meet requirements.\nYou can download wxPython 2.8 or 3.0 from http://www.wxpython.org/") sys.exit(1) try: import sqlalchemy - saVersion = sqlalchemy.__version__ + saVersion = sqlalchemy.__version__ saMatch = re.match("([0-9]+).([0-9]+)([b\.])([0-9]+)", saVersion) if saMatch: saMajor = int(saMatch.group(1)) @@ -88,10 +90,10 @@ if not hasattr(sys, 'frozen'): except ImportError: print("Cannot find sqlalchemy.\nYou can download sqlalchemy (0.6+) from http://www.sqlalchemy.org/") sys.exit(1) - + # check also for dateutil module installed. try: - import dateutil.parser # Copied import statement from service/update.py + import dateutil.parser # noqa - Copied import statement from service/update.py except ImportError: print("Cannot find python-dateutil.\nYou can download python-dateutil from https://pypi.python.org/pypi/python-dateutil") sys.exit(1) @@ -101,10 +103,10 @@ if __name__ == "__main__": # Configure paths if options.rootsavedata is True: config.saveInRoot = True - + # set title if it wasn't supplied by argument - if options.title == None: - options.title = "pyfa %s%s - Python Fitting Assistant"%(config.version, "" if config.tag.lower() != 'git' else " (git)") + if options.title is None: + options.title = "pyfa %s%s - Python Fitting Assistant" % (config.version, "" if config.tag.lower() != 'git' else " (git)") config.debug = options.debug # convert to unicode if it is set @@ -125,7 +127,7 @@ if __name__ == "__main__": import service.prefetch from gui.mainFrame import MainFrame - #Make sure the saveddata db exists + # Make sure the saveddata db exists if not os.path.exists(config.savePath): os.mkdir(config.savePath) diff --git a/requirements.txt b/requirements.txt index f8e777507..2d8894113 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,4 @@ PyYAML python-dateutil urllib3 requests==2.11.1 -sqlalchemy +sqlalchemy>=1.0.5 diff --git a/scripts/jsonToSql.py b/scripts/jsonToSql.py index 1f431f3d8..173fc59f3 100755 --- a/scripts/jsonToSql.py +++ b/scripts/jsonToSql.py @@ -47,6 +47,7 @@ def main(db, json_path): # Config dict tables = { + "clonegrades": eos.gamedata.AlphaCloneSkill, "dgmattribs": eos.gamedata.AttributeInfo, "dgmeffects": eos.gamedata.EffectInfo, "dgmtypeattribs": eos.gamedata.Attribute, @@ -60,7 +61,8 @@ def main(db, json_path): "evetypes": eos.gamedata.Item, "phbtraits": eos.gamedata.Traits, "phbmetadata": eos.gamedata.MetaData, - "mapbulk_marketGroups": eos.gamedata.MarketGroup + "mapbulk_marketGroups": eos.gamedata.MarketGroup, + } fieldMapping = { @@ -109,6 +111,19 @@ def main(db, json_path): new.append(v) return new + def convertClones(data): + newData = [] + + for ID in data: + for skill in data[ID]["skills"]: + newData.append({ + "alphaCloneID": int(ID), + "alphaCloneName": data[ID]["internalDescription"], + "typeID": skill["typeID"], + "level": skill["level"]}) + + return newData + def convertTraits(data): def convertSection(sectionData): @@ -167,6 +182,8 @@ def main(db, json_path): tableData = convertTraits(tableData) if jsonName == "evetypes": tableData = convertTypes(tableData) + if jsonName == "clonegrades": + tableData = convertClones(tableData) data[jsonName] = tableData # Set with typeIDs which we will have in our database @@ -191,7 +208,10 @@ def main(db, json_path): # Loop through each json file and write it away, checking ignored rows for jsonName, table in data.iteritems(): fieldMap = fieldMapping.get(jsonName, {}) + tmp = [] + print "processing {}".format(jsonName) + for row in table: # We don't care about some kind of rows, filter it out if so if not isIgnored(jsonName, row): @@ -207,6 +227,14 @@ def main(db, json_path): if jsonName is "icons" and "modules/" in str(row["iconFile"]).lower(): row["iconFile"] = row["iconFile"].lower().replace("modules/", "").replace(".png", "") + if jsonName is "clonegrades": + if (row["alphaCloneID"] not in tmp): + cloneParent = eos.gamedata.AlphaClone() + setattr(cloneParent, "alphaCloneID", row["alphaCloneID"]) + setattr(cloneParent, "alphaCloneName", row["alphaCloneName"]) + eos.db.gamedata_session.add(cloneParent) + tmp.append(row['alphaCloneID']) + for k, v in row.iteritems(): if (isinstance(v, basestring)): v = v.strip() diff --git a/scripts/prep_data.py b/scripts/prep_data.py index 5df4d715f..7de1cfdc3 100644 --- a/scripts/prep_data.py +++ b/scripts/prep_data.py @@ -80,7 +80,7 @@ if not args.nojson: list = "dgmexpressions,dgmattribs,dgmeffects,dgmtypeattribs,dgmtypeeffects,"\ "dgmunits,invcategories,invgroups,invmetagroups,invmetatypes,"\ "invtypes,mapbulk_marketGroups,phbmetadata,phbtraits,fsdTypeOverrides,"\ - "evegroups,evetypes,evecategories,mapbulk_marketGroups" + "evegroups,evetypes,evecategories,mapbulk_marketGroups,clonegrades" FlowManager(miners, writers).run(list, "en-us") diff --git a/service/__init__.py b/service/__init__.py index 91ed07d82..e69de29bb 100644 --- a/service/__init__.py +++ b/service/__init__.py @@ -1,18 +0,0 @@ -from service.market import Market -from service.fit import Fit -from service.attribute import Attribute -from service.character import Character -from service.damagePattern import DamagePattern -from service.targetResists import TargetResists -from service.settings import SettingsProvider -from service.update import Update -from service.price import Price -from service.network import Network -from service.eveapi import EVEAPIConnection, ParseXML -from service.implantSet import ImplantSets - -import wx -if not 'wxMac' in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3,0)): - from service.pycrest import EVE - from service.server import StoppableHTTPServer, AuthHandler - from service.crest import Crest diff --git a/service/attribute.py b/service/attribute.py index b6a9ea500..ee4f43328 100644 --- a/service/attribute.py +++ b/service/attribute.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,12 +15,14 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import eos.db + class Attribute(): instance = None + @classmethod def getInstance(cls): if cls.instance is None: @@ -32,6 +34,8 @@ class Attribute(): if isinstance(identity, (int, basestring)): info = eos.db.getAttributeInfo(identity, eager=("icon", "unit")) elif isinstance(identity, (int, float)): - id = int(identity) - info = eos.db.getAttributeInfo(id, eager=("icon", "unit")) + id_ = int(identity) + info = eos.db.getAttributeInfo(id_, eager=("icon", "unit")) + else: + info = None return info diff --git a/service/character.py b/service/character.py index e69ff2f16..33cd4c765 100644 --- a/service/character.py +++ b/service/character.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,11 +15,12 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import copy import itertools import json +import logging import threading from codecs import open from xml.etree import ElementTree @@ -28,16 +29,18 @@ import gzip import wx -import eos.db -import eos.types -import service import config -import logging +import eos.db +from service.eveapi import EVEAPIConnection, ParseXML +from eos.saveddata.implant import Implant as es_Implant from eos.saveddata.character import Character as es_Character +from eos.saveddata.module import Slot as es_Slot, Module as es_Module +from eos.saveddata.fighter import Fighter as es_Fighter logger = logging.getLogger(__name__) + class CharacterImportThread(threading.Thread): def __init__(self, paths, callback): threading.Thread.__init__(self) @@ -58,8 +61,8 @@ class CharacterImportThread(threading.Thread): try: # we try to parse api XML data first with open(path, mode='r') as charFile: - sheet = service.ParseXML(charFile) - char = sCharacter.new(sheet.name+" (imported)") + sheet = ParseXML(charFile) + char = sCharacter.new(sheet.name + " (imported)") sCharacter.apiUpdateCharSheet(char.ID, sheet.skills) except: # if it's not api XML data, try this @@ -94,6 +97,7 @@ class CharacterImportThread(threading.Thread): wx.CallAfter(self.callback) + class SkillBackupThread(threading.Thread): def __init__(self, path, saveFmt, activeFit, callback): threading.Thread.__init__(self) @@ -106,9 +110,6 @@ class SkillBackupThread(threading.Thread): def run(self): path = self.path sCharacter = Character.getInstance() - sFit = service.Fit.getInstance() - fit = sFit.getFit(self.activeFit) - backupData = "" if self.saveFmt == "xml" or self.saveFmt == "emp": backupData = sCharacter.exportXml() else: @@ -118,11 +119,12 @@ class SkillBackupThread(threading.Thread): with gzip.open(path, mode='wb') as backupFile: backupFile.write(backupData) else: - with open(path, mode='w',encoding='utf-8') as backupFile: + with open(path, mode='w', encoding='utf-8') as backupFile: backupFile.write(backupData) wx.CallAfter(self.callback) + class Character(object): instance = None skillReqsDict = {} @@ -140,7 +142,7 @@ class Character(object): self.all5() def exportText(self): - data = "Pyfa exported plan for \""+self.skillReqsDict['charname']+"\"\n" + data = "Pyfa exported plan for \"" + self.skillReqsDict['charname'] + "\"\n" data += "=" * 79 + "\n" data += "\n" item = "" @@ -156,7 +158,7 @@ class Character(object): def exportXml(self): root = ElementTree.Element("plan") - root.attrib["name"] = "Pyfa exported plan for "+self.skillReqsDict['charname'] + root.attrib["name"] = "Pyfa exported plan for " + self.skillReqsDict['charname'] root.attrib["revision"] = config.evemonMinVersion sorts = ElementTree.SubElement(root, "sorting") @@ -167,9 +169,9 @@ class Character(object): skillsSeen = set() for s in self.skillReqsDict['skills']: - skillKey = str(s["skillID"])+"::"+s["skill"]+"::"+str(int(s["level"])) + skillKey = str(s["skillID"]) + "::" + s["skill"] + "::" + str(int(s["level"])) if skillKey in skillsSeen: - pass # Duplicate skills confuse EVEMon + pass # Duplicate skills confuse EVEMon else: skillsSeen.add(skillKey) entry = ElementTree.SubElement(root, "entry") @@ -181,7 +183,7 @@ class Character(object): notes = ElementTree.SubElement(entry, "notes") notes.text = entry.attrib["skill"] - tree = ElementTree.ElementTree(root) + # tree = ElementTree.ElementTree(root) data = ElementTree.tostring(root, 'utf-8') prettydata = minidom.parseString(data).toprettyxml(indent=" ") @@ -196,17 +198,20 @@ class Character(object): thread.start() def all0(self): - return eos.types.Character.getAll0() + return es_Character.getAll0() def all0ID(self): return self.all0().ID def all5(self): - return eos.types.Character.getAll5() + return es_Character.getAll5() def all5ID(self): return self.all5().ID + def getAlphaCloneList(self): + return eos.db.getAlphaCloneList() + def getCharacterList(self): return eos.db.getCharacterList() @@ -248,10 +253,14 @@ class Character(object): group = eos.db.getGroup(groupID) skills = [] for skill in group.items: - if skill.published == True: + if skill.published is True: skills.append((skill.ID, skill.name)) return skills + def setAlphaClone(self, char, cloneID): + char.alphaCloneID = cloneID + eos.db.commit() + def getSkillDescription(self, itemID): return eos.db.getItem(itemID).description @@ -269,7 +278,7 @@ class Character(object): return eos.db.getCharacter(charID).name def new(self, name="New Character"): - char = eos.types.Character(name) + char = es_Character(name) eos.db.save(char) return char @@ -297,8 +306,8 @@ class Character(object): return (char.apiID or "", char.apiKey or "", char.defaultChar or "", chars or []) def apiEnabled(self, charID): - id, key, default, _ = self.getApiDetails(charID) - return id is not "" and key is not "" and default is not "" + id_, key, default, _ = self.getApiDetails(charID) + return id_ is not "" and key is not "" and default is not "" def apiCharList(self, charID, userID, apiKey): char = eos.db.getCharacter(charID) @@ -306,7 +315,7 @@ class Character(object): char.apiID = userID char.apiKey = apiKey - api = service.EVEAPIConnection() + api = EVEAPIConnection() auth = api.auth(keyID=userID, vCode=apiKey) apiResult = auth.account.Characters() charList = map(lambda c: unicode(c.name), apiResult.characters) @@ -318,7 +327,7 @@ class Character(object): dbChar = eos.db.getCharacter(charID) dbChar.defaultChar = charName - api = service.EVEAPIConnection() + api = EVEAPIConnection() auth = api.auth(keyID=dbChar.apiID, vCode=dbChar.apiKey) apiResult = auth.account.Characters() charID = None @@ -326,7 +335,7 @@ class Character(object): if char.name == charName: charID = char.characterID - if charID == None: + if charID is None: return sheet = auth.character(charID).CharacterSheet() @@ -368,7 +377,7 @@ class Character(object): logger.error("Trying to add implant to read-only character") return - implant = eos.types.Implant(eos.db.getItem(itemID)) + implant = es_Implant(eos.db.getItem(itemID)) char.implants.append(implant) eos.db.commit() @@ -382,20 +391,20 @@ class Character(object): return char.implants def checkRequirements(self, fit): - toCheck = [] + # toCheck = [] reqs = {} for thing in itertools.chain(fit.modules, fit.drones, fit.fighters, (fit.ship,)): - if isinstance(thing, eos.types.Module) and thing.slot == eos.types.Slot.RIG: + if isinstance(thing, es_Module) and thing.slot == es_Slot.RIG: continue for attr in ("item", "charge"): - if attr == "charge" and isinstance(thing, eos.types.Fighter): + if attr == "charge" and isinstance(thing, es_Fighter): # Fighter Bombers are automatically charged with micro bombs. # These have skill requirements attached, but aren't used in EVE. continue subThing = getattr(thing, attr, None) subReqs = {} if subThing is not None: - if isinstance(thing, eos.types.Fighter) and attr == "charge": + if isinstance(thing, es_Fighter) and attr == "charge": continue self._checkRequirements(fit, fit.character, subThing, subReqs) if subReqs: diff --git a/service/conversions/releaseApril2016.py b/service/conversions/releaseApril2016.py index a20914179..bd14944ee 100644 --- a/service/conversions/releaseApril2016.py +++ b/service/conversions/releaseApril2016.py @@ -42,4 +42,4 @@ CONVERSIONS = { "Unit W-634's Modified Drone Control Unit": "Unit W-634's Modified Fighter Support Unit", "Heavy Shadow Serpentis Stasis Grappler": "Shadow Serpentis Heavy Stasis Grappler", "Heavy Domination Stasis Grappler": "Domination Heavy Stasis Grappler", -} \ No newline at end of file +} diff --git a/service/conversions/releaseDecember15.py b/service/conversions/releaseDecember15.py index adcd9e552..456dedb59 100644 --- a/service/conversions/releaseDecember15.py +++ b/service/conversions/releaseDecember15.py @@ -96,4 +96,4 @@ CONVERSIONS = { "Micro S95a Remote Shield Booster": "'Micro' Remote Shield Booster", "Large 'Atonement' Remote Shield Booster": "Large Murky Compact Remote Shield Booster", "E50 Prototype Energy Vampire": "Medium Knave Scoped Energy Nosferatu", -} \ No newline at end of file +} diff --git a/service/conversions/releaseFeb2016.py b/service/conversions/releaseFeb2016.py index 4314ef173..9b2e8d838 100644 --- a/service/conversions/releaseFeb2016.py +++ b/service/conversions/releaseFeb2016.py @@ -7,4 +7,3 @@ CONVERSIONS = { "Capital Coaxial Remote Armor Repairer Blueprint": "CONCORD Capital Remote Armor Repairer Blueprint", "Capital Murky Remote Shield Booster Blueprint": "CONCORD Capital Remote Shield Booster Blueprint", } - diff --git a/service/conversions/releaseJan2016.py b/service/conversions/releaseJan2016.py index e5f9beba3..eb0763d6b 100644 --- a/service/conversions/releaseJan2016.py +++ b/service/conversions/releaseJan2016.py @@ -10,4 +10,4 @@ CONVERSIONS = { "'Distributor' Guidance Disruptor I Blueprint": "'Distributor' Guidance Disruptor Blueprint", "Highstroke Scoped Guidance Disruptor I": "Highstroke Scoped Guidance Disruptor", "A-211 Enduring Guidance Disruptor I": "A-211 Enduring Guidance Disruptor", -} \ No newline at end of file +} diff --git a/service/conversions/releaseMar2016.py b/service/conversions/releaseMar2016.py index 2af04e1af..65e26adb1 100644 --- a/service/conversions/releaseMar2016.py +++ b/service/conversions/releaseMar2016.py @@ -118,7 +118,6 @@ CONVERSIONS = { "'Full Duplex' Ballistic Targeting System": "'Full Duplex' Ballistic Control System", "'Kindred' Stabilization Actuator I": "'Kindred' Gyrostabilizer", "Process-Interruptive Warp Disruptor": "'Interruptive' Warp Disruptor", - "Multi Sensor Firewall": "'Firewall' Signal Amplifier", "'Inception' Target Painter I": "'Inception' Target Painter", "Citadel Torpedoes": "XL Torpedoes", "'Shady' ECCM - Gravimetric I": "'Shady' Sensor Booster", @@ -358,4 +357,4 @@ CONVERSIONS = { "Wavelength Signal Enhancer I": "F-89 Compact Signal Amplifier", "Type-D Attenuation Signal Augmentation": "F-89 Compact Signal Amplifier", "Indirect Scanning Dampening Unit I": "Phased Muon Scoped Sensor Dampener", -} \ No newline at end of file +} diff --git a/service/crest.py b/service/crest.py index b2771242b..74c74d311 100644 --- a/service/crest.py +++ b/service/crest.py @@ -9,23 +9,25 @@ import time import eos.db from eos.enum import Enum from eos.types import CrestChar - -import service - import gui.globalEvents as GE +from service.settings import CRESTSettings +from service.server import StoppableHTTPServer, AuthHandler +from service.pycrest.eve import EVE logger = logging.getLogger(__name__) + class Servers(Enum): TQ = 0 SISI = 1 + class CrestModes(Enum): IMPLICIT = 0 USER = 1 -class Crest(): +class Crest(): clientIDs = { Servers.TQ: 'f9be379951c046339dc13a00e6be7704', Servers.SISI: 'af87365240d644f7950af563b8418bad' @@ -36,9 +38,10 @@ class Crest(): clientTest = True _instance = None + @classmethod def getInstance(cls): - if cls._instance == None: + if cls._instance is None: cls._instance = Crest() return cls._instance @@ -64,7 +67,7 @@ class Crest(): characters still in the cache (if USER mode) """ - self.settings = service.settings.CRESTSettings.getInstance() + self.settings = CRESTSettings.getInstance() self.scopes = ['characterFittingsRead', 'characterFittingsWrite'] # these will be set when needed @@ -73,8 +76,9 @@ class Crest(): self.ssoTimer = None # Base EVE connection that is copied to all characters - self.eve = service.pycrest.EVE( - client_id=self.settings.get('clientID') if self.settings.get('mode') == CrestModes.USER else self.clientIDs.get(self.settings.get('server')), + self.eve = EVE( + client_id=self.settings.get('clientID') if self.settings.get( + 'mode') == CrestModes.USER else self.clientIDs.get(self.settings.get('server')), api_key=self.settings.get('clientSecret') if self.settings.get('mode') == CrestModes.USER else None, redirect_uri=self.clientCallback, testing=self.isTestServer @@ -114,9 +118,9 @@ class Crest(): return chars2 def getCrestCharacter(self, charID): - ''' + """ Get character, and modify to include the eve connection - ''' + """ if self.settings.get('mode') == CrestModes.IMPLICIT: if self.implicitCharacter.ID != charID: raise ValueError("CharacterID does not match currently logged in character.") @@ -134,16 +138,17 @@ class Crest(): def getFittings(self, charID): char = self.getCrestCharacter(charID) - return char.eve.get('%scharacters/%d/fittings/'%(char.eve._authed_endpoint,char.ID)) + return char.eve.get('%scharacters/%d/fittings/' % (char.eve._authed_endpoint, char.ID)) def postFitting(self, charID, json): - #@todo: new fitting ID can be recovered from Location header, ie: Location -> https://api-sisi.testeveonline.com/characters/1611853631/fittings/37486494/ + # @todo: new fitting ID can be recovered from Location header, + # ie: Location -> https://api-sisi.testeveonline.com/characters/1611853631/fittings/37486494/ char = self.getCrestCharacter(charID) - return char.eve.post('%scharacters/%d/fittings/'%(char.eve._authed_endpoint,char.ID), data=json) + return char.eve.post('%scharacters/%d/fittings/' % (char.eve._authed_endpoint, char.ID), data=json) def delFitting(self, charID, fittingID): char = self.getCrestCharacter(charID) - return char.eve.delete('%scharacters/%d/fittings/%d/'%(char.eve._authed_endpoint, char.ID, fittingID)) + return char.eve.delete('%scharacters/%d/fittings/%d/' % (char.eve._authed_endpoint, char.ID, fittingID)) def logout(self): """Logout of implicit character""" @@ -160,8 +165,9 @@ class Crest(): logging.debug("Starting server") if self.httpd: self.stopServer() - time.sleep(1) # we need this to ensure that the previous get_request finishes, and then the socket will close - self.httpd = service.StoppableHTTPServer(('', 6461), service.AuthHandler) + time.sleep(1) + # we need this to ensure that the previous get_request finishes, and then the socket will close + self.httpd = StoppableHTTPServer(('', 6461), AuthHandler) thread.start_new_thread(self.httpd.serve, (self.handleLogin,)) self.state = str(uuid.uuid4()) @@ -175,7 +181,7 @@ class Crest(): logger.warn("OAUTH state mismatch") return - logger.debug("Handling CREST login with: %s"%message) + logger.debug("Handling CREST login with: %s" % message) if 'access_token' in message: # implicit eve = copy.deepcopy(self.eve) @@ -193,7 +199,7 @@ class Crest(): self.implicitCharacter = CrestChar(info['CharacterID'], info['CharacterName']) self.implicitCharacter.eve = eve - #self.implicitCharacter.fetchImage() + # self.implicitCharacter.fetchImage() wx.PostEvent(self.mainFrame, GE.SsoLogin(type=CrestModes.IMPLICIT)) elif 'code' in message: diff --git a/service/damagePattern.py b/service/damagePattern.py index f617fa846..2343693d3 100644 --- a/service/damagePattern.py +++ b/service/damagePattern.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,19 +15,21 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= -import eos.db -import eos.types import copy -from eos.db.saveddata.loadDefaultDatabaseValues import DefaultDatabaseValues +import eos.db +from eos.saveddata.damagePattern import DamagePattern as es_DamagePattern + class ImportError(Exception): pass + class DamagePattern(): instance = None + @classmethod def getInstance(cls): if cls.instance is None: @@ -42,7 +44,7 @@ class DamagePattern(): return eos.db.getDamagePattern(name) def newPattern(self, name): - p = eos.types.DamagePattern(0, 0, 0, 0) + p = es_DamagePattern(0, 0, 0, 0) p.name = name eos.db.save(p) return p @@ -68,7 +70,7 @@ class DamagePattern(): for pattern in current: lookup[pattern.name] = pattern - imports, num = eos.types.DamagePattern.importPatterns(text) + imports, num = es_DamagePattern.importPatterns(text) for pattern in imports: if pattern.name in lookup: match = lookup[pattern.name] @@ -81,7 +83,7 @@ class DamagePattern(): if lenImports == 0: raise ImportError("No patterns found for import") if lenImports != num: - raise ImportError("%d patterns imported from clipboard; %d had errors"%(num, num-lenImports)) + raise ImportError("%d patterns imported from clipboard; %d had errors" % (num, num - lenImports)) def exportPatterns(self): patterns = self.getDamagePatternList() @@ -90,4 +92,4 @@ class DamagePattern(): del patterns[i] patterns.sort(key=lambda p: p.name) - return eos.types.DamagePattern.exportPatterns(*patterns) + return es_DamagePattern.exportPatterns(*patterns) diff --git a/service/eveapi.py b/service/eveapi.py index 4b19340b0..67a238f47 100644 --- a/service/eveapi.py +++ b/service/eveapi.py @@ -1,4 +1,4 @@ -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- # eveapi - EVE Online API access # # Copyright (c)2007-2014 Jamie "Entity" van den Berge @@ -24,7 +24,7 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE # -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- # # Version: 1.3.0 - 27 May 2014 # - Added set_user_agent() module-level function to set the User-Agent header @@ -145,10 +145,10 @@ # Requirements: # Python 2.4+ # -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- # This eveapi has been modified for pyfa. # # Specifically, the entire network request/response has been substituted for @@ -156,7 +156,7 @@ # # Additionally, various other parts have been changed to support urllib2 # responses instead of httplib -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- import urlparse @@ -166,7 +166,7 @@ from xml.parsers import expat from time import strptime from calendar import timegm -import service +from service.network import Network proxy = None proxySSL = False @@ -174,7 +174,9 @@ proxySSL = False _default_useragent = "eveapi.py/1.3" _useragent = None # use set_user_agent() to set this. -#----------------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- + def set_cast_func(func): """Sets an alternative value casting function for the XML parser. @@ -185,25 +187,30 @@ def set_cast_func(func): global _castfunc _castfunc = _autocast if func is None else func + def set_user_agent(user_agent_string): """Sets a User-Agent for any requests sent by the library.""" global _useragent _useragent = user_agent_string -class Error(StandardError): +class Error(Exception): def __init__(self, code, message): self.code = code self.args = (message.rstrip("."),) + def __unicode__(self): return u'%s [code=%s]' % (self.args[0], self.code) + class RequestError(Error): pass + class AuthenticationError(Error): pass + class ServerError(Error): pass @@ -304,18 +311,16 @@ def _ParseXML(response, fromContext, storeFunc): return result - - - -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- # API Classes -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- + _listtypes = (list, tuple, dict) _unspecified = [] -class _Context(object): +class _Context(object): def __init__(self, root, path, parentDict, newKeywords=None): self._root = root or self self._path = path @@ -356,20 +361,18 @@ class _Context(object): class _AuthContext(_Context): - def character(self, characterID): # returns a copy of this connection object but for every call made # through it, it will add the folder "/char" to the url, and the # characterID to the parameters passed. - return _Context(self._root, self._path + "/char", self.parameters, {"characterID":characterID}) + return _Context(self._root, self._path + "/char", self.parameters, {"characterID": characterID}) def corporation(self, characterID): # same as character except for the folder "/corp" - return _Context(self._root, self._path + "/corp", self.parameters, {"characterID":characterID}) + return _Context(self._root, self._path + "/corp", self.parameters, {"characterID": characterID}) class _RootContext(_Context): - def auth(self, **kw): if len(kw) == 2 and (("keyID" in kw and "vCode" in kw) or ("userID" in kw and "apiKey" in kw)): return _AuthContext(self._root, self._path, self.parameters, kw) @@ -395,9 +398,9 @@ class _RootContext(_Context): response = None if response is None: - network = service.Network.getInstance() + network = Network.getInstance() - req = self._scheme+'://'+self._host+path + req = self._scheme + '://' + self._host + path response = network.request(req, network.EVE, kw) @@ -413,8 +416,9 @@ class _RootContext(_Context): if retrieve_fallback: # implementor is handling fallbacks... try: - return _ParseXML(response, True, store and (lambda obj: cache.store(self._host, path, kw, response, obj))) - except Error, e: + return _ParseXML(response, True, + store and (lambda obj: cache.store(self._host, path, kw, response, obj))) + except Error as e: response = retrieve_fallback(self._host, path, kw, reason=e) if response is not None: return response @@ -423,9 +427,11 @@ class _RootContext(_Context): # implementor is not handling fallbacks... return _ParseXML(response, True, store and (lambda obj: cache.store(self._host, path, kw, response, obj))) -#----------------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- # XML Parser -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- + def _autocast(key, value): # attempts to cast an XML string to the most probable type. @@ -452,11 +458,11 @@ def _autocast(key, value): # couldn't cast. return string unchanged. return value + _castfunc = _autocast class _Parser(object): - def Parse(self, data, isStream=False): self.container = self.root = None self._cdata = False @@ -475,7 +481,6 @@ class _Parser(object): p.Parse(data, True) return self.root - def tag_cdatasection_enter(self): # encountered an explicit CDATA tag. self._cdata = True @@ -501,21 +506,20 @@ class _Parser(object): if name == "rowset": # for rowsets, use the given name try: - columns = attributes[attributes.index('columns')+1].replace(" ", "").split(",") + columns = attributes[attributes.index('columns') + 1].replace(" ", "").split(",") except ValueError: # rowset did not have columns tag set (this is a bug in API) # columns will be extracted from first row instead. columns = [] try: - priKey = attributes[attributes.index('key')+1] + priKey = attributes[attributes.index('key') + 1] this = IndexRowset(cols=columns, key=priKey) except ValueError: this = Rowset(cols=columns) - - this._name = attributes[attributes.index('name')+1] - this.__catch = "row" # tag to auto-add to rowset. + this._name = attributes[attributes.index('name') + 1] + this.__catch = "row" # tag to auto-add to rowset. else: this = Element() this._name = name @@ -528,7 +532,7 @@ class _Parser(object): if name != "eveapi": raise RuntimeError("Invalid API response") try: - this.version = attributes[attributes.index("version")+1] + this.version = attributes[attributes.index("version") + 1] except KeyError: raise RuntimeError("Invalid API response") self.root = this @@ -541,16 +545,18 @@ class _Parser(object): # such as rawQuantity in the assets lists. # In either case the tag is assumed to be correct and the rowset's # columns are overwritten with the tag's version, if required. - numAttr = len(attributes)/2 + numAttr = len(attributes) / 2 numCols = len(self.container._cols) if numAttr < numCols and (attributes[-2] == self.container._cols[-1]): # the row data is missing attributes that were defined in the rowset. # missing attributes' values will be set to None. fixed = [] - row_idx = 0; hdr_idx = 0; numAttr*=2 + row_idx = 0 + hdr_idx = 0 + numAttr *= 2 for col in self.container._cols: if col == attributes[row_idx]: - fixed.append(_castfunc(col, attributes[row_idx+1])) + fixed.append(_castfunc(col, attributes[row_idx + 1])) row_idx += 2 else: fixed.append(None) @@ -560,7 +566,9 @@ class _Parser(object): if not self.container._cols or (numAttr > numCols): # the row data contains more attributes than were defined. self.container._cols = attributes[0::2] - self.container.append([_castfunc(attributes[i], attributes[i+1]) for i in xrange(0, len(attributes), 2)]) + self.container.append( + [_castfunc(attributes[i], attributes[i + 1]) for i in xrange(0, len(attributes), 2)] + ) # this._isrow = True @@ -611,7 +619,7 @@ class _Parser(object): if this is self.root: del this._attributes - #this.__dict__.pop("_attributes", None) + # this.__dict__.pop("_attributes", None) return # we're done with current tag, so we can pop it off. This means that @@ -651,7 +659,7 @@ class _Parser(object): e._name = this._name setattr(self.container, this._name, e) for i in xrange(0, len(attributes), 2): - setattr(e, attributes[i], attributes[i+1]) + setattr(e, attributes[i], attributes[i + 1]) else: # tag of the form: , treat as empty string. setattr(self.container, this._name, "") @@ -663,7 +671,7 @@ class _Parser(object): # multiples of some tag or attribute. Code below handles this case. elif isinstance(sibling, Rowset): # its doppelganger is a rowset, append this as a row to that. - row = [_castfunc(attributes[i], attributes[i+1]) for i in xrange(0, len(attributes), 2)] + row = [_castfunc(attributes[i], attributes[i + 1]) for i in xrange(0, len(attributes), 2)] row.extend([getattr(this, col) for col in attributes2]) sibling.append(row) elif isinstance(sibling, Element): @@ -672,11 +680,13 @@ class _Parser(object): # into a Rowset, adding the sibling element and this one. rs = Rowset() rs.__catch = rs._name = this._name - row = [_castfunc(attributes[i], attributes[i+1]) for i in xrange(0, len(attributes), 2)]+[getattr(this, col) for col in attributes2] + row = [_castfunc(attributes[i], attributes[i + 1]) for i in xrange(0, len(attributes), 2)] + \ + [getattr(this, col) for col in attributes2] rs.append(row) - row = [getattr(sibling, attributes[i]) for i in xrange(0, len(attributes), 2)]+[getattr(sibling, col) for col in attributes2] + row = [getattr(sibling, attributes[i]) for i in xrange(0, len(attributes), 2)] + \ + [getattr(sibling, col) for col in attributes2] rs.append(row) - rs._cols = [attributes[i] for i in xrange(0, len(attributes), 2)]+[col for col in attributes2] + rs._cols = [attributes[i] for i in xrange(0, len(attributes), 2)] + [col for col in attributes2] setattr(self.container, this._name, rs) else: # something else must have set this attribute already. @@ -685,29 +695,31 @@ class _Parser(object): # Now fix up the attributes and be done with it. for i in xrange(0, len(attributes), 2): - this.__dict__[attributes[i]] = _castfunc(attributes[i], attributes[i+1]) + this.__dict__[attributes[i]] = _castfunc(attributes[i], attributes[i + 1]) return - - -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- # XML Data Containers -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- # The following classes are the various container types the XML data is # unpacked into. # # Note that objects returned by API calls are to be treated as read-only. This # is not enforced, but you have been warned. -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- + class Element(object): # Element is a namespace for attributes and nested tags def __str__(self): return "" % self._name + _fmt = u"%s:%s".__mod__ + + class Row(object): # A Row is a single database record associated with a Rowset. # The fields in the record are accessed as attributes by their respective @@ -750,7 +762,7 @@ class Row(object): try: return self._row[self._cols.index(this)] except: - raise AttributeError, this + raise AttributeError(this) def __getitem__(self, this): return self._row[self._cols.index(this)] @@ -823,7 +835,6 @@ class Rowset(object): for line in self._rows: yield [line[x] for x in i] - # ------------- def __init__(self, cols=None, rows=None): @@ -871,7 +882,6 @@ class Rowset(object): self._cols, self._rows = state - class IndexRowset(Rowset): # An IndexRowset is a Rowset that keeps an index on a column. # @@ -888,7 +898,7 @@ class IndexRowset(Rowset): if row is None: if default: return default[0] - raise KeyError, key + raise KeyError(key) return Row(self._cols, row) # ------------- @@ -939,28 +949,28 @@ class FilterRowset(object): # - Each key maps to a Rowset, containing only the rows where the value # of the column this FilterRowset was made on matches the key. - def __init__(self, cols=None, rows=None, key=None, key2=None, dict=None): - if dict is not None: - self._items = items = dict + def __init__(self, cols=None, rows=None, key=None, key2=None, dict_=None): + if dict_ is not None: + self._items = items = dict_ elif cols is not None: self._items = items = {} idfield = cols.index(key) if not key2: for row in rows: - id = row[idfield] - if id in items: - items[id].append(row) + id_ = row[idfield] + if id_ in items: + items[id_].append(row) else: - items[id] = [row] + items[id_] = [row] else: idfield2 = cols.index(key2) for row in rows: - id = row[idfield] - if id in items: - items[id][row[idfield2]] = row + id_ = row[idfield] + if id_ in items: + items[id_][row[idfield2]] = row else: - items[id] = {row[idfield2]:row} + items[id_] = {row[idfield2]: row} self._cols = cols self.key = key @@ -977,7 +987,7 @@ class FilterRowset(object): self.__iter__ = items.__iter__ def copy(self): - return FilterRowset(self._cols[:], None, self.key, self.key2, dict=copy.deepcopy(self._items)) + return FilterRowset(self._cols[:], None, self.key, self.key2, dict_=copy.deepcopy(self._items)) def get(self, key, default=_unspecified): try: diff --git a/service/fit.py b/service/fit.py index 655c833e0..c8c97baf5 100644 --- a/service/fit.py +++ b/service/fit.py @@ -17,67 +17,29 @@ # along with pyfa. If not, see . # =============================================================================== -import locale import copy -import threading import logging -import wx -from codecs import open - -import xml.parsers.expat import eos.db -import eos.types - -from eos.types import State, Slot - -from service.market import Market -from service.damagePattern import DamagePattern +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.module import Module as es_Module +from eos.saveddata.ship import Ship as es_Ship +from eos.types import State, Slot, Fit as FitType from service.character import Character +from service.damagePattern import DamagePattern +from service.market import Market from service.settings import SettingsProvider -from service.port import Port logger = logging.getLogger(__name__) -class FitBackupThread(threading.Thread): - def __init__(self, path, callback): - threading.Thread.__init__(self) - self.name = "FitBackup" - self.path = path - self.callback = callback - - def run(self): - path = self.path - sFit = Fit.getInstance() - allFits = map(lambda x: x[0], sFit.getAllFits()) - backedUpFits = sFit.exportXml(self.callback, *allFits) - backupFile = open(path, "w", encoding="utf-8") - backupFile.write(backedUpFits) - backupFile.close() - - # Send done signal to GUI - wx.CallAfter(self.callback, -1) - - -class FitImportThread(threading.Thread): - def __init__(self, paths, callback): - threading.Thread.__init__(self) - self.name = "FitImport" - self.paths = paths - self.callback = callback - - def run(self): - sFit = Fit.getInstance() - success, result = sFit.importFitFromFiles(self.paths, self.callback) - - if not success: # there was an error during processing - logger.error("Error while processing file import: %s", result) - wx.CallAfter(self.callback, -2, result) - else: # Send done signal to GUI - wx.CallAfter(self.callback, -1, result) - - class Fit(object): instance = None @@ -91,7 +53,7 @@ class Fit(object): def __init__(self): self.pattern = DamagePattern.getInstance().getDamagePattern("Uniform") self.targetResists = None - self.character = Character.getInstance().all5() + self.character = saveddata_Character.getAll5() self.booster = False self.dirtyFitIDs = set() @@ -108,19 +70,15 @@ class Fit(object): "showMarketShortcuts": False, "enableGaugeAnimation": True, "exportCharges": True, - "openFitInNew":False - } + "openFitInNew": False, + } self.serviceFittingOptions = SettingsProvider.getInstance().getSettings( "pyfaServiceFittingOptions", serviceFittingDefaultOptions) def getAllFits(self): fits = eos.db.getFitList() - names = [] - for fit in fits: - names.append((fit.ID, fit.name)) - - return names + return fits def getFitsWithShip(self, shipID): """ Lists fits of shipID, used with shipBrowser """ @@ -153,10 +111,10 @@ class Fit(object): def newFit(self, shipID, name=None): try: - ship = eos.types.Ship(eos.db.getItem(shipID)) + ship = es_Ship(eos.db.getItem(shipID)) except ValueError: - ship = eos.types.Citadel(eos.db.getItem(shipID)) - fit = eos.types.Fit(ship) + ship = es_Citadel(eos.db.getItem(shipID)) + fit = FitType(ship) fit.name = name if name is not None else "New %s" % fit.ship.item.name fit.damagePattern = self.pattern fit.targetResists = self.targetResists @@ -228,11 +186,12 @@ class Fit(object): self.recalc(fit, withBoosters=True) def getFit(self, fitID, projected=False, basic=False): - ''' Gets fit from database + """ + Gets fit from database Projected is a recursion flag that is set to reduce recursions into projected fits Basic is a flag to simply return the fit without any other processing - ''' + """ if fitID is None: return None fit = eos.db.getFit(fitID) @@ -272,7 +231,7 @@ class Fit(object): fit = eos.db.getFit(fitID) item = eos.db.getItem(itemID, eager="attributes") try: - implant = eos.types.Implant(item) + implant = es_Implant(item) except ValueError: return False @@ -298,7 +257,7 @@ class Fit(object): fit = eos.db.getFit(fitID) item = eos.db.getItem(itemID, eager="attributes") try: - booster = eos.types.Booster(item) + booster = es_Booster(item) except ValueError: return False @@ -326,7 +285,7 @@ class Fit(object): thing = eos.db.getItem(thing, eager=("attributes", "group.category")) - if isinstance(thing, eos.types.Fit): + if isinstance(thing, FitType): if thing in fit.projectedFits: return @@ -343,19 +302,19 @@ class Fit(object): break if drone is None: - drone = eos.types.Drone(thing) + drone = es_Drone(thing) fit.projectedDrones.append(drone) drone.amount += 1 elif thing.category.name == "Fighter": - fighter = eos.types.Fighter(thing) + fighter = es_Fighter(thing) fit.projectedFighters.append(fighter) elif thing.group.name == "Effect Beacon": - module = eos.types.Module(thing) + module = es_Module(thing) module.state = State.ONLINE fit.projectedModules.append(module) else: - module = eos.types.Module(thing) + module = es_Module(thing) module.state = State.ACTIVE if not module.canHaveState(module.state, fit): module.state = State.OFFLINE @@ -386,18 +345,18 @@ class Fit(object): def toggleProjected(self, fitID, thing, click): fit = eos.db.getFit(fitID) - if isinstance(thing, eos.types.Drone): + if isinstance(thing, es_Drone): if thing.amountActive == 0 and thing.canBeApplied(fit): thing.amountActive = thing.amount else: thing.amountActive = 0 - elif isinstance(thing, eos.types.Fighter): + elif isinstance(thing, es_Fighter): thing.active = not thing.active - elif isinstance(thing, eos.types.Module): + elif isinstance(thing, es_Module): thing.state = self.__getProposedState(thing, click) if not thing.canHaveState(thing.state, fit): thing.state = State.OFFLINE - elif isinstance(thing, eos.types.Fit): + elif isinstance(thing, FitType): projectionInfo = thing.getProjectionInfo(fitID) if projectionInfo: projectionInfo.active = not projectionInfo.active @@ -434,11 +393,11 @@ class Fit(object): def removeProjected(self, fitID, thing): fit = eos.db.getFit(fitID) - if isinstance(thing, eos.types.Drone): + if isinstance(thing, es_Drone): fit.projectedDrones.remove(thing) - elif isinstance(thing, eos.types.Module): + elif isinstance(thing, es_Module): fit.projectedModules.remove(thing) - elif isinstance(thing, eos.types.Fighter): + elif isinstance(thing, es_Fighter): fit.projectedFighters.remove(thing) else: del fit.__projectedFits[thing.ID] @@ -458,7 +417,7 @@ class Fit(object): fit = eos.db.getFit(fitID) item = eos.db.getItem(itemID, eager=("attributes", "group.category")) try: - m = eos.types.Module(item) + m = es_Module(item) except ValueError: return False @@ -505,7 +464,7 @@ class Fit(object): item = eos.db.getItem(newItemID, eager=("attributes", "group.category")) try: - m = eos.types.Module(item) + m = es_Module(item) except ValueError: return False @@ -542,7 +501,7 @@ class Fit(object): # Gather modules and convert Cargo item to Module, silently return if not a module try: - cargoP = eos.types.Module(cargo.item) + cargoP = es_Module(cargo.item) cargoP.owner = fit if cargoP.isValidState(State.ACTIVE): cargoP.state = State.ACTIVE @@ -572,7 +531,7 @@ class Fit(object): x.amount += 1 break else: - moduleP = eos.types.Cargo(module.item) + moduleP = es_Cargo(module.item) moduleP.amount = 1 fit.cargo.insert(cargoIdx, moduleP) @@ -637,7 +596,7 @@ class Fit(object): if cargo is None: # if we don't have the item already in cargo, use default values - cargo = eos.types.Cargo(item) + cargo = es_Cargo(item) fit.cargo.append(cargo) if replace: @@ -675,10 +634,10 @@ class Fit(object): break ''' if fighter is None: - fighter = eos.types.Fighter(item) + fighter = es_Fighter(item) used = fit.getSlotsUsed(fighter.slot) total = fit.getNumSlots(fighter.slot) - standardAttackActive = False; + standardAttackActive = False for ability in fighter.abilities: if (ability.effect.isImplemented and ability.effect.handlerName == u'fighterabilityattackm'): # Activate "standard attack" if available @@ -686,10 +645,10 @@ class Fit(object): standardAttackActive = True else: # Activate all other abilities (Neut, Web, etc) except propmods if no standard attack is active - if (ability.effect.isImplemented - and standardAttackActive == False - and ability.effect.handlerName != u'fighterabilitymicrowarpdrive' - and ability.effect.handlerName != u'fighterabilityevasivemaneuvers'): + if ability.effect.isImplemented and \ + standardAttackActive is False and \ + ability.effect.handlerName != u'fighterabilitymicrowarpdrive' and \ + ability.effect.handlerName != u'fighterabilityevasivemaneuvers': ability.active = True if used >= total: @@ -729,7 +688,7 @@ class Fit(object): break if drone is None: - drone = eos.types.Drone(item) + drone = es_Drone(item) if drone.fits(fit) is True: fit.drones.append(drone) else: @@ -766,7 +725,7 @@ class Fit(object): d.amount = amount d.amountActive = amount if active else 0 - newD = eos.types.Drone(d.item) + newD = es_Drone(d.item) newD.amount = total - amount newD.amountActive = newD.amount if active else 0 l.append(newD) @@ -931,7 +890,7 @@ class Fit(object): sDP = DamagePattern.getInstance() dp = sDP.getDamagePattern("Selected Ammo") if dp is None: - dp = eos.types.DamagePattern() + dp = es_DamagePattern() dp.name = "Selected Ammo" fit = eos.db.getFit(fitID) @@ -941,140 +900,6 @@ class Fit(object): fit.damagePattern = dp self.recalc(fit) - def exportFit(self, fitID): - fit = eos.db.getFit(fitID) - return Port.exportEft(fit) - - def exportEftImps(self, fitID): - fit = eos.db.getFit(fitID) - return Port.exportEftImps(fit) - - def exportDna(self, fitID): - fit = eos.db.getFit(fitID) - return Port.exportDna(fit) - - def exportCrest(self, fitID, callback=None): - fit = eos.db.getFit(fitID) - return Port.exportCrest(fit, callback) - - def exportXml(self, callback=None, *fitIDs): - fits = map(lambda fitID: eos.db.getFit(fitID), fitIDs) - return Port.exportXml(callback, *fits) - - def exportMultiBuy(self, fitID): - fit = eos.db.getFit(fitID) - return Port.exportMultiBuy(fit) - - def backupFits(self, path, callback): - thread = FitBackupThread(path, callback) - thread.start() - - def importFitsThreaded(self, paths, callback): - thread = FitImportThread(paths, callback) - thread.start() - - def importFitFromFiles(self, paths, callback=None): - """ - Imports fits from file(s). First processes all provided paths and stores - assembled fits into a list. This allows us to call back to the GUI as - fits are processed as well as when fits are being saved. - returns - """ - defcodepage = locale.getpreferredencoding() - - fits = [] - for path in paths: - if callback: # Pulse - wx.CallAfter(callback, 1, "Processing file:\n%s" % path) - - file = open(path, "r") - srcString = file.read() - - if len(srcString) == 0: # ignore blank files - continue - - codec_found = None - # If file had ANSI encoding, decode it to unicode using detection - # of BOM header or if there is no header try default - # codepage then fallback to utf-16, cp1252 - - if isinstance(srcString, str): - encoding_map = ( - ('\xef\xbb\xbf', 'utf-8'), - ('\xff\xfe\0\0', 'utf-32'), - ('\0\0\xfe\xff', 'UTF-32BE'), - ('\xff\xfe', 'utf-16'), - ('\xfe\xff', 'UTF-16BE')) - - for bom, encoding in encoding_map: - if srcString.startswith(bom): - codec_found = encoding - savebom = bom - - if codec_found is None: - logger.info("Unicode BOM not found in file %s.", path) - attempt_codecs = (defcodepage, "utf-8", "utf-16", "cp1252") - - for page in attempt_codecs: - try: - logger.info("Attempting to decode file %s using %s page.", path, page) - srcString = unicode(srcString, page) - codec_found = page - logger.info("File %s decoded using %s page.", path, page) - except UnicodeDecodeError: - logger.info("Error unicode decoding %s from page %s, trying next codec", path, page) - else: - break - else: - logger.info("Unicode BOM detected in %s, using %s page.", path, codec_found) - srcString = unicode(srcString[len(savebom):], codec_found) - - else: - # nasty hack to detect other transparent utf-16 loading - if srcString[0] == '<' and 'utf-16' in srcString[:128].lower(): - codec_found = "utf-16" - else: - codec_found = "utf-8" - - if codec_found is None: - return False, "Proper codec could not be established for %s" % path - - try: - _, fitsImport = Port.importAuto(srcString, path, callback=callback, encoding=codec_found) - fits += fitsImport - except xml.parsers.expat.ExpatError, e: - return False, "Malformed XML in %s" % path - except Exception, e: - logger.exception("Unknown exception processing: %s", path) - return False, "Unknown Error while processing %s" % path - - IDs = [] - numFits = len(fits) - for i, fit in enumerate(fits): - # Set some more fit attributes and save - fit.character = self.character - fit.damagePattern = self.pattern - fit.targetResists = self.targetResists - eos.db.save(fit) - IDs.append(fit.ID) - if callback: # Pulse - wx.CallAfter( - callback, 1, - "Processing complete, saving fits to database\n(%d/%d)" % - (i + 1, numFits) - ) - - return True, fits - - def importFitFromBuffer(self, bufferStr, activeFit=None): - _, fits = Port.importAuto(bufferStr, activeFit=activeFit) - for fit in fits: - fit.character = self.character - fit.damagePattern = self.pattern - fit.targetResists = self.targetResists - eos.db.save(fit) - return fits - def checkStates(self, fit, base): changed = False for mod in fit.modules: diff --git a/service/implantSet.py b/service/implantSet.py index 0d0df5808..f1da65aed 100644 --- a/service/implantSet.py +++ b/service/implantSet.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2016 Ryan Holmes # # This file is part of pyfa. @@ -15,18 +15,23 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= + +import copy import eos.db -import eos.types -import copy -import service.market +from service.market import Market +from eos.saveddata.implant import Implant as es_Implant +from eos.saveddata.implantSet import ImplantSet as es_ImplantSet + class ImportError(Exception): pass -class ImplantSets(): + +class ImplantSets(object): instance = None + @classmethod def getInstance(cls): if cls.instance is None: @@ -41,43 +46,41 @@ class ImplantSets(): return eos.db.getImplantSet(name) def getImplants(self, setID): - set = eos.db.getImplantSet(setID) - return set.implants + return eos.db.getImplantSet(setID).implants def addImplant(self, setID, itemID): - set = eos.db.getImplantSet(setID) - implant = eos.types.Implant(eos.db.getItem(itemID)) - set.implants.append(implant) + implant_set = eos.db.getImplantSet(setID) + implant = es_Implant(eos.db.getItem(itemID)) + implant_set.implants.append(implant) eos.db.commit() def removeImplant(self, setID, implant): - set = eos.db.getImplantSet(setID) - set.implants.remove(implant) + eos.db.getImplantSet(setID).implants.remove(implant) eos.db.commit() def newSet(self, name): - s = eos.types.ImplantSet() - s.name = name - eos.db.save(s) - return s + implant_set = es_ImplantSet() + implant_set.name = name + eos.db.save(implant_set) + return implant_set - def renameSet(self, s, newName): - s.name = newName - eos.db.save(s) + def renameSet(self, implant_set, newName): + implant_set.name = newName + eos.db.save(implant_set) - def deleteSet(self, s): - eos.db.remove(s) + def deleteSet(self, implant_set): + eos.db.remove(implant_set) - def copySet(self, s): - newS = copy.deepcopy(s) + def copySet(self, implant_set): + newS = copy.deepcopy(implant_set) eos.db.save(newS) return newS - def saveChanges(self, s): - eos.db.save(s) - + def saveChanges(self, implant_set): + eos.db.save(implant_set) + def importSets(self, text): - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() lines = text.splitlines() newSets = [] errors = 0 @@ -90,25 +93,25 @@ class ImplantSets(): if line == '' or line[0] == "#": # comments / empty string continue if line[:1] == "[" and line[-1:] == "]": - current = eos.types.ImplantSet(line[1:-1]) + current = es_ImplantSet(line[1:-1]) newSets.append(current) else: item = sMkt.getItem(line) - current.implants.append(eos.types.Implant(item)) + current.implants.append(es_Implant(item)) except: errors += 1 continue - for set in self.getImplantSetList(): - lookup[set.name] = set + for implant_set in self.getImplantSetList(): + lookup[implant_set.name] = implant_set - for set in newSets: - if set.name in lookup: - match = lookup[set.name] - for implant in set.implants: - match.implants.append(eos.types.Implant(implant.item)) + for implant_set in newSets: + if implant_set.name in lookup: + match = lookup[implant_set.name] + for implant in implant_set.implants: + match.implants.append(es_Implant(implant.item)) else: - eos.db.save(set) + eos.db.save(implant_set) eos.db.commit() @@ -116,10 +119,10 @@ class ImplantSets(): if lenImports == 0: raise ImportError("No patterns found for import") if errors > 0: - raise ImportError("%d sets imported from clipboard; %d errors"%(lenImports, errors)) - + raise ImportError("%d sets imported from clipboard; %d errors" % + (lenImports, errors)) + def exportSets(self): patterns = self.getImplantSetList() patterns.sort(key=lambda p: p.name) - return eos.types.ImplantSet.exportSets(*patterns) - + return es_ImplantSet.exportSets(*patterns) diff --git a/service/market.py b/service/market.py index dde6e9621..6edb3d432 100644 --- a/service/market.py +++ b/service/market.py @@ -1,4 +1,4 @@ -#=============================================================================== +# =============================================================================== # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,22 +15,27 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# =============================================================================== import re import threading -import wx - +import logging import Queue +import wx +from sqlalchemy.sql import or_ + import config import eos.db -import eos.types -from sqlalchemy.sql import and_, or_ -from service.settings import SettingsProvider, NetworkSettings -import service -import service.conversions as conversions -import logging +from service import conversions +from service.settings import SettingsProvider +from service.price import Price + +# TODO: Convert eos.types over to eos.gamedata +# from eos.gamedata import Category as e_Category, Group as e_Group, Item as e_Item + +from eos.types import MarketGroup as types_MarketGroup, MetaGroup as types_MetaGroup, MetaType as types_MetaType, \ + Category as types_Category, Item as types_Item, Group as types_Group, Price as types_Price try: from collections import OrderedDict @@ -42,6 +47,7 @@ logger = logging.getLogger(__name__) # Event which tells threads dependent on Market that it's initialized mktRdy = threading.Event() + class ShipBrowserWorkerThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) @@ -61,13 +67,13 @@ class ShipBrowserWorkerThread(threading.Thread): sMkt = Market.getInstance() while True: try: - id, callback = queue.get() - set = cache.get(id) - if set is None: - set = sMkt.getShipList(id) - cache[id] = set + id_, callback = queue.get() + set_ = cache.get(id_) + if set_ is None: + set_ = sMkt.getShipList(id_) + cache[id_] = set_ - wx.CallAfter(callback, (id, set)) + wx.CallAfter(callback, (id_, set_)) except: pass finally: @@ -76,6 +82,7 @@ class ShipBrowserWorkerThread(threading.Thread): except: pass + class PriceWorkerThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) @@ -94,7 +101,7 @@ class PriceWorkerThread(threading.Thread): # Grab prices, this is the time-consuming part if len(requests) > 0: - service.Price.fetchPrices(requests) + Price.fetchPrices(requests) wx.CallAfter(callback) queue.task_done() @@ -114,6 +121,7 @@ class PriceWorkerThread(threading.Thread): self.wait[itemID] = [] self.wait[itemID].append(callback) + class SearchWorkerThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) @@ -138,14 +146,14 @@ class SearchWorkerThread(threading.Thread): sMkt = Market.getInstance() if filterOn is True: # Rely on category data provided by eos as we don't hardcode them much in service - filter = or_(eos.types.Category.name.in_(sMkt.SEARCH_CATEGORIES), eos.types.Group.name.in_(sMkt.SEARCH_GROUPS)) + filter_ = or_(types_Category.name.in_(sMkt.SEARCH_CATEGORIES), types_Group.name.in_(sMkt.SEARCH_GROUPS)) elif filterOn: # filter by selected categories - filter = eos.types.Category.name.in_(filterOn) + filter_ = types_Category.name.in_(filterOn) else: - filter=None + filter_ = None - results = eos.db.searchItems(request, where=filter, - join=(eos.types.Item.group, eos.types.Group.category), + results = eos.db.searchItems(request, where=filter_, + join=(types_Item.group, types_Group.category), eager=("icon", "group.category", "metaGroup", "metaGroup.parent")) items = set() @@ -161,15 +169,18 @@ class SearchWorkerThread(threading.Thread): self.cv.notify() self.cv.release() + class Market(): instance = None + def __init__(self): self.priceCache = {} - #Init recently used module storage + # Init recently used module storage serviceMarketRecentlyUsedModules = {"pyfaMarketRecentlyUsedModules": []} - self.serviceMarketRecentlyUsedModules = SettingsProvider.getInstance().getSettings("pyfaMarketRecentlyUsedModules", serviceMarketRecentlyUsedModules) + self.serviceMarketRecentlyUsedModules = SettingsProvider.getInstance().getSettings( + "pyfaMarketRecentlyUsedModules", serviceMarketRecentlyUsedModules) # Start price fetcher self.priceWorkerThread = PriceWorkerThread() @@ -189,7 +200,7 @@ class Market(): # Items' group overrides self.customGroups = set() # Limited edition ships - self.les_grp = eos.types.Group() + self.les_grp = types_Group() self.les_grp.ID = -1 self.les_grp.name = "Limited Issue Ships" self.les_grp.published = True @@ -199,36 +210,37 @@ class Market(): self.les_grp.description = "" self.les_grp.icon = None self.ITEMS_FORCEGROUP = { - "Opux Luxury Yacht": self.les_grp, # One of those is wedding present at CCP fanfest, another was hijacked from ISD guy during an event + "Opux Luxury Yacht": self.les_grp, + # One of those is wedding present at CCP fanfest, another was hijacked from ISD guy during an event "Silver Magnate": self.les_grp, # Amarr Championship prize "Gold Magnate": self.les_grp, # Amarr Championship prize "Armageddon Imperial Issue": self.les_grp, # Amarr Championship prize - "Apocalypse Imperial Issue": self.les_grp, # Amarr Championship prize - "Guardian-Vexor": self.les_grp, # Illegal rewards for the Gallente Frontier Tour Lines event arc - "Megathron Federate Issue": self.les_grp, # Reward during Crielere event + "Apocalypse Imperial Issue": self.les_grp, # Amarr Championship prize + "Guardian-Vexor": self.les_grp, # Illegal rewards for the Gallente Frontier Tour Lines event arc + "Megathron Federate Issue": self.les_grp, # Reward during Crielere event "Raven State Issue": self.les_grp, # AT4 prize - "Tempest Tribal Issue": self.les_grp, # AT4 prize - "Apotheosis": self.les_grp, # 5th EVE anniversary present - "Zephyr": self.les_grp, # 2010 new year gift - "Primae": self.les_grp, # Promotion of planetary interaction - "Freki": self.les_grp, # AT7 prize - "Mimir": self.les_grp, # AT7 prize - "Utu": self.les_grp, # AT8 prize - "Adrestia": self.les_grp, # AT8 prize - "Echelon": self.les_grp, # 2011 new year gift - "Malice": self.les_grp, # AT9 prize - "Vangel": self.les_grp, # AT9 prize - "Cambion": self.les_grp, # AT10 prize - "Etana": self.les_grp, # AT10 prize - "Chremoas": self.les_grp, # AT11 prize :( - "Moracha": self.les_grp, # AT11 prize - "Stratios Emergency Responder": self.les_grp, # Issued for Somer Blink lottery - "Miasmos Quafe Ultra Edition": self.les_grp, # Gift to people who purchased FF HD stream + "Tempest Tribal Issue": self.les_grp, # AT4 prize + "Apotheosis": self.les_grp, # 5th EVE anniversary present + "Zephyr": self.les_grp, # 2010 new year gift + "Primae": self.les_grp, # Promotion of planetary interaction + "Freki": self.les_grp, # AT7 prize + "Mimir": self.les_grp, # AT7 prize + "Utu": self.les_grp, # AT8 prize + "Adrestia": self.les_grp, # AT8 prize + "Echelon": self.les_grp, # 2011 new year gift + "Malice": self.les_grp, # AT9 prize + "Vangel": self.les_grp, # AT9 prize + "Cambion": self.les_grp, # AT10 prize + "Etana": self.les_grp, # AT10 prize + "Chremoas": self.les_grp, # AT11 prize :( + "Moracha": self.les_grp, # AT11 prize + "Stratios Emergency Responder": self.les_grp, # Issued for Somer Blink lottery + "Miasmos Quafe Ultra Edition": self.les_grp, # Gift to people who purchased FF HD stream "InterBus Shuttle": self.les_grp, - "Leopard": self.les_grp, # 2013 new year gift - "Whiptail": self.les_grp, # AT12 prize - "Chameleon": self.les_grp, # AT12 prize - "Victorieux Luxury Yacht": self.les_grp, # Worlds Collide prize \o/ chinese getting owned + "Leopard": self.les_grp, # 2013 new year gift + "Whiptail": self.les_grp, # AT12 prize + "Chameleon": self.les_grp, # AT12 prize + "Victorieux Luxury Yacht": self.les_grp, # Worlds Collide prize \o/ chinese getting owned "Imp": self.les_grp, # AT13 prize "Fiend": self.les_grp, # AT13 prize "Caedes": self.les_grp, # AT14 prize @@ -241,8 +253,8 @@ class Market(): # List of items which are forcibly published or hidden self.ITEMS_FORCEPUBLISHED = { - "Data Subverter I": False, # Not used in EVE, probably will appear with Dust link - "QA Cross Protocol Analyzer": False, # QA modules used by CCP internally + "Data Subverter I": False, # Not used in EVE, probably will appear with Dust link + "QA Cross Protocol Analyzer": False, # QA modules used by CCP internally "QA Damage Module": False, "QA ECCM": False, "QA Immunity Module": False, @@ -278,7 +290,7 @@ class Market(): # List of groups which are forcibly published self.GROUPS_FORCEPUBLISHED = { - "Prototype Exploration Ship": False } # We moved the only ship from this group to other group anyway + "Prototype Exploration Ship": False} # We moved the only ship from this group to other group anyway # Dictionary of items with forced meta groups, uses following format: # Item name: (metagroup name, parent type name) @@ -287,82 +299,112 @@ class Market(): "'Wild' Miner I": ("Storyline", "Miner I"), "Medium Nano Armor Repair Unit I": ("Tech I", "Medium Armor Repairer I"), "Large 'Reprieve' Vestment Reconstructer I": ("Storyline", "Large Armor Repairer I"), - "Khanid Navy Torpedo Launcher": ("Faction", "Torpedo Launcher I"),} + "Khanid Navy Torpedo Launcher": ("Faction", "Torpedo Launcher I"), } # Parent type name: set(item names) self.ITEMS_FORCEDMETAGROUP_R = {} for item, value in self.ITEMS_FORCEDMETAGROUP.items(): parent = value[1] - if not parent in self.ITEMS_FORCEDMETAGROUP_R: + if parent not in self.ITEMS_FORCEDMETAGROUP_R: self.ITEMS_FORCEDMETAGROUP_R[parent] = set() self.ITEMS_FORCEDMETAGROUP_R[parent].add(item) # Dictionary of items with forced market group (service assumes they have no # market group assigned in db, otherwise they'll appear in both original and forced groups) self.ITEMS_FORCEDMARKETGROUP = { - "'Alpha' Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners - "'Codex' Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners - "'Daemon' Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners - "'Libram' Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners - "Advanced Cerebral Accelerator": 977, # Implants & Boosters > Booster - "Civilian Damage Control": 615, # Ship Equipment > Hull & Armor > Damage Controls - "Civilian EM Ward Field": 1695, # Ship Equipment > Shield > Shield Hardeners > EM Shield Hardeners - "Civilian Explosive Deflection Field": 1694, # Ship Equipment > Shield > Shield Hardeners > Explosive Shield Hardeners - "Civilian Hobgoblin": 837, # Drones > Combat Drones > Light Scout Drones - "Civilian Kinetic Deflection Field": 1693, # Ship Equipment > Shield > Shield Hardeners > Kinetic Shield Hardeners - "Civilian Light Missile Launcher": 640, # Ship Equipment > Turrets & Bays > Missile Launchers > Light Missile Launchers - "Civilian Scourge Light Missile": 920, # Ammunition & Charges > Missiles > Light Missiles > Standard Light Missiles - "Civilian Small Remote Armor Repairer": 1059, # Ship Equipment > Hull & Armor > Remote Armor Repairers > Small - "Civilian Small Remote Shield Booster": 603, # Ship Equipment > Shield > Remote Shield Boosters > Small - "Civilian Stasis Webifier": 683, # Ship Equipment > Electronic Warfare > Stasis Webifiers - "Civilian Thermic Dissipation Field": 1692, # Ship Equipment > Shield > Shield Hardeners > Thermal Shield Hardeners - "Civilian Warp Disruptor": 1935, # Ship Equipment > Electronic Warfare > Warp Disruptors - "Hardwiring - Zainou 'Sharpshooter' ZMX10": 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06 - "Hardwiring - Zainou 'Sharpshooter' ZMX100": 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06 - "Hardwiring - Zainou 'Sharpshooter' ZMX1000": 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06 - "Hardwiring - Zainou 'Sharpshooter' ZMX11": 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06 - "Hardwiring - Zainou 'Sharpshooter' ZMX110": 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06 - "Hardwiring - Zainou 'Sharpshooter' ZMX1100": 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06 - "Nugoehuvi Synth Blue Pill Booster": 977, # Implants & Boosters > Booster - "Prototype Cerebral Accelerator": 977, # Implants & Boosters > Booster - "Prototype Iris Probe Launcher": 712, # Ship Equipment > Turrets & Bays > Scan Probe Launchers - "Shadow": 1310, # Drones > Combat Drones > Fighter Bombers - "Sleeper Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners - "Standard Cerebral Accelerator": 977, # Implants & Boosters > Booster - "Talocan Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners - "Terran Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners - "Tetrimon Data Analyzer I": 714 # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners + "'Alpha' Data Analyzer I": 714, + # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners + "'Codex' Data Analyzer I": 714, + # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners + "'Daemon' Data Analyzer I": 714, + # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners + "'Libram' Data Analyzer I": 714, + # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners + "Advanced Cerebral Accelerator": 977, # Implants & Boosters > Booster + "Civilian Damage Control": 615, # Ship Equipment > Hull & Armor > Damage Controls + "Civilian EM Ward Field": 1695, # Ship Equipment > Shield > Shield Hardeners > EM Shield Hardeners + "Civilian Explosive Deflection Field": 1694, + # Ship Equipment > Shield > Shield Hardeners > Explosive Shield Hardeners + "Civilian Hobgoblin": 837, # Drones > Combat Drones > Light Scout Drones + "Civilian Kinetic Deflection Field": 1693, + # Ship Equipment > Shield > Shield Hardeners > Kinetic Shield Hardeners + "Civilian Light Missile Launcher": 640, + # Ship Equipment > Turrets & Bays > Missile Launchers > Light Missile Launchers + "Civilian Scourge Light Missile": 920, + # Ammunition & Charges > Missiles > Light Missiles > Standard Light Missiles + "Civilian Small Remote Armor Repairer": 1059, + # Ship Equipment > Hull & Armor > Remote Armor Repairers > Small + "Civilian Small Remote Shield Booster": 603, # Ship Equipment > Shield > Remote Shield Boosters > Small + "Civilian Stasis Webifier": 683, # Ship Equipment > Electronic Warfare > Stasis Webifiers + "Civilian Thermic Dissipation Field": 1692, + # Ship Equipment > Shield > Shield Hardeners > Thermal Shield Hardeners + "Civilian Warp Disruptor": 1935, # Ship Equipment > Electronic Warfare > Warp Disruptors + "Hardwiring - Zainou 'Sharpshooter' ZMX10": 1493, + # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06 + "Hardwiring - Zainou 'Sharpshooter' ZMX100": 1493, + # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06 + "Hardwiring - Zainou 'Sharpshooter' ZMX1000": 1493, + # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06 + "Hardwiring - Zainou 'Sharpshooter' ZMX11": 1493, + # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06 + "Hardwiring - Zainou 'Sharpshooter' ZMX110": 1493, + # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06 + "Hardwiring - Zainou 'Sharpshooter' ZMX1100": 1493, + # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06 + "Nugoehuvi Synth Blue Pill Booster": 977, # Implants & Boosters > Booster + "Prototype Cerebral Accelerator": 977, # Implants & Boosters > Booster + "Prototype Iris Probe Launcher": 712, # Ship Equipment > Turrets & Bays > Scan Probe Launchers + "Shadow": 1310, # Drones > Combat Drones > Fighter Bombers + "Sleeper Data Analyzer I": 714, + # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners + "Standard Cerebral Accelerator": 977, # Implants & Boosters > Booster + "Talocan Data Analyzer I": 714, + # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners + "Terran Data Analyzer I": 714, + # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners + "Tetrimon Data Analyzer I": 714 + # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners } self.ITEMS_FORCEDMARKETGROUP_R = self.__makeRevDict(self.ITEMS_FORCEDMARKETGROUP) self.FORCEDMARKETGROUP = { - 685: False, # Ship Equipment > Electronic Warfare > ECCM - 681: False, # Ship Equipment > Electronic Warfare > Sensor Backup Arrays + 685: False, # Ship Equipment > Electronic Warfare > ECCM + 681: False, # Ship Equipment > Electronic Warfare > Sensor Backup Arrays } # Misc definitions # 0 is for items w/o meta group - self.META_MAP = OrderedDict([("normal", frozenset((0, 1, 2, 14))), + self.META_MAP = OrderedDict([("normal", frozenset((0, 1, 2, 14))), ("faction", frozenset((4, 3))), ("complex", frozenset((6,))), ("officer", frozenset((5,)))]) - self.SEARCH_CATEGORIES = ("Drone", "Module", "Subsystem", "Charge", "Implant", "Deployable", "Fighter", "Structure", "Structure Module") + self.SEARCH_CATEGORIES = ( + "Drone", + "Module", + "Subsystem", + "Charge", + "Implant", + "Deployable", + "Fighter", + "Structure", + "Structure Module", + ) self.SEARCH_GROUPS = ("Ice Product",) - self.ROOT_MARKET_GROUPS = (9, # Modules + self.ROOT_MARKET_GROUPS = (9, # Modules 1111, # Rigs - 157, # Drones - 11, # Ammo + 157, # Drones + 11, # Ammo 1112, # Subsystems - 24, # Implants & Boosters - 404, # Deployables + 24, # Implants & Boosters + 404, # Deployables 2202, # Structure Equipment - 2203 # Structure Modifications + 2203 # Structure Modifications ) # Tell other threads that Market is at their service mktRdy.set() @classmethod def getInstance(cls): - if cls.instance == None: + if cls.instance is None: cls.instance = Market() return cls.instance @@ -370,7 +412,7 @@ class Market(): """Creates reverse dictionary""" rev = {} for item, value in orig.items(): - if not value in rev: + if value not in rev: rev[value] = set() rev[value].add(item) return rev @@ -378,7 +420,7 @@ class Market(): def getItem(self, identity, *args, **kwargs): """Get item by its ID or name""" try: - if isinstance(identity, eos.types.Item): + if isinstance(identity, types_Item): item = identity elif isinstance(identity, int): item = eos.db.getItem(identity, *args, **kwargs) @@ -387,9 +429,10 @@ class Market(): # features. Check against overrides identity = conversions.all.get(identity, identity) item = eos.db.getItem(identity, *args, **kwargs) + elif isinstance(identity, float): - id = int(identity) - item = eos.db.getItem(id, *args, **kwargs) + id_ = int(identity) + item = eos.db.getItem(id_, *args, **kwargs) else: raise TypeError("Need Item object, integer, float or string as argument") except: @@ -400,7 +443,7 @@ class Market(): def getGroup(self, identity, *args, **kwargs): """Get group by its ID or name""" - if isinstance(identity, eos.types.Group): + if isinstance(identity, types_Group): return identity elif isinstance(identity, (int, float, basestring)): if isinstance(identity, float): @@ -418,37 +461,37 @@ class Market(): def getCategory(self, identity, *args, **kwargs): """Get category by its ID or name""" - if isinstance(identity, eos.types.Category): + if isinstance(identity, types_Category): category = identity elif isinstance(identity, (int, basestring)): category = eos.db.getCategory(identity, *args, **kwargs) elif isinstance(identity, float): - id = int(identity) - category = eos.db.getCategory(id, *args, **kwargs) + id_ = int(identity) + category = eos.db.getCategory(id_, *args, **kwargs) else: raise TypeError("Need Category object, integer, float or string as argument") return category def getMetaGroup(self, identity, *args, **kwargs): """Get meta group by its ID or name""" - if isinstance(identity, eos.types.MetaGroup): + if isinstance(identity, types_MetaGroup): metaGroup = identity elif isinstance(identity, (int, basestring)): metaGroup = eos.db.getMetaGroup(identity, *args, **kwargs) elif isinstance(identity, float): - id = int(identity) - metaGroup = eos.db.getMetaGroup(id, *args, **kwargs) + id_ = int(identity) + metaGroup = eos.db.getMetaGroup(id_, *args, **kwargs) else: raise TypeError("Need MetaGroup object, integer, float or string as argument") return metaGroup def getMarketGroup(self, identity, *args, **kwargs): """Get market group by its ID""" - if isinstance(identity, eos.types.MarketGroup): + if isinstance(identity, types_MarketGroup): marketGroup = identity elif isinstance(identity, (int, float)): - id = int(identity) - marketGroup = eos.db.getMarketGroup(id, *args, **kwargs) + id_ = int(identity) + marketGroup = eos.db.getMarketGroup(id_, *args, **kwargs) else: raise TypeError("Need MarketGroup object, integer or float as argument") return marketGroup @@ -472,7 +515,7 @@ class Market(): # Check if item is in forced metagroup map if item.name in self.ITEMS_FORCEDMETAGROUP: # Create meta group from scratch - metaGroup = eos.types.MetaType() + metaGroup = types_MetaType() # Get meta group info object based on meta group name metaGroupInfo = self.getMetaGroup(self.ITEMS_FORCEDMETAGROUP[item.name][0]) # Get parent item based on its name @@ -492,8 +535,8 @@ class Market(): def getMetaGroupIdByItem(self, item, fallback=0): """Get meta group ID by item""" - id = getattr(self.getMetaGroupByItem(item), "ID", fallback) - return id + id_ = getattr(self.getMetaGroupByItem(item), "ID", fallback) + return id_ def getMarketGroupByItem(self, item, parentcheck=True): """Get market group by item, its ID or name""" @@ -574,10 +617,11 @@ class Market(): groupItems = set(group.items) if hasattr(group, 'addItems'): groupItems.update(group.addItems) - items = set(filter(lambda item: self.getPublicityByItem(item) and self.getGroupByItem(item) == group, groupItems)) + items = set( + filter(lambda item: self.getPublicityByItem(item) and self.getGroupByItem(item) == group, groupItems)) return items - def getItemsByMarketGroup(self, mg, vars=True): + def getItemsByMarketGroup(self, mg, vars_=True): """Get items in the given market group""" result = set() # Get items from eos market group @@ -586,7 +630,7 @@ class Market(): if mg.ID in self.ITEMS_FORCEDMARKETGROUP_R: forceditms = set(self.getItem(itmn) for itmn in self.ITEMS_FORCEDMARKETGROUP_R[mg.ID]) baseitms.update(forceditms) - if vars: + if vars_: parents = set() for item in baseitms: # Add one of the base market group items to result @@ -604,7 +648,7 @@ class Market(): else: result = baseitms # Get rid of unpublished items - result = set(filter(lambda item: self.getPublicityByItem(item), result)) + result = set(filter(lambda item_: self.getPublicityByItem(item_), result)) return result def marketGroupHasTypesCheck(self, mg): @@ -639,7 +683,7 @@ class Market(): elif self.marketGroupHasTypesCheck(mg): # Do not request variations to make process faster # Pick random item and use its icon - items = self.getItemsByMarketGroup(mg, vars=False) + items = self.getItemsByMarketGroup(mg, vars_=False) try: item = items.pop() except KeyError: @@ -677,8 +721,8 @@ class Market(): the ID, the name and the icon of the group """ root = set() - for id in self.ROOT_MARKET_GROUPS: - mg = self.getMarketGroup(id, eager="icon") + for id_ in self.ROOT_MARKET_GROUPS: + mg = self.getMarketGroup(id_, eager="icon") root.add(mg) return root @@ -698,15 +742,15 @@ class Market(): ship.race return ships - def getShipListDelayed(self, id, callback): + def getShipListDelayed(self, id_, callback): """Background version of getShipList""" - self.shipBrowserWorkerThread.queue.put((id, callback)) + self.shipBrowserWorkerThread.queue.put((id_, callback)) def searchShips(self, name): """Find ships according to given text pattern""" - filter = eos.types.Category.name.in_(["Ship", "Structure"]) - results = eos.db.searchItems(name, where=filter, - join=(eos.types.Item.group, eos.types.Group.category), + filter_ = types_Category.name.in_(["Ship", "Structure"]) + results = eos.db.searchItems(name, where=filter_, + join=(types_Item.group, types_Group.category), eager=("icon", "group.category", "metaGroup", "metaGroup.parent")) ships = set() for item in results: @@ -760,7 +804,7 @@ class Market(): if price is None: price = eos.db.getPrice(typeID) if price is None: - price = eos.types.Price(typeID) + price = types_Price(typeID) eos.db.add(price) self.priceCache[typeID] = price @@ -781,7 +825,7 @@ class Market(): def cb(): try: callback(requests) - except Exception, e: + except Exception: pass eos.db.commit() @@ -804,7 +848,7 @@ class Market(): def clearPriceCache(self): self.priceCache.clear() - deleted_rows = eos.db.clearPrices() + eos.db.clearPrices() def getSystemWideEffects(self): """ @@ -847,7 +891,7 @@ class Market(): groupname = re.sub(garbage, "", groupname) groupname = re.sub(" {2,}", " ", groupname).strip() # Add stuff to dictionary - if not groupname in effects: + if groupname not in effects: effects[groupname] = set() effects[groupname].add((beacon, beaconname, shortname)) # Break loop on 1st result diff --git a/service/network.py b/service/network.py index f7383e03d..481c77a41 100644 --- a/service/network.py +++ b/service/network.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2014 Ryan Holmes # # This file is part of pyfa. @@ -15,31 +15,38 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= + -from service.settings import NetworkSettings import urllib2 import urllib -import config import socket +import config +from service.settings import NetworkSettings + # network timeout, otherwise pyfa hangs for a long while if no internet connection timeout = 3 socket.setdefaulttimeout(timeout) + class Error(StandardError): def __init__(self, msg=None): self.message = msg + class RequestError(StandardError): pass + class AuthenticationError(StandardError): pass + class ServerError(StandardError): pass + class TimeoutError(StandardError): pass @@ -53,16 +60,17 @@ class Network(): UPDATE = 8 _instance = None + @classmethod def getInstance(cls): - if cls._instance == None: + if cls._instance is None: cls._instance = Network() return cls._instance def request(self, url, type, data=None): # URL is required to be https as of right now - #print "Starting request: %s\n\tType: %s\n\tPost Data: %s"%(url,type,data) + # print "Starting request: %s\n\tType: %s\n\tPost Data: %s"%(url,type,data) # Make sure request is enabled access = NetworkSettings.getInstance().getAccess() @@ -71,8 +79,9 @@ class Network(): raise Error("Access not enabled - please enable in Preferences > Network") # Set up some things for the request - versionString = "{0} {1} - {2} {3}".format(config.version, config.tag, config.expansionName, config.expansionVersion) - headers = {"User-Agent" : "pyfa {0} (Python-urllib2)".format(versionString)} + versionString = "{0} {1} - {2} {3}".format(config.version, config.tag, config.expansionName, + config.expansionVersion) + headers = {"User-Agent": "pyfa {0} (Python-urllib2)".format(versionString)} proxy = NetworkSettings.getInstance().getProxySettings() if proxy is not None: @@ -101,14 +110,14 @@ class Network(): request = urllib2.Request(url, headers=headers, data=urllib.urlencode(data) if data else None) try: return urllib2.urlopen(request) - except urllib2.HTTPError, error: + except urllib2.HTTPError as error: if error.code == 404: raise RequestError() elif error.code == 403: raise AuthenticationError() elif error.code >= 500: raise ServerError() - except urllib2.URLError, error: + except urllib2.URLError as error: if "timed out" in error.reason: raise TimeoutError() else: diff --git a/service/port.py b/service/port.py index f0b24306b..cbd24007d 100644 --- a/service/port.py +++ b/service/port.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2014 Ryan Holmes # # This file is part of pyfa. @@ -15,19 +15,32 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import re import os import xml.dom - -from eos.types import State, Slot, Module, Cargo, Fit, Ship, Drone, Implant, Booster, Citadel, Fighter -import service -import wx import logging -import config import collections import json +import threading +import locale + +from codecs import open + +import xml.parsers.expat + +from eos import db +from service.fit import Fit as svcFit + +import wx + +from eos.types import State, Slot, Module, Cargo, Ship, Drone, Implant, Booster, Citadel, Fighter, Fit + +if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3, 0)): + from service.crest import Crest + +from service.market import Market logger = logging.getLogger("pyfa.service.port") @@ -38,18 +51,142 @@ except ImportError: EFT_SLOT_ORDER = [Slot.LOW, Slot.MED, Slot.HIGH, Slot.RIG, Slot.SUBSYSTEM] INV_FLAGS = { - Slot.LOW: 11, - Slot.MED: 19, - Slot.HIGH: 27, - Slot.RIG: 92, - Slot.SUBSYSTEM: 125} + Slot.LOW: 11, + Slot.MED: 19, + Slot.HIGH: 27, + Slot.RIG: 92, + Slot.SUBSYSTEM: 125 +} INV_FLAG_CARGOBAY = 5 INV_FLAG_DRONEBAY = 87 INV_FLAG_FIGHTER = 158 + class Port(object): + instance = None + + @classmethod + def getInstance(cls): + if cls.instance is None: + cls.instance = Port() + + return cls.instance + + def backupFits(self, path, callback): + thread = FitBackupThread(path, callback) + thread.start() + + def importFitsThreaded(self, paths, callback): + thread = FitImportThread(paths, callback) + thread.start() + + def importFitFromFiles(self, paths, callback=None): + """ + Imports fits from file(s). First processes all provided paths and stores + assembled fits into a list. This allows us to call back to the GUI as + fits are processed as well as when fits are being saved. + returns + """ + defcodepage = locale.getpreferredencoding() + sFit = svcFit.getInstance() + + fits = [] + for path in paths: + if callback: # Pulse + wx.CallAfter(callback, 1, "Processing file:\n%s" % path) + + file_ = open(path, "r") + srcString = file_.read() + + if len(srcString) == 0: # ignore blank files + continue + + codec_found = None + # If file had ANSI encoding, decode it to unicode using detection + # of BOM header or if there is no header try default + # codepage then fallback to utf-16, cp1252 + + if isinstance(srcString, str): + encoding_map = ( + ('\xef\xbb\xbf', 'utf-8'), + ('\xff\xfe\0\0', 'utf-32'), + ('\0\0\xfe\xff', 'UTF-32BE'), + ('\xff\xfe', 'utf-16'), + ('\xfe\xff', 'UTF-16BE')) + + for bom, encoding in encoding_map: + if srcString.startswith(bom): + codec_found = encoding + savebom = bom + + if codec_found is None: + logger.info("Unicode BOM not found in file %s.", path) + attempt_codecs = (defcodepage, "utf-8", "utf-16", "cp1252") + + for page in attempt_codecs: + try: + logger.info("Attempting to decode file %s using %s page.", path, page) + srcString = unicode(srcString, page) + codec_found = page + logger.info("File %s decoded using %s page.", path, page) + except UnicodeDecodeError: + logger.info("Error unicode decoding %s from page %s, trying next codec", path, page) + else: + break + else: + logger.info("Unicode BOM detected in %s, using %s page.", path, codec_found) + srcString = unicode(srcString[len(savebom):], codec_found) + + else: + # nasty hack to detect other transparent utf-16 loading + if srcString[0] == '<' and 'utf-16' in srcString[:128].lower(): + codec_found = "utf-16" + else: + codec_found = "utf-8" + + if codec_found is None: + return False, "Proper codec could not be established for %s" % path + + try: + _, fitsImport = Port.importAuto(srcString, path, callback=callback, encoding=codec_found) + fits += fitsImport + except xml.parsers.expat.ExpatError: + return False, "Malformed XML in %s" % path + except Exception: + logger.exception("Unknown exception processing: %s", path) + return False, "Unknown Error while processing %s" % path + + IDs = [] + numFits = len(fits) + for i, fit in enumerate(fits): + # Set some more fit attributes and save + fit.character = sFit.character + fit.damagePattern = sFit.pattern + fit.targetResists = sFit.targetResists + db.save(fit) + IDs.append(fit.ID) + if callback: # Pulse + wx.CallAfter( + callback, 1, + "Processing complete, saving fits to database\n(%d/%d)" % + (i + 1, numFits) + ) + + return True, fits + + def importFitFromBuffer(self, bufferStr, activeFit=None): + sFit = svcFit.getInstance() + _, fits = Port.importAuto(bufferStr, activeFit=activeFit) + for fit in fits: + fit.character = sFit.character + fit.damagePattern = sFit.pattern + fit.targetResists = sFit.targetResists + db.save(fit) + return fits + """Service which houses all import/export format functions""" + @classmethod def exportCrest(cls, ofit, callback=None): # A few notes: @@ -58,19 +195,19 @@ class Port(object): nested_dict = lambda: collections.defaultdict(nested_dict) fit = nested_dict() - sCrest = service.Crest.getInstance() - sFit = service.Fit.getInstance() + sCrest = Crest.getInstance() + sFit = svcFit.getInstance() eve = sCrest.eve # max length is 50 characters name = ofit.name[:47] + '...' if len(ofit.name) > 50 else ofit.name fit['name'] = name - fit['ship']['href'] = "%sinventory/types/%d/"%(eve._authed_endpoint, ofit.ship.item.ID) + fit['ship']['href'] = "%sinventory/types/%d/" % (eve._authed_endpoint, ofit.ship.item.ID) fit['ship']['id'] = ofit.ship.item.ID fit['ship']['name'] = '' - fit['description'] = ""%ofit.ID + fit['description'] = "" % ofit.ID fit['items'] = [] slotNum = {} @@ -87,20 +224,20 @@ class Port(object): slot = int(module.getModifiedItemAttr("subSystemSlot")) item['flag'] = slot else: - if not slot in slotNum: + if slot not in slotNum: slotNum[slot] = INV_FLAGS[slot] item['flag'] = slotNum[slot] slotNum[slot] += 1 item['quantity'] = 1 - item['type']['href'] = "%sinventory/types/%d/"%(eve._authed_endpoint, module.item.ID) + item['type']['href'] = "%sinventory/types/%d/" % (eve._authed_endpoint, module.item.ID) item['type']['id'] = module.item.ID item['type']['name'] = '' fit['items'].append(item) if module.charge and sFit.serviceFittingOptions["exportCharges"]: - if not module.chargeID in charges: + 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 @@ -109,7 +246,7 @@ class Port(object): item = nested_dict() item['flag'] = INV_FLAG_CARGOBAY item['quantity'] = cargo.amount - item['type']['href'] = "%sinventory/types/%d/"%(eve._authed_endpoint, cargo.item.ID) + item['type']['href'] = "%sinventory/types/%d/" % (eve._authed_endpoint, cargo.item.ID) item['type']['id'] = cargo.item.ID item['type']['name'] = '' fit['items'].append(item) @@ -118,7 +255,7 @@ class Port(object): item = nested_dict() item['flag'] = INV_FLAG_CARGOBAY item['quantity'] = amount - item['type']['href'] = "%sinventory/types/%d/"%(eve._authed_endpoint, chargeID) + item['type']['href'] = "%sinventory/types/%d/" % (eve._authed_endpoint, chargeID) item['type']['id'] = chargeID item['type']['name'] = '' fit['items'].append(item) @@ -127,7 +264,7 @@ class Port(object): item = nested_dict() item['flag'] = INV_FLAG_DRONEBAY item['quantity'] = drone.amount - item['type']['href'] = "%sinventory/types/%d/"%(eve._authed_endpoint, drone.item.ID) + item['type']['href'] = "%sinventory/types/%d/" % (eve._authed_endpoint, drone.item.ID) item['type']['id'] = drone.item.ID item['type']['name'] = '' fit['items'].append(item) @@ -136,7 +273,7 @@ class Port(object): item = nested_dict() item['flag'] = INV_FLAG_FIGHTER item['quantity'] = fighter.amountActive - item['type']['href'] = "%sinventory/types/%d/"%(eve._authed_endpoint, fighter.item.ID) + item['type']['href'] = "%sinventory/types/%d/" % (eve._authed_endpoint, fighter.item.ID) item['type']['id'] = fighter.item.ID item['type']['name'] = fighter.item.name fit['items'].append(item) @@ -176,9 +313,9 @@ class Port(object): return "DNA", (cls.importDna(string),) @staticmethod - def importCrest(str): - fit = json.loads(str) - sMkt = service.Market.getInstance() + def importCrest(str_): + fit = json.loads(str_) + sMkt = Market.getInstance() f = Fit() f.name = fit['name'] @@ -229,7 +366,7 @@ class Port(object): continue # Recalc to get slot numbers correct for T3 cruisers - service.Fit.getInstance().recalc(f) + svcFit.getInstance().recalc(f) for module in moduleList: if module.fits(f): @@ -239,19 +376,19 @@ class Port(object): @staticmethod def importDna(string): - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() ids = map(int, re.findall(r'\d+', string)) - for id in ids: + for id_ in ids: try: try: try: - Ship(sMkt.getItem(sMkt.getItem(id))) + Ship(sMkt.getItem(sMkt.getItem(id_))) except ValueError: - Citadel(sMkt.getItem(sMkt.getItem(id))) + Citadel(sMkt.getItem(sMkt.getItem(id_))) except ValueError: - Citadel(sMkt.getItem(id)) - string = string[string.index(str(id)):] + Citadel(sMkt.getItem(id_)) + string = string[string.index(str(id_)):] break except: pass @@ -265,12 +402,13 @@ class Port(object): except ValueError: f.ship = Citadel(sMkt.getItem(int(info[0]))) f.name = "{0} - DNA Imported".format(f.ship.item.name) - except UnicodeEncodeError as e: - def logtransform(s): - if len(s) > 10: - return s[:10] + "..." - return s - logger.exception("Couldn't import ship data %r", [ logtransform(s) for s in info ]) + except UnicodeEncodeError: + def logtransform(s_): + if len(s_) > 10: + return s_[:10] + "..." + return s_ + + logger.exception("Couldn't import ship data %r", [logtransform(s) for s in info]) return None moduleList = [] @@ -309,7 +447,7 @@ class Port(object): moduleList.append(m) # Recalc to get slot numbers correct for T3 cruisers - service.Fit.getInstance().recalc(f) + svcFit.getInstance().recalc(f) for module in moduleList: if module.fits(f): @@ -322,7 +460,7 @@ class Port(object): @staticmethod def importEft(eftString): - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() offineSuffix = " /OFFLINE" fit = Fit() @@ -389,20 +527,20 @@ class Port(object): if item.category.name == "Drone": extraAmount = int(extraAmount) if extraAmount is not None else 1 - if not modName in droneMap: + 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 + 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 not modName in cargoMap: + if modName not in cargoMap: cargoMap[modName] = 0 cargoMap[modName] += extraAmount elif item.category.name == "Implant": @@ -446,13 +584,13 @@ class Port(object): moduleList.append(m) # Recalc to get slot numbers correct for T3 cruisers - service.Fit.getInstance().recalc(fit) + svcFit.getInstance().recalc(fit) for m in moduleList: if m.fits(fit): m.owner = fit if not m.isValidState(m.state): - print "Error: Module", m, "cannot have state", m.state + print("Error: Module", m, "cannot have state", m.state) fit.modules.append(m) @@ -473,7 +611,7 @@ class Port(object): """Handle import from EFT config store file""" # Check if we have such ship in database, bail if we don't - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() try: sMkt.getItem(shipname) except: @@ -632,7 +770,7 @@ class Port(object): moduleList.append(m) # Recalc to get slot numbers correct for T3 cruisers - service.Fit.getInstance().recalc(f) + svcFit.getInstance().recalc(f) for module in moduleList: if module.fits(f): @@ -651,7 +789,7 @@ class Port(object): @staticmethod def importXml(text, callback=None, encoding="utf-8"): - sMkt = service.Market.getInstance() + sMkt = Market.getInstance() doc = xml.dom.minidom.parseString(text.encode(encoding)) fittings = doc.getElementsByTagName("fittings").item(0) @@ -716,7 +854,7 @@ class Port(object): continue # Recalc to get slot numbers correct for T3 cruisers - service.Fit.getInstance().recalc(f) + svcFit.getInstance().recalc(f) for module in moduleList: if module.fits(f): @@ -734,12 +872,13 @@ class Port(object): offineSuffix = " /OFFLINE" export = "[%s, %s]\n" % (fit.ship.item.name, fit.name) stuff = {} - sFit = service.Fit.getInstance() + sFit = svcFit.getInstance() for module in fit.modules: slot = module.slot - if not slot in stuff: + if slot not in stuff: stuff[slot] = [] - curr = module.item.name if module.item else ("[Empty %s slot]" % Slot.getName(slot).capitalize() if slot is not None else "") + curr = module.item.name if module.item \ + else ("[Empty %s slot]" % Slot.getName(slot).capitalize() if slot is not None else "") if module.charge and sFit.serviceFittingOptions["exportCharges"]: curr += ", %s" % module.charge.name if module.state == State.OFFLINE: @@ -816,29 +955,27 @@ class Port(object): if mod.slot == Slot.SUBSYSTEM: subsystems.append(mod) continue - if not mod.itemID in mods: + if mod.itemID not in mods: mods[mod.itemID] = 0 mods[mod.itemID] += 1 if mod.charge: - if not mod.chargeID in charges: + 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")): + 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]) - # drones are known to be in split stacks - groupedDrones = OrderedDict() for drone in fit.drones: - groupedDrones[drone.itemID] = groupedDrones.get(drone.itemID, 0) + drone.amount + dna += ":{0};{1}".format(drone.itemID, drone.amount) - for droneItemID in groupedDrones: - dna += ":{0};{1}".format(droneItemID, groupedDrones[droneItemID]) + 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) @@ -850,7 +987,7 @@ class Port(object): # 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 not cargo.item.ID in charges: + if cargo.item.ID not in charges: charges[cargo.item.ID] = 0 charges[cargo.item.ID] += cargo.amount @@ -864,7 +1001,7 @@ class Port(object): doc = xml.dom.minidom.Document() fittings = doc.createElement("fittings") doc.appendChild(fittings) - sFit = service.Fit.getInstance() + sFit = svcFit.getInstance() for i, fit in enumerate(fits): try: @@ -890,7 +1027,7 @@ class Port(object): # Order of subsystem matters based on this attr. See GH issue #130 slotId = module.getModifiedItemAttr("subSystemSlot") - 125 else: - if not slot in slotNum: + if slot not in slotNum: slotNum[slot] = 0 slotId = slotNum[slot] @@ -904,7 +1041,7 @@ class Port(object): fitting.appendChild(hardware) if module.charge and sFit.serviceFittingOptions["exportCharges"]: - if not module.charge.name in charges: + 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 @@ -924,7 +1061,7 @@ class Port(object): fitting.appendChild(hardware) for cargo in fit.cargo: - if not cargo.item.name in charges: + if cargo.item.name not in charges: charges[cargo.item.name] = 0 charges[cargo.item.name] += cargo.amount @@ -935,7 +1072,7 @@ class Port(object): hardware.setAttribute("type", name) fitting.appendChild(hardware) except: - print "Failed on fitID: %d"%fit.ID + print("Failed on fitID: %d" % fit.ID) continue finally: if callback: @@ -947,13 +1084,12 @@ class Port(object): def exportMultiBuy(fit): export = "%s\n" % (fit.ship.item.name) stuff = {} - sFit = service.Fit.getInstance() + sFit = svcFit.getInstance() for module in fit.modules: slot = module.slot - if not slot in stuff: + if slot not in stuff: stuff[slot] = [] - curr = "%s\n" % module.item.name if module.item else ( - "") + 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) @@ -989,3 +1125,39 @@ class Port(object): export = export[:-1] return export + + +class FitBackupThread(threading.Thread): + def __init__(self, path, callback): + threading.Thread.__init__(self) + self.path = path + self.callback = callback + + def run(self): + path = self.path + sFit = svcFit.getInstance() + sPort = Port.getInstance() + backedUpFits = sPort.exportXml(self.callback, *sFit.getAllFits()) + backupFile = open(path, "w", encoding="utf-8") + backupFile.write(backedUpFits) + backupFile.close() + + # Send done signal to GUI + wx.CallAfter(self.callback, -1) + + +class FitImportThread(threading.Thread): + def __init__(self, paths, callback): + threading.Thread.__init__(self) + self.paths = paths + self.callback = callback + + def run(self): + sPort = Port.getInstance() + success, result = sPort.importFitFromFiles(self.paths, self.callback) + + if not success: # there was an error during processing + logger.error("Error while processing file import: %s", result) + wx.CallAfter(self.callback, -2, result) + else: # Send done signal to GUI + wx.CallAfter(self.callback, -1, result) diff --git a/service/prefetch.py b/service/prefetch.py index a3efb38e2..cf40f90f8 100644 --- a/service/prefetch.py +++ b/service/prefetch.py @@ -1,68 +1,72 @@ -#=============================================================================== -# 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 threading -import config -import os -import eos.types -import eos.db.migration as migration -from eos.db.saveddata.loadDefaultDatabaseValues import DefaultDatabaseValues -from eos.db.saveddata.databaseRepair import DatabaseCleanup -import logging - -logger = logging.getLogger(__name__) - -######## -# The following code does not belong here, however until we rebuild skeletons -# to include modified pyfa.py, this is the best place to put it. See GH issue -# #176 -# @ todo: move this to pyfa.py -######## - -#Make sure the saveddata db exists -if not os.path.exists(config.savePath): - os.mkdir(config.savePath) - -if os.path.isfile(config.saveDB): - # If database exists, run migration after init'd database - eos.db.saveddata_meta.create_all() - migration.update(eos.db.saveddata_engine) - # Import default database values - # Import values that must exist otherwise Pyfa breaks - DefaultDatabaseValues.importRequiredDefaults() - - logging.debug("Starting database validation.") - database_cleanup_instance = DatabaseCleanup() - database_cleanup_instance.OrphanedCharacterSkills(eos.db.saveddata_engine) - database_cleanup_instance.OrphanedFitCharacterIDs(eos.db.saveddata_engine) - database_cleanup_instance.OrphanedFitDamagePatterns(eos.db.saveddata_engine) - logging.debug("Completed database validation.") - -else: - # If database does not exist, do not worry about migration. Simply - # create and set version - eos.db.saveddata_meta.create_all() - eos.db.saveddata_engine.execute('PRAGMA user_version = {}'.format(migration.getAppVersion())) - #Import default database values - # Import values that must exist otherwise Pyfa breaks - DefaultDatabaseValues.importRequiredDefaults() - # Import default values for damage profiles - DefaultDatabaseValues.importDamageProfileDefaults() - # Import default values for target resist profiles - DefaultDatabaseValues.importResistProfileDefaults() +# ============================================================================= +# 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 threading +import os + +import config +from eos import db +from eos.db import migration +from eos.db.saveddata.loadDefaultDatabaseValues import DefaultDatabaseValues +from eos.db.saveddata.databaseRepair import DatabaseCleanup +from eos.saveddata.character import Character as es_Character + +import logging + +logger = logging.getLogger(__name__) + +# The following code does not belong here, however until we rebuild skeletons +# to include modified pyfa.py, this is the best place to put it. See GH issue +# #176 +# @ todo: move this to pyfa.py + +# Make sure the saveddata db exists +if config.savePath and not os.path.exists(config.savePath): + os.mkdir(config.savePath) + +if config.saveDB and os.path.isfile(config.saveDB): + # If database exists, run migration after init'd database + db.saveddata_meta.create_all() + migration.update(db.saveddata_engine) + # Import default database values + # Import values that must exist otherwise Pyfa breaks + DefaultDatabaseValues.importRequiredDefaults() + + # Finds and fixes database corruption issues. + logging.debug("Starting database validation.") + database_cleanup_instance = DatabaseCleanup() + database_cleanup_instance.OrphanedCharacterSkills(db.saveddata_engine) + database_cleanup_instance.OrphanedFitCharacterIDs(db.saveddata_engine) + database_cleanup_instance.OrphanedFitDamagePatterns(db.saveddata_engine) + database_cleanup_instance.NullDamagePatternNames(db.saveddata_engine) + database_cleanup_instance.NullTargetResistNames(db.saveddata_engine) + logging.debug("Completed database validation.") + +else: + # If database does not exist, do not worry about migration. Simply + # create and set version + db.saveddata_meta.create_all() + db.saveddata_engine.execute('PRAGMA user_version = {}'.format(migration.getAppVersion())) + # Import default database values + # Import values that must exist otherwise Pyfa breaks + DefaultDatabaseValues.importRequiredDefaults() + # Import default values for damage profiles + DefaultDatabaseValues.importDamageProfileDefaults() + # Import default values for target resist profiles + DefaultDatabaseValues.importResistProfileDefaults() diff --git a/service/price.py b/service/price.py index 71858cf7c..e3d39d734 100644 --- a/service/price.py +++ b/service/price.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,20 +15,21 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= + -import service -import eos.db -import eos.types import time from xml.dom import minidom -VALIDITY = 24*60*60 # Price validity period, 24 hours -REREQUEST = 4*60*60 # Re-request delay for failed fetches, 4 hours -TIMEOUT = 15*60 # Network timeout delay for connection issues, 15 minutes +from eos import db +from service.network import Network, TimeoutError -class Price(): +VALIDITY = 24 * 60 * 60 # Price validity period, 24 hours +REREQUEST = 4 * 60 * 60 # Re-request delay for failed fetches, 4 hours +TIMEOUT = 15 * 60 # Network timeout delay for connection issues, 15 minutes + +class Price(object): @classmethod def fetchPrices(cls, prices): """Fetch all prices passed to this method""" @@ -49,7 +50,7 @@ class Price(): # Compose list of items we're going to request for typeID in priceMap: # Get item object - item = eos.db.getItem(typeID) + item = db.getItem(typeID) # We're not going to request items only with market group, as eve-central # doesn't provide any data for items not on the market if item is not None and item.marketGroupID: @@ -64,22 +65,22 @@ class Price(): # Base request URL baseurl = "https://eve-central.com/api/marketstat" - data.append(("usesystem", 30000142)) # Use Jita for market + data.append(("usesystem", 30000142)) # Use Jita for market for typeID in toRequest: # Add all typeID arguments data.append(("typeid", typeID)) # Attempt to send request and process it try: - network = service.Network.getInstance() + network = Network.getInstance() data = network.request(baseurl, network.PRICES, data) xml = minidom.parse(data) types = xml.getElementsByTagName("marketstat").item(0).getElementsByTagName("type") # Cycle through all types we've got from request - for type in types: + for type_ in types: # Get data out of each typeID details tree - typeID = int(type.getAttribute("id")) - sell = type.getElementsByTagName("sell").item(0) + typeID = int(type_.getAttribute("id")) + sell = type_.getElementsByTagName("sell").item(0) # If price data wasn't there, set price to zero try: percprice = float(sell.getElementsByTagName("percentile").item(0).firstChild.data) @@ -96,7 +97,7 @@ class Price(): del priceMap[typeID] # If getting or processing data returned any errors - except service.network.TimeoutError, e: + except TimeoutError: # Timeout error deserves special treatment for typeID in priceMap.keys(): priceobj = priceMap[typeID] diff --git a/service/pycrest/__init__.py b/service/pycrest/__init__.py index 97244c957..f083e1f84 100644 --- a/service/pycrest/__init__.py +++ b/service/pycrest/__init__.py @@ -5,9 +5,8 @@ class NullHandler(logging.Handler): def emit(self, record): pass + logger = logging.getLogger('pycrest') logger.addHandler(NullHandler()) version = "0.0.1" - -from .eve import EVE \ No newline at end of file diff --git a/service/pycrest/compat.py b/service/pycrest/compat.py index 06320069b..7484b41dd 100644 --- a/service/pycrest/compat.py +++ b/service/pycrest/compat.py @@ -21,4 +21,4 @@ def text_(s, encoding='latin-1', errors='strict'): # pragma: no cover def bytes_(s, encoding='latin-1', errors='strict'): # pragma: no cover if isinstance(s, text_type): return s.encode(encoding, errors) - return s \ No newline at end of file + return s diff --git a/service/pycrest/errors.py b/service/pycrest/errors.py index 33b9ca9ae..4216deabb 100644 --- a/service/pycrest/errors.py +++ b/service/pycrest/errors.py @@ -1,2 +1,2 @@ class APIException(Exception): - pass \ No newline at end of file + pass diff --git a/service/pycrest/eve.py b/service/pycrest/eve.py index c0f33becd..5f6fa9ffc 100644 --- a/service/pycrest/eve.py +++ b/service/pycrest/eve.py @@ -1,15 +1,17 @@ -import os import base64 +import logging +import os +import re import time import zlib import requests - -from . import version -from compat import bytes_, text_ -from errors import APIException from requests.adapters import HTTPAdapter +import config +from service.pycrest.compat import bytes_, text_ +from service.pycrest.errors import APIException + try: from urllib.parse import urlparse, urlunparse, parse_qsl except ImportError: # pragma: no cover @@ -51,7 +53,7 @@ class FileCache(APICache): os.mkdir(self.path, 0o700) def _getpath(self, key): - return os.path.join(self.path, str(hash(key)) + '.cache') + return config.parsePath(self.path, str(hash(key)) + '.cache') def put(self, key, value): with open(self._getpath(key), 'wb') as f: @@ -110,8 +112,7 @@ class APIConnection(object): "Accept": "application/json", }) session.headers.update(additional_headers) - session.mount('https://public-crest.eveonline.com', - HTTPAdapter()) + session.mount('https://public-crest.eveonline.com', HTTPAdapter()) self._session = session if cache: if isinstance(cache, APICache): @@ -249,19 +250,18 @@ class EVE(APIConnection): def temptoken_authorize(self, access_token=None, expires_in=0, refresh_token=None): self.set_auth_values({'access_token': access_token, - 'refresh_token': refresh_token, - 'expires_in': expires_in}) + 'refresh_token': refresh_token, + 'expires_in': expires_in}) class AuthedConnection(EVE): - def __call__(self): if not self._data: self._data = APIObject(self.get(self._endpoint), self) return self._data def whoami(self): - #if 'whoami' not in self._cache: + # if 'whoami' not in self._cache: # print "Setting this whoami cache" # self._cache['whoami'] = self.get("%s/verify" % self._oauth_endpoint) return self.get("%s/verify" % self._oauth_endpoint) @@ -281,6 +281,7 @@ class AuthedConnection(EVE): self.refr_authorize(self.refresh_token) return self._session.delete(resource, params=params) + class APIObject(object): def __init__(self, parent, connection): self._dict = {} diff --git a/service/pycrest/weak_ciphers.py b/service/pycrest/weak_ciphers.py index 03de8321a..48da3c909 100644 --- a/service/pycrest/weak_ciphers.py +++ b/service/pycrest/weak_ciphers.py @@ -1,36 +1,26 @@ import datetime import ssl -import sys import warnings from requests.adapters import HTTPAdapter try: - from requests.packages import urllib3 - from requests.packages.urllib3.util import ssl_ - - from requests.packages.urllib3.exceptions import ( - SystemTimeWarning, - SecurityWarning, - ) - from requests.packages.urllib3.packages.ssl_match_hostname import \ - match_hostname + from requests.packages import urllib3 + from requests.packages.urllib3.util import ssl_ + from requests.packages.urllib3.exceptions import ( + SystemTimeWarning, + SecurityWarning, + ) + from requests.packages.urllib3.packages.ssl_match_hostname import \ + match_hostname except: - import urllib3 - from urllib3.util import ssl_ - - from urllib3.exceptions import ( - SystemTimeWarning, - SecurityWarning, - ) - from urllib3.packages.ssl_match_hostname import \ - match_hostname + import urllib3 + from urllib3.util import ssl_ + from urllib3.exceptions import SystemTimeWarning, SecurityWarning + from urllib3.packages.ssl_match_hostname import match_hostname - - -class WeakCiphersHTTPSConnection( - urllib3.connection.VerifiedHTTPSConnection): # pragma: no cover +class WeakCiphersHTTPSConnection(urllib3.connection.VerifiedHTTPSConnection): # pragma: no cover # Python versions >=2.7.9 and >=3.4.1 do not (by default) allow ciphers # with MD5. Unfortunately, the CREST public server _only_ supports @@ -77,22 +67,26 @@ class WeakCiphersHTTPSConnection( warnings.warn(( 'System time is way off (before {0}). This will probably ' 'lead to SSL verification errors').format( - urllib3.connection.RECENT_DATE), + urllib3.connection.RECENT_DATE), SystemTimeWarning ) # Wrap socket using verification with the root certs in # trusted_root_certs - self.sock = ssl_.ssl_wrap_socket(conn, self.key_file, self.cert_file, - cert_reqs=resolved_cert_reqs, - ca_certs=self.ca_certs, - server_hostname=hostname, - ssl_version=resolved_ssl_version, - ciphers=self.ciphers) + self.sock = ssl_.ssl_wrap_socket( + conn, + self.key_file, + self.cert_file, + cert_reqs=resolved_cert_reqs, + ca_certs=self.ca_certs, + server_hostname=hostname, + ssl_version=resolved_ssl_version, + ciphers=self.ciphers, + ) if self.assert_fingerprint: ssl_.assert_fingerprint(self.sock.getpeercert(binary_form=True), - self.assert_fingerprint) + self.assert_fingerprint) elif resolved_cert_reqs != ssl.CERT_NONE \ and self.assert_hostname is not False: cert = self.sock.getpeercert() @@ -105,36 +99,34 @@ class WeakCiphersHTTPSConnection( ) match_hostname(cert, self.assert_hostname or hostname) - self.is_verified = (resolved_cert_reqs == ssl.CERT_REQUIRED - or self.assert_fingerprint is not None) + self.is_verified = (resolved_cert_reqs == ssl.CERT_REQUIRED or self.assert_fingerprint is not None) -class WeakCiphersHTTPSConnectionPool( - urllib3.connectionpool.HTTPSConnectionPool): - +class WeakCiphersHTTPSConnectionPool(urllib3.connectionpool.HTTPSConnectionPool): ConnectionCls = WeakCiphersHTTPSConnection class WeakCiphersPoolManager(urllib3.poolmanager.PoolManager): - def _new_pool(self, scheme, host, port): if scheme == 'https': - return WeakCiphersHTTPSConnectionPool(host, port, - **(self.connection_pool_kw)) - return super(WeakCiphersPoolManager, self)._new_pool(scheme, host, - port) + return WeakCiphersHTTPSConnectionPool(host, port, **(self.connection_pool_kw)) + return super(WeakCiphersPoolManager, self)._new_pool(scheme, host, port) class WeakCiphersAdapter(HTTPAdapter): """"Transport adapter" that allows us to use TLS_RSA_WITH_RC4_128_MD5.""" - def init_poolmanager(self, connections, maxsize, block=False, - **pool_kwargs): + def init_poolmanager(self, connections, maxsize, block=False, **pool_kwargs): # Rewrite of the requests.adapters.HTTPAdapter.init_poolmanager method # to use WeakCiphersPoolManager instead of urllib3's PoolManager self._pool_connections = connections self._pool_maxsize = maxsize self._pool_block = block - self.poolmanager = WeakCiphersPoolManager(num_pools=connections, - maxsize=maxsize, block=block, strict=True, **pool_kwargs) + self.poolmanager = WeakCiphersPoolManager( + num_pools=connections, + maxsize=maxsize, + block=block, + strict=True, + **pool_kwargs + ) diff --git a/service/server.py b/service/server.py index ed42d0082..268637515 100644 --- a/service/server.py +++ b/service/server.py @@ -2,13 +2,15 @@ import BaseHTTPServer import urlparse import socket import thread -import wx -from service.settings import CRESTSettings - import logging +import wx + +from service.settings import CRESTSettings + logger = logging.getLogger(__name__) +# noinspection PyPep8 HTML = ''' @@ -56,6 +58,7 @@ else { ''' + # https://github.com/fuzzysteve/CREST-Market-Downloader/ class AuthHandler(BaseHTTPServer.BaseHTTPRequestHandler): def do_GET(self): @@ -72,9 +75,9 @@ class AuthHandler(BaseHTTPServer.BaseHTTPRequestHandler): def log_message(self, format, *args): return + # http://code.activestate.com/recipes/425210-simple-stoppable-server-using-socket-timeout/ class StoppableHTTPServer(BaseHTTPServer.HTTPServer): - def server_bind(self): BaseHTTPServer.HTTPServer.server_bind(self) self.settings = CRESTSettings.getInstance() @@ -101,7 +104,7 @@ class StoppableHTTPServer(BaseHTTPServer.HTTPServer): self.run = False def handle_timeout(self): - #logger.debug("Number of tries: %d"%self.tries) + # logger.debug("Number of tries: %d"%self.tries) self.tries += 1 if self.tries == self.max_tries: logger.debug("Server timed out waiting for connection") @@ -116,9 +119,9 @@ class StoppableHTTPServer(BaseHTTPServer.HTTPServer): pass self.server_close() + if __name__ == "__main__": httpd = StoppableHTTPServer(('', 6461), AuthHandler) thread.start_new_thread(httpd.serve, ()) raw_input("Press to stop server\n") httpd.stop() - diff --git a/service/settings.py b/service/settings.py index 89f871973..1d5923985 100644 --- a/service/settings.py +++ b/service/settings.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. @@ -15,33 +15,36 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import cPickle import os.path -import config import urllib2 -class SettingsProvider(): - BASE_PATH = os.path.join(config.savePath, "settings") +import config + + +class SettingsProvider(object): + BASE_PATH = config.getSavePath("settings") settings = {} _instance = None + @classmethod def getInstance(cls): - if cls._instance == None: + if cls._instance is None: cls._instance = SettingsProvider() return cls._instance def __init__(self): if not os.path.exists(self.BASE_PATH): - os.mkdir(self.BASE_PATH); + os.mkdir(self.BASE_PATH) def getSettings(self, area, defaults=None): s = self.settings.get(area) if s is None: - p = os.path.join(self.BASE_PATH, area) + p = config.parsePath(self.BASE_PATH, area) if not os.path.exists(p): info = {} @@ -71,7 +74,8 @@ class SettingsProvider(): for settings in self.settings.itervalues(): settings.save() -class Settings(): + +class Settings(object): def __init__(self, location, info): self.location = location self.info = info @@ -111,17 +115,17 @@ class Settings(): return self.info.items() -class NetworkSettings(): +class NetworkSettings(object): _instance = None # constants for serviceNetworkDefaultSettings["mode"] parameter - PROXY_MODE_NONE = 0 # 0 - No proxy + PROXY_MODE_NONE = 0 # 0 - No proxy PROXY_MODE_AUTODETECT = 1 # 1 - Auto-detected proxy settings - PROXY_MODE_MANUAL = 2 # 2 - Manual proxy settings + PROXY_MODE_MANUAL = 2 # 2 - Manual proxy settings @classmethod def getInstance(cls): - if cls._instance == None: + if cls._instance is None: cls._instance = NetworkSettings() return cls._instance @@ -184,17 +188,16 @@ class NetworkSettings(): def setAccess(self, access): self.serviceNetworkSettings["access"] = access - def autodetect(self): + @staticmethod + def autodetect(): proxy = None - proxAddr = proxPort = "" proxydict = urllib2.ProxyHandler().proxies - txt = "Auto-detected: " validPrefixes = ("http", "https") for prefix in validPrefixes: - if not prefix in proxydict: + if prefix not in proxydict: continue proxyline = proxydict[prefix] proto = "{0}://".format(prefix) @@ -237,53 +240,58 @@ class NetworkSettings(): self.serviceNetworkSettings["password"] = password - -""" -Settings used by the HTML export feature. -""" -class HTMLExportSettings(): +class HTMLExportSettings(object): + """ + Settings used by the HTML export feature. + """ _instance = None @classmethod def getInstance(cls): - if cls._instance == None: + if cls._instance is None: cls._instance = HTMLExportSettings() return cls._instance def __init__(self): - serviceHTMLExportDefaultSettings = {"enabled": False, "path": config.pyfaPath + os.sep + 'pyfaFits.html', "minimal": False } - self.serviceHTMLExportSettings = SettingsProvider.getInstance().getSettings("pyfaServiceHTMLExportSettings", serviceHTMLExportDefaultSettings) + serviceHTMLExportDefaultSettings = { + "enabled": False, + "path": config.pyfaPath + os.sep + 'pyfaFits.html', + "minimal": False + } + self.serviceHTMLExportSettings = SettingsProvider.getInstance().getSettings( + "pyfaServiceHTMLExportSettings", + serviceHTMLExportDefaultSettings + ) def getEnabled(self): return self.serviceHTMLExportSettings["enabled"] def setEnabled(self, enabled): self.serviceHTMLExportSettings["enabled"] = enabled - - + def getMinimalEnabled(self): return self.serviceHTMLExportSettings["minimal"] def setMinimalEnabled(self, minimal): self.serviceHTMLExportSettings["minimal"] = minimal - def getPath(self): return self.serviceHTMLExportSettings["path"] def setPath(self, path): self.serviceHTMLExportSettings["path"] = path -""" -Settings used by update notification -""" -class UpdateSettings(): + +class UpdateSettings(object): + """ + Settings used by update notification + """ _instance = None @classmethod def getInstance(cls): - if cls._instance == None: + if cls._instance is None: cls._instance = UpdateSettings() return cls._instance @@ -293,8 +301,11 @@ class UpdateSettings(): # Updates are completely suppressed via network settings # prerelease - If True, suppress prerelease notifications # version - Set to release tag that user does not want notifications for - serviceUpdateDefaultSettings = {"prerelease": True, 'version': None } - self.serviceUpdateSettings = SettingsProvider.getInstance().getSettings("pyfaServiceUpdateSettings", serviceUpdateDefaultSettings) + serviceUpdateDefaultSettings = {"prerelease": True, 'version': None} + self.serviceUpdateSettings = SettingsProvider.getInstance().getSettings( + "pyfaServiceUpdateSettings", + serviceUpdateDefaultSettings + ) def get(self, type): return self.serviceUpdateSettings[type] @@ -302,7 +313,8 @@ class UpdateSettings(): def set(self, type, value): self.serviceUpdateSettings[type] = value -class CRESTSettings(): + +class CRESTSettings(object): _instance = None @classmethod @@ -313,13 +325,15 @@ class CRESTSettings(): return cls._instance def __init__(self): - # mode # 0 - Implicit authentication # 1 - User-supplied client details serviceCRESTDefaultSettings = {"mode": 0, "server": 0, "clientID": "", "clientSecret": "", "timeout": 60} - self.serviceCRESTSettings = SettingsProvider.getInstance().getSettings("pyfaServiceCRESTSettings", serviceCRESTDefaultSettings) + self.serviceCRESTSettings = SettingsProvider.getInstance().getSettings( + "pyfaServiceCRESTSettings", + serviceCRESTDefaultSettings + ) def get(self, type): return self.serviceCRESTSettings[type] @@ -327,5 +341,4 @@ class CRESTSettings(): def set(self, type, value): self.serviceCRESTSettings[type] = value - # @todo: migrate fit settings (from fit service) here? diff --git a/service/targetResists.py b/service/targetResists.py index 2640551f4..2a4863c5d 100644 --- a/service/targetResists.py +++ b/service/targetResists.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2014 Ryan Holmes # # This file is part of pyfa. @@ -15,17 +15,21 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= -import eos.db -import eos.types import copy +from eos import db +from eos.saveddata.targetResists import TargetResists as es_TargetResists + + class ImportError(Exception): pass -class TargetResists(): + +class TargetResists(object): instance = None + @classmethod def getInstance(cls): if cls.instance is None: @@ -34,31 +38,31 @@ class TargetResists(): return cls.instance def getTargetResistsList(self): - return eos.db.getTargetResistsList() + return db.getTargetResistsList() def getTargetResists(self, name): - return eos.db.getTargetResists(name) + return db.getTargetResists(name) def newPattern(self, name): - p = eos.types.TargetResists(0.0, 0.0, 0.0, 0.0) + p = es_TargetResists(0.0, 0.0, 0.0, 0.0) p.name = name - eos.db.save(p) + db.save(p) return p def renamePattern(self, p, newName): p.name = newName - eos.db.save(p) + db.save(p) def deletePattern(self, p): - eos.db.remove(p) + db.remove(p) def copyPattern(self, p): newP = copy.deepcopy(p) - eos.db.save(newP) + db.save(newP) return newP def saveChanges(self, p): - eos.db.save(p) + db.save(p) def importPatterns(self, text): lookup = {} @@ -66,23 +70,22 @@ class TargetResists(): for pattern in current: lookup[pattern.name] = pattern - imports, num = eos.types.TargetResists.importPatterns(text) + imports, num = es_TargetResists.importPatterns(text) for pattern in imports: if pattern.name in lookup: match = lookup[pattern.name] match.__dict__.update(pattern.__dict__) else: - eos.db.save(pattern) - eos.db.commit() + db.save(pattern) + db.commit() lenImports = len(imports) if lenImports == 0: raise ImportError("No patterns found for import") if lenImports != num: - raise ImportError("%d patterns imported from clipboard; %d had errors"%(num, num-lenImports)) + raise ImportError("%d patterns imported from clipboard; %d had errors" % (num, num - lenImports)) def exportPatterns(self): patterns = self.getTargetResistsList() patterns.sort(key=lambda p: p.name) - return eos.types.TargetResists.exportPatterns(*patterns) - + return es_TargetResists.exportPatterns(*patterns) diff --git a/service/update.py b/service/update.py index 9025a6583..2c09910d7 100644 --- a/service/update.py +++ b/service/update.py @@ -1,4 +1,4 @@ -#=============================================================================== +# ============================================================================= # Copyright (C) 2014 Ryan Holmes # # This file is part of pyfa. @@ -15,32 +15,38 @@ # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . -#=============================================================================== +# ============================================================================= import threading -import wx -import urllib2 import json -import config -import service -import dateutil.parser import calendar +import wx +import dateutil.parser + +import config +from service.network import Network +from service.settings import UpdateSettings + + class CheckUpdateThread(threading.Thread): def __init__(self, callback): threading.Thread.__init__(self) self.name = "CheckUpdate" self.callback = callback - self.settings = service.settings.UpdateSettings.getInstance() - self.network = service.Network.getInstance() + self.settings = UpdateSettings.getInstance() + self.network = Network.getInstance() def run(self): - network = service.Network.getInstance() + network = Network.getInstance() try: response = network.request('https://api.github.com/repos/pyfa-org/Pyfa/releases', network.UPDATE) jsonResponse = json.loads(response.read()) - jsonResponse.sort(key=lambda x: calendar.timegm(dateutil.parser.parse(x['published_at']).utctimetuple()), reverse=True) + jsonResponse.sort( + key=lambda x: calendar.timegm(dateutil.parser.parse(x['published_at']).utctimetuple()), + reverse=True + ) for release in jsonResponse: # Suppress pre releases @@ -48,7 +54,7 @@ class CheckUpdateThread(threading.Thread): continue # Handle use-case of updating to suppressed version - if self.settings.get('version') == 'v'+config.version: + if self.settings.get('version') == 'v' + config.version: self.settings.set('version', None) # Suppress version @@ -61,16 +67,18 @@ class CheckUpdateThread(threading.Thread): else: rVersion = release['tag_name'].replace('v', '', 1) - if config.tag is 'git' and not release['prerelease'] and self.versiontuple(rVersion) >= self.versiontuple(config.version): - wx.CallAfter(self.callback, release) # git (dev/Singularity) -> Stable + if config.tag is 'git' and \ + not release['prerelease'] and \ + self.versiontuple(rVersion) >= self.versiontuple(config.version): + wx.CallAfter(self.callback, release) # git (dev/Singularity) -> Stable elif config.expansionName is not "Singularity": if release['prerelease']: - wx.CallAfter(self.callback, release) # Stable -> Singularity + wx.CallAfter(self.callback, release) # Stable -> Singularity elif self.versiontuple(rVersion) > self.versiontuple(config.version): - wx.CallAfter(self.callback, release) # Stable -> Stable + wx.CallAfter(self.callback, release) # Stable -> Stable else: if release['prerelease'] and rVersion > config.expansionVersion: - wx.CallAfter(self.callback, release) # Singularity -> Singularity + wx.CallAfter(self.callback, release) # Singularity -> Singularity break except: pass @@ -78,10 +86,9 @@ class CheckUpdateThread(threading.Thread): def versiontuple(self, v): return tuple(map(int, (v.split(".")))) + class Update(): instance = None - def __init__(self): - pass def CheckUpdate(self, callback): thread = CheckUpdateThread(callback) @@ -89,8 +96,6 @@ class Update(): @classmethod def getInstance(cls): - if cls.instance == None: + if cls.instance is None: cls.instance = Update() return cls.instance - - diff --git a/tests/test_package.py b/tests/test_package.py new file mode 100644 index 000000000..74450c866 --- /dev/null +++ b/tests/test_package.py @@ -0,0 +1,42 @@ +"""import tests.""" + +import os +import importlib + +import pytest + +import service +import gui +import eos +import utils + + +def test_packages(): + assert service + assert gui + assert eos + assert utils + +def service_modules(): + for root, folders, files in os.walk("service"): + for file_ in files: + if file_.endswith(".py") and not file_.startswith("_"): + mod_name = "{}.{}".format( + root.replace("/", "."), + file_.split(".py")[0], + ) + yield mod_name + +def eos_modules(): + for root, folders, files in os.walk("eos"): + for file_ in files: + if file_.endswith(".py") and not file_.startswith("_"): + mod_name = "{}.{}".format( + root.replace("/", "."), + file_.split(".py")[0], + ) + yield mod_name + +@pytest.mark.parametrize("mod_name", eos_modules()) +def test_service_imports(mod_name): + assert importlib.import_module(mod_name) diff --git a/tox.ini b/tox.ini new file mode 100644 index 000000000..ad49d6c5b --- /dev/null +++ b/tox.ini @@ -0,0 +1,15 @@ +[tox] +envlist = pep8 +skipsdist = True + +[testenv] +passenv = CI TRAVIS TRAVIS_* +deps = + -rrequirements.txt + -rrequirements_test.txt +basepython = python2.7 +commands = py.test -vv --cov Pyfa tests/ + +[testenv:pep8] +deps = flake8 +commands = flake8 --exclude=.svn,CVS,.bzr,.hg,.git,__pycache__,venv,tests,.tox,build,dist,__init__.py --ignore=E127,E501,E731,F401,F403,F405 service gui eos utils config.py pyfa.py --max-line-length=130 diff --git a/utils/compat.py b/utils/compat.py index d8177973b..bf49eb4aa 100644 --- a/utils/compat.py +++ b/utils/compat.py @@ -237,7 +237,7 @@ class OrderedDict(dict): ''' if isinstance(other, OrderedDict): - return len(self)==len(other) and self.items() == other.items() + return len(self) == len(other) and self.items() == other.items() return dict.__eq__(self, other) def __ne__(self, other): diff --git a/utils/timer.py b/utils/timer.py index c1ca87a8b..41b5f78b7 100644 --- a/utils/timer.py +++ b/utils/timer.py @@ -1,5 +1,6 @@ import time + class Timer(): def __init__(self, name='', logger=None): self.name = name @@ -9,11 +10,11 @@ class Timer(): @property def elapsed(self): - return (time.time() - self.start)*1000 + return (time.time() - self.start) * 1000 @property def last(self): - return (time.time() - self.__last)*1000 + return (time.time() - self.__last) * 1000 def checkpoint(self, name=''): text = u'Timer - {timer} - {checkpoint} - {last:.2f}ms ({elapsed:.2f}ms elapsed)'.format( @@ -26,7 +27,7 @@ class Timer(): if self.logger: self.logger.debug(text) else: - print text + print(text) def __enter__(self): return self