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

contractsDetailsWnd.py (53515B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\neocom\contracts\contractsDetailsWnd.py
      2 from collections import defaultdict
      3 import eveformat
      4 import dogma.data as dogma_data
      5 import evetypes
      6 import log
      7 import utillib
      8 from brennivin.itertoolsext import Bundle
      9 from carbon.common.script.util.format import FmtAmt, FmtDate
     10 from carbonui import const as uiconst
     11 from carbonui.primitives.container import Container
     12 from carbonui.primitives.line import Line
     13 from eve.client.script.ui.control import eveEdit, eveIcon, eveLabel, eveScroll
     14 from carbonui.button.group import ButtonGroup, ButtonSizeMode
     15 from eve.client.script.ui.control.entries.item import Item
     16 from eve.client.script.ui.control.entries.util import GetFromClass
     17 from carbonui.control.window import Window
     18 from eve.client.script.ui.control.infoIcon import InfoIcon
     19 from eve.client.script.ui.control.itemIcon import ItemIcon
     20 from eve.client.script.ui.control.themeColored import SpriteThemeColored
     21 from eve.client.script.ui.shared.neocom.contracts.contractDraggableIcon import ContractDraggableIcon
     22 from eve.client.script.util.contractutils import GetContractIcon, ConFmtDate, FmtISKWithDescription, COL_GET, COL_PAY, CategoryName, GetCorpseName
     23 from eve.common.lib import appConst as const
     24 from eve.common.script.sys import eveCfg, idCheckers
     25 from eve.common.script.sys.idCheckers import IsNPC
     26 from eve.common.script.util import contractscommon
     27 from eve.common.script.sys.eveCfg import GetShipFlagLocationName
     28 import blue
     29 import localization
     30 from eve.common.script.util.contractscommon import IsPlayerAllowedToRejectContract
     31 from eve.common.script.util.eveFormat import FmtISK
     32 from eveexceptions import UserError
     33 from eveformat.client import solar_system_security_status
     34 from eveservices.menu import GetMenuService
     35 from localization import GetByLabel
     36 from menu import MenuLabel
     37 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     38 BCancel = 0
     39 BAccept = 1
     40 BReject = 2
     41 BComplete = 3
     42 BDelete = 4
     43 BSucceed = 5
     44 BFail = 6
     45 BGetItems = 7
     46 BGetMoney = 8
     47 BAcceptForCorp = 9
     48 BPlaceBid = 10
     49 HISTORY_LENGTH = 10
     50 
     51 class ContractDetailsWindow(Window):
     52     __guid__ = 'form.ContractDetailsWindow'
     53     default_windowID = 'contractdetails'
     54 
     55     def ApplyAttributes(self, attributes):
     56         Window.ApplyAttributes(self, attributes)
     57         contractID = attributes.contractID
     58         self.contract = None
     59         self.buttons = []
     60         self.isContractMgr = False
     61         self.contractID = contractID
     62         self.sr.main.clipChildren = True
     63         self.sr.main.padRight = const.defaultPadding
     64         self.scope = uiconst.SCOPE_INGAME
     65         self.SetCaption(GetByLabel('UI/Common/Contract') % {'name': '-'})
     66         self.LoadTabs()
     67         self.icon = GetContractIcon(const.conTypeNothing)
     68         self.SetMinSize([520, 200])
     69         self.MakeUnstackable()
     70         self.MakeUncollapseable()
     71         self.history = settings.user.ui.Get('contracts_history', [])
     72         self.state = uiconst.UI_HIDDEN
     73         self.pathfinder = sm.GetService('clientPathfinderService')
     74         self.Init()
     75 
     76     def Init(self):
     77         self.corpseNameLabel = None
     78         self.sr.main.Flush()
     79         topParent = Container(name='topParent', parent=self.GetMainArea(), align=uiconst.TOTOP, height=52, clipChildren=True)
     80         SpriteThemeColored(name='mainicon', parent=topParent, state=uiconst.UI_DISABLED, pos=(0, -5, 64, 64), texturePath=self.iconNum, colorType=uiconst.COLORTYPE_UIHILIGHTGLOW)
     81         self.buttons = []
     82         contract = sm.GetService('contracts').GetContract(self.contractID, force=True)
     83         if not contract:
     84             self.HistoryRemove(self.contractID)
     85             self.Close()
     86             raise UserError('ConContractNotFound')
     87         self.contract = contract
     88         c = contract.contract
     89         self.contractID = c.contractID
     90         self.isContractMgr = isContractMgr = session.corprole & const.corpRoleContractManager == const.corpRoleContractManager
     91         canRejectContract = IsPlayerAllowedToRejectContract(c, session.charid, session.corpid, session.allianceid, session.corprole)
     92         isAssignedToMePersonally = c.assigneeID == session.charid
     93         isAcceptedByMe = c.acceptorID == session.charid or c.acceptorID == session.corpid and isContractMgr
     94         isAcceptedByMyCorp = c.acceptorID == session.corpid
     95         isIssuedByMe = c.issuerID == session.charid or c.issuerCorpID == session.corpid and c.forCorp and isContractMgr
     96         isIssuedByMePersonally = c.issuerID == session.charid
     97         isExpired = c.dateExpired < blue.os.GetWallclockTime()
     98         isOverdue = c.dateAccepted + const.DAY * c.numDays < blue.os.GetWallclockTime()
     99         title = GetByLabel('UI/Contracts/ContractsService/ContractTitleAndType', contractTitle=contractscommon.GetContractTitle(c, contract.items), contractType=contractscommon.GetContractTypeText(c.type))
    100         self.icon = GetContractIcon(c.type)
    101         icon = ContractDraggableIcon(name='theicon', align=uiconst.TOPLEFT, parent=self, height=64, width=64, left=0, top=11)
    102         icon.Startup(c, title)
    103         icon.state = uiconst.UI_NORMAL
    104         Container(name='push', parent=self.sr.main, align=uiconst.TOLEFT, width=6)
    105         Container(name='push', parent=self.sr.main, align=uiconst.TORIGHT, width=6)
    106         titleParent = Container(name='titleparent', parent=topParent, align=uiconst.TOPLEFT, top=12, left=70, width=430)
    107         l = eveLabel.EveLabelLarge(text=title, parent=titleParent, width=400, state=uiconst.UI_DISABLED)
    108         titleParent.height = l.textheight + 2 * const.defaultPadding
    109         self.HistoryAdd(self.contractID, c.startSolarSystemID, title)
    110         text = GetBasicInfoText(c)
    111         tabs = [115, 480]
    112         basicInfoParent = Container(name='infocontainer', parent=self.sr.main, align=uiconst.TOTOP, padRight=const.defaultPadding)
    113         basicInfo = eveLabel.EveLabelMedium(text=text, parent=basicInfoParent, top=const.defaultPadding, idx=0, tabs=tabs, state=uiconst.UI_NORMAL, left=6)
    114         basicInfoParent.height = basicInfo.textheight + 5
    115         Line(parent=basicInfoParent, align=uiconst.TOTOP)
    116         isResizable = False
    117         if c.status == const.conStatusInProgress:
    118             if isAcceptedByMe:
    119                 if c.type != 4:
    120                     self.AddButton(BComplete)
    121                 self.AddButton(BFail)
    122             elif isIssuedByMe and isOverdue:
    123                 self.AddButton(BFail)
    124             elif isAcceptedByMyCorp and c.type == const.conTypeCourier:
    125                 self.AddButton(BComplete)
    126         if c.type == const.conTypeAuction:
    127             text = ''
    128             text += AddBasicInfoRow(GetByLabel('UI/Contracts/ContractsWindow/StartingBid'), FmtISKWithDescription(c.price))
    129             bo = [GetByLabel('UI/Contracts/ContractEntry/NoneParen'), FmtISKWithDescription(c.collateral)][c.collateral > 0]
    130             text += AddBasicInfoRow(GetByLabel('UI/Contracts/ContractsWindow/BuyoutPrice'), bo)
    131             b = GetByLabel('UI/Contracts/ContractEntry/NoBids')
    132             if len(contract.bids) > 0:
    133                 b = GetByLabel('UI/Contracts/ContractsWindow/BidsSoFar', numISK=FmtISKWithDescription(contract.bids[0].amount), numBids=len(contract.bids))
    134             text += AddBasicInfoRow(GetByLabel('UI/Contracts/ContractsWindow/CurrentBid'), b)
    135             timeleft = GetByLabel('UI/Contracts/ContractsWindow/Finished')
    136             if c.status == const.conStatusOutstanding:
    137                 diff = c.dateExpired - blue.os.GetWallclockTime()
    138                 if c.dateExpired - blue.os.GetWallclockTime() > 0:
    139                     timeleft = ConFmtDate(diff, True)
    140             text += AddBasicInfoRow(GetByLabel('UI/Contracts/ContractsWindow/TimeLeft'), timeleft)
    141             isExpired = c.dateExpired < blue.os.GetWallclockTime()
    142             isCancelled = c.status == const.conStatusCancelled
    143             highBidder = None
    144             if len(contract.bids) > 0:
    145                 highBidder = contract.bids[0].bidderID
    146             if not isCancelled:
    147                 if session.charid == highBidder:
    148                     if isExpired:
    149                         strToBold = GetByLabel('UI/Contracts/ContractsWindow/YouWon')
    150                     else:
    151                         strToBold = GetByLabel('UI/Contracts/ContractsWindow/YouAreHighBidder')
    152                     boldStr = GetByLabel('UI/Contracts/ContractsService/BoldGenericLabel', labelText=strToBold)
    153                     rowInfo = '<color=%s>%s</color>' % (COL_GET, boldStr)
    154                     text += AddBasicInfoRow('', rowInfo)
    155                 elif session.corpid == highBidder:
    156                     if isExpired:
    157                         strToBold = GetByLabel('UI/Contracts/ContractsWindow/YourCorpWon')
    158                     else:
    159                         strToBold = GetByLabel('UI/Contracts/ContractsWindow/YourCorpHighBidder')
    160                     boldStr = GetByLabel('UI/Contracts/ContractsService/BoldGenericLabel', labelText=strToBold)
    161                     rowInfo = '<color=%s>%s</color>' % (COL_GET, boldStr)
    162                     text += AddBasicInfoRow('', rowInfo)
    163                 else:
    164                     for i in range(len(contract.bids)):
    165                         b = contract.bids[i]
    166                         if i != 0:
    167                             if b.bidderID == session.charid:
    168                                 if isExpired:
    169                                     strToBold = GetByLabel('UI/Contracts/ContractsWindow/YouLost')
    170                                 else:
    171                                     strToBold = GetByLabel('UI/Contracts/ContractsWindow/YouHaveBeenOutBid')
    172                                 boldStr = GetByLabel('UI/Contracts/ContractsService/BoldGenericLabel', labelText=strToBold)
    173                                 rowInfo = '<color=%s>%s</color>' % (COL_PAY, boldStr)
    174                                 text += AddBasicInfoRow('', rowInfo)
    175                             elif b.bidderID == session.corpid:
    176                                 if isExpired:
    177                                     strToBold = GetByLabel('UI/Contracts/ContractsWindow/YourCorpLost')
    178                                 else:
    179                                     strToBold = GetByLabel('UI/Contracts/ContractsWindow/YourCorpWasOutBid')
    180                                 boldStr = GetByLabel('UI/Contracts/ContractsService/BoldGenericLabel', labelText=strToBold)
    181                                 rowInfo = '<color=%s>%s</color>' % (COL_PAY, boldStr)
    182                                 text += AddBasicInfoRow('', rowInfo)
    183                             break
    184 
    185                     if isExpired and len(contract.bids) > 0:
    186                         winner = cfg.eveowners.Get(contract.bids[0].bidderID)
    187                         showInfoLink = GetByLabel('UI/Contracts/ContractsWindow/ShowInfoLinkWithMore', showInfoName=winner.ownerName, info=('showinfo', winner.typeID, winner.ownerID), more=GetByLabel('UI/Contracts/ContractsWindow/WonThisAuction'))
    188                         text += AddBasicInfoRow('', showInfoLink)
    189             infoParent = Container(name='infocontainer', parent=self.sr.main, align=uiconst.TOTOP, width=const.defaultPadding)
    190             info = eveLabel.EveLabelMedium(text=text, parent=infoParent, top=const.defaultPadding, idx=0, tabs=tabs, state=uiconst.UI_NORMAL, left=6)
    191             infoParent.height = info.textheight + 2 * const.defaultPadding
    192             Line(parent=infoParent, align=uiconst.TOTOP)
    193             Line(parent=infoParent, align=uiconst.TOBOTTOM)
    194             isResizable = self.InsertItemList(contract, '<color=%s>%s</color>' % (COL_GET, [GetByLabel('UI/Contracts/ContractsWindow/YouWillGet'), GetByLabel('UI/Contracts/ContractsWindow/BuyerWillGet')][session.charid == c.issuerID]), True, 3)
    195             if len(contract.bids) > 0 and isExpired and not isCancelled:
    196                 if c.status != const.conStatusFinishedIssuer and c.status != const.conStatusFinished and isIssuedByMe:
    197                     self.AddButton(BGetMoney)
    198                 if c.status != const.conStatusFinishedContractor and c.status != const.conStatusFinished and (contract.bids[0].bidderID == session.charid or contract.bids[0].bidderID == session.corpid and isContractMgr):
    199                     self.AddButton(BGetItems)
    200             if isIssuedByMe and not isCancelled:
    201                 if (c.status == const.conStatusOutstanding or c.status == const.conStatusRejected) and len(contract.bids) == 0:
    202                     self.AddButton(BDelete)
    203             if not isIssuedByMePersonally and c.status == const.conStatusOutstanding:
    204                 if not isExpired:
    205                     self.AddButton(BPlaceBid)
    206                     if canRejectContract and not highBidder:
    207                         self.AddButton(BReject)
    208         elif c.type == const.conTypeItemExchange:
    209             text = ''
    210             if c.price > 0:
    211                 if session.charid == c.issuerID:
    212                     rowLabel = GetByLabel('UI/Contracts/ContractsWindow/BuyerWillPay')
    213                 else:
    214                     rowLabel = GetByLabel('UI/Contracts/ContractsWindow/YouWillPay')
    215                 boldIsk = GetByLabel('UI/Contracts/ContractsService/BoldGenericLabel', labelText=FmtISKWithDescription(c.price))
    216                 rowInfo = '<color=%s>%s</color>' % (COL_PAY, boldIsk)
    217                 text += AddBasicInfoRow(rowLabel, rowInfo)
    218             if c.reward > 0 or c.price == 0:
    219                 if session.charid == c.issuerID:
    220                     rowLabel = GetByLabel('UI/Contracts/ContractsWindow/BuyerWillGet')
    221                 else:
    222                     rowLabel = GetByLabel('UI/Contracts/ContractsWindow/YouWillGet')
    223                 boldIsk = GetByLabel('UI/Contracts/ContractsService/BoldGenericLabel', labelText=FmtISKWithDescription(c.reward))
    224                 rowInfo = '<color=%s>%s</color>' % (COL_GET, boldIsk)
    225                 text += AddBasicInfoRow(rowLabel, rowInfo)
    226             infoParent = Container(name='infocontainer', parent=self.sr.main, align=uiconst.TOTOP, width=const.defaultPadding)
    227             info = eveLabel.EveLabelLarge(text=text, parent=infoParent, top=const.defaultPadding, idx=0, tabs=tabs, state=uiconst.UI_NORMAL, left=6)
    228             infoParent.height = info.textheight + 2 * const.defaultPadding
    229             Line(parent=infoParent, align=uiconst.TOTOP)
    230             Line(parent=infoParent, align=uiconst.TOBOTTOM)
    231             fixedSize = False
    232             for i in contract.items:
    233                 if not i.inCrate:
    234                     fixedSize = True
    235 
    236             isResizable = self.InsertItemList(contract, '<color=%s>%s</color>' % (COL_GET, [GetByLabel('UI/Contracts/ContractsWindow/YouWillGet'), GetByLabel('UI/Contracts/ContractsWindow/BuyerWillGet')][session.charid == c.issuerID]), True, 2, fixedSize=fixedSize)
    237             if self.InsertItemList(contract, '<color=%s>%s</color>' % (COL_PAY, [GetByLabel('UI/Contracts/ContractsWindow/YouWillPay'), GetByLabel('UI/Contracts/ContractsWindow/BuyerWillPay')][session.charid == c.issuerID]), False, 2, hint=GetByLabel('UI/Contracts/ContractEntry/NoRequiredItems'), forceList=True):
    238                 isResizable = True
    239             if isIssuedByMe:
    240                 if c.status == const.conStatusOutstanding or c.status == const.conStatusRejected:
    241                     self.AddButton(BDelete)
    242             if c.status == const.conStatusOutstanding and (not isIssuedByMePersonally or isAssignedToMePersonally):
    243                 if not isExpired:
    244                     self.AddButton(BAccept)
    245                     if isContractMgr:
    246                         self.AddButton(BAcceptForCorp)
    247                     if canRejectContract:
    248                         self.AddButton(BReject)
    249         elif c.type == const.conTypeCourier:
    250             text = ''
    251             if c.status == const.conStatusInProgress:
    252                 de = c.dateExpired
    253                 if c.status == const.conStatusInProgress:
    254                     de = c.dateAccepted + const.DAY * c.numDays
    255                 diff = de - blue.os.GetWallclockTime()
    256                 if diff > 0:
    257                     timeleft = GetByLabel('UI/Contracts/ContractsService/TimeLeftWithoutCaption', timeLeft=ConFmtDate(diff, False), expireTime=FmtDate(de, 'ss'))
    258                 else:
    259                     overdueLabel = GetByLabel('UI/Contracts/ContractsService/Overdue', time=FmtDate(-diff, 'ss'))
    260                     timeleft = '<color=red>%s</color>' % overdueLabel
    261                 text += AddBasicInfoRow(GetByLabel('UI/Contracts/ContractsWindow/TimeLeft'), timeleft)
    262             elif c.status == const.conStatusOutstanding:
    263                 rowInfoText = GetByLabel('UI/Contracts/ContractsService/QuantityDays', numDays=c.numDays)
    264                 text += AddBasicInfoRow(GetByLabel('UI/Contracts/ContractsWindow/CompleteIn'), rowInfoText)
    265             volumeLabel = GetByLabel('UI/Contracts/ContractsWindow/NumericVolume', volume=eveformat.number(c.volume))
    266             text += AddBasicInfoRow(GetByLabel('UI/Contracts/ContractsSearch/columnVolume'), volumeLabel)
    267             numJumps = self.pathfinder.GetAutopilotJumpCount(c.endSolarSystemID, c.startSolarSystemID)
    268             perjump = ''
    269             if numJumps:
    270                 jumpCost = int(c.reward / numJumps)
    271                 perjump = GetByLabel('UI/Contracts/ContractsService/ISKPerJump', costPerJump=FmtISKWithDescription(jumpCost, justDesc=True))
    272             if c.reward > 0:
    273                 boldIsk = GetByLabel('UI/Contracts/ContractsService/BoldGenericLabel', labelText=FmtISKWithDescription(c.reward))
    274                 b = '<color=%s>%s</color>' % (COL_GET, boldIsk)
    275             else:
    276                 b = GetByLabel('UI/Contracts/ContractEntry/NoneParen')
    277             text += AddBasicInfoRow(GetByLabel('UI/Contracts/ContractsWindow/Reward'), b)
    278             if c.reward > 0:
    279                 text += AddBasicInfoRow('', perjump)
    280                 if c.volume:
    281                     volumeCost = FmtISK(float(c.reward) / c.volume, showFractionsAlways=1)
    282                     perM3 = GetByLabel('UI/Contracts/ContractsService/ISKPerM3', costPerM3=volumeCost)
    283                     text += AddBasicInfoRow('', perM3)
    284             if c.collateral > 0:
    285                 boldIsk = GetByLabel('UI/Contracts/ContractsService/BoldGenericLabel', labelText=FmtISKWithDescription(c.collateral))
    286                 b = '<color=%s>%s</color>' % (COL_PAY, boldIsk)
    287             else:
    288                 b = GetByLabel('UI/Contracts/ContractEntry/NoneParen')
    289             text += AddBasicInfoRow(GetByLabel('UI/Contracts/ContractsWindow/Collateral'), b)
    290             mr = sm.GetService('contracts').GetRouteSecurityWarning(c.startSolarSystemID, c.endSolarSystemID)
    291             if mr:
    292                 mr = '<t>%s' % mr
    293             if idCheckers.IsStation(c.endStationID):
    294                 endStationTypeID = sm.GetService('ui').GetStationStaticInfo(c.endStationID).stationTypeID
    295             else:
    296                 endStationTypeID = sm.GetService('structureDirectory').GetStructureInfo(c.endStationID).typeID
    297             dot = solar_system_security_status(c.endSolarSystemID)
    298             loc = GetByLabel('UI/Contracts/ContractsWindow/StationLinkWithDot', dot=dot, station=c.endStationID, info=('showinfo', endStationTypeID, c.endStationID))
    299             if not idCheckers.IsStation(c.endStationID):
    300                 loc += '<br><t><color=0xffbb0000>%s</color>' % GetByLabel('UI/Contracts/ContractEntry/MightBeInaccessible')
    301             jumpsToEndSolarSystem = self.pathfinder.GetAutopilotJumpCount(session.solarsystemid2, c.endSolarSystemID)
    302             if jumpsToEndSolarSystem <= contractscommon.NUMJUMPS_UNREACHABLE:
    303                 routeLabel = GetByLabel('UI/Contracts/ContractsService/RouteInfo', numJumps=jumpsToEndSolarSystem)
    304                 loc += '<br><t>%s' % routeLabel
    305             if c.startSolarSystemID != session.solarsystemid2:
    306                 if numJumps <= contractscommon.NUMJUMPS_UNREACHABLE:
    307                     routeLabel = GetByLabel('UI/Contracts/ContractsService/ShowRouteFromStart', numJumps=numJumps)
    308                     loc += '<br><t>%s' % routeLabel
    309             if mr:
    310                 loc += '<br>%s' % mr
    311             text += AddBasicInfoRow(GetByLabel('UI/Common/Destination'), loc)
    312             infoParent = Container(name='infocontainer', parent=self.sr.main, align=uiconst.TOTOP, width=const.defaultPadding)
    313             info = eveLabel.EveLabelMedium(text=text, parent=infoParent, top=const.defaultPadding, idx=0, tabs=tabs, state=uiconst.UI_NORMAL, left=const.defaultPadding)
    314             infoParent.height = info.textheight
    315             Line(parent=infoParent, align=uiconst.TOTOP)
    316             if isIssuedByMe:
    317                 if c.status == const.conStatusOutstanding or c.status == const.conStatusRejected:
    318                     self.AddButton(BDelete)
    319             if c.status == const.conStatusOutstanding and (not isIssuedByMePersonally or isAssignedToMePersonally):
    320                 if not isExpired:
    321                     self.AddButton(BAccept)
    322                     if isContractMgr:
    323                         self.AddButton(BAcceptForCorp)
    324                     if canRejectContract:
    325                         self.AddButton(BReject)
    326         elif c.type == const.conTypeLoan:
    327             text = ''
    328             if c.status == const.conStatusInProgress:
    329                 timeleft = '<font color=red>%s</font>' % GetByLabel('UI/Contracts/ContractsWindow/Expired')
    330                 de = c.dateExpired
    331                 if c.status == const.conStatusInProgress:
    332                     de = c.dateAccepted + const.DAY * c.numDays
    333                     overdueLabel = GetByLabel('UI/Contracts/ContractsService/Overdue', time=FmtDate(-(de - blue.os.GetWallclockTime()), 'ss'))
    334                     timeleft = '<color=red>%s</color>' % overdueLabel
    335                 diff = de - blue.os.GetWallclockTime()
    336                 if diff > 0:
    337                     timeleft = GetByLabel('UI/Contracts/ContractsService/TimeLeftWithoutCaption', timeLeft=ConFmtDate(diff, False), expireTime=FmtDate(de, 'ss'))
    338                 text += AddBasicInfoRow(GetByLabel('UI/Contracts/ContractsWindow/TimeLeft'), timeleft)
    339             elif c.status == const.conStatusOutstanding or c.status == const.conStatusRejected:
    340                 self.AddButton(BDelete)
    341             if c.price > 0:
    342                 boldISK = GetByLabel('UI/Contracts/ContractsService/BoldGenericLabel', labelText=FmtISKWithDescription(c.price))
    343                 rowInfo = '<color=%s>%s</color>' % (COL_PAY, boldISK)
    344             else:
    345                 rowInfo = GetByLabel('UI/Contracts/ContractEntry/NoneParen')
    346             text += AddBasicInfoRow(GetByLabel('UI/Contracts/ContractsSearch/columnPrice'), rowInfo)
    347             if c.collateral > 0:
    348                 boldISK = GetByLabel('UI/Contracts/ContractsService/BoldGenericLabel', labelText=FmtISKWithDescription(c.collateral))
    349                 rowInfo = '<color=%s>%s</color>' % (COL_PAY, boldISK)
    350             else:
    351                 rowInfo = GetByLabel('UI/Contracts/ContractEntry/NoneParen')
    352             text += AddBasicInfoRow(GetByLabel('UI/Contracts/ContractsWindow/Collateral'), rowInfo)
    353             if c.reward > 0:
    354                 text += AddBasicInfoRow(GetByLabel('UI/Contracts/ContractEntry/ISKBorrowed'), '<color=%s>%s</color>' % (COL_GET, FmtISKWithDescription(c.reward)))
    355             infoParent = Container(name='infocontainer', parent=self.sr.main, align=uiconst.TOTOP, width=const.defaultPadding)
    356             info = eveLabel.EveLabelMedium(text=text, parent=infoParent, top=const.defaultPadding, idx=0, tabs=tabs, state=uiconst.UI_NORMAL)
    357             infoParent.height = info.textheight
    358             Line(parent=infoParent, align=uiconst.TOTOP)
    359             Line(parent=infoParent, align=uiconst.TOBOTTOM)
    360             isResizable = self.InsertItemList(contract, GetByLabel('UI/Contracts/ContractsWindow/BorrowedItems'), True, 3, fixedSize=True)
    361             if isIssuedByMe:
    362                 if c.status == const.conStatusRejected:
    363                     self.AddButton(BDelete)
    364             if c.status == const.conStatusInProgress:
    365                 nocollateral = ''
    366                 if not c.collateral:
    367                     isk = c.reward or 0
    368                     nocollateral = GetByLabel('UI/Contracts/ContractsService/NoCollateralISK', reward=isk)
    369                 else:
    370                     nocollateral = GetByLabel('UI/Contracts/ContractsService/NoCollateral')
    371                 contractTypeLabel = GetByLabel('UI/Contracts/ContractsService/ContractTypeNotSupported')
    372                 notSupportedLabel = GetByLabel('UI/Contracts/ContractsService/LoanContractNotSupported')
    373                 failLabel = GetByLabel('UI/Contracts/ContractsService/ClickFail')
    374                 apologizeLabel = GetByLabel('UI/Contracts/ContractsService/WeApologize')
    375                 html = '<font color=0xffff4444><h4>%s</h4></font>%s<br>%s<br><br>%s<br><br>%s' % (contractTypeLabel,
    376                  notSupportedLabel,
    377                  failLabel,
    378                  nocollateral,
    379                  apologizeLabel)
    380                 descParent = Container(name='desc', parent=self.sr.main, align=uiconst.TOTOP, left=const.defaultPadding, top=const.defaultPadding, height=180)
    381                 desc = eveEdit.Edit(parent=descParent, readonly=1, hideBackground=1)
    382                 desc.SetValue('<html><body>%s</body></html>' % html)
    383         else:
    384             raise RuntimeError('Invalid contract type!')
    385         self.AddButton(BCancel)
    386         childrenList = self.sr.main.children
    387         height = sum([ x.height for x in childrenList if x.state != uiconst.UI_HIDDEN and x.align in (uiconst.TOBOTTOM, uiconst.TOTOP) ]) + 110
    388         w, h = self.minsize
    389         add = {False: 0,
    390          True: 160}[isResizable]
    391         self.SetMinSize([w, height + add])
    392         self.buttonWnd = ButtonGroup(btns=self.buttons, parent=self.sr.main, button_size_mode=ButtonSizeMode.DYNAMIC, idx=0)
    393         self.state = uiconst.UI_NORMAL
    394         self.sr.captionpush = Container(name='captionpush', parent=self.sr.main, align=uiconst.TOBOTTOM, height=12, left=0, top=-16)
    395         historyicon = eveIcon.MenuIcon(size=24, ignoreSize=True, align=uiconst.CENTERLEFT)
    396         historyicon.GetMenu = lambda : self.GetHistoryMenu()
    397         historyicon.hint = GetByLabel('UI/Common/History')
    398         self.sr.captionpush = Container(name='captionpush', parent=self.sr.main, align=uiconst.TOBOTTOM, height=12, left=0, top=-16)
    399         self.sr.captionpush.children.insert(1000, historyicon)
    400         return self
    401 
    402     def GetHistoryMenu(self):
    403         m = []
    404         if self.contract.contract.issuerID == session.charid:
    405             if self.contract.contract.forCorp:
    406                 if not IsNPC(session.corpid):
    407                     lastCopiedCorpFlag = settings.char.ui.Get('contracts_lastCopiedDiv', const.flagCorpSAG1)
    408                     if lastCopiedCorpFlag not in (const.flagCorpDeliveries,) + const.flagCorpSAGs:
    409                         lastCopiedCorpFlag = const.flagCorpSAG1
    410                     divName = self.GetDivisionName(lastCopiedCorpFlag)
    411                     text = GetByLabel('UI/Contracts/ContractsWindow/CopyContractDivisionName', divisionName=divName)
    412                     m.append((text, sm.GetService('contracts').OpenCreateContract, (None, self.contract, lastCopiedCorpFlag)))
    413                     m += [(MenuLabel('UI/Contracts/ContractsWindow/CopyContractFromDivision'), ('isDynamic', self._GetCorpDivisions, ()))]
    414             else:
    415                 m.append((MenuLabel('UI/Contracts/ContractsWindow/CopyContract'), sm.GetService('contracts').OpenCreateContract, (None, self.contract)))
    416         typeID = None
    417         if self.contract.items and len(self.contract.items) == 1:
    418             typeID = self.contract.items[0].itemTypeID
    419         m += [(MenuLabel('UI/Contracts/ContractEntry/FindRelated'), ('isDynamic', sm.GetService('contracts').GetRelatedMenu, (self.contract.contract, typeID)))]
    420         m += [None]
    421         m += [(MenuLabel('UI/Contracts/ContractsWindow/PreviouslyViewedContracts'), ('isDynamic', self._GetLatestContractsForHistory, ()))]
    422         return m
    423 
    424     def GetDivisionName(self, corpFlag):
    425         if corpFlag == const.flagCorpDeliveries:
    426             return GetByLabel('UI/Contracts/ContractsWindow/Deliveries')
    427         division = const.corpDivisionsByFlag[corpFlag]
    428         divName = sm.GetService('corp').GetDivisionNames()[division + 1]
    429         return divName
    430 
    431     def _GetCorpDivisions(self):
    432         m = []
    433         for eachFlagID in const.flagCorpSAGs:
    434             text = self.GetDivisionName(eachFlagID)
    435             m.append((text, self._OpenCreateContractForCorp, (self.contract, eachFlagID)))
    436 
    437         if session.corprole & (const.corpRoleAccountant | const.corpRoleJuniorAccountant | const.corpRoleTrader):
    438             m.append((GetByLabel('UI/Contracts/ContractsWindow/Deliveries'), self._OpenCreateContractForCorp, (self.contract, const.flagCorpDeliveries)))
    439         return m
    440 
    441     def _OpenCreateContractForCorp(self, contract, corpFlagID):
    442         settings.char.ui.Set('contracts_lastCopiedDiv', corpFlagID)
    443         sm.GetService('contracts').OpenCreateContract(None, contract, corpFlagID)
    444 
    445     def _GetLatestContractsForHistory(self):
    446         m = []
    447         for i in range(len(self.history)):
    448             h = self.history[-(i + 1)]
    449             m.append((h.title, self.SelectHistory, (h.contractID, h.solarSystemID)))
    450 
    451         return m
    452 
    453     def SelectHistory(self, contractID, solarSystemID):
    454         sm.GetService('contracts').ShowContract(contractID)
    455 
    456     def AddButton(self, which):
    457         caption = function = None
    458         if which == BCancel:
    459             caption = GetByLabel('UI/Common/Close')
    460             function = self.Cancel
    461         elif which == BAccept:
    462             caption = GetByLabel('UI/Contracts/ContractsWindow/Accept')
    463             function = self.Accept
    464         elif which == BAcceptForCorp:
    465             caption = GetByLabel('UI/Contracts/ContractsWindow/AcceptForCorp')
    466             function = self.AcceptForCorp
    467         elif which == BReject:
    468             caption = GetByLabel('UI/Contracts/ContractsWindow/Reject')
    469             function = self.Reject
    470         elif which == BComplete:
    471             caption = GetByLabel('UI/Contracts/ContractsWindow/Complete')
    472             function = self.Complete
    473         elif which == BDelete:
    474             caption = GetByLabel('UI/Contracts/ContractsWindow/Delete')
    475             function = self.Delete
    476         elif which == BSucceed:
    477             caption = GetByLabel('UI/Contracts/ContractsWindow/Succeed')
    478             function = self.Succeed
    479         elif which == BFail:
    480             caption = GetByLabel('UI/Contracts/ContractsWindow/Fail')
    481             function = self.Fail
    482         elif which == BGetItems:
    483             caption = GetByLabel('UI/Contracts/ContractEntry/GetItems')
    484             function = self.GetItems
    485         elif which == BGetMoney:
    486             caption = GetByLabel('UI/Contracts/ContractEntry/GetMoney')
    487             function = self.GetMoney
    488         elif which == BPlaceBid:
    489             caption = GetByLabel('UI/Contracts/ContractEntry/PlaceBid')
    490             function = self.PlaceBid
    491         button = (caption,
    492          function,
    493          (),
    494          84)
    495         self.buttons.append(button)
    496 
    497     def Cancel(self):
    498         self.Close()
    499 
    500     def TryHideLoad(self):
    501         try:
    502             self.HideLoad()
    503         except:
    504             pass
    505 
    506     def Accept(self):
    507         try:
    508             self.ShowLoad()
    509             if sm.GetService('contracts').AcceptContract(self.contractID, False):
    510                 if not self or self.destroyed:
    511                     return
    512                 self.Init()
    513         finally:
    514             self.TryHideLoad()
    515 
    516     def AcceptForCorp(self):
    517         try:
    518             self.ShowLoad()
    519             if sm.GetService('contracts').AcceptContract(self.contractID, True):
    520                 self.Init()
    521         finally:
    522             self.TryHideLoad()
    523 
    524     def Reject(self):
    525         try:
    526             self.ShowLoad()
    527             if sm.GetService('contracts').RejectContract(self.contractID):
    528                 self.Init()
    529         finally:
    530             self.TryHideLoad()
    531 
    532     def Complete(self):
    533         try:
    534             self.ShowLoad()
    535             if sm.GetService('contracts').CompleteContract(self.contractID):
    536                 self.Init()
    537         finally:
    538             self.TryHideLoad()
    539 
    540     def Delete(self):
    541         try:
    542             self.ShowLoad()
    543             if sm.GetService('contracts').DeleteContract(self.contractID):
    544                 self.Close()
    545         finally:
    546             try:
    547                 self.TryHideLoad()
    548             except:
    549                 pass
    550 
    551     def Succeed(self):
    552         try:
    553             self.ShowLoad()
    554             if sm.GetService('contracts').CompleteContract(self.contractID):
    555                 self.Init()
    556         finally:
    557             self.TryHideLoad()
    558 
    559     def Fail(self):
    560         try:
    561             self.ShowLoad()
    562             if sm.GetService('contracts').FailContract(self.contractID):
    563                 self.Init()
    564         finally:
    565             self.TryHideLoad()
    566 
    567     def GetItems(self):
    568         try:
    569             self.ShowLoad()
    570             sm.GetService('contracts').FinishAuction(self.contractID, False)
    571             self.Init()
    572         finally:
    573             self.TryHideLoad()
    574 
    575     def GetMoney(self):
    576         try:
    577             self.ShowLoad()
    578             sm.GetService('contracts').FinishAuction(self.contractID, True)
    579             self.Init()
    580         finally:
    581             self.TryHideLoad()
    582 
    583     def PlaceBid(self):
    584         try:
    585             self.ShowLoad()
    586             if sm.GetService('contracts').PlaceBid(self.contractID):
    587                 if not self.destroyed:
    588                     self.Init()
    589         finally:
    590             self.TryHideLoad()
    591 
    592     def InsertItemList(self, contract, title, inCrate, numRows, hint = None, fixedSize = False, forceList = False):
    593         shouldHideBlueprintInfo = contract.contract.status in [const.conStatusFinished, const.conStatusFinishedContractor]
    594         items = [ e for e in contract.items if e.inCrate == inCrate ]
    595         if len(items) == 0:
    596             if len(contract.items) > 1:
    597                 return True
    598             else:
    599                 return False
    600         else:
    601             titleParent = Container(name='title', parent=self.sr.main, align=uiconst.TOTOP, width=const.defaultPadding)
    602             boldTitle = GetByLabel('UI/Contracts/ContractsService/BoldGenericLabel', labelText=title)
    603             title = eveLabel.EveLabelLarge(text=boldTitle, parent=titleParent, top=6, idx=0, state=uiconst.UI_NORMAL, left=6)
    604             titleParent.height = title.textheight + 6
    605             if len(items) == 1 and not forceList:
    606                 item = items[0]
    607                 typeID = item.itemTypeID
    608                 itemID = item.itemID
    609                 groupName = evetypes.GetGroupName(item.itemTypeID)
    610                 isCorpse = evetypes.GetGroupID(item.itemTypeID) == const.groupBiomass
    611                 categoryID = evetypes.GetCategoryID(item.itemTypeID)
    612                 categoryName = CategoryName(categoryID)
    613                 details = ''
    614                 if categoryID == const.categoryBlueprint:
    615                     if item.copy == 1:
    616                         if shouldHideBlueprintInfo:
    617                             details = GetByLabel('UI/Contracts/ContractsService/BlueprintCopy')
    618                         else:
    619                             details = GetByLabel('UI/VirtualGoodsStore/BlueprintCopy', runs=item.licensedProductionRunsRemaining or 0, materialLevel=item.materialLevel or 0, productivityLevel=item.productivityLevel or 0)
    620                     elif shouldHideBlueprintInfo:
    621                         details = GetByLabel('UI/Contracts/ContractsService/BlueprintOriginal')
    622                     else:
    623                         details = GetByLabel('UI/VirtualGoodsStore/OriginalBlueprint', materialLevel=item.materialLevel or 0, productivityLevel=item.productivityLevel or 0)
    624                 descParent = Container(name='desc', parent=self.sr.main, align=uiconst.TOTOP, left=const.defaultPadding, top=const.defaultPadding, height=80)
    625                 leftParent = Container(name='leftParent', parent=descParent, align=uiconst.TOLEFT, width=72)
    626                 infoParent = Container(name='infoParent', parent=descParent, align=uiconst.TOALL, padding=(8,
    627                  2,
    628                  const.defaultPadding,
    629                  0))
    630                 if getattr(item, 'copy', False):
    631                     isCopy = True
    632                 else:
    633                     isCopy = False
    634                 icon = ItemIcon(parent=leftParent, typeID=typeID, itemID=itemID, isCopy=isCopy, width=64, height=64, align=uiconst.TOPRIGHT)
    635                 if eveCfg.IsPreviewable(typeID):
    636                     setattr(icon, 'typeID', typeID)
    637                     icon.cursor = uiconst.UICURSOR_MAGNIFIER
    638                     icon.OnClick = (self.OnPreviewClick, icon)
    639                 captionText = GetByLabel('UI/Contracts/ContractsService/NameXQuantity', typeID=item.itemTypeID, quantity=FmtAmt(max(1, item.quantity)))
    640                 self.info_caption = eveLabel.EveCaptionSmall(parent=infoParent, text=captionText, padRight=16)
    641                 top = self.info_caption.textheight
    642                 self.corpseNameLabel = None
    643                 if isCorpse:
    644                     corpseName = GetCorpseName(itemID)
    645                     if corpseName:
    646                         self.corpseNameLabel = eveLabel.EveLabelMedium(parent=infoParent, top=top, text=corpseName)
    647                         top += self.corpseNameLabel.textheight
    648                 self.infolink = InfoIcon(itemID=itemID, typeID=typeID, left=0, top=const.defaultPadding, parent=infoParent, idx=0)
    649                 self.infolink.left = self.info_caption.textwidth + 8
    650                 categoryAndGroupText = GetByLabel('UI/Contracts/ContractEntry/CategoryAndGroup', categoryName=categoryName, groupName=groupName)
    651                 self.categoryAndGroup = eveLabel.EveLabelMedium(parent=infoParent, top=top, text=categoryAndGroupText)
    652                 top += self.categoryAndGroup.textheight
    653                 if GetItemDamageText(item):
    654                     damageAndTextilsText = '<color=red>%s</color> %s' % (GetItemDamageText(item), details)
    655                 else:
    656                     damageAndTextilsText = details
    657                 self.damageAndTextils = eveLabel.EveLabelMedium(parent=infoParent, top=top, text=damageAndTextilsText)
    658                 return False
    659             if fixedSize:
    660                 self.sr.scroll = eveScroll.Scroll(parent=self.sr.main, align=uiconst.TOTOP, padding=(const.defaultPadding,
    661                  const.defaultPadding,
    662                  const.defaultPadding,
    663                  const.defaultPadding), height=100)
    664             else:
    665                 self.sr.scroll = eveScroll.Scroll(parent=self.sr.main, padding=(const.defaultPadding,
    666                  const.defaultPadding,
    667                  const.defaultPadding,
    668                  const.defaultPadding))
    669             self.sr.scroll.sr.id = 'contractDetailScroll'
    670             self.sr.data = {'items': []}
    671             parents = []
    672             children = []
    673             for item in items:
    674                 if not item.parentID:
    675                     parents.append(item)
    676                 else:
    677                     children.append(item)
    678 
    679             items = []
    680             for parent in parents:
    681                 items.append(parent)
    682                 for child in children:
    683                     if child.parentID == parent.itemID:
    684                         items.append(child)
    685 
    686             for child in children:
    687                 for item in items:
    688                     if child.itemID == item.itemID:
    689                         break
    690                 else:
    691                     items.append(child)
    692 
    693             scrolllist = []
    694             itemsByParentID = defaultdict(set)
    695             for eachItem in items:
    696                 itemsByParentID[eachItem.parentID].add(eachItem)
    697 
    698             for item in items:
    699                 if item.inCrate != inCrate:
    700                     continue
    701                 typeName = evetypes.GetName(item.itemTypeID)
    702                 groupName = evetypes.GetGroupName(item.itemTypeID)
    703                 categoryName = evetypes.GetCategoryName(item.itemTypeID)
    704                 categoryID = evetypes.GetCategoryID(item.itemTypeID)
    705                 details = ''
    706                 isBlueprint = False
    707                 isCopy = False
    708                 if categoryID == const.categoryBlueprint:
    709                     isBlueprint = True
    710                     if item.copy == 1:
    711                         isCopy = True
    712                         if shouldHideBlueprintInfo:
    713                             details = GetByLabel('UI/Contracts/ContractsService/BlueprintCopy')
    714                         else:
    715                             details = GetByLabel('UI/VirtualGoodsStore/BlueprintCopy', runs=item.licensedProductionRunsRemaining or 0, materialLevel=item.materialLevel or 0, productivityLevel=item.productivityLevel or 0)
    716                     elif shouldHideBlueprintInfo:
    717                         details = GetByLabel('UI/Contracts/ContractsService/BlueprintOriginal')
    718                     else:
    719                         details = GetByLabel('UI/VirtualGoodsStore/OriginalBlueprint', materialLevel=item.materialLevel or 0, productivityLevel=item.productivityLevel or 0)
    720                 elif item.flagID:
    721                     details = GetShipFlagLocationName(item.flagID)
    722                 chld = ''
    723                 sublevel = 0
    724                 if item.parentID > 0:
    725                     chld = ' '
    726                     sublevel = 1
    727                 mrdmg = GetItemDamageText(item)
    728                 quantity = max(1, item.quantity) if item.quantity is not None else None
    729                 quantityLabel = localization.formatters.FormatNumeric(quantity, useGrouping=True)
    730                 if forceList:
    731                     label = '%s%s<t>%s<t>%s' % (chld,
    732                      typeName,
    733                      quantityLabel,
    734                      groupName)
    735                     hdr = [GetByLabel('UI/Contracts/ContractsWindow/Name'), GetByLabel('UI/Inventory/ItemQuantityShort'), GetByLabel('UI/Common/Type')]
    736                 else:
    737                     label = '%s%s<t>%s<t>%s<t>%s<t>%s%s' % (chld,
    738                      typeName,
    739                      quantityLabel,
    740                      groupName,
    741                      categoryName,
    742                      details,
    743                      mrdmg)
    744                     hdr = [GetByLabel('UI/Contracts/ContractsWindow/Name'),
    745                      GetByLabel('UI/Inventory/ItemQuantityShort'),
    746                      GetByLabel('UI/Common/Type'),
    747                      GetByLabel('UI/Common/Category'),
    748                      GetByLabel('UI/Common/Details')]
    749                 scrolllist.append(GetFromClass(Item, {'itemID': item.itemID,
    750                  'typeID': item.itemTypeID,
    751                  'label': label,
    752                  'getIcon': 1,
    753                  'isBlueprint': isBlueprint,
    754                  'isCopy': isCopy,
    755                  'GetMenu': GetContractItemMenu,
    756                  'sublevel': sublevel,
    757                  'childrenItems': itemsByParentID.get(item.itemID, set()),
    758                  'sort_%s' % GetByLabel('UI/Inventory/ItemQuantityShort'): quantity,
    759                  'LoadTooltipPanelFunc': self.LoadItemTooltipPanel}))
    760 
    761             self.sr.scroll.Load(None, scrolllist, headers=hdr)
    762             if len(scrolllist) >= 1:
    763                 hint = None
    764             elif hint is None:
    765                 hint = GetByLabel('UI/Contracts/ContractsWindow/NoItemsFound')
    766             self.sr.scroll.ShowHint(hint)
    767             return not fixedSize
    768 
    769     def LoadItemTooltipPanel(self, tooltipPanel, itemID, typeID):
    770         if evetypes.GetGroupID(typeID) == const.groupBiomass:
    771             corpseName = GetCorpseName(itemID)
    772             if corpseName:
    773                 tooltipPanel.LoadGeneric1ColumnTemplate()
    774                 tooltipPanel.AddTextBodyLabel(text=corpseName)
    775 
    776     def OnPreviewClick(self, wnd, *args):
    777         sm.GetService('preview').PreviewType(getattr(wnd, 'typeID'))
    778 
    779     def UpdateTexts(self):
    780         if hasattr(self, 'info_caption'):
    781             self.infolink.left = self.info_caption.textwidth + 8
    782             top = self.info_caption.textheight
    783             if self.corpseNameLabel:
    784                 top += self.corpseNameLabel.textheight
    785             self.categoryAndGroup.top = top
    786             top += self.categoryAndGroup.textheight
    787             self.damageAndTextils.top = top
    788 
    789     def _OnResize(self, *args):
    790         self.UpdateTexts()
    791 
    792     def LoadTabs(self):
    793         pass
    794 
    795     def Load(self, key):
    796         pass
    797 
    798     def Confirm(self, *etc):
    799         pass
    800 
    801     def GetError(self, checkNumber = 1):
    802         return ''
    803 
    804     def Error(self, error):
    805         if error:
    806             prompt_player_fsd_dialog('CustomInfo', {'info': error})
    807 
    808     def HistoryAdd(self, id, solarSystemID, title):
    809         self.HistoryRemove(id)
    810         kv = utillib.KeyVal()
    811         kv.contractID = id
    812         kv.solarSystemID = solarSystemID
    813         kv.title = title
    814         self.history.append(kv)
    815         if len(self.history) > HISTORY_LENGTH:
    816             del self.history[0]
    817         settings.user.ui.Set('contracts_history', self.history)
    818 
    819     def HistoryRemove(self, id):
    820         for i in range(len(self.history)):
    821             if self.history[i].contractID == id:
    822                 del self.history[i]
    823                 return
    824 
    825 
    826 def AddBasicInfoRow(key, val):
    827     boldKey = GetByLabel('UI/Contracts/ContractsService/BoldGenericLabel', labelText=key)
    828     return '%(key)s<t>%(val)s<br>' % {'key': boldKey,
    829      'val': val}
    830 
    831 
    832 def GetBasicInfoText(c):
    833     isContractMgr = session.corprole & const.corpRoleContractManager == const.corpRoleContractManager
    834     text = ''
    835     desc = c.title
    836     if desc == '':
    837         desc = GetByLabel('UI/Contracts/ContractEntry/NoneParen')
    838     else:
    839         desc = GetByLabel('UI/Contracts/ContractsWindow/ContractDescription', description=desc)
    840     text += AddBasicInfoRow(GetByLabel('UI/Contracts/ContractsWindow/InfoByIssuer'), '<color=0xff999999>%s</color>' % desc)
    841     text += AddBasicInfoRow(GetByLabel('UI/Common/Type'), contractscommon.GetContractTypeText(c.type))
    842     if c.forCorp:
    843         issuerID = c.issuerCorpID
    844     else:
    845         issuerID = c.issuerID
    846     try:
    847         issuer = cfg.eveowners.Get(issuerID)
    848         issuerTypeID = issuer.typeID
    849         issuerName = issuer.ownerName
    850     except:
    851         issuerTypeID = cfg.eveowners.Get(session.charid).typeID
    852         issuerName = GetByLabel('UI/Contracts/ContractsWindow/UnknownSystem')
    853         log.LogException()
    854 
    855     issuedByURL = GetByLabel('UI/Contracts/ContractsWindow/ShowInfoLink', showInfoName=issuerName, info=('showinfo', issuerTypeID, issuerID))
    856     issuedByLabel = GetByLabel('UI/Contracts/ContractsWindow/IssuedBy')
    857     text += AddBasicInfoRow(issuedByLabel, issuedByURL)
    858     isPrivate = not not c.availability
    859     if isPrivate:
    860         assignee = cfg.eveowners.Get(c.assigneeID)
    861         a = GetByLabel('UI/Contracts/ContractsWindow/PrivateWithLink', showInfoName=assignee.name, info=('showinfo', assignee.typeID, c.assigneeID))
    862     else:
    863         if c.startRegionID == session.regionid:
    864             reg = GetByLabel('UI/Contracts/ContractsWindow/CurrentRegion')
    865         else:
    866             reg = GetByLabel('UI/Contracts/ContractEntry/OtherRegion')
    867         a = GetByLabel('UI/Contracts/ContractsService/RegionInfo', regionHeader=GetByLabel('UI/Common/LocationTypes/Region'), region=c.startRegionID, currentOrOther=reg)
    868     text += AddBasicInfoRow(GetByLabel('UI/Contracts/ContractsWindow/Availability'), a)
    869     if c.acceptorID > 0 and (c.status != const.conStatusInProgress or c.issuerID == session.charid or c.issuerCorpID == session.corpid and c.forCorp or c.acceptorID == session.charid or c.acceptorID == session.corpid):
    870         acceptor = cfg.eveowners.Get(c.acceptorID)
    871         more = ''
    872         if c.acceptorID == session.corpid and isContractMgr and c.acceptorWalletKey is not None:
    873             more = GetByLabel('UI/Contracts/ContractsService/WalletDivisionAccountName', accountName=sm.GetService('corp').GetCorpAccountName(c.acceptorWalletKey))
    874         acceptorURL = GetByLabel('UI/Contracts/ContractsWindow/ShowInfoLinkWithMore', showInfoName=acceptor.ownerName, info=('showinfo', acceptor.typeID, c.acceptorID), more=more)
    875         contractorLabel = GetByLabel('UI/Contracts/ContractsWindow/Contractor')
    876         text += AddBasicInfoRow(contractorLabel, acceptorURL)
    877     st = contractscommon.GetContractStatusText(c.status, c.type)
    878     if c.status == const.conStatusFailed:
    879         textToBold = '<color=red>%s</color>' % st
    880         st = GetByLabel('UI/Contracts/ContractsService/BoldGenericLabel', labelText=textToBold)
    881     boldStatus = GetByLabel('UI/Contracts/ContractsService/BoldGenericLabel', labelText=GetByLabel('UI/Contracts/ContractsWindow/Status'))
    882     text += '%(statusKey)s<t>%(status)s<br>' % {'statusKey': boldStatus,
    883      'status': st}
    884     if c.startStationID == 0:
    885         loc = GetByLabel('UI/Contracts/ContractEntry/NoneParen')
    886     else:
    887         if idCheckers.IsStation(c.startStationID):
    888             startStationTypeID = sm.GetService('ui').GetStationStaticInfo(c.startStationID).stationTypeID
    889         else:
    890             startStationTypeID = sm.GetService('structureDirectory').GetStructureInfo(c.startStationID).typeID
    891         dot = solar_system_security_status(c.startSolarSystemID)
    892         loc = GetByLabel('UI/Contracts/ContractsWindow/StationLinkWithDot', dot=dot, station=c.startStationID, info=('showinfo', startStationTypeID, c.startStationID))
    893         if c.startStationID == session.stationid:
    894             loc += '<br><t>%s' % GetByLabel('UI/Generic/CurrentStation')
    895         elif c.startSolarSystemID == session.solarsystemid:
    896             loc += '<br><t>%s' % GetByLabel('UI/Generic/CurrentSystem')
    897             if not idCheckers.IsStation(c.startStationID):
    898                 loc += ' - <color=0xffbb0000>%s</color>' % GetByLabel('UI/Contracts/ContractEntry/MightBeInaccessible')
    899         else:
    900             if not idCheckers.IsStation(c.startStationID):
    901                 loc += '<br><t><color=0xffbb0000>%s</color>' % GetByLabel('UI/Contracts/ContractEntry/MightBeInaccessible')
    902             jumpsToStartSystem = sm.GetService('clientPathfinderService').GetAutopilotJumpCount(session.solarsystemid2, c.startSolarSystemID)
    903             mr = sm.GetService('contracts').GetRouteSecurityWarning(session.solarsystemid2, c.startSolarSystemID)
    904             if jumpsToStartSystem <= contractscommon.NUMJUMPS_UNREACHABLE:
    905                 loc += '<br><t>'
    906                 loc += GetByLabel('UI/Common/NumJumpsAway', numJumps=int(jumpsToStartSystem))
    907             if mr:
    908                 loc += '<br><t>%s' % mr
    909     text += AddBasicInfoRow(GetByLabel('UI/Contracts/ContractsWindow/Location'), loc)
    910     if c.type != const.conTypeAuction or c.status != const.conStatusOutstanding or session.charid == c.issuerID:
    911         text += AddBasicInfoRow(GetByLabel('UI/Contracts/ContractsWindow/DateIssued'), FmtDate(c.dateIssued, 'ss'))
    912     if c.status == const.conStatusInProgress:
    913         cb = c.dateAccepted + const.DAY * c.numDays
    914         if cb < blue.os.GetWallclockTime() + const.HOUR:
    915             if cb - blue.os.GetWallclockTime() < 0:
    916                 timeLeftLabel = GetByLabel('UI/Contracts/ContractEntry/Overdue')
    917             else:
    918                 timeLeftLabel = GetByLabel('UI/Contracts/ContractsService/TimeLeftWithoutLabelVerbose', time=FmtDate(cb, 'ls'), timeLeft=FmtDate(cb - blue.os.GetWallclockTime(), 'ls'))
    919             cb = '<color=red>%s</color>' % timeLeftLabel
    920         else:
    921             cb = FmtDate(cb, 'ls')
    922         text += AddBasicInfoRow(GetByLabel('UI/Contracts/ContractsWindow/CompleteBefore'), cb)
    923     elif c.status != const.conStatusOutstanding:
    924         text += AddBasicInfoRow(GetByLabel('UI/Contracts/ContractsWindow/DateCompleted'), FmtDate(c.dateCompleted, 'ls'))
    925     elif c.type != const.conTypeAuction:
    926         expirationDateLabel = GetByLabel('UI/Contracts/ContractsService/ExpirationDate', expiredOn=FmtDate(c.dateExpired, 'ls'), timeSinceExpired=ConFmtDate(c.dateExpired - blue.os.GetWallclockTime(), False))
    927         text += AddBasicInfoRow(GetByLabel('UI/Contracts/ContractsWindow/ExpirationDate'), expirationDateLabel)
    928     return text
    929 
    930 
    931 def GetItemDamageText(item):
    932     dmg = 0
    933     if item.damage:
    934         for attribute in dogma_data.get_type_attributes(item.itemTypeID):
    935             if attribute.attributeID == const.attributeHp and attribute.value:
    936                 dmg = item.damage / attribute.value
    937                 dmg = int(dmg * 100)
    938                 break
    939 
    940     txt = ''
    941     if dmg > 0:
    942         txt = ' <color=0xffff4444>%s</color>' % GetByLabel('UI/Contracts/ContractsService/PercentDamaged', percent=dmg)
    943     return txt
    944 
    945 
    946 def GetContractItemMenu(entry, *args):
    947     node = entry.sr.node
    948     typeID = entry.typeID
    949     itemID = entry.itemID
    950     m = []
    951     if evetypes.GetCategoryID(typeID) == const.categoryShip:
    952         m += [(MenuLabel('UI/Fitting/FittingWindow/SimulateShipFitting'), SimulateShipFromContract, (typeID, node.childrenItems))]
    953     m += GetMenuService().GetMenuFromItemIDTypeID(itemID, entry.typeID, includeMarketDetails=True)
    954     return m
    955 
    956 
    957 def SimulateShipFromContract(shipTypeID, fittedItems):
    958     fittedItems = {Bundle(typeID=x.itemTypeID, itemID=x.itemID, flagID=x.flagID, categoryID=evetypes.GetCategoryID(x.itemTypeID), groupID=evetypes.GetGroupID(x.itemTypeID), stacksize=x.quantity) for x in fittedItems}
    959     fitData, _ = sm.GetService('fittingSvc').GetFittingDictFromItems(fittedItems, putModuleAmmoInCargo=False)
    960     fitting = utillib.KeyVal(shipTypeID=shipTypeID, fitData=fitData)
    961     sm.GetService('ghostFittingSvc').SimulateFitting(fitting)