Merge branch 'development'
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -49,7 +49,6 @@ Pyfa.egg-info/
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
|
||||
93
config.py
93
config.py
@@ -1,17 +1,18 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
# TODO: move all logging back to pyfa.py main loop
|
||||
# We moved it here just to avoid rebuilding windows skeleton for now (any change to pyfa.py needs it)
|
||||
import logging
|
||||
import logging.handlers
|
||||
from logbook import Logger
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
# Load variable overrides specific to distribution type
|
||||
try:
|
||||
import configforced
|
||||
except ImportError:
|
||||
pyfalog.warning("Failed to import: configforced")
|
||||
configforced = None
|
||||
|
||||
|
||||
# Turns on debug mode
|
||||
debug = False
|
||||
# Defines if our saveddata will be in pyfa root or not
|
||||
@@ -30,22 +31,6 @@ saveDB = None
|
||||
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 = ''
|
||||
|
||||
def write(self, buf):
|
||||
for line in buf.rstrip().splitlines():
|
||||
self.logger.log(self.log_level, line.rstrip())
|
||||
|
||||
|
||||
def isFrozen():
|
||||
if hasattr(sys, 'frozen'):
|
||||
return True
|
||||
@@ -77,10 +62,7 @@ def defPaths(customSavePath):
|
||||
global gameDB
|
||||
global saveInRoot
|
||||
|
||||
if debug:
|
||||
logLevel = logging.DEBUG
|
||||
else:
|
||||
logLevel = logging.WARN
|
||||
pyfalog.debug("Configuring Pyfa")
|
||||
|
||||
# The main pyfa directory which contains run.py
|
||||
# Python 2.X uses ANSI by default, so we need to convert the character encoding
|
||||
@@ -107,26 +89,6 @@ def defPaths(customSavePath):
|
||||
os.environ["REQUESTS_CA_BUNDLE"] = os.path.join(pyfaPath, "cacert.pem").encode('utf8')
|
||||
os.environ["SSL_CERT_FILE"] = os.path.join(pyfaPath, "cacert.pem").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)
|
||||
handler.setFormatter(formatter)
|
||||
logging.getLogger('').addHandler(handler)
|
||||
|
||||
logging.info("Starting pyfa")
|
||||
|
||||
if hasattr(sys, 'frozen'):
|
||||
stdout_logger = logging.getLogger('STDOUT')
|
||||
sl = StreamToLogger(stdout_logger, logging.INFO)
|
||||
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
|
||||
|
||||
# The database where we store all the fits etc
|
||||
saveDB = os.path.join(savePath, "saveddata.db")
|
||||
|
||||
@@ -144,43 +106,6 @@ def defPaths(customSavePath):
|
||||
eos.config.saveddata_connectionstring = "sqlite:///" + saveDB + "?check_same_thread=False"
|
||||
eos.config.gamedata_connectionstring = "sqlite:///" + gameDB + "?check_same_thread=False"
|
||||
|
||||
|
||||
# Keeping disabled code here for now until we can determine with decent certainty that this isn't needed
|
||||
'''
|
||||
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
|
||||
'''
|
||||
# initialize the settings
|
||||
from service.settings import EOSSettings
|
||||
eos.config.settings = EOSSettings.getInstance().EOSSettings # this is kind of confusing, but whatever
|
||||
|
||||
5666
dist_assets/cacert.pem
Normal file
5666
dist_assets/cacert.pem
Normal file
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,9 @@ gamedata_connectionstring = 'sqlite:///' + unicode(realpath(join(dirname(abspath
|
||||
saveddata_connectionstring = 'sqlite:///' + unicode(
|
||||
realpath(join(dirname(abspath(__file__)), "..", "saveddata", "saveddata.db")), sys.getfilesystemencoding())
|
||||
|
||||
settings = {
|
||||
"setting1": True
|
||||
}
|
||||
|
||||
# Autodetect path, only change if the autodetection bugs out.
|
||||
path = dirname(unicode(__file__, sys.getfilesystemencoding()))
|
||||
|
||||
@@ -24,6 +24,9 @@ from sqlalchemy.orm import sessionmaker
|
||||
|
||||
import migration
|
||||
from eos import config
|
||||
from logbook import Logger
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class ReadOnlyException(Exception):
|
||||
@@ -46,7 +49,9 @@ try:
|
||||
config.gamedata_version = gamedata_session.execute(
|
||||
"SELECT `field_value` FROM `metadata` WHERE `field_name` LIKE 'client_build'"
|
||||
).fetchone()[0]
|
||||
except:
|
||||
except Exception as e:
|
||||
pyfalog.warning("Missing gamedata version.")
|
||||
pyfalog.critical(e)
|
||||
config.gamedata_version = None
|
||||
|
||||
saveddata_connectionstring = config.saveddata_connectionstring
|
||||
|
||||
@@ -23,6 +23,7 @@ from sqlalchemy.sql import and_, or_, select
|
||||
import eos.config
|
||||
from eos.db import gamedata_session
|
||||
from eos.db.gamedata.metaGroup import metatypes_table, items_table
|
||||
from eos.db.gamedata.group import groups_table
|
||||
from eos.db.util import processEager, processWhere
|
||||
from eos.gamedata import AlphaClone, Attribute, Category, Group, Item, MarketGroup, MetaGroup, AttributeInfo, MetaData
|
||||
|
||||
@@ -249,7 +250,7 @@ def searchItems(nameLike, where=None, join=None, eager=None):
|
||||
|
||||
|
||||
@cachedQuery(2, "where", "itemids")
|
||||
def getVariations(itemids, where=None, eager=None):
|
||||
def getVariations(itemids, groupIDs=None, where=None, eager=None):
|
||||
for itemid in itemids:
|
||||
if not isinstance(itemid, int):
|
||||
raise TypeError("All passed item IDs must be integers")
|
||||
@@ -262,7 +263,17 @@ def getVariations(itemids, where=None, eager=None):
|
||||
joinon = items_table.c.typeID == metatypes_table.c.typeID
|
||||
vars = gamedata_session.query(Item).options(*processEager(eager)).join((metatypes_table, joinon)).filter(
|
||||
filter).all()
|
||||
return vars
|
||||
|
||||
if vars:
|
||||
return vars
|
||||
elif groupIDs:
|
||||
itemfilter = or_(*(groups_table.c.groupID == groupID for groupID in groupIDs))
|
||||
filter = processWhere(itemfilter, where)
|
||||
joinon = items_table.c.groupID == groups_table.c.groupID
|
||||
vars = gamedata_session.query(Item).options(*processEager(eager)).join((groups_table, joinon)).filter(
|
||||
filter).all()
|
||||
|
||||
return vars
|
||||
|
||||
|
||||
@cachedQuery(1, "attr")
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import logging
|
||||
from logbook import Logger
|
||||
import shutil
|
||||
import time
|
||||
|
||||
import config
|
||||
import migrations
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
def getVersion(db):
|
||||
@@ -37,7 +37,7 @@ def update(saveddata_engine):
|
||||
for version in xrange(dbVersion, appVersion):
|
||||
func = migrations.updates[version + 1]
|
||||
if func:
|
||||
logger.info("Applying database update: %d", version + 1)
|
||||
pyfalog.info("Applying database update: {0}", version + 1)
|
||||
func(saveddata_engine)
|
||||
|
||||
# when all is said and done, set version to current
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
# ===============================================================================
|
||||
|
||||
from sqlalchemy.exc import DatabaseError
|
||||
import logging
|
||||
from logbook import Logger
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class DatabaseCleanup(object):
|
||||
@@ -33,7 +33,7 @@ class DatabaseCleanup(object):
|
||||
results = saveddata_engine.execute(query)
|
||||
return results
|
||||
except DatabaseError:
|
||||
logger.error("Failed to connect to database or error executing query:\n%s", query)
|
||||
pyfalog.error("Failed to connect to database or error executing query:\n{0}", query)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
@@ -41,7 +41,7 @@ class DatabaseCleanup(object):
|
||||
# Find orphaned character skills.
|
||||
# This solves an issue where the character doesn't exist, but skills for that character do.
|
||||
# See issue #917
|
||||
logger.debug("Running database cleanup for character skills.")
|
||||
pyfalog.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)
|
||||
|
||||
@@ -53,14 +53,14 @@ class DatabaseCleanup(object):
|
||||
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)
|
||||
pyfalog.error("Database corruption found. Cleaning up {0} 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
|
||||
logger.debug("Running database cleanup for orphaned damage patterns attached to fits.")
|
||||
pyfalog.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)
|
||||
|
||||
@@ -80,20 +80,20 @@ class DatabaseCleanup(object):
|
||||
rows = uniform_results.fetchall()
|
||||
|
||||
if len(rows) == 0:
|
||||
logger.error("Missing uniform damage pattern.")
|
||||
pyfalog.error("Missing uniform damage pattern.")
|
||||
elif len(rows) > 1:
|
||||
logger.error("More than one uniform damage pattern found.")
|
||||
pyfalog.error("More than one uniform damage pattern found.")
|
||||
else:
|
||||
uniform_damage_pattern_id = rows[0]['ID']
|
||||
update_query = "UPDATE 'fits' SET 'damagePatternID' = {} " \
|
||||
"WHERE damagePatternID NOT IN (SELECT ID FROM damagePatterns) OR damagePatternID IS NULL".format(uniform_damage_pattern_id)
|
||||
update_results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, update_query)
|
||||
logger.error("Database corruption found. Cleaning up %d records.", update_results.rowcount)
|
||||
pyfalog.error("Database corruption found. Cleaning up {0} 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.
|
||||
logger.debug("Running database cleanup for orphaned characters attached to fits.")
|
||||
pyfalog.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)
|
||||
|
||||
@@ -113,22 +113,22 @@ class DatabaseCleanup(object):
|
||||
rows = all5_results.fetchall()
|
||||
|
||||
if len(rows) == 0:
|
||||
logger.error("Missing 'All 5' character.")
|
||||
pyfalog.error("Missing 'All 5' character.")
|
||||
elif len(rows) > 1:
|
||||
logger.error("More than one 'All 5' character found.")
|
||||
pyfalog.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)
|
||||
pyfalog.error("Database corruption found. Cleaning up {0} 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.")
|
||||
pyfalog.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)
|
||||
|
||||
@@ -140,14 +140,14 @@ class DatabaseCleanup(object):
|
||||
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)
|
||||
pyfalog.error("Database corruption found. Cleaning up {0} 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.")
|
||||
pyfalog.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)
|
||||
|
||||
@@ -159,14 +159,14 @@ class DatabaseCleanup(object):
|
||||
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)
|
||||
pyfalog.error("Database corruption found. Cleaning up {0} records.", delete.rowcount)
|
||||
|
||||
@staticmethod
|
||||
def OrphanedFitIDItemID(saveddata_engine):
|
||||
# Orphaned items that are missing the fit ID or item ID.
|
||||
# See issue #954
|
||||
for table in ['drones', 'cargo', 'fighters']:
|
||||
logger.debug("Running database cleanup for orphaned %s items.", table)
|
||||
pyfalog.debug("Running database cleanup for orphaned {0} items.", table)
|
||||
query = "SELECT COUNT(*) AS num FROM {} WHERE itemID IS NULL OR itemID = '' or itemID = '0' or fitID IS NULL OR fitID = '' or fitID = '0'".format(
|
||||
table)
|
||||
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
@@ -180,10 +180,10 @@ class DatabaseCleanup(object):
|
||||
query = "DELETE FROM {} WHERE itemID IS NULL OR itemID = '' or itemID = '0' or fitID IS NULL OR fitID = '' or fitID = '0'".format(
|
||||
table)
|
||||
delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
logger.error("Database corruption found. Cleaning up %d records.", delete.rowcount)
|
||||
pyfalog.error("Database corruption found. Cleaning up {0} records.", delete.rowcount)
|
||||
|
||||
for table in ['modules']:
|
||||
logger.debug("Running database cleanup for orphaned %s items.", table)
|
||||
pyfalog.debug("Running database cleanup for orphaned {0} items.", table)
|
||||
query = "SELECT COUNT(*) AS num FROM {} WHERE itemID = '0' or fitID IS NULL OR fitID = '' or fitID = '0'".format(
|
||||
table)
|
||||
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
@@ -196,7 +196,7 @@ class DatabaseCleanup(object):
|
||||
if row and row['num']:
|
||||
query = "DELETE FROM {} WHERE itemID = '0' or fitID IS NULL OR fitID = '' or fitID = '0'".format(table)
|
||||
delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
logger.error("Database corruption found. Cleaning up %d records.", delete.rowcount)
|
||||
pyfalog.error("Database corruption found. Cleaning up {0} records.", delete.rowcount)
|
||||
|
||||
@staticmethod
|
||||
def NullDamageTargetPatternValues(saveddata_engine):
|
||||
@@ -204,7 +204,7 @@ class DatabaseCleanup(object):
|
||||
# See issue #954
|
||||
for profileType in ['damagePatterns', 'targetResists']:
|
||||
for damageType in ['em', 'thermal', 'kinetic', 'explosive']:
|
||||
logger.debug("Running database cleanup for null %s values. (%s)", profileType, damageType)
|
||||
pyfalog.debug("Running database cleanup for null {0} values. ({1})", profileType, damageType)
|
||||
query = "SELECT COUNT(*) AS num FROM {0} WHERE {1}Amount IS NULL OR {1}Amount = ''".format(profileType,
|
||||
damageType)
|
||||
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
@@ -218,13 +218,13 @@ class DatabaseCleanup(object):
|
||||
query = "UPDATE '{0}' SET '{1}Amount' = '0' WHERE {1}Amount IS NULL OR Amount = ''".format(profileType,
|
||||
damageType)
|
||||
delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
logger.error("Database corruption found. Cleaning up %d records.", delete.rowcount)
|
||||
pyfalog.error("Database corruption found. Cleaning up {0} records.", delete.rowcount)
|
||||
|
||||
@staticmethod
|
||||
def DuplicateSelectedAmmoName(saveddata_engine):
|
||||
# Orphaned items that are missing the fit ID or item ID.
|
||||
# See issue #954
|
||||
logger.debug("Running database cleanup for duplicated selected ammo profiles.")
|
||||
pyfalog.debug("Running database cleanup for duplicated selected ammo profiles.")
|
||||
query = "SELECT COUNT(*) AS num FROM damagePatterns WHERE name = 'Selected Ammo'"
|
||||
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
|
||||
@@ -236,4 +236,4 @@ class DatabaseCleanup(object):
|
||||
if row and row['num'] > 1:
|
||||
query = "DELETE FROM damagePatterns WHERE name = 'Selected Ammo'"
|
||||
delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
|
||||
logger.error("Database corruption found. Cleaning up %d records.", delete.rowcount)
|
||||
pyfalog.error("Database corruption found. Cleaning up {0} records.", delete.rowcount)
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
import logging
|
||||
from logbook import Logger
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class HandledList(list):
|
||||
@@ -198,7 +198,7 @@ class HandledImplantBoosterList(HandledList):
|
||||
# if needed, remove booster that was occupying slot
|
||||
oldObj = next((m for m in self if m.slot == thing.slot), None)
|
||||
if oldObj:
|
||||
logging.info("Slot %d occupied with %s, replacing with %s", thing.slot, oldObj.item.name, thing.item.name)
|
||||
pyfalog.info("Slot {0} occupied with {1}, replacing with {2}", thing.slot, oldObj.item.name, thing.item.name)
|
||||
oldObj.itemID = 0 # hack to remove from DB. See GH issue #324
|
||||
self.remove(oldObj)
|
||||
|
||||
@@ -222,7 +222,7 @@ class HandledProjectedModList(HandledList):
|
||||
oldEffect = next((m for m in self if m.item.group.name == "Effect Beacon"), None)
|
||||
|
||||
if oldEffect:
|
||||
logging.info("System effect occupied with %s, replacing with %s", oldEffect.item.name, proj.item.name)
|
||||
pyfalog.info("System effect occupied with {0}, replacing with {1}", oldEffect.item.name, proj.item.name)
|
||||
self.remove(oldEffect)
|
||||
|
||||
HandledList.append(self, proj)
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
#
|
||||
# Used by:
|
||||
# Module: Reactive Armor Hardener
|
||||
import logging
|
||||
from logbook import Logger
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
runTime = "late"
|
||||
type = "active"
|
||||
@@ -23,7 +23,7 @@ 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])
|
||||
# pyfalog.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
|
||||
@@ -39,7 +39,7 @@ def handler(fit, module, context):
|
||||
cycleList = []
|
||||
loopStart = -20
|
||||
for num in range(50):
|
||||
# logger.debug("Starting cycle %d.", num)
|
||||
# pyfalog.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 = [
|
||||
@@ -77,7 +77,7 @@ def handler(fit, module, context):
|
||||
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])
|
||||
# pyfalog.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):
|
||||
@@ -87,7 +87,7 @@ def handler(fit, module, context):
|
||||
abs(RAHResistance[2] - val[2]) <= tolerance and \
|
||||
abs(RAHResistance[3] - val[3]) <= tolerance:
|
||||
loopStart = i
|
||||
# logger.debug("Loop found: %d-%d", loopStart, num)
|
||||
# pyfalog.debug("Loop found: %d-%d", loopStart, num)
|
||||
break
|
||||
if loopStart >= 0:
|
||||
break
|
||||
@@ -95,7 +95,7 @@ def handler(fit, module, context):
|
||||
cycleList.append(list(RAHResistance))
|
||||
|
||||
if loopStart < 0:
|
||||
logger.error("Reactive Armor Hardener failed to find equilibrium. Damage profile after armor: %f/%f/%f/%f",
|
||||
pyfalog.error("Reactive Armor Hardener failed to find equilibrium. Damage profile after armor: {0}/{1}/{2}/{3}",
|
||||
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.
|
||||
@@ -110,7 +110,7 @@ def handler(fit, module, context):
|
||||
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])
|
||||
# pyfalog.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')):
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Tractor Beam (4 of 4)
|
||||
from eos.config import settings
|
||||
type = "active"
|
||||
|
||||
|
||||
def handler(fit, module, context):
|
||||
print settings['setting1']
|
||||
pass
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
# ===============================================================================
|
||||
|
||||
import re
|
||||
import traceback
|
||||
|
||||
from sqlalchemy.orm import reconstructor
|
||||
|
||||
@@ -30,6 +29,10 @@ try:
|
||||
except ImportError:
|
||||
from utils.compat import OrderedDict
|
||||
|
||||
from logbook import Logger
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class Effect(EqBase):
|
||||
"""
|
||||
@@ -64,6 +67,8 @@ class Effect(EqBase):
|
||||
if not self.__generated:
|
||||
self.__generateHandler()
|
||||
|
||||
pyfalog.debug("Generating effect: {0} ({1}) [runTime: {2}]", self.name, self.effectID, self.runTime)
|
||||
|
||||
return self.__handler
|
||||
|
||||
@property
|
||||
@@ -138,7 +143,7 @@ class Effect(EqBase):
|
||||
@property
|
||||
def isImplemented(self):
|
||||
"""
|
||||
Wether this effect is implemented in code or not,
|
||||
Whether this effect is implemented in code or not,
|
||||
unimplemented effects simply do nothing at all when run
|
||||
"""
|
||||
return self.handler != effectDummy
|
||||
@@ -156,36 +161,30 @@ class Effect(EqBase):
|
||||
"""
|
||||
try:
|
||||
self.__effectModule = effectModule = __import__('eos.effects.' + self.handlerName, fromlist=True)
|
||||
try:
|
||||
self.__handler = getattr(effectModule, "handler")
|
||||
except AttributeError:
|
||||
print "effect {} exists, but no handler".format(self.handlerName)
|
||||
raise
|
||||
|
||||
try:
|
||||
self.__runTime = getattr(effectModule, "runTime") or "normal"
|
||||
except AttributeError:
|
||||
self.__runTime = "normal"
|
||||
|
||||
try:
|
||||
self.__activeByDefault = getattr(effectModule, "activeByDefault")
|
||||
except AttributeError:
|
||||
self.__activeByDefault = True
|
||||
|
||||
try:
|
||||
t = getattr(effectModule, "type")
|
||||
except AttributeError:
|
||||
t = None
|
||||
self.__handler = getattr(effectModule, "handler", effectDummy)
|
||||
self.__runTime = getattr(effectModule, "runTime", "normal")
|
||||
self.__activeByDefault = getattr(effectModule, "activeByDefault", True)
|
||||
t = getattr(effectModule, "type", None)
|
||||
|
||||
t = t if isinstance(t, tuple) or t is None else (t,)
|
||||
self.__type = t
|
||||
except (ImportError, AttributeError):
|
||||
except (ImportError) as e:
|
||||
# Effect probably doesn't exist, so create a dummy effect and flag it with a warning.
|
||||
self.__handler = effectDummy
|
||||
self.__runTime = "normal"
|
||||
self.__activeByDefault = True
|
||||
self.__type = None
|
||||
pyfalog.warning("ImportError generating handler: {0}", e)
|
||||
except (AttributeError) as e:
|
||||
# Effect probably exists but there is an issue with it. Turn it into a dummy effect so we can continue, but flag it with an error.
|
||||
self.__handler = effectDummy
|
||||
self.__runTime = "normal"
|
||||
self.__activeByDefault = True
|
||||
self.__type = None
|
||||
pyfalog.error("AttributeError generating handler: {0}", e)
|
||||
except Exception as e:
|
||||
traceback.print_exc(e)
|
||||
pyfalog.critical("Exception generating handler:")
|
||||
pyfalog.critical(e)
|
||||
|
||||
self.__generated = True
|
||||
|
||||
@@ -285,8 +284,6 @@ class Item(EqBase):
|
||||
@property
|
||||
def requiredSkills(self):
|
||||
if self.__requiredSkills is None:
|
||||
# This import should be here to make sure it's fully initialized
|
||||
from eos import db
|
||||
requiredSkills = OrderedDict()
|
||||
self.__requiredSkills = requiredSkills
|
||||
# Map containing attribute IDs we may need for required skills
|
||||
@@ -297,7 +294,7 @@ class Item(EqBase):
|
||||
# { attributeID : attributeValue }
|
||||
skillAttrs = {}
|
||||
# Get relevant attribute values from db (required skill IDs and levels) for our item
|
||||
for attrInfo in db.directAttributeRequest((self.ID,), tuple(combinedAttrIDs)):
|
||||
for attrInfo in eos.db.directAttributeRequest((self.ID,), tuple(combinedAttrIDs)):
|
||||
attrID = attrInfo[1]
|
||||
attrVal = attrInfo[2]
|
||||
skillAttrs[attrID] = attrVal
|
||||
@@ -308,7 +305,7 @@ class Item(EqBase):
|
||||
skillID = int(skillAttrs[srqIDAtrr])
|
||||
skillLvl = skillAttrs[srqLvlAttr]
|
||||
# Fetch item from database and fill map
|
||||
item = db.getItem(skillID)
|
||||
item = eos.db.getItem(skillID)
|
||||
requiredSkills[item] = skillLvl
|
||||
return self.__requiredSkills
|
||||
|
||||
@@ -341,18 +338,20 @@ class Item(EqBase):
|
||||
# thus keep old mechanism for now
|
||||
except KeyError:
|
||||
# Define race map
|
||||
map = {1: "caldari",
|
||||
2: "minmatar",
|
||||
4: "amarr",
|
||||
5: "sansha", # Caldari + Amarr
|
||||
6: "blood", # Minmatar + Amarr
|
||||
8: "gallente",
|
||||
9: "guristas", # Caldari + Gallente
|
||||
10: "angelserp", # Minmatar + Gallente, final race depends on the order of skills
|
||||
12: "sisters", # Amarr + Gallente
|
||||
16: "jove",
|
||||
32: "sansha", # Incrusion Sansha
|
||||
128: "ore"}
|
||||
map = {
|
||||
1 : "caldari",
|
||||
2 : "minmatar",
|
||||
4 : "amarr",
|
||||
5 : "sansha", # Caldari + Amarr
|
||||
6 : "blood", # Minmatar + Amarr
|
||||
8 : "gallente",
|
||||
9 : "guristas", # Caldari + Gallente
|
||||
10 : "angelserp", # Minmatar + Gallente, final race depends on the order of skills
|
||||
12 : "sisters", # Amarr + Gallente
|
||||
16 : "jove",
|
||||
32 : "sansha", # Incrusion Sansha
|
||||
128: "ore"
|
||||
}
|
||||
# Race is None by default
|
||||
race = None
|
||||
# Check primary and secondary required skills' races
|
||||
@@ -422,7 +421,7 @@ class Item(EqBase):
|
||||
|
||||
def __repr__(self):
|
||||
return "Item(ID={}, name={}) at {}".format(
|
||||
self.ID, self.name, hex(id(self))
|
||||
self.ID, self.name, hex(id(self))
|
||||
)
|
||||
|
||||
|
||||
@@ -447,7 +446,6 @@ class Category(EqBase):
|
||||
|
||||
|
||||
class AlphaClone(EqBase):
|
||||
|
||||
@reconstructor
|
||||
def init(self):
|
||||
self.skillCache = {}
|
||||
@@ -475,10 +473,9 @@ class Icon(EqBase):
|
||||
|
||||
|
||||
class MarketGroup(EqBase):
|
||||
|
||||
def __repr__(self):
|
||||
return u"MarketGroup(ID={}, name={}, parent={}) at {}".format(
|
||||
self.ID, self.name, getattr(self.parent, "name", None), self.name, hex(id(self))
|
||||
self.ID, self.name, getattr(self.parent, "name", None), self.name, hex(id(self))
|
||||
).encode('utf8')
|
||||
|
||||
|
||||
|
||||
@@ -21,6 +21,9 @@ from math import log, sin, radians, exp
|
||||
|
||||
from eos.graph import Graph
|
||||
from eos.saveddata.module import State, Hardpoint
|
||||
from logbook import Logger
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class FitDpsGraph(Graph):
|
||||
@@ -65,8 +68,9 @@ class FitDpsGraph(Graph):
|
||||
bonus = values[i]
|
||||
val *= 1 + (bonus - 1) * exp(- i ** 2 / 7.1289)
|
||||
data[attr] = val
|
||||
except:
|
||||
pass
|
||||
except Exception as e:
|
||||
pyfalog.critical("Caught exception in calcDPS.")
|
||||
pyfalog.critical(e)
|
||||
|
||||
for mod in fit.modules:
|
||||
dps, _ = mod.damageStats(fit.targetResists)
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
# ===============================================================================
|
||||
# Copyright (C) 2010 Anton Vorobyov
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
import decimal
|
||||
|
||||
|
||||
def floorFloat(value):
|
||||
"""Round float down to integer"""
|
||||
# We have to convert float to str to keep compatibility with
|
||||
# decimal module in python 2.6
|
||||
value = str(value)
|
||||
# Do the conversions for proper rounding down, avoiding float
|
||||
# representation errors
|
||||
result = int(decimal.Decimal(value).to_integral_value(rounding=decimal.ROUND_DOWN))
|
||||
return result
|
||||
@@ -17,7 +17,7 @@
|
||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
import logging
|
||||
from logbook import Logger
|
||||
|
||||
from sqlalchemy.orm import reconstructor, validates
|
||||
|
||||
@@ -25,7 +25,7 @@ import eos.db
|
||||
from eos.effectHandlerHelpers import HandledItem
|
||||
from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class Booster(HandledItem, ItemAttrShortcut):
|
||||
@@ -47,11 +47,11 @@ class Booster(HandledItem, ItemAttrShortcut):
|
||||
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)
|
||||
pyfalog.error("Item (id: {0}) does not exist", self.itemID)
|
||||
return
|
||||
|
||||
if self.isInvalid:
|
||||
logger.error("Item (id: %d) is not a Booser", self.itemID)
|
||||
pyfalog.error("Item (id: {0}) is not a Booster", self.itemID)
|
||||
return
|
||||
|
||||
self.build()
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
# ===============================================================================
|
||||
|
||||
import sys
|
||||
import logging
|
||||
from logbook import Logger
|
||||
|
||||
from sqlalchemy.orm import validates, reconstructor
|
||||
|
||||
@@ -26,7 +26,7 @@ import eos.db
|
||||
from eos.effectHandlerHelpers import HandledItem
|
||||
from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class Cargo(HandledItem, ItemAttrShortcut):
|
||||
@@ -47,7 +47,7 @@ class Cargo(HandledItem, ItemAttrShortcut):
|
||||
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)
|
||||
pyfalog.error("Item (id: {0}) does not exist", self.itemID)
|
||||
return
|
||||
|
||||
self.__itemModifiedAttributes = ModifiedAttributeDict()
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
# ===============================================================================
|
||||
|
||||
|
||||
import logging
|
||||
from logbook import Logger
|
||||
from itertools import chain
|
||||
|
||||
from sqlalchemy.orm import validates, reconstructor
|
||||
@@ -27,7 +27,7 @@ import eos
|
||||
import eos.db
|
||||
from eos.effectHandlerHelpers import HandledItem, HandledImplantBoosterList
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class Character(object):
|
||||
|
||||
@@ -17,16 +17,17 @@
|
||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
import logging
|
||||
from logbook import Logger
|
||||
|
||||
from eos.saveddata.ship import Ship
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class Citadel(Ship):
|
||||
def validate(self, item):
|
||||
if item.category.name != "Structure":
|
||||
pyfalog.error("Passed item '{0}' (category: {1}) is not under Structure category", item.name, item.category.name)
|
||||
raise ValueError(
|
||||
'Passed item "%s" (category: (%s)) is not under Structure category' % (item.name, item.category.name))
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
import logging
|
||||
from logbook import Logger
|
||||
|
||||
from sqlalchemy.orm import validates, reconstructor
|
||||
|
||||
@@ -25,7 +25,7 @@ import eos.db
|
||||
from eos.effectHandlerHelpers import HandledItem, HandledCharge
|
||||
from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut, ChargeAttrShortcut
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
@@ -53,11 +53,11 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
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)
|
||||
pyfalog.error("Item (id: {0}) does not exist", self.itemID)
|
||||
return
|
||||
|
||||
if self.isInvalid:
|
||||
logger.error("Item (id: %d) is not a Drone", self.itemID)
|
||||
pyfalog.error("Item (id: {0}) is not a Drone", self.itemID)
|
||||
return
|
||||
|
||||
self.build()
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
import logging
|
||||
from logbook import Logger
|
||||
|
||||
from sqlalchemy.orm import validates, reconstructor
|
||||
|
||||
@@ -27,7 +27,7 @@ from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut, C
|
||||
from eos.saveddata.fighterAbility import FighterAbility
|
||||
from eos.saveddata.module import Slot
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
@@ -61,11 +61,11 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
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)
|
||||
pyfalog.error("Item (id: {0}) does not exist", self.itemID)
|
||||
return
|
||||
|
||||
if self.isInvalid:
|
||||
logger.error("Item (id: %d) is not a Fighter", self.itemID)
|
||||
pyfalog.error("Item (id: {0}) is not a Fighter", self.itemID)
|
||||
return
|
||||
|
||||
self.build()
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
import logging
|
||||
from logbook import Logger
|
||||
|
||||
from sqlalchemy.orm import reconstructor
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class FighterAbility(object):
|
||||
@@ -59,7 +59,7 @@ class FighterAbility(object):
|
||||
if self.effectID:
|
||||
self.__effect = next((x for x in self.fighter.item.effects.itervalues() if x.ID == self.effectID), None)
|
||||
if self.__effect is None:
|
||||
logger.error("Effect (id: %d) does not exist", self.effectID)
|
||||
pyfalog.error("Effect (id: {0}) does not exist", self.effectID)
|
||||
return
|
||||
|
||||
self.build()
|
||||
|
||||
@@ -33,9 +33,9 @@ from eos.saveddata.character import Character
|
||||
from eos.saveddata.citadel import Citadel
|
||||
from eos.saveddata.module import Module, State, Slot, Hardpoint
|
||||
from utils.timer import Timer
|
||||
import logging
|
||||
from logbook import Logger
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class ImplantLocation(Enum):
|
||||
@@ -84,7 +84,7 @@ class Fit(object):
|
||||
if self.shipID:
|
||||
item = eos.db.getItem(self.shipID)
|
||||
if item is None:
|
||||
logger.error("Item (id: %d) does not exist", self.shipID)
|
||||
pyfalog.error("Item (id: {0}) does not exist", self.shipID)
|
||||
return
|
||||
|
||||
try:
|
||||
@@ -97,7 +97,7 @@ class Fit(object):
|
||||
# change all instances in source). Remove this at some point
|
||||
self.extraAttributes = self.__ship.itemModifiedAttributes
|
||||
except ValueError:
|
||||
logger.error("Item (id: %d) is not a Ship", self.shipID)
|
||||
pyfalog.error("Item (id: {0}) is not a Ship", self.shipID)
|
||||
return
|
||||
|
||||
if self.modeID and self.__ship:
|
||||
@@ -127,6 +127,12 @@ class Fit(object):
|
||||
self.__capUsed = None
|
||||
self.__capRecharge = None
|
||||
self.__calculatedTargets = []
|
||||
self.__remoteReps = {
|
||||
"Armor": None,
|
||||
"Shield": None,
|
||||
"Hull": None,
|
||||
"Capacitor": None,
|
||||
}
|
||||
self.factorReload = False
|
||||
self.boostsFits = set()
|
||||
self.gangBoosts = None
|
||||
@@ -392,6 +398,9 @@ class Fit(object):
|
||||
self.ecmProjectedStr = 1
|
||||
self.commandBonuses = {}
|
||||
|
||||
for remoterep_type in self.__remoteReps:
|
||||
self.__remoteReps[remoterep_type] = None
|
||||
|
||||
del self.__calculatedTargets[:]
|
||||
del self.__extraDrains[:]
|
||||
|
||||
@@ -448,7 +457,7 @@ class Fit(object):
|
||||
self.commandBonuses[warfareBuffID] = (runTime, value, module, effect)
|
||||
|
||||
def __runCommandBoosts(self, runTime="normal"):
|
||||
logger.debug("Applying gang boosts for %r", self)
|
||||
pyfalog.debug("Applying gang boosts for {0}", self)
|
||||
for warfareBuffID in self.commandBonuses.keys():
|
||||
# Unpack all data required to run effect properly
|
||||
effect_runTime, value, thing, effect = self.commandBonuses[warfareBuffID]
|
||||
@@ -539,26 +548,32 @@ class Fit(object):
|
||||
|
||||
if warfareBuffID == 22: # Skirmish Burst: Rapid Deployment: AB/MWD Speed Increase
|
||||
self.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.requiresSkill("Afterburner") or mod.item.requiresSkill(
|
||||
"High Speed Maneuvering"), "speedFactor", value, stackingPenalties=True)
|
||||
lambda mod: mod.item.requiresSkill("Afterburner")
|
||||
or mod.item.requiresSkill("High Speed Maneuvering"),
|
||||
"speedFactor", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 23: # Mining Burst: Mining Laser Field Enhancement: Mining/Survey Range
|
||||
self.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.requiresSkill("Mining") or mod.item.requiresSkill(
|
||||
"Ice Harvesting") or mod.item.requiresSkill("Gas Cloud Harvesting"), "maxRange",
|
||||
value, stackingPenalties=True)
|
||||
lambda mod: mod.item.requiresSkill("Mining") or
|
||||
mod.item.requiresSkill("Ice Harvesting") or
|
||||
mod.item.requiresSkill("Gas Cloud Harvesting"),
|
||||
"maxRange", value, stackingPenalties=True)
|
||||
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("CPU Management"),
|
||||
"surveyScanRange", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 24: # Mining Burst: Mining Laser Optimization: Mining Capacitor/Duration
|
||||
self.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.requiresSkill("Mining") or mod.item.requiresSkill(
|
||||
"Ice Harvesting") or mod.item.requiresSkill("Gas Cloud Harvesting"),
|
||||
lambda mod: mod.item.requiresSkill("Mining") or
|
||||
mod.item.requiresSkill("Ice Harvesting") or
|
||||
mod.item.requiresSkill("Gas Cloud Harvesting"),
|
||||
"capacitorNeed", value, stackingPenalties=True)
|
||||
|
||||
self.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.requiresSkill("Mining") or mod.item.requiresSkill(
|
||||
"Ice Harvesting") or mod.item.requiresSkill("Gas Cloud Harvesting"), "duration",
|
||||
value, stackingPenalties=True)
|
||||
lambda mod: mod.item.requiresSkill("Mining") or
|
||||
mod.item.requiresSkill("Ice Harvesting") or
|
||||
mod.item.requiresSkill("Gas Cloud Harvesting"),
|
||||
"duration", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 25: # Mining Burst: Mining Equipment Preservation: Crystal Volatility
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining"),
|
||||
@@ -630,21 +645,21 @@ class Fit(object):
|
||||
del self.commandBonuses[warfareBuffID]
|
||||
|
||||
def calculateModifiedAttributes(self, targetFit=None, withBoosters=False, dirtyStorage=None):
|
||||
timer = Timer(u'Fit: {}, {}'.format(self.ID, self.name), logger)
|
||||
logger.debug("Starting fit calculation on: %r, withBoosters: %s", self, withBoosters)
|
||||
timer = Timer(u'Fit: {}, {}'.format(self.ID, self.name), pyfalog)
|
||||
pyfalog.debug("Starting fit calculation on: {0}, withBoosters: {1}", self, withBoosters)
|
||||
|
||||
shadow = False
|
||||
if targetFit and not withBoosters:
|
||||
logger.debug("Applying projections to target: %r", targetFit)
|
||||
pyfalog.debug("Applying projections to target: {0}", targetFit)
|
||||
projectionInfo = self.getProjectionInfo(targetFit.ID)
|
||||
logger.debug("ProjectionInfo: %s", projectionInfo)
|
||||
pyfalog.debug("ProjectionInfo: {0}", projectionInfo)
|
||||
if self == targetFit:
|
||||
copied = self # original fit
|
||||
shadow = True
|
||||
# Don't inspect this, we genuinely want to reassign self
|
||||
# noinspection PyMethodFirstArgAssignment
|
||||
self = deepcopy(self)
|
||||
logger.debug("Handling self projection - making shadow copy of fit. %r => %r", copied, self)
|
||||
pyfalog.debug("Handling self projection - making shadow copy of fit. {0} => {1}", copied, self)
|
||||
# we delete the fit because when we copy a fit, flush() is
|
||||
# called to properly handle projection updates. However, we do
|
||||
# not want to save this fit to the database, so simply remove it
|
||||
@@ -679,7 +694,7 @@ class Fit(object):
|
||||
# projection have modifying stuff applied, such as gang boosts and other
|
||||
# local modules that may help
|
||||
if self.__calculated and not projected and not withBoosters:
|
||||
logger.debug("Fit has already been calculated and is not projected, returning: %r", self)
|
||||
pyfalog.debug("Fit has already been calculated and is not projected, returning: {0}", self)
|
||||
return
|
||||
|
||||
for runTime in ("early", "normal", "late"):
|
||||
@@ -730,6 +745,10 @@ class Fit(object):
|
||||
# targetFit.register(item, origin=self)
|
||||
item.calculateModifiedAttributes(targetFit, runTime, False, True)
|
||||
|
||||
if len(self.commandBonuses) > 0:
|
||||
pyfalog.info("Command bonuses applied.")
|
||||
pyfalog.debug(self.commandBonuses)
|
||||
|
||||
if not withBoosters and self.commandBonuses:
|
||||
self.__runCommandBoosts(runTime)
|
||||
|
||||
@@ -747,7 +766,7 @@ class Fit(object):
|
||||
timer.checkpoint('Done with fit calculation')
|
||||
|
||||
if shadow:
|
||||
logger.debug("Delete shadow fit object")
|
||||
pyfalog.debug("Delete shadow fit object")
|
||||
del self
|
||||
|
||||
def fill(self):
|
||||
@@ -914,20 +933,19 @@ class Fit(object):
|
||||
|
||||
return amount
|
||||
|
||||
# Expresses how difficult a target is to probe down with scan probes
|
||||
# If this is <1.08, the ship is unproabeable
|
||||
@property
|
||||
def probeSize(self):
|
||||
"""
|
||||
Expresses how difficult a target is to probe down with scan probes
|
||||
"""
|
||||
|
||||
sigRad = self.ship.getModifiedItemAttr("signatureRadius")
|
||||
sensorStr = float(self.scanStrength)
|
||||
probeSize = sigRad / sensorStr if sensorStr != 0 else None
|
||||
# http://www.eveonline.com/ingameboard.asp?a=topic&threadID=1532170&page=2#42
|
||||
if probeSize is not None:
|
||||
# http://forum.eve-ru.com/index.php?showtopic=74195&view=findpost&p=1333691
|
||||
# http://forum.eve-ru.com/index.php?showtopic=74195&view=findpost&p=1333763
|
||||
# Tests by tester128 and several conclusions by me, prove that cap is in range
|
||||
# from 1.1 to 1.12, we're picking average value
|
||||
probeSize = max(probeSize, 1.11)
|
||||
# Probe size is capped at 1.08
|
||||
probeSize = max(probeSize, 1.08)
|
||||
return probeSize
|
||||
|
||||
@property
|
||||
@@ -1147,6 +1165,67 @@ class Fit(object):
|
||||
self.__capStable = True
|
||||
self.__capState = 100
|
||||
|
||||
@property
|
||||
def remoteReps(self):
|
||||
force_recalc = False
|
||||
for remote_type in self.__remoteReps:
|
||||
if self.__remoteReps[remote_type] is None:
|
||||
force_recalc = True
|
||||
break
|
||||
|
||||
if force_recalc is False:
|
||||
return self.__remoteReps
|
||||
|
||||
# We are rerunning the recalcs. Explicitly set to 0 to make sure we don't duplicate anything and correctly set all values to 0.
|
||||
for remote_type in self.__remoteReps:
|
||||
self.__remoteReps[remote_type] = 0
|
||||
|
||||
for module in self.modules:
|
||||
# Skip empty and non-Active modules
|
||||
if module.isEmpty or module.state < State.ACTIVE:
|
||||
continue
|
||||
|
||||
# Covert cycleTime to seconds
|
||||
duration = module.cycleTime / 1000
|
||||
|
||||
# Skip modules with no duration.
|
||||
if not duration:
|
||||
continue
|
||||
|
||||
fueledMultiplier = module.getModifiedItemAttr("chargedArmorDamageMultiplier", 1)
|
||||
|
||||
remote_module_groups = {
|
||||
"Remote Armor Repairer" : "Armor",
|
||||
"Ancillary Remote Armor Repairer": "Armor",
|
||||
"Remote Hull Repairer" : "Hull",
|
||||
"Remote Shield Booster" : "Shield",
|
||||
"Ancillary Remote Shield Booster": "Shield",
|
||||
"Remote Capacitor Transmitter" : "Capacitor",
|
||||
}
|
||||
|
||||
module_group = module.item.group.name
|
||||
|
||||
if module_group in remote_module_groups:
|
||||
remote_type = remote_module_groups[module_group]
|
||||
else:
|
||||
# Module isn't in our list of remote rep modules, bail
|
||||
continue
|
||||
|
||||
if remote_type == "Hull":
|
||||
hp = module.getModifiedItemAttr("structureDamageAmount", 0)
|
||||
elif remote_type == "Armor":
|
||||
hp = module.getModifiedItemAttr("armorDamageAmount", 0)
|
||||
elif remote_type == "Shield":
|
||||
hp = module.getModifiedItemAttr("shieldBonus", 0)
|
||||
elif remote_type == "Capacitor":
|
||||
hp = module.getModifiedItemAttr("powerTransferAmount", 0)
|
||||
else:
|
||||
hp = 0
|
||||
|
||||
self.__remoteReps[remote_type] += (hp * fueledMultiplier) / duration
|
||||
|
||||
return self.__remoteReps
|
||||
|
||||
@property
|
||||
def hp(self):
|
||||
hp = {}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
import logging
|
||||
from logbook import Logger
|
||||
|
||||
from sqlalchemy.orm import validates, reconstructor
|
||||
|
||||
@@ -25,7 +25,7 @@ import eos.db
|
||||
from eos.effectHandlerHelpers import HandledItem
|
||||
from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class Implant(HandledItem, ItemAttrShortcut):
|
||||
@@ -46,11 +46,11 @@ class Implant(HandledItem, ItemAttrShortcut):
|
||||
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)
|
||||
pyfalog.error("Item (id: {0}) does not exist", self.itemID)
|
||||
return
|
||||
|
||||
if self.isInvalid:
|
||||
logger.error("Item (id: %d) is not an Implant", self.itemID)
|
||||
pyfalog.error("Item (id: {0}) is not an Implant", self.itemID)
|
||||
return
|
||||
|
||||
self.build()
|
||||
|
||||
@@ -17,18 +17,18 @@
|
||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
import logging
|
||||
from logbook import Logger
|
||||
|
||||
from sqlalchemy.orm import validates, reconstructor
|
||||
from math import floor
|
||||
|
||||
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.saveddata.citadel import Citadel
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class State(Enum):
|
||||
@@ -94,11 +94,11 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
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)
|
||||
pyfalog.error("Item (id: {0}) does not exist", self.itemID)
|
||||
return
|
||||
|
||||
if self.isInvalid:
|
||||
logger.error("Item (id: %d) is not a Module", self.itemID)
|
||||
pyfalog.error("Item (id: {0}) is not a Module", self.itemID)
|
||||
return
|
||||
|
||||
if self.chargeID:
|
||||
@@ -172,7 +172,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
if chargeVolume is None or containerCapacity is None:
|
||||
charges = 0
|
||||
else:
|
||||
charges = floorFloat(float(containerCapacity) / chargeVolume)
|
||||
charges = floor(containerCapacity / chargeVolume)
|
||||
return charges
|
||||
|
||||
@property
|
||||
@@ -216,9 +216,10 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
def __calculateAmmoShots(self):
|
||||
if self.charge is not None:
|
||||
# Set number of cycles before reload is needed
|
||||
# numcycles = math.floor(module_capacity / (module_volume * module_chargerate))
|
||||
chargeRate = self.getModifiedItemAttr("chargeRate")
|
||||
numCharges = self.numCharges
|
||||
numShots = floorFloat(float(numCharges) / chargeRate)
|
||||
numShots = floor(numCharges / chargeRate)
|
||||
else:
|
||||
numShots = None
|
||||
return numShots
|
||||
@@ -231,7 +232,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
chance = self.getModifiedChargeAttr("crystalVolatilityChance")
|
||||
damage = self.getModifiedChargeAttr("crystalVolatilityDamage")
|
||||
crystals = self.numCharges
|
||||
numShots = floorFloat(float(crystals * hp) / (damage * chance))
|
||||
numShots = floor((crystals * hp) / (damage * chance))
|
||||
else:
|
||||
# Set 0 (infinite) for permanent crystals like t1 laser crystals
|
||||
numShots = 0
|
||||
@@ -665,32 +666,68 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
|
||||
@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
|
||||
|
||||
numShots = self.numShots
|
||||
speed = self.rawCycleTime
|
||||
|
||||
if factorReload and self.charge:
|
||||
raw_reload_time = self.reloadTime
|
||||
else:
|
||||
raw_reload_time = 0.0
|
||||
|
||||
# Module can only fire one shot at a time, think bomb launchers or defender launchers
|
||||
if self.disallowRepeatingAction:
|
||||
if numShots > 1:
|
||||
"""
|
||||
The actual mechanics behind this is complex. Behavior will be (for 3 ammo):
|
||||
fire, reactivation delay, fire, reactivation delay, fire, max(reactivation delay, reload)
|
||||
so your effective reload time depends on where you are at in the cycle.
|
||||
|
||||
We can't do that, so instead we'll average it out.
|
||||
|
||||
Currently would apply to bomb launchers and defender missiles
|
||||
"""
|
||||
effective_reload_time = ((self.reactivationDelay * (numShots - 1)) + max(raw_reload_time, self.reactivationDelay, 0)) / numShots
|
||||
else:
|
||||
"""
|
||||
Applies to MJD/MJFG
|
||||
"""
|
||||
effective_reload_time = max(raw_reload_time, self.reactivationDelay, 0)
|
||||
else:
|
||||
"""
|
||||
Currently no other modules would have a reactivation delay, so for sanities sake don't try and account for it.
|
||||
Okay, technically cloaks do, but they also have 0 cycle time and cap usage so why do you care?
|
||||
"""
|
||||
effective_reload_time = raw_reload_time
|
||||
|
||||
if numShots > 0 and self.charge:
|
||||
speed = (speed * numShots + effective_reload_time) / numShots
|
||||
|
||||
return speed
|
||||
|
||||
@property
|
||||
def rawCycleTime(self):
|
||||
speed = self.getModifiedItemAttr("speed") or self.getModifiedItemAttr("duration")
|
||||
speed = max(
|
||||
self.getModifiedItemAttr("speed"), # Most weapons
|
||||
self.getModifiedItemAttr("duration"), # Most average modules
|
||||
self.getModifiedItemAttr("durationSensorDampeningBurstProjector"),
|
||||
self.getModifiedItemAttr("durationTargetIlluminationBurstProjector"),
|
||||
self.getModifiedItemAttr("durationECMJammerBurstProjector"),
|
||||
self.getModifiedItemAttr("durationWeaponDisruptionBurstProjector"),
|
||||
0, # Return 0 if none of the above are valid
|
||||
)
|
||||
return speed
|
||||
|
||||
@property
|
||||
def disallowRepeatingAction(self):
|
||||
return self.getModifiedItemAttr("disallowRepeatingAction", 0)
|
||||
|
||||
@property
|
||||
def reactivationDelay(self):
|
||||
return self.getModifiedItemAttr("moduleReactivationDelay", 0)
|
||||
|
||||
@property
|
||||
def capUse(self):
|
||||
capNeed = self.getModifiedItemAttr("capacitorNeed")
|
||||
|
||||
@@ -17,14 +17,14 @@
|
||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
import logging
|
||||
from logbook import Logger
|
||||
|
||||
from sqlalchemy.orm import reconstructor
|
||||
|
||||
import eos.db
|
||||
from eos.eqBase import EqBase
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class Override(EqBase):
|
||||
@@ -43,13 +43,13 @@ class Override(EqBase):
|
||||
if self.attrID:
|
||||
self.__attr = eos.db.getAttributeInfo(self.attrID)
|
||||
if self.__attr is None:
|
||||
logger.error("Attribute (id: %d) does not exist", self.attrID)
|
||||
pyfalog.error("Attribute (id: {0}) does not exist", self.attrID)
|
||||
return
|
||||
|
||||
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)
|
||||
pyfalog.error("Item (id: {0}) does not exist", self.itemID)
|
||||
return
|
||||
|
||||
@property
|
||||
|
||||
@@ -17,14 +17,14 @@
|
||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
import logging
|
||||
from logbook import Logger
|
||||
|
||||
import eos.db
|
||||
from eos.effectHandlerHelpers import HandledItem
|
||||
from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut, cappingAttrKeyCache
|
||||
from eos.saveddata.mode import Mode
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class Ship(ItemAttrShortcut, HandledItem):
|
||||
@@ -63,6 +63,7 @@ class Ship(ItemAttrShortcut, HandledItem):
|
||||
|
||||
def validate(self, item):
|
||||
if item.category.name != "Ship":
|
||||
pyfalog.error("Passed item '{0}' (category: {1}) is not under Ship category", item.name, item.category.name)
|
||||
raise ValueError(
|
||||
'Passed item "%s" (category: (%s)) is not under Ship category' % (item.name, item.category.name))
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
# ===============================================================================
|
||||
|
||||
import re
|
||||
from logbook import Logger
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class TargetResists(object):
|
||||
@@ -43,7 +46,7 @@ class TargetResists(object):
|
||||
type, data = line.rsplit('=', 1)
|
||||
type, data = type.strip(), data.split(',')
|
||||
except:
|
||||
# Data isn't in correct format, continue to next line
|
||||
pyfalog.warning("Data isn't in correct format, continue to next line.")
|
||||
continue
|
||||
|
||||
if type != "TargetResists":
|
||||
@@ -59,6 +62,7 @@ class TargetResists(object):
|
||||
assert 0 <= val <= 100
|
||||
fields["%sAmount" % cls.DAMAGE_TYPES[index]] = val / 100
|
||||
except:
|
||||
pyfalog.warning("Caught unhandled exception in import patterns.")
|
||||
continue
|
||||
|
||||
if len(fields) == 4: # Avoid possible blank lines
|
||||
|
||||
@@ -26,6 +26,9 @@ import wx
|
||||
|
||||
import config
|
||||
|
||||
from logbook import Logger
|
||||
logging = Logger(__name__)
|
||||
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
except ImportError:
|
||||
@@ -35,7 +38,9 @@ except ImportError:
|
||||
class BitmapLoader(object):
|
||||
try:
|
||||
archive = zipfile.ZipFile(os.path.join(config.pyfaPath, 'imgs.zip'), 'r')
|
||||
logging.info("Using zipped image files.")
|
||||
except IOError:
|
||||
logging.info("Using local image files.")
|
||||
archive = None
|
||||
|
||||
cachedBitmaps = OrderedDict()
|
||||
|
||||
@@ -22,4 +22,6 @@ __all__ = [
|
||||
"metaSwap",
|
||||
"implantSets",
|
||||
"fighterAbilities",
|
||||
"cargoAmmo",
|
||||
"droneStack"
|
||||
]
|
||||
|
||||
@@ -4,13 +4,18 @@ import gui.mainFrame
|
||||
import wx
|
||||
import gui.globalEvents as GE
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class AmmoPattern(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('ammoPattern'):
|
||||
return False
|
||||
|
||||
if srcContext not in ("marketItemGroup", "marketItemMisc") or self.mainFrame.getActiveFit() is None:
|
||||
return False
|
||||
|
||||
|
||||
@@ -7,13 +7,18 @@ 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
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class ChangeAmount(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('amount'):
|
||||
return False
|
||||
|
||||
return srcContext in ("cargoItem", "projectedFit", "fighterItem", "projectedFighter")
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
|
||||
@@ -4,20 +4,28 @@ import gui.globalEvents as GE
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class Cargo(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('cargo'):
|
||||
return False
|
||||
|
||||
if srcContext not in ("marketItemGroup", "marketItemMisc"):
|
||||
return False
|
||||
|
||||
sFit = Fit.getInstance()
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
|
||||
fit = sFit.getFit(fitID)
|
||||
# Make sure context menu registers in the correct view
|
||||
if srcContext not in ("marketItemGroup", "marketItemMisc") or not fit or fit.isStructure:
|
||||
if not fit or fit.isStructure:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
|
||||
35
gui/builtinContextMenus/cargoAmmo.py
Normal file
35
gui/builtinContextMenus/cargoAmmo.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from gui.contextMenu import ContextMenu
|
||||
import gui.mainFrame
|
||||
import service
|
||||
import gui.globalEvents as GE
|
||||
import wx
|
||||
|
||||
|
||||
class CargoAmmo(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
|
||||
|
||||
for selected_item in selection:
|
||||
if selected_item.category.ID in (
|
||||
8, # Charge
|
||||
):
|
||||
return True
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
return "Add {0} to Cargo (x1000)".format(itmContext)
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
sFit = service.Fit.getInstance()
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
|
||||
typeID = int(selection[0].ID)
|
||||
sFit.addCargo(fitID, typeID, 1000)
|
||||
self.mainFrame.additionsPane.select("Cargo")
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
|
||||
|
||||
|
||||
CargoAmmo.register()
|
||||
@@ -8,13 +8,18 @@ from eos.saveddata.character import Skill
|
||||
import gui.globalEvents as GE
|
||||
from service.fit import Fit
|
||||
from service.character import Character
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class ChangeAffectingSkills(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('changeAffectingSkills'):
|
||||
return False
|
||||
|
||||
if self.mainFrame.getActiveFit() is None or srcContext not in ("fittingModule", "fittingCharge", "fittingShip"):
|
||||
return False
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import wx
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
from service.fit import Fit
|
||||
from service.damagePattern import DamagePattern as import_DamagePattern
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
@@ -16,8 +17,12 @@ except ImportError:
|
||||
class DamagePattern(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('damagePattern'):
|
||||
return False
|
||||
|
||||
return srcContext == "resistancesViewFull" and self.mainFrame.getActiveFit() is not None
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
|
||||
@@ -4,13 +4,18 @@ import gui.mainFrame
|
||||
import wx
|
||||
import gui.globalEvents as GE
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class ItemRemove(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('droneRemoveStack'):
|
||||
return False
|
||||
|
||||
return srcContext == "droneItem"
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
|
||||
@@ -4,13 +4,18 @@ import gui.globalEvents as GE
|
||||
from service.fit import Fit
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class DroneSplit(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('droneSplit'):
|
||||
return False
|
||||
|
||||
return srcContext in ("droneItem", "projectedDrone") and selection[0].amount > 1
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
|
||||
37
gui/builtinContextMenus/droneStack.py
Normal file
37
gui/builtinContextMenus/droneStack.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from gui.contextMenu import ContextMenu
|
||||
import gui.mainFrame
|
||||
import service
|
||||
import gui.globalEvents as GE
|
||||
import wx
|
||||
|
||||
|
||||
class CargoAmmo(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
|
||||
|
||||
for selected_item in selection:
|
||||
if selected_item.category.ID in (
|
||||
18, # Drones
|
||||
):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
return "Add {0} to Drone Bay (x5)".format(itmContext)
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
sFit = service.Fit.getInstance()
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
|
||||
typeID = int(selection[0].ID)
|
||||
sFit.addDrone(fitID, typeID, 5)
|
||||
self.mainFrame.additionsPane.select("Drones")
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
|
||||
|
||||
|
||||
CargoAmmo.register()
|
||||
@@ -5,13 +5,18 @@ import gui.globalEvents as GE
|
||||
import wx
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class FactorReload(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('factorReload'):
|
||||
return False
|
||||
|
||||
return srcContext == "firepowerViewFull" and self.mainFrame.getActiveFit() is not None
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
|
||||
@@ -4,13 +4,18 @@ from gui.contextMenu import ContextMenu
|
||||
import gui.mainFrame
|
||||
import gui.globalEvents as GE
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class FighterAbility(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('fighterAbilities'):
|
||||
return False
|
||||
|
||||
if self.mainFrame.getActiveFit() is None or srcContext not in ("fighterItem", "projectedFighter"):
|
||||
return False
|
||||
|
||||
|
||||
@@ -6,13 +6,18 @@ import wx
|
||||
from service.implantSet import ImplantSets as s_ImplantSets
|
||||
from service.character import Character
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class ImplantSets(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('implantSets'):
|
||||
return False
|
||||
|
||||
return srcContext in ("implantView", "implantEditor")
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
|
||||
@@ -4,13 +4,18 @@ import gui.mainFrame
|
||||
import wx
|
||||
import gui.globalEvents as GE
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class ItemRemove(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('itemRemove'):
|
||||
return False
|
||||
|
||||
return srcContext in ("fittingModule", "fittingCharge",
|
||||
"droneItem", "implantItem",
|
||||
"boosterItem", "projectedModule",
|
||||
|
||||
@@ -4,13 +4,17 @@ import gui.mainFrame
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class ItemStats(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('itemStats'):
|
||||
return False
|
||||
|
||||
return srcContext in ("marketItemGroup", "marketItemMisc",
|
||||
"fittingModule", "fittingCharge",
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
from gui.contextMenu import ContextMenu
|
||||
import gui.mainFrame
|
||||
from service.market import Market
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class MarketJump(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('marketJump'):
|
||||
return False
|
||||
|
||||
validContexts = ("marketItemMisc", "fittingModule",
|
||||
"fittingCharge", "droneItem",
|
||||
"implantItem", "boosterItem",
|
||||
|
||||
@@ -8,15 +8,30 @@ from service.market import Market
|
||||
import gui.mainFrame
|
||||
import gui.globalEvents as GE
|
||||
from gui.contextMenu import ContextMenu
|
||||
from service.settings import ContextMenuSettings
|
||||
from eos.saveddata.booster import Booster
|
||||
from eos.saveddata.module import Module
|
||||
from eos.saveddata.drone import Drone
|
||||
from eos.saveddata.fighter import Fighter
|
||||
from eos.saveddata.implant import Implant
|
||||
|
||||
|
||||
class MetaSwap(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('metaSwap'):
|
||||
return False
|
||||
|
||||
if self.mainFrame.getActiveFit() is None or srcContext not in ("fittingModule",):
|
||||
if self.mainFrame.getActiveFit() is None or srcContext not in (
|
||||
"fittingModule",
|
||||
"droneItem",
|
||||
"fighterItem",
|
||||
"boosterItem",
|
||||
"implantItem",
|
||||
):
|
||||
return False
|
||||
|
||||
# Check if list of variations is same for all of selection
|
||||
@@ -52,6 +67,17 @@ class MetaSwap(ContextMenu):
|
||||
def get_metagroup(x):
|
||||
return x.metaGroup.ID if x.metaGroup is not None else 0
|
||||
|
||||
def get_boosterrank(x):
|
||||
# If we're returning a lot of items, sort my name
|
||||
if len(self.variations) > 7:
|
||||
return x.name
|
||||
# Sort by booster chance to get some sort of pseudorank.
|
||||
elif 'boosterEffectChance1' in x.attributes:
|
||||
return x.attributes['boosterEffectChance1'].value
|
||||
# the "first" rank (Synth) doesn't have boosterEffectChance1. If we're not pulling back all boosters, return 0 for proper sorting
|
||||
else:
|
||||
return 0
|
||||
|
||||
m = wx.Menu()
|
||||
|
||||
# If on Windows we need to bind out events into the root menu, on other
|
||||
@@ -63,8 +89,17 @@ class MetaSwap(ContextMenu):
|
||||
|
||||
# Sort items by metalevel, and group within that metalevel
|
||||
items = list(self.variations)
|
||||
items.sort(key=get_metalevel)
|
||||
items.sort(key=get_metagroup)
|
||||
print context
|
||||
if "implantItem" in context:
|
||||
# sort implants based on name
|
||||
items.sort(key=lambda x: x.name)
|
||||
elif "boosterItem" in context:
|
||||
# boosters don't have meta or anything concrete that we can rank by. Go by chance to inflict side effect
|
||||
items.sort(key=get_boosterrank)
|
||||
else:
|
||||
# sort by group and meta level
|
||||
items.sort(key=get_metalevel)
|
||||
items.sort(key=get_metagroup)
|
||||
|
||||
group = None
|
||||
for item in items:
|
||||
@@ -74,7 +109,7 @@ class MetaSwap(ContextMenu):
|
||||
else:
|
||||
thisgroup = item.metaGroup.name
|
||||
|
||||
if thisgroup != group:
|
||||
if thisgroup != group and context not in ("implantItem", "boosterItem"):
|
||||
group = thisgroup
|
||||
id = ContextMenu.nextID()
|
||||
m.Append(id, u'─ %s ─' % group)
|
||||
@@ -97,9 +132,56 @@ class MetaSwap(ContextMenu):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = sFit.getFit(fitID)
|
||||
|
||||
for mod in self.selection:
|
||||
pos = fit.modules.index(mod)
|
||||
sFit.changeModule(fitID, pos, item.ID)
|
||||
for selected_item in self.selection:
|
||||
if isinstance(selected_item, Module):
|
||||
pos = fit.modules.index(selected_item)
|
||||
sFit.changeModule(fitID, pos, item.ID)
|
||||
|
||||
elif isinstance(selected_item, Drone):
|
||||
drone_count = None
|
||||
|
||||
for idx, drone_stack in enumerate(fit.drones):
|
||||
if drone_stack is selected_item:
|
||||
drone_count = drone_stack.amount
|
||||
sFit.removeDrone(fitID, idx, drone_count)
|
||||
break
|
||||
|
||||
if drone_count:
|
||||
sFit.addDrone(fitID, item.ID, drone_count)
|
||||
|
||||
elif isinstance(selected_item, Fighter):
|
||||
fighter_count = None
|
||||
|
||||
for idx, fighter_stack in enumerate(fit.fighters):
|
||||
# Right now fighters always will have max stack size.
|
||||
# Including this for future improvement, so if adjustable
|
||||
# fighter stacks get added we're ready for it.
|
||||
if fighter_stack is selected_item:
|
||||
if fighter_stack.amount > 0:
|
||||
fighter_count = fighter_stack.amount
|
||||
elif fighter_stack.amount == -1:
|
||||
fighter_count = fighter_stack.amountActive
|
||||
else:
|
||||
fighter_count.amount = 0
|
||||
|
||||
sFit.removeFighter(fitID, idx)
|
||||
break
|
||||
|
||||
sFit.addFighter(fitID, item.ID)
|
||||
|
||||
elif isinstance(selected_item, Booster):
|
||||
for idx, booster_stack in enumerate(fit.boosters):
|
||||
if booster_stack is selected_item:
|
||||
sFit.removeBooster(fitID, idx)
|
||||
sFit.addBooster(fitID, item.ID)
|
||||
break
|
||||
|
||||
elif isinstance(selected_item, Implant):
|
||||
for idx, implant_stack in enumerate(fit.implants):
|
||||
if implant_stack is selected_item:
|
||||
sFit.removeImplant(fitID, idx)
|
||||
sFit.addImplant(fitID, item.ID, False)
|
||||
break
|
||||
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import gui.mainFrame
|
||||
import gui.globalEvents as GE
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class ModuleAmmoPicker(ContextMenu):
|
||||
@@ -18,8 +19,12 @@ class ModuleAmmoPicker(ContextMenu):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('moduleAmmoPicker'):
|
||||
return False
|
||||
|
||||
if self.mainFrame.getActiveFit() is None or srcContext not in ("fittingModule", "projectedModule"):
|
||||
return False
|
||||
|
||||
|
||||
@@ -6,12 +6,14 @@ import gui.globalEvents as GE
|
||||
from gui.builtinContextMenus.moduleAmmoPicker import ModuleAmmoPicker
|
||||
from eos.db.saveddata.queries import getFit as db_getFit
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class ModuleGlobalAmmoPicker(ModuleAmmoPicker):
|
||||
def __init__(self):
|
||||
super(ModuleGlobalAmmoPicker, self).__init__()
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
return "Charge (All)"
|
||||
@@ -42,6 +44,9 @@ class ModuleGlobalAmmoPicker(ModuleAmmoPicker):
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('moduleGlobalAmmoPicker'):
|
||||
return False
|
||||
|
||||
try:
|
||||
selectionLen = len(selection)
|
||||
except:
|
||||
|
||||
@@ -3,13 +3,18 @@ import gui.mainFrame
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
from gui.shipBrowser import FitSelected
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class OpenFit(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('openFit'):
|
||||
return False
|
||||
|
||||
return srcContext == "projectedFit"
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
|
||||
@@ -4,13 +4,18 @@ import gui.mainFrame
|
||||
import wx
|
||||
import gui.globalEvents as GE
|
||||
from service.market import Market
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class PriceClear(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('priceClear'):
|
||||
return False
|
||||
|
||||
return srcContext == "priceViewFull"
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
|
||||
@@ -4,13 +4,18 @@ import gui.globalEvents as GE
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class Project(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('project'):
|
||||
return False
|
||||
|
||||
if srcContext not in ("marketItemGroup", "marketItemMisc") or self.mainFrame.getActiveFit() is None:
|
||||
return False
|
||||
|
||||
|
||||
@@ -4,13 +4,18 @@ from gui.contextMenu import ContextMenu
|
||||
import gui.mainFrame
|
||||
from gui.shipBrowser import Stage3Selected
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class ShipJump(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('shipJump'):
|
||||
return False
|
||||
|
||||
return srcContext == "fittingShip"
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
|
||||
@@ -5,13 +5,18 @@ import gui.mainFrame
|
||||
|
||||
import gui.globalEvents as GE
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class TacticalMode(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('tacticalMode'):
|
||||
return False
|
||||
|
||||
if self.mainFrame.getActiveFit() is None or srcContext != "fittingShip":
|
||||
return False
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import wx
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
from service.targetResists import TargetResists as svc_TargetResists
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
@@ -16,8 +17,12 @@ except ImportError:
|
||||
class TargetResists(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('targetResists'):
|
||||
return False
|
||||
|
||||
if self.mainFrame.getActiveFit() is None or srcContext != "firepowerViewFull":
|
||||
return False
|
||||
|
||||
|
||||
@@ -5,13 +5,18 @@ import gui.globalEvents as GE
|
||||
import wx
|
||||
from service.market import Market
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class WhProjector(ContextMenu):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if not self.settings.get('whProjector'):
|
||||
return False
|
||||
|
||||
return srcContext == "projected"
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
|
||||
__all__ = ["pyfaGeneralPreferences", "pyfaHTMLExportPreferences", "pyfaUpdatePreferences",
|
||||
"pyfaNetworkPreferences"] # noqa
|
||||
__all__ = [
|
||||
"pyfaGeneralPreferences",
|
||||
"pyfaHTMLExportPreferences",
|
||||
"pyfaUpdatePreferences",
|
||||
"pyfaNetworkPreferences",
|
||||
"pyfaDatabasePreferences",
|
||||
"pyfaLoggingPreferences",
|
||||
"pyfaEnginePreferences",
|
||||
"pyfaStatViewPreferences",
|
||||
]
|
||||
|
||||
if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3, 0)):
|
||||
__all__.append("pyfaCrestPreferences")
|
||||
|
||||
114
gui/builtinPreferenceViews/pyfaContextMenuPreferences.py
Normal file
114
gui/builtinPreferenceViews/pyfaContextMenuPreferences.py
Normal file
@@ -0,0 +1,114 @@
|
||||
import wx
|
||||
|
||||
from gui.preferenceView import PreferenceView
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
import gui.mainFrame
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class PFContextMenuPref(PreferenceView):
|
||||
title = "Context Menu Panel"
|
||||
|
||||
def populatePanel(self, panel):
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
|
||||
self.dirtySettings = False
|
||||
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.stSubTitle = wx.StaticText(panel, wx.ID_ANY,
|
||||
u"Disabling context menus can improve responsiveness.",
|
||||
wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stSubTitle.Wrap(-1)
|
||||
mainSizer.Add(self.stSubTitle, 0, wx.ALL, 5)
|
||||
|
||||
# Row 1
|
||||
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.ALL, 5)
|
||||
|
||||
rbSizerRow1 = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
self.rbBox1 = wx.RadioBox(panel, -1, "Set as Damage Pattern", wx.DefaultPosition, wx.DefaultSize, ['Disabled', 'Enabled'], 1, wx.RA_SPECIFY_COLS)
|
||||
self.rbBox1.SetSelection(self.settings.get('ammoPattern'))
|
||||
rbSizerRow1.Add(self.rbBox1, 1, wx.TOP | wx.RIGHT, 5)
|
||||
self.rbBox1.Bind(wx.EVT_RADIOBOX, self.OnSetting1Change)
|
||||
|
||||
self.rbBox2 = wx.RadioBox(panel, -1, "Change Skills", wx.DefaultPosition, wx.DefaultSize, ['Disabled', 'Enabled'], 1, wx.RA_SPECIFY_COLS)
|
||||
self.rbBox2.SetSelection(self.settings.get('changeAffectingSkills'))
|
||||
rbSizerRow1.Add(self.rbBox2, 1, wx.ALL, 5)
|
||||
self.rbBox2.Bind(wx.EVT_RADIOBOX, self.OnSetting2Change)
|
||||
|
||||
self.rbBox3 = wx.RadioBox(panel, -1, "Factor in Reload Time", wx.DefaultPosition, wx.DefaultSize, ['Disabled', 'Enabled'], 1, wx.RA_SPECIFY_COLS)
|
||||
self.rbBox3.SetSelection(self.settings.get('factorReload'))
|
||||
rbSizerRow1.Add(self.rbBox3, 1, wx.ALL, 5)
|
||||
self.rbBox3.Bind(wx.EVT_RADIOBOX, self.OnSetting3Change)
|
||||
|
||||
mainSizer.Add(rbSizerRow1, 1, wx.ALL | wx.EXPAND, 0)
|
||||
|
||||
# Row 2
|
||||
rbSizerRow2 = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
self.rbBox4 = wx.RadioBox(panel, -1, "Variations", wx.DefaultPosition, wx.DefaultSize, ['Disabled', 'Enabled'], 1, wx.RA_SPECIFY_COLS)
|
||||
self.rbBox4.SetSelection(self.settings.get('metaSwap'))
|
||||
rbSizerRow2.Add(self.rbBox4, 1, wx.TOP | wx.RIGHT, 5)
|
||||
self.rbBox4.Bind(wx.EVT_RADIOBOX, self.OnSetting4Change)
|
||||
|
||||
'''
|
||||
self.rbBox5 = wx.RadioBox(panel, -1, "Charge", wx.DefaultPosition, wx.DefaultSize, ['Disabled', 'Enabled'], 1, wx.RA_SPECIFY_COLS)
|
||||
self.rbBox5.SetSelection(self.settings.get('moduleAmmoPicker'))
|
||||
rbSizerRow2.Add(self.rbBox5, 1, wx.ALL, 5)
|
||||
self.rbBox5.Bind(wx.EVT_RADIOBOX, self.OnSetting5Change)
|
||||
'''
|
||||
|
||||
self.rbBox6 = wx.RadioBox(panel, -1, "Charge (All)", wx.DefaultPosition, wx.DefaultSize, ['Disabled', 'Enabled'], 1, wx.RA_SPECIFY_COLS)
|
||||
self.rbBox6.SetSelection(self.settings.get('moduleGlobalAmmoPicker'))
|
||||
rbSizerRow2.Add(self.rbBox6, 1, wx.ALL, 5)
|
||||
self.rbBox6.Bind(wx.EVT_RADIOBOX, self.OnSetting6Change)
|
||||
|
||||
mainSizer.Add(rbSizerRow2, 1, wx.ALL | wx.EXPAND, 0)
|
||||
|
||||
# Row 3
|
||||
rbSizerRow3 = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
self.rbBox7 = wx.RadioBox(panel, -1, "Project onto Fit", wx.DefaultPosition, wx.DefaultSize, ['Disabled', 'Enabled'], 1, wx.RA_SPECIFY_COLS)
|
||||
self.rbBox7.SetSelection(self.settings.get('project'))
|
||||
rbSizerRow3.Add(self.rbBox7, 1, wx.TOP | wx.RIGHT, 5)
|
||||
self.rbBox7.Bind(wx.EVT_RADIOBOX, self.OnSetting7Change)
|
||||
|
||||
mainSizer.Add(rbSizerRow3, 1, wx.ALL | wx.EXPAND, 0)
|
||||
|
||||
panel.SetSizer(mainSizer)
|
||||
panel.Layout()
|
||||
|
||||
def OnSetting1Change(self, event):
|
||||
self.settings.set('ammoPattern', event.GetInt())
|
||||
|
||||
def OnSetting2Change(self, event):
|
||||
self.settings.set('changeAffectingSkills', event.GetInt())
|
||||
|
||||
def OnSetting3Change(self, event):
|
||||
self.settings.set('factorReload', event.GetInt())
|
||||
|
||||
def OnSetting4Change(self, event):
|
||||
self.settings.set('metaSwap', event.GetInt())
|
||||
|
||||
def OnSetting5Change(self, event):
|
||||
self.settings.set('moduleAmmoPicker', event.GetInt())
|
||||
|
||||
def OnSetting6Change(self, event):
|
||||
self.settings.set('moduleGlobalAmmoPicker', event.GetInt())
|
||||
|
||||
def OnSetting7Change(self, event):
|
||||
self.settings.set('project', event.GetInt())
|
||||
|
||||
def getImage(self):
|
||||
return BitmapLoader.getBitmap("settings_menu", "gui")
|
||||
|
||||
|
||||
PFContextMenuPref.register()
|
||||
112
gui/builtinPreferenceViews/pyfaDatabasePreferences.py
Normal file
112
gui/builtinPreferenceViews/pyfaDatabasePreferences.py
Normal file
@@ -0,0 +1,112 @@
|
||||
import wx
|
||||
|
||||
from gui.preferenceView import PreferenceView
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
import config
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PFGeneralPref(PreferenceView):
|
||||
title = "Database"
|
||||
|
||||
def populatePanel(self, panel):
|
||||
self.dirtySettings = False
|
||||
# self.openFitsSettings = service.SettingsProvider.getInstance().getSettings("pyfaPrevOpenFits", {"enabled": False, "pyfaOpenFits": []})
|
||||
|
||||
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.stSubTitle = wx.StaticText(panel, wx.ID_ANY, u"(Cannot be changed while pyfa is running. Set via command line switches.)",
|
||||
wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stSubTitle.Wrap(-1)
|
||||
mainSizer.Add(self.stSubTitle, 0, wx.ALL, 3)
|
||||
|
||||
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)
|
||||
|
||||
# Save in Root
|
||||
self.cbsaveInRoot = wx.CheckBox(panel, wx.ID_ANY, u"Using Executable Path for Saved Fit Database and Settings", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
mainSizer.Add(self.cbsaveInRoot, 0, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
# Database path
|
||||
self.stSetUserPath = wx.StaticText(panel, wx.ID_ANY, u"pyfa User Path:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stSetUserPath.Wrap(-1)
|
||||
mainSizer.Add(self.stSetUserPath, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
self.inputUserPath = wx.TextCtrl(panel, wx.ID_ANY, config.savePath, wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.inputUserPath.SetEditable(False)
|
||||
self.inputUserPath.SetBackgroundColour((200, 200, 200))
|
||||
mainSizer.Add(self.inputUserPath, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5)
|
||||
|
||||
# Save DB
|
||||
self.stFitDB = wx.StaticText(panel, wx.ID_ANY, u"Fitting Database:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stFitDB.Wrap(-1)
|
||||
mainSizer.Add(self.stFitDB, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
|
||||
self.inputFitDB = wx.TextCtrl(panel, wx.ID_ANY, config.saveDB, wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.inputFitDB.SetEditable(False)
|
||||
self.inputFitDB.SetBackgroundColour((200, 200, 200))
|
||||
mainSizer.Add(self.inputFitDB, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5)
|
||||
|
||||
# Game Data DB
|
||||
self.stGameDB = wx.StaticText(panel, wx.ID_ANY, u"Game Database:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stGameDB.Wrap(-1)
|
||||
mainSizer.Add(self.stGameDB, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
|
||||
self.inputGameDB = wx.TextCtrl(panel, wx.ID_ANY, config.gameDB, wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.inputGameDB.SetEditable(False)
|
||||
self.inputGameDB.SetBackgroundColour((200, 200, 200))
|
||||
mainSizer.Add(self.inputGameDB, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5)
|
||||
|
||||
self.cbsaveInRoot.SetValue(config.saveInRoot)
|
||||
self.cbsaveInRoot.Bind(wx.EVT_CHECKBOX, self.onCBsaveInRoot)
|
||||
|
||||
self.inputUserPath.Bind(wx.EVT_LEAVE_WINDOW, self.OnWindowLeave)
|
||||
self.inputFitDB.Bind(wx.EVT_LEAVE_WINDOW, self.OnWindowLeave)
|
||||
self.inputGameDB.Bind(wx.EVT_LEAVE_WINDOW, self.OnWindowLeave)
|
||||
|
||||
panel.SetSizer(mainSizer)
|
||||
panel.Layout()
|
||||
|
||||
def onCBsaveInRoot(self, event):
|
||||
# We don't want users to be able to actually change this,
|
||||
# so if they try and change it, set it back to the current setting
|
||||
self.cbsaveInRoot.SetValue(config.saveInRoot)
|
||||
|
||||
# If we ever enable it might need this.
|
||||
'''
|
||||
config.saveInRoot = self.cbsaveInRoot.GetValue()
|
||||
'''
|
||||
|
||||
def getImage(self):
|
||||
return BitmapLoader.getBitmap("settings_database", "gui")
|
||||
|
||||
def OnWindowLeave(self, event):
|
||||
# We don't want to do anything when they leave,
|
||||
# but in the future we'd want to make sure settings
|
||||
# changed get saved.
|
||||
pass
|
||||
|
||||
'''
|
||||
#Set database path
|
||||
config.defPaths(self.inputFitDBPath.GetValue())
|
||||
|
||||
logger.debug("Running database import")
|
||||
if self.cbimportDefaults is True:
|
||||
# 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()
|
||||
'''
|
||||
|
||||
|
||||
PFGeneralPref.register()
|
||||
84
gui/builtinPreferenceViews/pyfaEnginePreferences.py
Normal file
84
gui/builtinPreferenceViews/pyfaEnginePreferences.py
Normal file
@@ -0,0 +1,84 @@
|
||||
import logging
|
||||
|
||||
import wx
|
||||
|
||||
from service.fit import Fit
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
from gui.preferenceView import PreferenceView
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PFFittingEnginePref(PreferenceView):
|
||||
title = "Fitting Engine"
|
||||
|
||||
def __init__(self):
|
||||
self.dirtySettings = False
|
||||
|
||||
def refreshPanel(self, fit):
|
||||
pass
|
||||
|
||||
# noinspection PyAttributeOutsideInit
|
||||
def populatePanel(self, panel):
|
||||
# self.openFitsSettings = service.SettingsProvider.getInstance().getSettings("pyfaPrevOpenFits", {"enabled": False, "pyfaOpenFits": []})
|
||||
|
||||
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.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.cbGlobalForceReload = wx.CheckBox(panel, wx.ID_ANY, u"Factor in reload time when calculating capacitor usage, damage, and tank.",
|
||||
wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
mainSizer.Add(self.cbGlobalForceReload, 0, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
# Future code once new cap sim is implemented
|
||||
'''
|
||||
self.cbGlobalForceReactivationTimer = wx.CheckBox( panel, wx.ID_ANY, u"Factor in reactivation timer", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
mainSizer.Add( self.cbGlobalForceReactivationTimer, 0, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
text = u" Ignores reactivation timer when calculating capacitor usage,\n damage, and tank."
|
||||
self.cbGlobalForceReactivationTimerText = wx.StaticText( panel, wx.ID_ANY, text, wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.cbGlobalForceReactivationTimerText.Wrap( -1 )
|
||||
self.cbGlobalForceReactivationTimerText.SetFont( wx.Font( 10, 70, 90, 90, False, wx.EmptyString ) )
|
||||
mainSizer.Add( self.cbGlobalForceReactivationTimerText, 0, wx.ALL, 5 )
|
||||
'''
|
||||
|
||||
# Future code for mining laser crystal
|
||||
'''
|
||||
self.cbGlobalMiningSpecialtyCrystal = wx.CheckBox( panel, wx.ID_ANY, u"Factor in reactivation timer", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
mainSizer.Add( self.cbGlobalMiningSpecialtyCrystal, 0, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
text = u" If enabled, displays the Specialty Crystal mining amount.\n This is the amount mined when using crystals and mining the matching asteroid."
|
||||
self.cbGlobalMiningSpecialtyCrystalText = wx.StaticText( panel, wx.ID_ANY, text, wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.cbGlobalMiningSpecialtyCrystalText.Wrap( -1 )
|
||||
self.cbGlobalMiningSpecialtyCrystalText.SetFont( wx.Font( 10, 70, 90, 90, False, wx.EmptyString ) )
|
||||
mainSizer.Add( self.cbGlobalMiningSpecialtyCrystalText, 0, wx.ALL, 5 )
|
||||
'''
|
||||
|
||||
self.sFit = Fit.getInstance()
|
||||
|
||||
self.cbGlobalForceReload.SetValue(self.sFit.serviceFittingOptions["useGlobalForceReload"])
|
||||
|
||||
self.cbGlobalForceReload.Bind(wx.EVT_CHECKBOX, self.OnCBGlobalForceReloadStateChange)
|
||||
|
||||
panel.SetSizer(mainSizer)
|
||||
panel.Layout()
|
||||
|
||||
def OnCBGlobalForceReloadStateChange(self, event):
|
||||
self.sFit.serviceFittingOptions["useGlobalForceReload"] = self.cbGlobalForceReload.GetValue()
|
||||
|
||||
def getImage(self):
|
||||
return BitmapLoader.getBitmap("settings_fitting", "gui")
|
||||
|
||||
def OnWindowLeave(self, event):
|
||||
# We don't want to do anything when they leave,
|
||||
# but in the future we might.
|
||||
pass
|
||||
|
||||
|
||||
PFFittingEnginePref.register()
|
||||
@@ -40,10 +40,6 @@ class PFGeneralPref(PreferenceView):
|
||||
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.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)
|
||||
@@ -97,7 +93,6 @@ class PFGeneralPref(PreferenceView):
|
||||
|
||||
self.cbGlobalChar.SetValue(self.sFit.serviceFittingOptions["useGlobalCharacter"])
|
||||
self.cbGlobalDmgPattern.SetValue(self.sFit.serviceFittingOptions["useGlobalDamagePattern"])
|
||||
self.cbGlobalForceReload.SetValue(self.sFit.serviceFittingOptions["useGlobalForceReload"])
|
||||
self.cbFitColorSlots.SetValue(self.sFit.serviceFittingOptions["colorFitBySlot"] or False)
|
||||
self.cbRackSlots.SetValue(self.sFit.serviceFittingOptions["rackSlots"] or False)
|
||||
self.cbRackLabels.SetValue(self.sFit.serviceFittingOptions["rackLabels"] or False)
|
||||
@@ -112,7 +107,6 @@ class PFGeneralPref(PreferenceView):
|
||||
|
||||
self.cbGlobalChar.Bind(wx.EVT_CHECKBOX, self.OnCBGlobalCharStateChange)
|
||||
self.cbGlobalDmgPattern.Bind(wx.EVT_CHECKBOX, self.OnCBGlobalDmgPatternStateChange)
|
||||
self.cbGlobalForceReload.Bind(wx.EVT_CHECKBOX, self.OnCBGlobalForceReloadStateChange)
|
||||
self.cbFitColorSlots.Bind(wx.EVT_CHECKBOX, self.onCBGlobalColorBySlot)
|
||||
self.cbRackSlots.Bind(wx.EVT_CHECKBOX, self.onCBGlobalRackSlots)
|
||||
self.cbRackLabels.Bind(wx.EVT_CHECKBOX, self.onCBGlobalRackLabels)
|
||||
@@ -152,13 +146,6 @@ class PFGeneralPref(PreferenceView):
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
|
||||
event.Skip()
|
||||
|
||||
def OnCBGlobalForceReloadStateChange(self, event):
|
||||
self.sFit.serviceFittingOptions["useGlobalForceReload"] = self.cbGlobalForceReload.GetValue()
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
self.sFit.refreshFit(fitID)
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
|
||||
event.Skip()
|
||||
|
||||
def OnCBGlobalCharStateChange(self, event):
|
||||
self.sFit.serviceFittingOptions["useGlobalCharacter"] = self.cbGlobalChar.GetValue()
|
||||
event.Skip()
|
||||
|
||||
59
gui/builtinPreferenceViews/pyfaLoggingPreferences.py
Normal file
59
gui/builtinPreferenceViews/pyfaLoggingPreferences.py
Normal file
@@ -0,0 +1,59 @@
|
||||
import wx
|
||||
|
||||
from gui.preferenceView import PreferenceView
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
import config
|
||||
|
||||
|
||||
class PFGeneralPref(PreferenceView):
|
||||
title = "Logging"
|
||||
|
||||
def populatePanel(self, panel):
|
||||
self.dirtySettings = False
|
||||
# self.openFitsSettings = service.SettingsProvider.getInstance().getSettings("pyfaPrevOpenFits", {"enabled": False, "pyfaOpenFits": []})
|
||||
|
||||
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.stSubTitle = wx.StaticText(panel, wx.ID_ANY, u"(Cannot be changed while pyfa is running. Set via command line switches.)",
|
||||
wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stSubTitle.Wrap(-1)
|
||||
mainSizer.Add(self.stSubTitle, 0, wx.ALL, 3)
|
||||
|
||||
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)
|
||||
|
||||
# Debug Logging
|
||||
self.cbdebugLogging = wx.CheckBox(panel, wx.ID_ANY, u"Debug Logging Enabled", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
mainSizer.Add(self.cbdebugLogging, 0, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
self.cbdebugLogging.SetValue(config.debug)
|
||||
self.cbdebugLogging.Bind(wx.EVT_CHECKBOX, self.onCBdebugLogging)
|
||||
|
||||
panel.SetSizer(mainSizer)
|
||||
panel.Layout()
|
||||
|
||||
def onCBdebugLogging(self, event):
|
||||
# We don't want users to be able to actually change this,
|
||||
# so if they try and change it, set it back to the current setting
|
||||
self.cbdebugLogging.SetValue(config.debug)
|
||||
|
||||
# In case we do, down there road, here's a bit of a start.
|
||||
'''
|
||||
if self.cbdebugLogging.GetValue() is True:
|
||||
self.cbdebugLogging.SetValue(False)
|
||||
config.Debug = self.cbdebugLogging.GetValue()
|
||||
else:
|
||||
self.cbdebugLogging.SetValue(True)
|
||||
config.Debug = self.cbdebugLogging.GetValue()
|
||||
'''
|
||||
|
||||
def getImage(self):
|
||||
return BitmapLoader.getBitmap("settings_log", "gui")
|
||||
|
||||
|
||||
PFGeneralPref.register()
|
||||
158
gui/builtinPreferenceViews/pyfaStatViewPreferences.py
Normal file
158
gui/builtinPreferenceViews/pyfaStatViewPreferences.py
Normal file
@@ -0,0 +1,158 @@
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
|
||||
from gui.preferenceView import PreferenceView
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
from service.settings import StatViewSettings
|
||||
|
||||
|
||||
class PFStatViewPref(PreferenceView):
|
||||
title = "Statistics Panel"
|
||||
|
||||
def __init__(self):
|
||||
self.dirtySettings = False
|
||||
self.settings = StatViewSettings.getInstance()
|
||||
|
||||
def refreshPanel(self, fit):
|
||||
pass
|
||||
|
||||
# noinspection PyAttributeOutsideInit
|
||||
def populatePanel(self, panel):
|
||||
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.stSubTitle = wx.StaticText(panel, wx.ID_ANY,
|
||||
u"Changes require restart of pyfa to take effect.",
|
||||
wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stSubTitle.Wrap(-1)
|
||||
mainSizer.Add(self.stSubTitle, 0, wx.ALL, 3)
|
||||
|
||||
# Row 1
|
||||
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.ALL, 5)
|
||||
|
||||
rbSizerRow1 = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
self.rbResources = wx.RadioBox(panel, -1, "Resources", wx.DefaultPosition, wx.DefaultSize, ['None', 'Minimal', 'Full'], 1, wx.RA_SPECIFY_COLS)
|
||||
# Disable minimal as we don't have a view for this yet
|
||||
self.rbResources.EnableItem(1, False)
|
||||
self.rbResources.SetSelection(self.settings.get('resources'))
|
||||
rbSizerRow1.Add(self.rbResources, 1, wx.TOP | wx.RIGHT, 5)
|
||||
self.rbResources.Bind(wx.EVT_RADIOBOX, self.OnResourcesChange)
|
||||
|
||||
self.rbResistances = wx.RadioBox(panel, -1, "Resistances", wx.DefaultPosition, wx.DefaultSize, ['None', 'Minimal', 'Full'], 1, wx.RA_SPECIFY_COLS)
|
||||
# Disable minimal as we don't have a view for this yet
|
||||
self.rbResistances.EnableItem(1, False)
|
||||
self.rbResistances.SetSelection(self.settings.get('resistances'))
|
||||
rbSizerRow1.Add(self.rbResistances, 1, wx.ALL, 5)
|
||||
self.rbResistances.Bind(wx.EVT_RADIOBOX, self.OnResistancesChange)
|
||||
|
||||
self.rbRecharge = wx.RadioBox(panel, -1, "Shield/Armor Tank", wx.DefaultPosition, wx.DefaultSize, ['None', 'Minimal', 'Full'], 1, wx.RA_SPECIFY_COLS)
|
||||
# Disable minimal as we don't have a view for this yet
|
||||
self.rbRecharge.EnableItem(1, False)
|
||||
self.rbRecharge.SetSelection(self.settings.get('recharge'))
|
||||
rbSizerRow1.Add(self.rbRecharge, 1, wx.ALL, 5)
|
||||
self.rbRecharge.Bind(wx.EVT_RADIOBOX, self.OnRechargeChange)
|
||||
|
||||
mainSizer.Add(rbSizerRow1, 1, wx.ALL | wx.EXPAND, 0)
|
||||
|
||||
# Row 2
|
||||
rbSizerRow2 = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
self.rbFirepower = wx.RadioBox(panel, -1, "Firepower", wx.DefaultPosition, wx.DefaultSize, ['None', 'Minimal', 'Full'], 1, wx.RA_SPECIFY_COLS)
|
||||
# Disable minimal as we don't have a view for this yet
|
||||
self.rbFirepower.EnableItem(1, False)
|
||||
self.rbFirepower.SetSelection(self.settings.get('firepower'))
|
||||
rbSizerRow2.Add(self.rbFirepower, 1, wx.TOP | wx.RIGHT, 5)
|
||||
self.rbFirepower.Bind(wx.EVT_RADIOBOX, self.OnFirepowerChange)
|
||||
|
||||
self.rbCapacitor = wx.RadioBox(panel, -1, "Capacitor", wx.DefaultPosition, wx.DefaultSize, ['None', 'Minimal', 'Full'], 1, wx.RA_SPECIFY_COLS)
|
||||
# Disable minimal as we don't have a view for this yet
|
||||
self.rbCapacitor.EnableItem(1, False)
|
||||
self.rbCapacitor.SetSelection(self.settings.get('capacitor'))
|
||||
rbSizerRow2.Add(self.rbCapacitor, 1, wx.ALL, 5)
|
||||
self.rbCapacitor.Bind(wx.EVT_RADIOBOX, self.OnCapacitorChange)
|
||||
|
||||
self.rbMisc = wx.RadioBox(panel, -1, "Misc", wx.DefaultPosition, wx.DefaultSize, ['None', 'Minimal', 'Full'], 1, wx.RA_SPECIFY_COLS)
|
||||
# Disable full as we don't have a view for this yet
|
||||
self.rbMisc.EnableItem(2, False)
|
||||
self.rbMisc.SetSelection(self.settings.get('targetingMisc'))
|
||||
rbSizerRow2.Add(self.rbMisc, 1, wx.ALL, 5)
|
||||
self.rbMisc.Bind(wx.EVT_RADIOBOX, self.OnTargetingMiscChange)
|
||||
|
||||
mainSizer.Add(rbSizerRow2, 1, wx.ALL | wx.EXPAND, 0)
|
||||
|
||||
# Row 3
|
||||
rbSizerRow3 = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
self.rbPrice = wx.RadioBox(panel, -1, "Price", wx.DefaultPosition, wx.DefaultSize, ['None', 'Minimal', 'Full'], 1, wx.RA_SPECIFY_COLS)
|
||||
# Disable minimal as we don't have a view for this yet
|
||||
self.rbPrice.EnableItem(1, False)
|
||||
self.rbPrice.SetSelection(self.settings.get('price'))
|
||||
rbSizerRow3.Add(self.rbPrice, 1, wx.TOP | wx.RIGHT, 5)
|
||||
self.rbPrice.Bind(wx.EVT_RADIOBOX, self.OnPriceChange)
|
||||
|
||||
self.rbOutgoing = wx.RadioBox(panel, -1, "Remote Reps", wx.DefaultPosition, wx.DefaultSize, ['None', 'Minimal', 'Full'], 1, wx.RA_SPECIFY_COLS)
|
||||
self.rbOutgoing.SetSelection(self.settings.get('outgoing'))
|
||||
rbSizerRow3.Add(self.rbOutgoing, 1, wx.TOP | wx.RIGHT, 5)
|
||||
self.rbOutgoing.Bind(wx.EVT_RADIOBOX, self.OnOutgoingChange)
|
||||
# We don't have views for these.....yet
|
||||
'''
|
||||
self.rbMining = wx.RadioBox(panel, -1, "Mining", wx.DefaultPosition, wx.DefaultSize,
|
||||
['None', 'Minimal', 'Full'], 1, wx.RA_SPECIFY_COLS)
|
||||
self.rbMining.SetSelection(self.settings.get('miningyield'))
|
||||
rbSizerRow3.Add(self.rbMining, 1, wx.ALL, 5)
|
||||
self.rbMining.Bind(wx.EVT_RADIOBOX, self.OnMiningYieldChange)
|
||||
|
||||
self.rbDrones = wx.RadioBox(panel, -1, "Drones", wx.DefaultPosition, wx.DefaultSize,
|
||||
['None', 'Minimal', 'Full'], 1, wx.RA_SPECIFY_COLS)
|
||||
self.rbDrones.SetSelection(self.settings.get('drones'))
|
||||
rbSizerRow3.Add(self.rbDrones, 1, wx.ALL, 5)
|
||||
self.rbDrones.Bind(wx.EVT_RADIOBOX, self.OnDroneChange)
|
||||
'''
|
||||
|
||||
mainSizer.Add(rbSizerRow3, 1, wx.ALL | wx.EXPAND, 0)
|
||||
|
||||
panel.SetSizer(mainSizer)
|
||||
panel.Layout()
|
||||
|
||||
def OnResourcesChange(self, event):
|
||||
self.settings.set('resources', event.GetInt())
|
||||
|
||||
def OnResistancesChange(self, event):
|
||||
self.settings.set('resistances', event.GetInt())
|
||||
|
||||
def OnRechargeChange(self, event):
|
||||
self.settings.set('recharge', event.GetInt())
|
||||
|
||||
def OnFirepowerChange(self, event):
|
||||
self.settings.set('firepower', event.GetInt())
|
||||
|
||||
def OnCapacitorChange(self, event):
|
||||
self.settings.set('capacitor', event.GetInt())
|
||||
|
||||
def OnTargetingMiscChange(self, event):
|
||||
self.settings.set('targetingMisc', event.GetInt())
|
||||
|
||||
def OnPriceChange(self, event):
|
||||
self.settings.set('price', event.GetInt())
|
||||
|
||||
def OnOutgoingChange(self, event):
|
||||
self.settings.set('outgoing', event.GetInt())
|
||||
|
||||
def OnMiningYieldChange(self, event):
|
||||
self.settings.set('miningyield', event.GetInt())
|
||||
|
||||
def OnDroneChange(self, event):
|
||||
self.settings.set('drones', event.GetInt())
|
||||
|
||||
def getImage(self):
|
||||
return BitmapLoader.getBitmap("settings_stats", "gui")
|
||||
|
||||
|
||||
PFStatViewPref.register()
|
||||
@@ -44,7 +44,7 @@ class PFUpdatePref(PreferenceView):
|
||||
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.UpdateSettings.get('version')), wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.versionTitle.Wrap(-1)
|
||||
self.versionTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString))
|
||||
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
__all__ = ["resourcesViewFull", "resistancesViewFull",
|
||||
"rechargeViewFull", "firepowerViewFull", "capacitorViewFull",
|
||||
"targetingMiscViewFull", "priceViewFull", "miningyieldViewFull"]
|
||||
__all__ = [
|
||||
"resourcesViewFull",
|
||||
"resistancesViewFull",
|
||||
"rechargeViewFull",
|
||||
"firepowerViewFull",
|
||||
"capacitorViewFull",
|
||||
"outgoingViewFull",
|
||||
"outgoingViewMinimal",
|
||||
"targetingMiscViewMinimal",
|
||||
"priceViewFull",
|
||||
]
|
||||
|
||||
106
gui/builtinStatsViews/outgoingViewFull.py
Normal file
106
gui/builtinStatsViews/outgoingViewFull.py
Normal file
@@ -0,0 +1,106 @@
|
||||
# ===============================================================================
|
||||
# Copyright (C) 2014 Alexandros Kosiaris
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
from gui.statsView import StatsView
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
from gui.utils.numberFormatter import formatAmount
|
||||
|
||||
|
||||
class OutgoingViewFull(StatsView):
|
||||
name = "outgoingViewFull"
|
||||
|
||||
def __init__(self, parent):
|
||||
StatsView.__init__(self)
|
||||
self.parent = parent
|
||||
self._cachedValues = []
|
||||
|
||||
def getHeaderText(self, fit):
|
||||
return "Remote Reps"
|
||||
|
||||
def getTextExtentW(self, text):
|
||||
width, height = self.parent.GetTextExtent(text)
|
||||
return width
|
||||
|
||||
def populatePanel(self, contentPanel, headerPanel):
|
||||
contentSizer = contentPanel.GetSizer()
|
||||
parent = self.panel = contentPanel
|
||||
self.headerPanel = headerPanel
|
||||
|
||||
sizerOutgoing = wx.GridSizer(1, 4)
|
||||
|
||||
contentSizer.Add(sizerOutgoing, 0, wx.EXPAND, 0)
|
||||
|
||||
counter = 0
|
||||
|
||||
rr_list = [
|
||||
("RemoteCapacitor", "Capacitor:", "capacitorInfo", "Capacitor GJ/s per second transferred remotely."),
|
||||
("RemoteShield", "Shield:", "shieldActive", "Shield hitpoints per second repaired remotely."),
|
||||
("RemoteArmor", "Armor:", "armorActive", "Armor hitpoints per second repaired remotely."),
|
||||
("RemoteHull", "Hull:", "hullActive", "Hull hitpoints per second repaired remotely."),
|
||||
]
|
||||
|
||||
for outgoingType, label, image, tooltip in rr_list:
|
||||
baseBox = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
baseBox.Add(BitmapLoader.getStaticBitmap("%s_big" % image, parent, "gui"), 0, wx.ALIGN_CENTER)
|
||||
|
||||
if "Capacitor" in outgoingType:
|
||||
lbl = wx.StaticText(parent, wx.ID_ANY, u"0 GJ/s")
|
||||
else:
|
||||
lbl = wx.StaticText(parent, wx.ID_ANY, u"0 HP/s")
|
||||
|
||||
lbl.SetToolTip(wx.ToolTip(tooltip))
|
||||
|
||||
setattr(self, "label%s" % outgoingType, lbl)
|
||||
|
||||
baseBox.Add(lbl, 0, wx.ALIGN_CENTER)
|
||||
self._cachedValues.append(0)
|
||||
counter += 1
|
||||
|
||||
sizerOutgoing.Add(baseBox, 1, wx.ALIGN_LEFT)
|
||||
|
||||
def refreshPanel(self, fit):
|
||||
# If we did anything intresting, we'd update our labels to reflect the new fit's stats here
|
||||
|
||||
stats = [
|
||||
("labelRemoteArmor", lambda: fit.remoteReps["Armor"], 3, 0, 0, u"%s HP/s", None),
|
||||
("labelRemoteShield", lambda: fit.remoteReps["Shield"], 3, 0, 0, u"%s HP/s", None),
|
||||
("labelRemoteHull", lambda: fit.remoteReps["Hull"], 3, 0, 0, u"%s HP/s", None),
|
||||
("labelRemoteCapacitor", lambda: fit.remoteReps["Capacitor"], 3, 0, 0, u"%s GJ/s", None),
|
||||
]
|
||||
|
||||
counter = 0
|
||||
for labelName, value, prec, lowest, highest, valueFormat, altFormat in stats:
|
||||
label = getattr(self, labelName)
|
||||
value = value() if fit is not None else 0
|
||||
value = value if value is not None else 0
|
||||
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
|
||||
label.SetToolTip(wx.ToolTip(tipStr))
|
||||
self._cachedValues[counter] = value
|
||||
counter += 1
|
||||
self.panel.Layout()
|
||||
self.headerPanel.Layout()
|
||||
|
||||
|
||||
OutgoingViewFull.register()
|
||||
106
gui/builtinStatsViews/outgoingViewMinimal.py
Normal file
106
gui/builtinStatsViews/outgoingViewMinimal.py
Normal file
@@ -0,0 +1,106 @@
|
||||
# ===============================================================================
|
||||
# Copyright (C) 2014 Alexandros Kosiaris
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
from gui.statsView import StatsView
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
from gui.utils.numberFormatter import formatAmount
|
||||
|
||||
|
||||
class OutgoingViewMinimal(StatsView):
|
||||
name = "outgoingViewMinimal"
|
||||
|
||||
def __init__(self, parent):
|
||||
StatsView.__init__(self)
|
||||
self.parent = parent
|
||||
self._cachedValues = []
|
||||
|
||||
def getHeaderText(self, fit):
|
||||
return "Remote Reps"
|
||||
|
||||
def getTextExtentW(self, text):
|
||||
width, height = self.parent.GetTextExtent(text)
|
||||
return width
|
||||
|
||||
def populatePanel(self, contentPanel, headerPanel):
|
||||
contentSizer = contentPanel.GetSizer()
|
||||
parent = self.panel = contentPanel
|
||||
self.headerPanel = headerPanel
|
||||
|
||||
sizerOutgoing = wx.GridSizer(1, 4)
|
||||
|
||||
contentSizer.Add(sizerOutgoing, 0, wx.EXPAND, 0)
|
||||
|
||||
counter = 0
|
||||
|
||||
rr_list = [
|
||||
("RemoteCapacitor", "Capacitor:", "capacitorInfo", "Capacitor GJ/s per second transferred remotely."),
|
||||
("RemoteShield", "Shield:", "shieldActive", "Shield hitpoints per second repaired remotely."),
|
||||
("RemoteArmor", "Armor:", "armorActive", "Armor hitpoints per second repaired remotely."),
|
||||
("RemoteHull", "Hull:", "hullActive", "Hull hitpoints per second repaired remotely."),
|
||||
]
|
||||
|
||||
for outgoingType, label, image, tooltip in rr_list:
|
||||
baseBox = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
baseBox.Add(wx.StaticText(contentPanel, wx.ID_ANY, label), 0, wx.ALIGN_CENTER)
|
||||
|
||||
if "Capacitor" in outgoingType:
|
||||
lbl = wx.StaticText(parent, wx.ID_ANY, u"0 GJ/s")
|
||||
else:
|
||||
lbl = wx.StaticText(parent, wx.ID_ANY, u"0 HP/s")
|
||||
|
||||
lbl.SetToolTip(wx.ToolTip(tooltip))
|
||||
|
||||
setattr(self, "label%s" % outgoingType, lbl)
|
||||
|
||||
baseBox.Add(lbl, 0, wx.ALIGN_CENTER)
|
||||
self._cachedValues.append(0)
|
||||
counter += 1
|
||||
|
||||
sizerOutgoing.Add(baseBox, 1, wx.ALIGN_LEFT)
|
||||
|
||||
def refreshPanel(self, fit):
|
||||
# If we did anything intresting, we'd update our labels to reflect the new fit's stats here
|
||||
|
||||
stats = [
|
||||
("labelRemoteArmor", lambda: fit.remoteReps["Armor"], 3, 0, 0, u"%s HP/s", None),
|
||||
("labelRemoteShield", lambda: fit.remoteReps["Shield"], 3, 0, 0, u"%s HP/s", None),
|
||||
("labelRemoteHull", lambda: fit.remoteReps["Hull"], 3, 0, 0, u"%s HP/s", None),
|
||||
("labelRemoteCapacitor", lambda: fit.remoteReps["Capacitor"], 3, 0, 0, u"%s GJ/s", None),
|
||||
]
|
||||
|
||||
counter = 0
|
||||
for labelName, value, prec, lowest, highest, valueFormat, altFormat in stats:
|
||||
label = getattr(self, labelName)
|
||||
value = value() if fit is not None else 0
|
||||
value = value if value is not None else 0
|
||||
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
|
||||
label.SetToolTip(wx.ToolTip(tipStr))
|
||||
self._cachedValues[counter] = value
|
||||
counter += 1
|
||||
self.panel.Layout()
|
||||
self.headerPanel.Layout()
|
||||
|
||||
|
||||
OutgoingViewMinimal.register()
|
||||
@@ -29,7 +29,7 @@ except ImportError:
|
||||
|
||||
|
||||
class TargetingMiscViewFull(StatsView):
|
||||
name = "targetingmiscViewFull"
|
||||
name = "targetingMiscViewFull"
|
||||
|
||||
def __init__(self, parent):
|
||||
StatsView.__init__(self)
|
||||
|
||||
256
gui/builtinStatsViews/targetingMiscViewMinimal.py
Normal file
256
gui/builtinStatsViews/targetingMiscViewMinimal.py
Normal file
@@ -0,0 +1,256 @@
|
||||
# =============================================================================
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
# =============================================================================
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
from gui.statsView import StatsView
|
||||
from gui.utils.numberFormatter import formatAmount
|
||||
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
except ImportError:
|
||||
from utils.compat import OrderedDict
|
||||
|
||||
|
||||
class TargetingMiscViewMinimal(StatsView):
|
||||
name = "targetingMiscViewMinimal"
|
||||
|
||||
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)
|
||||
return width
|
||||
|
||||
def populatePanel(self, contentPanel, headerPanel):
|
||||
contentSizer = contentPanel.GetSizer()
|
||||
|
||||
self.panel = contentPanel
|
||||
self.headerPanel = headerPanel
|
||||
gridTargetingMisc = wx.FlexGridSizer(1, 3)
|
||||
contentSizer.Add(gridTargetingMisc, 0, wx.EXPAND | wx.ALL, 0)
|
||||
gridTargetingMisc.AddGrowableCol(0)
|
||||
gridTargetingMisc.AddGrowableCol(2)
|
||||
# Targeting
|
||||
|
||||
gridTargeting = wx.FlexGridSizer(5, 2)
|
||||
gridTargeting.AddGrowableCol(1)
|
||||
|
||||
gridTargetingMisc.Add(gridTargeting, 0, wx.ALIGN_LEFT | wx.ALL, 5)
|
||||
|
||||
labels = (("Targets", "Targets", ""),
|
||||
("Range", "Range", "km"),
|
||||
("Scan res.", "ScanRes", "mm"),
|
||||
("Sensor str.", "SensorStr", ""),
|
||||
("Drone range", "CtrlRange", "km"))
|
||||
|
||||
for header, labelShort, unit in labels:
|
||||
gridTargeting.Add(wx.StaticText(contentPanel, wx.ID_ANY, "%s: " % header), 0, wx.ALIGN_LEFT)
|
||||
|
||||
box = wx.BoxSizer(wx.HORIZONTAL)
|
||||
gridTargeting.Add(box, 0, wx.ALIGN_LEFT)
|
||||
|
||||
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)
|
||||
gridMisc = wx.FlexGridSizer(5, 2)
|
||||
gridMisc.AddGrowableCol(1)
|
||||
gridTargetingMisc.Add(gridMisc, 0, wx.ALIGN_LEFT | wx.ALL, 5)
|
||||
|
||||
labels = (("Speed", "Speed", "m/s"),
|
||||
("Align time", "AlignTime", "s"),
|
||||
("Signature", "SigRadius", "m"),
|
||||
("Warp Speed", "WarpSpeed", "AU/s"),
|
||||
("Cargo", "Cargo", u"m\u00B3"))
|
||||
|
||||
for header, labelShort, unit in labels:
|
||||
gridMisc.Add(wx.StaticText(contentPanel, wx.ID_ANY, "%s: " % header), 0, wx.ALIGN_LEFT)
|
||||
|
||||
box = wx.BoxSizer(wx.HORIZONTAL)
|
||||
gridMisc.Add(box, 0, wx.ALIGN_LEFT)
|
||||
|
||||
lbl = wx.StaticText(contentPanel, wx.ID_ANY, "0 %s" % unit)
|
||||
setattr(self, "labelFull%s" % labelShort, lbl)
|
||||
box.Add(lbl, 0, wx.ALIGN_LEFT)
|
||||
|
||||
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
|
||||
|
||||
cargoNamesOrder = OrderedDict((
|
||||
("fleetHangarCapacity", "Fleet hangar"),
|
||||
("shipMaintenanceBayCapacity", "Maintenance bay"),
|
||||
("specialAmmoHoldCapacity", "Ammo hold"),
|
||||
("specialFuelBayCapacity", "Fuel bay"),
|
||||
("specialShipHoldCapacity", "Ship hold"),
|
||||
("specialSmallShipHoldCapacity", "Small ship hold"),
|
||||
("specialMediumShipHoldCapacity", "Medium ship hold"),
|
||||
("specialLargeShipHoldCapacity", "Large ship hold"),
|
||||
("specialIndustrialShipHoldCapacity", "Industrial ship hold"),
|
||||
("specialOreHoldCapacity", "Ore hold"),
|
||||
("specialMineralHoldCapacity", "Mineral hold"),
|
||||
("specialMaterialBayCapacity", "Material bay"),
|
||||
("specialGasHoldCapacity", "Gas hold"),
|
||||
("specialSalvageHoldCapacity", "Salvage hold"),
|
||||
("specialCommandCenterHoldCapacity", "Command center hold"),
|
||||
("specialPlanetaryCommoditiesHoldCapacity", "Planetary goods hold"),
|
||||
("specialQuafeHoldCapacity", "Quafe hold")
|
||||
))
|
||||
|
||||
cargoValues = {
|
||||
"main": lambda: fit.ship.getModifiedItemAttr("capacity"),
|
||||
"fleetHangarCapacity": lambda: fit.ship.getModifiedItemAttr("fleetHangarCapacity"),
|
||||
"shipMaintenanceBayCapacity": lambda: fit.ship.getModifiedItemAttr("shipMaintenanceBayCapacity"),
|
||||
"specialAmmoHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialAmmoHoldCapacity"),
|
||||
"specialFuelBayCapacity": lambda: fit.ship.getModifiedItemAttr("specialFuelBayCapacity"),
|
||||
"specialShipHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialShipHoldCapacity"),
|
||||
"specialSmallShipHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialSmallShipHoldCapacity"),
|
||||
"specialMediumShipHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialMediumShipHoldCapacity"),
|
||||
"specialLargeShipHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialLargeShipHoldCapacity"),
|
||||
"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"),
|
||||
"specialQuafeHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialQuafeHoldCapacity")
|
||||
}
|
||||
|
||||
stats = (("labelTargets", {"main": lambda: fit.maxTargets}, 3, 0, 0, ""),
|
||||
("labelRange", {"main": lambda: fit.maxTargetRange / 1000}, 3, 0, 0, "km"),
|
||||
("labelScanRes", {"main": lambda: fit.ship.getModifiedItemAttr("scanResolution")}, 3, 0, 0, "mm"),
|
||||
("labelSensorStr", {"main": lambda: fit.scanStrength}, 3, 0, 0, ""),
|
||||
("labelCtrlRange", {"main": lambda: fit.extraAttributes["droneControlRange"] / 1000}, 3, 0, 0, "km"),
|
||||
("labelFullSpeed", {"main": lambda: fit.maxSpeed}, 3, 0, 0, "m/s"),
|
||||
("labelFullAlignTime", {"main": lambda: fit.alignTime}, 3, 0, 0, "s"),
|
||||
("labelFullSigRadius", {"main": lambda: fit.ship.getModifiedItemAttr("signatureRadius")}, 3, 0, 9, ""),
|
||||
("labelFullWarpSpeed", {"main": lambda: fit.warpSpeed}, 3, 0, 0, "AU/s"),
|
||||
("labelFullCargo", cargoValues, 4, 0, 9, u"m\u00B3"))
|
||||
|
||||
counter = 0
|
||||
RADII = [("Pod", 25), ("Interceptor", 33), ("Frigate", 38),
|
||||
("Destroyer", 83), ("Cruiser", 130),
|
||||
("Battlecruiser", 265), ("Battleship", 420),
|
||||
("Carrier", 3000)]
|
||||
for labelName, valueDict, prec, lowest, highest, unit in stats:
|
||||
label = getattr(self, labelName)
|
||||
newValues = {}
|
||||
for valueAlias, value in valueDict.items():
|
||||
value = value() if fit is not None else 0
|
||||
value = value if value is not None else 0
|
||||
newValues[valueAlias] = value
|
||||
if self._cachedValues[counter] != newValues:
|
||||
mainValue = newValues["main"]
|
||||
otherValues = dict((k, newValues[k]) for k in filter(lambda k: k != "main", newValues))
|
||||
if labelName == "labelFullCargo":
|
||||
# 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))
|
||||
else:
|
||||
label.SetLabel("%s %s" % (formatAmount(mainValue, prec, lowest, highest), unit))
|
||||
else:
|
||||
label.SetLabel("%s %s" % (formatAmount(mainValue, prec, lowest, highest), unit))
|
||||
# Tooltip stuff
|
||||
if fit:
|
||||
if labelName == "labelScanRes":
|
||||
lockTime = "%s\n" % "Lock Times".center(30)
|
||||
for size, radius in RADII:
|
||||
left = "%.1fs" % fit.calculateLockTime(radius)
|
||||
right = "%s [%d]" % (size, radius)
|
||||
lockTime += "%5s\t%s\n" % (left, right)
|
||||
label.SetToolTip(wx.ToolTip(lockTime))
|
||||
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)))
|
||||
else:
|
||||
label.SetToolTip(wx.ToolTip("Type: %s" % fit.scanType))
|
||||
elif labelName == "labelFullAlignTime":
|
||||
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)
|
||||
label.SetToolTip(wx.ToolTip("%s\n%s\n%s" % (alignTime, mass, agility)))
|
||||
elif labelName == "labelFullCargo":
|
||||
tipLines = [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]))
|
||||
label.SetToolTip(wx.ToolTip(u"\n".join(tipLines)))
|
||||
else:
|
||||
label.SetToolTip(wx.ToolTip("%.1f" % mainValue))
|
||||
else:
|
||||
label.SetToolTip(wx.ToolTip(""))
|
||||
self._cachedValues[counter] = newValues
|
||||
elif labelName == "labelFullWarpSpeed":
|
||||
if fit:
|
||||
label.SetToolTip(wx.ToolTip("Max Warp Distance: %.1f AU" % fit.maxWarpDistance))
|
||||
else:
|
||||
label.SetToolTip(wx.ToolTip(""))
|
||||
elif labelName == "labelSensorStr":
|
||||
if fit:
|
||||
if fit.jamChance > 0:
|
||||
label.SetToolTip(wx.ToolTip("Type: %s\n%.1f%% Chance of Jam" % (fit.scanType, fit.jamChance)))
|
||||
else:
|
||||
label.SetToolTip(wx.ToolTip("Type: %s" % fit.scanType))
|
||||
else:
|
||||
label.SetToolTip(wx.ToolTip(""))
|
||||
elif labelName == "labelFullCargo":
|
||||
if fit:
|
||||
cachedCargo = self._cachedValues[counter]
|
||||
# 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 = [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]))
|
||||
label.SetToolTip(wx.ToolTip(u"\n".join(tipLines)))
|
||||
else:
|
||||
label.SetToolTip(wx.ToolTip(""))
|
||||
|
||||
# forces update of probe size, since this stat is used by both sig radius and sensor str
|
||||
if labelName == "labelFullSigRadius":
|
||||
print "labelName"
|
||||
if fit:
|
||||
label.SetToolTip(wx.ToolTip("Probe Size: %.3f" % (fit.probeSize or 0)))
|
||||
else:
|
||||
label.SetToolTip(wx.ToolTip(""))
|
||||
|
||||
counter += 1
|
||||
self.panel.Layout()
|
||||
self.headerPanel.Layout()
|
||||
|
||||
|
||||
TargetingMiscViewMinimal.register()
|
||||
@@ -33,7 +33,7 @@ from gui.builtinViewColumns.state import State
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
import gui.builtinViews.emptyView
|
||||
from gui.utils.exportHtml import exportHtml
|
||||
from logging import getLogger
|
||||
from logbook import Logger
|
||||
from gui.chromeTabs import EVT_NOTEBOOK_PAGE_CHANGED
|
||||
|
||||
from service.fit import Fit
|
||||
@@ -41,7 +41,7 @@ from service.market import Market
|
||||
|
||||
import gui.globalEvents as GE
|
||||
|
||||
logger = getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
# Tab spawning handler
|
||||
@@ -55,14 +55,16 @@ class FitSpawner(gui.multiSwitch.TabSpawner):
|
||||
def fitSelected(self, event):
|
||||
count = -1
|
||||
for index, page in enumerate(self.multiSwitch.pages):
|
||||
try:
|
||||
if page.activeFitID == event.fitID:
|
||||
count += 1
|
||||
self.multiSwitch.SetSelection(index)
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=event.fitID))
|
||||
break
|
||||
except:
|
||||
pass
|
||||
if not isinstance(page, gui.builtinViews.emptyView.BlankPage): # Don't try and process it if it's a blank page.
|
||||
try:
|
||||
if page.activeFitID == event.fitID:
|
||||
count += 1
|
||||
self.multiSwitch.SetSelection(index)
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=event.fitID))
|
||||
break
|
||||
except Exception as e:
|
||||
pyfalog.critical("Caught exception in fitSelected")
|
||||
pyfalog.critical(e)
|
||||
if count < 0:
|
||||
startup = getattr(event, "startup", False) # see OpenFitsThread in gui.mainFrame
|
||||
sFit = Fit.getInstance()
|
||||
@@ -278,6 +280,7 @@ class FittingView(d.Display):
|
||||
sFit.refreshFit(self.getActiveFit())
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.activeFitID))
|
||||
except wx._core.PyDeadObjectError:
|
||||
pyfalog.warning("Caught dead object")
|
||||
pass
|
||||
|
||||
event.Skip()
|
||||
@@ -406,7 +409,7 @@ class FittingView(d.Display):
|
||||
if mod1.slot != mod2.slot:
|
||||
return
|
||||
|
||||
if getattr(mod2, "modPosition"):
|
||||
if getattr(mod2, "modPosition") is not None:
|
||||
if clone and mod2.isEmpty:
|
||||
sFit.cloneModule(self.mainFrame.getActiveFit(), srcIdx, mod2.modPosition)
|
||||
else:
|
||||
@@ -414,7 +417,7 @@ class FittingView(d.Display):
|
||||
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit()))
|
||||
else:
|
||||
logger.error("Missing module position for: %s", str(getattr(mod2, "ID", "Unknown")))
|
||||
pyfalog.error("Missing module position for: {0}", str(getattr(mod2, "ID", "Unknown")))
|
||||
|
||||
def generateMods(self):
|
||||
"""
|
||||
@@ -483,7 +486,7 @@ class FittingView(d.Display):
|
||||
|
||||
self.Show(self.activeFitID is not None and self.activeFitID == event.fitID)
|
||||
except wx._core.PyDeadObjectError:
|
||||
pass
|
||||
pyfalog.warning("Caught dead object")
|
||||
finally:
|
||||
event.Skip()
|
||||
|
||||
@@ -636,15 +639,17 @@ class FittingView(d.Display):
|
||||
if 'wxMac' in wx.PlatformInfo:
|
||||
try:
|
||||
self.MakeSnapshot()
|
||||
except:
|
||||
pass
|
||||
except Exception as e:
|
||||
pyfalog.critical("Failed to make snapshot")
|
||||
pyfalog.critical(e)
|
||||
|
||||
def OnShow(self, event):
|
||||
if event.GetShow():
|
||||
try:
|
||||
self.MakeSnapshot()
|
||||
except:
|
||||
pass
|
||||
except Exception as e:
|
||||
pyfalog.critical("Failed to make snapshot")
|
||||
pyfalog.critical(e)
|
||||
event.Skip()
|
||||
|
||||
def Snapshot(self):
|
||||
@@ -669,8 +674,9 @@ class FittingView(d.Display):
|
||||
sFit = Fit.getInstance()
|
||||
try:
|
||||
fit = sFit.getFit(self.activeFitID)
|
||||
except:
|
||||
return
|
||||
except Exception as e:
|
||||
pyfalog.critical("Failed to get fit")
|
||||
pyfalog.critical(e)
|
||||
|
||||
if fit is None:
|
||||
return
|
||||
|
||||
@@ -33,6 +33,8 @@ from service.fit import Fit
|
||||
from service.character import Character
|
||||
from service.network import AuthenticationError, TimeoutError
|
||||
from service.market import Market
|
||||
from logbook import Logger
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class CharacterTextValidor(BaseValidator):
|
||||
@@ -55,6 +57,7 @@ class CharacterTextValidor(BaseValidator):
|
||||
|
||||
return True
|
||||
except ValueError, e:
|
||||
pyfalog.error(e)
|
||||
wx.MessageBox(u"{}".format(e), "Error")
|
||||
textCtrl.SetFocus()
|
||||
return False
|
||||
@@ -628,11 +631,16 @@ class APIView(wx.Panel):
|
||||
try:
|
||||
activeChar = self.charEditor.entityEditor.getActiveEntity()
|
||||
list = sChar.apiCharList(activeChar.ID, self.inputID.GetLineText(0), self.inputKey.GetLineText(0))
|
||||
except AuthenticationError:
|
||||
self.stStatus.SetLabel("Authentication failure. Please check keyID and vCode combination.")
|
||||
except TimeoutError:
|
||||
self.stStatus.SetLabel("Request timed out. Please check network connectivity and/or proxy settings.")
|
||||
except AuthenticationError, e:
|
||||
msg = "Authentication failure. Please check keyID and vCode combination."
|
||||
pyfalog.info(msg)
|
||||
self.stStatus.SetLabel(msg)
|
||||
except TimeoutError, e:
|
||||
msg = "Request timed out. Please check network connectivity and/or proxy settings."
|
||||
pyfalog.info(msg)
|
||||
self.stStatus.SetLabel(msg)
|
||||
except Exception, e:
|
||||
pyfalog.error(e)
|
||||
self.stStatus.SetLabel("Error:\n%s" % e.message)
|
||||
else:
|
||||
self.charChoice.Clear()
|
||||
@@ -655,6 +663,7 @@ class APIView(wx.Panel):
|
||||
sChar.apiFetch(activeChar.ID, charName)
|
||||
self.stStatus.SetLabel("Successfully fetched %s\'s skills from EVE API." % charName)
|
||||
except Exception, e:
|
||||
pyfalog.error("Unable to retrieve {0}\'s skills. Error message:\n{1}", charName, e)
|
||||
self.stStatus.SetLabel("Unable to retrieve %s\'s skills. Error message:\n%s" % (charName, e))
|
||||
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ import gui.globalEvents as GE
|
||||
import gui.mainFrame
|
||||
from service.character import Character
|
||||
from service.fit import Fit
|
||||
from logbook import Logger
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class CharacterSelection(wx.Panel):
|
||||
@@ -112,9 +114,10 @@ class CharacterSelection(wx.Panel):
|
||||
if charName:
|
||||
try:
|
||||
sChar.apiFetch(self.getActiveCharacter(), charName)
|
||||
except:
|
||||
except Exception as e:
|
||||
# can we do a popup, notifying user of API error?
|
||||
pass
|
||||
pyfalog.error("API fetch error")
|
||||
pyfalog.error(e)
|
||||
self.refreshCharacterList()
|
||||
|
||||
def charChanged(self, event):
|
||||
|
||||
@@ -25,9 +25,11 @@ import gui.utils.colorUtils as colorUtils
|
||||
import gui.utils.drawUtils as drawUtils
|
||||
import gui.utils.fonts as fonts
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
|
||||
from logbook import Logger
|
||||
from service.fit import Fit
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
_PageChanging, EVT_NOTEBOOK_PAGE_CHANGING = wx.lib.newevent.NewEvent()
|
||||
_PageChanged, EVT_NOTEBOOK_PAGE_CHANGED = wx.lib.newevent.NewEvent()
|
||||
_PageAdding, EVT_NOTEBOOK_PAGE_ADDING = wx.lib.newevent.NewEvent()
|
||||
@@ -1093,8 +1095,9 @@ class PFTabsContainer(wx.Panel):
|
||||
self.previewTab = tab
|
||||
self.previewTimer.Start(500, True)
|
||||
break
|
||||
except:
|
||||
pass
|
||||
except Exception as e:
|
||||
pyfalog.critical("Exception caught in CheckTabPreview.")
|
||||
pyfalog.critical(e)
|
||||
|
||||
def CheckAddHighlighted(self, x, y):
|
||||
"""
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
import logging
|
||||
from logbook import Logger
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class ContextMenu(object):
|
||||
@@ -121,7 +121,7 @@ class ContextMenu(object):
|
||||
|
||||
debug_end = len(cls._ids)
|
||||
if debug_end - debug_start:
|
||||
logger.debug("%d new IDs created for this menu" % (debug_end - debug_start))
|
||||
pyfalog.debug("{0} new IDs created for this menu", (debug_end - debug_start))
|
||||
|
||||
return rootMenu if empty is False else None
|
||||
|
||||
|
||||
@@ -14,6 +14,9 @@ from eos.db import getItem
|
||||
from gui.display import Display
|
||||
import gui.globalEvents as GE
|
||||
|
||||
from logbook import Logger
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3, 0)):
|
||||
from service.crest import Crest, CrestModes
|
||||
|
||||
@@ -147,7 +150,9 @@ class CrestFittings(wx.Frame):
|
||||
self.fitTree.populateSkillTree(fittings)
|
||||
del waitDialog
|
||||
except requests.exceptions.ConnectionError:
|
||||
self.statusbar.SetStatusText("Connection error, please check your internet connection")
|
||||
msg = "Connection error, please check your internet connection"
|
||||
pyfalog.error(msg)
|
||||
self.statusbar.SetStatusText(msg)
|
||||
|
||||
def importFitting(self, event):
|
||||
selection = self.fitView.fitSelection
|
||||
@@ -173,7 +178,9 @@ class CrestFittings(wx.Frame):
|
||||
try:
|
||||
sCrest.delFitting(self.getActiveCharacter(), data['fittingID'])
|
||||
except requests.exceptions.ConnectionError:
|
||||
self.statusbar.SetStatusText("Connection error, please check your internet connection")
|
||||
msg = "Connection error, please check your internet connection"
|
||||
pyfalog.error(msg)
|
||||
self.statusbar.SetStatusText(msg)
|
||||
|
||||
|
||||
class ExportToEve(wx.Frame):
|
||||
@@ -281,9 +288,12 @@ class ExportToEve(wx.Frame):
|
||||
text = json.loads(res.text)
|
||||
self.statusbar.SetStatusText(text['message'], 1)
|
||||
except ValueError:
|
||||
pyfalog.warning("Value error on loading JSON.")
|
||||
self.statusbar.SetStatusText("", 1)
|
||||
except requests.exceptions.ConnectionError:
|
||||
self.statusbar.SetStatusText("Connection error, please check your internet connection", 1)
|
||||
msg = "Connection error, please check your internet connection"
|
||||
pyfalog.error(msg)
|
||||
self.statusbar.SetStatusText(msg)
|
||||
|
||||
|
||||
class CrestMgmt(wx.Dialog):
|
||||
@@ -405,8 +415,9 @@ class FittingsTreeView(wx.Panel):
|
||||
cargo = Cargo(getItem(item['type']['id']))
|
||||
cargo.amount = item['quantity']
|
||||
list.append(cargo)
|
||||
except:
|
||||
pass
|
||||
except Exception as e:
|
||||
pyfalog.critical("Exception caught in displayFit")
|
||||
pyfalog.critical(e)
|
||||
|
||||
self.parent.fitView.fitSelection = selection
|
||||
self.parent.fitView.update(list)
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
# =============================================================================
|
||||
|
||||
import os
|
||||
import logging
|
||||
from logbook import Logger
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
@@ -30,6 +30,8 @@ import gui.globalEvents as GE
|
||||
from gui.graph import Graph
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
try:
|
||||
import matplotlib as mpl
|
||||
|
||||
@@ -51,8 +53,7 @@ except ImportError:
|
||||
graphFrame_enabled = False
|
||||
mplImported = False
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class GraphFrame(wx.Frame):
|
||||
@@ -61,11 +62,29 @@ class GraphFrame(wx.Frame):
|
||||
global graphFrame_enabled
|
||||
global mplImported
|
||||
|
||||
self.mpl_version = int(mpl.__version__[0])
|
||||
self.Patch = None
|
||||
self.mpl_version = -1
|
||||
|
||||
try:
|
||||
import matplotlib as mpl
|
||||
self.mpl_version = int(mpl.__version__[0])
|
||||
if self.mpl_version >= 2:
|
||||
mpl.use('wxagg')
|
||||
mplImported = True
|
||||
else:
|
||||
mplImported = False
|
||||
from matplotlib.patches import Patch
|
||||
self.Patch = Patch
|
||||
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas
|
||||
from matplotlib.figure import Figure
|
||||
graphFrame_enabled = True
|
||||
except ImportError:
|
||||
Patch = mpl = Canvas = Figure = None
|
||||
graphFrame_enabled = False
|
||||
|
||||
self.legendFix = False
|
||||
if not graphFrame_enabled:
|
||||
logger.info("Problems importing matplotlib; continuing without graphs")
|
||||
pyfalog.info("Problems importing matplotlib; continuing without graphs")
|
||||
return
|
||||
|
||||
try:
|
||||
@@ -236,6 +255,7 @@ class GraphFrame(wx.Frame):
|
||||
self.subplot.plot(x, y)
|
||||
legend.append(fit.name)
|
||||
except:
|
||||
pyfalog.warning("Invalid values in '{0}'", fit.name)
|
||||
self.SetStatusText("Invalid values in '%s'" % fit.name)
|
||||
self.canvas.draw()
|
||||
return
|
||||
|
||||
191
gui/itemStats.py
191
gui/itemStats.py
@@ -62,13 +62,13 @@ class ItemStatsDialog(wx.Dialog):
|
||||
):
|
||||
|
||||
wx.Dialog.__init__(
|
||||
self,
|
||||
gui.mainFrame.MainFrame.getInstance(),
|
||||
wx.ID_ANY,
|
||||
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
|
||||
self,
|
||||
gui.mainFrame.MainFrame.getInstance(),
|
||||
wx.ID_ANY,
|
||||
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
|
||||
)
|
||||
|
||||
empty = getattr(victim, "isEmpty", False)
|
||||
@@ -197,6 +197,10 @@ class ItemStatsContainer(wx.Panel):
|
||||
self.affectedby = ItemAffectedBy(self.nbContainer, stuff, item)
|
||||
self.nbContainer.AddPage(self.affectedby, "Affected by")
|
||||
|
||||
if config.debug:
|
||||
self.properties = ItemProperties(self.nbContainer, stuff, item, context)
|
||||
self.nbContainer.AddPage(self.properties, "Properties")
|
||||
|
||||
self.nbContainer.Bind(wx.EVT_LEFT_DOWN, self.mouseHit)
|
||||
self.SetSizer(mainSizer)
|
||||
self.Layout()
|
||||
@@ -256,7 +260,7 @@ class ItemDescription(wx.Panel):
|
||||
# Strip URLs
|
||||
desc = re.sub("<( *)a(.*?)>(?P<inside>.*?)<( *)/( *)a( *)>", "\g<inside>", desc)
|
||||
desc = "<body bgcolor='" + bgcolor.GetAsString(wx.C2S_HTML_SYNTAX) + "' text='" + fgcolor.GetAsString(
|
||||
wx.C2S_HTML_SYNTAX) + "' >" + desc + "</body>"
|
||||
wx.C2S_HTML_SYNTAX) + "' >" + desc + "</body>"
|
||||
|
||||
self.description.SetPage(desc)
|
||||
|
||||
@@ -358,13 +362,13 @@ class ItemParams(wx.Panel):
|
||||
writer = csv.writer(exportFile, delimiter=',')
|
||||
|
||||
writer.writerow(
|
||||
[
|
||||
"ID",
|
||||
"Internal Name",
|
||||
"Friendly Name",
|
||||
"Modified Value",
|
||||
"Base Value",
|
||||
]
|
||||
[
|
||||
"ID",
|
||||
"Internal Name",
|
||||
"Friendly Name",
|
||||
"Modified Value",
|
||||
"Base Value",
|
||||
]
|
||||
)
|
||||
|
||||
for attribute in self.attrValues:
|
||||
@@ -395,13 +399,13 @@ class ItemParams(wx.Panel):
|
||||
attribute_modified_value = self.attrValues[attribute]
|
||||
|
||||
writer.writerow(
|
||||
[
|
||||
attribute_id,
|
||||
attribute_name,
|
||||
attribute_displayname,
|
||||
attribute_modified_value,
|
||||
attribute_value,
|
||||
]
|
||||
[
|
||||
attribute_id,
|
||||
attribute_name,
|
||||
attribute_displayname,
|
||||
attribute_modified_value,
|
||||
attribute_value,
|
||||
]
|
||||
)
|
||||
|
||||
def PopulateList(self):
|
||||
@@ -496,17 +500,19 @@ class ItemParams(wx.Panel):
|
||||
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),
|
||||
"Volume": (lambda: value, u"m\u00B3"),
|
||||
"Sizeclass": (lambda: value, ""),
|
||||
"Absolute Percent": (lambda: (value * 100), unitName),
|
||||
"Milliseconds": (lambda: value / 1000.0, unitName),
|
||||
"typeID": (itemIDCallback, ""),
|
||||
"groupID": (groupIDCallback, ""),
|
||||
"attributeID": (attributeIDCallback, "")}
|
||||
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),
|
||||
"Milliseconds" : (lambda: value / 1000.0, unitName),
|
||||
"typeID" : (itemIDCallback, ""),
|
||||
"groupID" : (groupIDCallback, ""),
|
||||
"attributeID" : (attributeIDCallback, "")
|
||||
}
|
||||
|
||||
override = trans.get(unitDisplayName)
|
||||
if override is not None:
|
||||
@@ -689,17 +695,18 @@ class ItemCompare(wx.Panel):
|
||||
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),
|
||||
"Volume": (lambda: value, u"m\u00B3"),
|
||||
"Sizeclass": (lambda: value, ""),
|
||||
"Absolute Percent": (lambda: (value * 100), unitName),
|
||||
"Milliseconds": (lambda: value / 1000.0, unitName),
|
||||
"typeID": (itemIDCallback, ""),
|
||||
"groupID": (groupIDCallback, ""),
|
||||
"attributeID": (attributeIDCallback, "")}
|
||||
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),
|
||||
"Milliseconds" : (lambda: value / 1000.0, unitName),
|
||||
"typeID" : (itemIDCallback, ""),
|
||||
"groupID" : (groupIDCallback, ""),
|
||||
"attributeID" : (attributeIDCallback, "")
|
||||
}
|
||||
|
||||
override = trans.get(unitDisplayName)
|
||||
if override is not None:
|
||||
@@ -1067,7 +1074,7 @@ class ItemAffectedBy(wx.Panel):
|
||||
item = afflictor.item
|
||||
|
||||
items[attrName].append(
|
||||
(type(afflictor), afflictor, item, modifier, amount, getattr(afflictor, "projected", False)))
|
||||
(type(afflictor), afflictor, item, modifier, amount, getattr(afflictor, "projected", False)))
|
||||
|
||||
# Make sure projected fits are on top
|
||||
rootOrder = container.keys()
|
||||
@@ -1295,3 +1302,97 @@ class ItemAffectedBy(wx.Panel):
|
||||
treeitem = self.affectedBy.AppendItem(child, display, attrIcon)
|
||||
self.affectedBy.SetPyData(treeitem, saved)
|
||||
self.treeItems.append(treeitem)
|
||||
|
||||
|
||||
class ItemProperties(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_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
|
||||
self.item = item
|
||||
self.attrInfo = {}
|
||||
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.totalAttrsLabel = wx.StaticText(self, wx.ID_ANY, u" ", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
bSizer.Add(self.totalAttrsLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT)
|
||||
|
||||
mainSizer.Add(bSizer, 0, wx.ALIGN_RIGHT)
|
||||
|
||||
self.PopulateList()
|
||||
|
||||
def _fetchValues(self):
|
||||
if self.stuff is None:
|
||||
self.attrInfo.clear()
|
||||
self.attrValues.clear()
|
||||
self.attrInfo.update(self.item.attributes)
|
||||
self.attrValues.update(self.item.attributes)
|
||||
elif self.stuff.item == self.item:
|
||||
self.attrInfo.clear()
|
||||
self.attrValues.clear()
|
||||
self.attrInfo.update(self.stuff.item.attributes)
|
||||
self.attrValues.update(self.stuff.itemModifiedAttributes)
|
||||
elif self.stuff.charge == self.item:
|
||||
self.attrInfo.clear()
|
||||
self.attrValues.clear()
|
||||
self.attrInfo.update(self.stuff.charge.attributes)
|
||||
self.attrValues.update(self.stuff.chargeModifiedAttributes)
|
||||
# When item for stats window no longer exists, don't change anything
|
||||
else:
|
||||
return
|
||||
|
||||
def PopulateList(self):
|
||||
self.paramList.InsertColumn(0, "Attribute")
|
||||
self.paramList.InsertColumn(1, "Current Value")
|
||||
self.paramList.SetColumnWidth(0, 110)
|
||||
self.paramList.SetColumnWidth(1, 1500)
|
||||
self.paramList.setResizeColumn(0)
|
||||
|
||||
if self.stuff:
|
||||
names = dir(self.stuff)
|
||||
else:
|
||||
names = dir(self.item)
|
||||
|
||||
names = [a for a in names if not (a.startswith('__') and a.endswith('__'))]
|
||||
|
||||
idNameMap = {}
|
||||
idCount = 0
|
||||
for name in names:
|
||||
try:
|
||||
if self.stuff:
|
||||
attrName = name.title()
|
||||
value = getattr(self.stuff, name)
|
||||
else:
|
||||
attrName = name.title()
|
||||
value = getattr(self.item, name)
|
||||
except Exception as e:
|
||||
# TODO: Add logging to this.
|
||||
# We couldn't get a property for some reason. Skip it for now.
|
||||
print(e)
|
||||
continue
|
||||
|
||||
index = self.paramList.InsertStringItem(sys.maxint, attrName)
|
||||
# index = self.paramList.InsertImageStringItem(sys.maxint, attrName)
|
||||
idNameMap[idCount] = attrName
|
||||
self.paramList.SetItemData(index, idCount)
|
||||
idCount += 1
|
||||
|
||||
valueUnit = str(value)
|
||||
|
||||
self.paramList.SetStringItem(index, 1, valueUnit)
|
||||
|
||||
self.paramList.SortItems(lambda id1, id2: cmp(idNameMap[id1], idNameMap[id2]))
|
||||
self.paramList.RefreshRows()
|
||||
self.totalAttrsLabel.SetLabel("%d attributes. " % idCount)
|
||||
self.Layout()
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
import sys
|
||||
import os.path
|
||||
import logging
|
||||
from logbook import Logger
|
||||
|
||||
import sqlalchemy
|
||||
# noinspection PyPackageRequirements
|
||||
@@ -94,7 +94,7 @@ except ImportError as e:
|
||||
print("Error loading Attribute Editor: %s.\nAccess to Attribute Editor is disabled." % e.message)
|
||||
disableOverrideEditor = True
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
# dummy panel(no paint no erasebk)
|
||||
@@ -145,6 +145,7 @@ class MainFrame(wx.Frame):
|
||||
return cls.__instance if cls.__instance is not None else MainFrame()
|
||||
|
||||
def __init__(self, title="pyfa"):
|
||||
pyfalog.debug("Initialize MainFrame")
|
||||
self.title = title
|
||||
wx.Frame.__init__(self, None, wx.ID_ANY, self.title)
|
||||
|
||||
@@ -399,7 +400,7 @@ class MainFrame(wx.Frame):
|
||||
try:
|
||||
dlg.Destroy()
|
||||
except PyDeadObjectError:
|
||||
logger.error("Tried to destroy an object that doesn't exist in <showDamagePatternEditor>.")
|
||||
pyfalog.error("Tried to destroy an object that doesn't exist in <showDamagePatternEditor>.")
|
||||
|
||||
def showImplantSetEditor(self, event):
|
||||
ImplantSetEditorDlg(self)
|
||||
@@ -427,7 +428,7 @@ class MainFrame(wx.Frame):
|
||||
try:
|
||||
dlg.Destroy()
|
||||
except PyDeadObjectError:
|
||||
logger.error("Tried to destroy an object that doesn't exist in <showExportDialog>.")
|
||||
pyfalog.error("Tried to destroy an object that doesn't exist in <showExportDialog>.")
|
||||
return
|
||||
|
||||
with open(path, "w", encoding="utf-8") as openfile:
|
||||
@@ -437,7 +438,7 @@ class MainFrame(wx.Frame):
|
||||
try:
|
||||
dlg.Destroy()
|
||||
except PyDeadObjectError:
|
||||
logger.error("Tried to destroy an object that doesn't exist in <showExportDialog>.")
|
||||
pyfalog.error("Tried to destroy an object that doesn't exist in <showExportDialog>.")
|
||||
|
||||
def showPreferenceDialog(self, event):
|
||||
dlg = PreferenceDialog(self)
|
||||
@@ -734,7 +735,7 @@ class MainFrame(wx.Frame):
|
||||
try:
|
||||
fits = Port().importFitFromBuffer(clipboard, self.getActiveFit())
|
||||
except:
|
||||
logger.error("Attempt to import failed:\n%s", clipboard)
|
||||
pyfalog.error("Attempt to import failed:\n{0}", clipboard)
|
||||
else:
|
||||
self._openAfterImport(fits)
|
||||
|
||||
@@ -754,7 +755,7 @@ class MainFrame(wx.Frame):
|
||||
try:
|
||||
dlg.Destroy()
|
||||
except PyDeadObjectError:
|
||||
logger.error("Tried to destroy an object that doesn't exist in <exportToClipboard>.")
|
||||
pyfalog.error("Tried to destroy an object that doesn't exist in <exportToClipboard>.")
|
||||
|
||||
def exportSkillsNeeded(self, event):
|
||||
""" Exports skills needed for active fit and active character """
|
||||
@@ -811,7 +812,7 @@ class MainFrame(wx.Frame):
|
||||
try:
|
||||
dlg.Destroy()
|
||||
except PyDeadObjectError:
|
||||
logger.error("Tried to destroy an object that doesn't exist in <fileImportDialog>.")
|
||||
pyfalog.error("Tried to destroy an object that doesn't exist in <fileImportDialog>.")
|
||||
|
||||
def backupToXml(self, event):
|
||||
""" Back up all fits to EVE XML file """
|
||||
|
||||
@@ -26,6 +26,9 @@ import gui.graphFrame
|
||||
import gui.globalEvents as GE
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
|
||||
from logbook import Logger
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
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
|
||||
@@ -33,6 +36,7 @@ if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION
|
||||
|
||||
class MainMenuBar(wx.MenuBar):
|
||||
def __init__(self, mainFrame):
|
||||
pyfalog.debug("Initialize MainMenuBar")
|
||||
self.characterEditorId = wx.NewId()
|
||||
self.damagePatternEditorId = wx.NewId()
|
||||
self.targetResistsEditorId = wx.NewId()
|
||||
@@ -166,6 +170,7 @@ class MainMenuBar(wx.MenuBar):
|
||||
self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged)
|
||||
|
||||
def fitChanged(self, event):
|
||||
pyfalog.debug("fitChanged triggered")
|
||||
enable = event.fitID is not None
|
||||
self.Enable(wx.ID_SAVEAS, enable)
|
||||
self.Enable(wx.ID_COPY, enable)
|
||||
|
||||
@@ -26,6 +26,9 @@ import gui.PFSearchBox as SBox
|
||||
from gui.cachingImageList import CachingImageList
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
from logbook import Logger
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
ItemSelected, ITEM_SELECTED = wx.lib.newevent.NewEvent()
|
||||
|
||||
@@ -56,6 +59,7 @@ class MetaButton(wx.ToggleButton):
|
||||
class MarketBrowser(wx.Panel):
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__(self, parent)
|
||||
pyfalog.debug("Initialize marketBrowser")
|
||||
vbox = wx.BoxSizer(wx.VERTICAL)
|
||||
self.SetSizer(vbox)
|
||||
|
||||
@@ -134,6 +138,7 @@ class SearchBox(SBox.PFSearchBox):
|
||||
class MarketTree(wx.TreeCtrl):
|
||||
def __init__(self, parent, marketBrowser):
|
||||
wx.TreeCtrl.__init__(self, parent, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT)
|
||||
pyfalog.debug("Initialize marketTree")
|
||||
self.root = self.AddRoot("root")
|
||||
|
||||
self.imageList = CachingImageList(16, 16)
|
||||
@@ -182,7 +187,9 @@ class MarketTree(wx.TreeCtrl):
|
||||
iconId = self.addImage(sMkt.getIconByMarketGroup(childMktGrp))
|
||||
try:
|
||||
childId = self.AppendItem(root, childMktGrp.name, iconId, data=wx.TreeItemData(childMktGrp.ID))
|
||||
except:
|
||||
except Exception as e:
|
||||
pyfalog.debug("Error appending item.")
|
||||
pyfalog.debug(e)
|
||||
continue
|
||||
if sMkt.marketGroupHasTypesCheck(childMktGrp) is False:
|
||||
self.AppendItem(childId, "dummy")
|
||||
@@ -226,6 +233,7 @@ class ItemView(Display):
|
||||
|
||||
def __init__(self, parent, marketBrowser):
|
||||
Display.__init__(self, parent)
|
||||
pyfalog.debug("Initialize ItemView")
|
||||
marketBrowser.Bind(wx.EVT_TREE_SEL_CHANGED, self.selectionMade)
|
||||
|
||||
self.unfilteredStore = set()
|
||||
@@ -252,6 +260,7 @@ class ItemView(Display):
|
||||
self.metaMap = self.makeReverseMetaMap()
|
||||
|
||||
# Fill up recently used modules set
|
||||
pyfalog.debug("Fill up recently used modules set")
|
||||
for itemID in self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"]:
|
||||
self.recentlyUsedModules.add(self.sMkt.getItem(itemID))
|
||||
|
||||
|
||||
@@ -25,6 +25,9 @@ from wx.lib.intctrl import IntCtrl
|
||||
from gui.utils.clipboard import toClipboard, fromClipboard
|
||||
from gui.builtinViews.entityEditor import EntityEditor, BaseValidator
|
||||
from service.damagePattern import DamagePattern, ImportError
|
||||
from logbook import Logger
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class DmgPatternTextValidor(BaseValidator):
|
||||
@@ -47,6 +50,7 @@ class DmgPatternTextValidor(BaseValidator):
|
||||
|
||||
return True
|
||||
except ValueError as e:
|
||||
pyfalog.error(e)
|
||||
wx.MessageBox(u"{}".format(e), "Error")
|
||||
textCtrl.SetFocus()
|
||||
return False
|
||||
@@ -256,9 +260,13 @@ class DmgPatternEditorDlg(wx.Dialog):
|
||||
sDP.importPatterns(text)
|
||||
self.stNotice.SetLabel("Patterns successfully imported from clipboard")
|
||||
except ImportError as e:
|
||||
pyfalog.error(e)
|
||||
self.stNotice.SetLabel(str(e))
|
||||
except Exception:
|
||||
self.stNotice.SetLabel("Could not import from clipboard: unknown errors")
|
||||
except Exception as e:
|
||||
msg = "Could not import from clipboard: unknown errors"
|
||||
pyfalog.warning(msg)
|
||||
pyfalog.error(e)
|
||||
self.stNotice.SetLabel(msg)
|
||||
finally:
|
||||
self.entityEditor.refreshEntityList()
|
||||
else:
|
||||
|
||||
@@ -66,12 +66,12 @@ class PreferenceDialog(wx.Dialog):
|
||||
|
||||
# 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
|
||||
minHeight = 550
|
||||
bestFit = self.GetBestVirtualSize()
|
||||
if minHeight > bestFit[1]:
|
||||
self.SetSizeWH(450, minHeight)
|
||||
self.SetSizeWH(650, minHeight)
|
||||
else:
|
||||
self.SetSizeWH(450, bestFit[1])
|
||||
self.SetSizeWH(650, bestFit[1])
|
||||
|
||||
self.Layout()
|
||||
|
||||
|
||||
@@ -44,5 +44,10 @@ from gui.builtinPreferenceViews import ( # noqa: E402, F401
|
||||
pyfaNetworkPreferences,
|
||||
pyfaHTMLExportPreferences,
|
||||
pyfaCrestPreferences,
|
||||
pyfaUpdatePreferences
|
||||
pyfaContextMenuPreferences,
|
||||
pyfaStatViewPreferences,
|
||||
pyfaUpdatePreferences,
|
||||
pyfaEnginePreferences,
|
||||
pyfaDatabasePreferences,
|
||||
pyfaLoggingPreferences
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import csv
|
||||
import logging
|
||||
from logbook import Logger
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
@@ -21,7 +21,7 @@ import gui.PFSearchBox as SBox
|
||||
from gui.marketBrowser import SearchBox
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class AttributeEditor(wx.Frame):
|
||||
@@ -270,7 +270,7 @@ class AttributeGrid(wxpg.PropertyGrid):
|
||||
|
||||
self.itemView.updateItems()
|
||||
|
||||
logger.debug('%s changed to "%s"' % (p.GetName(), p.GetValueAsString()))
|
||||
pyfalog.debug('{0} changed to "{1}"', p.GetName(), p.GetValueAsString())
|
||||
|
||||
def OnPropGridSelect(self, event):
|
||||
pass
|
||||
|
||||
@@ -23,6 +23,9 @@ from service.targetResists import TargetResists
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
from gui.utils.clipboard import toClipboard, fromClipboard
|
||||
from gui.builtinViews.entityEditor import EntityEditor, BaseValidator
|
||||
from logbook import Logger
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class TargetResistsTextValidor(BaseValidator):
|
||||
@@ -45,6 +48,7 @@ class TargetResistsTextValidor(BaseValidator):
|
||||
|
||||
return True
|
||||
except ValueError as e:
|
||||
pyfalog.error(e)
|
||||
wx.MessageBox(u"{}".format(e), "Error")
|
||||
textCtrl.SetFocus()
|
||||
return False
|
||||
@@ -230,10 +234,14 @@ class ResistsEditorDlg(wx.Dialog):
|
||||
|
||||
except ValueError:
|
||||
editObj.SetForegroundColour(wx.RED)
|
||||
self.stNotice.SetLabel("Incorrect Formatting (decimals only)")
|
||||
msg = "Incorrect Formatting (decimals only)"
|
||||
pyfalog.warning(msg)
|
||||
self.stNotice.SetLabel(msg)
|
||||
except AssertionError:
|
||||
editObj.SetForegroundColour(wx.RED)
|
||||
self.stNotice.SetLabel("Incorrect Range (must be 0-100)")
|
||||
msg = "Incorrect Range (must be 0-100)"
|
||||
pyfalog.warning(msg)
|
||||
self.stNotice.SetLabel(msg)
|
||||
finally: # Refresh for color changes to take effect immediately
|
||||
self.Refresh()
|
||||
|
||||
@@ -271,9 +279,13 @@ class ResistsEditorDlg(wx.Dialog):
|
||||
sTR.importPatterns(text)
|
||||
self.stNotice.SetLabel("Patterns successfully imported from clipboard")
|
||||
except ImportError as e:
|
||||
pyfalog.error(e)
|
||||
self.stNotice.SetLabel(str(e))
|
||||
except Exception:
|
||||
self.stNotice.SetLabel("Could not import from clipboard: unknown errors")
|
||||
except Exception as e:
|
||||
msg = "Could not import from clipboard:"
|
||||
pyfalog.warning(msg)
|
||||
pyfalog.error(e)
|
||||
self.stNotice.SetLabel(msg)
|
||||
finally:
|
||||
self.entityEditor.refreshEntityList()
|
||||
else:
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
|
||||
# =============================================================================
|
||||
|
||||
import logging
|
||||
from logbook import Logger
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
|
||||
@@ -26,7 +26,7 @@ from gui.builtinViews.implantEditor import BaseImplantEditorView
|
||||
from gui.utils.clipboard import toClipboard, fromClipboard
|
||||
from gui.builtinViews.entityEditor import EntityEditor, BaseValidator
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class ImplantTextValidor(BaseValidator):
|
||||
@@ -49,6 +49,7 @@ class ImplantTextValidor(BaseValidator):
|
||||
|
||||
return True
|
||||
except ValueError as e:
|
||||
pyfalog.error(e)
|
||||
wx.MessageBox(u"{}".format(e), "Error")
|
||||
textCtrl.SetFocus()
|
||||
return False
|
||||
@@ -198,9 +199,10 @@ class ImplantSetEditorDlg(wx.Dialog):
|
||||
self.stNotice.SetLabel("Patterns successfully imported from clipboard")
|
||||
self.showInput(False)
|
||||
except ImportError as e:
|
||||
pyfalog.error(e)
|
||||
self.stNotice.SetLabel(str(e))
|
||||
except Exception as e:
|
||||
logging.exception("Unhandled Exception")
|
||||
pyfalog.error(e)
|
||||
self.stNotice.SetLabel("Could not import from clipboard: unknown errors")
|
||||
finally:
|
||||
self.updateChoices()
|
||||
|
||||
@@ -21,6 +21,8 @@ import gui.utils.animEffects as animEffects
|
||||
from gui.PFListPane import PFListPane
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
from logbook import Logger
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
FitRenamed, EVT_FIT_RENAMED = wx.lib.newevent.NewEvent()
|
||||
FitSelected, EVT_FIT_SELECTED = wx.lib.newevent.NewEvent()
|
||||
@@ -684,6 +686,7 @@ class ShipBrowser(wx.Panel):
|
||||
self.lpane.Freeze()
|
||||
self.lpane.RemoveAllChildren()
|
||||
|
||||
pyfalog.debug("Populate ship category list.")
|
||||
if len(self.categoryList) == 0:
|
||||
# set cache of category list
|
||||
self.categoryList = list(sMkt.getShipRoot())
|
||||
@@ -1552,6 +1555,10 @@ class FitItem(SFItem.SFBrowserItem):
|
||||
self.selTimer.Start(100)
|
||||
|
||||
self.Bind(wx.EVT_RIGHT_UP, self.OnContextMenu)
|
||||
self.Bind(wx.EVT_MIDDLE_UP, self.OpenNewTab)
|
||||
|
||||
def OpenNewTab(self, evt):
|
||||
self.selectFit(newTab=True)
|
||||
|
||||
def OnToggleBooster(self, event):
|
||||
sFit = Fit.getInstance()
|
||||
@@ -1616,6 +1623,9 @@ class FitItem(SFItem.SFBrowserItem):
|
||||
# menu.AppendSubMenu(boosterMenu, 'Set Booster')
|
||||
|
||||
if fit:
|
||||
newTabItem = menu.Append(wx.ID_ANY, "Open in new tab")
|
||||
self.Bind(wx.EVT_MENU, self.OpenNewTab, newTabItem)
|
||||
|
||||
projectedItem = menu.Append(wx.ID_ANY, "Project onto Active Fit")
|
||||
self.Bind(wx.EVT_MENU, self.OnProjectToFit, projectedItem)
|
||||
|
||||
@@ -1809,8 +1819,11 @@ class FitItem(SFItem.SFBrowserItem):
|
||||
self.dragWindow.SetPosition(pos)
|
||||
return
|
||||
|
||||
def selectFit(self, event=None):
|
||||
wx.PostEvent(self.mainFrame, FitSelected(fitID=self.fitID))
|
||||
def selectFit(self, event=None, newTab=False):
|
||||
if newTab:
|
||||
wx.PostEvent(self.mainFrame, FitSelected(fitID=self.fitID, startup=2))
|
||||
else:
|
||||
wx.PostEvent(self.mainFrame, FitSelected(fitID=self.fitID))
|
||||
|
||||
def RestoreEditButton(self):
|
||||
self.tcFitName.Show(False)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
import wx
|
||||
|
||||
from service.fit import Fit
|
||||
from service.settings import StatViewSettings
|
||||
import gui.mainFrame
|
||||
import gui.builtinStatsViews
|
||||
import gui.globalEvents as GE
|
||||
@@ -28,12 +29,44 @@ import gui.globalEvents as GE
|
||||
from gui.statsView import StatsView
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.pyfatogglepanel import TogglePanel
|
||||
from logbook import Logger
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class StatsPane(wx.Panel):
|
||||
DEFAULT_VIEWS = ["resourcesViewFull", "resistancesViewFull", "rechargeViewFull", "firepowerViewFull",
|
||||
"capacitorViewFull", "targetingmiscViewFull",
|
||||
"priceViewFull"]
|
||||
AVAILIBLE_VIEWS = [
|
||||
"resources",
|
||||
"resistances",
|
||||
"recharge",
|
||||
"firepower",
|
||||
"outgoing",
|
||||
"capacitor",
|
||||
"targetingMisc",
|
||||
"price",
|
||||
]
|
||||
|
||||
# Don't have these....yet....
|
||||
'''
|
||||
"miningyield", "drones"
|
||||
]
|
||||
'''
|
||||
|
||||
DEFAULT_VIEWS = []
|
||||
|
||||
settings = StatViewSettings.getInstance()
|
||||
|
||||
for aView in AVAILIBLE_VIEWS:
|
||||
if settings.get(aView) == 2:
|
||||
DEFAULT_VIEWS.extend(["%sViewFull" % aView])
|
||||
pyfalog.debug("Setting full view for: {0}", aView)
|
||||
elif settings.get(aView) == 1:
|
||||
DEFAULT_VIEWS.extend(["%sViewMinimal" % aView])
|
||||
pyfalog.debug("Setting minimal view for: {0}", aView)
|
||||
elif settings.get(aView) == 0:
|
||||
pyfalog.debug("Setting disabled view for: {0}", aView)
|
||||
else:
|
||||
pyfalog.error("Unknown setting for view: {0}", aView)
|
||||
|
||||
def fitChanged(self, event):
|
||||
sFit = Fit.getInstance()
|
||||
@@ -66,7 +99,12 @@ class StatsPane(wx.Panel):
|
||||
contentPanel = tp.GetContentPane()
|
||||
contentPanel.viewName = viewName
|
||||
|
||||
view = StatsView.getView(viewName)(self)
|
||||
try:
|
||||
view = StatsView.getView(viewName)(self)
|
||||
pyfalog.debug("Load view: {0}", viewName)
|
||||
except KeyError:
|
||||
pyfalog.error("Attempted to load an invalid view: {0}", viewName)
|
||||
|
||||
self.nameViewMap[viewName] = view
|
||||
self.views.append(view)
|
||||
|
||||
|
||||
@@ -50,6 +50,8 @@ from gui.builtinStatsViews import ( # noqa: E402, F401
|
||||
miningyieldViewFull,
|
||||
capacitorViewFull,
|
||||
rechargeViewFull,
|
||||
targetingMiscViewFull,
|
||||
targetingMiscViewMinimal,
|
||||
priceViewFull,
|
||||
outgoingViewFull,
|
||||
outgoingViewMinimal,
|
||||
)
|
||||
|
||||
@@ -6,8 +6,11 @@ from service.settings import HTMLExportSettings
|
||||
from service.fit import Fit
|
||||
from service.port import Port
|
||||
from service.market import Market
|
||||
from logbook import Logger
|
||||
from eos.db import getFit
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class exportHtml(object):
|
||||
_instance = None
|
||||
@@ -175,7 +178,6 @@ class exportHtmlThread(threading.Thread):
|
||||
|
||||
count = 0
|
||||
|
||||
# todo: logging for export exceptions
|
||||
for group in categoryList:
|
||||
# init market group string to give ships something to attach to
|
||||
HTMLgroup = ''
|
||||
@@ -200,7 +202,8 @@ class exportHtmlThread(threading.Thread):
|
||||
HTMLgroup += ' <li><a data-dna="' + dnaFit + '" target="_blank">' + ship.name + ": " + \
|
||||
fit[1] + '</a></li>\n'
|
||||
except:
|
||||
continue
|
||||
pyfalog.warning("Failed to export line")
|
||||
pass
|
||||
finally:
|
||||
if self.callback:
|
||||
wx.CallAfter(self.callback, count)
|
||||
@@ -223,6 +226,7 @@ class exportHtmlThread(threading.Thread):
|
||||
HTMLship += ' <li><a data-dna="' + dnaFit + '" target="_blank">' + fit[
|
||||
1] + '</a></li>\n'
|
||||
except:
|
||||
pyfalog.warning("Failed to export line")
|
||||
continue
|
||||
finally:
|
||||
if self.callback:
|
||||
@@ -275,6 +279,7 @@ class exportHtmlThread(threading.Thread):
|
||||
HTML += '<a class="outOfGameBrowserLink" target="_blank" href="' + dnaUrl + dnaFit + '">' + ship.name + ': ' + \
|
||||
fit[1] + '</a><br> \n'
|
||||
except:
|
||||
pyfalog.error("Failed to export line")
|
||||
continue
|
||||
finally:
|
||||
if self.callback:
|
||||
|
||||
BIN
imgs/gui/settings_database.png
Normal file
BIN
imgs/gui/settings_database.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
BIN
imgs/gui/settings_fitting.png
Normal file
BIN
imgs/gui/settings_fitting.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
BIN
imgs/gui/settings_log.png
Normal file
BIN
imgs/gui/settings_log.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
BIN
imgs/gui/settings_menu.png
Normal file
BIN
imgs/gui/settings_menu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
BIN
imgs/gui/settings_stats.png
Normal file
BIN
imgs/gui/settings_stats.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 894 B |
142
pyfa.py
142
pyfa.py
@@ -19,11 +19,17 @@
|
||||
# ==============================================================================
|
||||
|
||||
import sys
|
||||
import os
|
||||
import os.path
|
||||
import re
|
||||
import config
|
||||
|
||||
from optparse import OptionParser, BadOptionError, AmbiguousOptionError
|
||||
|
||||
from logbook import TimedRotatingFileHandler, Logger, StreamHandler, NestedSetup, FingersCrossedHandler, NullHandler, \
|
||||
CRITICAL, ERROR, WARNING, DEBUG, INFO
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class PassThroughOptionParser(OptionParser):
|
||||
"""
|
||||
@@ -36,9 +42,30 @@ class PassThroughOptionParser(OptionParser):
|
||||
try:
|
||||
OptionParser._process_args(self, largs, rargs, values)
|
||||
except (BadOptionError, AmbiguousOptionError) as e:
|
||||
pyfalog.error("Bad startup option passed.")
|
||||
largs.append(e.opt_str)
|
||||
|
||||
|
||||
class LoggerWriter:
|
||||
def __init__(self, level):
|
||||
# self.level is really like using log.debug(message)
|
||||
# at least in my case
|
||||
self.level = level
|
||||
|
||||
def write(self, message):
|
||||
# if statement reduces the amount of newlines that are
|
||||
# printed to the logger
|
||||
if message not in {'\n', ' '}:
|
||||
self.level(message.replace("\n", ""))
|
||||
|
||||
def flush(self):
|
||||
# create a flush method so things can be flushed when
|
||||
# the system wants to. Not sure if simply 'printing'
|
||||
# sys.stderr is the correct way to do it, but it seemed
|
||||
# to work properly for me.
|
||||
self.level(sys.stderr)
|
||||
|
||||
|
||||
# Parse command line options
|
||||
usage = "usage: %prog [--root]"
|
||||
parser = PassThroughOptionParser(usage=usage)
|
||||
@@ -47,9 +74,23 @@ parser.add_option("-w", "--wx28", action="store_true", dest="force28", help="For
|
||||
parser.add_option("-d", "--debug", action="store_true", dest="debug", help="Set logger to debug level.", default=False)
|
||||
parser.add_option("-t", "--title", action="store", dest="title", help="Set Window Title", default=None)
|
||||
parser.add_option("-s", "--savepath", action="store", dest="savepath", help="Set the folder for savedata", default=None)
|
||||
parser.add_option("-l", "--logginglevel", action="store", dest="logginglevel", help="Set desired logging level [Critical|Error|Warning|Info|Debug]", default="Error")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if options.logginglevel == "Critical":
|
||||
options.logginglevel = CRITICAL
|
||||
elif options.logginglevel == "Error":
|
||||
options.logginglevel = ERROR
|
||||
elif options.logginglevel == "Warning":
|
||||
options.logginglevel = WARNING
|
||||
elif options.logginglevel == "Info":
|
||||
options.logginglevel = INFO
|
||||
elif options.logginglevel == "Debug":
|
||||
options.logginglevel = DEBUG
|
||||
else:
|
||||
options.logginglevel = ERROR
|
||||
|
||||
if not hasattr(sys, 'frozen'):
|
||||
|
||||
if sys.version_info < (2, 6) or sys.version_info > (3, 0):
|
||||
@@ -115,7 +156,6 @@ if __name__ == "__main__":
|
||||
|
||||
config.debug = options.debug
|
||||
|
||||
import logging
|
||||
# Import everything
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
@@ -129,7 +169,75 @@ if __name__ == "__main__":
|
||||
config.defPaths(options.savepath)
|
||||
|
||||
# Basic logging initialization
|
||||
logging.basicConfig()
|
||||
|
||||
# Logging levels:
|
||||
'''
|
||||
logbook.CRITICAL
|
||||
logbook.ERROR
|
||||
logbook.WARNING
|
||||
logbook.INFO
|
||||
logbook.DEBUG
|
||||
logbook.NOTSET
|
||||
'''
|
||||
|
||||
if options.debug:
|
||||
savePath_filename = "Pyfa_debug.log"
|
||||
else:
|
||||
savePath_filename = "Pyfa.log"
|
||||
|
||||
savePath_Destination = os.path.join(config.savePath, savePath_filename)
|
||||
|
||||
try:
|
||||
if options.debug:
|
||||
logging_mode = "Debug"
|
||||
logging_setup = NestedSetup([
|
||||
# make sure we never bubble up to the stderr handler
|
||||
# if we run out of setup handling
|
||||
NullHandler(),
|
||||
StreamHandler(
|
||||
sys.stdout,
|
||||
bubble=False,
|
||||
level=options.logginglevel
|
||||
),
|
||||
TimedRotatingFileHandler(
|
||||
savePath_Destination,
|
||||
level=0,
|
||||
backup_count=3,
|
||||
bubble=True,
|
||||
date_format='%Y-%m-%d',
|
||||
),
|
||||
])
|
||||
else:
|
||||
logging_mode = "User"
|
||||
logging_setup = NestedSetup([
|
||||
# make sure we never bubble up to the stderr handler
|
||||
# if we run out of setup handling
|
||||
NullHandler(),
|
||||
FingersCrossedHandler(
|
||||
TimedRotatingFileHandler(
|
||||
savePath_Destination,
|
||||
level=0,
|
||||
backup_count=3,
|
||||
bubble=False,
|
||||
date_format='%Y-%m-%d',
|
||||
),
|
||||
action_level=ERROR,
|
||||
buffer_size=1000,
|
||||
# pull_information=True,
|
||||
# reset=False,
|
||||
)
|
||||
])
|
||||
except:
|
||||
logging_mode = "Console Only"
|
||||
logging_setup = NestedSetup([
|
||||
# make sure we never bubble up to the stderr handler
|
||||
# if we run out of setup handling
|
||||
NullHandler(),
|
||||
StreamHandler(
|
||||
sys.stdout,
|
||||
bubble=False
|
||||
)
|
||||
])
|
||||
|
||||
import eos.db
|
||||
# noinspection PyUnresolvedReferences
|
||||
@@ -152,8 +260,30 @@ if __name__ == "__main__":
|
||||
pyfa.MainLoop()
|
||||
sys.exit()
|
||||
|
||||
from gui.mainFrame import MainFrame
|
||||
with logging_setup.threadbound():
|
||||
# Don't redirect if frozen
|
||||
if not hasattr(sys, 'frozen'):
|
||||
# Output all stdout (print) messages as warnings
|
||||
try:
|
||||
sys.stdout = LoggerWriter(pyfalog.warning)
|
||||
except ValueError, Exception:
|
||||
pyfalog.critical("Cannot access log file. Continuing without writing stdout to log.")
|
||||
|
||||
pyfa = wx.App(False)
|
||||
MainFrame(options.title)
|
||||
pyfa.MainLoop()
|
||||
if not options.debug:
|
||||
# Output all stderr (stacktrace) messages as critical
|
||||
try:
|
||||
sys.stderr = LoggerWriter(pyfalog.critical)
|
||||
except ValueError, Exception:
|
||||
pyfalog.critical("Cannot access log file. Continuing without writing stderr to log.")
|
||||
|
||||
pyfalog.info("Starting Pyfa")
|
||||
pyfalog.info("Running in logging mode: {0}", logging_mode)
|
||||
|
||||
if hasattr(sys, 'frozen') and options.debug:
|
||||
pyfalog.critical("Running in frozen mode with debug turned on. Forcing all output to be written to log.")
|
||||
|
||||
from gui.mainFrame import MainFrame
|
||||
|
||||
pyfa = wx.App(False)
|
||||
MainFrame(options.title)
|
||||
pyfa.MainLoop()
|
||||
|
||||
83
pyfa.spec
Normal file
83
pyfa.spec
Normal file
@@ -0,0 +1,83 @@
|
||||
# -*- mode: python -*-
|
||||
|
||||
# Note: This script is provided AS-IS for those that may be interested.
|
||||
# pyfa does not currently support pyInstaller (or any other build process) 100% at the moment
|
||||
|
||||
# Command line to build:
|
||||
# (Run from directory where pyfa.py and pyfa.spec lives.)
|
||||
# c:\Python27\scripts\pyinstaller.exe --clean --noconfirm --windowed --upx-dir=.\scripts\upx.exe pyfa.spec
|
||||
|
||||
# Don't forget to change the path to where your pyfa.py and pyfa.spec lives
|
||||
# pathex=['C:\\Users\\Ebag333\\Documents\\GitHub\\Ebag333\\Pyfa'],
|
||||
|
||||
import os
|
||||
|
||||
block_cipher = None
|
||||
|
||||
added_files = [
|
||||
( 'imgs/gui/*.png', 'imgs/gui' ),
|
||||
( 'imgs/gui/*.gif', 'imgs/gui' ),
|
||||
( 'imgs/icons/*.png', 'imgs/icons' ),
|
||||
( 'imgs/renders/*.png', 'imgs/renders' ),
|
||||
( 'dist_assets/win/pyfa.ico', '.' ),
|
||||
( 'dist_assets/cacert.pem', '.' ),
|
||||
( 'eve.db', '.' ),
|
||||
( 'README.md', '.' ),
|
||||
( 'LICENSE', '.' ),
|
||||
]
|
||||
|
||||
import_these = []
|
||||
|
||||
# Walk eos.effects and add all effects so we can import them properly
|
||||
for root, folders, files in os.walk("eos/effects"):
|
||||
for file_ in files:
|
||||
if file_.endswith(".py") and not file_.startswith("_"):
|
||||
mod_name = "{}.{}".format(
|
||||
root.replace("/", "."),
|
||||
file_.split(".py")[0],
|
||||
)
|
||||
import_these.append(mod_name)
|
||||
|
||||
a = Analysis(
|
||||
['pyfa.py'],
|
||||
pathex=['C:\\Users\\Ebag333\\Documents\\GitHub\\Ebag333\\Pyfa'],
|
||||
binaries=[],
|
||||
datas=added_files,
|
||||
hiddenimports=import_these,
|
||||
hookspath=[],
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher,
|
||||
)
|
||||
|
||||
pyz = PYZ(
|
||||
a.pure,
|
||||
a.zipped_data,
|
||||
cipher=block_cipher,
|
||||
)
|
||||
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
exclude_binaries=True,
|
||||
debug=False,
|
||||
console=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
name='pyfa',
|
||||
icon='dist_assets/win/pyfa.ico',
|
||||
onefile=False,
|
||||
)
|
||||
|
||||
coll = COLLECT(
|
||||
exe,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
strip=False,
|
||||
upx=True,
|
||||
onefile=False,
|
||||
name='pyfa',
|
||||
icon='dist_assets/win/pyfa.ico',
|
||||
)
|
||||
@@ -1,3 +1,4 @@
|
||||
logbook
|
||||
matplotlib
|
||||
PyYAML
|
||||
python-dateutil
|
||||
|
||||
9
requirements_build_OSx.txt
Normal file
9
requirements_build_OSx.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
PyInstaller >= 3.2.1
|
||||
cycler >= 0.10.0
|
||||
functools32 >= 3.2.3
|
||||
future >= 0.16.0
|
||||
numpy >= 1.12.
|
||||
pyparsing >= 2.1.10
|
||||
pypiwin32 >= 219
|
||||
pytz >= 2016.10
|
||||
six >= 1.10.0
|
||||
8
requirements_build_linux.txt
Normal file
8
requirements_build_linux.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
PyInstaller >= 3.2.1
|
||||
cycler >= 0.10.0
|
||||
functools32 >= 3.2.3
|
||||
future >= 0.16.0
|
||||
numpy >= 1.12.
|
||||
pyparsing >= 2.1.10
|
||||
pytz >= 2016.10
|
||||
six
|
||||
10
requirements_build_windows.txt
Normal file
10
requirements_build_windows.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
PyInstaller >= 3.2.1
|
||||
cycler >= 0.10.0
|
||||
functools32 >= 3.2.3
|
||||
future >= 0.16.0
|
||||
numpy >= 1.12.
|
||||
pyparsing >= 2.1.10
|
||||
pypiwin32 >= 219
|
||||
pytz >= 2016.10
|
||||
six >= 1.10.0
|
||||
tornado
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user