From 6e54d6788cd4784c5d6b76c26a2ec243e4c87cad Mon Sep 17 00:00:00 2001 From: Ebag333 Date: Thu, 15 Sep 2016 15:27:10 -0700 Subject: [PATCH] Revert "Purging fleet bonuses from code base" This reverts commit 68f45706ab7dc9c2e68a3f9d868b37b1ce56decc. --- eos/db/saveddata/fleet.py | 48 +++- eos/db/saveddata/queries.py | 58 +++++ eos/types.py | 1 + gui/additionsPane.py | 7 +- gui/builtinViews/fleetView.py | 141 ++++++++++- gui/fleetBrowser.py | 457 +++++++++++++++++++++++++++++++++- gui/gangView.py | 394 ++++++++++++++++++++++++++++- gui/mainFrame.py | 7 + service/__init__.py | 1 + service/fit.py | 13 +- service/fleet.py | 197 ++++++++++++++- 11 files changed, 1317 insertions(+), 7 deletions(-) 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)