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

contractentry.py (36367B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\neocom\contracts\contractentry.py
      2 import blue
      3 import carbonui.const as uiconst
      4 import eveformat
      5 import evetypes
      6 import localization
      7 from carbon.common.script.sys.serviceConst import ROLE_GML
      8 from carbon.common.script.util.format import FmtAmt, FmtDate
      9 from carbonui.control.contextMenu.menuData import MenuData
     10 from carbonui.control.contextMenu.menuEntryData import MenuEntryData
     11 from carbonui.control.scrollentries import SE_BaseClassCore
     12 from carbonui.primitives.container import Container
     13 from eve.client.script.ui.control import eveIcon, eveLabel
     14 from carbonui.control.checkbox import Checkbox
     15 from player_messaging.client.ui_message import message_player
     16 from eve.client.script.ui.util import uix
     17 from carbon.client.script.environment.AudioUtil import PlaySound
     18 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     19 from carbonui.uicore import uicore
     20 from eve.client.script.ui.control.entries.item import Item
     21 from eve.client.script.util.contractutils import GetContractIcon, GetContractTimeLeftText, FmtISKWithDescription
     22 from eve.common.lib import appConst as const
     23 from eve.common.script.sys import idCheckers
     24 from eve.common.script.util.contractscommon import GetContractTitle, GetContractTypeText, GetCurrentBid
     25 from eve.client.script.ui.control.itemIcon import ItemIcon
     26 from eve.client.script.ui.shared.tooltip.blueprints import AddBlueprintInfo
     27 from eve.client.script.ui.shared.tooltip.dynamicItem import AddDynamicItemAttributes
     28 from eve.common.script.util import contractscommon as cc
     29 from eveexceptions import UserError
     30 from eveprefs import prefs
     31 from eveservices.menu import GetMenuService
     32 from menu import MenuLabel
     33 
     34 class ContractStartPageEntry(ContainerAutoSize):
     35     default_padTop = 8
     36     default_padBottom = 8
     37     default_alignMode = uiconst.TOTOP
     38 
     39     def ApplyAttributes(self, attributes):
     40         super(ContractStartPageEntry, self).ApplyAttributes(attributes)
     41         node = attributes.node
     42         self.icon = eveIcon.Icon(parent=self, size=32, ignoreSize=True, left=4)
     43         self.header = eveLabel.EveLabelLarge(parent=self, padLeft=50, state=uiconst.UI_NORMAL, align=uiconst.TOTOP)
     44         self.text = eveLabel.EveLabelMedium(parent=self, padLeft=50, state=uiconst.UI_NORMAL, align=uiconst.TOTOP)
     45         if node.isSmall:
     46             self.header.Hide()
     47             self.icon.SetSize(16, 16)
     48             self.icon.LoadIcon(node.icon, ignoreSize=True)
     49             if node.header:
     50                 self.text.text = node.header + '<br>' + node.text
     51             else:
     52                 self.text.text = node.text
     53         else:
     54             self.header.state = uiconst.UI_NORMAL
     55             self.header.text = node.header
     56             self.text.text = node.text
     57             self.icon.SetSize(32, 32)
     58             self.icon.LoadIcon(node.icon, ignoreSize=True)
     59 
     60 
     61 class ContractEntry(SE_BaseClassCore):
     62     __guid__ = 'listentry.ContractEntry'
     63     isDragObject = True
     64     OnSelectCallback = None
     65 
     66     def GetMenu(self):
     67         m = []
     68         selectedNodes = self.sr.node.scroll.GetSelectedNodes(self.sr.node)
     69         if len(selectedNodes) > 1:
     70             return self.GetMenuForMultipleNodes(selectedNodes)
     71         node = selectedNodes[0]
     72         c = node.contract
     73         m.append((MenuLabel('UI/Contracts/ContractEntry/ViewContract'), self.ViewContract, (node,)))
     74         if c.startStationID:
     75             typeID = self.GetStationType(c.startStationID)
     76             m += [(MenuLabel('UI/Contracts/ContractEntry/PickupStation'), ('isDynamic', GetMenuService().CelestialMenu, (c.startStationID,
     77                 None,
     78                 None,
     79                 typeID)))]
     80         if c.endStationID and c.endStationID != c.startStationID:
     81             typeID = self.GetStationType(c.endStationID)
     82             m += [(MenuLabel('UI/Contracts/ContractEntry/DropOffStation'), ('isDynamic', GetMenuService().CelestialMenu, (c.endStationID,
     83                 None,
     84                 None,
     85                 typeID)))]
     86         if c.type == const.conTypeAuction and c.issuerID != session.charid and c.status == const.conStatusOutstanding and c.dateExpired > blue.os.GetWallclockTime():
     87             m.append((MenuLabel('UI/Contracts/ContractEntry/PlaceBid'), self.PlaceBid, (node,)))
     88         if node.Get('canDismiss', False):
     89             m.append((MenuLabel('UI/Contracts/ContractEntry/Dismiss'), self.Dismiss, (node,)))
     90         if node.Get('canGetItems', False):
     91             m.append((MenuLabel('UI/Contracts/ContractEntry/GetItems'), self.GetItems, (node,)))
     92         if node.Get('canGetMoney', False):
     93             m.append((MenuLabel('UI/Contracts/ContractEntry/GetMoney'), self.GetMoney, (node,)))
     94         if node.Get('canIgnore', True) and c.issuerID != session.charid:
     95             m.append((MenuLabel('UI/Contracts/ContractEntry/IgnoreFromThisIssuer'), self.AddIgnore, (node,)))
     96         filtStatus = node.status
     97         if self._OfferForgetAuctionContract(c, node.forCorp, filtStatus):
     98             m += [(MenuLabel('UI/Contracts/ContractEntry/ForgetContract'), sm.GetService('contracts').ForgetAuctionContract, (c.contractID, node.forCorp))]
     99         typeID = node.Get('typeID', None)
    100         if typeID and node.contract.type != const.conTypeCourier:
    101             m.append(None)
    102             m.append((MenuLabel('UI/Commands/ShowInfo'), sm.GetService('info').ShowInfo, (typeID,)))
    103             if evetypes.GetMarketGroupID(typeID) is not None:
    104                 sm.GetService('marketutils').AddMarketDetailsMenuOption(m, typeID)
    105         m.append(None)
    106         if c.issuerID == session.charid:
    107             m.append((MenuLabel('UI/Contracts/ContractEntry/Delete'), self.Delete, (node,)))
    108         if session.role & ROLE_GML > 0:
    109             m.append(('GM - contractID: %s' % node.contract.contractID, blue.pyos.SetClipboardData, (str(node.contract.contractID),)))
    110             m.append(('GM - issuerID: %s' % node.contract.issuerID, blue.pyos.SetClipboardData, (str(node.contract.issuerID),)))
    111             m.append(('GM - Expire now', self._ExpireContract, (node.contract.contractID,)))
    112         return m
    113 
    114     def _OfferForgetAuctionContract(self, contract, forCorp, filtStatus):
    115         if filtStatus != const.conStatusRequiresAttention:
    116             return False
    117         if contract.type != const.conTypeAuction:
    118             return False
    119         if contract.status not in (const.conStatusOutstanding, const.conStatusFinishedIssuer, const.conStatusFinishedContractor):
    120             return False
    121         if contract.dateExpired > blue.os.GetWallclockTime():
    122             return False
    123         if forCorp:
    124             isContractMgr = session.corprole & const.corpRoleContractManager
    125             if not isContractMgr:
    126                 return False
    127             if contract.issuerID == session.corpid:
    128                 return False
    129         elif contract.issuerID == session.charid:
    130             return False
    131         contractDetails = sm.GetService('contracts').GetContract(contract.contractID)
    132         if not contractDetails.bids:
    133             return False
    134         highestBidderHasClaimed = contract.status == const.conStatusFinishedContractor
    135         highBidder = contractDetails.bids[0].bidderID
    136         if forCorp:
    137             if highBidder == session.corpid and not highestBidderHasClaimed:
    138                 return False
    139         elif highBidder == session.charid and not highestBidderHasClaimed:
    140             return False
    141         return True
    142 
    143     def GetMenuForMultipleNodes(self, nodes):
    144         m = MenuData()
    145         isContractMgr = session.corprole & const.corpRoleContractManager
    146         mySelectedNodes = [ node for node in nodes if node.contract.issuerID == session.charid or node.contract.issuerCorpID == session.corpid and node.contract.forCorp and isContractMgr ]
    147         if not mySelectedNodes:
    148             hint = localization.GetByLabel('UI/Contracts/ContractEntry/ContractsNotIssuedByCharacter')
    149             m.append(MenuEntryData(MenuLabel('UI/Contracts/ContractEntry/Delete'), isEnabled=False, hint=hint))
    150             return m
    151         if len(nodes) != len(mySelectedNodes):
    152             text = localization.GetByLabel('UI/Contracts/ContractEntry/NoAllContractsNotIssuedByCharacter')
    153             message_player(text)
    154             self.sr.node.scroll.SelectNodes(mySelectedNodes)
    155         if len(mySelectedNodes) == 1:
    156             m.AddEntry(MenuLabel('UI/Contracts/ContractEntry/Delete'), lambda : self.Delete(mySelectedNodes[0]))
    157         elif len(mySelectedNodes) > 1:
    158             ml = MenuLabel('UI/Contracts/ContractEntry/DeleteMultipleContracts', {'numToDelete': len(mySelectedNodes)})
    159             m.append((ml, lambda : self.DeteleMultiple(mySelectedNodes)))
    160         return m
    161 
    162     @staticmethod
    163     def GetStationType(stationID):
    164         if idCheckers.IsStation(stationID):
    165             return sm.GetService('ui').GetStationStaticInfo(stationID).stationTypeID
    166         return sm.GetService('structureDirectory').GetStructureInfo(stationID).typeID
    167 
    168     def NoEvent(self, *args):
    169         pass
    170 
    171     def _ExpireContract(self, contractID):
    172         sm.ProxySvc('contractProxy').GM_ExpireContract(contractID)
    173 
    174     def FindMore(self, typeID, *args):
    175         sm.GetService('contracts').OpenAvailableTab(7, reset=True, typeID=typeID)
    176 
    177     def ViewContract(self, node = None, *args):
    178         node = node if node != None else self.sr.node
    179         sm.GetService('contracts').ShowContract(node.contract.contractID)
    180 
    181     def Delete(self, node = None, *args):
    182         node = node if node != None else self.sr.node
    183         sm.GetService('contracts').DeleteContract(node.contract.contractID)
    184 
    185     def DeteleMultiple(self, nodes):
    186         contractIDs = [ node.contract.contractID for node in nodes ]
    187         sm.GetService('contracts').DeleteMultipleContracts(contractIDs)
    188 
    189     def PlaceBid(self, node = None, *args):
    190         node = node if node != None else self.sr.node
    191         if sm.GetService('contracts').PlaceBid(node.contract.contractID):
    192             self.Reload()
    193 
    194     def Dismiss(self, node = None, *args):
    195         node = node if node != None else self.sr.node
    196         if sm.GetService('contracts').DeleteNotification(node.contractID, node.Get('forCorp', False)):
    197             node.scroll.RemoveEntries([node])
    198 
    199     def GetItems(self, node = None, *args):
    200         node = node if node != None else self.sr.node
    201         if sm.GetService('contracts').FinishAuction(node.contract.contractID, isIssuer=False):
    202             node.scroll.RemoveEntries([node])
    203 
    204     def GetMoney(self, node = None, *args):
    205         node = node if node != None else self.sr.node
    206         if sm.GetService('contracts').FinishAuction(node.contract.contractID, isIssuer=True):
    207             node.scroll.RemoveEntries([node])
    208 
    209     def AddIgnore(self, node = None, *args):
    210         node = node if node != None else self.sr.node
    211         issuerID = node.contract.issuerID
    212         if node.contract.forCorp:
    213             issuerID = node.contract.issuerCorpID
    214         sm.GetService('contracts').AddIgnore(issuerID)
    215 
    216     def OnDblClick(self, *args):
    217         PlaySound(uiconst.SOUND_BUTTON_CLICK)
    218         self.ViewContract(*args)
    219 
    220     def GetDragData(self, *args):
    221         if self and not self.destroyed:
    222             return self.sr.node.scroll.GetSelectedNodes(self.sr.node)
    223 
    224     def OnSelect(self, *args):
    225         if getattr(self, 'OnSelectCallback', None):
    226             self.OnSelectCallback(*args)
    227 
    228     def _OnClose(self, *args):
    229         self.updatetimer = None
    230 
    231     def OnClick(self, *args):
    232         self.sr.node.scroll.SelectNode(self.sr.node)
    233         self.OnSelect(self)
    234 
    235     def Reload(self, *args):
    236         contract = sm.GetService('contracts').GetContract(self.sr.node.contractID)
    237         self.sr.node.contract = contract.contract
    238         self.sr.node.contractItems = contract.items
    239         self.sr.node.bids = contract.bids
    240         self.Load(self.sr.node)
    241 
    242 
    243 class ContractEntrySmall(ContractEntry):
    244     __guid__ = 'listentry.ContractEntrySmall'
    245 
    246     def Startup(self, *etc):
    247         self.sr.label = eveLabel.EveLabelMedium(text='', parent=self, left=5, state=uiconst.UI_DISABLED, color=None, maxLines=1, align=uiconst.CENTERLEFT)
    248         self.sr.line = Container(name='lineparent', align=uiconst.TOBOTTOM, parent=self, height=1)
    249 
    250     def Load(self, node):
    251         self.sr.node = node
    252         c = node.contract
    253         self.sr.node.contractID = c.contractID
    254         self.sr.node.solarSystemID = c.startSolarSystemID
    255         items = node.contractItems
    256         name = GetContractTitle(c, items)
    257         self.sr.label.text = self.sr.node.label = node.label
    258         self.OnSelectCallback = node.Get('callback', None)
    259         if node.Get('selected', 0):
    260             self.Select()
    261         else:
    262             self.Deselect()
    263         self.state = uiconst.UI_NORMAL
    264         self.sr.claiming = 0
    265         self.sr.node.name = name
    266 
    267     def LoadTooltipPanel(self, tooltipPanel, *args):
    268         tooltipPanel.LoadGeneric1ColumnTemplate()
    269         node = self.sr.node
    270         wrapWidth = 250
    271         c = node.contract
    272         items = node.contractItems
    273         jmps = None
    274         if c.startSolarSystemID > 0:
    275             n = sm.GetService('clientPathfinderService').GetAutopilotJumpCount(session.solarsystemid2, c.startSolarSystemID)
    276             if c.startStationID in {session.stationid, session.structureid}:
    277                 jmps = localization.GetByLabel('UI/Generic/CurrentStation')
    278             elif c.startSolarSystemID == session.solarsystemid2:
    279                 jmps = localization.GetByLabel('UI/Generic/CurrentSystem')
    280             elif n == 1:
    281                 jmps = localization.GetByLabel('UI/Contracts/OneJumpAway')
    282             elif n <= cc.NUMJUMPS_UNREACHABLE:
    283                 jmps = localization.GetByLabel('UI/Contracts/ContractEntry/NumJumpsAway', numJumps=n)
    284             else:
    285                 jmps = localization.GetByLabel('UI/Generic/NoGateToGateRoute')
    286         hintLine = localization.GetByLabel('UI/Contracts/ContractEntry/ContractTypeWithType', contractType=GetContractTypeText(c.type))
    287         tooltipPanel.AddLabelMedium(text=hintLine, wrapWidth=wrapWidth)
    288         if c.title != '':
    289             hintLine = localization.GetByLabel('UI/Contracts/ContractEntry/IssuerDescriptionWithDescription', description=c.title)
    290             tooltipPanel.AddLabelMedium(text=hintLine, wrapWidth=wrapWidth)
    291         if jmps:
    292             hintLine = localization.GetByLabel('UI/Contracts/ContractEntry/ContractLocation', location=c.startSolarSystemID, numJumpsInfo=jmps)
    293         else:
    294             labelText = localization.GetByLabel('UI/Contracts/ContractEntry/MenuLocation')
    295             hintLine = localization.GetByLabel('UI/Contracts/ContractsService/BoldGenericLabel', labelText=labelText)
    296         tooltipPanel.AddLabelMedium(text=hintLine, wrapWidth=wrapWidth)
    297         if c.assigneeID > 0:
    298             labelText = localization.GetByLabel('UI/Contracts/ContractEntry/PrivateContract')
    299             boldLabelText = localization.GetByLabel('UI/Contracts/ContractsService/BoldGenericLabel', labelText=labelText)
    300             tooltipPanel.AddLabelMedium(text=boldLabelText, wrapWidth=wrapWidth)
    301         if c.type in [const.conTypeAuction, const.conTypeItemExchange] and len(items) > 0:
    302             itemList = []
    303             itemReqList = []
    304             numItems = 0
    305             numItemsReq = 0
    306             for e in items:
    307                 if e.inCrate:
    308                     itemInfo = cfg.FormatConvert(const.UE_TYPEIDANDQUANTITY, e.itemTypeID, max(1, e.quantity))
    309                     itemList.append(itemInfo)
    310                     numItems += 1
    311                 else:
    312                     itemReqInfo = cfg.FormatConvert(const.UE_TYPEIDANDQUANTITY, e.itemTypeID, max(1, e.quantity))
    313                     itemReqList.append(itemReqInfo)
    314                     numItemsReq += 1
    315 
    316             if len(itemList) >= 2:
    317                 itemList.append(localization.GetByLabel('UI/Common/MoreWithTrailing'))
    318             if len(itemReqList) >= 2:
    319                 itemReqList.append(localization.GetByLabel('UI/Common/MoreWithTrailing'))
    320             if itemList:
    321                 itemsText = localization.GetByLabel('UI/Contracts/ContractEntry/ItemsWithItemList', itemsString='')
    322                 tooltipPanel.AddLabelMedium(text=itemsText, wrapWidth=wrapWidth)
    323                 for eachItem in itemList:
    324                     tooltipPanel.AddLabelMedium(text=eachItem, wrapWidth=250, padLeft=10)
    325 
    326             else:
    327                 itemsText = localization.GetByLabel('UI/Contracts/ContractEntry/ItemsWithItemList', itemsString=localization.GetByLabel('UI/Contracts/ContractEntry/NoneParen'))
    328                 tooltipPanel.AddLabelMedium(text=itemsText, wrapWidth=wrapWidth)
    329             if len(itemReqList) > 0:
    330                 itemsReqText = localization.GetByLabel('UI/Contracts/ContractEntry/ItemsRequiredWithItemList', reqItemsString='')
    331                 tooltipPanel.AddLabelMedium(text=itemsReqText)
    332                 for eachItem in itemReqList:
    333                     tooltipPanel.AddLabelMedium(text=eachItem, wrapWidth=wrapWidth, padLeft=10)
    334 
    335             if len(itemList) >= 2 or len(itemReqList) >= 2:
    336                 tooltipPanel.AddLabelMedium(text=localization.GetByLabel('UI/Contracts/ContractEntry/OpenForItems'), wrapWidth=250)
    337 
    338     def GetHeight(_self, *args):
    339         node, width = args
    340         node.height = 19
    341         return node.height
    342 
    343     @classmethod
    344     def GetCopyData(cls, node):
    345         return node.label
    346 
    347 
    348 class ContractItemSelect(Item):
    349     __guid__ = 'listentry.ContractItemSelect'
    350 
    351     def ApplyAttributes(self, attributes):
    352         Item.ApplyAttributes(self, attributes)
    353         self.sr.overlay = Container(name='overlay', align=uiconst.TOPLEFT, parent=self, height=1)
    354         self.sr.tlicon = None
    355 
    356     def Startup(self, *args):
    357         Item.Startup(self, args)
    358         self.sr.checkbox = Checkbox(align=uiconst.TOPLEFT, state=uiconst.UI_DISABLED, pos=(6, 4, 0, 0), callback=self.CheckBoxChange, parent=self, idx=0)
    359 
    360     def Load(self, args):
    361         Item.Load(self, args)
    362         data = self.sr.node
    363         self.sr.checkbox.SetChecked(data.checked, 0)
    364         self.sr.icon.left = 24
    365         self.sr.label.left = self.sr.icon.left + self.sr.icon.width + 4
    366         self.sr.icon.state = uiconst.UI_PICKCHILDREN
    367 
    368     def CheckBoxChange(self, *args):
    369         self.sr.node.checked = self.sr.checkbox.checked
    370         self.sr.node.OnChange(self.sr.checkbox.GetValue(), self.sr.node.itemData)
    371 
    372     def OnClick(self, *args):
    373         shift = uicore.uilib.Key(uiconst.VK_SHIFT)
    374         lastSelected = self.sr.node.scroll.sr.lastSelected
    375         if lastSelected is None:
    376             shift = 0
    377         idx = self.sr.node.idx
    378         self.sr.checkbox.ToggleState()
    379         isChecked = self.sr.checkbox.GetValue()
    380         if shift > 0:
    381             r = [lastSelected, self.sr.node.idx]
    382             r.sort()
    383             for node in self.sr.node.scroll.GetNodes():
    384                 if node.idx > r[0] and node.idx <= r[1]:
    385                     node.checked = isChecked
    386                     if node.panel:
    387                         node.OnChange(node.panel.sr.checkbox)
    388                         node.panel.sr.checkbox.SetChecked(isChecked)
    389 
    390         self.sr.node.scroll.sr.lastSelected = idx
    391 
    392     def GetHeight(self, *args):
    393         node, width = args
    394         node.height = 28
    395         return node.height
    396 
    397     def GetMenu(self):
    398         m = []
    399         if self.sr.node.quantity > 1:
    400             m.append((MenuLabel('UI/Generic/SplitStack'), self.SplitStack))
    401         m.extend(GetMenuService().GetMenuFromItemIDTypeID(self.sr.node.itemID, self.sr.node.typeID))
    402         return m
    403 
    404     def SplitStack(self):
    405         maxQty = self.sr.node.quantity
    406         msg = localization.GetByLabel('UI/Common/HowManyItems')
    407         ret = uix.QtyPopup(int(maxQty), 1, 1, msg)
    408         if ret:
    409             sm.GetService('contracts').SplitStack(self.sr.node.stationID, self.sr.node.itemID, ret['qty'], self.sr.node.forCorp, self.sr.node.flag)
    410 
    411 
    412 class ContractEntrySearch(ContractEntry):
    413     __guid__ = 'listentry.ContractEntrySearch'
    414     iconSize = 32
    415     iconMargin = 2
    416     lineHeight = 10
    417     labelMargin = 6
    418     reqItemEntryHeight = 16
    419     entryHeight = 10
    420 
    421     def ApplyAttributes(self, attributes):
    422         SE_BaseClassCore.ApplyAttributes(self, attributes)
    423         self.sr.contractParent = Container(parent=self, name='contractParent', align=uiconst.TOLEFT, state=uiconst.UI_PICKCHILDREN, padTop=2)
    424         self.sr.contractIconParent = Container(parent=self.sr.contractParent, name='contractIconParent', align=uiconst.TOLEFT, width=self.iconSize + 5)
    425         self.sr.icon = ItemIcon(parent=self.sr.contractIconParent, pos=(2, 2, 32, 32), align=uiconst.TOPLEFT, state=uiconst.UI_DISABLED)
    426         subPar = Container(parent=self.sr.contractParent, name='contractLabelClipper', state=uiconst.UI_DISABLED, align=uiconst.TOALL, clipChildren=True, padLeft=2)
    427         self.sr.contractLabel = eveLabel.EveLabelMedium(parent=subPar, left=self.labelMargin, align=uiconst.TOTOP, padRight=const.defaultPadding)
    428 
    429     def Load(self, node):
    430         self.sr.node = node
    431         c = node.contract
    432         numJumps = node.numJumps
    433         self.sr.node.contractID = c.contractID
    434         self.sr.node.solarSystemID = c.startSolarSystemID
    435         self.sr.node.name = GetContractTitle(c, node.contractItems)
    436         if prefs.GetValue('contractsSimpleView', 0):
    437             self.sr.icon.state = uiconst.UI_HIDDEN
    438             self.sr.contractIconParent.width = 6
    439         else:
    440             self.sr.icon.state = uiconst.UI_DISABLED
    441             self.sr.contractIconParent.width = self.iconSize + 5
    442         label = self.GetContractLabel()
    443         self.sr.contractLabel.SetText(label)
    444         if c.type in [const.conTypeAuction, const.conTypeItemExchange] and len(node.contractItems) == 1:
    445             typeID = node.contractItems[0].itemTypeID
    446             self.sr.icon.SetTypeID(typeID, isCopy=getattr(node.contractItems[0], 'copy', False))
    447         else:
    448             self.sr.icon.SetTexturePath(GetContractIcon(node.contract.type))
    449         numJumpsTxt = ''
    450         if numJumps == 0:
    451             if c.startStationID in {session.stationid, session.structureid}:
    452                 numJumpsTxt = localization.GetByLabel('UI/Generic/CurrentStation')
    453             elif c.startSolarSystemID == session.solarsystemid2:
    454                 numJumpsTxt = localization.GetByLabel('UI/Generic/CurrentSystem')
    455         elif numJumps == 1:
    456             numJumpsTxt = localization.GetByLabel('UI/Contracts/OneJumpAway')
    457         elif numJumps <= cc.NUMJUMPS_UNREACHABLE:
    458             numJumpsTxt = localization.GetByLabel('UI/Contracts/ContractEntry/NumJumpsAway', numJumps=numJumps)
    459         else:
    460             numJumpsTxt = '<color=0xffff6666>%s</color>' % localization.GetByLabel('UI/Generic/NoGateToGateRoute').upper()
    461         self.sr.jumpsLabel.SetText(numJumpsTxt)
    462         self.sr.timeLeftLabel.SetText(GetContractTimeLeftText(c))
    463 
    464     def GetContractLabel(self):
    465         node = self.sr.node
    466         contract = node.contract
    467         name = GetContractTitle(contract, node.contractItems)
    468         label = '<color=0xFFFFA600>%s</color>' % name
    469         if len(node.contractItems) == 1:
    470             item = node.contractItems[0]
    471             if evetypes.GetCategoryID(item.itemTypeID) == const.categoryBlueprint:
    472                 if item.copy:
    473                     label += ' (%s)' % localization.GetByLabel('UI/Generic/Copy').lower()
    474                 else:
    475                     label += ' (%s)' % localization.GetByLabel('UI/Generic/Original').lower()
    476         if contract.type == const.conTypeAuction:
    477             label += ' (%s)' % localization.GetByLabel('UI/Contracts/Auction').lower()
    478         return label
    479 
    480     def MakeTextLabel(self, name):
    481         subPar = Container(name='%sParent' % name, parent=self, state=uiconst.UI_PICKCHILDREN, align=uiconst.TOLEFT, clipChildren=False)
    482         label = eveLabel.EveLabelMedium(parent=subPar, name='%sLabel' % name, left=self.labelMargin, align=uiconst.TOLEFT, padTop=2)
    483         subPar.sr.label = label
    484         setattr(self.sr, '%sLabel' % name, label)
    485 
    486     def GetLocationText(self, solarSystemID, regionID, stationID = None):
    487         solarSystemName = cfg.evelocations.Get(solarSystemID).name
    488         dot = sm.GetService('contracts').GetSystemSecurityDot(solarSystemID)
    489         txt = '%s %s' % (dot, solarSystemName)
    490         if stationID and not idCheckers.IsStation(stationID):
    491             txt += '<color=0xffff6666> &lt;!&gt; </color>'
    492         if regionID and regionID != session.regionid:
    493             txt += '<br><color=0xffff6666>  %s</color>' % cfg.evelocations.Get(regionID).name
    494         return txt
    495 
    496     def GetMenu(self):
    497         m = ContractEntry.GetMenu(self)
    498         m += [(MenuLabel('UI/Contracts/ContractEntry/FindRelated'), ('isDynamic', sm.GetService('contracts').GetRelatedMenu, (self.sr.node.contract, self.sr.node.Get('typeID', None), False)))]
    499         return m
    500 
    501     def LoadTooltipPanel(self, tooltipPanel, *args):
    502         tooltipPanel.LoadGeneric1ColumnTemplate()
    503         wrapWidth = 250
    504         node = self.sr.node
    505         c = node.contract
    506         privateTxt = '<font size=10 color=red> %s</font>' % localization.GetByLabel('UI/Contracts/ContractEntry/PrivateProperty')
    507         label = self.GetContractLabel()
    508         boldLabel = localization.GetByLabel('UI/Contracts/ContractsService/BoldGenericLabel', labelText=label)
    509         tooltipPanel.AddLabelMedium(text=boldLabel, wrapWidth=wrapWidth)
    510         hintLine = localization.GetByLabel('UI/Contracts/ContractEntry/ContractTypeWithType', contractType=GetContractTypeText(c.type))
    511         tooltipPanel.AddLabelMedium(text=hintLine, wrapWidth=wrapWidth)
    512         if node.numJumps <= cc.NUMJUMPS_UNREACHABLE:
    513             numJumpsInfo = node.numJumps
    514         else:
    515             numJumpsInfo = '<color=0xffff6666>%s</color>' % localization.GetByLabel('UI/Generic/NoGateToGateRoute').upper()
    516         hintLine = localization.GetByLabel('UI/Contracts/ContractEntry/ContractLocation', location=c.startSolarSystemID, numJumpsInfo=numJumpsInfo)
    517         if not idCheckers.IsStation(c.startStationID):
    518             hintLine += privateTxt
    519         if c.type == const.conTypeCourier and not idCheckers.IsStation(c.endStationID):
    520             hintLine += '<br>' + localization.GetByLabel('UI/Contracts/ContractEntry/DropOffStation') + privateTxt
    521         tooltipPanel.AddLabelMedium(text=hintLine, wrapWidth=wrapWidth)
    522         if c.forCorp:
    523             issuerID = c.issuerCorpID
    524         else:
    525             issuerID = c.issuerID
    526         issuer = cfg.eveowners.Get(issuerID)
    527         hintLine = localization.GetByLabel('UI/Contracts/ContractEntry/IssuerWithName', issuerName=issuer.name)
    528         tooltipPanel.AddLabelMedium(text=hintLine, wrapWidth=wrapWidth)
    529         if c.title != '':
    530             hintLine = localization.GetByLabel('UI/Contracts/ContractEntry/IssuerDescriptionWithDescription', description=c.title)
    531             tooltipPanel.AddLabelMedium(text=hintLine, wrapWidth=wrapWidth)
    532         contractItems = node.contractItems
    533         if contractItems < 1:
    534             return
    535         if c.type in [const.conTypeAuction, const.conTypeItemExchange]:
    536             itemList = []
    537             itemReqList = []
    538             numItems = 0
    539             numItemsReq = 0
    540             for e in contractItems:
    541                 if e.inCrate:
    542                     itemInfo = cfg.FormatConvert(const.UE_TYPEIDANDQUANTITY, e.itemTypeID, max(1, e.quantity))
    543                     itemList.append(itemInfo)
    544                     numItems += 1
    545                 else:
    546                     itemReqInfo = cfg.FormatConvert(const.UE_TYPEIDANDQUANTITY, e.itemTypeID, max(1, e.quantity))
    547                     itemReqList.append(itemReqInfo)
    548                     numItemsReq += 1
    549 
    550             if len(itemList) >= 2:
    551                 itemList.append(localization.GetByLabel('UI/Common/MoreWithTrailing'))
    552             if len(itemReqList) >= 2:
    553                 itemReqList.append(localization.GetByLabel('UI/Common/MoreWithTrailing'))
    554             if itemList:
    555                 itemListText = localization.GetByLabel('UI/Contracts/ContractEntry/ItemsWithItemList', itemsString='')
    556                 tooltipPanel.AddLabelMedium(text=itemListText, wrapWidth=wrapWidth)
    557                 for eachItem in itemList:
    558                     tooltipPanel.AddLabelMedium(text=eachItem, wrapWidth=250, padLeft=10)
    559 
    560             else:
    561                 itemListText = localization.GetByLabel('UI/Contracts/ContractEntry/ItemsWithItemList', itemsString=localization.GetByLabel('UI/Contracts/ContractEntry/NoneParen'))
    562                 tooltipPanel.AddLabelMedium(text=itemListText, wrapWidth=wrapWidth)
    563             if len(itemReqList) > 0:
    564                 itemsReq = localization.GetByLabel('UI/Contracts/ContractEntry/ItemsRequiredWithItemList', reqItemsString='')
    565                 tooltipPanel.AddLabelMedium(text=itemsReq, wrapWidth=wrapWidth)
    566                 for eachItem in itemReqList:
    567                     tooltipPanel.AddLabelMedium(text=eachItem, wrapWidth=wrapWidth, padLeft=10)
    568 
    569             if len(itemList) >= 2 or len(itemReqList) >= 2:
    570                 tooltipPanel.AddLabelMedium(text=localization.GetByLabel('UI/Contracts/ContractEntry/OpenForItems'), wrapWidth=wrapWidth)
    571             if len(contractItems) == 1:
    572                 margin = list(tooltipPanel.margin)
    573                 margin[3] = 12
    574                 tooltipPanel.margin = tuple(margin)
    575                 tooltipPanel.AddLabelMedium(text=self.hint)
    576                 itemInContract = contractItems[0]
    577                 try:
    578                     AddDynamicItemAttributes(tooltipPanel, itemInContract.itemID, itemInContract.itemTypeID, spacerHeight=8)
    579                 except UserError as e:
    580                     if e.msg != 'ItemNotFound':
    581                         raise
    582 
    583                 category = evetypes.GetCategoryID(itemInContract.itemTypeID)
    584                 if category == const.categoryBlueprint or category == const.categoryAncientRelic:
    585                     AddBlueprintInfo(tooltipPanel, itemInContract.itemID, itemInContract.itemTypeID, spacerHeight=8)
    586 
    587     def OnColumnResize(self, newCols):
    588         for container, width in zip(self.children, newCols):
    589             if not isinstance(container, Container):
    590                 continue
    591             container.width = width
    592             label = container.sr.label
    593             if label and label != self.sr.contractLabel:
    594                 label.width = width - 14
    595 
    596     def GetDynamicHeight(_self, *args):
    597         text = localization.GetByLabel('UI/Contracts/ContractEntry/WantToBuy')
    598         textWidth, textHeight = eveLabel.EveLabelMedium.MeasureTextSize(text)
    599         if not prefs.GetValue('contractsSimpleView', 0):
    600             textHeight *= 2
    601         return textHeight + const.defaultPadding
    602 
    603     def OnMouseEnter(self, *args):
    604         ContractEntry.OnMouseEnter(self, *args)
    605         self.sr.icon.OnMouseEnter()
    606 
    607     def OnMouseExit(self, *args):
    608         ContractEntry.OnMouseExit(self, *args)
    609         self.sr.icon.OnMouseExit()
    610 
    611 
    612 class ContractEntrySearchItemExchange(ContractEntrySearch):
    613     __guid__ = 'listentry.ContractEntrySearchItemExchange'
    614 
    615     def ApplyAttributes(self, attributes):
    616         ContractEntrySearch.ApplyAttributes(self, attributes)
    617         self.MakeTextLabel('location')
    618         self.MakeTextLabel('price')
    619         self.MakeTextLabel('jumps')
    620         self.MakeTextLabel('timeLeft')
    621         self.MakeTextLabel('issuer')
    622         self.MakeTextLabel('created')
    623         self.MakeTextLabel('info')
    624 
    625     def Load(self, node):
    626         ContractEntrySearch.Load(self, node)
    627         c = node.contract
    628         p = c.price
    629         self.sr.locationLabel.text = self.GetLocationText(c.startSolarSystemID, c.startRegionID, c.startStationID)
    630         if p == 0 and c.reward > 0:
    631             txt = '<color=0xff999999>-%s</color>' % FmtISKWithDescription(c.reward, True)
    632         else:
    633             txt = '<color=white>%s</color>' % FmtISKWithDescription(p, True)
    634         self.sr.priceLabel.SetText(txt)
    635         if localization.GetByLabel('UI/Contracts/ContractEntry/WantToBuy') not in self.sr.contractLabel.text:
    636             if len([ e for e in node.contractItems if not e.inCrate ]) >= 1:
    637                 self.sr.priceLabel.text += '<br>[%s]' % localization.GetByLabel('UI/Generic/Items')
    638         if c.type == const.conTypeAuction:
    639             self.sr.priceLabel.text = '<color=white>%s</color>' % FmtISKWithDescription(GetCurrentBid(c, node.bids), True)
    640             if c.collateral:
    641                 self.sr.priceLabel.text += '<br>(%s)' % FmtISKWithDescription(c.collateral, True)
    642             else:
    643                 self.sr.priceLabel.text += '<br>(%s)' % localization.GetByLabel('UI/Contracts/ContractEntry/NoBuyoutPrice')
    644         self.sr.issuerLabel.text = node.issuer
    645         self.sr.createdLabel.text = '%s' % FmtDate(node.dateIssued, 'ss')
    646         self.sr.infoLabel.text = c.title
    647 
    648 
    649 class ContractEntrySearchAuction(ContractEntrySearch):
    650     __guid__ = 'listentry.ContractEntrySearchAuction'
    651 
    652     def ApplyAttributes(self, attributes):
    653         ContractEntrySearch.ApplyAttributes(self, attributes)
    654         self.MakeTextLabel('location')
    655         self.MakeTextLabel('currentBid')
    656         self.MakeTextLabel('buyout')
    657         self.MakeTextLabel('bids')
    658         self.MakeTextLabel('jumps')
    659         self.MakeTextLabel('timeLeft')
    660         self.MakeTextLabel('issuer')
    661         self.MakeTextLabel('created')
    662         self.MakeTextLabel('info')
    663 
    664     def Load(self, node):
    665         ContractEntrySearch.Load(self, node)
    666         c = node.contract
    667         self.sr.locationLabel.text = self.GetLocationText(c.startSolarSystemID, c.startRegionID, c.startStationID)
    668         self.sr.currentBidLabel.text = '<color=white>%s</color>' % FmtISKWithDescription(GetCurrentBid(c, node.bids), True)
    669         self.sr.buyoutLabel.text = '%s' % ['<color=0xff999999>' + localization.GetByLabel('UI/Contracts/ContractEntry/NoneParen') + '</color>', '<color=white>' + FmtISKWithDescription(c.collateral, True) + '</color>'][c.collateral > 0]
    670         self.sr.bidsLabel.text = '%s' % node.searchresult.numBids
    671         self.sr.issuerLabel.text = node.issuer
    672         self.sr.createdLabel.text = '%s' % FmtDate(node.dateIssued, 'ss')
    673         self.sr.infoLabel.text = c.title
    674 
    675 
    676 class ContractEntrySearchCourier(ContractEntrySearch):
    677     __guid__ = 'listentry.ContractEntrySearchCourier'
    678 
    679     def ApplyAttributes(self, attributes):
    680         ContractEntrySearch.ApplyAttributes(self, attributes)
    681         self.MakeTextLabel('to')
    682         self.MakeTextLabel('volume')
    683         self.MakeTextLabel('reward')
    684         self.MakeTextLabel('collateral')
    685         self.MakeTextLabel('route')
    686         self.MakeTextLabel('jumps')
    687         self.MakeTextLabel('timeLeft')
    688         self.MakeTextLabel('issuer')
    689         self.MakeTextLabel('created')
    690         self.MakeTextLabel('info')
    691 
    692     def Load(self, node):
    693         ContractEntrySearch.Load(self, node)
    694         c = node.contract
    695         self.sr.contractLabel.text = '<color=0xFFFFA600>%s</color>' % self.GetLocationText(c.startSolarSystemID, c.startRegionID, c.startStationID)
    696         self.sr.toLabel.text = '<color=0xFFFFA600>%s</color>' % self.GetLocationText(c.endSolarSystemID, None, c.endStationID)
    697         routeLength = node.routeLength
    698         volumeText = localization.GetByLabel('UI/Contracts/ContractsWindow/NumericVolume', volume=eveformat.number(c.volume))
    699         self.sr.volumeLabel.text = volumeText
    700         self.sr.rewardLabel.text = '<color=white>%s</color>' % [localization.GetByLabel('UI/Contracts/ContractEntry/NoneParen'), FmtISKWithDescription(c.reward, True)][c.reward > 0]
    701         self.sr.collateralLabel.text = '<color=white>%s</color>' % [localization.GetByLabel('UI/Contracts/ContractEntry/NoneParen'), FmtISKWithDescription(c.collateral, True)][c.collateral > 0]
    702         if int(routeLength) > cc.NUMJUMPS_UNREACHABLE:
    703             numJumpsTxt = '<color=0xffff6666>%s</color>' % localization.GetByLabel('UI/Generic/NoGateToGateRoute').upper()
    704         elif routeLength == 0:
    705             numJumpsTxt = localization.GetByLabel('UI/Contracts/ContractEntry/SameSystem')
    706         elif routeLength == 1:
    707             numJumpsTxt = localization.GetByLabel('UI/Contracts/ContractEntry/NextSystem')
    708         else:
    709             numJumpsTxt = localization.GetByLabel('UI/Contracts/ContractEntry/NumJumps', numJumps=routeLength)
    710         self.sr.routeLabel.text = '<color=white>%s</color>' % numJumpsTxt
    711         self.sr.issuerLabel.text = node.issuer
    712         self.sr.createdLabel.text = '%s' % FmtDate(node.dateIssued, 'ss')
    713         self.sr.infoLabel.text = c.title