NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

export.py (59302B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\export.py
      2 import codecs
      3 import operator
      4 import os
      5 import sys
      6 import yaml
      7 from player_messaging.client.ui_message import prompt_player_fsd_dialog
      8 from xml.dom.minidom import getDOMImplementation, parse
      9 import blue
     10 import evetypes
     11 import localization
     12 import utillib
     13 from carbon.common.script.util.commonutils import StripTags
     14 from carbonui import uiconst
     15 from carbonui.control.combo import Combo
     16 from carbonui.control.singlelineedits.singleLineEditText import SingleLineEditText
     17 from carbonui.primitives.container import Container
     18 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     19 from carbonui.util.stringManip import SanitizeFilename
     20 import overviewPresets.overviewSettingsConst as osConst
     21 from carbonui.button.group import ButtonGroup
     22 from eve.client.script.ui.control.entries.checkbox import CheckboxEntry
     23 from eve.client.script.ui.control.entries.generic import Generic
     24 from eve.client.script.ui.control.entries.util import GetFromClass
     25 from eve.client.script.ui.control.listgroup import ListGroup
     26 from carbonui.control.button import Button
     27 from carbonui.control.checkbox import Checkbox
     28 from carbonui.control.window import Window
     29 from eve.client.script.ui.control import eveLabel, eveScroll
     30 from eve.client.script.ui.control.draggableShareContainer import DraggableShareContainer
     31 from eveexceptions import UserError
     32 from inventorycommon.util import IsShipFittable, IsSubsystemFlag, IsSubsystemFlagVisible
     33 from overviewPresets import overviewSettingsConst
     34 from overviewPresets.overviewPresetUtil import GetDeterministicListFromDict, GetDictFromList, ReplaceInnerListsWithDicts
     35 from overviewPresets.overviewSettingsConst import SETTING_BRACKETS_SHOWNONE, SETTING_BRACKETS_SHOWSPECIALS, SETTING_BRACKETS_SHOWALL, TAB_SETTING_IDS, MAX_SHARED_PRESETS
     36 from textImporting import StripImportantSymbol
     37 INVALID_FLAG_STRING = 'invalid flag'
     38 
     39 class ImportBaseWindow(Window):
     40     __guid__ = 'form.ImportBaseWindow'
     41 
     42     def ApplyAttributes(self, attributes):
     43         Window.ApplyAttributes(self, attributes)
     44         self.SetMinSize([450, 250])
     45         self.minWidth = 225
     46         self.scrollWidth = 0
     47         dirpath = attributes.get('dirpath', None)
     48         if dirpath:
     49             self.dirpath = dirpath
     50         else:
     51             self.dirpath = os.path.join(blue.sysinfo.GetUserDocumentsDirectory(), 'EVE', 'Overview')
     52         self.ConstructLayout()
     53 
     54     def ConstructLayout(self, *args):
     55         self.sr.fileContainer = Container(name='fileContainer', align=uiconst.TOLEFT, parent=self.sr.main, padTop=const.defaultPadding, width=256)
     56         self.sr.profilesContainer = Container(name='profilesContainer', align=uiconst.TOALL, parent=self.sr.main, pos=(0, 0, 0, 0))
     57         self.sr.fileHeader = eveLabel.CaptionLabel(text=localization.GetByLabel('UI/Common/Files/FileName'), parent=self.sr.fileContainer, left=const.defaultPadding, align=uiconst.TOTOP, fontsize=14)
     58         fileScrollCont = Container(name='fileScrollCont', parent=self.sr.fileContainer, align=uiconst.TOALL)
     59         self.sr.fileScroll = eveScroll.Scroll(name='fileScroll', parent=fileScrollCont, padding=(const.defaultPadding,
     60          0,
     61          const.defaultPadding,
     62          const.defaultPadding))
     63         self.sr.refreshFileListBtn = ButtonGroup(btns=[[localization.GetByLabel('UI/Commands/Refresh'),
     64           self.RefreshFileList,
     65           (),
     66           None]], parent=self.sr.fileContainer, idx=0)
     67         profilesTopCont = Container(name='fileTopCont', parent=self.sr.profilesContainer, align=uiconst.TOTOP, height=40)
     68         profilesScrollCont = Container(name='fileScrollCont', parent=self.sr.profilesContainer, align=uiconst.TOALL)
     69         self.sr.profilesHeader = eveLabel.CaptionLabel(text=localization.GetByLabel('UI/Common/PleaseSelect'), parent=profilesTopCont, align=uiconst.TOPLEFT, left=4)
     70         self.sr.profilesHeader.fontsize = 14
     71         self.checkAllCB = Checkbox(text=localization.GetByLabel('UI/Shared/CheckAllOn'), parent=profilesTopCont, align=uiconst.TOBOTTOM, height=16, padLeft=const.defaultPadding, callback=self.CheckAll, checked=True)
     72         self.sr.profilesScroll = eveScroll.Scroll(name='profilesScroll', parent=profilesScrollCont, padding=(const.defaultPadding,
     73          0,
     74          const.defaultPadding,
     75          const.defaultPadding))
     76         self.sr.importProfilesBtnGroup = ButtonGroup(parent=self.sr.profilesContainer, idx=0, state=uiconst.UI_NORMAL)
     77         self.sr.importProfilesBtn = self.sr.importProfilesBtnGroup.AddButton(localization.GetByLabel('UI/Commands/Import'), self.Import)
     78         self.ChangeImportButtonDisplayState(display=False)
     79         self.RefreshFileList()
     80 
     81     def RefreshFileList(self, *args):
     82         fileList = self.GetFilesByExt('.xml')
     83         contentList = []
     84         for fileName in fileList:
     85             contentList.append(GetFromClass(Generic, {'label': fileName,
     86              'OnClick': self.OnFileSelected}))
     87 
     88         self.sr.fileScroll.Load(contentList=contentList)
     89 
     90     def GetFilesByExt(self, ext):
     91         fileList = []
     92         if os.path.exists(self.dirpath):
     93             for file in os.listdir(self.dirpath):
     94                 if file.endswith(ext):
     95                     fileList.append(file[:-len(ext)])
     96 
     97         return fileList
     98 
     99     def OnChange(self, *args):
    100         self.ChangeImportButtonState()
    101 
    102     def ChangeImportButtonState(self):
    103         anySelected = self.IsAnyEntrySelected()
    104         self.ChangeImportButtonDisplayState(display=bool(anySelected))
    105 
    106     def ChangeImportButtonDisplayState(self, display):
    107         self.sr.importProfilesBtnGroup.display = display
    108 
    109     def IsAnyEntrySelected(self):
    110         for entry in self.sr.profilesScroll.GetNodes():
    111             if entry.checked:
    112                 return True
    113 
    114         return False
    115 
    116     def Import(self, *args):
    117         raise NotImplementedError('')
    118 
    119     def OnFileSelected(self, entry):
    120         raise NotImplementedError('')
    121 
    122     def CheckAll(self, *args):
    123         for entry in self.sr.profilesScroll.GetNodes():
    124             if entry.__guid__ == 'listentry.Checkbox':
    125                 entry.checked = self.checkAllCB.checked
    126                 if entry.panel:
    127                     entry.panel.Load(entry)
    128 
    129         self.ChangeImportButtonState()
    130 
    131 
    132 class ExportBaseWindow(Window):
    133     __guid__ = 'form.ExportBaseWindow'
    134 
    135     def ApplyAttributes(self, attributes):
    136         Window.ApplyAttributes(self, attributes)
    137         dirpath = attributes.get('dirpath', None)
    138         if dirpath:
    139             self.dirpath = dirpath
    140         else:
    141             self.dirpath = os.path.join(blue.sysinfo.GetUserDocumentsDirectory(), 'EVE', 'Overview')
    142         self.SetMinSize([370, 270])
    143         self.ConstructLayout()
    144 
    145     def ConstructLayout(self, *args):
    146         self.ConstructTopCont()
    147         left = const.defaultPadding
    148         self.sr.buttonContainer = Container(name='buttonContainer', align=uiconst.TOBOTTOM, parent=self.sr.main)
    149         self.sr.filenameLabel = eveLabel.EveLabelMedium(text=localization.GetByLabel('UI/Common/Files/FileName'), parent=self.sr.buttonContainer, top=const.defaultPadding, left=left, state=uiconst.UI_NORMAL)
    150         left += self.sr.filenameLabel.width + const.defaultPadding
    151         self.sr.filename = SingleLineEditText(name='filename', parent=self.sr.buttonContainer, pos=(left,
    152          const.defaultPadding,
    153          150,
    154          0), align=uiconst.TOPLEFT)
    155         self.sr.filename.SetMaxLength(32)
    156         left += self.sr.filename.width + const.defaultPadding
    157         self.sr.exportBtn = Button(parent=self.sr.buttonContainer, label=localization.GetByLabel('UI/Commands/Export'), func=self.Export, btn_default=1, idx=0, pos=(left,
    158          const.defaultPadding,
    159          0,
    160          0))
    161         self.sr.buttonContainer.height = self.sr.filename.height + 10
    162         self.sr.scrolllistcontainer = Container(name='scrolllistcontainer', align=uiconst.TOALL, parent=self.sr.main, pos=(0, 0, 0, 0))
    163         self.sr.scroll = eveScroll.Scroll(name='scroll', parent=self.sr.scrolllistcontainer, padding=(const.defaultPadding,
    164          const.defaultPadding,
    165          const.defaultPadding,
    166          const.defaultPadding))
    167         self.ConstructScrollList()
    168 
    169     def ConstructTopCont(self):
    170         self.topCont = Container(name='topCont', align=uiconst.TOTOP, height=14, parent=self.sr.main)
    171         self.checkAllCB = Checkbox(text=localization.GetByLabel('UI/Shared/CheckAllOn'), parent=self.topCont, align=uiconst.TOPLEFT, pos=(const.defaultPadding,
    172          0,
    173          100,
    174          0), callback=self.CheckAll, checked=True)
    175 
    176     def CheckAll(self, *args):
    177         for entry in self.sr.scroll.GetNodes():
    178             if entry.__guid__ == 'listentry.Checkbox':
    179                 entry.checked = self.checkAllCB.checked
    180                 if entry.panel:
    181                     entry.panel.Load(entry)
    182 
    183         self.ChangeExportButtonState()
    184 
    185     def OnSelectionChanged(self, c, *args):
    186         self.ChangeExportButtonState()
    187 
    188     def ChangeExportButtonState(self):
    189         anySelected = self.IsAnyEntrySelected()
    190         if anySelected:
    191             self.sr.exportBtn.state = uiconst.UI_NORMAL
    192         else:
    193             self.sr.exportBtn.state = uiconst.UI_HIDDEN
    194 
    195     def IsAnyEntrySelected(self):
    196         for entry in self.sr.scroll.GetNodes():
    197             if entry.checked:
    198                 return True
    199 
    200         return False
    201 
    202 
    203 class ExportFittingsWindow(ExportBaseWindow):
    204     __guid__ = 'form.ExportFittingsWindow'
    205     default_windowID = 'ExportFittingsWindow'
    206     default_iconNum = 'res:/ui/Texture/WindowIcons/fitting.png'
    207 
    208     def ApplyAttributes(self, attributes):
    209         self.selectedOwnerID = attributes.ownerID
    210         self.fittingSvc = sm.StartService('fittingSvc')
    211         dirpath = os.path.join(blue.sysinfo.GetUserDocumentsDirectory(), 'EVE', 'Overview')
    212         attributes.dirpath = dirpath
    213         ExportBaseWindow.ApplyAttributes(self, attributes)
    214         self.SetCaption(localization.GetByLabel('UI/Fitting/ExportFittings'))
    215 
    216     def ConstructLayout(self, *args):
    217         ExportBaseWindow.ConstructLayout(self, *args)
    218         options = [(localization.GetByLabel('UI/Fitting/FittingWindow/FittingManagement/PersonalFittings'), session.charid), (localization.GetByLabel('UI/Fitting/FittingWindow/FittingManagement/CorporationFittings'), session.corpid)]
    219         if session.allianceid:
    220             options.append((localization.GetByLabel('UI/Fitting/FittingWindow/FittingManagement/AllianceFittings'), session.allianceid))
    221         if self.selectedOwnerID in [ x[1] for x in options ]:
    222             selected = self.selectedOwnerID
    223         else:
    224             selected = session.charid
    225         self.ownerCombo = Combo(label=None, parent=self.topCont, options=options, name='exportFitting_ownerCombo', select=selected, callback=self.ChangeOwnerFilter, align=uiconst.TOTOP, padding=4)
    226         self.checkAllCB.SetAlign(uiconst.BOTTOMLEFT)
    227         self.topCont.height = self.ownerCombo.height + self.checkAllCB.height + 5
    228 
    229     def ChangeOwnerFilter(self, cb, key, value, *args):
    230         self.selectedOwnerID = value
    231         self.ConstructScrollList()
    232 
    233     def ConstructScrollList(self):
    234         fittings = self.fittingSvc.GetAllFittings()
    235         scrolllist = []
    236         fittingList = []
    237         for fittingID, fitting in fittings.iteritems():
    238             if fitting.ownerID == self.selectedOwnerID:
    239                 fittingList.append((fitting.name, fitting))
    240 
    241         fittingList.sort()
    242         for fittingName, fitting in fittingList:
    243             scrolllist.append(GetFromClass(CheckboxEntry, {'label': fittingName,
    244              'checked': True,
    245              'cfgname': 'groups',
    246              'retval': True,
    247              'report': False,
    248              'OnChange': self.OnSelectionChanged,
    249              'fitting': fitting}))
    250 
    251         self.sr.scroll.Load(contentList=scrolllist)
    252 
    253     def Export(self, *args):
    254         if self.sr.filename.GetValue().strip() == '':
    255             raise UserError('NameInvalid')
    256         impl = getDOMImplementation()
    257         newdoc = impl.createDocument(None, 'fittings', None)
    258         try:
    259             docEl = newdoc.documentElement
    260             export = {}
    261             for entry in self.sr.scroll.GetNodes():
    262                 if not entry.checked:
    263                     continue
    264                 profile = newdoc.createElement('fitting')
    265                 docEl.appendChild(profile)
    266                 profile.attributes['name'] = entry.fitting.name
    267                 element = newdoc.createElement('description')
    268                 element.attributes['value'] = entry.fitting.Get('description')
    269                 profile.appendChild(element)
    270                 element = newdoc.createElement('shipType')
    271                 shipType = evetypes.GetName(entry.fitting.Get('shipTypeID'))
    272                 element.attributes['value'] = shipType
    273                 profile.appendChild(element)
    274                 for typeID, flag, qty in entry.fitting.fitData:
    275                     typeName = evetypes.GetName(typeID)
    276                     hardWareElement = newdoc.createElement('hardware')
    277                     hardWareElement.attributes['type'] = typeName
    278                     slot = self.GetSlotFromFlag(flag)
    279                     if slot is None:
    280                         slot = INVALID_FLAG_STRING
    281                     hardWareElement.attributes['slot'] = slot
    282                     if flag in (const.flagDroneBay, const.flagCargo, const.flagFighterBay):
    283                         hardWareElement.attributes['qty'] = str(qty)
    284                     profile.appendChild(hardWareElement)
    285 
    286             filename = self.sr.filename.GetValue()
    287             illegalFileNameChars = ['?',
    288              '*',
    289              ':',
    290              ';',
    291              '~',
    292              '\\',
    293              '/',
    294              '"',
    295              '|']
    296             for char in illegalFileNameChars:
    297                 if char in filename:
    298                     prompt_player_fsd_dialog('IllegalFilename')
    299                     return
    300 
    301             self.dirpath = os.path.join(blue.sysinfo.GetUserDocumentsDirectory(), 'EVE', 'fittings')
    302             filepath = os.path.join(self.dirpath, self.sr.filename.GetValue() + '.xml')
    303             if not os.path.exists(self.dirpath):
    304                 os.makedirs(self.dirpath)
    305             if os.path.exists(filepath):
    306                 if prompt_player_fsd_dialog('FileExists', {}, uiconst.YESNO) == uiconst.ID_NO:
    307                     return
    308             outfile = codecs.open(filepath, 'w', 'utf-8')
    309             newdoc.writexml(outfile, indent='\t', addindent='\t', newl='\n')
    310             self.CloseByUser()
    311             prompt_player_fsd_dialog('FittingExportDone', {'filename': filepath})
    312         finally:
    313             newdoc.unlink()
    314 
    315     def GetSlotFromFlag(self, flag):
    316         if flag in const.hiSlotFlags:
    317             return 'hi slot ' + str(flag - const.flagHiSlot0)
    318         if flag in const.medSlotFlags:
    319             return 'med slot ' + str(flag - const.flagMedSlot0)
    320         if flag in const.loSlotFlags:
    321             return 'low slot ' + str(flag - const.flagLoSlot0)
    322         if flag in const.rigSlotFlags:
    323             return 'rig slot ' + str(flag - const.flagRigSlot0)
    324         if IsSubsystemFlagVisible(flag):
    325             return 'subsystem slot ' + str(flag - const.flagSubSystemSlot0)
    326         if flag == const.flagCargo:
    327             return 'cargo'
    328         if flag == const.flagDroneBay:
    329             return 'drone bay'
    330         if flag == const.flagFighterBay:
    331             return 'fighter bay'
    332         if flag in const.serviceSlotFlags:
    333             return 'service slot ' + str(flag - const.flagServiceSlot0)
    334 
    335 
    336 class ImportFittingsWindow(ImportBaseWindow):
    337     __guid__ = 'form.ImportFittingsWindow'
    338     default_windowID = 'ImportFittingsWindow'
    339     default_iconNum = 'res:/ui/Texture/WindowIcons/fitting.png'
    340 
    341     def ApplyAttributes(self, attributes):
    342         dirpath = os.path.join(blue.sysinfo.GetUserDocumentsDirectory(), 'EVE', 'Fittings')
    343         attributes.dirpath = dirpath
    344         ImportBaseWindow.ApplyAttributes(self, attributes)
    345         self.sr.importProfilesBtn.LoadTooltipPanel = self.LoadImportTooltip
    346         self.SetCaption(localization.GetByLabel('UI/Fitting/ImportFittings'))
    347         self.fittingSvc = sm.StartService('fittingSvc')
    348 
    349     def LoadImportTooltip(self, tooltipPanel, *args):
    350         hasCorpRoles = bool(session.corprole & const.corpRoleFittingManager)
    351         if not hasCorpRoles:
    352             return
    353         tooltipPanel.LoadGeneric1ColumnTemplate()
    354         tooltipPanel.state = uiconst.UI_NORMAL
    355         tooltipPanel.columns = 1
    356         tooltipPanel.margin = (12, 12, 12, 12)
    357         tooltipPanel.cellPadding = 0
    358         tooltipPanel.cellSpacing = 10
    359         saveAllianceBtn = None
    360         if session.allianceid and sm.GetService('alliance').GetAlliance(session.allianceid).executorCorpID == session.corpid:
    361             saveAllianceBtn = Button(parent=tooltipPanel, label=localization.GetByLabel('UI/Fitting/FittingWindow/SaveForAlliance'), func=self.ImportForOwner, args=(session.allianceid,), align=uiconst.CENTER)
    362         importCorpBtn = Button(parent=tooltipPanel, label=localization.GetByLabel('UI/Fitting/FittingWindow/SaveForCorp'), func=self.ImportForOwner, args=(session.corpid,), align=uiconst.CENTER)
    363         importPersonalBtn = Button(parent=tooltipPanel, label=localization.GetByLabel('UI/Fitting/FittingWindow/SaveForCharacter', charID=session.charid), func=self.ImportForOwner, args=(session.charid,), align=uiconst.CENTER)
    364         maxWidth = max(importCorpBtn.width, importPersonalBtn.width)
    365         if saveAllianceBtn:
    366             maxWidth = max(maxWidth, saveAllianceBtn.width)
    367         importCorpBtn.width = importPersonalBtn.width = maxWidth
    368         if saveAllianceBtn:
    369             saveAllianceBtn.width = maxWidth
    370 
    371     def OnFileSelected(self, entry):
    372         filepath = os.path.join(self.dirpath, entry.sr.node.label + '.xml')
    373         self.sr.selectedFileName = entry.sr.node.label
    374         profileCheckboxes = []
    375         try:
    376             doc = parse(filepath)
    377             try:
    378                 profiles = doc.documentElement.getElementsByTagName('fitting')
    379                 for x in profiles:
    380                     profileCheckboxes.append(GetFromClass(CheckboxEntry, {'label': x.attributes['name'].value,
    381                      'checked': True,
    382                      'cfgname': 'profiles',
    383                      'retval': True,
    384                      'OnChange': self.OnChange}))
    385 
    386                 self.ChangeImportButtonDisplayState(display=True)
    387             finally:
    388                 doc.unlink()
    389 
    390         except Exception as e:
    391             raise
    392             profileCheckboxes = [GetFromClass(Generic, {'label': localization.GetByLabel('UI/Common/Files/FileNotValid')})]
    393             self.ChangeImportButtonDisplayState(display=False)
    394 
    395         self.sr.profilesScroll.Load(contentList=profileCheckboxes)
    396         self.OnChange()
    397 
    398     def Import(self, *args):
    399         return self.ImportForOwner()
    400 
    401     def ImportForOwner(self, ownerID = None):
    402         filepath = os.path.join(self.dirpath, self.sr.selectedFileName + '.xml')
    403         godma = sm.GetService('godma')
    404         doc = parse(filepath)
    405         try:
    406             fittings = doc.documentElement.getElementsByTagName('fitting')
    407             fittingsDict = {}
    408             borkedTypeNames = set()
    409             borkedFlags = set()
    410             obsoleteModules = set()
    411             for checkbox in self.sr.profilesScroll.GetNodes():
    412                 if not checkbox.checked:
    413                     continue
    414                 fittingName = checkbox.label
    415                 kv = utillib.KeyVal()
    416                 for fitting in fittings:
    417                     if fitting.attributes['name'].value != fittingName:
    418                         continue
    419                     descriptionElements = fitting.getElementsByTagName('description')
    420                     if descriptionElements > 0:
    421                         description = descriptionElements[0].attributes['value'].value
    422                     else:
    423                         description = ''
    424                     shipTypeName = fitting.getElementsByTagName('shipType')[0].attributes['value'].value
    425                     try:
    426                         cleanShipTypeName = StripTags(shipTypeName)
    427                         cleanShipTypeName = StripImportantSymbol(cleanShipTypeName)
    428                         importFittingUtil = sm.GetService('fittingSvc').GetImportFittingUtil()
    429                         shipTypeID = importFittingUtil.GetTypeIDFromName(cleanShipTypeName.lower())
    430                     except evetypes.TypeNotFoundException:
    431                         sys.exc_clear()
    432                         borkedTypeNames.add(shipTypeName)
    433                         continue
    434 
    435                     shipTypeID = int(shipTypeID)
    436                     fitData = {}
    437                     for hardwareElement in fitting.getElementsByTagName('hardware'):
    438                         typeName = hardwareElement.attributes['type'].value
    439                         try:
    440                             cleanTypeName = StripTags(typeName)
    441                             cleanTypeName = StripImportantSymbol(cleanTypeName)
    442                             typeID = evetypes.GetTypeIDByName(cleanTypeName)
    443                         except evetypes.TypeNotFoundException:
    444                             borkedTypeNames.add(typeName)
    445                             sys.exc_clear()
    446                             continue
    447 
    448                         slot = hardwareElement.attributes['slot'].value
    449                         flag = self.GetFlagFromSlot(slot)
    450                         if flag is None:
    451                             borkedFlags.add(typeName)
    452                             continue
    453                         if IsShipFittable(evetypes.GetCategoryID(typeID)) and flag != const.flagCargo:
    454                             qty = 1
    455                         elif IsModuleObsolete(typeID):
    456                             obsoleteModules.add(typeName)
    457                             continue
    458                         else:
    459                             qty = hardwareElement.attributes['qty'].value
    460                             qty = int(qty)
    461                         fitData[typeID, flag] = (typeID, flag, qty)
    462 
    463                     kv.name = fittingName
    464                     kv.description = description
    465                     kv.shipTypeID = shipTypeID
    466                     kv.fitData = fitData.values()
    467                     kv.ownerID = None
    468                     kv.fittingID = fittingName
    469                     fittingsDict[fittingName] = kv
    470 
    471             text = ''
    472             if len(borkedTypeNames) > 0:
    473                 text += '<b>%s</b><br>' % localization.GetByLabel('UI/Fitting/MalformedXML')
    474                 for typeName in borkedTypeNames:
    475                     text += typeName + '<br>'
    476 
    477             if len(borkedFlags) > 0:
    478                 if len(text) > 0:
    479                     text += '<br><br>'
    480                 text += '<b>%s</b><br>' % localization.GetByLabel('UI/Fitting/MalformedFlagInformation')
    481                 for typeName in borkedFlags:
    482                     text += typeName + '<br>'
    483 
    484             if len(obsoleteModules) > 0:
    485                 if len(text) > 0:
    486                     text += '<br><br>'
    487                 text += '<b>%s</b><br>' % localization.GetByLabel('UI/Fitting/ObsoleteModules')
    488                 for typeName in obsoleteModules:
    489                     text += typeName + '<br>'
    490 
    491             if len(text) > 0:
    492                 prompt_player_fsd_dialog('CustomInfo', {'info': text})
    493             fittingOwner = ownerID or session.charid
    494             self.fittingSvc.PersistManyFittings(fittingOwner, fittingsDict.values())
    495             self.CloseByUser()
    496         finally:
    497             doc.unlink()
    498 
    499     def GetFlagFromSlot(self, slot):
    500         if slot == INVALID_FLAG_STRING:
    501             return None
    502         if slot == 'drone bay':
    503             return const.flagDroneBay
    504         if slot == 'fighter bay':
    505             return const.flagFighterBay
    506         if slot == 'cargo':
    507             return const.flagCargo
    508         offset = int(slot[-1])
    509         if slot.startswith('hi slot'):
    510             return const.flagHiSlot0 + offset
    511         if slot.startswith('med slot'):
    512             return const.flagMedSlot0 + offset
    513         if slot.startswith('low slot'):
    514             return const.flagLoSlot0 + offset
    515         if slot.startswith('rig slot'):
    516             return const.flagRigSlot0 + offset
    517         if slot.startswith('subsystem slot'):
    518             return const.flagSubSystemSlot0 + offset
    519         if slot.startswith('service slot'):
    520             return const.flagServiceSlot0 + offset
    521 
    522 
    523 class ImportOverviewWindow(ImportBaseWindow):
    524     __guid__ = 'form.ImportOverviewWindow'
    525     default_windowID = 'ImportOverviewWindow'
    526 
    527     def ApplyAttributes(self, attributes):
    528         dirpath = os.path.join(blue.sysinfo.GetUserDocumentsDirectory(), 'EVE', 'Overview')
    529         self.presetsSelected = set()
    530         ImportBaseWindow.ApplyAttributes(self, attributes)
    531         self.SetCaption(localization.GetByLabel('UI/Overview/ImportOverviewSettings'))
    532         self.sr.fileScroll.multiSelect = False
    533         self.fileType = ''
    534         self.yamlSettingsDict = {}
    535 
    536     def RefreshFileList(self, *args):
    537         legacyPresets = self.GetLegacyPresets()
    538         fileList = self.GetFilesByExt('.yaml')
    539         contentList = []
    540         for fileName in fileList:
    541             contentList.append(GetFromClass(Generic, {'label': fileName,
    542              'OnClick': self.OnFileSelected,
    543              'ext': 'yaml'}))
    544 
    545         contentList += legacyPresets
    546         self.sr.fileScroll.Load(contentList=contentList)
    547 
    548     def GetLegacyPresets(self):
    549         filelist = self.GetFilesByExt('.xml')
    550         if not filelist:
    551             return []
    552         return [GetFromClass(ListGroup, {'GetSubContent': self.GetOldPresetSubContent,
    553           'label': localization.GetByLabel('UI/Overview/OldOverviewSettings'),
    554           'id': ('importOverview', 'oldPresets'),
    555           'groupItems': filelist,
    556           'showlen': 1,
    557           'sublevel': 0,
    558           'showicon': 'hide',
    559           'state': 'locked'})]
    560 
    561     def GetOldPresetSubContent(self, nodedata):
    562         fileList = []
    563         for fileName in nodedata.groupItems:
    564             fileList.append(GetFromClass(Generic, {'label': fileName,
    565              'OnClick': self.OnFileSelected,
    566              'sublevel': 1,
    567              'ext': 'xml'}))
    568 
    569         return fileList
    570 
    571     def OnFileSelected(self, entry):
    572         if entry.sr.node.ext == 'xml':
    573             self.ShowXmlSettings(entry)
    574         else:
    575             self.yamlSettingsDict = {}
    576             self.ShowYamlSettings(entry)
    577 
    578     def ShowXmlSettings(self, entry):
    579         self.fileType = 'xml'
    580         filepath = os.path.join(self.dirpath, entry.sr.node.label + '.xml')
    581         self.sr.selectedFileName = entry.sr.node.label
    582         profileCheckboxes = []
    583         try:
    584             doc = parse(filepath)
    585             try:
    586                 profiles = doc.documentElement.getElementsByTagName('profile')
    587                 for x in profiles:
    588                     profileCheckboxes.append(GetFromClass(CheckboxEntry, {'label': x.attributes['name'].value,
    589                      'checked': True,
    590                      'cfgname': 'profiles',
    591                      'retval': True,
    592                      'OnChange': self.OnChange}))
    593 
    594                 if len(doc.documentElement.getElementsByTagName('globalSettings')):
    595                     profileCheckboxes.append(GetFromClass(CheckboxEntry, {'label': localization.GetByLabel('UI/Overview/GlobalOverviewSettings'),
    596                      'checked': True,
    597                      'cfgname': 'profiles',
    598                      'retval': True,
    599                      'OnChange': self.OnChange}))
    600                 self.ChangeImportButtonDisplayState(display=True)
    601             finally:
    602                 doc.unlink()
    603 
    604         except Exception as e:
    605             profileCheckboxes = [GetFromClass(Generic, {'label': localization.GetByLabel('UI/Common/Files/FileNotValid')})]
    606             self.ChangeImportButtonDisplayState(display=False)
    607 
    608         self.sr.profilesScroll.Load(contentList=profileCheckboxes)
    609         self.ChangeImportButtonState()
    610 
    611     def ShowYamlSettings(self, entry):
    612         self.fileType = 'yaml'
    613         filepath = os.path.join(self.dirpath, entry.sr.node.label + '.yaml')
    614         filestream = open(filepath)
    615         settingDict = yaml.safe_load(filestream)
    616         self.yamlSettingsDict = settingDict
    617         self.ConstructScrollList(initPresetsSelected=True)
    618 
    619     def ConstructScrollList(self, initPresetsSelected = False):
    620         if self.fileType != 'yaml':
    621             return
    622         allChecked = True
    623         settingDict = self.yamlSettingsDict
    624         tabPresets = GetDictFromList(settingDict.get('presets', []))
    625         tabPresets = ReplaceInnerListsWithDicts(tabPresets)
    626         tabSetup = sm.GetService('overviewPresetSvc').GetTabSetupToLoad(settingDict)
    627         presetsInUseDict = sm.GetService('overviewPresetSvc').GetPresetsInUseFromTabSettings(tabSetup, tabPresets)
    628         if initPresetsSelected:
    629             self.InitPresetsSelected(presetsInUseDict)
    630         checked = 'generalSettings' in self.presetsSelected
    631         scrolllist = [GetGeneralOverviewSettingsEntry(onChangeFunc=self.OnChange, checked=checked)]
    632         allChecked = allChecked and checked
    633         checked = 'overviewProfile' in self.presetsSelected
    634         profileEntry = GetOverviewProfileEntry(onChangeFunc=self.OnChange, checked=checked)
    635         scrolllist.append(profileEntry)
    636         allChecked = allChecked and checked
    637         presetsInUseList = []
    638         for eachPresetName in presetsInUseDict:
    639             lowerDisplayName = eachPresetName.lower()
    640             presetsInUseList.append((lowerDisplayName, eachPresetName))
    641 
    642         presetsInUseList = [ x[1] for x in localization.util.Sort(presetsInUseList, key=operator.itemgetter(0)) ]
    643         for eachPresetName in presetsInUseList:
    644             checked = eachPresetName in self.presetsSelected
    645             entry = GetTabPresetEntry(eachPresetName, onChangeFunc=self.OnChange, checked=checked)
    646             scrolllist.append(entry)
    647             allChecked = allChecked and checked
    648 
    649         restOfPresets = []
    650         for eachPresetName in tabPresets:
    651             if eachPresetName in presetsInUseList:
    652                 continue
    653             lowerDisplayName = eachPresetName.lower()
    654             restOfPresets.append((lowerDisplayName, eachPresetName))
    655 
    656         if restOfPresets:
    657             restOfPresets = [ x[1] for x in localization.util.Sort(restOfPresets, key=operator.itemgetter(0)) ]
    658             posttext, allSubPresetsChecked = GetPresetPostText(restOfPresets, self.presetsSelected)
    659             allChecked = allChecked and allSubPresetsChecked
    660             scrolllist.append(GetFromClass(ListGroup, {'GetSubContent': self.GetPresetSubContent,
    661              'label': localization.GetByLabel('UI/Overview/OtherTabPresets'),
    662              'id': ('importOverview', 'restOfPresets'),
    663              'groupItems': restOfPresets,
    664              'showlen': 0,
    665              'sublevel': 0,
    666              'showicon': 'hide',
    667              'state': 'locked',
    668              'posttext': posttext}))
    669         self.sr.profilesScroll.Load(contentList=scrolllist)
    670         self.ChangeImportButtonState()
    671         self.checkAllCB.SetChecked(allChecked, report=False)
    672 
    673     def InitPresetsSelected(self, presetsInUseDict):
    674         self.presetsSelected = set(['generalSettings', 'overviewProfile'])
    675         for eachPresetName in presetsInUseDict:
    676             self.presetsSelected.add(eachPresetName)
    677 
    678     def OnChange(self, c, *args):
    679         OnOverviewCheckboxChange(c, self.presetsSelected)
    680         if self.fileType == 'yaml':
    681             self.ConstructScrollList()
    682         ImportBaseWindow.OnChange(self, c)
    683 
    684     def CheckAll(self, *args):
    685         if self.fileType == 'xml':
    686             return ImportBaseWindow.CheckAll(self)
    687         if self.fileType == 'yaml':
    688             checkAll = self.checkAllCB.checked
    689             ModifyPresetSelectedDict(checkAll, self.sr.profilesScroll, self.presetsSelected)
    690             self.ConstructScrollList()
    691         self.ChangeImportButtonState()
    692 
    693     def IsAnyEntrySelected(self):
    694         if self.fileType == 'xml':
    695             return ImportBaseWindow.IsAnyEntrySelected(self)
    696         else:
    697             return bool(self.presetsSelected)
    698 
    699     def GetPresetSubContent(self, nodedata):
    700         scrolllist = []
    701         for eachPresetName in nodedata.groupItems:
    702             checked = eachPresetName in self.presetsSelected
    703             entry = GetTabPresetEntry(eachPresetName, onChangeFunc=self.OnChange, checked=checked)
    704             scrolllist.append(entry)
    705 
    706         return scrolllist
    707 
    708     def AddProfilesToSettings(self, profileName, profiles):
    709         for profile in profiles:
    710             groups = []
    711             filteredStates = []
    712             if profile.attributes['name'].value != profileName:
    713                 continue
    714             for groupElement in profile.getElementsByTagName('groups')[0].getElementsByTagName('group'):
    715                 groups.append(int(groupElement.attributes['id'].value))
    716 
    717             for el in profile.getElementsByTagName('filteredStates')[0].getElementsByTagName('state'):
    718                 filteredStates.append(int(el.attributes['state'].value))
    719 
    720             profileValues = {overviewSettingsConst.PRESET_SETTINGS_GROUPS: groups,
    721              overviewSettingsConst.PRESET_SETTINGS_FILTERED_STATES: filteredStates}
    722             return (profileName, profileValues)
    723 
    724         return (None, None)
    725 
    726     def ImportGlobalSettings(self, doc, miscSettings):
    727         settingsElement = doc.documentElement.getElementsByTagName('globalSettings')[0]
    728         for setting in [osConst.SETTING_NAME_SMALL_TAGS,
    729          osConst.SETTING_NAME_APPLY_STRUCTURE,
    730          osConst.SETTING_NAME_APPLY_OTHER_OBJ,
    731          osConst.SETTING_HIDE_CORP_TICKER,
    732          osConst.SETTING_BROADCAST_TO_TOP]:
    733             elements = settingsElement.getElementsByTagName(setting)
    734             if not elements:
    735                 continue
    736             element = elements[0]
    737             value = bool(element.attributes['value'])
    738             miscSettings[setting] = value
    739 
    740         overviewColumns = []
    741         columnsElement = settingsElement.getElementsByTagName('columns')[0]
    742         for columnElement in columnsElement.getElementsByTagName('column'):
    743             overviewColumns.append(columnElement.attributes['id'].value)
    744 
    745         shipLabels = []
    746         if len(settingsElement.getElementsByTagName('shipLabels')):
    747             shipLabelsElement = settingsElement.getElementsByTagName('shipLabels')[0]
    748             shipLabelElements = shipLabelsElement.getElementsByTagName('label')
    749             for sle in shipLabelElements:
    750                 d = {}
    751                 for shipLabelPartElement in sle.getElementsByTagName('part'):
    752                     n = shipLabelPartElement.attributes['name'].value
    753                     v = shipLabelPartElement.attributes['value'].value
    754                     if n == 'state':
    755                         v = int(v)
    756                     if v == 'None':
    757                         v = None
    758                     d[n] = v
    759 
    760                 shipLabels.append(d)
    761 
    762         stateService = sm.StartService('stateSvc')
    763         if hasattr(stateService, 'shipLabels'):
    764             delattr(stateService, 'shipLabels')
    765         return (overviewColumns, shipLabels)
    766 
    767     def GetTabData(self, selectedProfiles, tabElement):
    768         overviewProfileName = tabElement.attributes['overview'].value
    769         bracketProfileName = tabElement.attributes['bracket'].value
    770         tabdata = {}
    771         if overviewProfileName in selectedProfiles and bracketProfileName in selectedProfiles:
    772             for attributeName in TAB_SETTING_IDS:
    773                 attribute = tabElement.getAttribute(attributeName)
    774                 if attribute:
    775                     if attribute in (SETTING_BRACKETS_SHOWNONE, SETTING_BRACKETS_SHOWSPECIALS, SETTING_BRACKETS_SHOWALL):
    776                         attribute = bool(attribute)
    777                     tabdata[attributeName] = attribute
    778 
    779         return tabdata
    780 
    781     def Import(self, *args):
    782         if self.fileType == 'xml':
    783             return self.ImportXml()
    784         else:
    785             return self.ImportYaml()
    786 
    787     def ImportXml(self, *args):
    788         dirpath = os.path.join(blue.sysinfo.GetUserDocumentsDirectory(), 'EVE', 'Overview')
    789         filepath = os.path.join(dirpath, self.sr.selectedFileName + '.xml')
    790         doc = parse(filepath)
    791         try:
    792             profiles = doc.documentElement.getElementsByTagName('profile')
    793             ov = settings.user.overview.Get(osConst.SETTING_PROFILE_PRESETS, {})
    794             miscSettings = {}
    795             selectedProfiles = []
    796             shipLabels = None
    797             overviewColumns = None
    798             closeWindow = True
    799             profileUpdateDict = {}
    800             for checkbox in self.sr.profilesScroll.GetNodes():
    801                 if not checkbox.checked:
    802                     continue
    803                 profileName = checkbox.label
    804                 if profileName in ov and prompt_player_fsd_dialog('OverviewProfileExists', {'name': profileName}, uiconst.YESNO) != uiconst.ID_YES:
    805                     closeWindow = False
    806                     continue
    807                 if profileName == localization.GetByLabel('UI/Overview/GlobalOverviewSettings'):
    808                     overviewColumns, shipLabels = self.ImportGlobalSettings(doc, miscSettings)
    809                     continue
    810                 selectedProfiles.append(profileName)
    811                 profileName, profileValues = self.AddProfilesToSettings(profileName, profiles)
    812                 if profileValues:
    813                     profileUpdateDict[profileName] = profileValues
    814 
    815             overviewPresetSvc = sm.GetService('overviewPresetSvc')
    816             overviewPresetSvc.UpdateAllPresets(profileUpdateDict)
    817             tabsChanged = False
    818             tabsData = {}
    819             tabIndex = 0
    820             for tabElement in doc.documentElement.getElementsByTagName('tab'):
    821                 if tabIndex >= 5:
    822                     prompt_player_fsd_dialog('TooManyTabsImported')
    823                     break
    824                 dataForTab = self.GetTabData(selectedProfiles, tabElement)
    825                 if dataForTab:
    826                     tabsData[tabIndex] = dataForTab
    827                     tabIndex += 1
    828                     tabsChanged = True
    829 
    830             if overviewColumns:
    831                 settings.user.overview.Set(osConst.SETTING_COLUMNS, overviewColumns)
    832             if shipLabels:
    833                 settings.user.overview.Set(osConst.SETTINGS_SHIP_LABELS, shipLabels)
    834             for k, v in miscSettings.items():
    835                 settings.user.overview.Set(k, v)
    836 
    837             overviewPresetSvc.LoadPresetsFromUserSettings()
    838             if tabsChanged:
    839                 overviewPresetSvc.ImportOverviewSettings(tabsData)
    840             if tabsChanged:
    841                 sm.ScatterEvent('OnOverviewPresetsChanged')
    842             else:
    843                 sm.ScatterEvent('OnFullOverviewReload')
    844             if closeWindow:
    845                 self.CloseByUser()
    846         finally:
    847             doc.unlink()
    848 
    849     def ImportYaml(self):
    850         tabPresetNamesToImport = []
    851         tabsChanged = False
    852         for checkboxConfig in self.presetsSelected:
    853             if checkboxConfig == 'generalSettings':
    854                 sm.GetService('overviewPresetSvc').LoadGeneralSettings(self.yamlSettingsDict)
    855             elif checkboxConfig == 'overviewProfile':
    856                 tabSetup = sm.GetService('overviewPresetSvc').GetTabSetupToLoad(self.yamlSettingsDict)
    857                 sm.GetService('overviewPresetSvc').PersistSettingsByTabID(tabSetup)
    858                 tabsChanged = True
    859             else:
    860                 tabPresetNamesToImport.append(checkboxConfig)
    861 
    862         presetsDict = GetDictFromList(self.yamlSettingsDict.get('presets', []))
    863         presetsDict = ReplaceInnerListsWithDicts(presetsDict)
    864         myPresets = {presetName:presetValue for presetName, presetValue in presetsDict.iteritems() if presetName in tabPresetNamesToImport}
    865         sm.GetService('overviewPresetSvc').UpdateAllPresets(myPresets)
    866         if tabsChanged:
    867             sm.GetService('overviewPresetSvc').ImportOverviewSettings(tabSetup)
    868         sm.ScatterEvent('OnReloadingOverviewProfile')
    869         self.CloseByUser()
    870 
    871 
    872 class ImportLegacyFittingsWindow(ExportBaseWindow):
    873     __guid__ = 'form.ImportLegacyFittingsWindow'
    874     default_windowID = 'ImportLegacyFittingsWindow'
    875     default_iconNum = 'res:/ui/Texture/WindowIcons/fitting.png'
    876 
    877     def OnSelectionChanged(self, c, *args):
    878         checkedCount = 0
    879         for entry in self.sr.scroll.GetNodes():
    880             if entry.checked:
    881                 checkedCount += 1
    882 
    883         text = localization.GetByLabel('UI/Fitting/MovingCount', count=checkedCount, total=self.totalLocalFittings)
    884         if self.fittingCount > 0:
    885             text += ' (' + localization.GetByLabel('UI/Fitting/CurrentlySaved', count=self.fittingCount) + ')'
    886         self.sr.countSelectedTextLabel.text = text
    887         if not self.okBtn.disabled and self.fittingCount + checkedCount > const.maxCharFittings:
    888             self.okBtn.Disable()
    889         elif self.okBtn.disabled and self.fittingCount + checkedCount <= const.maxCharFittings:
    890             self.okBtn.Enable()
    891 
    892     def ApplyAttributes(self, attributes):
    893         self.fittingSvc = sm.StartService('fittingSvc')
    894         self.fittingCount = len(self.fittingSvc.GetFittingMgr(session.charid).GetFittings(session.charid))
    895         Window.ApplyAttributes(self, attributes)
    896         self.SetMinSize([370, 270])
    897         self.SetCaption(localization.GetByLabel('UI/Fitting/MoveToServer'))
    898         self.ConstructLayout()
    899 
    900     def ConstructLayout(self, *args):
    901         self.countSelectedText = ''
    902         self.sr.textContainer = Container(name='textContainer', align=uiconst.TOTOP, parent=self.sr.main, height=65, padding=const.defaultPadding)
    903         self.sr.textLabel = eveLabel.EveLabelMedium(text=localization.GetByLabel('UI/Fitting/LegacyImport', maxFittings=const.maxCharFittings), align=uiconst.TOTOP, parent=self.sr.textContainer)
    904         self.sr.textContainer2 = Container(name='textContainer', align=uiconst.TOTOP, parent=self.sr.main, height=15, padding=const.defaultPadding)
    905         self.sr.countSelectedTextLabel = eveLabel.EveLabelMedium(text=self.countSelectedText, align=uiconst.TOALL, parent=self.sr.textContainer2)
    906         self.sr.buttonContainer = Container(name='buttonContainer', align=uiconst.TOBOTTOM, parent=self.sr.main)
    907         btns = [[localization.GetByLabel('UI/Generic/Cancel'),
    908           self.CloseByUser,
    909           None,
    910           81], [localization.GetByLabel('UI/Generic/OK'),
    911           self.Import,
    912           None,
    913           81]]
    914         self.buttonGroup = ButtonGroup(btns=btns, parent=self.sr.buttonContainer)
    915         self.okBtn = self.buttonGroup.children[0].children[1]
    916         self.sr.buttonContainer.height = 23
    917         self.sr.scrolllistcontainer = Container(name='scrolllistcontainer', align=uiconst.TOALL, parent=self.sr.main, pos=(0, 0, 0, 0))
    918         self.sr.scroll = eveScroll.Scroll(name='scroll', parent=self.sr.scrolllistcontainer, padding=(const.defaultPadding,
    919          const.defaultPadding,
    920          const.defaultPadding,
    921          const.defaultPadding))
    922         self.ConstructScrollList()
    923 
    924     def ConstructScrollList(self):
    925         fittings = self.fittingSvc.GetLegacyClientFittings()
    926         scrolllist = []
    927         fittingList = []
    928         for fittingID, fitting in fittings.iteritems():
    929             fittingList.append((fitting.name, fitting))
    930 
    931         fittingList.sort()
    932         self.emptyFittings = []
    933         for fittingName, fitting in fittingList:
    934             if len(fitting.fitData) == 0:
    935                 self.emptyFittings.append(fitting)
    936                 continue
    937             typeFlag = set()
    938             for typeID, flag, qty in fitting.fitData[:]:
    939                 if (typeID, flag) in typeFlag:
    940                     fitting.fitData.remove((typeID, flag, qty))
    941                 else:
    942                     typeFlag.add((typeID, flag))
    943 
    944             scrolllist.append(GetFromClass(CheckboxEntry, {'label': fittingName,
    945              'checked': False,
    946              'OnChange': self.OnSelectionChanged,
    947              'cfgname': 'groups',
    948              'retval': True,
    949              'report': False,
    950              'fitting': fitting}))
    951 
    952         self.sr.scroll.Load(contentList=scrolllist)
    953         self.totalLocalFittings = len(fittingList)
    954         self.OnSelectionChanged(None)
    955 
    956     def Import(self, *args):
    957         impl = getDOMImplementation()
    958         newdoc = impl.createDocument(None, 'fittings', None)
    959         try:
    960             docEl = newdoc.documentElement
    961             fittings = []
    962             saveSomeToFile = False
    963             for entry in self.sr.scroll.GetNodes():
    964                 if entry.checked:
    965                     fittings.append(entry.fitting)
    966                 else:
    967                     saveSomeToFile = True
    968                     profile = newdoc.createElement('fitting')
    969                     docEl.appendChild(profile)
    970                     profile.attributes['name'] = entry.fitting.name
    971                     element = newdoc.createElement('description')
    972                     element.attributes['value'] = entry.fitting.Get('description')
    973                     profile.appendChild(element)
    974                     element = newdoc.createElement('shipType')
    975                     try:
    976                         shipType = evetypes.GetName(entry.fitting.Get('shipTypeID'))
    977                     except KeyError:
    978                         shipType = 'unknown type'
    979 
    980                     element.attributes['value'] = shipType
    981                     profile.appendChild(element)
    982                     for typeID, flag, qty in entry.fitting.fitData:
    983                         try:
    984                             typeName = evetypes.GetName(typeID)
    985                         except KeyError:
    986                             typeName = 'unknown type'
    987 
    988                         hardWareElement = newdoc.createElement('hardware')
    989                         hardWareElement.attributes['type'] = typeName
    990                         slot = self.GetSlotFromFlag(flag)
    991                         if slot is None:
    992                             slot = 'unknown slot'
    993                         hardWareElement.attributes['slot'] = slot
    994                         if flag == const.flagDroneBay:
    995                             hardWareElement.attributes['qty'] = str(qty)
    996                         profile.appendChild(hardWareElement)
    997 
    998             for emptyFitting in self.emptyFittings:
    999                 saveSomeToFile = True
   1000                 profile = newdoc.createElement('fitting')
   1001                 docEl.appendChild(profile)
   1002                 profile.attributes['name'] = entry.fitting.name
   1003                 element = newdoc.createElement('description')
   1004                 element.attributes['value'] = entry.fitting.Get('description')
   1005                 profile.appendChild(element)
   1006                 element = newdoc.createElement('shipType')
   1007                 try:
   1008                     shipType = evetypes.GetName(entry.fitting.Get('shipTypeID'))
   1009                 except KeyError:
   1010                     shipType = 'unknown type'
   1011 
   1012                 element.attributes['value'] = shipType
   1013                 profile.appendChild(element)
   1014 
   1015             if len(fittings) > 0:
   1016                 self.fittingSvc.PersistManyFittings(session.charid, fittings)
   1017             if saveSomeToFile:
   1018                 self.dirpath = os.path.join(blue.sysinfo.GetUserDocumentsDirectory(), 'EVE', 'fittings')
   1019                 filename = cfg.eveowners.Get(session.charid).ownerName
   1020                 filename = filename.replace(' ', '')
   1021                 filename = SanitizeFilename(filename)
   1022                 dirpath = os.path.join(blue.sysinfo.GetUserDocumentsDirectory(), 'EVE', 'fittings')
   1023                 filename = os.path.join(dirpath, filename)
   1024                 extraEnding = ''
   1025                 while os.path.exists(filename + str(extraEnding) + '.xml'):
   1026                     if not isinstance(extraEnding, int):
   1027                         extraEnding = 1
   1028                     extraEnding += 1
   1029 
   1030                 filename += str(extraEnding) + '.xml'
   1031                 if not os.path.exists(self.dirpath):
   1032                     os.makedirs(self.dirpath)
   1033                 outfile = codecs.open(filename, 'w', 'utf-8')
   1034                 newdoc.writexml(outfile, indent='\t', addindent='\t', newl='\n')
   1035                 prompt_player_fsd_dialog('LegacyFittingExportDone', {'filename': filename})
   1036             self.fittingSvc.DeleteLegacyClientFittings()
   1037             self.CloseByUser()
   1038         finally:
   1039             newdoc.unlink()
   1040 
   1041     def GetSlotFromFlag(self, flag):
   1042         if const.flagHiSlot0 <= flag <= const.flagHiSlot7:
   1043             return 'hi slot ' + str(flag - const.flagHiSlot0)
   1044         if const.flagMedSlot0 <= flag <= const.flagMedSlot7:
   1045             return 'med slot ' + str(flag - const.flagMedSlot0)
   1046         if const.flagLoSlot0 <= flag <= const.flagLoSlot7:
   1047             return 'low slot ' + str(flag - const.flagLoSlot0)
   1048         if const.flagRigSlot0 <= flag <= const.flagRigSlot7:
   1049             return 'rig slot ' + str(flag - const.flagRigSlot0)
   1050         if IsSubsystemFlag(flag):
   1051             return 'subsystem slot ' + str(flag - const.flagSubSystemSlot0)
   1052         if flag == const.flagDroneBay:
   1053             return 'drone bay'
   1054         if flag in const.serviceSlotFlags:
   1055             return 'service slot ' + str(flag - const.flagServiceSlot0)
   1056 
   1057 
   1058 class ExportOverviewWindow(ExportBaseWindow):
   1059     __guid__ = 'form.ExportOverviewWindow'
   1060     default_windowID = 'ExportOverviewWindow'
   1061     __notifyevents__ = ['OnOverviewPresetSaved']
   1062     EXPORT_EVERYTHING = False
   1063 
   1064     def ApplyAttributes(self, attributes):
   1065         self.overviewPresetSvc = sm.StartService('overviewPresetSvc')
   1066         dirpath = os.path.join(blue.sysinfo.GetUserDocumentsDirectory(), 'EVE', 'Overview')
   1067         attributes.dirpath = dirpath
   1068         self.InitPresetsSelected()
   1069         ExportBaseWindow.ApplyAttributes(self, attributes)
   1070         self.SetCaption(localization.GetByLabel('UI/Commands/ExportOverviewSettings'))
   1071 
   1072     def ConstructTopCont(self):
   1073         self.topCont = ContainerAutoSize(name='topCont', align=uiconst.TOTOP, padLeft=4, parent=self.sr.main)
   1074         currentText = self.overviewPresetSvc.GetOverviewName()
   1075         defaultText = localization.GetByLabel('UI/Overview/DefaultOverviewName', charID=session.charid)
   1076         configName = 'overviewProfileNameInExport'
   1077         getDragDataFunc = self.GetShareData
   1078         shareContainer = DraggableShareContainer(parent=self.topCont, currentText=currentText, defaultText=defaultText, configName=configName, getDragDataFunc=getDragDataFunc, hintText=localization.GetByLabel('UI/Overview/SharableOverviewIconExportHint'), align=uiconst.TOTOP, padTop=4)
   1079         self.topCont.height = shareContainer.sharedNameLabel.height + 10
   1080         self.checkAllCB = Checkbox(text=localization.GetByLabel('UI/Shared/CheckAllOn'), parent=self.topCont, align=uiconst.TOTOP, callback=self.CheckAll, checked=True, padTop=6, padLeft=4)
   1081 
   1082     def GetShareData(self, text):
   1083         selected = self.presetsSelected.copy()
   1084         for x in ('generalSettings', 'overviewProfile'):
   1085             if x in selected:
   1086                 selected.remove(x)
   1087 
   1088         if len(selected) > MAX_SHARED_PRESETS:
   1089             prompt_player_fsd_dialog('CustomNotify', {'notify': localization.GetByLabel('UI/Overview/TryingToShareTooManyPresets')})
   1090             return []
   1091         return self.overviewPresetSvc.GetShareData(text=text, presetsToUse=selected)
   1092 
   1093     def InitPresetsSelected(self):
   1094         self.presetsSelected = set(['generalSettings', 'overviewProfile'])
   1095         presetsInUse = self.overviewPresetSvc.GetPresetsInUse()
   1096         for eachPresetName in presetsInUse:
   1097             lowerDisplayName = eachPresetName.lower()
   1098             self.presetsSelected.add(eachPresetName)
   1099 
   1100     def ConstructScrollList(self):
   1101         allChecked = True
   1102         scrolllist = []
   1103         checked = 'generalSettings' in self.presetsSelected
   1104         generalSettingsEntry = GetGeneralOverviewSettingsEntry(onChangeFunc=self.OnSelectionChanged, checked=checked)
   1105         scrolllist.append(generalSettingsEntry)
   1106         allChecked = allChecked and checked
   1107         checked = 'overviewProfile' in self.presetsSelected
   1108         profileEntry = GetOverviewProfileEntry(onChangeFunc=self.OnSelectionChanged, checked=checked)
   1109         scrolllist.append(profileEntry)
   1110         allChecked = allChecked and checked
   1111         presetsInUse = self.overviewPresetSvc.GetPresetsInUse()
   1112         presetsInUseList = []
   1113         for eachPresetName in presetsInUse:
   1114             lowerDisplayName = eachPresetName.lower()
   1115             presetsInUseList.append((lowerDisplayName, eachPresetName))
   1116 
   1117         presetsInUseList = [ x[1] for x in localization.util.Sort(presetsInUseList, key=operator.itemgetter(0)) ]
   1118         for eachPresetName in presetsInUseList:
   1119             checked = eachPresetName in self.presetsSelected
   1120             entry = GetTabPresetEntry(eachPresetName, onChangeFunc=self.OnSelectionChanged, checked=checked)
   1121             scrolllist.append(entry)
   1122             allChecked = allChecked and checked
   1123 
   1124         allPresets = self.overviewPresetSvc.GetAllPresets()
   1125         restOfPresets = []
   1126         defaultProfileNames = self.overviewPresetSvc.GetDefaultOverviewPresetNames()
   1127         for eachPresetName in allPresets:
   1128             if not self.EXPORT_EVERYTHING:
   1129                 if eachPresetName in presetsInUse or eachPresetName in defaultProfileNames:
   1130                     continue
   1131             lowerDisplayName = eachPresetName.lower()
   1132             restOfPresets.append((lowerDisplayName, eachPresetName))
   1133 
   1134         if restOfPresets:
   1135             restOfPresets = [ x[1] for x in localization.util.Sort(restOfPresets, key=operator.itemgetter(0)) ]
   1136             posttext, allSubPresetsChecked = GetPresetPostText(restOfPresets, self.presetsSelected)
   1137             allChecked = allChecked and allSubPresetsChecked
   1138             scrolllist.append(GetFromClass(ListGroup, {'GetSubContent': self.GetPresetSubContent,
   1139              'label': localization.GetByLabel('UI/Overview/OtherTabPresets'),
   1140              'id': ('exportOverview', 'restOfPresets'),
   1141              'groupItems': restOfPresets,
   1142              'showlen': 0,
   1143              'sublevel': 0,
   1144              'showicon': 'hide',
   1145              'state': 'locked',
   1146              'posttext': posttext}))
   1147         self.sr.scroll.Load(contentList=scrolllist)
   1148         self.checkAllCB.SetChecked(allChecked, report=False)
   1149 
   1150     def GetPresetSubContent(self, nodedata):
   1151         scrolllist = []
   1152         for eachPresetName in nodedata.groupItems:
   1153             checked = eachPresetName in self.presetsSelected
   1154             entry = GetTabPresetEntry(eachPresetName, onChangeFunc=self.OnSelectionChanged, checked=checked)
   1155             scrolllist.append(entry)
   1156 
   1157         return scrolllist
   1158 
   1159     def Export(self, *args):
   1160         if self.sr.filename.GetValue().strip() == '':
   1161             raise UserError('NameInvalid')
   1162         exportData = {}
   1163         presetList = []
   1164         allPresets = self.overviewPresetSvc.GetAllPresets()
   1165         defaultProfileNames = self.overviewPresetSvc.GetDefaultOverviewPresetNames()
   1166         for checkboxConfig in self.presetsSelected:
   1167             if checkboxConfig == 'generalSettings':
   1168                 generalSettings = self.GetGeneralSettings()
   1169                 exportData.update(generalSettings)
   1170             elif checkboxConfig == 'overviewProfile':
   1171                 overviewProfile = self.GetOverviewProfile()
   1172                 exportData['tabSetup'] = overviewProfile
   1173             else:
   1174                 presetName = checkboxConfig
   1175                 if presetName in allPresets and (self.EXPORT_EVERYTHING or presetName not in defaultProfileNames):
   1176                     presetAsDict = allPresets[presetName]
   1177                     presetAsList = GetDeterministicListFromDict(presetAsDict)
   1178                     presetList.append((presetName, presetAsList))
   1179 
   1180         if presetList:
   1181             exportData['presets'] = presetList
   1182         dirpath = os.path.join(blue.sysinfo.GetUserDocumentsDirectory(), 'EVE', 'Overview')
   1183         filepath = os.path.join(dirpath, self.sr.filename.GetValue().strip() + '.yaml')
   1184         if not os.path.exists(dirpath):
   1185             os.makedirs(dirpath)
   1186         if os.path.exists(filepath):
   1187             if prompt_player_fsd_dialog('FileExists', {}, uiconst.YESNO) != uiconst.ID_YES:
   1188                 return
   1189         with open(filepath, 'w') as yamlFile:
   1190             yaml.safe_dump(exportData, yamlFile, default_flow_style=False, allow_unicode=True)
   1191         self.CloseByUser()
   1192         prompt_player_fsd_dialog('OverviewExportDone', {'filename': filepath})
   1193 
   1194     def GetGeneralSettings(self):
   1195         return self.overviewPresetSvc.GetGeneralSettings()
   1196 
   1197     def GetOverviewProfile(self):
   1198         return self.overviewPresetSvc.GetTabSettingsForSaving()
   1199 
   1200     def OnSelectionChanged(self, c, *args):
   1201         OnOverviewCheckboxChange(c, self.presetsSelected)
   1202         self.ConstructScrollList()
   1203         ExportBaseWindow.OnSelectionChanged(self, c)
   1204 
   1205     def CheckAll(self, *args):
   1206         checkAll = self.checkAllCB.checked
   1207         ModifyPresetSelectedDict(checkAll, self.sr.scroll, self.presetsSelected)
   1208         self.ConstructScrollList()
   1209         self.ChangeExportButtonState()
   1210 
   1211     def IsAnyEntrySelected(self):
   1212         return bool(self.presetsSelected)
   1213 
   1214     def OnOverviewPresetSaved(self, *args):
   1215         self.ConstructScrollList()
   1216 
   1217 
   1218 def GetGeneralOverviewSettingsEntry(onChangeFunc, checked = True):
   1219     return GetFromClass(CheckboxEntry, {'label': localization.GetByLabel('UI/Overview/GeneralOverviewSettings'),
   1220      'checked': checked,
   1221      'cfgname': 'generalSettings',
   1222      'retval': checked,
   1223      'OnChange': onChangeFunc})
   1224 
   1225 
   1226 def GetOverviewProfileEntry(onChangeFunc, checked = True):
   1227     return GetFromClass(CheckboxEntry, {'label': localization.GetByLabel('UI/Overview/OverviewProfile'),
   1228      'checked': checked,
   1229      'cfgname': 'overviewProfile',
   1230      'retval': checked,
   1231      'OnChange': onChangeFunc,
   1232      'hint': localization.GetByLabel('UI/Overview/OverviewProfileHint')})
   1233 
   1234 
   1235 def GetTabPresetEntry(eachProfileName, onChangeFunc, checked = True):
   1236     return GetFromClass(CheckboxEntry, {'label': localization.GetByLabel('UI/Overview/TabPresetName', presetName=eachProfileName),
   1237      'checked': checked,
   1238      'cfgname': eachProfileName,
   1239      'presetName': eachProfileName,
   1240      'retval': checked,
   1241      'sublevel': 1,
   1242      'OnChange': onChangeFunc})
   1243 
   1244 
   1245 def ModifyPresetSelectedDict(checkAll, scroll, presetSelectedDict):
   1246     if checkAll:
   1247         for entry in scroll.GetNodes():
   1248             guid = entry.__guid__
   1249             if guid == 'listentry.Checkbox':
   1250                 presetSelectedDict.add(entry.cfgname)
   1251             elif guid == 'listentry.Group':
   1252                 for each in entry.groupItems:
   1253                     presetSelectedDict.add(each)
   1254 
   1255     else:
   1256         presetSelectedDict.clear()
   1257 
   1258 
   1259 def OnOverviewCheckboxChange(c, presetSelectedDict):
   1260     if c.checked:
   1261         presetSelectedDict.add(c.GetSettingsKey())
   1262     elif c.GetSettingsKey() in presetSelectedDict:
   1263         presetSelectedDict.remove(c.GetSettingsKey())
   1264 
   1265 
   1266 def GetPresetPostText(presetsList, presetSelectedDict):
   1267     checkedPresets = [ p for p in presetsList if p in presetSelectedDict ]
   1268     allChecked = len(checkedPresets) == len(presetsList)
   1269     return ('[%s/%s]' % (len(checkedPresets), len(presetsList)), allChecked)
   1270 
   1271 
   1272 def IsModuleObsolete(typeID):
   1273     return bool(sm.GetService('clientDogmaStaticSvc').GetTypeAttribute(typeID, const.attributeModuleIsObsolete))