Merge pull request #1 from MartyMacGyver/add_skills_exporter

Added an exporter for skills required for a given fit
This commit is contained in:
Anton Vorobyov
2013-07-01 09:17:46 -07:00
4 changed files with 149 additions and 12 deletions

View File

@@ -109,7 +109,6 @@ class CharacterSelection(wx.Panel):
def fitChanged(self, event):
self.charChoice.Enable(event.fitID != None)
choice = self.charChoice
cFit = service.Fit.getInstance()
currCharID = choice.GetClientData(choice.GetCurrentSelection())
@@ -117,15 +116,17 @@ class CharacterSelection(wx.Panel):
newCharID = fit.character.ID if fit is not None else None
if event.fitID is None:
self.skillReqsStaticBitmap.SetBitmap(self.cleanSkills)
self.skillReqsStaticBitmap.SetToolTipString("No active fit.")
self.skillReqsStaticBitmap.SetToolTipString("No active fit")
else:
sCharacter = service.Character.getInstance()
reqs = sCharacter.checkRequirements(fit)
sCharacter.skillReqsDict = {'charname':fit.character.name, 'skills':[]}
if len(reqs) == 0:
tip = "All prerequisites have been met"
tip = "All skill prerequisites have been met"
self.skillReqsStaticBitmap.SetBitmap(self.greenSkills)
else:
tip = self._buildSkillsTooltip(reqs)
tip = "Skills required:\n"
tip += self._buildSkillsTooltip(reqs)
self.skillReqsStaticBitmap.SetBitmap(self.redSkills)
self.skillReqsStaticBitmap.SetToolTipString(tip.strip())
@@ -137,16 +138,24 @@ class CharacterSelection(wx.Panel):
event.Skip()
def _buildSkillsTooltip(self, reqs, tabulationLevel = 0):
def _buildSkillsTooltip(self, reqs, currItem = "", tabulationLevel = 0):
tip = ""
sCharacter = service.Character.getInstance()
if tabulationLevel == 0:
for item, subReqs in reqs.iteritems():
tip += "%s:\n" % item.name
tip += self._buildSkillsTooltip(subReqs, 1)
tip += " %s:\n" % item.name
tip += self._buildSkillsTooltip(subReqs, item.name, 1)
else:
for name, info in reqs.iteritems():
level, more = info
tip += "%s%s: %d\n" % (" " * tabulationLevel, name, level)
tip += self._buildSkillsTooltip(more, tabulationLevel + 1)
level, ID, more = info
sCharacter.skillReqsDict['skills'].append({
'item' : currItem,
'skillID' : ID,
'skill' : name,
'level' : level,
'indent' : tabulationLevel
})
tip += " %s%s: %d\n" % (" " * tabulationLevel, name, level)
tip += self._buildSkillsTooltip(more, currItem, tabulationLevel + 1)
return tip

View File

