diff --git a/eos/db/saveddata/fleet.py b/eos/db/saveddata/fleet.py
index 0583b43b0..8f0e6736b 100644
--- a/eos/db/saveddata/fleet.py
+++ b/eos/db/saveddata/fleet.py
@@ -17,4 +17,50 @@
# along with eos. If not, see .
#===============================================================================
-#Purging fleet
\ No newline at end of file
+from sqlalchemy import Table, Column, Integer, ForeignKey, String
+from sqlalchemy.orm import mapper, relation
+
+from eos.db import saveddata_meta
+from eos.types import Fleet, Wing, Squad, Fit
+from eos.db.saveddata.fit import fits_table
+
+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 cb3033cc1..5a6dd1bfc 100644
--- a/eos/db/saveddata/queries.py
+++ b/eos/db/saveddata/queries.py
@@ -21,6 +21,7 @@ from eos.db.util import processEager, processWhere
from eos.db import saveddata_session, sd_lock
from eos.types import *
+from eos.db.saveddata.fleet import squadmembers_table
from eos.db.saveddata.fit import projectedFits_table
from sqlalchemy.sql import and_
import eos.config
@@ -193,6 +194,48 @@ 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.
@@ -265,6 +308,12 @@ 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):
@@ -374,6 +423,15 @@ 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/types.py b/eos/types.py
index f2550ad31..12e7eb281 100644
--- a/eos/types.py
+++ b/eos/types.py
@@ -38,6 +38,7 @@ from eos.saveddata.booster import SideEffect
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 f1ca44be4..8c855dc95 100644
--- a/gui/additionsPane.py
+++ b/gui/additionsPane.py
@@ -26,6 +26,7 @@ from gui.cargoView import CargoView
from gui.implantView import ImplantView
from gui.projectedView import ProjectedView
from gui.pyfatogglepanel import TogglePanel
+from gui.gangView import GangView
from gui.bitmapLoader import BitmapLoader
import gui.chromeTabs
@@ -54,6 +55,7 @@ class AdditionsPane(TogglePanel):
implantImg = BitmapLoader.getImage("implant_small", "gui")
boosterImg = BitmapLoader.getImage("booster_small", "gui")
projectedImg = BitmapLoader.getImage("projected_small", "gui")
+ gangImg = BitmapLoader.getImage("fleet_fc_small", "gui")
cargoImg = BitmapLoader.getImage("cargo_small", "gui")
self.drone = DroneView(self.notebook)
@@ -74,9 +76,12 @@ class AdditionsPane(TogglePanel):
self.projectedPage = ProjectedView(self.notebook)
self.notebook.AddPage(self.projectedPage, "Projected", tabImage = projectedImg, showClose = False)
+ self.gangPage = GangView(self.notebook)
+ self.notebook.AddPage(self.gangPage, "Fleet", tabImage = gangImg, showClose = False)
+
self.notebook.SetSelection(0)
- PANES = ["Drones", "Fighters", "Cargo", "Implants", "Boosters", "Projected"]
+ PANES = ["Drones", "Fighters", "Cargo", "Implants", "Boosters", "Projected", "Fleet"]
def select(self, name):
self.notebook.SetSelection(self.PANES.index(name))
diff --git a/gui/builtinViews/fleetView.py b/gui/builtinViews/fleetView.py
index 9058bc35f..bc6eef9a2 100644
--- a/gui/builtinViews/fleetView.py
+++ b/gui/builtinViews/fleetView.py
@@ -1 +1,140 @@
-#Purge fleet boosts
\ No newline at end of file
+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
index bb28be251..7476d7d7f 100644
--- a/gui/fleetBrowser.py
+++ b/gui/fleetBrowser.py
@@ -1 +1,456 @@
-# purging fleet
\ No newline at end of file
+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
index d5f8e43cb..106f14f98 100644
--- a/gui/gangView.py
+++ b/gui/gangView.py
@@ -16,5 +16,397 @@
# 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
-#Purging fleet boosts
\ No newline at end of file
+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 220a8f0ab..c209a0422 100644
--- a/gui/mainFrame.py
+++ b/gui/mainFrame.py
@@ -55,6 +55,7 @@ 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 *
@@ -157,6 +158,12 @@ 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 91ed07d82..b19c6db17 100644
--- a/service/__init__.py
+++ b/service/__init__.py
@@ -5,6 +5,7 @@ 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/fit.py b/service/fit.py
index d05865514..455e76463 100644
--- a/service/fit.py
+++ b/service/fit.py
@@ -34,6 +34,7 @@ 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
@@ -183,6 +184,8 @@ class Fit(object):
def deleteFit(self, fitID):
fit = eos.db.getFit(fitID)
+ sFleet = Fleet.getInstance()
+ sFleet.removeAssociatedFleetData(fit)
eos.db.remove(fit)
@@ -233,7 +236,7 @@ class Fit(object):
self.recalc(fit, withBoosters=True)
def getFit(self, fitID, projected=False, basic=False):
- ''' Gets fit from database.
+ ''' Gets fit from database, and populates fleet data.
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
@@ -248,6 +251,14 @@ 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
index 3a158cb2d..cfad7f04b 100644
--- a/service/fleet.py
+++ b/service/fleet.py
@@ -17,4 +17,199 @@
# along with pyfa. If not, see .
#===============================================================================
-#Purge fleet boosts
+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)