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

multiFitWnd.py (28876B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\fitting\multiFitWnd.py
      2 from collections import defaultdict
      3 import evetypes
      4 import uthread
      5 from carbon.common.script.sys.serviceConst import ROLE_GML, ROLE_WORLDMOD
      6 from carbon.common.script.util.commonutils import StripTags
      7 from carbon.common.script.util.linkUtil import GetShowInfoLink
      8 from carbon.common.script.util.timerstuff import AutoTimer
      9 from carbonui.control.combo import Combo
     10 from carbonui.control.comboEntryData import ComboEntryData
     11 from carbonui.control.singlelineedits.singleLineEditInteger import SingleLineEditInteger
     12 from carbonui.control.singlelineedits.singleLineEditText import SingleLineEditText
     13 from carbonui.primitives.container import Container
     14 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     15 from carbonui.primitives.flowcontainer import FlowContainer
     16 from carbonui.primitives.layoutGrid import LayoutGrid
     17 from carbonui.primitives.sprite import Sprite
     18 from carbonui.primitives.transform import Transform
     19 from carbonui.util.sortUtil import SortListOfTuples
     20 from carbonui.control.button import Button
     21 from carbonui.control.checkbox import Checkbox
     22 from eve.client.script.ui.control.eveIcon import Icon
     23 from eve.client.script.ui.control.eveLabel import EveLabelMedium, EveLabelLarge, EveCaptionSmall, EveCaptionMedium, EveLabelSmall
     24 from carbonui.control.window import Window
     25 import carbonui.const as uiconst
     26 from eve.client.script.ui.util import uix
     27 from eve.client.script.ui.control.infoIcon import MoreExtraInfoInTooltip
     28 from carbonui.control.progressBar import ProgressBar
     29 from eve.client.script.ui.shared.dockedUI.controllers.stationController import StationController
     30 from eve.client.script.ui.shared.dockedUI.controllers.structureController import StructureController
     31 from eve.client.script.ui.shared.dockedUI.lobbyWnd import CheckCanAccessService
     32 from eve.common.script.sys.eveCfg import IsDocked, InStructure
     33 from globalConfig.getFunctions import GetMaxShipsToFit
     34 from inventorycommon.util import IsModularShip
     35 from localization import GetByLabel
     36 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     37 from shipfitting import Fitting
     38 from shipfitting.multiBuyUtil import BuyMultipleTypesWithQty
     39 from threadutils import throttled
     40 from utillib import KeyVal
     41 from carbonui.control.buttonIcon import ButtonIcon
     42 from carbonui.uicore import uicore
     43 NORMAL_COLOR = (1,
     44  1,
     45  1,
     46  0.75)
     47 WARNING_COLOR = (1,
     48  0,
     49  0,
     50  0.75)
     51 MAX_TOOLTIP_ENTRIES = 10
     52 REFRESH_TEXTUREPATH = 'res:/UI/Texture/Icons/105_32_22.png'
     53 MAX_TEXT_WIDTH = 300
     54 LEFT_EDGE = 10
     55 
     56 class MultiFitWnd(Window):
     57     __notifyevents__ = ['OnSessionChanged', 'OnMultipleItemChange']
     58     default_windowID = 'multiFitWnd'
     59     default_captionLabelPath = 'UI/Fitting/FittingWindow/FittingManagement/MultiFitHeader'
     60     default_iconNum = 'res:/ui/Texture/WindowIcons/fittingManagement.png'
     61     layoutColumns = 3
     62 
     63     def ApplyAttributes(self, attributes):
     64         Window.ApplyAttributes(self, attributes)
     65         self.fitting = None
     66         self.isFitting = False
     67         self.MakeUnstackable()
     68         self.canFitNum = 0
     69         self.tryingToFitNum = 1
     70         self.currentProgress = 0
     71         self.ConstructUI()
     72         fitting = attributes.fitting
     73         self.tryingToFitNum = attributes.get('qty', 1)
     74         self.LoadWindow(fitting, self.tryingToFitNum)
     75         self.SetInventoryStatus()
     76         sm.RegisterNotify(self)
     77 
     78     def ConstructUI(self):
     79         self.BuildTopParentUI()
     80         self.AddButtons()
     81         numColumns = 2
     82         self.sr.main.clipChildren = True
     83         self.layoutGrid = layoutGrid = LayoutGrid(parent=ContainerAutoSize(parent=self.GetMainArea(), align=uiconst.TOTOP), align=uiconst.TOPLEFT, columns=numColumns, cellSpacing=(4, 10))
     84         spacer = Container(pos=(0, 0, 50, 0), align=uiconst.TOPLEFT)
     85         layoutGrid.AddCell(cellObject=spacer, colSpan=1)
     86         layoutGrid.FillRow()
     87         self.BuildNumToFitUI()
     88         self.BuildWarningUI()
     89         self.BuildRefreshInventory()
     90         self.missingLayoutGrid = LayoutGrid(parent=self.layoutGrid, columns=2, cellSpacing=(4, 10))
     91         self.BuildAvailableShipsUI()
     92         self.BuildEquipmentUI()
     93         self.BuildProgressUI()
     94         self.MakeRigCbUI()
     95 
     96     def BuildTopParentUI(self):
     97         self.topParent = Container(parent=self.GetMainArea(), name='topParent', align=uiconst.TOTOP, height=100, clipChildren=True)
     98         self.shipIcon = Icon(name='shipIcon', parent=self.topParent, state=uiconst.UI_NORMAL, size=64, ignoreSize=True)
     99         self.shipIcon.GetDragData = self.GetFittingDragData
    100         self.shipIcon.OnClick = self.OpenFitting
    101         self.shipIcon.hint = GetByLabel('UI/Fitting/ShowFitting')
    102         self.techSprite = Sprite(name='techIcon', parent=self.topParent, align=uiconst.RELATIVE, width=16, height=16, idx=0)
    103         self.fitNameEdit = SingleLineEditText(name='fitNameEdit', parent=self.topParent, left=72, width=150, maxLength=20, hint=GetByLabel('UI/Common/ShipName'))
    104         top = self.fitNameEdit.top + self.fitNameEdit.height + 5
    105         self.shipNameLabel = EveLabelMedium(name='shipNameLabel', parent=self.topParent, left=77, top=top, state=uiconst.UI_NORMAL)
    106         top = self.shipNameLabel.top + 20
    107         equipmentText = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/EquipmentLocation')
    108         equipCont = Container(name='equipCont', parent=self.topParent, align=uiconst.TOTOP, top=top, padLeft=77)
    109         equipLabel = EveLabelSmall(text=equipmentText, parent=equipCont, name='equipLabel', align=uiconst.CENTERLEFT)
    110         self.equipmentLocationCombo = Combo(parent=equipCont, options=[], name='equipmentLocationCombo', pos=(equipLabel.left + equipLabel.textwidth + 6,
    111          0,
    112          0,
    113          0), callback=self.OnEquipLocationChanged, hint=GetByLabel('UI/Fitting/FittingWindow/FittingManagement/EquipmentLocationHint'))
    114         equipCont.height = max(equipLabel.height, self.equipmentLocationCombo.height)
    115 
    116     def LoadEquipCombo(self):
    117         fittingSvc = sm.GetService('fittingSvc')
    118         personalContainers = fittingSvc.FindPersonalContainers()
    119         options = []
    120         if personalContainers:
    121             cfg.evelocations.Prime({x.itemID for x in personalContainers})
    122             for eachContainer in personalContainers:
    123                 itemID = eachContainer.itemID
    124                 containerName = cfg.evelocations.Get(itemID).name or evetypes.GetName(eachContainer.typeID)
    125                 options.append((containerName.lower(), ComboEntryData(containerName, itemID)))
    126 
    127             options = SortListOfTuples(options)
    128         options.insert(0, ComboEntryData(GetByLabel('UI/Inventory/ItemHangar'), None))
    129         if [ (x.label, x.returnValue) for x in self.equipmentLocationCombo.entries ] != [ (x.label, x.returnValue) for x in options ]:
    130             self.equipmentLocationCombo.LoadOptions(options)
    131 
    132     def AddButtons(self):
    133         btnCont = FlowContainer(name='buttonParent', parent=self.sr.main, align=uiconst.TOBOTTOM, padding=6, autoHeight=True, centerContent=True, contentSpacing=uiconst.BUTTONGROUPMARGIN, idx=0)
    134         text = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/FitShips', numToFit=1)
    135         self.fitBtn = Button(parent=btnCont, label=text, func=self.DoFitShips, align=uiconst.NOALIGN)
    136         self.cancelBtn = Button(parent=btnCont, label=GetByLabel('UI/Common/Close'), func=self.Cancel, align=uiconst.NOALIGN)
    137         if sm.GetService('publicQaToolsClient').CanGiveItemForMultifit():
    138             self.spawnFitBtn = Button(parent=btnCont, label='Create Missing', func=self.GiveAllPlayer, align=uiconst.NOALIGN)
    139 
    140     def BuildNumToFitUI(self):
    141         maxShipsAllowed = GetMaxShipsToFit(sm.GetService('machoNet'))
    142         numCont = Container(name='numCont', align=uiconst.TOTOP, height=30, padLeft=LEFT_EDGE)
    143         text = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/NumShipsToFit')
    144         self.numToFitLabel = EveLabelLarge(name='numToFitLabel', parent=numCont, text=text, width=250, autoFitToText=True)
    145         left = self.numToFitLabel.left + self.numToFitLabel.textwidth + 10
    146         self.numToFitEdit = SingleLineEditInteger(name='numToFitEdit', parent=numCont, minValue=1, maxValue=maxShipsAllowed, OnChange=self.OnNumChanged, left=left, align=uiconst.CENTERLEFT)
    147         numCont.height = max(self.numToFitLabel.textheight, self.numToFitEdit.height)
    148         self.layoutGrid.AddCell(cellObject=numCont, colSpan=self.layoutGrid.columns)
    149 
    150     def BuildWarningUI(self):
    151         self.numWarningLabel = EveCaptionSmall(name='numWarningLabel', state=uiconst.UI_NORMAL, align=uiconst.CENTERTOP, width=MAX_TEXT_WIDTH, autoFitToText=True, text=GetByLabel('UI/Fitting/FittingWindow/FittingManagement/MissingShipEquipment'))
    152         self.numWarningLabel.SetRGBA(*WARNING_COLOR)
    153         self.PulseLabel(self.numWarningLabel)
    154         self.numWarningLabel.LoadTooltipPanel = self.LoadMissingTooltip
    155         self.layoutGrid.AddCell(cellObject=self.numWarningLabel, colSpan=self.layoutGrid.columns)
    156         self.moreInfoIcon = MoreExtraInfoInTooltip(parent=self.numWarningLabel.parent, align=uiconst.CENTER)
    157         self.t3Warning = EveCaptionSmall(name='t3Warning', state=uiconst.UI_NORMAL, align=uiconst.CENTERTOP, width=MAX_TEXT_WIDTH, autoFitToText=True, text=GetByLabel('UI/Fitting/FittingWindow/FittingManagement/InvalidT3Fit'))
    158         self.t3Warning.SetRGBA(*WARNING_COLOR)
    159         self.layoutGrid.AddCell(cellObject=self.t3Warning, colSpan=self.layoutGrid.columns)
    160         self.HideT3Warning()
    161         self.moreInfoIcon.display = False
    162         self.moreInfoIcon.LoadTooltipPanel = self.LoadMissingTooltip
    163         self.layoutGrid.FillRow()
    164 
    165     def BuildRefreshInventory(self):
    166         self.refreshCont = Transform(parent=self.layoutGrid, pos=(0, 0, 32, 32), align=uiconst.CENTER)
    167         self.refreshIcon = ButtonIcon(name='refreshSprite', parent=self.refreshCont, width=32, height=32, align=uiconst.CENTER, texturePath=REFRESH_TEXTUREPATH, iconSize=32, func=self.OnRefreshClicked)
    168         self.refreshIcon.hint = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/RefreshInventoryStatusHint')
    169 
    170     def OnRefreshClicked(self, *args):
    171         uthread.new(self.refreshCont.StartRotationCycle, cycles=1)
    172         self.RefreshInventory()
    173 
    174     def RefreshInventory(self):
    175         self.LoadEquipCombo()
    176         self.SetEquipmentText()
    177         self.SetInventoryStatus()
    178 
    179     def OnEquipLocationChanged(self, combo, key, val):
    180         self.RefreshInventory()
    181 
    182     def BuildAvailableShipsUI(self):
    183         self.shipCounter = EveCaptionMedium(name='shipCounter', parent=self.missingLayoutGrid, state=uiconst.UI_NORMAL, align=uiconst.CENTERRIGHT, left=4, text='000')
    184         self.shipCounter.LoadTooltipPanel = self.LoadShipCounterTooltipPanel
    185         self.shipCounter.missingDict = {}
    186         shipText = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/PackagedShipsInHangar')
    187         self.availableShipsLabel = EveLabelLarge(name='availableShipsLabel', parent=self.missingLayoutGrid, state=uiconst.UI_NORMAL, text=shipText, align=uiconst.CENTERLEFT, width=MAX_TEXT_WIDTH, autoFitToText=True)
    188         self.availableShipsLabel.hint = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/PackagedShipsInHangarHint')
    189         self.layoutGrid.FillRow()
    190 
    191     def BuildEquipmentUI(self):
    192         self.equipmentCounter = EveCaptionMedium(name='equipmentCounter', parent=self.missingLayoutGrid, state=uiconst.UI_NORMAL, align=uiconst.CENTERRIGHT, left=4, text='000')
    193         self.equipmentCounter.LoadTooltipPanel = self.LoadEqCounterTooltipPanel
    194         self.equipmentCounter.missingDict = {}
    195         self.availableEquipmentLabel = EveLabelLarge(name='availableEquipmentLabel', parent=self.missingLayoutGrid, state=uiconst.UI_NORMAL, text='', align=uiconst.CENTERLEFT, width=MAX_TEXT_WIDTH, autoFitToText=True)
    196         self.SetEquipmentText()
    197         self.layoutGrid.FillRow()
    198 
    199     def SetEquipmentText(self):
    200         locationID = self.equipmentLocationCombo.GetValue()
    201         if locationID is None:
    202             locationName = GetByLabel('UI/Inventory/ItemHangar')
    203         else:
    204             locationName = cfg.evelocations.Get(locationID).name or self.equipmentLocationCombo.GetKey()
    205         eqText = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/RoundsOfFittingsInLocation', locationName=locationName)
    206         self.availableEquipmentLabel.text = eqText
    207 
    208     def BuildProgressUI(self):
    209         self.progressCont = Container(parent=self.sr.main, height=36, align=uiconst.TOBOTTOM, padding=(10, 0, 10, 10))
    210         self.progressCounter = EveCaptionMedium(name='progressCounter', parent=self.progressCont, state=uiconst.UI_NORMAL, align=uiconst.CENTERTOP)
    211         self.progressBar = ProgressBar(parent=self.progressCont, height=10, align=uiconst.TOBOTTOM)
    212         self.progressCont.display = False
    213 
    214     def MakeRigCbUI(self):
    215         checked = settings.user.ui.Get('fitting_rigCB', True)
    216         text = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/FitRigs')
    217         self.rigCB = Checkbox(name='rigCB', text=text, OnChange=self.OnCbChanged, left=LEFT_EDGE, checked=checked, settingsPath=('user', 'ui'), settingsKey='fitting_rigCB')
    218         self.rigCB.hint = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/FitRigsHint')
    219         self.layoutGrid.AddCell(cellObject=self.rigCB, colSpan=self.layoutGrid.columns)
    220 
    221     def OnNumChanged(self, *args):
    222         self.onNumChangedTimer = AutoTimer(100, self.SetInventoryStatus)
    223 
    224     def OnCbChanged(self, *args):
    225         self.SetInventoryStatus()
    226 
    227     def OpenFitting(self, *args):
    228         sm.GetService('fittingSvc').DisplayFitting(self.fitting)
    229 
    230     def LoadWindow(self, fitting, qty = 1):
    231         self.fitting = fitting
    232         self.shipCounter.missingDict = {}
    233         self.equipmentCounter.missingDict = {}
    234         shipTypeID = fitting.shipTypeID
    235         self.shipIcon.LoadIconByTypeID(shipTypeID)
    236         uix.GetTechLevelIcon(self.techSprite, typeID=shipTypeID)
    237         self.numToFitEdit.SetValue(qty)
    238         self.fitNameEdit.SetValue(fitting.name)
    239         self.shipNameLabel.text = GetShowInfoLink(shipTypeID, evetypes.GetName(shipTypeID))
    240         self.VerifyT3Fit()
    241         self.RefreshInventory()
    242         self._ApplyFixedWindowSize()
    243         self.RegisterPositionAndSize()
    244         self.Maximize()
    245 
    246     def _ApplyFixedWindowSize(self):
    247         self.missingLayoutGrid.RefreshGridLayout()
    248         self.layoutGrid.RefreshGridLayout()
    249         layoutWidth, layoutHeight = self.layoutGrid.GetSize()
    250         newHeight = layoutHeight + self.fitBtn.height + self.progressCont.height + self.topParent.height
    251         height = max(newHeight, self.default_height)
    252         width = max(layoutWidth, self.default_width)
    253         width, height = self.GetWindowSizeForContentSize(width, height)
    254         self.SetFixedWidth(width)
    255         self.SetFixedHeight(height)
    256 
    257     def SetInventoryStatus(self):
    258         self.onNumChangedTimer = None
    259         fitting = self.fitting
    260         shipTypeID = fitting.shipTypeID
    261         fittingSvc = sm.GetService('fittingSvc')
    262         fittingObj = Fitting(fitting.fitData, None)
    263         itemTypes = fittingObj.GetQuantityByType()
    264         modulesByFlag = fittingObj.GetModulesByFlag()
    265         rigsByFlags = fittingObj.GetRigsByFlag()
    266         rigsToFit = bool(rigsByFlags)
    267         if rigsToFit:
    268             self.rigCB.display = True
    269         else:
    270             self.rigCB.display = False
    271         numToFit = self.numToFitEdit.GetValue()
    272         self.tryingToFitNum = numToFit
    273         maxAvailableFitting, missingForFullFit = self._GetMaxAvailabeAndMissingForFullFit(itemTypes, modulesByFlag, numToFit)
    274         nonSingletonShipsNumDict = fittingSvc.GetQtyInLocationByTypeIDs([shipTypeID], onlyGetNonSingletons=True)
    275         packagedShipsNum = nonSingletonShipsNumDict.get(shipTypeID, 0)
    276         canFitNum = min(packagedShipsNum, numToFit)
    277         if maxAvailableFitting is not None:
    278             canFitNum = min(canFitNum, maxAvailableFitting)
    279         self.canFitNum = canFitNum
    280         btnText = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/FitShips', numToFit=self.canFitNum)
    281         self.fitBtn.SetLabel(btnText)
    282         self.UpdateFitBtnState()
    283         missingNumShips = max(0, numToFit - packagedShipsNum)
    284         if missingNumShips:
    285             missingDict = {shipTypeID: missingNumShips}
    286         else:
    287             missingDict = {}
    288         self.shipCounter.missingDict = missingDict
    289         if missingForFullFit:
    290             missingDict = missingForFullFit
    291         else:
    292             missingDict = {}
    293         self.equipmentCounter.missingDict = missingDict
    294         if missingForFullFit or missingNumShips:
    295             missingText = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/MissingShipEquipment')
    296             self.numWarningLabel.text = missingText
    297             self.moreInfoIcon.display = True
    298             self.moreInfoIcon.left = self.numWarningLabel.textwidth / 2 + 10
    299             if sm.GetService('publicQaToolsClient').CanGiveItemForMultifit():
    300                 self.spawnFitBtn.Enable()
    301         else:
    302             self.numWarningLabel.text = ''
    303             self.numWarningLabel.height = 0
    304             self.moreInfoIcon.display = False
    305             if sm.GetService('publicQaToolsClient').CanGiveItemForMultifit():
    306                 self.spawnFitBtn.Disable()
    307         self.SetAvailabilityShipOrEq(self.shipCounter, packagedShipsNum, numToFit)
    308         self.SetAvailabilityShipOrEq(self.equipmentCounter, maxAvailableFitting, numToFit)
    309 
    310     def UpdateFitBtnState(self):
    311         if self.canFitNum < 1 or self.IsInvalidT3Fit():
    312             self.fitBtn.Disable()
    313         else:
    314             self.fitBtn.Enable()
    315 
    316     def _GetMaxAvailabeAndMissingForFullFit(self, itemTypes, modulesByFlag, numToFit):
    317         locationID = self.equipmentLocationCombo.GetValue()
    318         fittingSvc = sm.GetService('fittingSvc')
    319         qtyByTypeID = fittingSvc.GetQtyInLocationByTypeIDs(itemTypes, locationID=locationID)
    320         rigTypeIDs = {t for f, t in modulesByFlag.iteritems() if f in const.rigSlotFlags}
    321         maxAvailableFitting, missingForFullFit = fittingSvc.GetMaxAvailabeAndMissingForFullFit(True, itemTypes, numToFit, qtyByTypeID, rigTypeIDs)
    322         return (maxAvailableFitting, missingForFullFit)
    323 
    324     def SetAvailabilityShipOrEq(self, label, available, numToFit):
    325         if available is None:
    326             label.text = '-'
    327             label.SetRGBA(*NORMAL_COLOR)
    328             return
    329         label.text = available
    330         if available < numToFit:
    331             label.SetRGBA(*WARNING_COLOR)
    332         else:
    333             label.SetRGBA(*NORMAL_COLOR)
    334 
    335     def DoFitShips(self, *args):
    336         fitting = self.fitting
    337         fitRigs = self.rigCB.GetValue()
    338         numToActuallyFit = self.canFitNum
    339         fittingName = self.fitNameEdit.GetValue()
    340         if fittingName is None or fittingName.strip() == '':
    341             fittingName = fitting.name or evetypes.GetName(fitting.shipTypeID)
    342             fittingName = StripTags(fittingName)
    343         fittingSvc = sm.GetService('fittingSvc')
    344         fittingObj = Fitting(fitting.fitData, None)
    345         rigsToFit = fittingObj.GetRigsByFlag()
    346         rigsToFit = bool(rigsToFit)
    347         if fitRigs or not rigsToFit:
    348             cargoItemsByType = {}
    349         else:
    350             cargoItemsByType = defaultdict(int)
    351             for flagID, typeID in fittingObj.GetModulesByFlag().iteritems():
    352                 if flagID in const.rigSlotFlags:
    353                     cargoItemsByType[typeID] += 1
    354 
    355             cargoItemsByType = dict(cargoItemsByType)
    356         if session.stationid:
    357             stationController = StationController(itemID=session.stationid)
    358         elif InStructure():
    359             stationController = StructureController(itemID=session.structureid)
    360         else:
    361             return
    362         CheckCanAccessService('fitting', stationController)
    363         equipmentLocationID = self.equipmentLocationCombo.GetValue()
    364         _, missingForFullFit = self._GetMaxAvailabeAndMissingForFullFit(fittingObj.GetQuantityByType(), fittingObj.GetModulesByFlag(), numToActuallyFit)
    365         if missingForFullFit:
    366             self.SetInventoryStatus()
    367             prompt_player_fsd_dialog('uiwarning03')
    368             return
    369         try:
    370             fitInfo = fittingObj.GetKeyValForApplyingFit()
    371             self.PrepareForMultiFitCall()
    372             fittingSvc.DoFitManyShips(fitting.shipTypeID, fitInfo, cargoItemsByType, fitRigs, fittingName, numToActuallyFit, itemContainerID=equipmentLocationID)
    373         finally:
    374             uthread.new(self.ResetUIAfterFitting)
    375 
    376     def PrepareForMultiFitCall(self):
    377         self.fitBtn.Disable()
    378         self.cancelBtn.Disable()
    379         self.isFitting = True
    380         self.currentProgress = 0
    381         self.progressCounter.text = self.currentProgress
    382         self.progressCont.display = True
    383         self.layoutGrid.Disable()
    384         self.layoutGrid.opacity = 0.2
    385         sm.RegisterForNotifyEvent(self, 'OnItemChange')
    386 
    387     def ResetUIAfterFitting(self):
    388         sm.UnregisterForNotifyEvent(self, 'OnItemChange')
    389         self.isFitting = False
    390         self.currentProgress = 0
    391         uicore.animations.BlinkOut(self.progressCont, startVal=0.0, endVal=1.0, duration=0.5, loops=3, sleep=True)
    392         self.progressCont.display = False
    393         self.progressCounter.text = self.currentProgress
    394         self.cancelBtn.Enable()
    395         self.layoutGrid.Enable()
    396         self.layoutGrid.opacity = 1.0
    397         self.SetInventoryStatus()
    398 
    399     def Cancel(self, *args):
    400         self.CloseByUser()
    401 
    402     def GetFittingDragData(self):
    403         entry = KeyVal()
    404         entry.fitting = self.fitting
    405         entry.label = self.fitting.name
    406         entry.displayText = self.fitting.name
    407         entry.__guid__ = 'listentry.FittingEntry'
    408         return [entry]
    409 
    410     def LoadMissingTooltip(self, tooltipPanel, *args):
    411         text = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/MissingItems', numToFit=self.tryingToFitNum, fittingName=self.fitting.name)
    412         tooltipPanel.AddLabelLarge(text=text, padBottom=8)
    413         self.LoadShipCounterTooltipPanel(tooltipPanel, singleGroupShowing=False)
    414         self.LoadEqCounterTooltipPanel(tooltipPanel, singleGroupShowing=False)
    415         missingDict = {}
    416         missingDict.update(self.shipCounter.missingDict)
    417         missingDict.update(self.equipmentCounter.missingDict)
    418         self.AddBuyAllBtn(tooltipPanel, missingDict)
    419 
    420     def LoadShipCounterTooltipPanel(self, tooltipPanel, *args, **kwargs):
    421         missingDict = self.shipCounter.missingDict
    422         if not missingDict:
    423             return
    424         singleGroupShowing = kwargs.get('singleGroupShowing', True)
    425         text = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/MissingShips', numToFit=self.tryingToFitNum, fittingName=self.fitting.name)
    426         return self.LoadCounterTooltip(tooltipPanel, missingDict, text, singleGroupShowing)
    427 
    428     def LoadEqCounterTooltipPanel(self, tooltipPanel, *args, **kwargs):
    429         missingDict = self.equipmentCounter.missingDict
    430         if not missingDict:
    431             return
    432         singleGroupShowing = kwargs.get('singleGroupShowing', True)
    433         text = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/MissingEquipment', numToFit=self.tryingToFitNum, fittingName=self.fitting.name)
    434         self.LoadCounterTooltip(tooltipPanel, missingDict, text, singleGroupShowing)
    435 
    436     def LoadCounterTooltip(self, tooltipPanel, missingDict, text, singleGroupShowing = True):
    437         tooltipPanel.LoadGeneric1ColumnTemplate()
    438         tooltipPanel.state = uiconst.UI_NORMAL
    439         if singleGroupShowing:
    440             tooltipPanel.AddLabelLarge(text=text, padBottom=8)
    441         typeList = []
    442         for eachTypeID, eachQty in missingDict.iteritems():
    443             typeName = evetypes.GetName(eachTypeID)
    444             typeList.append((typeName.lower(), (eachTypeID, eachQty)))
    445 
    446         typeList = SortListOfTuples(typeList)
    447         for eachTypeID, eachQty in typeList[:MAX_TOOLTIP_ENTRIES]:
    448             typeCont = TooltipEntry(parent=tooltipPanel, typeID=eachTypeID, qty=eachQty)
    449 
    450         if len(typeList) > MAX_TOOLTIP_ENTRIES:
    451             numItemsNotDisplayed = len(typeList) - MAX_TOOLTIP_ENTRIES
    452             text = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/MoreItemTypesMissing', numMoreItems=numItemsNotDisplayed)
    453             tooltipPanel.AddLabelMedium(text=text, align=uiconst.CENTERLEFT)
    454         if singleGroupShowing:
    455             self.AddBuyAllBtn(tooltipPanel, missingDict)
    456 
    457     def AddBuyAllBtn(self, tooltipPanel, missingDict):
    458 
    459         def BuyAll(*args):
    460             BuyMultipleTypesWithQty(missingDict)
    461 
    462         Button(parent=tooltipPanel, label=GetByLabel('UI/Market/MarketQuote/BuyAll'), func=BuyAll, align=uiconst.CENTER)
    463         if session.role & ROLE_WORLDMOD == ROLE_WORLDMOD:
    464             Button(parent=tooltipPanel, label='GM: Give all', func=self.GiveAllGM, align=uiconst.CENTERRIGHT, args=(missingDict,))
    465         if session.role & ROLE_GML == ROLE_GML:
    466             Button(parent=tooltipPanel, label='GM: Load me all', func=self.LoadAllGM, align=uiconst.CENTERRIGHT, args=(missingDict,))
    467 
    468     def GiveAllGM(self, missingDict):
    469         from eve.client.script.ui.shared.fittingScreen.missingItemsPopup import GiveAllGM
    470         GiveAllGM(missingDict)
    471 
    472     def LoadAllGM(self, missingDict):
    473         from eve.client.script.ui.shared.fittingScreen.missingItemsPopup import LoadAllGM
    474         LoadAllGM(missingDict)
    475 
    476     def GiveAllPlayer(self, *args):
    477         self.SetInventoryStatus()
    478         missingDict = {}
    479         missingDict.update(self.shipCounter.missingDict)
    480         missingDict.update(self.equipmentCounter.missingDict)
    481         commandString = ''
    482         for typeID, qty in missingDict.iteritems():
    483             commandString += '{typeID}|{qty},'.format(typeID=typeID, qty=qty)
    484 
    485         commandString = commandString[:-1]
    486         sm.GetService('publicQaToolsClient').SlashCmd('/giveitem {}'.format(commandString))
    487 
    488     def OnItemChange(self, item, change, location):
    489         if item.typeID != self.fitting.shipTypeID:
    490             return
    491         if const.ixSingleton in change:
    492             self.currentProgress += 1
    493             self.progressCounter.text = '%s / %s' % (self.currentProgress, self.canFitNum)
    494 
    495     def OnSessionChanged(self, isRemote, sess, change):
    496         if not IsDocked():
    497             self.CloseByUser()
    498 
    499     def PulseLabel(self, label):
    500         uicore.animations.FadeTo(label, startVal=0.65, endVal=0.9, duration=1.0, loops=uiconst.ANIM_REPEAT, curveType=uiconst.ANIM_WAVE)
    501 
    502     def OnMultipleItemChange(self, *args):
    503         if self.isFitting:
    504             return
    505         self.RefreshOnItemChanged_throttled()
    506 
    507     @throttled(0.5)
    508     def RefreshOnItemChanged_throttled(self):
    509         self.RefreshInventory()
    510 
    511     def VerifyT3Fit(self):
    512         isInvalidT3Fit = self.IsInvalidT3Fit()
    513         if isInvalidT3Fit:
    514             self.t3Warning.text = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/InvalidT3Fit')
    515         else:
    516             self.HideT3Warning()
    517 
    518     def IsInvalidT3Fit(self):
    519         fitting = self.fitting
    520         if not fitting:
    521             self.HideT3Warning()
    522             return False
    523         shipTypeID = fitting.shipTypeID
    524         if not IsModularShip(shipTypeID):
    525             return False
    526         clientDogmaStaticSvc = sm.GetService('clientDogmaStaticSvc')
    527         subsystemSlotFlagsMissing = const.subsystemSlotFlags[:]
    528         for typeID, flagID, qty in fitting.fitData:
    529             if flagID in subsystemSlotFlagsMissing:
    530                 isObsolete = bool(clientDogmaStaticSvc.GetTypeAttribute(typeID, const.attributeModuleIsObsolete))
    531                 if not isObsolete:
    532                     subsystemSlotFlagsMissing.remove(flagID)
    533                 if clientDogmaStaticSvc.GetTypeAttribute2(typeID, const.attributeFitsToShipType) != shipTypeID:
    534                     return True
    535 
    536         return bool(subsystemSlotFlagsMissing)
    537 
    538     def HideT3Warning(self):
    539         self.t3Warning.text = ''
    540         self.t3Warning.height = 0
    541 
    542 
    543 class TooltipEntry(Container):
    544     default_height = 32
    545     default_align = uiconst.TOPLEFT
    546 
    547     def ApplyAttributes(self, attributes):
    548         Container.ApplyAttributes(self, attributes)
    549         typeID = attributes.typeID
    550         qty = attributes.qty
    551         iconPadding = 1 * const.defaultPadding
    552         typeIcon = Icon(name='typeIcon', parent=self, state=uiconst.UI_NORMAL, size=32, left=iconPadding, ignoreSize=True, typeID=typeID)
    553         techIcon = uix.GetTechLevelIcon(typeID=typeID)
    554         if techIcon:
    555             techIcon.left = iconPadding
    556             techIcon.SetParent(self, idx=0)
    557         typeName = evetypes.GetName(typeID)
    558         link = '<url="showinfo:%s">%s</url>' % (typeID, typeName)
    559         text = '%sx %s' % (qty, link)
    560         left = iconPadding * 2 + typeIcon.width + 10
    561         label = EveLabelMedium(parent=self, left=left, text=text, state=uiconst.UI_NORMAL, align=uiconst.CENTERLEFT)
    562         self.width = label.left + label.textwidth + 10