From f53e6f85335606280589e1c75c59c2885bb63fbc Mon Sep 17 00:00:00 2001 From: Martin Falatic Date: Sat, 22 Jun 2013 17:57:23 -0700 Subject: [PATCH] Added the character import enhancement (reads native EVE CCP XML) Character class inherits from 'object' now for consitency (as fit class does) Strings updated for consistency (e.g., 'EvE' -> 'EVE') Minor cleanup of the previous skills exporter enhancement Moved character change/update event bindings to globalEvents (as fit changes are) for better re-use --- config.py | 1 + eos/saveddata/character.py | 3 ++ .../pyfaHTMLExportPreferences.py | 2 +- gui/builtinViews/fittingView.py | 2 +- gui/characterEditor.py | 17 ++++----- gui/characterSelection.py | 2 +- gui/copySelectDialog.py | 6 +-- gui/droneView.py | 2 +- gui/gangView.py | 2 +- gui/globalEvents.py | 4 +- gui/mainFrame.py | 28 ++++++++++++-- gui/mainMenuBar.py | 8 ++-- gui/projectedView.py | 2 +- service/character.py | 37 ++++++++++++++++--- 14 files changed, 84 insertions(+), 32 deletions(-) diff --git a/config.py b/config.py index f7e342c89..f3568ea60 100644 --- a/config.py +++ b/config.py @@ -17,6 +17,7 @@ version = "1.1.15" tag = "git" expansionName = "Odyssey" expansionVersion = "1.0" +evemonMinVersion = "4081" pyfaPath = None savePath = None diff --git a/eos/saveddata/character.py b/eos/saveddata/character.py index f7ebb1ec4..7bc9e189e 100755 --- a/eos/saveddata/character.py +++ b/eos/saveddata/character.py @@ -126,6 +126,9 @@ class Character(object): return sheet = auth.character(charID).CharacterSheet() + apiUpdateCharSheet(sheet) + + def apiUpdateCharSheet(self, sheet): del self.__skills[:] self.__skillIdMap.clear() for skillRow in sheet.skills: diff --git a/gui/builtinPreferenceViews/pyfaHTMLExportPreferences.py b/gui/builtinPreferenceViews/pyfaHTMLExportPreferences.py index 66a6dc2fd..1e9a50bbd 100644 --- a/gui/builtinPreferenceViews/pyfaHTMLExportPreferences.py +++ b/gui/builtinPreferenceViews/pyfaHTMLExportPreferences.py @@ -42,7 +42,7 @@ The file will be updated every time a fit changes or gets added. self.PathLinkCtrl = wx.HyperlinkCtrl( panel, wx.ID_ANY, str(self.HTMLExportSettings.getPath()), 'file:///' + str(self.HTMLExportSettings.getPath()), wx.DefaultPosition, wx.DefaultSize, wx.HL_ALIGN_LEFT|wx.NO_BORDER|wx.HL_CONTEXTMENU ) mainSizer.Add( self.PathLinkCtrl, 0, wx.ALL|wx.EXPAND, 5) - self.fileSelectDialog = wx.FileDialog(None, "Save Fitting As...", wildcard = "EvE IGB HTML fitting file (*.html)|*.html", style = wx.FD_SAVE) + self.fileSelectDialog = wx.FileDialog(None, "Save Fitting As...", wildcard = "EVE IGB HTML fitting file (*.html)|*.html", style = wx.FD_SAVE) self.fileSelectDialog.SetPath(self.HTMLExportSettings.getPath()) self.fileSelectDialog.SetFilename(os.path.basename(self.HTMLExportSettings.getPath())); diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index eedaddc03..23e06cf23 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -90,7 +90,7 @@ class FittingViewDrop(wx.PyDropTarget): def __init__(self, dropFn): wx.PyDropTarget.__init__(self) self.dropFn = dropFn - # this is really transferring an EvE itemID + # this is really transferring an EVE itemID self.dropData = wx.PyTextDataObject() self.SetDataObject(self.dropData) diff --git a/gui/characterEditor.py b/gui/characterEditor.py index 92116d67f..d0102a24a 100644 --- a/gui/characterEditor.py +++ b/gui/characterEditor.py @@ -30,9 +30,6 @@ from wx.lib.buttons import GenBitmapButton import sys import gui.globalEvents as GE -CharListUpdated, CHAR_LIST_UPDATED = wx.lib.newevent.NewEvent() -CharChanged, CHAR_CHANGED = wx.lib.newevent.NewEvent() - class CharacterEditor(wx.Frame): def __init__(self, parent): wx.Frame.__init__ (self, parent, id=wx.ID_ANY, title=u"pyfa: Character Editor", pos=wx.DefaultPosition, @@ -136,7 +133,7 @@ class CharacterEditor(wx.Frame): def editingFinished(self, event): del self.disableWin - wx.PostEvent(self.mainFrame, CharListUpdated()) + wx.PostEvent(self.mainFrame, GE.CharListUpdated()) self.Destroy() def registerEvents(self): @@ -145,7 +142,7 @@ class CharacterEditor(wx.Frame): def closeEvent(self, event): del self.disableWin - wx.PostEvent(self.mainFrame, CharListUpdated()) + wx.PostEvent(self.mainFrame, GE.CharListUpdated()) self.Destroy() def restrict(self): @@ -182,7 +179,7 @@ class CharacterEditor(wx.Frame): else: self.unrestrict() - wx.PostEvent(self, CharChanged()) + wx.PostEvent(self, GE.CharChanged()) if event is not None: event.Skip() @@ -253,7 +250,7 @@ class CharacterEditor(wx.Frame): self.unrestrict() self.btnSave.SetLabel("Copy") self.rename(None) - wx.PostEvent(self, CharChanged()) + wx.PostEvent(self, GE.CharChanged()) def delete(self, event): cChar = service.Character.getInstance() @@ -265,7 +262,7 @@ class CharacterEditor(wx.Frame): if cChar.getCharName(newSelection) in ("All 0", "All 5"): self.restrict() - wx.PostEvent(self, CharChanged()) + wx.PostEvent(self, GE.CharChanged()) def Destroy(self): cFit = service.Fit.getInstance() @@ -452,7 +449,7 @@ class ImplantsTreeView (wx.Panel): self.btnRemove.Bind(wx.EVT_BUTTON, self.removeImplant) #Bind the change of a character* - self.Parent.Parent.Bind(CHAR_CHANGED, self.charChanged) + self.Parent.Parent.Bind(GE.CHAR_CHANGED, self.charChanged) self.Enable(False) self.Layout() @@ -537,7 +534,7 @@ class AvailableImplantsView(d.Display): class APIView (wx.Panel): def __init__(self, parent): wx.Panel.__init__ (self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(500, 300), style=wx.TAB_TRAVERSAL) - self.Parent.Parent.Bind(CHAR_CHANGED, self.charChanged) + self.Parent.Parent.Bind(GE.CHAR_CHANGED, self.charChanged) self.apiUrlCreatePredefined = u"https://community.eveonline.com/support/api-key/update/" self.apiUrlKeyList = u"https://community.eveonline.com/support/api-key/" diff --git a/gui/characterSelection.py b/gui/characterSelection.py index 3d20d5589..340994501 100644 --- a/gui/characterSelection.py +++ b/gui/characterSelection.py @@ -48,7 +48,7 @@ class CharacterSelection(wx.Panel): self.skillReqsStaticBitmap.SetBitmap(self.cleanSkills) self.Bind(wx.EVT_CHOICE, self.charChanged) - self.mainFrame.Bind(ce.CHAR_LIST_UPDATED, self.refreshCharacterList) + self.mainFrame.Bind(GE.CHAR_LIST_UPDATED, self.refreshCharacterList) self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) # panelSize = wx.Size(-1,30) diff --git a/gui/copySelectDialog.py b/gui/copySelectDialog.py index d14a5ebb0..0faf850cb 100644 --- a/gui/copySelectDialog.py +++ b/gui/copySelectDialog.py @@ -31,9 +31,9 @@ class CopySelectDialog(wx.Dialog): mainSizer = wx.BoxSizer(wx.VERTICAL) copyFormats = [u"EFT", u"EFT (Implants)", u"XML", u"DNA"] - copyFormatTooltips = {CopySelectDialog.copyFormatEft: u"Eve Fitting Tool text format", - CopySelectDialog.copyFormatEftImps: u"Eve Fitting Tool text format", - CopySelectDialog.copyFormatXml: u"EvE native XML format", + copyFormatTooltips = {CopySelectDialog.copyFormatEft: u"EFT text format", + CopySelectDialog.copyFormatEftImps: u"EFT text format", + CopySelectDialog.copyFormatXml: u"EVE native XML format", CopySelectDialog.copyFormatDna: u"A one-line text format"} selector = wx.RadioBox(self, wx.ID_ANY, label = u"Copy to the clipboard using:", choices = copyFormats, style = wx.RA_SPECIFY_ROWS) selector.Bind(wx.EVT_RADIOBOX, self.Selected) diff --git a/gui/droneView.py b/gui/droneView.py index 934e8869f..c063aba42 100644 --- a/gui/droneView.py +++ b/gui/droneView.py @@ -30,7 +30,7 @@ class DroneViewDrop(wx.PyDropTarget): def __init__(self, dropFn): wx.PyDropTarget.__init__(self) self.dropFn = dropFn - # this is really transferring an EvE itemID + # this is really transferring an EVE itemID self.dropData = wx.PyTextDataObject() self.SetDataObject(self.dropData) diff --git a/gui/gangView.py b/gui/gangView.py index 20c266356..88080a56f 100644 --- a/gui/gangView.py +++ b/gui/gangView.py @@ -137,7 +137,7 @@ class GangView ( ScrolledPanel ): self.SetupScrolling() self.Disable() - self.mainFrame.Bind(CharEditor.CHAR_LIST_UPDATED, self.RefreshCharacterList) + 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) diff --git a/gui/globalEvents.py b/gui/globalEvents.py index a0d4bedad..afb2d7bb3 100644 --- a/gui/globalEvents.py +++ b/gui/globalEvents.py @@ -1,3 +1,5 @@ import wx.lib.newevent -FitChanged, FIT_CHANGED = wx.lib.newevent.NewEvent() \ No newline at end of file +FitChanged, FIT_CHANGED = wx.lib.newevent.NewEvent() +CharListUpdated, CHAR_LIST_UPDATED = wx.lib.newevent.NewEvent() +CharChanged, CHAR_CHANGED = wx.lib.newevent.NewEvent() diff --git a/gui/mainFrame.py b/gui/mainFrame.py index bdd29fe2e..069167fea 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -32,6 +32,7 @@ import config import gui.aboutData import gui.chromeTabs import gui.utils.animUtils as animUtils +import gui.globalEvents as GE from gui import bitmapLoader from gui.mainMenuBar import MainMenuBar @@ -264,7 +265,7 @@ class MainFrame(wx.Frame): self, "Open One Or More Fitting Files", wildcard = "EFT text fitting files (*.cfg)|*.cfg|" \ - "EvE XML fitting files (*.xml)|*.xml|" \ + "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): @@ -273,7 +274,6 @@ class MainFrame(wx.Frame): dlg.Destroy() self.waitDialog.ShowModal() - def importCallback(self, fits): self.waitDialog.Destroy() sFit = service.Fit.getInstance() @@ -291,7 +291,7 @@ class MainFrame(wx.Frame): dlg=wx.FileDialog( self, "Save Fitting As...", - wildcard = "EvE XML fitting files (*.xml)|*.xml", + wildcard = "EVE XML fitting files (*.xml)|*.xml", style = wx.FD_SAVE) if (dlg.ShowModal() == wx.ID_OK): sFit = service.Fit.getInstance() @@ -339,6 +339,8 @@ class MainFrame(wx.Frame): self.Bind(wx.EVT_MENU, self.backupToXml, id=menuBar.backupFitsId) # Export skills needed self.Bind(wx.EVT_MENU, self.exportSkillsNeeded, id=menuBar.exportSkillsNeededId) + # Import character + self.Bind(wx.EVT_MENU, self.importCharacter, id=menuBar.importCharacterId) # Preference dialog self.Bind(wx.EVT_MENU, self.showPreferenceDialog, id = menuBar.preferencesId) @@ -467,7 +469,7 @@ class MainFrame(wx.Frame): saveDialog = wx.FileDialog( self, "Save Backup As...", - wildcard = "EvE XML fitting file (*.xml)|*.xml", + wildcard = "EVE XML fitting file (*.xml)|*.xml", style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) if (saveDialog.ShowModal() == wx.ID_OK): filePath = saveDialog.GetPath() @@ -504,6 +506,24 @@ class MainFrame(wx.Frame): saveDialog.Destroy() + def importCharacter(self, event): + sCharacter = service.Character.getInstance() + dlg=wx.FileDialog( + self, + "Open One Or More Character Files", + wildcard = "EVE CCP API XML character 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 Character") + sCharacter.importCharacter(dlg.GetPaths(), self.importCharacterCallback) + dlg.Destroy() + self.waitDialog.ShowModal() + + def importCharacterCallback(self): + self.waitDialog.Destroy() + wx.PostEvent(self, GE.CharListUpdated()) + def closeWaitDialog(self): self.waitDialog.Destroy() diff --git a/gui/mainMenuBar.py b/gui/mainMenuBar.py index 327bc0e60..cf0583dac 100644 --- a/gui/mainMenuBar.py +++ b/gui/mainMenuBar.py @@ -31,6 +31,7 @@ class MainMenuBar(wx.MenuBar): self.graphFrameId = wx.NewId() self.backupFitsId = wx.NewId() self.exportSkillsNeededId = wx.NewId() + self.importCharacterId = wx.NewId() self.preferencesId = wx.NewId() self.mainFrame = gui.mainFrame.MainFrame.getInstance() @@ -45,10 +46,11 @@ class MainMenuBar(wx.MenuBar): fileMenu.Append(self.mainFrame.closePageId, "&Close Tab\tCTRL+W", "Close the current fit") fileMenu.AppendSeparator() - 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.backupFitsId, "&Backup All Fittings", "Backup all fittings to a XML file") + fileMenu.Append(wx.ID_OPEN, "&Import Fittings\tCTRL+O", "Import fittings into pyfa") + fileMenu.Append(wx.ID_SAVEAS, "&Export Fitting\tCTRL+S", "Export fitting to another format") fileMenu.Append(self.exportSkillsNeededId, "Export &Skills Needed", "Export skills needed for this fitting") + fileMenu.Append(self.importCharacterId, "Import C&haracters", "Import characters into pyfa") fileMenu.AppendSeparator() fileMenu.Append(wx.ID_EXIT) diff --git a/gui/projectedView.py b/gui/projectedView.py index d380a5a97..87851e396 100644 --- a/gui/projectedView.py +++ b/gui/projectedView.py @@ -31,7 +31,7 @@ class ProjectedViewDrop(wx.PyDropTarget): def __init__(self, dropFn): wx.PyDropTarget.__init__(self) self.dropFn = dropFn - # this is really transferring an EvE itemID + # this is really transferring an EVE itemID self.dropData = wx.PyTextDataObject() self.SetDataObject(self.dropData) diff --git a/service/character.py b/service/character.py index 97c55ec0a..3f2942a5e 100644 --- a/service/character.py +++ b/service/character.py @@ -22,6 +22,8 @@ import eos.types import copy import service import itertools +from eos import eveapi +import config import os.path import locale @@ -34,7 +36,23 @@ from xml.dom import minidom import gzip -EVEMON_COMPATIBLE_VERSION = "4081" +class CharacterImportThread(threading.Thread): + def __init__(self, paths, callback): + threading.Thread.__init__(self) + self.paths = paths + self.callback = callback + + def run(self): + paths = self.paths + sCharacter = Character.getInstance() + for path in paths: + with open(path, mode='r') as charFile: + sheet = eveapi.ParseXML(charFile) + charID = sCharacter.new() + sCharacter.rename(charID, sheet.name+" (imported)") + sCharacter.apiUpdateCharSheet(charID, sheet) + + wx.CallAfter(self.callback) class SkillBackupThread(threading.Thread): def __init__(self, path, saveFmt, activeFit, callback): @@ -56,15 +74,15 @@ class SkillBackupThread(threading.Thread): backupData = sCharacter.exportText() if self.saveFmt == "emp": - with gzip.open(path, "wb") as backupFile: + with gzip.open(path, mode='wb') as backupFile: backupFile.write(backupData) else: - with open(path, "w", encoding="utf-8") as backupFile: + with open(path, mode='w',encoding='utf-8') as backupFile: backupFile.write(backupData) wx.CallAfter(self.callback) -class Character(): +class Character(object): instance = None skillReqsDict = {} @@ -93,7 +111,7 @@ class Character(): def exportXml(self): root = ElementTree.Element("plan") root.attrib["name"] = "Pyfa exported plan for "+self.skillReqsDict['charname'] - root.attrib["revision"] = EVEMON_COMPATIBLE_VERSION + root.attrib["revision"] = config.evemonMinVersion sorts = ElementTree.SubElement(root, "sorting") sorts.attrib["criteria"] = "None" @@ -127,6 +145,10 @@ class Character(): thread = SkillBackupThread(path, saveFmt, activeFit, callback) thread.start() + def importCharacter(self, path, callback): + thread = CharacterImportThread(path, callback) + thread.start() + def all0(self): all0 = eos.types.Character.getAll0() eos.db.commit() @@ -222,6 +244,11 @@ class Character(): char.apiFetch(charName, proxy = service.settings.ProxySettings.getInstance().getProxySettings()) eos.db.commit() + def apiUpdateCharSheet(self, charID, sheet): + char = eos.db.getCharacter(charID) + char.apiUpdateCharSheet(sheet) + eos.db.commit() + def changeLevel(self, charID, skillID, level): char = eos.db.getCharacter(charID) skill = char.getSkill(skillID)