diff --git a/eos/db/saveddata/__init__.py b/eos/db/saveddata/__init__.py
index d409e8ca7..7dbf2a45d 100644
--- a/eos/db/saveddata/__init__.py
+++ b/eos/db/saveddata/__init__.py
@@ -8,7 +8,6 @@ __all__ = [
"booster",
"drone",
"implant",
- "fleet",
"damagePattern",
"miscData",
"targetResists",
diff --git a/eos/db/saveddata/databaseRepair.py b/eos/db/saveddata/databaseRepair.py
new file mode 100644
index 000000000..ede0f2fde
--- /dev/null
+++ b/eos/db/saveddata/databaseRepair.py
@@ -0,0 +1,104 @@
+# ===============================================================================
+# Copyright (C) 2010 Diego Duclos
+#
+# This file is part of pyfa.
+#
+# pyfa is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# pyfa is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with pyfa. If not, see .
+# ===============================================================================
+
+import sqlalchemy
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+class DatabaseCleanup:
+ def __init__(self):
+ pass
+
+ @staticmethod
+ def OrphanedCharacterSkills(saveddata_engine):
+ # Finds and fixes database corruption issues.
+ logger.debug("Start databsae validation and cleanup.")
+
+ # Find orphaned character skills.
+ # This solves an issue where the character doesn't exist, but skills for that character do.
+ # See issue #917
+ try:
+ logger.debug("Running database cleanup for character skills.")
+ results = saveddata_engine.execute("SELECT COUNT(*) AS num FROM characterSkills "
+ "WHERE characterID NOT IN (SELECT ID from characters)")
+ row = results.first()
+
+ if row and row['num']:
+ delete = saveddata_engine.execute("DELETE FROM characterSkills WHERE characterID NOT IN (SELECT ID from characters)")
+ logger.error("Database corruption found. Cleaning up %d records.", delete.rowcount)
+
+ except sqlalchemy.exc.DatabaseError:
+ logger.error("Failed to connect to database.")
+
+ @staticmethod
+ def OrphanedFitDamagePatterns(saveddata_engine):
+ # Find orphaned damage patterns.
+ # This solves an issue where the damage pattern doesn't exist, but fits reference the pattern.
+ # See issue #777
+ try:
+ logger.debug("Running database cleanup for orphaned damage patterns attached to fits.")
+
+ results = saveddata_engine.execute("SELECT COUNT(*) AS num FROM fits WHERE damagePatternID NOT IN (SELECT ID FROM damagePatterns) OR damagePatternID IS NULL")
+ row = results.first()
+
+ if row and row['num']:
+ # Get Uniform damage pattern ID
+ query = saveddata_engine.execute("SELECT ID FROM damagePatterns WHERE name = 'Uniform'")
+ rows = query.fetchall()
+
+ if len(rows) == 0:
+ logger.error("Missing uniform damage pattern.")
+ elif len(rows) > 1:
+ logger.error("More than one uniform damage pattern found.")
+ else:
+ uniform_damage_pattern_id = rows[0]['ID']
+ update = saveddata_engine.execute("UPDATE 'fits' SET 'damagePatternID' = ? "
+ "WHERE damagePatternID NOT IN (SELECT ID FROM damagePatterns) OR damagePatternID IS NULL",
+ uniform_damage_pattern_id)
+ logger.error("Database corruption found. Cleaning up %d records.", update.rowcount)
+ except sqlalchemy.exc.DatabaseError:
+ logger.error("Failed to connect to database.")
+
+ @staticmethod
+ def OrphanedFitCharacterIDs(saveddata_engine):
+ # Find orphaned character IDs. This solves an issue where the character doesn't exist, but fits reference the pattern.
+ try:
+ logger.debug("Running database cleanup for orphaned characters attached to fits.")
+ results = saveddata_engine.execute("SELECT COUNT(*) AS num FROM fits WHERE characterID NOT IN (SELECT ID FROM characters) OR characterID IS NULL")
+ row = results.first()
+
+ if row['num']:
+ # Get All 5 character ID
+ query = saveddata_engine.execute("SELECT ID FROM characters WHERE name = 'All 5'")
+ rows = query.fetchall()
+
+ if len(rows) == 0:
+ logger.error("Missing 'All 5' character.")
+ elif len(rows) > 1:
+ logger.error("More than one 'All 5' character found.")
+ else:
+ all5_id = rows[0]['ID']
+ update = saveddata_engine.execute("UPDATE 'fits' SET 'characterID' = ? "
+ "WHERE characterID not in (select ID from characters) OR characterID IS NULL",
+ all5_id)
+ logger.error("Database corruption found. Cleaning up %d records.", update.rowcount)
+ except sqlalchemy.exc.DatabaseError:
+ logger.error("Failed to connect to database.")
diff --git a/eos/db/saveddata/fleet.py b/eos/db/saveddata/fleet.py
deleted file mode 100644
index eb644b02e..000000000
--- a/eos/db/saveddata/fleet.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# ===============================================================================
-# Copyright (C) 2010 Diego Duclos
-#
-# This file is part of eos.
-#
-# eos is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, either version 2 of the License, or
-# (at your option) any later version.
-#
-# eos is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with eos. If not, see .
-# ===============================================================================
-
-from sqlalchemy import Table, Column, Integer, ForeignKey, String
-from sqlalchemy.orm import mapper, relation
-
-from eos.db import saveddata_meta
-from eos.db.saveddata.fit import fits_table
-from eos.types import Fleet, Wing, Squad, Fit
-
-gangs_table = Table("gangs", saveddata_meta,
- Column("ID", Integer, primary_key=True),
- Column("leaderID", ForeignKey("fits.ID")),
- Column("boosterID", ForeignKey("fits.ID")),
- Column("name", String))
-
-wings_table = Table("wings", saveddata_meta,
- Column("ID", Integer, primary_key=True),
- Column("gangID", ForeignKey("gangs.ID")),
- Column("boosterID", ForeignKey("fits.ID")),
- Column("leaderID", ForeignKey("fits.ID")))
-
-squads_table = Table("squads", saveddata_meta,
- Column("ID", Integer, primary_key=True),
- Column("wingID", ForeignKey("wings.ID")),
- Column("leaderID", ForeignKey("fits.ID")),
- Column("boosterID", ForeignKey("fits.ID")))
-
-squadmembers_table = Table("squadmembers", saveddata_meta,
- Column("squadID", ForeignKey("squads.ID"), primary_key=True),
- Column("memberID", ForeignKey("fits.ID"), primary_key=True))
-
-mapper(Fleet, gangs_table,
- properties={"wings": relation(Wing, backref="gang"),
- "leader": relation(Fit, primaryjoin=gangs_table.c.leaderID == fits_table.c.ID),
- "booster": relation(Fit, primaryjoin=gangs_table.c.boosterID == fits_table.c.ID)})
-
-mapper(Wing, wings_table,
- properties={"squads": relation(Squad, backref="wing"),
- "leader": relation(Fit, primaryjoin=wings_table.c.leaderID == fits_table.c.ID),
- "booster": relation(Fit, primaryjoin=wings_table.c.boosterID == fits_table.c.ID)})
-
-mapper(Squad, squads_table,
- properties={"leader": relation(Fit, primaryjoin=squads_table.c.leaderID == fits_table.c.ID),
- "booster": relation(Fit, primaryjoin=squads_table.c.boosterID == fits_table.c.ID),
- "members": relation(Fit,
- primaryjoin=squads_table.c.ID == squadmembers_table.c.squadID,
- secondaryjoin=squadmembers_table.c.memberID == fits_table.c.ID,
- secondary=squadmembers_table)})
diff --git a/eos/db/saveddata/queries.py b/eos/db/saveddata/queries.py
index f615aa913..8c0d1c2b6 100644
--- a/eos/db/saveddata/queries.py
+++ b/eos/db/saveddata/queries.py
@@ -17,14 +17,12 @@
# along with eos. If not, see .
# ===============================================================================
-from sqlalchemy.sql import and_
-
-from eos.db import saveddata_session, sd_lock
-from eos.db.saveddata.fit import projectedFits_table
-from eos.db.saveddata.fleet import squadmembers_table
from eos.db.util import processEager, processWhere
-from eos.types import *
+from eos.db import saveddata_session, sd_lock
+from eos.types import *
+from eos.db.saveddata.fit import projectedFits_table
+from sqlalchemy.sql import and_
import eos.config
configVal = getattr(eos.config, "saveddataCache", None)
@@ -212,52 +210,6 @@ def getFit(lookfor, eager=None):
return fit
-
-@cachedQuery(Fleet, 1, "fleetID")
-def getFleet(fleetID, eager=None):
- if isinstance(fleetID, int):
- if eager is None:
- with sd_lock:
- fleet = saveddata_session.query(Fleet).get(fleetID)
- else:
- eager = processEager(eager)
- with sd_lock:
- fleet = saveddata_session.query(Fleet).options(*eager).filter(Fleet.ID == fleetID).first()
- else:
- raise TypeError("Need integer as argument")
- return fleet
-
-
-@cachedQuery(Wing, 1, "wingID")
-def getWing(wingID, eager=None):
- if isinstance(wingID, int):
- if eager is None:
- with sd_lock:
- wing = saveddata_session.query(Wing).get(wingID)
- else:
- eager = processEager(eager)
- with sd_lock:
- wing = saveddata_session.query(Wing).options(*eager).filter(Wing.ID == wingID).first()
- else:
- raise TypeError("Need integer as argument")
- return wing
-
-
-@cachedQuery(Squad, 1, "squadID")
-def getSquad(squadID, eager=None):
- if isinstance(squadID, int):
- if eager is None:
- with sd_lock:
- squad = saveddata_session.query(Squad).get(squadID)
- else:
- eager = processEager(eager)
- with sd_lock:
- squad = saveddata_session.query(Squad).options(*eager).filter(Fleet.ID == squadID).first()
- else:
- raise TypeError("Need integer as argument")
- return squad
-
-
def getFitsWithShip(shipID, ownerID=None, where=None, eager=None):
"""
Get all the fits using a certain ship.
@@ -341,14 +293,6 @@ def getFitList(eager=None):
return fits
-
-def getFleetList(eager=None):
- eager = processEager(eager)
- with sd_lock:
- fleets = saveddata_session.query(Fleet).options(*eager).all()
- return fleets
-
-
@cachedQuery(Price, 1, "typeID")
def getPrice(typeID):
if isinstance(typeID, int):
@@ -472,18 +416,6 @@ def searchFits(nameLike, where=None, eager=None):
return fits
-
-def getSquadsIDsWithFitID(fitID):
- if isinstance(fitID, int):
- with sd_lock:
- squads = saveddata_session.query(squadmembers_table.c.squadID).filter(
- squadmembers_table.c.memberID == fitID).all()
- squads = tuple(entry[0] for entry in squads)
- return squads
- else:
- raise TypeError("Need integer as argument")
-
-
def getProjectedFits(fitID):
if isinstance(fitID, int):
with sd_lock:
diff --git a/eos/effects/usemissiles.py b/eos/effects/usemissiles.py
index be8396d58..49ef3c5a0 100644
--- a/eos/effects/usemissiles.py
+++ b/eos/effects/usemissiles.py
@@ -3,10 +3,28 @@
# Used by:
# Modules from group: Missile Launcher Heavy (12 of 12)
# Modules from group: Missile Launcher Rocket (15 of 15)
-# Modules named like: Launcher (153 of 153)
-type = 'active'
+# Modules named like: Launcher (151 of 151)
+type = 'active', "projected"
-def handler(fit, module, context):
+def handler(fit, src, context):
# Set reload time to 10 seconds
- module.reloadTime = 10000
+ src.reloadTime = 10000
+
+ if "projected" in context:
+ if src.item.group.name == 'Missile Launcher Bomb':
+ # Bomb Launcher Cooldown Timer
+ moduleReactivationDelay = src.getModifiedItemAttr("moduleReactivationDelay")
+
+ # Void and Focused Void Bombs
+ neutAmount = src.getModifiedChargeAttr("energyNeutralizerAmount")
+
+ if moduleReactivationDelay and neutAmount:
+ fit.addDrain(src, moduleReactivationDelay, neutAmount, 0)
+
+ # Lockbreaker Bombs
+ ecmStrengthBonus = src.getModifiedChargeAttr("scan{0}StrengthBonus".format(fit.scanType))
+
+ if ecmStrengthBonus:
+ strModifier = 1 - ecmStrengthBonus / fit.scanStrength
+ fit.ecmProjectedStr *= strModifier
diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py
index 4637601a2..ff4653697 100644
--- a/eos/saveddata/fit.py
+++ b/eos/saveddata/fit.py
@@ -134,7 +134,6 @@ class Fit(object):
self.__capRecharge = None
self.__calculatedTargets = []
self.factorReload = False
- self.fleet = None
self.boostsFits = set()
self.gangBoosts = None
self.ecmProjectedStr = 1
@@ -632,14 +631,6 @@ class Fit(object):
groups = ("Energy Weapon", "Hybrid Weapon")
self.modules.filteredItemBoost(lambda mod: mod.item.group.name in groups, "maxRange", value, stackingPenalties=True)
- # if effect.isType("offline") or (effect.isType("passive") and thing.state >= State.ONLINE) or \
- # (effect.isType("active") and thing.state >= State.ACTIVE):
- # # Run effect, and get proper bonuses applied
- # try:
- # self.register(thing)
- # effect.handler(self, thing, context)
- # except:
- # pass
else:
# Run effect, and get proper bonuses applied
try:
@@ -665,7 +656,6 @@ class Fit(object):
# Don't inspect this, we genuinely want to reassign self
# noinspection PyMethodFirstArgAssignment
self = copy.deepcopy(self)
- self.fleet = copied.fleet
logger.debug("Handling self projection - making shadow copy of fit. %r => %r", copied, self)
# we delete the fit because when we copy a fit, flush() is
# called to properly handle projection updates. However, we do
@@ -678,24 +668,6 @@ class Fit(object):
continue
fit.calculateModifiedAttributes(self, True)
- #
- # for thing in chain(fit.modules, fit.implants, fit.character.skills, (fit.ship,)):
- # if thing.item is None:
- # continue
- # for effect in thing.item.effects.itervalues():
- # # And check if it actually has gang boosting effects
- # if effect.isType("gang"):
- # effect.handler(self, thing, ("commandRun"))
-
- # if self.fleet is not None and withBoosters is True:
- # logger.debug("Fleet is set, gathering gang boosts")
- #
- # self.gangBoosts = self.fleet.recalculateLinear(withBoosters=withBoosters)
- #
- # timer.checkpoint("Done calculating gang boosts for %r"%self)
-
- # elif self.fleet is None:
- # self.gangBoosts = None
# If we're not explicitly asked to project fit onto something,
# set self as target fit
diff --git a/eos/saveddata/fleet.py b/eos/saveddata/fleet.py
deleted file mode 100644
index 6fc1b6330..000000000
--- a/eos/saveddata/fleet.py
+++ /dev/null
@@ -1,341 +0,0 @@
-# ===============================================================================
-# Copyright (C) 2010 Diego Duclos
-#
-# This file is part of eos.
-#
-# eos is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, either version 2 of the License, or
-# (at your option) any later version.
-#
-# eos is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with eos. If not, see .
-# ===============================================================================
-
-from copy import deepcopy
-from itertools import chain
-
-from eos.types import Skill, Module, Ship
-
-
-class Fleet(object):
- def calculateModifiedAttributes(self):
- # Make sure ALL fits in the gang have been calculated
- for c in chain(self.wings, (self.leader,)):
- if c is not None:
- c.calculateModifiedAttributes()
-
- leader = self.leader
- self.booster = booster = self.booster if self.booster is not None else leader
- self.broken = False
- self.store = store = Store()
- store.set(booster, "fleet")
- # Go all the way down for each subtree we have.
- for wing in self.wings:
- wing.calculateGangBonusses(store)
-
- # Check skill requirements and wing amount to see if we break or not
- if len(self.wings) == 0 or leader is None or leader.character is None or leader.character.getSkill(
- "Fleet Command").level < len(self.wings):
- self.broken = True
-
- # Now calculate our own if we aren't broken
- if not self.broken:
- # We only get our own bonuses *Sadface*
- store.apply(leader, "fleet")
-
- def recalculateLinear(self, withBoosters=True, dirtyStorage=None):
- self.store = Store()
- self.linearBoosts = {}
- if withBoosters is True:
- if self.leader is not None and self.leader.character is not None and self.leader.character.getSkill(
- "Fleet Command").level >= 1:
- self.leader.boostsFits.add(self.wings[0].squads[0].members[0].ID)
- self.leader.calculateModifiedAttributes()
- self.store.set(self.leader, "squad", clearingUpdate=True)
- else:
- self.store = Store()
- if self.leader is not None:
- try:
- self.leader.boostsFits.remove(self.wings[0].squads[0].members[0].ID)
- except KeyError:
- pass
- self.wings[0].recalculateLinear(self.store, withBoosters=withBoosters, dirtyStorage=dirtyStorage)
- return self.linearBoosts
-
- def count(self):
- total = 0
- for wing in self.wings:
- total += wing.count()
-
- return total
-
- def extend(self):
- self.wings.append(Wing())
-
- def __deepcopy__(self, memo):
- copy = Fleet()
- copy.name = self.name
- copy.booster = deepcopy(self.booster)
- copy.leader = deepcopy(self.leader)
- for wing in self.wings:
- copy.wings.append(deepcopy(wing))
-
- return copy
-
-
-class Wing(object):
- def calculateModifiedAttributes(self):
- for c in chain(self.squads, (self.leader,)):
- if c is not None:
- c.calculateModifiedAttributes()
-
- def calculateGangBonusses(self, store):
- self.broken = False
- leader = self.leader
- self.booster = booster = self.booster if self.booster is not None else leader
-
- store.set(booster, "wing")
-
- # ALWAYS move down
- for squad in self.squads:
- squad.calculateGangBonusses(store)
-
- # Check skill requirements and squad amount to see if we break or not
- if len(self.squads) == 0 or leader is None or leader.character is None or leader.character.getSkill(
- "Wing Command").level < len(self.squads):
- self.broken = True
-
- # Check if we aren't broken, if we aren't, boost
- if not self.broken:
- store.apply(leader, "wing")
- else:
- # We broke, don't go up
- self.gang.broken = True
-
- def recalculateLinear(self, store, withBoosters=True, dirtyStorage=None):
- if withBoosters is True:
- if self.leader is not None and self.leader.character is not None and self.leader.character.getSkill(
- "Wing Command").level >= 1:
- self.leader.boostsFits.add(self.squads[0].members[0].ID)
- self.leader.calculateModifiedAttributes()
- store.set(self.leader, "squad", clearingUpdate=False)
- else:
- store = Store()
- if self.gang.leader is not None:
- try:
- self.gang.leader.boostsFits.remove(self.squads[0].members[0].ID)
- except KeyError:
- pass
- if self.leader is not None:
- try:
- self.leader.boostsFits.remove(self.squads[0].members[0].ID)
- except KeyError:
- pass
- self.squads[0].recalculateLinear(store, withBoosters=withBoosters, dirtyStorage=dirtyStorage)
-
- def count(self):
- total = 0 if self.leader is None else 1
- for squad in self.squads:
- total += squad.count()
-
- return total
-
- def extend(self):
- self.squads.append(Squad())
-
- def __deepcopy__(self, memo):
- copy = Wing()
- copy.booster = deepcopy(self.booster)
- copy.leader = deepcopy(self.leader)
- for squad in self.squads:
- copy.squads.append(deepcopy(squad))
-
- return copy
-
-
-class Squad(object):
- def calculateModifiedAttributes(self):
- for member in self.members:
- member.calculateModifiedAttributes()
-
- def calculateGangBonusses(self, store):
- self.broken = False
- leader = self.leader
- self.booster = booster = self.booster if self.booster is not None else leader
- store.set(booster, "squad")
-
- # Check skill requirements and squad size to see if we break or not
- if len(self.members) <= 0 or leader is None or leader.character is None or leader.character.getSkill(
- "Leadership").level * 2 < len(self.members):
- self.broken = True
-
- if not self.broken:
- for member in self.members:
- store.apply(member, "squad")
- else:
- self.wing.broken = True
-
- def recalculateLinear(self, store, withBoosters=True, dirtyStorage=None):
- if withBoosters is True:
- if self.leader is not None and self.leader.character is not None and self.leader.character.getSkill(
- "Leadership").level >= 1:
- self.leader.boostsFits.add(self.members[0].ID)
- self.leader.calculateModifiedAttributes(dirtyStorage=dirtyStorage)
- store.set(self.leader, "squad", clearingUpdate=False)
- else:
- store = Store()
- if self.leader is not None:
- try:
- self.leader.boostsFits.remove(self.members[0].ID)
- except KeyError:
- pass
- if self.wing.leader is not None:
- try:
- self.wing.leader.boostsFits.remove(self.members[0].ID)
- except KeyError:
- pass
- if self.wing.gang.leader is not None:
- try:
- self.wing.gang.leader.boostsFits.remove(self.members[0].ID)
- except KeyError:
- pass
- if getattr(self.wing.gang, "linearBoosts", None) is None:
- self.wing.gang.linearBoosts = {}
- dict = store.bonuses["squad"]
- for boostedAttr, boostInfoList in dict.iteritems():
- for boostInfo in boostInfoList:
- effect, thing = boostInfo
- # Get current boost value for given attribute, use 0 as fallback if
- # no boosts applied yet
- currBoostAmount = self.wing.gang.linearBoosts.get(boostedAttr, (0,))[0]
- # Attribute name which is used to get boost value
- newBoostAttr = effect.getattr("gangBonus") or "commandBonus"
- # Get boost amount for current boost
- newBoostAmount = thing.getModifiedItemAttr(newBoostAttr) or 0
- # Skill used to modify the gang bonus (for purposes of comparing old vs new)
- newBoostSkill = effect.getattr("gangBonusSkill")
- # If skill takes part in gang boosting, multiply by skill level
- if type(thing) == Skill:
- newBoostAmount *= thing.level
- # boost the gang bonus based on skill noted in effect file
- if newBoostSkill:
- newBoostAmount *= thing.parent.character.getSkill(newBoostSkill).level
- # If new boost is more powerful, replace older one with it
- if abs(newBoostAmount) > abs(currBoostAmount):
- self.wing.gang.linearBoosts[boostedAttr] = (newBoostAmount, boostInfo)
-
- def count(self):
- return len(self.members)
-
- def __deepcopy__(self, memo):
- copy = Squad()
- copy.booster = deepcopy(self.booster)
- copy.leader = deepcopy(self.leader)
- for member in self.members:
- copy.members.append(deepcopy(member))
-
- return copy
-
-
-class Store(object):
- def __init__(self):
- # Container for gang boosters and their respective bonuses, three-layered
- self.bonuses = {}
- for dictType in ("fleet", "wing", "squad"):
- self.bonuses[dictType] = {}
- # Container for boosted fits and corresponding boosts applied onto them
- self.boosts = {}
-
- def set(self, fitBooster, layer, clearingUpdate=True):
- """Add all gang boosts of given fit for given layer to boost store"""
- if fitBooster is None:
- return
-
- # This dict contains all bonuses for specified layer
- dict = self.bonuses[layer]
- if clearingUpdate is True:
- # Clear existing bonuses
- dict.clear()
-
- # Go through everything which can be used as gang booster
- for thing in chain(fitBooster.modules, fitBooster.implants, fitBooster.character.skills, (fitBooster.ship,)):
- if thing.item is None:
- continue
- for effect in thing.item.effects.itervalues():
- # And check if it actually has gang boosting effects
- if effect.isType("gang"):
- # Attribute which is boosted
- boostedAttr = effect.getattr("gangBoost")
- # List which contains all bonuses for given attribute for given layer
- l = dict.get(boostedAttr)
- # If there was no list, create it
- if l is None:
- l = dict[boostedAttr] = []
- # And append effect which is used to boost stuff and carrier of this effect
- l.append((effect, thing))
-
- contextMap = {Skill: "skill",
- Ship: "ship",
- Module: "module"}
-
- def apply(self, fitBoosted, layer):
- """Applies all boosts onto given fit for given layer"""
- if fitBoosted is None:
- return
- # Boosts dict contains all bonuses applied onto given fit
- self.boosts[fitBoosted] = boosts = {}
- # Go through all bonuses for given layer, and find highest one per boosted attribute
- for currLayer in ("fleet", "wing", "squad"):
- # Dictionary with boosts for given layer
- dict = self.bonuses[currLayer]
- for boostedAttr, boostInfoList in dict.iteritems():
- for boostInfo in boostInfoList:
- effect, thing = boostInfo
- # Get current boost value for given attribute, use 0 as fallback if
- # no boosts applied yet
- currBoostAmount = boosts.get(boostedAttr, (0,))[0]
- # Attribute name which is used to get boost value
- newBoostAttr = effect.getattr("gangBonus") or "commandBonus"
- # Get boost amount for current boost
- newBoostAmount = thing.getModifiedItemAttr(newBoostAttr) or 0
- # Skill used to modify the gang bonus (for purposes of comparing old vs new)
- newBoostSkill = effect.getattr("gangBonusSkill")
- # If skill takes part in gang boosting, multiply by skill level
- if type(thing) == Skill:
- newBoostAmount *= thing.level
- # boost the gang bonus based on skill noted in effect file
- if newBoostSkill:
- newBoostAmount *= thing.parent.character.getSkill(newBoostSkill).level
- # If new boost is more powerful, replace older one with it
- if abs(newBoostAmount) > abs(currBoostAmount):
- boosts[boostedAttr] = (newBoostAmount, boostInfo)
-
- # Don't look further down then current layer, wing commanders don't get squad bonuses and all that
- if layer == currLayer:
- break
-
- self.modify(fitBoosted)
-
- def getBoosts(self, fit):
- """Return all boosts applied onto given fit"""
- return self.boosts.get(fit)
-
- def modify(self, fitBoosted):
- # Get all boosts which should be applied onto current fit
- boosts = self.getBoosts(fitBoosted)
- # Now we got it all figured out, actually do the useful part of all this
- for name, info in boosts.iteritems():
- # Unpack all data required to run effect properly
- effect, thing = info[1]
- context = ("gang", self.contextMap[type(thing)])
- # Run effect, and get proper bonuses applied
- try:
- effect.handler(fitBoosted, thing, context)
- except:
- pass
diff --git a/eos/types.py b/eos/types.py
index d42cd0fe8..1fbf2676b 100644
--- a/eos/types.py
+++ b/eos/types.py
@@ -39,7 +39,6 @@ from eos.saveddata.implantSet import ImplantSet
from eos.saveddata.booster import Booster
from eos.saveddata.fit import Fit, ImplantLocation
from eos.saveddata.mode import Mode
-from eos.saveddata.fleet import Fleet, Wing, Squad
from eos.saveddata.miscData import MiscData
from eos.saveddata.override import Override
diff --git a/gui/additionsPane.py b/gui/additionsPane.py
index c7b28b48b..e67963ee1 100644
--- a/gui/additionsPane.py
+++ b/gui/additionsPane.py
@@ -29,7 +29,6 @@ from gui.projectedView import ProjectedView
from gui.commandView import CommandView
from gui.notesView import NotesView
from gui.pyfatogglepanel import TogglePanel
-from gui.gangView import GangView
from gui.bitmapLoader import BitmapLoader
import gui.chromeTabs
diff --git a/gui/builtinViews/__init__.py b/gui/builtinViews/__init__.py
index 46a500f7b..d51fdbad6 100644
--- a/gui/builtinViews/__init__.py
+++ b/gui/builtinViews/__init__.py
@@ -1 +1 @@
-__all__ = ["fittingView", "fleetView", "implantEditor"]
+__all__ = ["fittingView", "implantEditor"]
diff --git a/gui/builtinViews/fleetView.py b/gui/builtinViews/fleetView.py
deleted file mode 100644
index bc6eef9a2..000000000
--- a/gui/builtinViews/fleetView.py
+++ /dev/null
@@ -1,140 +0,0 @@
-import wx.gizmos
-import gui.fleetBrowser
-import service
-from gui.bitmapLoader import BitmapLoader
-
-#Tab spawning handler
-class FleetSpawner(gui.multiSwitch.TabSpawner):
- def __init__(self, multiSwitch):
- self.multiSwitch = multiSwitch
- mainFrame = gui.mainFrame.MainFrame.getInstance()
- mainFrame.Bind(gui.fleetBrowser.EVT_FLEET_SELECTED, self.fleetSelected)
-
- def fleetSelected(self, event):
- if self.multiSwitch.GetPageCount() == 0:
- self.multiSwitch.AddPage(wx.Panel(self.multiSwitch, size = (0,0)), "Empty Tab")
-
- view = FleetView(self.multiSwitch)
- self.multiSwitch.ReplaceActivePage(view)
- view.populate(event.fleetID)
- view.Show()
-
-FleetSpawner.register()
-
-class FleetView(wx.gizmos.TreeListCtrl):
- def __init__(self, parent, size = (0,0)):
- wx.gizmos.TreeListCtrl.__init__(self, parent, size = size)
-
- self.tabManager = parent
-
- self.fleetId = None
- self.fleetImg = BitmapLoader.getImage("53_16", "icons")
-
- self.imageList = wx.ImageList(16, 16)
- self.SetImageList(self.imageList)
-
- for col in ("", "Fit", "Shiptype", "Character", "Bonusses"):
- self.AddColumn(col)
-
- self.SetMainColumn(1)
- self.icons = {}
- self.addImage = self.imageList.Add(BitmapLoader.getBitmap("add_small", "gui"))
- for icon in ("fb", "fc", "sb", "sc", "wb", "wc"):
- self.icons[icon] = self.imageList.Add(BitmapLoader.getBitmap("fleet_%s_small" % icon, "gui"))
-
- self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.checkNew)
- self.mainFrame = gui.mainFrame.MainFrame.getInstance()
-
- self.mainFrame.Bind(gui.fleetBrowser.EVT_FLEET_RENAMED, self.fleetRenamed)
- self.mainFrame.Bind(gui.fleetBrowser.EVT_FLEET_REMOVED, self.fleetRemoved)
-
- def Destroy(self):
- self.mainFrame.Unbind(gui.fleetBrowser.EVT_FLEET_REMOVED, handler = self.fleetRemoved)
- self.mainFrame.Unbind(gui.fleetBrowser.EVT_FLEET_RENAMED, handler = self.fleetRenamed)
- wx.gizmos.TreeListCtrl.Destroy(self)
-
- def fleetRenamed(self, event):
- if event.fleetID == self.fleetId:
- sFleet = service.Fleet.getInstance()
- f = sFleet.getFleetByID(event.fleetID)
- self.UpdateTab(f.name, self.fleetImg)
-
- event.Skip()
-
- def fleetRemoved(self, event):
- if event.fleetID == self.fleetId:
- self.tabManager.DeletePage(self.tabManager.GetPageIndex(self))
-
- event.Skip()
-
- def checkNew(self, event):
- data = self.GetPyData(event.Item)
- if data and isinstance(data, tuple) and data[0] == "add":
- layer = data[1]
-
-
- def UpdateTab(self, name, img):
- self.tabManager.SetPageTextIcon(self.tabManager.GetSelection(), name, img)
-
- def populate(self, fleetID):
- sFleet = service.Fleet.getInstance()
- f = sFleet.getFleetByID(fleetID)
- self.fleetId = fleetID
-
- self.UpdateTab( f.name, self.fleetImg)
- self.fleet = f
- self.DeleteAllItems()
- root = self.AddRoot("")
-
- self.setEntry(root, f.leader, "fleet", f)
- for wing in f.wings:
- wingId = self.AppendItem(root, "")
- self.setEntry(wingId, wing.leader, "wing", wing)
- for squad in wing.squads:
- for member in squad.members:
- memberId = self.AppendItem(wingId, "")
- self.setEntry(memberId, member, "squad", squad)
-
- self.addAdder(wingId, "squad")
-
- self.addAdder(root, "wing")
-
- self.ExpandAll(root)
- self.SetColumnWidth(0, 16)
- for i in xrange(1, 5):
- self.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER)
- headerWidth = self.GetColumnWidth(i) + 5
- self.SetColumnWidth(i, wx.LIST_AUTOSIZE)
- baseWidth = self.GetColumnWidth(i)
- if baseWidth < headerWidth:
- self.SetColumnWidth(i, headerWidth)
- else:
- self.SetColumnWidth(i, baseWidth)
-
-
- def addAdder(self, treeItemId, layer):
- id = self.AppendItem(treeItemId, "Add new %s" % layer.capitalize())
- self.SetPyData(id, ("add", layer))
- self.SetItemImage(id, self.addImage, 1)
-
- def setEntry(self, treeItemId, fit, layer, info):
- self.SetPyData(treeItemId, info)
- if fit is None:
- self.SetItemText(treeItemId, "%s Commander" % layer.capitalize(), 1)
- else:
- fleet = self.fleet
- if fit == info.booster:
- self.SetItemImage(treeItemId, self.icons["%sb" % layer[0]], 0)
- elif fit == info.leader:
- self.SetItemImage(treeItemId, self.icons["%sc" % layer[0]], 1)
-
- self.SetItemText(treeItemId, fit.name, 1)
- self.SetItemText(treeItemId, fit.ship.item.name, 2)
- self.SetItemText(treeItemId, fit.character.name, 3)
- boosts = fleet.store.getBoosts(fit)
- if boosts:
- bonusses = []
- for name, info in boosts.iteritems():
- bonusses.append("%s: %.2g" % (name, info[0]))
-
- self.SetItemText(treeItemId, ", ".join(bonusses), 3)
diff --git a/gui/fleetBrowser.py b/gui/fleetBrowser.py
deleted file mode 100644
index 7476d7d7f..000000000
--- a/gui/fleetBrowser.py
+++ /dev/null
@@ -1,456 +0,0 @@
-import wx
-import copy
-from gui.bitmapLoader import BitmapLoader
-import gui.mainFrame
-from gui.PFListPane import PFListPane
-import service.fleet
-from gui.utils.drawUtils import GetPartialText
-
-from wx.lib.buttons import GenBitmapButton
-
-import gui.utils.colorUtils as colorUtils
-import gui.utils.drawUtils as drawUtils
-
-import gui.sfBrowserItem as SFItem
-
-FleetSelected, EVT_FLEET_SELECTED = wx.lib.newevent.NewEvent()
-FleetRenamed, EVT_FLEET_RENAMED = wx.lib.newevent.NewEvent()
-FleetRemoved, EVT_FLEET_REMOVED = wx.lib.newevent.NewEvent()
-
-
-FleetItemSelect, EVT_FLEET_ITEM_SELECT = wx.lib.newevent.NewEvent()
-FleetItemDelete, EVT_FLEET_ITEM_DELETE = wx.lib.newevent.NewEvent()
-FleetItemNew, EVT_FLEET_ITEM_NEW = wx.lib.newevent.NewEvent()
-FleetItemCopy, EVT_FLEET_ITEM_COPY = wx.lib.newevent.NewEvent()
-FleetItemRename, EVT_FLEET_ITEM_RENAME = wx.lib.newevent.NewEvent()
-
-
-
-class FleetBrowser(wx.Panel):
- def __init__(self, parent):
- wx.Panel.__init__(self, parent)
-
- self.sFleet = service.fleet.Fleet.getInstance()
- self.mainFrame = gui.mainFrame.MainFrame.getInstance()
-
- mainSizer = wx.BoxSizer(wx.VERTICAL)
-
- self.hpane = FleetBrowserHeader(self)
- mainSizer.Add(self.hpane, 0, wx.EXPAND)
-
- self.m_sl2 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
- mainSizer.Add( self.m_sl2, 0, wx.EXPAND, 0 )
-
- self.fleetItemContainer = PFFleetItemContainer(self)
-
- mainSizer.Add(self.fleetItemContainer, 1, wx.EXPAND)
-
- self.SetSizer(mainSizer)
- self.Layout()
-
- self.filter = ""
- self.fleetIDMustEditName = -1
-
- self.Bind(wx.EVT_SIZE, self.SizeRefreshList)
-
- self.Bind(EVT_FLEET_ITEM_NEW, self.AddNewFleetItem)
- self.Bind(EVT_FLEET_ITEM_SELECT, self.SelectFleetItem)
- self.Bind(EVT_FLEET_ITEM_DELETE, self.DeleteFleetItem)
- self.Bind(EVT_FLEET_ITEM_COPY, self.CopyFleetItem)
- self.Bind(EVT_FLEET_ITEM_RENAME, self.RenameFleetItem)
-
- self.PopulateFleetList()
-
- def AddNewFleetItem(self, event):
- fleetName = event.fleetName
- newFleet = self.sFleet.addFleet()
- self.sFleet.renameFleet(newFleet, fleetName)
-
- self.fleetIDMustEditName = newFleet.ID
- self.AddItem(newFleet.ID, newFleet.name, newFleet.count())
-
- def SelectFleetItem(self, event):
- fleetID = event.fleetID
- self.fleetItemContainer.SelectWidgetByFleetID(fleetID)
- wx.PostEvent(self.mainFrame, FleetSelected(fleetID=fleetID))
-
- def CopyFleetItem(self, event):
- fleetID = event.fleetID
- fleet = self.sFleet.copyFleetByID(fleetID)
-
- fleetName = fleet.name + " Copy"
- self.sFleet.renameFleet(fleet,fleetName)
-
- self.fleetIDMustEditName = fleet.ID
- self.AddItem(fleet.ID, fleet.name, fleet.count())
-
- self.fleetItemContainer.SelectWidgetByFleetID(fleet.ID)
- wx.PostEvent(self.mainFrame, FleetSelected(fleetID=fleet.ID))
-
- def RenameFleetItem(self, event):
- fleetID = event.fleetID
- fleet = self.sFleet.getFleetByID(fleetID)
-
- newFleetName = event.fleetName
-
- self.sFleet.renameFleet(fleet, newFleetName)
- wx.PostEvent(self.mainFrame, FleetRenamed(fleetID = fleet.ID))
-
- def DeleteFleetItem(self, event):
- self.sFleet.deleteFleetByID(event.fleetID)
- self.PopulateFleetList()
- wx.PostEvent(self.mainFrame, FleetRemoved(fleetID = event.fleetID))
-
- def AddItem (self, ID, name, count):
- self.fleetItemContainer.AddWidget(FleetItem(self, ID, name, count))
- widget = self.fleetItemContainer.GetWidgetByFleetID(ID)
- self.fleetItemContainer.RefreshList(True)
- self.fleetItemContainer.ScrollChildIntoView(widget)
- wx.PostEvent(self, FleetItemSelect(fleetID = ID))
-
- def PopulateFleetList(self):
- self.Freeze()
- filter = self.filter
- self.fleetItemContainer.RemoveAllChildren()
- fleetList = self.sFleet.getFleetList()
- for fleetID, fleetName, fleetCount in fleetList:
- if fleetName.lower().find(filter.lower()) != -1:
- self.fleetItemContainer.AddWidget(FleetItem(self, fleetID, fleetName, fleetCount))
- self.fleetItemContainer.RefreshList()
- self.Thaw()
-
- def SetFilter(self, filter):
- self.filter = filter
-
- def SizeRefreshList(self, event):
- ewidth, eheight = event.GetSize()
- self.Layout()
- self.fleetItemContainer.Layout()
- self.fleetItemContainer.RefreshList(True)
- event.Skip()
-
-
-class FleetBrowserHeader (wx.Panel):
- def __init__(self, parent):
- wx.Panel.__init__ (self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(500, 24), style=wx.TAB_TRAVERSAL)
- self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
-
- self.newBmp = BitmapLoader.getBitmap("fit_add_small","gui")
- bmpSize = (16,16)
-
- mainSizer = wx.BoxSizer(wx.HORIZONTAL)
-
- if 'wxMac' in wx.PlatformInfo:
- bgcolour = wx.Colour(0, 0, 0, 0)
- else:
- bgcolour = wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE )
-
- self.fbNewFleet = PFGenBitmapButton( self, wx.ID_ANY, self.newBmp, wx.DefaultPosition, bmpSize, wx.BORDER_NONE )
- mainSizer.Add(self.fbNewFleet, 0, wx.LEFT | wx.TOP | wx.BOTTOM | wx.ALIGN_CENTER_VERTICAL , 5)
- self.fbNewFleet.SetBackgroundColour( bgcolour )
-
- self.sl1 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_VERTICAL )
- mainSizer.Add( self.sl1, 0, wx.EXPAND |wx.LEFT, 5 )
-
- self.tcFilter = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
- mainSizer.Add( self.tcFilter, 0, wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 5 )
-
- self.stStatus = wx.StaticText( self, wx.ID_ANY, u"", wx.DefaultPosition, wx.DefaultSize, 0 )
- self.stStatus.Wrap( -1 )
- mainSizer.Add( self.stStatus, 1, wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 5 )
-
- self.SetSizer(mainSizer)
- self.Layout()
-
- self.fbNewFleet.Bind(wx.EVT_ENTER_WINDOW, self.fbNewEnterWindow)
- self.fbNewFleet.Bind(wx.EVT_LEAVE_WINDOW, self.fbHItemLeaveWindow)
- self.fbNewFleet.Bind(wx.EVT_BUTTON, self.OnNewFleetItem)
-
- self.tcFilter.Bind(wx.EVT_TEXT, self.OnFilterText)
-
- self.tcFilter.Bind(wx.EVT_ENTER_WINDOW, self.fbFilterEnterWindow)
- self.tcFilter.Bind(wx.EVT_LEAVE_WINDOW, self.fbHItemLeaveWindow)
-
- def OnFilterText(self, event):
- filter = self.tcFilter.GetValue()
- self.Parent.SetFilter(filter)
- self.Parent.PopulateFleetList()
- event.Skip()
-
- def OnNewFleetItem(self, event):
- wx.PostEvent(self.Parent, FleetItemNew(fleetName = "New Fleet"))
-
- def fbNewEnterWindow(self, event):
- self.stStatus.SetLabel("New fleet")
- self.Parent.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
- event.Skip()
-
- def fbHItemLeaveWindow(self, event):
- self.stStatus.SetLabel("")
- self.Parent.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
- event.Skip()
-
- def fbFilterEnterWindow(self, event):
- self.stStatus.SetLabel("Filter list")
- event.Skip()
-
-
-
-class PFFleetItemContainer(PFListPane):
- def __init__(self,parent):
- PFListPane.__init__(self,parent)
- self.selectedWidget = -1
- self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
-
- def IsWidgetSelectedByContext(self, widget):
- if self.GetWidgetList()[widget].IsSelected():
- return True
- return False
-
- def GetWidgetIndex(self, widgetWnd):
- return self.GetWidgetList().index(widgetWnd)
-
- def GetWidgetByFleetID(self, fleetID):
- for widget in self.GetWidgetList():
- if widget.fleetID == fleetID:
- return widget
- return None
-
- def SelectWidget(self, widgetWnd):
- wlist = self.GetWidgetList()
- if self.selectedWidget != -1:
- wlist[self.selectedWidget].SetSelected(False)
- wlist[self.selectedWidget].Refresh()
- windex = self.GetWidgetIndex(widgetWnd)
- wlist[windex].SetSelected(True)
- wlist[windex].Refresh()
- self.selectedWidget = windex
-
- def SelectWidgetByFleetID(self, fleetID):
- widgetWnd = self.GetWidgetByFleetID(fleetID)
- if widgetWnd:
- self.SelectWidget(widgetWnd)
-
- def RemoveWidget(self, child):
- child.Destroy()
- self.selectedWidget = -1
- self._wList.remove(child)
-
-
- def RemoveAllChildren(self):
- for widget in self._wList:
- widget.Destroy()
-
- self.selectedWidget = -1
- self._wList = []
-
- def OnLeftUp(self, event):
- event.Skip()
-
-class FleetItem(SFItem.SFBrowserItem):
- def __init__(self, parent, fleetID, fleetName, fleetCount,
- id=wx.ID_ANY, pos=wx.DefaultPosition,
- size=(0,40), style=0):
- SFItem.SFBrowserItem.__init__(self, parent, size = size)
-
- self.fleetBrowser = self.Parent
- self.fleetID = fleetID
- self.fleetName = fleetName
- self.fleetCount = fleetCount
-
- self.padding = 4
-
- self.fontBig = wx.FontFromPixelSize((0,15),wx.SWISS, wx.NORMAL, wx.BOLD, False)
- self.fontNormal = wx.FontFromPixelSize((0,14),wx.SWISS, wx.NORMAL, wx.NORMAL, False)
- self.fontSmall = wx.FontFromPixelSize((0,12),wx.SWISS, wx.NORMAL, wx.NORMAL, False)
-
- self.copyBmp = BitmapLoader.getBitmap("fit_add_small", "gui")
- self.renameBmp = BitmapLoader.getBitmap("fit_rename_small", "gui")
- self.deleteBmp = BitmapLoader.getBitmap("fit_delete_small","gui")
- self.acceptBmp = BitmapLoader.getBitmap("faccept_small", "gui")
- self.fleetBmp = BitmapLoader.getBitmap("fleet_item_big", "gui")
-
- fleetImg = self.fleetBmp.ConvertToImage()
- fleetImg = fleetImg.Blur(2)
-
- if not fleetImg.HasAlpha():
- fleetImg.InitAlpha()
-
- fleetImg = fleetImg.AdjustChannels(1, 1, 1, 0.5)
- self.fleetEffBmp = wx.BitmapFromImage(fleetImg)
-
- self.toolbar.AddButton(self.copyBmp, "Copy", self.CopyFleetCB)
- self.renameBtn = self.toolbar.AddButton(self.renameBmp, "Rename", self.RenameFleetCB)
- self.toolbar.AddButton(self.deleteBmp, "Delete", self.DeleteFleetCB)
-
- self.editWidth = 150
- self.tcFleetName = wx.TextCtrl(self, wx.ID_ANY, "%s" % self.fleetName, wx.DefaultPosition, (self.editWidth,-1), wx.TE_PROCESS_ENTER)
-
- if self.fleetBrowser.fleetIDMustEditName != self.fleetID:
- self.tcFleetName.Show(False)
- else:
- self.tcFleetName.SetFocus()
- self.tcFleetName.SelectAll()
- self.fleetBrowser.fleetIDMustEditName = -1
- self.renameBtn.SetBitmap(self.acceptBmp)
- self.selected = True
-
- self.tcFleetName.Bind(wx.EVT_KILL_FOCUS, self.OnEditLostFocus)
- self.tcFleetName.Bind(wx.EVT_TEXT_ENTER, self.RenameFleet)
- self.tcFleetName.Bind(wx.EVT_KEY_DOWN, self.EditCheckEsc)
-
-
- self.animCount = 0
-
- def MouseLeftUp(self, event):
- if self.tcFleetName.IsShown():
- self.RestoreEditButton()
- else:
- wx.PostEvent(self.fleetBrowser, FleetItemSelect(fleetID = self.fleetID))
-
- def CopyFleetCB(self):
- if self.tcFleetName.IsShown():
- self.RestoreEditButton()
- return
-
- wx.PostEvent(self.fleetBrowser, FleetItemCopy(fleetID = self.fleetID))
-
- def RenameFleetCB(self):
-
- if self.tcFleetName.IsShown():
-
- self.RenameFleet(None)
- self.RestoreEditButton()
-
- else:
- self.tcFleetName.SetValue(self.fleetName)
- self.tcFleetName.Show()
-
- self.renameBtn.SetBitmap(self.acceptBmp)
- self.Refresh()
-
- self.tcFleetName.SetFocus()
- self.tcFleetName.SelectAll()
-
- self.Refresh()
-
- def RenameFleet(self, event):
-
- newFleetName = self.tcFleetName.GetValue()
- self.fleetName = newFleetName
-
- self.tcFleetName.Show(False)
-
- wx.PostEvent(self.fleetBrowser, FleetItemRename(fleetID = self.fleetID, fleetName = self.fleetName))
- self.Refresh()
-
- def DeleteFleetCB(self):
- if self.tcFleetName.IsShown():
- self.RestoreEditButton()
- return
- wx.PostEvent(self.fleetBrowser, FleetItemDelete(fleetID = self.fleetID))
-
- def RestoreEditButton(self):
- self.tcFleetName.Show(False)
- self.renameBtn.SetBitmap(self.renameBmp)
- self.Refresh()
-
- def OnEditLostFocus(self, event):
- self.RestoreEditButton()
- self.Refresh()
-
- def EditCheckEsc(self, event):
- if event.GetKeyCode() == wx.WXK_ESCAPE:
- self.RestoreEditButton()
- else:
- event.Skip()
-
- def IsSelected(self):
- return self.selected
-
- def UpdateElementsPos(self, mdc):
- rect = self.GetRect()
-
- self.toolbarx = rect.width - self.toolbar.GetWidth() - self.padding
- self.toolbary = (rect.height - self.toolbar.GetHeight()) / 2
-
- self.toolbarx = self.toolbarx + self.animCount
-
- self.fleetBmpx = self.padding + (rect.height - self.fleetBmp.GetWidth()) / 2
- self.fleetBmpy = (rect.height - self.fleetBmp.GetHeight()) / 2
-
- self.fleetBmpx -= self.animCount
-
- self.textStartx = self.fleetBmpx + self.fleetBmp.GetWidth() + self.padding
-
- self.fleetNamey = (rect.height - self.fleetBmp.GetHeight()) / 2
-
- mdc.SetFont(self.fontBig)
- wtext, htext = mdc.GetTextExtent(self.fleetName)
-
- self.fleetCounty = self.fleetNamey + htext
-
- mdc.SetFont(self.fontSmall)
-
- wlabel,hlabel = mdc.GetTextExtent(self.toolbar.hoverLabel)
-
- self.thoverx = self.toolbarx - self.padding - wlabel
- self.thovery = (rect.height - hlabel)/2
- self.thoverw = wlabel
-
- def DrawItem(self, mdc):
- rect = self.GetRect()
-
- windowColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)
- textColor = colorUtils.GetSuitableColor(windowColor, 1)
-
- mdc.SetTextForeground(textColor)
-
- self.UpdateElementsPos(mdc)
-
- self.toolbar.SetPosition((self.toolbarx, self.toolbary))
- mdc.DrawBitmap(self.fleetEffBmp, self.fleetBmpx + 3, self.fleetBmpy + 2)
- mdc.DrawBitmap(self.fleetBmp, self.fleetBmpx,self.fleetBmpy)
-
- mdc.SetFont(self.fontNormal)
-
- suffix = "%d ships" % self.fleetCount if self.fleetCount >1 else "%d ship" % self.fleetCount if self.fleetCount == 1 else "No ships"
- fleetCount = "Fleet size: %s" % suffix
- fleetCount = drawUtils.GetPartialText(mdc, fleetCount, self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw)
-
- mdc.DrawText(fleetCount, self.textStartx, self.fleetCounty)
-
- mdc.SetFont(self.fontSmall)
- mdc.DrawText(self.toolbar.hoverLabel, self.thoverx, self.thovery)
-
- mdc.SetFont(self.fontBig)
-
- pfname = drawUtils.GetPartialText(mdc, self.fleetName, self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw)
- mdc.DrawText(pfname, self.textStartx, self.fleetNamey)
-
- if self.tcFleetName.IsShown():
- self.AdjustControlSizePos(self.tcFleetName, self.textStartx, self.toolbarx - self.editWidth - self.padding)
-
- def AdjustControlSizePos(self, editCtl, start, end):
- fnEditSize = editCtl.GetSize()
- wSize = self.GetSize()
- fnEditPosX = end
- fnEditPosY = (wSize.height - fnEditSize.height)/2
- if fnEditPosX < start:
- editCtl.SetSize((self.editWidth + fnEditPosX - start,-1))
- editCtl.SetPosition((start,fnEditPosY))
- else:
- editCtl.SetSize((self.editWidth,-1))
- editCtl.SetPosition((fnEditPosX,fnEditPosY))
-
-
-class PFGenBitmapButton(GenBitmapButton):
- def __init__(self, parent, id, bitmap, pos, size, style):
- GenBitmapButton.__init__(self, parent, id, bitmap, pos, size, style)
- self.bgcolor = wx.Brush(wx.WHITE)
-
- def SetBackgroundColour(self, color):
- self.bgcolor = wx.Brush(color)
-
- def GetBackgroundBrush(self, dc):
- return self.bgcolor
diff --git a/gui/gangView.py b/gui/gangView.py
deleted file mode 100644
index 106f14f98..000000000
--- a/gui/gangView.py
+++ /dev/null
@@ -1,412 +0,0 @@
-#===============================================================================
-# Copyright (C) 2010 Diego Duclos
-#
-# This file is part of pyfa.
-#
-# pyfa is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# pyfa is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with pyfa. If not, see .
-#===============================================================================
-import wx
-from wx.lib.scrolledpanel import ScrolledPanel
-
-import service
-import gui.mainFrame
-import gui.shipBrowser
-import gui.globalEvents as GE
-
-from gui import characterEditor as CharEditor
-
-class GangView ( ScrolledPanel ):
-
- def __init__( self, parent ):
- ScrolledPanel.__init__ ( self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = wx.Size( 100,20 ), style = wx.TAB_TRAVERSAL | wx.HSCROLL | wx.VSCROLL )
- mainSizer = wx.BoxSizer( wx.VERTICAL )
-
- self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
- self.mainFrame = gui.mainFrame.MainFrame.getInstance()
-
- self.draggedFitID = None
-
- help = '''Set fit as booster to display in dropdown, or drag fitting from\nship browser to this window, or right click fit and select booster role.'''
- helpSizer = wx.BoxSizer( wx.HORIZONTAL )
- self.helpText = wx.StaticText( self, wx.ID_ANY, help, wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE )
- helpSizer.Add( self.helpText, 1, wx.ALL, 5 )
-
- self.options = ["Fleet", "Wing", "Squad"]
-
- self.fleet = {}
- for id, option in enumerate(self.options):
-
- # set content for each commander
- self.fleet[id] = {}
- self.fleet[id]['stLabel'] = wx.StaticText( self, wx.ID_ANY, self.options[id]+':', wx.DefaultPosition, wx.DefaultSize, 0 )
- self.fleet[id]['stText'] = wx.StaticText( self, wx.ID_ANY, 'None', wx.DefaultPosition, wx.DefaultSize, 0 )
- self.fleet[id]['chFit'] = wx.Choice( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, [] )
- self.fleet[id]['chChar'] = wx.Choice( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, [] )
- self.fleet[id]['fitSizer'] = wx.BoxSizer( wx.VERTICAL )
-
- self.FitDNDPopupMenu = self.buildBoostermenu()
-
- contentFGSizer = wx.FlexGridSizer( 5, 3, 0, 0 )
- contentFGSizer.AddGrowableCol( 1 )
- contentFGSizer.SetFlexibleDirection( wx.BOTH )
- contentFGSizer.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED )
-
- ### Header
- self.stBooster = wx.StaticText( self, wx.ID_ANY, u"Booster", wx.DefaultPosition, wx.DefaultSize, 0 )
- self.stBooster.Wrap( -1 )
- self.stBooster.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) )
- contentFGSizer.Add( self.stBooster, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 5 )
-
- self.stFits = wx.StaticText( self, wx.ID_ANY, u"Fits", wx.DefaultPosition, wx.DefaultSize, 0 )
- self.stFits.Wrap( -1 )
- self.stFits.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) )
- contentFGSizer.Add( self.stFits, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL, 5 )
-
- self.stCharacters = wx.StaticText( self, wx.ID_ANY, u"Characters", wx.DefaultPosition, wx.DefaultSize, 0 )
- self.stCharacters.Wrap( -1 )
- self.stCharacters.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) )
- contentFGSizer.Add( self.stCharacters, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL, 5 )
-
- self.m_staticline2 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
- contentFGSizer.Add( self.m_staticline2, 0, wx.EXPAND, 5 )
-
- self.m_staticline3 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
- contentFGSizer.Add( self.m_staticline3, 0, wx.EXPAND, 5 )
-
- self.m_staticline4 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
- contentFGSizer.Add( self.m_staticline4, 0, wx.EXPAND, 5 )
-
- ### Content
- for id in self.fleet:
- # set various properties
- self.fleet[id]['stLabel'].Wrap( -1 )
- self.fleet[id]['stLabel'].SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) )
- self.fleet[id]['stText'].Wrap( -1 )
-
- # bind text and choice events
- self.fleet[id]['stText'].Bind(wx.EVT_LEFT_DCLICK, self.RemoveBooster)
- self.fleet[id]['stText'].Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
- self.fleet[id]['stText'].Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
- self.fleet[id]['stText'].SetToolTip(wx.ToolTip("Double click to remove booster"))
- self.fleet[id]['chChar'].Bind(wx.EVT_CHOICE, self.CharChanged)
- self.fleet[id]['chFit'].Bind(wx.EVT_CHOICE, self.OnFitChoiceSelected)
-
- # add fit text and choice to the fit sizer
- self.fleet[id]['fitSizer'].Add( self.fleet[id]['stText'], 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
- self.fleet[id]['fitSizer'].Add( self.fleet[id]['chFit'], 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.EXPAND, 1 )
-
- # add everything to the content sizer
- contentFGSizer.Add( self.fleet[id]['stLabel'], 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
- contentFGSizer.Add( self.fleet[id]['fitSizer'], 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.EXPAND, 5 )
- contentFGSizer.Add( self.fleet[id]['chChar'], 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
-
- mainSizer.Add( contentFGSizer, 1, wx.EXPAND, 0 )
- mainSizer.Add( helpSizer, 0, wx.EXPAND, 0 )
-
- self.SetSizer( mainSizer )
- self.SetAutoLayout(True)
- self.SetupScrolling()
-
- self.mainFrame.Bind(GE.CHAR_LIST_UPDATED, self.RefreshCharacterList)
- self.mainFrame.Bind(GE.FIT_CHANGED, self.fitSelected)
- self.mainFrame.Bind(gui.shipBrowser.EVT_FIT_RENAMED, self.fitRenamed)
- self.mainFrame.Bind(gui.shipBrowser.BOOSTER_LIST_UPDATED, self.RefreshBoosterFits)
-
- self.RefreshBoosterFits()
- self.RefreshCharacterList()
-
- def buildBoostermenu(self):
- menu = wx.Menu()
-
- for id, option in enumerate(self.options):
- item = menu.Append(-1, option)
- # We bind it to the mainFrame because it may be called from either this class or from FitItem via shipBrowser
- self.mainFrame.Bind(wx.EVT_MENU, self.OnPopupItemSelected, item)
- return menu
-
- def OnEnterWindow(self, event):
- obj = event.GetEventObject()
- obj.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
- event.Skip()
-
- def OnLeaveWindow(self, event):
- obj = event.GetEventObject()
- obj.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
- event.Skip()
-
- def CharChanged(self, event):
- ''' Change booster character '''
- chBooster = event.GetEventObject()
-
- type = -1
- for id in self.fleet:
- if chBooster == self.fleet[id]['chChar']: type = id
-
- if type == -1:
- event.Skip()
- return
-
- sFit = service.Fit.getInstance()
-
- fleetSrv = service.Fleet.getInstance()
-
- activeFitID = self.mainFrame.getActiveFit()
- fit = sFit.getFit(activeFitID)
-
- sChar = service.Character.getInstance()
- charList = sChar.getCharacterList()
-
- if activeFitID:
- commanders = fleetSrv.loadLinearFleet(fit)
- if commanders is None:
- fleetCom, wingCom, squadCom = (None, None, None)
- else:
- fleetCom, wingCom, squadCom = commanders
-
- if type == 0:
- if fleetCom:
- charID = chBooster.GetClientData(chBooster.GetSelection())
- sFit.changeChar(fleetCom.ID, charID)
- else:
- chBooster.SetSelection(0)
-
- if type == 1:
- if wingCom:
- charID = chBooster.GetClientData(chBooster.GetSelection())
- sFit.changeChar(wingCom.ID, charID)
- else:
- chBooster.SetSelection(0)
-
- if type == 2:
- if squadCom:
- charID = chBooster.GetClientData(chBooster.GetSelection())
- sFit.changeChar(squadCom.ID, charID)
- else:
- chBooster.SetSelection(0)
-
- sFit.recalc(fit, withBoosters=True)
- wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFitID))
-
- else:
- chBooster.SetSelection(0)
-
- def RemoveBooster(self, event):
- activeFitID = self.mainFrame.getActiveFit()
- if not activeFitID:
- return
-
- location = event.GetEventObject()
-
- for id in self.fleet:
- if location == self.fleet[id]['stText']: type = id
-
- sFit = service.Fit.getInstance()
- boostee = sFit.getFit(activeFitID)
- booster = None
-
- fleetSrv = service.Fleet.getInstance()
-
- if type == 0: fleetSrv.setLinearFleetCom(boostee, booster)
- if type == 1: fleetSrv.setLinearWingCom(boostee, booster)
- if type == 2: fleetSrv.setLinearSquadCom(boostee, booster)
-
- # Hide stText and, default fit selection, and enable it
- location.Hide()
- choice = self.fleet[type]['chFit']
- choice.SetSelection(0)
- choice.Show()
-
- sFit.recalc(boostee, withBoosters=True)
- wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFitID))
-
- def fitRenamed(self, event):
- fleetSrv = service.Fleet.getInstance()
- activeFitID = self.mainFrame.getActiveFit()
-
- if activeFitID:
- ev = event
- ev.fitID = activeFitID
- self.fitSelected(ev)
-
- def fitSelected(self, event):
- ''' Fires when active fit is selected and when booster is saved to fit. Update the UI to reflect changes '''
- fleetSrv = service.Fleet.getInstance()
-
- activeFitID = self.mainFrame.getActiveFit()
- sFit = service.Fit.getInstance()
- fit = sFit.getFit(event.fitID or activeFitID)
-
- self.Parent.Parent.DisablePage(self, not fit or fit.isStructure)
-
- commanders = (None, None, None)
-
- if activeFitID:
- commanders = fleetSrv.loadLinearFleet(fit)
-
- for id in self.fleet:
- # try...except here as we're trying 2 different criteria and want to fall back on the same code
- try:
- commander = commanders[id]
-
- if not activeFitID or commander is None:
- raise Exception()
-
- self.fleet[id]['stText'].SetLabel(commander.ship.item.name + ": " + commander.name)
- self.fleet[id]['chChar'].SetStringSelection(commander.character.name if commander.character is not None else "All 0")
- self.fleet[id]['chChar'].Enable()
- self.fleet[id]['chFit'].Hide()
- self.fleet[id]['stText'].Show()
- except:
- #set defaults, disable char selection, and enable fit selection
- self.fleet[id]['stText'].SetLabel("None")
- self.fleet[id]['chChar'].SetStringSelection("All 0")
- self.fleet[id]['chChar'].Disable()
- self.fleet[id]['chFit'].SetSelection(0)
- self.fleet[id]['chFit'].Show()
- self.fleet[id]['stText'].Hide()
-
- if activeFitID:
- self.Enable()
- else:
- self.Disable()
-
- self.Layout()
- self.SendSizeEvent()
-
- def AddCommander(self, fitID, type = None):
- ''' Adds booster to a fit, then recalculates active fit '''
- if type is None:
- return
-
- activeFitID = self.mainFrame.getActiveFit()
- if activeFitID:
- sFit = service.Fit.getInstance()
-
- boostee = sFit.getFit(activeFitID)
- booster = sFit.getFit(fitID)
-
- fleetSrv = service.Fleet.getInstance()
-
- if type == 0: fleetSrv.setLinearFleetCom(boostee, booster)
- if type == 1: fleetSrv.setLinearWingCom(boostee, booster)
- if type == 2: fleetSrv.setLinearSquadCom(boostee, booster)
-
- sFit.recalc(boostee)
- wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFitID))
-
- def RefreshBoosterFits(self, event = None):
- sFit = service.Fit.getInstance()
- sMkt = service.Market.getInstance()
- fitList = sFit.getBoosterFits()
-
- for id in self.fleet:
- choice = self.fleet[id]['chFit']
- chCurrSelection = choice.GetSelection()
- chCurrData = -1
- if chCurrSelection != -1:
- chCurrData = choice.GetClientData(chCurrSelection)
- chCurrSelString = choice.GetString(chCurrSelection)
- choice.Clear()
- currSelFound = False
- choice.Append("None", -1)
- for fit in fitList:
- id,name,type = fit
- ship = sMkt.getItem(type)
- choice.Append(ship.name+': '+name, id)
- if chCurrData == id:
- currSelFound = True
-
- if chCurrSelection == -1:
- choice.SetSelection(0)
- else:
- if currSelFound:
- choice.SetStringSelection(chCurrSelString)
- else:
- choice.SetSelection(0)
-
- def RefreshCharacterList(self, event = None):
- sChar = service.Character.getInstance()
- charList = sChar.getCharacterList()
- for id in self.fleet:
- choice = self.fleet[id]['chChar']
- chCurrSelection = choice.GetSelection()
- chCurrData = -1
- if chCurrSelection != -1:
- chCurrData = choice.GetClientData(chCurrSelection)
- chCurrSelString = choice.GetString(chCurrSelection)
- choice.Clear()
- currSelFound = False
- for char in charList:
- choice.Append(char.name, char.ID)
- if chCurrData == char.ID:
- currSelFound = True
-
- if chCurrSelection == -1:
- choice.SetSelection(1)
- else:
- if currSelFound:
- choice.SetStringSelection(chCurrSelString)
- else:
- choice.SetSelection(1)
-
- def handleDrag(self, type, fitID):
- ''' Handle dragging of fit to fleet interface '''
- #Those are drags coming from pyfa sources, NOT builtin wx drags
- self.draggedFitID = None
- if type == "fit":
- sFit = service.Fit.getInstance()
- fit = sFit.getFit(self.mainFrame.getActiveFit())
-
- if fit and not fit.isStructure:
- self.draggedFitID = fitID
-
- pos = wx.GetMousePosition()
- pos = self.ScreenToClient(pos)
-
- self.PopupMenu(self.FitDNDPopupMenu, pos)
-
-
- def OnPopupItemSelected(self, event):
- ''' Fired when booster popup item is selected '''
- # Get menu selection ID via self.options
- menuItem = event.EventObject.FindItemById(event.GetId())
- type = self.options.index(menuItem.GetText())
-
- if self.draggedFitID:
- sFit = service.Fit.getInstance()
- draggedFit = sFit.getFit(self.draggedFitID)
-
- self.AddCommander(draggedFit.ID, type)
- self.mainFrame.additionsPane.select("Fleet")
-
- def OnFitChoiceSelected(self, event):
- ''' Fired when booster choice is selected '''
- sFit = service.Fit.getInstance()
-
- # set type via choice box used
- chFit = event.GetEventObject()
- fitID = chFit.GetClientData(chFit.GetSelection())
-
- type = -1
- for id in self.fleet:
- if chFit == self.fleet[id]['chFit']: type = id
-
- if type == -1 or fitID == -1:
- event.Skip()
- return
-
- fit = sFit.getFit(fitID)
-
- self.AddCommander(fit.ID, type)
- self.mainFrame.additionsPane.select("Fleet")
diff --git a/gui/mainFrame.py b/gui/mainFrame.py
index 49fb9385a..4c2b350a5 100644
--- a/gui/mainFrame.py
+++ b/gui/mainFrame.py
@@ -55,7 +55,6 @@ from gui.preferenceDialog import PreferenceDialog
from gui.graphFrame import GraphFrame
from gui.copySelectDialog import CopySelectDialog
from gui.utils.clipboard import toClipboard, fromClipboard
-from gui.fleetBrowser import FleetBrowser
from gui.updateDialog import UpdateDialog
from gui.builtinViews import *
@@ -158,12 +157,6 @@ class MainFrame(wx.Frame):
self.shipBrowser = ShipBrowser(self.notebookBrowsers)
self.notebookBrowsers.AddPage(self.shipBrowser, "Fittings", tabImage = shipBrowserImg, showClose = False)
- #=======================================================================
- # DISABLED FOR RC2 RELEASE
- #self.fleetBrowser = FleetBrowser(self.notebookBrowsers)
- #self.notebookBrowsers.AddPage(self.fleetBrowser, "Fleets", showClose = False)
- #=======================================================================
-
self.notebookBrowsers.SetSelection(1)
self.browser_fitting_split.SplitVertically(self.notebookBrowsers, self.fitting_additions_split)
diff --git a/service/__init__.py b/service/__init__.py
index b19c6db17..91ed07d82 100644
--- a/service/__init__.py
+++ b/service/__init__.py
@@ -5,7 +5,6 @@ from service.character import Character
from service.damagePattern import DamagePattern
from service.targetResists import TargetResists
from service.settings import SettingsProvider
-from service.fleet import Fleet
from service.update import Update
from service.price import Price
from service.network import Network
diff --git a/service/character.py b/service/character.py
index 802d11092..d439f1cd4 100644
--- a/service/character.py
+++ b/service/character.py
@@ -34,6 +34,8 @@ import service
import config
import logging
+from eos.saveddata.character import Character as es_Character
+
logger = logging.getLogger(__name__)
class CharacterImportThread(threading.Thread):
@@ -45,6 +47,12 @@ class CharacterImportThread(threading.Thread):
def run(self):
paths = self.paths
sCharacter = Character.getInstance()
+ all5_character = es_Character("All 5", 5)
+ all_skill_ids = []
+ for skill in all5_character.skills:
+ # Parse out the skill item IDs to make searching it easier later on
+ all_skill_ids.append(skill.itemID)
+
for path in paths:
try:
# we try to parse api XML data first
@@ -59,19 +67,28 @@ class CharacterImportThread(threading.Thread):
charFile = open(path, mode='r').read()
doc = minidom.parseString(charFile)
if doc.documentElement.tagName not in ("SerializableCCPCharacter", "SerializableUriCharacter"):
+ logger.error("Incorrect EVEMon XML sheet")
raise RuntimeError("Incorrect EVEMon XML sheet")
name = doc.getElementsByTagName("name")[0].firstChild.nodeValue
skill_els = doc.getElementsByTagName("skill")
skills = []
for skill in skill_els:
- skills.append({
- "typeID": int(skill.getAttribute("typeID")),
- "level": int(skill.getAttribute("level")),
- })
+ if int(skill.getAttribute("typeID")) in all_skill_ids and (0 <= int(skill.getAttribute("level")) <= 5):
+ skills.append({
+ "typeID": int(skill.getAttribute("typeID")),
+ "level": int(skill.getAttribute("level")),
+ })
+ else:
+ logger.error("Attempted to import unknown skill %s (ID: %s) (Level: %s)",
+ skill.getAttribute("name"),
+ skill.getAttribute("typeID"),
+ skill.getAttribute("level"),
+ )
char = sCharacter.new(name+" (EVEMon)")
sCharacter.apiUpdateCharSheet(char.ID, skills)
except Exception, e:
- print e.message
+ logger.error("Exception on character import:")
+ logger.error(e)
continue
wx.CallAfter(self.callback)
@@ -255,8 +272,11 @@ class Character(object):
return char
def rename(self, char, newName):
- char.name = newName
- eos.db.commit()
+ if char.name in ("All 0", "All 5"):
+ logger.info("Cannot rename built in characters.")
+ else:
+ char.name = newName
+ eos.db.commit()
def copy(self, char):
newChar = copy.deepcopy(char)
diff --git a/service/fit.py b/service/fit.py
index 70bc020fc..7382df1fd 100644
--- a/service/fit.py
+++ b/service/fit.py
@@ -34,7 +34,6 @@ from eos.types import State, Slot
from service.market import Market
from service.damagePattern import DamagePattern
from service.character import Character
-from service.fleet import Fleet
from service.settings import SettingsProvider
from service.port import Port
@@ -177,8 +176,6 @@ class Fit(object):
def deleteFit(self, fitID):
fit = eos.db.getFit(fitID)
- sFleet = Fleet.getInstance()
- sFleet.removeAssociatedFleetData(fit)
eos.db.remove(fit)
@@ -229,7 +226,8 @@ class Fit(object):
self.recalc(fit, withBoosters=True)
def getFit(self, fitID, projected=False, basic=False):
- ''' Gets fit from database, and populates fleet data.
+ ''' Gets fit from database
+
Projected is a recursion flag that is set to reduce recursions into projected fits
Basic is a flag to simply return the fit without any other processing
'''
@@ -243,14 +241,6 @@ class Fit(object):
inited = getattr(fit, "inited", None)
if inited is None or inited is False:
- sFleet = Fleet.getInstance()
- f = sFleet.getLinearFleet(fit)
- if f is None:
- sFleet.removeAssociatedFleetData(fit)
- fit.fleet = None
- else:
- fit.fleet = f
-
if not projected:
for fitP in fit.projectedFits:
self.getFit(fitP.ID, projected=True)
diff --git a/service/fleet.py b/service/fleet.py
deleted file mode 100644
index cfad7f04b..000000000
--- a/service/fleet.py
+++ /dev/null
@@ -1,215 +0,0 @@
-#===============================================================================
-# Copyright (C) 2010 Diego Duclos
-#
-# This file is part of pyfa.
-#
-# pyfa is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# pyfa is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with pyfa. If not, see .
-#===============================================================================
-
-import eos.db
-from eos.types import Fleet as Fleet_, Wing, Squad
-import copy
-
-class Fleet(object):
- instance = None
- @classmethod
- def getInstance(cls):
- if cls.instance is None:
- cls.instance = Fleet()
-
- return cls.instance
-
- def __init__(self):
- pass
-
- def getFleetList(self):
- fleetList = []
- fleets = eos.db.getFleetList()
- for fleet in fleets:
- fleetList.append((fleet.ID, fleet.name, fleet.count()))
-
- return fleetList
-
- def getFleetByID(self, ID):
- f = eos.db.getFleet(ID)
- return f
-
- def addFleet(self):
- f = Fleet_()
- eos.db.save(f)
- return f
-
- def renameFleet(self, fleet, newName):
- fleet.name = newName
- eos.db.commit()
-
- def copyFleet(self, fleet):
- newFleet = copy.deepcopy(fleet)
- eos.db.save(newFleet)
- return newFleet
-
- def copyFleetByID(self, ID):
- fleet = self.getFleetByID(ID)
- return self.copyFleet(fleet)
-
- def deleteFleet(self, fleet):
- eos.db.remove(fleet)
-
- def deleteFleetByID(self, ID):
- fleet = self.getFleetByID(ID)
- self.deleteFleet(fleet)
-
- def makeLinearFleet(self, fit):
- f = Fleet_()
- w = Wing()
- f.wings.append(w)
- s = Squad()
- w.squads.append(s)
- s.members.append(fit)
- fit.fleet = f
- eos.db.save(f)
-
- def setLinearFleetCom(self, boostee, booster):
- #if boostee == booster:
- # return
- if self.getLinearFleet(boostee) is None:
- self.removeAssociatedFleetData(boostee)
- self.makeLinearFleet(boostee)
- squadIDs = set(eos.db.getSquadsIDsWithFitID(boostee.ID))
- squad = eos.db.getSquad(squadIDs.pop())
- if squad.wing.gang.leader is not None and booster is None:
- try:
- squad.wing.gang.leader.boostsFits.remove(boostee.ID)
- except KeyError:
- pass
- squad.wing.gang.leader = booster
- if self.anyBoosters(squad) is False:
- self.removeAssociatedFleetData(boostee)
- from service.fit import Fit
- sFit = Fit.getInstance()
- sFit.recalc(boostee, withBoosters=True)
-
- def setLinearWingCom(self, boostee, booster):
- #if boostee == booster:
- # return
- if self.getLinearFleet(boostee) is None:
- self.removeAssociatedFleetData(boostee)
- self.makeLinearFleet(boostee)
- squadIDs = set(eos.db.getSquadsIDsWithFitID(boostee.ID))
- squad = eos.db.getSquad(squadIDs.pop())
- if squad.wing.leader is not None and booster is None:
- try:
- squad.wing.leader.boostsFits.remove(boostee.ID)
- except KeyError:
- pass
- squad.wing.leader = booster
- if self.anyBoosters(squad) is False:
- self.removeAssociatedFleetData(boostee)
- from service.fit import Fit
- sFit = Fit.getInstance()
- sFit.recalc(boostee, withBoosters=True)
-
- def setLinearSquadCom(self, boostee, booster):
- #if boostee == booster:
- # return
- if self.getLinearFleet(boostee) is None:
- self.removeAssociatedFleetData(boostee)
- self.makeLinearFleet(boostee)
- squadIDs = set(eos.db.getSquadsIDsWithFitID(boostee.ID))
- squad = eos.db.getSquad(squadIDs.pop())
- if squad.leader is not None and booster is None:
- try:
- squad.leader.boostsFits.remove(boostee.ID)
- except KeyError:
- pass
- squad.leader = booster
- if self.anyBoosters(squad) is False:
- self.removeAssociatedFleetData(boostee)
- from service.fit import Fit
- sFit = Fit.getInstance()
- sFit.recalc(boostee, withBoosters=True)
-
-
- def getLinearFleet(self, fit):
- sqIDs = eos.db.getSquadsIDsWithFitID(fit.ID)
- if len(sqIDs) != 1:
- return None
- s = eos.db.getSquad(sqIDs[0])
- if len(s.members) != 1:
- return None
- w = s.wing
- if len(w.squads) != 1:
- return None
- f = w.gang
- if len(f.wings) != 1:
- return None
- return f
-
- def removeAssociatedFleetData(self, fit):
- squadIDs = set(eos.db.getSquadsIDsWithFitID(fit.ID))
- if len(squadIDs) == 0:
- return
- squads = list(eos.db.getSquad(sqID) for sqID in squadIDs)
- wingIDs = set(squad.wing.ID for squad in squads)
- fleetIDs = set(squad.wing.gang.ID for squad in squads)
- for fleetID in fleetIDs:
- fleet = eos.db.getFleet(fleetID)
- for wing in fleet.wings:
- wingIDs.add(wing.ID)
- for wingID in wingIDs:
- wing = eos.db.getWing(wingID)
- for squad in wing.squads:
- squadIDs.add(squad.ID)
- for squadID in squadIDs:
- squad = eos.db.getSquad(squadID)
- if squad.leader is not None:
- try:
- squad.leader.boostsFits.remove(fit.ID)
- except KeyError:
- pass
- eos.db.remove(squad)
- for wingID in wingIDs:
- wing = eos.db.getWing(wingID)
- if wing.leader is not None:
- try:
- wing.leader.boostsFits.remove(fit.ID)
- except KeyError:
- pass
- eos.db.remove(wing)
- for fleetID in fleetIDs:
- fleet = eos.db.getFleet(fleetID)
- if fleet.leader is not None:
- try:
- fleet.leader.boostsFits.remove(fit.ID)
- except KeyError:
- pass
- eos.db.remove(fleet)
- fit.fleet = None
- return
-
- def anyBoosters(self, squad):
- wing = squad.wing
- fleet = wing.gang
- if squad.leader is None and wing.leader is None and fleet.leader is None:
- return False
- return True
-
- def loadLinearFleet(self, fit):
- if self.getLinearFleet(fit) is None:
- return None
- squadID = eos.db.getSquadsIDsWithFitID(fit.ID)[0]
- s = eos.db.getSquad(squadID)
- w = s.wing
- f = w.gang
- return (f.leader, w.leader, s.leader)
diff --git a/service/port.py b/service/port.py
index 66e105c06..f0b24306b 100644
--- a/service/port.py
+++ b/service/port.py
@@ -406,7 +406,12 @@ class Port(object):
cargoMap[modName] = 0
cargoMap[modName] += extraAmount
elif item.category.name == "Implant":
- fit.implants.append(Implant(item))
+ if "implantness" in item.attributes:
+ fit.implants.append(Implant(item))
+ elif "boosterness" in item.attributes:
+ fit.boosters.append(Booster(item))
+ else:
+ logger.error("Failed to import implant: %s", line)
# elif item.category.name == "Subsystem":
# try:
# subsystem = Module(item)
diff --git a/service/prefetch.py b/service/prefetch.py
index b16f52d40..6c45ffc63 100644
--- a/service/prefetch.py
+++ b/service/prefetch.py
@@ -23,6 +23,11 @@ import os
import eos.types
import eos.db.migration as migration
from eos.db.saveddata.loadDefaultDatabaseValues import DefaultDatabaseValues
+from eos.db.saveddata.databaseRepair import DatabaseCleanup
+import logging
+
+logger = logging.getLogger(__name__)
+
class PrefetchThread(threading.Thread):
def run(self):
@@ -55,6 +60,14 @@ if os.path.isfile(config.saveDB):
# Import default database values
# Import values that must exist otherwise Pyfa breaks
DefaultDatabaseValues.importRequiredDefaults()
+
+ logging.debug("Starting database validation.")
+ database_cleanup_instance = DatabaseCleanup()
+ database_cleanup_instance.OrphanedCharacterSkills(eos.db.saveddata_engine)
+ database_cleanup_instance.OrphanedFitCharacterIDs(eos.db.saveddata_engine)
+ database_cleanup_instance.OrphanedFitDamagePatterns(eos.db.saveddata_engine)
+ logging.debug("Completed database validation.")
+
else:
# If database does not exist, do not worry about migration. Simply
# create and set version
@@ -67,4 +80,3 @@ else:
DefaultDatabaseValues.importDamageProfileDefaults()
# Import default values for target resist profiles
DefaultDatabaseValues.importResistProfileDefaults()
-