443 lines
16 KiB
Python
443 lines
16 KiB
Python
#===============================================================================
|
|
# Copyright (C) 2010 Diego Duclos
|
|
#
|
|
# This file is part of pyfa.
|
|
#
|
|
# pyfa is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# pyfa is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
|
|
#===============================================================================
|
|
|
|
import wx
|
|
import service
|
|
import config
|
|
from gui import bitmapLoader
|
|
from gui.mainMenuBar import MainMenuBar
|
|
from gui.additionsPane import AdditionsPane
|
|
from gui.marketBrowser import MarketBrowser
|
|
from gui.multiSwitch import MultiSwitch
|
|
from gui.statsPane import StatsPane
|
|
from gui.shipBrowser import ShipBrowser, FitSelected
|
|
from wx.lib.wordwrap import wordwrap
|
|
from gui.characterEditor import CharacterEditor
|
|
from gui.characterSelection import CharacterSelection
|
|
from gui.patternEditor import DmgPatternEditorDlg
|
|
from gui.preferenceDialog import PreferenceDialog
|
|
from gui.graphFrame import GraphFrame
|
|
from gui.copySelectDialog import CopySelectDialog
|
|
import aboutData
|
|
from wx._core import PyDeadObjectError
|
|
import os.path
|
|
import gui.chromeTabs
|
|
from util import toClipboard, fromClipboard
|
|
from builtinViews import *
|
|
from gui.fleetBrowser import FleetBrowser
|
|
|
|
#dummy panel no paint no erasebk
|
|
class PFPanel(wx.Panel):
|
|
def __init__(self,parent):
|
|
wx.Panel.__init__(self,parent)
|
|
self.Bind(wx.EVT_PAINT, self.OnPaint)
|
|
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnBkErase)
|
|
|
|
def OnPaint(self, event):
|
|
event.Skip()
|
|
def OnBkErase(self, event):
|
|
pass
|
|
|
|
class MainFrame(wx.Frame):
|
|
__instance = None
|
|
@classmethod
|
|
def getInstance(cls):
|
|
return cls.__instance if cls.__instance is not None else MainFrame()
|
|
|
|
def __init__(self):
|
|
wx.Frame.__init__(self, None, wx.ID_ANY, title="pyfa - Python Fitting Assistant")
|
|
MainFrame.__instance = self
|
|
|
|
self.LoadMainFrameAttribs()
|
|
|
|
if 'wxMSW' in wx.PlatformInfo:
|
|
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
|
|
|
i = wx.IconFromBitmap(bitmapLoader.getBitmap("pyfa", "icons"))
|
|
self.SetIcon(i)
|
|
|
|
|
|
mainSizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
|
|
self.splitter = wx.SplitterWindow(self, style = wx.SP_LIVE_UPDATE)
|
|
|
|
mainSizer.Add(self.splitter,1,wx.EXPAND | wx.LEFT, 2)
|
|
|
|
self.FitviewAdditionsPanel = PFPanel(self.splitter)
|
|
faSizer = wx.BoxSizer(wx.VERTICAL)
|
|
|
|
self.fitMultiSwitch = MultiSwitch(self.FitviewAdditionsPanel)
|
|
|
|
faSizer.Add(self.fitMultiSwitch,1,wx.EXPAND)
|
|
|
|
self.additionsPane = AdditionsPane(self.FitviewAdditionsPanel)
|
|
faSizer.Add(self.additionsPane, 0, wx.EXPAND)
|
|
|
|
self.FitviewAdditionsPanel.SetSizer(faSizer)
|
|
|
|
|
|
self.notebookBrowsers = gui.chromeTabs.PFNotebook(self.splitter, False)
|
|
|
|
self.marketBrowser = MarketBrowser(self.notebookBrowsers)
|
|
self.notebookBrowsers.AddPage(self.marketBrowser, "Market", showClose = False)
|
|
|
|
self.shipBrowser = ShipBrowser(self.notebookBrowsers)
|
|
self.notebookBrowsers.AddPage(self.shipBrowser, "Ships", showClose = False)
|
|
|
|
self.fleetBrowser = FleetBrowser(self.notebookBrowsers)
|
|
self.notebookBrowsers.AddPage(self.fleetBrowser, "Fleets", showClose = False)
|
|
|
|
self.notebookBrowsers.SetSelection(1)
|
|
|
|
self.splitter.SplitVertically(self.notebookBrowsers, self.FitviewAdditionsPanel)
|
|
self.splitter.SetMinimumPaneSize(200)
|
|
self.splitter.SetSashPosition(300)
|
|
|
|
cstatsSizer = wx.BoxSizer(wx.VERTICAL)
|
|
|
|
self.charSelection = CharacterSelection(self)
|
|
cstatsSizer.Add(self.charSelection, 0, wx.EXPAND)
|
|
|
|
self.statsPane = StatsPane(self)
|
|
cstatsSizer.Add(self.statsPane, 0, wx.EXPAND)
|
|
|
|
mainSizer.Add(cstatsSizer, 0 , wx.EXPAND)
|
|
|
|
self.SetSizer(mainSizer)
|
|
|
|
self.addPageId = wx.NewId()
|
|
self.closePageId = wx.NewId()
|
|
|
|
self.graphFrame = None
|
|
self.statsWnds = []
|
|
self.activeStatsWnd = None
|
|
|
|
#Add menu
|
|
self.SetMenuBar(MainMenuBar())
|
|
#self.SetToolBar(MainToolBar(self))
|
|
|
|
self.registerMenu()
|
|
self.Bind(wx.EVT_CLOSE, self.OnClose)
|
|
#Show ourselves
|
|
self.Show()
|
|
|
|
def LoadMainFrameAttribs(self):
|
|
|
|
mainFrameDefaultAttribs = {"wnd_width":1000, "wnd_height": 700, "wnd_maximized": False}
|
|
self.mainFrameAttribs = service.SettingsProvider.getInstance().getSettings("pyfaMainWindowAttribs", mainFrameDefaultAttribs)
|
|
if self.mainFrameAttribs["wnd_maximized"]:
|
|
width = mainFrameDefaultAttribs["wnd_width"]
|
|
height = mainFrameDefaultAttribs["wnd_height"]
|
|
self.Maximize()
|
|
else:
|
|
width = self.mainFrameAttribs["wnd_width"]
|
|
height = self.mainFrameAttribs["wnd_height"]
|
|
|
|
self.SetSize((width, height))
|
|
self.SetMinSize((mainFrameDefaultAttribs["wnd_width"], mainFrameDefaultAttribs["wnd_height"]))
|
|
|
|
def UpdateMainFrameAttribs(self):
|
|
if self.IsIconized():
|
|
return
|
|
width,height = self.GetSize()
|
|
|
|
self.mainFrameAttribs["wnd_width"] = width
|
|
self.mainFrameAttribs["wnd_height"] = height
|
|
self.mainFrameAttribs["wnd_maximized"] = self.IsMaximized()
|
|
|
|
def SetActiveStatsWindow(self, wnd):
|
|
self.activeStatsWnd = wnd
|
|
|
|
def GetActiveStatsWindow(self):
|
|
|
|
if self.activeStatsWnd in self.statsWnds:
|
|
return self.activeStatsWnd
|
|
|
|
if len(self.statsWnds) > 0:
|
|
return self.statsWnds[len(self.statsWnds) - 1]
|
|
else:
|
|
return None
|
|
|
|
def RegisterStatsWindow(self, wnd):
|
|
self.statsWnds.append(wnd)
|
|
|
|
def UnregisterStatsWindow(self, wnd):
|
|
self.statsWnds.remove(wnd)
|
|
|
|
def getActiveFit(self):
|
|
p = self.fitMultiSwitch.GetSelectedPage()
|
|
m = getattr(p, "getActiveFit", None)
|
|
return m() if m is not None else None
|
|
|
|
def getActiveView(self):
|
|
sel = self.fitMultiSwitch.GetSelectedPage()
|
|
|
|
def CloseCurrentPage(self, evt):
|
|
ms = self.fitMultiSwitch
|
|
|
|
page = ms.GetSelection()
|
|
if page is not None:
|
|
ms.DeletePage(page)
|
|
|
|
def OnClose(self, event):
|
|
self.UpdateMainFrameAttribs()
|
|
service.SettingsProvider.getInstance().saveAll()
|
|
event.Skip()
|
|
|
|
def ExitApp(self, event):
|
|
self.Close()
|
|
event.Skip()
|
|
|
|
def ShowAboutBox(self, evt):
|
|
info = wx.AboutDialogInfo()
|
|
info.Name = "pyfa"
|
|
info.Version = aboutData.versionString
|
|
info.Description = wordwrap(aboutData.description + "\n\n\nDevelopers: " + "".join(aboutData.developers) + "\n\nAdditional credits:\n " + "\n ".join(aboutData.credits) + "\n\nLicense: " + aboutData.license + " - see included " + aboutData.licenseLocation,
|
|
700, wx.ClientDC(self))
|
|
info.WebSite = ("http://www.evefit.org/Pyfa", "pyfa home page")
|
|
wx.AboutBox(info)
|
|
|
|
|
|
def showCharacterEditor(self, event):
|
|
dlg=CharacterEditor(self)
|
|
dlg.Show()
|
|
|
|
def showDamagePatternEditor(self, event):
|
|
dlg=DmgPatternEditorDlg(self)
|
|
dlg.ShowModal()
|
|
dlg.Destroy()
|
|
|
|
def showImportDialog(self, event):
|
|
fits = []
|
|
sFit = service.Fit.getInstance()
|
|
dlg=wx.FileDialog(
|
|
self,
|
|
"Open One Or More Fitting Files",
|
|
wildcard = "EFT text fitting files (*.cfg)|*.cfg|EvE XML fitting files (*.xml)|*.xml|All Files (*)|*",
|
|
style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE)
|
|
if (dlg.ShowModal() == wx.ID_OK):
|
|
try:
|
|
for importPath in dlg.GetPaths():
|
|
fits += sFit.importFit(importPath)
|
|
IDs = sFit.saveImportedFits(fits)
|
|
self._openAfterImport(len(fits), IDs)
|
|
except:
|
|
wx.MessageBox("Error importing from file.", "Error", wx.OK | wx.ICON_ERROR, self)
|
|
dlg.Destroy()
|
|
|
|
def _openAfterImport(self, importCount, fitIDs):
|
|
if importCount == 1:
|
|
if self.getActiveFit() != fitIDs[0]:
|
|
wx.PostEvent(self, FitSelected(fitID=fitIDs[0]))
|
|
self.shipBrowser.RefreshContent()
|
|
def showExportDialog(self, event):
|
|
dlg=wx.FileDialog(
|
|
self,
|
|
"Save Fitting As...",
|
|
wildcard = "EFT text fitting files (*.cfg)|*.cfg|EvE XML fitting files (*.xml)|*.xml",
|
|
style = wx.FD_SAVE)
|
|
if (dlg.ShowModal() == wx.ID_OK):
|
|
sFit = service.Fit.getInstance()
|
|
format = dlg.GetFilterIndex()
|
|
output = ""
|
|
path = dlg.GetPath()
|
|
if (format == 0):
|
|
output = sFit.exportFit(self.getActiveFit())
|
|
if '.' not in os.path.basename(path):
|
|
path += ".cfg"
|
|
elif (format == 1):
|
|
output = sFit.exportXml(self.getActiveFit())
|
|
if '.' not in os.path.basename(path):
|
|
path += ".xml"
|
|
else:
|
|
print "oops, invalid fit format %d" % format
|
|
dlg.Destroy()
|
|
return
|
|
file = open(path, "w")
|
|
file.write(output)
|
|
file.close()
|
|
dlg.Destroy()
|
|
|
|
def showPreferenceDialog(self, event):
|
|
dlg = PreferenceDialog(self)
|
|
dlg.ShowModal()
|
|
dlg.Destroy()
|
|
|
|
def registerMenu(self):
|
|
menuBar = self.GetMenuBar()
|
|
# Quit
|
|
self.Bind(wx.EVT_MENU, self.ExitApp, id=wx.ID_EXIT)
|
|
# Widgets Inspector
|
|
if config.debug:
|
|
self.Bind(wx.EVT_MENU, self.openWXInspectTool, id=911)
|
|
# About
|
|
self.Bind(wx.EVT_MENU, self.ShowAboutBox, id=wx.ID_ABOUT)
|
|
# Char editor
|
|
self.Bind(wx.EVT_MENU, self.showCharacterEditor, id=menuBar.characterEditorId)
|
|
# Damage pattern editor
|
|
self.Bind(wx.EVT_MENU, self.showDamagePatternEditor, id=menuBar.damagePatternEditorId)
|
|
# Import dialog
|
|
self.Bind(wx.EVT_MENU, self.showImportDialog, id=wx.ID_OPEN)
|
|
# Export dialog
|
|
self.Bind(wx.EVT_MENU, self.showExportDialog, id=wx.ID_SAVEAS)
|
|
# Import from Clipboard
|
|
self.Bind(wx.EVT_MENU, self.importFromClipboard, id=wx.ID_PASTE)
|
|
# Backup fits
|
|
self.Bind(wx.EVT_MENU, self.backupToXml, id=menuBar.backupFitsId)
|
|
# Preference dialog
|
|
self.Bind(wx.EVT_MENU, self.showPreferenceDialog, id = menuBar.preferencesId)
|
|
|
|
#Clipboard exports
|
|
self.Bind(wx.EVT_MENU, self.exportToClipboard, id=wx.ID_COPY)
|
|
|
|
#Graphs
|
|
self.Bind(wx.EVT_MENU, self.openGraphFrame, id=menuBar.graphFrameId)
|
|
|
|
toggleShipMarketId = wx.NewId()
|
|
# Close Page
|
|
self.Bind(wx.EVT_MENU, self.CloseCurrentPage, id=self.closePageId)
|
|
self.Bind(wx.EVT_MENU, self.HAddPage, id = self.addPageId)
|
|
self.Bind(wx.EVT_MENU, self.toggleShipMarket, id = toggleShipMarketId)
|
|
|
|
actb = [(wx.ACCEL_CTRL, ord('T'), self.addPageId),
|
|
(wx.ACCEL_CMD, ord('T'), self.addPageId),
|
|
(wx.ACCEL_CTRL, ord("W"), self.closePageId),
|
|
(wx.ACCEL_CMD, ord("W"), self.closePageId),
|
|
(wx.ACCEL_CTRL, ord(" "), toggleShipMarketId),
|
|
(wx.ACCEL_CMD, ord(" "), toggleShipMarketId)]
|
|
atable = wx.AcceleratorTable(actb)
|
|
self.SetAcceleratorTable(atable)
|
|
|
|
|
|
def HAddPage(self,event):
|
|
self.fitMultiSwitch.AddPage(wx.Panel(self, size = (0,0)), "Empty Tab")
|
|
|
|
def toggleShipMarket(self, event):
|
|
sel = self.notebookBrowsers.GetSelection()
|
|
self.notebookBrowsers.SetSelection(0 if sel == 1 else 1)
|
|
|
|
def clipboardEft(self):
|
|
sFit = service.Fit.getInstance()
|
|
toClipboard(sFit.exportFit(self.getActiveFit()))
|
|
|
|
def clipboardDna(self):
|
|
sFit = service.Fit.getInstance()
|
|
toClipboard(sFit.exportDna(self.getActiveFit()))
|
|
|
|
def clipboardXml(self):
|
|
sFit = service.Fit.getInstance()
|
|
toClipboard(sFit.exportXml(self.getActiveFit()))
|
|
|
|
def importFromClipboard(self, event):
|
|
sFit = service.Fit.getInstance()
|
|
try:
|
|
fits = sFit.importFitFromBuffer(fromClipboard())
|
|
IDs = sFit.saveImportedFits(fits)
|
|
self._openAfterImport(len(fits), IDs)
|
|
except:
|
|
pass
|
|
|
|
def exportToClipboard(self, event):
|
|
CopySelectDict = {CopySelectDialog.copyFormatEft: self.clipboardEft,
|
|
CopySelectDialog.copyFormatXml: self.clipboardXml,
|
|
CopySelectDialog.copyFormatDna: self.clipboardDna}
|
|
dlg = CopySelectDialog(self)
|
|
dlg.ShowModal()
|
|
selected = dlg.GetSelected()
|
|
try:
|
|
CopySelectDict[selected]()
|
|
except:
|
|
pass
|
|
dlg.Destroy()
|
|
|
|
def backupToXml(self, event):
|
|
sFit = service.Fit.getInstance()
|
|
saveDialog = wx.FileDialog(
|
|
self,
|
|
"Save Backup As...",
|
|
wildcard = "EvE XML fitting file (*.xml)|*.xml",
|
|
style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
|
|
if (saveDialog.ShowModal() == wx.ID_OK):
|
|
filePath = saveDialog.GetPath()
|
|
if '.' not in os.path.basename(filePath):
|
|
filePath += ".xml"
|
|
self.waitDialog = WaitDialog(self)
|
|
sFit.backupFits(filePath, self.closeWaitDialog)
|
|
self.waitDialog.ShowModal()
|
|
|
|
saveDialog.Destroy()
|
|
|
|
def closeWaitDialog(self):
|
|
if self.waitDialog.timer.IsRunning():
|
|
self.waitDialog.timer.Stop()
|
|
self.waitDialog.Destroy()
|
|
|
|
def openGraphFrame(self, event):
|
|
if not gui.graphFrame.enabled:
|
|
return
|
|
|
|
if not self.graphFrame:
|
|
self.graphFrame = GraphFrame(self)
|
|
self.graphFrame.Show()
|
|
else:
|
|
self.graphFrame.SetFocus()
|
|
|
|
def toggleShipBrowser(self, event):
|
|
self.GetToolBar().toggleShipBrowser(event)
|
|
|
|
def openWXInspectTool(self,event):
|
|
from wx.lib.inspection import InspectionTool
|
|
if not InspectionTool().initialized:
|
|
InspectionTool().Init()
|
|
|
|
# Find a widget to be selected in the tree. Use either the
|
|
# one under the cursor, if any, or this frame.
|
|
wnd = wx.FindWindowAtPointer()
|
|
if not wnd:
|
|
wnd = self
|
|
InspectionTool().Show(wnd, True)
|
|
|
|
class WaitDialog(wx.Dialog):
|
|
def __init__(self, parent):
|
|
wx.Dialog.__init__ (self, parent, id=wx.ID_ANY, title=u"Please wait ...", size=(200,30),
|
|
style=wx.NO_BORDER)
|
|
mainSizer = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
self.progress = wx.Gauge( self, wx.ID_ANY, 100, wx.DefaultPosition, wx.DefaultSize, wx.GA_HORIZONTAL | wx.GA_SMOOTH )
|
|
mainSizer.Add( self.progress, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 0 )
|
|
self.progress.SetRange(20)
|
|
self.progress.SetValue(0)
|
|
self.cycle = 0
|
|
self.SetSizer( mainSizer )
|
|
self.Layout()
|
|
self.timer = wx.Timer(self,wx.ID_ANY)
|
|
self.timer.Start(100)
|
|
self.Bind(wx.EVT_CLOSE,self.OnClose)
|
|
self.Bind(wx.EVT_TIMER,self.OnTimer)
|
|
self.CenterOnParent()
|
|
|
|
def OnTimer(self, event):
|
|
self.cycle += 1
|
|
if self.cycle > self.progress.GetRange():
|
|
self.cycle = 0
|
|
self.progress.SetValue(self.cycle)
|
|
|
|
def OnClose(self, event):
|
|
pass
|