@@ -263,7 +263,9 @@ class MainFrame(wx.Frame):
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 (*)|*",
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):
self.waitDialog = animUtils.WaitDialog(self, title = "Importing")
@@ -335,6 +337,8 @@ class MainFrame(wx.Frame):
self.Bind(wx.EVT_MENU, self.importFromClipboard, id=wx.ID_PASTE)
# Backup fits
self.Bind(wx.EVT_MENU, self.backupToXml, id=menuBar.backupFitsId)
# Export skills needed
self.Bind(wx.EVT_MENU, self.exportSkillsNeeded, id=menuBar.exportSkillsNeededId)
# Preference dialog
self.Bind(wx.EVT_MENU, self.showPreferenceDialog, id = menuBar.preferencesId)
@@ -475,6 +479,31 @@ class MainFrame(wx.Frame):
saveDialog.Destroy()
def exportSkillsNeeded(self, event):
sCharacter = service.Character.getInstance()
saveDialog = wx.FileDialog(
self,
"Export Skills Needed As...",
wildcard = "EVEMon skills training file (*.emp)|*.emp|" \
"EVEMon skills training XML file (*.xml)|*.xml|" \
"Text skills training file (*.txt)|*.txt",
style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
if (saveDialog.ShowModal() == wx.ID_OK):
saveFmtInt = saveDialog.GetFilterIndex()
saveFmt = ""
if saveFmtInt == 0: # Per ordering of wildcards above
saveFmt = "emp"
elif saveFmtInt == 1:
saveFmt = "xml"
else:
saveFmt = "txt"
filePath = saveDialog.GetPath()
self.waitDialog = animUtils.WaitDialog(self)
sCharacter.backupSkills(filePath, saveFmt, self.getActiveFit(), self.closeWaitDialog)
self.waitDialog.ShowModal()
saveDialog.Destroy()
def closeWaitDialog(self):
self.waitDialog.Destroy()

View File

@@ -30,6 +30,7 @@ class MainMenuBar(wx.MenuBar):
self.damagePatternEditorId = wx.NewId()
self.graphFrameId = wx.NewId()
self.backupFitsId = wx.NewId()
self.exportSkillsNeededId = wx.NewId()
self.preferencesId = wx.NewId()
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
@@ -47,6 +48,7 @@ class MainMenuBar(wx.MenuBar):
fileMenu.Append(self.backupFitsId, "&Backup fits", "Backup all fittings to a XML file")
fileMenu.Append(wx.ID_OPEN, "&Import\tCTRL+O", "Import a fit into pyfa.")
fileMenu.Append(wx.ID_SAVEAS, "&Export\tCTRL+S", "Export the fit to another format.")
fileMenu.Append(self.exportSkillsNeededId, "Export &Skills Needed", "Export skills needed for this fitting")
fileMenu.AppendSeparator()
fileMenu.Append(wx.ID_EXIT)
@@ -105,5 +107,6 @@ class MainMenuBar(wx.MenuBar):
enable = event.fitID is not None
self.Enable(wx.ID_SAVEAS, enable)
self.Enable(wx.ID_COPY, enable)
self.Enable(self.exportSkillsNeededId, enable)
event.Skip()

View File

@@ -23,8 +23,51 @@ import copy
import service
import itertools
import os.path
import locale
import threading
import wx
from codecs import open
from xml.etree import ElementTree
from xml.dom import minidom
import gzip
EVEMON_COMPATIBLE_VERSION = "4081"
class SkillBackupThread(threading.Thread):
def __init__(self, path, saveFmt, activeFit, callback):
threading.Thread.__init__(self)
self.path = path
self.saveFmt = saveFmt
self.activeFit = activeFit
self.callback = callback
def run(self):
path = self.path
sCharacter = Character.getInstance()
sFit = service.Fit.getInstance()
fit = sFit.getFit(self.activeFit)
backupData = "";
if self.saveFmt == "xml" or self.saveFmt == "emp":
backupData = sCharacter.exportXml()
else:
backupData = sCharacter.exportText()
if self.saveFmt == "emp":
with gzip.open(path, "wb") as backupFile:
backupFile.write(backupData)
else:
with open(path, "w", encoding="utf-8") as backupFile:
backupFile.write(backupData)
wx.CallAfter(self.callback)
class Character():
instance = None
skillReqsDict = {}
@classmethod
def getInstance(cls):
if cls.instance is None:
@@ -32,6 +75,58 @@ class Character():
return cls.instance
def exportText(self):
data = "Pyfa exported plan for \""+self.skillReqsDict['charname']+"\"\n"
data += "=" * 79 + "\n"
data += "\n"
item = ""
for s in self.skillReqsDict['skills']:
if item == "" or not item == s["item"]:
item = s["item"]
data += "-" * 79 + "\n"
data += "Skills required for {}:\n".format(item)
data += "{}{}: {}\n".format(" " * s["indent"], s["skill"], int(s["level"]))
data += "-" * 79 + "\n"
return data
def exportXml(self):
root = ElementTree.Element("plan")
root.attrib["name"] = "Pyfa exported plan for "+self.skillReqsDict['charname']
root.attrib["revision"] = EVEMON_COMPATIBLE_VERSION
sorts = ElementTree.SubElement(root, "sorting")
sorts.attrib["criteria"] = "None"
sorts.attrib["order"] = "None"
sorts.attrib["groupByPriority"] = "false"
skillsSeen = set()
for s in self.skillReqsDict['skills']:
skillKey = str(s["skillID"])+"::"+s["skill"]+"::"+str(int(s["level"]))
if skillKey in skillsSeen:
pass # Duplicate skills confuse EVEMon
else:
skillsSeen.add(skillKey)
entry = ElementTree.SubElement(root, "entry")
entry.attrib["skillID"] = str(s["skillID"])
entry.attrib["skill"] = s["skill"]
entry.attrib["level"] = str(int(s["level"]))
entry.attrib["priority"] = "3"
entry.attrib["type"] = "Prerequisite"
notes = ElementTree.SubElement(entry, "notes")
notes.text = entry.attrib["skill"]
tree = ElementTree.ElementTree(root)
data = ElementTree.tostring(root, 'utf-8')
prettydata = minidom.parseString(data).toprettyxml(indent=" ")
return prettydata
def backupSkills(self, path, saveFmt, activeFit, callback):
thread = SkillBackupThread(path, saveFmt, activeFit, callback)
thread.start()
def all0(self):
all0 = eos.types.Character.getAll0()
eos.db.commit()
@@ -169,10 +264,11 @@ class Character():
def _checkRequirements(self, fit, char, subThing, reqs):
for req, level in subThing.requiredSkills.iteritems():
name = req.name
ID = req.ID
info = reqs.get(name)
currLevel, subs = info if info is not None else 0, {}
if level > currLevel and (char is None or char.getSkill(req).level < level):
reqs[name] = (level, subs)
reqs[name] = (level, ID, subs)
self._checkRequirements(fit, char, req, subs)
return reqs