createContractWnd.py (103568B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\neocom\contracts\createContractWnd.py 2 from __future__ import absolute_import 3 import math 4 import sys 5 import eveLocalization 6 import evetypes 7 import localization 8 import utillib 9 from carbon.common.script.util import timerstuff 10 from carbon.common.script.util.format import FmtAmt, FmtDate 11 from carbonui.control.buttonIcon import ButtonIcon 12 from carbonui.control.combo import Combo 13 from carbonui.util.various_unsorted import SortListOfTuples, GetClipboardData 14 from carbonui.button.group import ButtonGroup 15 from carbonui.control.button import Button 16 from eve.client.script.ui.control.entries.item import Item 17 from eve.client.script.ui.control.entries.universe import SolarSystem 18 from eve.client.script.ui.control.entries.util import GetFromClass 19 from carbonui.control.window import Window 20 from eve.client.script.ui.control.utilMenu import UtilMenu 21 from eve.client.script.ui.services.menuMerge import MergeMenus 22 from eve.client.script.ui.shared.neocom.contracts.contractentry import ContractItemSelect 23 from eve.client.script.ui.util import uix 24 import uthread 25 import log 26 import blue 27 from bannedwords.client import bannedwords 28 from carbon.common.script.util.linkUtil import GetShowInfoLink 29 from carbonui import uiconst 30 from carbonui.control.singlelineedits.singleLineEditInteger import SingleLineEditInteger 31 from carbonui.control.singlelineedits.singleLineEditText import SingleLineEditText 32 from carbonui.primitives.line import Line 33 from carbonui.primitives.container import Container 34 from contracts.contractStruct import ContractStruct 35 from contracts.copyContracts import CopyContractObject, GetMissingTypesTxt, FindMissingBlueprints, FindMissingTypesAndQty 36 from eve.client.script.ui.control import eveEdit, eveLabel, eveScroll 37 from carbonui.control.checkbox import Checkbox 38 from eve.client.script.ui.control.listgroup import ListGroup 39 from eve.client.script.ui.control.listwindow import ListWindow 40 from eve.client.script.ui.util import searchUtil, searchOld 41 from eve.client.script.ui.util.form import FormWnd 42 from eve.client.script.util.contractutils import FmtISKWithDescription, GetContractIcon, IsSearchStringLongEnough, MatchInvTypeName, SelectItemTypeDlg, TypeName 43 from eve.common.script.search import const as search_const 44 from eve.common.script.sys import eveCfg, idCheckers 45 from eve.common.script.util.contractscommon import CREATECONTRACT_CONFIRM_CHARGESTOHANGAR, CalcContractFees, CanRequestType, EXPIRE_TIMES, GetContractTypeText, MAX_AMOUNT, MAX_NUM_CONTRACTS, MAX_NUM_ITEMS, MAX_TITLE_LENGTH, NUM_CONTRACTS_BY_SKILL, NUM_CONTRACTS_BY_ADVSKILL, NUM_CONTRACTS_BY_SKILL_CORP, const_conBidMinimum, const_conBrokersFeeMinimum, const_conCourierMaxVolume, const_conCourierWarningVolume, const_conDepositMinimum, const_conSalesTax 46 from eve.common.script.util.eveFormat import FmtISK, RoundISK 47 from eveexceptions import UserError 48 from evePathfinder.pathfinderconst import UNREACHABLE_JUMP_COUNT 49 from eveservices.menu import GetMenuService 50 from globalConfig.getFunctions import GetMaxShipsToContract 51 from inventorycommon.typeHelpers import GetAveragePrice 52 from inventorycommon.const import categoryStructure, groupStation, typeBrokerRelations, typeAccounting 53 from inventorycommon.util import GetItemVolume, IsNPC 54 from localization import GetByLabel 55 from menu import MenuLabel 56 from player_messaging.client.ui_message import prompt_player_fsd_dialog 57 from structures.types import IsFlexStructure 58 from textImporting.importMultibuy import ImportMultibuy 59 from threadutils import throttled 60 MIN_CONTRACT_MONEY = 1000 61 62 class CreateContractWnd(Window): 63 __guid__ = 'form.CreateContract' 64 __notifyevents__ = ['OnDeleteContracts'] 65 default_windowID = 'createcontract' 66 default_iconNum = 'res:/ui/Texture/WindowIcons/contracts.png' 67 default_captionLabelPath = 'UI/Inventory/ItemActions/CreateContract' 68 default_minSize = (410, 520) 69 70 def ApplyAttributes(self, attributes): 71 super(CreateContractWnd, self).ApplyAttributes(attributes) 72 self.topParent = Container(name='topParent', parent=self.GetMainArea(), align=uiconst.TOTOP, height=42) 73 self.ResetWizard() 74 contractItems = attributes.contractItems 75 copyContract = attributes.copyContract 76 copyContractCorpFlagID = attributes.copyContractDisvision 77 stationID = attributes.stationID 78 flag = attributes.flag 79 itemIDs = attributes.itemIDs 80 if stationID and not self.CanContractItemsFromLocation(stationID): 81 stationID = None 82 if stationID: 83 self.data.startStation = stationID 84 self.data.startStationDivision = const.flagHangar 85 if flag: 86 self.data.startStationDivision = flag 87 if attributes.contractType: 88 self.data.type = attributes.contractType 89 else: 90 self.contractType = const.conTypeNothing 91 self.isMultiContract = False 92 self.data.items = {} 93 self.data.childItems = {} 94 if stationID and itemIDs: 95 foundItems = [] 96 itemsInStation = sm.GetService('contracts').GetItemsInDockableLocation(self.data.startStation, False) 97 for item in itemsInStation: 98 if item.itemID in itemIDs: 99 foundItems.append(item) 100 101 if foundItems: 102 self.data.startStationDivision = foundItems[0].flagID 103 for item in foundItems: 104 self.data.items[item.itemID] = [item.typeID, item.stacksize, item] 105 106 self.currPage = 0 107 self.NUM_STEPS = 4 108 self.CREATECONTRACT_TITLES = {const.conTypeNothing: [GetByLabel('UI/Contracts/ContractsWindow/SelectContractType'), 109 '', 110 '', 111 ''], 112 const.conTypeAuction: [GetByLabel('UI/Contracts/ContractsWindow/SelectContractType'), 113 GetByLabel('UI/Contracts/ContractsWindow/PickItems'), 114 GetByLabel('UI/Contracts/ContractsWindow/SelectOptions'), 115 GetByLabel('UI/Common/Confirm')], 116 const.conTypeItemExchange: [GetByLabel('UI/Contracts/ContractsWindow/SelectContractType'), 117 GetByLabel('UI/Contracts/ContractsWindow/PickItems'), 118 GetByLabel('UI/Contracts/ContractsWindow/SelectOptions'), 119 GetByLabel('UI/Common/Confirm')], 120 const.conTypeCourier: [GetByLabel('UI/Contracts/ContractsWindow/SelectContractType'), 121 GetByLabel('UI/Contracts/ContractsWindow/PickItems'), 122 GetByLabel('UI/Contracts/ContractsWindow/SelectOptions'), 123 GetByLabel('UI/Common/Confirm')]} 124 self.isContractMgr = session.corprole & const.corpRoleContractManager == const.corpRoleContractManager 125 self.marketTypes = sm.GetService('contracts').GetMarketTypes() 126 self.sr.pageWnd = {} 127 self.lockedItems = {} 128 self.state = uiconst.UI_NORMAL 129 self.blockconfirmonreturn = 1 130 setattr(self, 'first', True) 131 if contractItems is not None: 132 self._SetStartVariablesInData(contractItems) 133 self.buttons = [(GetByLabel('UI/Common/Cancel'), 134 self.OnCancel, 135 (), 136 84), (GetByLabel('UI/Common/Previous'), 137 self.OnStepChange, 138 -1, 139 84), (GetByLabel('UI/Common/Next'), 140 self.OnStepChange, 141 1, 142 84)] 143 self.sr.buttonWnd = ButtonGroup(btns=self.buttons, parent=self.sr.main) 144 self.sr.buttonCancel = self.sr.buttonWnd.buttons[0] 145 self.sr.buttonPrev = self.sr.buttonWnd.buttons[1] 146 self.sr.buttonNext = self.sr.buttonWnd.buttons[2] 147 if copyContract: 148 self.CopyContract(copyContract, copyContractCorpFlagID) 149 self.formWnd = FormWnd(name='form', align=uiconst.TOALL, pos=(0, 0, 0, 0), parent=self.sr.main) 150 self.GotoPage(0) 151 152 def SetMainIcon(self, texturePath): 153 self.icon = texturePath 154 155 def _SetStartVariablesInData(self, contractItems): 156 firstItem = contractItems[0] 157 startStation = sm.StartService('invCache').GetStationIDOfItem(firstItem) 158 if not self.CanContractItemsFromLocation(startStation): 159 return 160 self.data.startStation = startStation 161 dataItems = {} 162 for item in contractItems: 163 dataItems[item.itemID] = [item.typeID, item.stacksize, item] 164 if item.ownerID == session.corpid: 165 if not self.isContractMgr: 166 raise UserError('ConNotContractManager') 167 self.data.forCorp = True 168 self.data.startStation = sm.StartService('invCache').GetStationIDOfItem(item) 169 self.data.startStationDivision = item.flagID 170 elif item.ownerID != session.charid: 171 raise RuntimeError('Not your item!') 172 173 self.data.items = dataItems 174 175 def CopyContract(self, contract, corpFlagID = None): 176 c = contract.contract 177 self.data.type = c.type 178 self.data.startStation = c.startStationID 179 self.data.endStation = c.endStationID 180 expireTime = 1440 * ((c.dateExpired - c.dateIssued) / const.DAY) 181 self.data.expiretime = expireTime 182 self.data.duration = c.numDays 183 self.data.description = c.title 184 self.data.assigneeID = c.assigneeID 185 if c.availability == 0: 186 self.data.avail = 0 187 elif c.assigneeID == session.corpid: 188 self.data.avail = 2 189 self.data.assigneeID = None 190 elif session.allianceid and c.assigneeID == session.allianceid: 191 self.data.avail = 3 192 self.data.assigneeID = None 193 else: 194 self.data.avail = 1 195 if self.data.assigneeID: 196 self.data.name = cfg.eveowners.Get(self.data.assigneeID).name 197 self.data.price = c.price 198 self.data.reward = c.reward 199 self.data.collateral = c.collateral 200 self.data.forCorp = c.forCorp 201 self.data.reqItems = {} 202 if self.data.type == const.conTypeCourier: 203 uthread.new(prompt_player_fsd_dialog, 'ConCopyContractCourier') 204 itemsInContract = contract.items 205 if not itemsInContract: 206 return 207 copyContractsObject = CopyContractObject(startStation=self.data.startStation, forCorp=self.data.forCorp, contractItems=itemsInContract, getItemsInStationFunc=sm.GetService('contracts').GetItemsInDockableLocation, corpFlagID=corpFlagID) 208 sellItems, sellBlueprintCopies, sellBlueprintOriginals, requestItems = copyContractsObject.GetSellAndRequestedItems() 209 foundBlueprint = sellBlueprintCopies or sellBlueprintOriginals 210 self.data.reqItems = dict(requestItems) 211 self.data.items = {} 212 self.data.childItems = {} 213 if sellItems or sellBlueprintCopies or sellBlueprintOriginals: 214 foundItems, foundBPC, foundBPO = copyContractsObject.FindItemToSellInHangar(sellItems, sellBlueprintCopies, sellBlueprintOriginals) 215 notFound = FindMissingTypesAndQty(foundItems, sellItems) 216 notFoundBPCs = FindMissingBlueprints(foundBPC, sellBlueprintCopies) 217 notFoundBPOs = FindMissingBlueprints(foundBPO, sellBlueprintOriginals) 218 if notFound or notFoundBPCs or notFoundBPOs: 219 missintTypesTxt = GetMissingTypesTxt(notFound) 220 missintTypesTxt += GetMissingTypesTxt(notFoundBPCs) 221 missintTypesTxt += GetMissingTypesTxt(notFoundBPOs) 222 uthread.new(prompt_player_fsd_dialog, 'ConCopyContractMissingItems', {'types': missintTypesTxt}) 223 allFoundItems = [] 224 for eachDict in (foundItems, foundBPC, foundBPO): 225 for eachItemList in eachDict.itervalues(): 226 allFoundItems += eachItemList 227 228 if allFoundItems: 229 self.data.startStationDivision = allFoundItems[0].flagID 230 for item in allFoundItems: 231 self.data.items[item.itemID] = [item.typeID, item.stacksize, item] 232 233 if foundBlueprint: 234 uthread.new(prompt_player_fsd_dialog, 'ConCopyContractBlueprint') 235 236 def _OnClose(self, *args): 237 self.UnlockItems() 238 239 def Refresh(self): 240 self.GotoPage(self.currPage) 241 242 def Confirm(self, *args): 243 pass 244 245 def SetTitle(self): 246 pageTitle = self.CREATECONTRACT_TITLES[self.data.type][self.currPage] 247 titleLabel = GetByLabel('UI/Contracts/ContractsService/PageOfTotal', pageTitle=pageTitle, pageNum=self.currPage + 1, numPages=self.NUM_STEPS) 248 title = titleLabel 249 if self.sr.Get('windowCaption', None) is None: 250 self.sr.windowCaption = eveLabel.EveCaptionMedium(parent=self.topParent, align=uiconst.CENTERLEFT, state=uiconst.UI_DISABLED, text=title) 251 else: 252 self.sr.windowCaption.text = title 253 254 def UnlockItems(self): 255 if not hasattr(self, 'lockedItems'): 256 return 257 for i in self.lockedItems.iterkeys(): 258 sm.StartService('invCache').UnlockItem(i) 259 260 self.lockedItems = {} 261 262 def LockItems(self, itemIDs): 263 for i, item in itemIDs.iteritems(): 264 self.lockedItems[i] = i 265 userErrorDict = {'typeID': item[0], 266 'action': GetByLabel('UI/Contracts/ContractsWindow/CreatingContract').lower()} 267 sm.StartService('invCache').TryLockItem(i, 'lockItemContractFunction', userErrorDict, 1) 268 269 def GotoPage(self, n): 270 uthread.Lock(self) 271 try: 272 if n < 2: 273 self.UnlockItems() 274 self.currPage = n 275 self.SetTitle() 276 for p in self.sr.pageWnd: 277 self.sr.pageWnd[p].state = uiconst.UI_HIDDEN 278 279 self.formWnd.Flush() 280 format = [] 281 self.form = retfields = reqresult = errorcheck = [] 282 self.sr.buttonNext.SetLabel(GetByLabel('/Carbon/UI/Common/Next')) 283 self.sr.buttonPrev.state = uiconst.UI_NORMAL 284 contractIconType = const.conTypeNothing if n == 0 else self.data.type 285 self.SetMainIcon(GetContractIcon(contractIconType)) 286 if n == 0: 287 retfields, reqresult, errorcheck = self.BuildPage0() 288 elif n == 1: 289 self.WriteSelectItems(GetByLabel('UI/Contracts/ContractsWindow/SelectStationToGetItems')) 290 elif n == 2: 291 errorcheck, reqresult, retfields = self.BuildPage2() 292 elif n == 3: 293 self.BuildPage3() 294 self.formdata = [retfields, reqresult, errorcheck] 295 finally: 296 uthread.UnLock(self) 297 298 def BuildPage0(self): 299 self.sr.buttonPrev.state = uiconst.UI_HIDDEN 300 format = [] 301 format += self.Page0_GetContractTypeOptions() 302 s = [0, 303 0, 304 0, 305 0] 306 s[getattr(self.data, 'avail', 0)] = 1 307 format += self.Page0_GetAvailabilityOptions(s) 308 forCorp = getattr(self.data, 'forCorp', 0) 309 if self.isContractMgr: 310 corpAcctName = sm.GetService('corp').GetMyCorpAccountName() or GetByLabel('UI/Common/None') 311 behalfLabel = GetByLabel('UI/Contracts/ContractsService/OnBehalfOfCorp', corpName=cfg.eveowners.Get(session.corpid).name, corpAccountName=corpAcctName) 312 format += [{'type': 'btline'}] 313 format += [{'type': 'checkbox', 314 'label': '_hide', 315 'key': 'forCorp', 316 'text': behalfLabel, 317 'required': 1, 318 'frame': 0, 319 'setvalue': forCorp, 320 'onchange': self.OnForCorpChange}] 321 else: 322 format += [{'type': 'data', 323 'key': 'forCorp', 324 'data': {'forCorp': 0}}] 325 uthread.new(self.WriteNumContractsAndLimitsLazy) 326 limitsParent = Container(name='limitsParent', parent=self.formWnd, align=uiconst.TOBOTTOM, height=10, idx=0, padBottom=8) 327 outstandingContractsLabel = GetByLabel('UI/Contracts/ContractsService/OutstandingContractsUnknown') 328 labelText = '<color=0xff999999>%s</color>' % outstandingContractsLabel 329 self.limitTextWnd = eveLabel.EveLabelSmall(text=labelText, parent=limitsParent, left=6, state=uiconst.UI_DISABLED) 330 self.form, retfields, reqresult, self.panels, errorcheck, refresh = sm.GetService('form').GetForm(format, self.formWnd) 331 nameEditField = self.form.FindChild('edit_name') 332 privateCheckbox = self.form.FindChild('privateCb') 333 if nameEditField and privateCheckbox: 334 nameEditField.OnChange = lambda *args: self.OnChangePrivateName(privateCheckbox, *args) 335 fittedShipsCb = self.form.FindChild('contractTypeCb_fittedShip') 336 if fittedShipsCb: 337 self.SetFittedShipsCbEnableState(self.data.type or const.conTypeItemExchange) 338 fittedShipsCb.padLeft = 16 339 fittedShipsCb.hint = GetByLabel('UI/Contracts/FittedShipsHint') 340 return (retfields, reqresult, errorcheck) 341 342 def Page0_GetContractTypeOptions(self): 343 selected = self.data.type 344 if selected == const.conTypeNothing: 345 selected = const.conTypeItemExchange 346 selectedOptions = [selected] 347 if self.IsFittedShipContract(selected): 348 selectedOptions = [selected, 'fittedShip'] 349 350 def GetFormatLine(conType, textPath, required = 1, group = 'type'): 351 return {'type': 'checkbox', 352 'label': '_hide', 353 'key': conType, 354 'text': GetByLabel(textPath), 355 'required': required, 356 'frame': 0, 357 'setvalue': conType in selectedOptions, 358 'group': group, 359 'OnChange': self.OnContractTypeOptionChanged, 360 'name': 'contractTypeCb_%s' % conType} 361 362 format = [{'type': 'header', 363 'text': GetByLabel('UI/Contracts/ContractType')}] 364 format += [GetFormatLine(const.conTypeAuction, 'UI/Contracts/Auction')] 365 format += [GetFormatLine(const.conTypeCourier, 'UI/Contracts/ContractsWindow/Courier')] 366 format += [GetFormatLine(const.conTypeItemExchange, 'UI/Contracts/ContractsWindow/ItemExchange')] 367 if GetMaxShipsToContract(sm.GetService('machoNet')): 368 format += [GetFormatLine('fittedShip', 'UI/Contracts/ContractsWindow/AssembledShips', 0, None)] 369 format += [{'type': 'btline'}] 370 return format 371 372 def OnContractTypeOptionChanged(self, cb, *args): 373 self.SetFittedShipsCbEnableState(cb.GetSettingsKey()) 374 375 def SetFittedShipsCbEnableState(self, cbConType): 376 fittedShipsCb = self.form.FindChild('contractTypeCb_fittedShip') 377 if fittedShipsCb: 378 if cbConType in (const.conTypeItemExchange, 'fittedShip'): 379 fittedShipsCb.Enable() 380 else: 381 fittedShipsCb.Disable() 382 383 def Page0_GetAvailabilityOptions(self, s): 384 n = getattr(self.data, 'name', '') 385 386 def ChangeSearchBy(combo, *args): 387 combo.UpdateSettings() 388 389 searchTypePrefsKey = ('char', 'ui', 'contracts_searchNameBy') 390 selectSearchBy = settings.char.ui.Get('contracts_searchNameBy', search_const.MatchBy.partial_terms) 391 f = [{'type': 'header', 392 'text': GetByLabel('UI/Contracts/ContractsWindow/Availability')}, 393 {'type': 'checkbox', 394 'label': '_hide', 395 'key': 0, 396 'text': GetByLabel('UI/Generic/Public'), 397 'required': 1, 398 'frame': 0, 399 'setvalue': s[0], 400 'group': 'avail', 401 'onchange': self.OnAvailChange}, 402 {'type': 'checkbox', 403 'label': '_hide', 404 'key': 1, 405 'text': GetByLabel('UI/Generic/Private'), 406 'required': 1, 407 'frame': 0, 408 'setvalue': s[1], 409 'group': 'avail', 410 'onchange': self.OnAvailChange, 411 'name': 'privateCb'}, 412 {'type': 'edit', 413 'width': 120, 414 'label': GetByLabel('UI/Contracts/ContractsService/IndentedName'), 415 'key': 'name', 416 'required': 0, 417 'frame': 0, 418 'setvalue': n, 419 'group': 'name', 420 'isCharCorpOrAllianceField': True}, 421 {'type': 'combo', 422 'width': 120, 423 'label': GetByLabel('UI/Common/SearchBy'), 424 'key': 'searchBy', 425 'options': searchUtil.GetSearchByChoices(), 426 'setvalue': selectSearchBy, 427 'group': 'name', 428 'callback': ChangeSearchBy, 429 'prefskey': searchTypePrefsKey}] 430 if not idCheckers.IsNPC(session.corpid): 431 f += [{'type': 'checkbox', 432 'label': '_hide', 433 'key': 2, 434 'text': GetByLabel('UI/Contracts/ContractsWindow/MyCorporation'), 435 'required': 1, 436 'frame': 0, 437 'setvalue': s[2], 438 'group': 'avail', 439 'onchange': self.OnAvailChange}] 440 if session.allianceid: 441 f += [{'type': 'checkbox', 442 'label': '_hide', 443 'key': 3, 444 'text': GetByLabel('UI/Contracts/ContractsWindow/MyAlliance'), 445 'required': 1, 446 'frame': 0, 447 'setvalue': s[3], 448 'group': 'avail', 449 'onchange': self.OnAvailChange}] 450 return f 451 452 def BuildPage2(self): 453 retfields = reqresult = errorcheck = [] 454 duration, expireTime, expireTimeOptions = self.GetDurationAndExpireTimes() 455 contractType = self.data.type 456 if contractType == const.conTypeAuction: 457 errorcheck, reqresult, retfields = self.BuildPage2_AddAuctionOption(expireTime, expireTimeOptions, errorcheck, reqresult, retfields) 458 elif self.IsFittedShipContract(contractType): 459 errorcheck, reqresult, retfields = self.BuildPage2_AddFittedShipOptions(expireTime, expireTimeOptions) 460 elif contractType == const.conTypeItemExchange: 461 errorcheck, reqresult, retfields = self.BuildPage2_AddItemExchangeOptions(expireTime, expireTimeOptions) 462 elif contractType == const.conTypeCourier: 463 errorcheck, reqresult, retfields = self.BuildPage2_AddCourierOptions(duration, expireTime, expireTimeOptions) 464 return (errorcheck, reqresult, retfields) 465 466 def GetDurationAndExpireTimes(self): 467 expireTime = getattr(self.data, 'expiretime', None) 468 if expireTime is None: 469 expireTime = settings.char.ui.Get('contracts_expiretime_%s' % self.data.type, 1440) 470 duration = getattr(self.data, 'duration', None) 471 if duration is None: 472 duration = settings.char.ui.Get('contracts_duration_%s' % self.data.type, 1) 473 expireTimeOptions = [] 474 for t in EXPIRE_TIMES: 475 num = numDays = t / 1440 476 txt = GetByLabel('UI/Contracts/ContractsService/QuantityDays', numDays=num) 477 numWeeks = t / 10080 478 if numWeeks >= 1: 479 num = numWeeks 480 txt = GetByLabel('UI/Contracts/ContractsService/QuantityWeeks', numWeeks=num) 481 expireTimeOptions.append((txt, t)) 482 483 return (duration, expireTime, expireTimeOptions) 484 485 def BuildPage2_AddAuctionOption(self, expireTime, expireTimeOptions, errorcheck, reqresult, retfields): 486 del expireTimeOptions[-1] 487 format = [{'type': 'push'}, 488 {'type': 'edit', 489 'labelwidth': 150, 490 'width': 120, 491 'label': GetByLabel('UI/Contracts/ContractsWindow/StartingBid'), 492 'key': 'price', 493 'autoselect': 1, 494 'required': 0, 495 'frame': 0, 496 'group': 'avail', 497 'floatonly': [0, MAX_AMOUNT, 2], 498 'setvalue': getattr(self.data, 'price', 0)}, 499 {'type': 'push'}, 500 {'type': 'edit', 501 'labelwidth': 150, 502 'width': 120, 503 'label': GetByLabel('UI/Contracts/ContractsWindow/BuyoutPriceOptional'), 504 'key': 'collateral', 505 'autoselect': 1, 506 'required': 0, 507 'frame': 0, 508 'group': 'avail', 509 'floatonly': [0, MAX_AMOUNT, 2], 510 'setvalue': getattr(self.data, 'collateral', 0)}, 511 {'type': 'push'}, 512 {'type': 'combo', 513 'labelwidth': 150, 514 'width': 120, 515 'label': GetByLabel('UI/Contracts/ContractsWindow/AuctionTime'), 516 'key': 'expiretime', 517 'options': expireTimeOptions, 518 'setvalue': getattr(self.data, 'expiretime', expireTime)}, 519 {'type': 'push'}, 520 {'type': 'edit', 521 'labelwidth': 150, 522 'width': 220, 523 'label': GetByLabel('UI/Contracts/ContractEntry/DescriptionOptional'), 524 'key': 'description', 525 'required': 0, 526 'frame': 0, 527 'group': 'avail', 528 'setvalue': getattr(self.data, 'description', '')}] 529 self.form, retfields, reqresult, self.panels, errorcheck, refresh = sm.GetService('form').GetForm(format, self.formWnd) 530 btnparent = Container(name='btnparent', parent=self.formWnd.sr.price.parent, align=uiconst.TOALL, padLeft=const.defaultPadding) 531 Button(parent=btnparent, label=GetByLabel('UI/Contracts/ContractsWindow/EstPrice'), func=self.SetPriceToEstPrice, btn_default=0, align=uiconst.CENTERLEFT) 532 return (errorcheck, reqresult, retfields) 533 534 def BuildPage2_AddItemExchangeOptions(self, expireTime, expireTimeOptions): 535 isRequestItems = not not self.data.reqItems 536 format = [{'type': 'push'}, 537 {'type': 'edit', 538 'labelwidth': 150, 539 'width': 120, 540 'label': GetByLabel('UI/Contracts/ContractEntry/IWillPay'), 541 'key': 'reward', 542 'autoselect': 1, 543 'required': 0, 544 'frame': 0, 545 'group': 'avail', 546 'floatonly': [0, MAX_AMOUNT, 2], 547 'setvalue': getattr(self.data, 'reward', 0)}, 548 {'type': 'push'}, 549 {'type': 'edit', 550 'labelwidth': 150, 551 'width': 120, 552 'label': GetByLabel('UI/Contracts/ContractEntry/IWillRecieve'), 553 'key': 'price', 554 'autoselect': 1, 555 'required': 0, 556 'frame': 0, 557 'group': 'avail', 558 'floatonly': [0, MAX_AMOUNT, 2], 559 'setvalue': getattr(self.data, 'price', 0)}, 560 {'type': 'push'}, 561 {'type': 'combo', 562 'labelwidth': 150, 563 'width': 120, 564 'label': GetByLabel('UI/Contracts/ContractsWindow/Expiration'), 565 'key': 'expiretime', 566 'options': expireTimeOptions, 567 'setvalue': getattr(self.data, 'expiretime', expireTime)}, 568 {'type': 'push'}, 569 {'type': 'edit', 570 'labelwidth': 150, 571 'width': 220, 572 'label': GetByLabel('UI/Contracts/ContractEntry/DescriptionOptional'), 573 'key': 'description', 574 'required': 0, 575 'frame': 0, 576 'maxLength': 50, 577 'group': 'avail', 578 'setvalue': getattr(self.data, 'description', '')}, 579 {'type': 'push', 580 'height': 10}, 581 {'type': 'checkbox', 582 'required': 1, 583 'height': 16, 584 'setvalue': isRequestItems, 585 'key': 'requestitems', 586 'label': '', 587 'text': GetByLabel('UI/Contracts/ContractsWindow/AlsoReqItemsFromBuyer'), 588 'frame': 0, 589 'onchange': self.OnRequestItemsChange}] 590 self.form, retfields, reqresult, self.panels, errorcheck, refresh = sm.GetService('form').GetForm(format, self.formWnd) 591 self.ConstructReqItems() 592 self.PopulateReqItemScroll() 593 btnparent = Container(name='btnparent', parent=self.formWnd.sr.price.parent, align=uiconst.TOALL, padLeft=const.defaultPadding) 594 Button(parent=btnparent, label=GetByLabel('UI/Contracts/ContractsWindow/EstPrice'), func=self.SetPriceToEstPrice, btn_default=0, align=uiconst.CENTERLEFT) 595 self.ToggleShowRequestItems(isRequestItems) 596 return (errorcheck, reqresult, retfields) 597 598 def ConstructReqItems(self): 599 self.sr.reqItemsParent = reqItemsParent = Container(name='reqItemsParent', parent=self.formWnd, align=uiconst.TOALL, pos=(0, 0, 0, 0), idx=50, state=uiconst.UI_NORMAL) 600 topReqItemCont = Container(name='topReqItemCont', parent=self.sr.reqItemsParent, align=uiconst.TOTOP, height=50, top=30) 601 importHint = '%s<br><br>%s' % (GetByLabel('UI/Contracts/ContractsWindow/ImportRequestedItemsListOption'), GetByLabel('UI/Market/MarketQuote/ImportShoppingListOptionHint', type1=const.typeVeldspar, type2=const.typeTritanium)) 602 importMenu = ButtonIcon(name='importMenu', menuAlign=uiconst.TOPLEFT, parent=topReqItemCont, align=uiconst.CENTERLEFT, pos=(0, 0, 32, 32), func=self.ImportRequestedList, texturePath='res:/UI/Texture/Shared/pasteFrom.png', iconSize=28, hint=importHint) 603 addBtn = Button(parent=topReqItemCont, label=GetByLabel('UI/Contracts/ContractEntry/AddItem'), func=self.AddRequestItem, pos=(0, 0, 0, 0), align=uiconst.CENTERRIGHT) 604 self.reqItemQtyWnd = c = SingleLineEditInteger(name='itemqty', parent=topReqItemCont, label=GetByLabel('UI/Inventory/ItemQuantity'), align=uiconst.CENTERRIGHT, width=50, setvalue=1, left=addBtn.width + 8) 605 self.reqItemTypeWnd = SingleLineEditText(name='itemtype', parent=topReqItemCont, label=GetByLabel('UI/Contracts/ContractsWindow/ItemType'), align=uiconst.TOTOP, isTypeField=True, top=9, padLeft=importMenu.left + importMenu.width + 8, padRight=self.reqItemQtyWnd.left + self.reqItemQtyWnd.width + 8) 606 self.reqItemTypeWnd.ShowClearButton() 607 self.reqItemTypeWnd.OnFocusLost = self.ParseItemType 608 self.reqItemTypeWnd.OnReturn = lambda *args: self.ParseItemType(self.reqItemTypeWnd) 609 self.reqItemScroll = eveScroll.Scroll(name='reqItemScroll', parent=reqItemsParent, padding=const.defaultPadding, id='reqitemscroll') 610 611 def ImportRequestedList(self, *args): 612 localizedDecimal = eveLocalization.GetDecimalSeparator(localization.SYSTEM_LANGUAGE) 613 localizedSeparator = eveLocalization.GetThousandSeparator(localization.SYSTEM_LANGUAGE) 614 typeIDFinder = sm.GetService('contracts').GetContractTypeIDFinder() 615 nameImporter = ImportMultibuy(typeIDFinder, localizedDecimal, localizedSeparator) 616 text = GetClipboardData() 617 toAdd, failedLines = nameImporter.GetTypesAndQty(text) 618 if not toAdd: 619 self.ShowFailedLines(failedLines) 620 return 621 for typeID, qty in toAdd.iteritems(): 622 if typeID not in self.data.reqItems: 623 self.data.reqItems[typeID] = 0 624 self.data.reqItems[typeID] += qty 625 626 self.PopulateReqItemScroll() 627 self.ShowFailedLines(failedLines) 628 629 def ShowFailedLines(self, failedLines): 630 if failedLines: 631 text = '%s<br>' % GetByLabel('UI/SkillQueue/CouldNotReadLines') 632 text += '<br>'.join(failedLines) 633 prompt_player_fsd_dialog('CustomInfo', {'info': text}, modal=False) 634 635 def BuildPage2_AddFittedShipOptions(self, expireTime, expireTimeOptions): 636 text = GetByLabel('UI/Contracts/ContractsWindow/AssembledShipOptionText', numShips=len(self.data.items)) 637 eveLabel.EveLabelMedium(text=text, parent=self.formWnd, state=uiconst.UI_DISABLED, align=uiconst.TOTOP, padding=(7, 0, 7, 0)) 638 format = [{'type': 'push'}, 639 {'type': 'edit', 640 'labelwidth': 150, 641 'width': 120, 642 'label': GetByLabel('UI/Contracts/ContractEntry/IWillRecieve'), 643 'key': 'price', 644 'autoselect': 1, 645 'required': 0, 646 'frame': 0, 647 'group': 'avail', 648 'floatonly': [0, MAX_AMOUNT, 2], 649 'setvalue': getattr(self.data, 'price', 0)}, 650 {'type': 'push'}, 651 {'type': 'combo', 652 'labelwidth': 150, 653 'width': 120, 654 'label': GetByLabel('UI/Contracts/ContractsWindow/Expiration'), 655 'key': 'expiretime', 656 'options': expireTimeOptions, 657 'setvalue': getattr(self.data, 'expiretime', expireTime)}, 658 {'type': 'push'}, 659 {'type': 'edit', 660 'labelwidth': 150, 661 'width': 220, 662 'label': GetByLabel('UI/Contracts/ContractEntry/DescriptionOptional'), 663 'key': 'description', 664 'required': 0, 665 'frame': 0, 666 'maxLength': 50, 667 'group': 'avail', 668 'setvalue': getattr(self.data, 'description', '')}, 669 {'type': 'push', 670 'height': 10}] 671 self.form, retfields, reqresult, self.panels, errorcheck, refresh = sm.GetService('form').GetForm(format, self.formWnd) 672 return (errorcheck, reqresult, retfields) 673 674 def BuildPage2_AddCourierOptions(self, duration, expireTime, expireTimeOptions): 675 if not self.data.endStation and len(self.data.items) == 1: 676 myItemInfo = self.data.items.values()[0] 677 if myItemInfo[0] == const.typePlasticWrap: 678 wrapItem = myItemInfo[2] 679 endStationID = sm.GetService('contracts').GetEndStationIDForCourierWrapID(wrapItem.itemID) 680 if endStationID: 681 self.data.endStation = endStationID 682 format = [{'type': 'push'}, 683 {'type': 'edit', 684 'label': GetByLabel('UI/Contracts/ContractsWindow/ShipTo'), 685 'labelwidth': 150, 686 'width': 120, 687 'key': 'endStationName', 688 'frame': 0, 689 'maxLength': 80, 690 'setvalue': ''}, 691 {'type': 'push'}, 692 {'type': 'edit', 693 'labelwidth': 150, 694 'width': 120, 695 'label': GetByLabel('UI/Contracts/ContractsWindow/Reward'), 696 'key': 'reward', 697 'autoselect': 1, 698 'required': 0, 699 'frame': 0, 700 'group': 'avail', 701 'floatonly': [0, MAX_AMOUNT, 2], 702 'setvalue': getattr(self.data, 'reward', 0)}, 703 {'type': 'push'}, 704 {'type': 'edit', 705 'labelwidth': 150, 706 'width': 120, 707 'label': GetByLabel('UI/Contracts/ContractsWindow/Collateral'), 708 'key': 'collateral', 709 'autoselect': 1, 710 'required': 0, 711 'frame': 0, 712 'group': 'avail', 713 'floatonly': [0, MAX_AMOUNT, 2], 714 'setvalue': getattr(self.data, 'collateral', 0)}, 715 {'type': 'push'}, 716 {'type': 'combo', 717 'labelwidth': 150, 718 'width': 120, 719 'label': GetByLabel('UI/Contracts/ContractsWindow/Expiration'), 720 'key': 'expiretime', 721 'options': expireTimeOptions, 722 'setvalue': expireTime}, 723 {'type': 'push'}, 724 {'type': 'edit', 725 'labelwidth': 150, 726 'width': 60, 727 'label': GetByLabel('UI/Contracts/ContractsWindow/DaysToComplete'), 728 'key': 'duration', 729 'autoselect': 1, 730 'required': 0, 731 'frame': 0, 732 'group': 'duration', 733 'setvalue': duration, 734 'intonly': [1, 365]}, 735 {'type': 'push'}, 736 {'type': 'edit', 737 'labelwidth': 150, 738 'width': 220, 739 'label': GetByLabel('UI/Contracts/ContractEntry/DescriptionOptional'), 740 'key': 'description', 741 'required': 0, 742 'frame': 0, 743 'group': 'avail', 744 'setvalue': getattr(self.data, 'description', '')}] 745 self.form, retfields, reqresult, self.panels, errorcheck, refresh = sm.GetService('form').GetForm(format, self.formWnd) 746 if self.data.endStation: 747 self.SearchStation(self.data.endStation) 748 endStationEdit = self.formWnd.sr.endStationName 749 endStationEdit.OnFocusLost = self.SearchStationFromEdit 750 endStationEdit.isLocationField = True 751 endStationEdit.SetValueAfterDragging = self.EndStationSetValueAfterDragging 752 btnparent = Container(name='btnparent', parent=endStationEdit.parent, align=uiconst.TOALL, padLeft=const.defaultPadding) 753 btn = Button(parent=btnparent, label=GetByLabel('UI/Common/Search'), func=self.SearchStationFromEdit, args=(endStationEdit,), btn_default=0, align=uiconst.CENTERLEFT) 754 Line(parent=self.formWnd, align=uiconst.TOTOP, padTop=10) 755 self.sr.courierHint = eveLabel.EveLabelSmall(name='courierHint', text='', align=uiconst.TOTOP, parent=self.formWnd, state=uiconst.UI_DISABLED, padding=6) 756 self.UpdateCourierHint() 757 if not getattr(self, 'courierHint', None): 758 self.courierHint = timerstuff.AutoTimer(1000, self.UpdateCourierHint) 759 btnparent2 = Container(name='btnparent', parent=self.formWnd.sr.collateral.parent, align=uiconst.TOALL, padLeft=const.defaultPadding) 760 btn2 = Button(parent=btnparent2, label=GetByLabel('UI/Contracts/ContractsWindow/EstPrice'), func=self.SetCollateralToEstPrice, btn_default=0, align=uiconst.CENTERLEFT) 761 return (errorcheck, reqresult, retfields) 762 763 def EndStationSetValueAfterDragging(self, name, locationID): 764 if self.IsDockableLocation(locationID): 765 SingleLineEditText.SetValueAfterDragging(self.formWnd.sr.endStationName, name, locationID) 766 self.data.endStation = None 767 768 def GetItemQtyLabel(self, iQty, iTypeID): 769 return GetByLabel('UI/Contracts/ContractsService/NameXQuantity', typeID=iTypeID, quantity=FmtAmt(iQty)) 770 771 def BuildPage3(self): 772 contractType = self.data.type 773 if hasattr(self.data, 'expiretime'): 774 settings.char.ui.Set('contracts_expiretime_%s' % contractType, self.data.expiretime) 775 if hasattr(self.data, 'duration'): 776 settings.char.ui.Set('contracts_duration_%s' % contractType, self.data.duration) 777 rows = [] 778 contractTypeText = GetContractTypeText(contractType) 779 if self.IsFittedShipContract(contractType): 780 contractTypeText += ' / %s' % GetByLabel('UI/Contracts/ContractsWindow/AssembledShips') 781 rows.append([GetByLabel('UI/Contracts/ContractType'), contractTypeText]) 782 desc = self.data.description 783 if desc == '': 784 desc = GetByLabel('UI/Contracts/ContractEntry/NoneParen') 785 rows.append([GetByLabel('UI/Contracts/ContractsWindow/Description'), desc]) 786 avail = self.data.avail 787 a = GetByLabel('UI/Generic/Public') 788 if avail > 0: 789 a = GetByLabel('UI/Generic/Private') 790 assignee = cfg.eveowners.Get(self.data.assigneeID) 791 a += ' (<a href=showinfo:%s//%s>%s</a>)' % (assignee.typeID, self.data.assigneeID, assignee.name) 792 else: 793 regionID = None 794 if idCheckers.IsStation(self.data.startStation): 795 regionID = cfg.evelocations.Get(self.data.startStation).Station().regionID 796 else: 797 structureInfo = sm.GetService('structureDirectory').GetStructureInfo(self.data.startStation) 798 if structureInfo is not None: 799 regionID = cfg.mapSystemCache.Get(structureInfo.solarSystemID).regionID 800 if regionID: 801 regionLabel = GetByLabel('UI/Contracts/ContractsService/RegionName', region=regionID) 802 else: 803 log.LogTraceback('No Region?') 804 regionLabel = '' 805 a += regionLabel 806 rows.append([GetByLabel('UI/Contracts/ContractsWindow/Availability'), a]) 807 loc = GetByLabel('UI/Contracts/ContractEntry/NoneParen') 808 if self.data.startStation: 809 loc = cfg.evelocations.Get(self.data.startStation).name 810 if idCheckers.IsStation(self.data.startStation): 811 startStationTypeID = sm.GetService('ui').GetStationStaticInfo(self.data.startStation).stationTypeID 812 else: 813 startStationTypeID = sm.GetService('structureDirectory').GetStructureInfo(self.data.startStation).typeID 814 loc = GetShowInfoLink(startStationTypeID, loc, self.data.startStation) 815 rows.append([GetByLabel('UI/Contracts/ContractsWindow/Location'), loc]) 816 expireLabel = GetByLabel('UI/Contracts/ContractsService/TimeLeftWithoutCaption', timeLeft=FmtDate(self.data.expiretime * const.MIN + blue.os.GetWallclockTime(), 'ss'), expireTime=FmtDate(self.data.expiretime * const.MIN)) 817 rows.append([GetByLabel('UI/Contracts/ContractsWindow/Expiration'), expireLabel]) 818 contractType = self.data.type 819 if not self.IsFittedShipContract(contractType): 820 rows += self.GetPaymentRows() 821 rows.append([]) 822 if contractType == const.conTypeAuction: 823 auctionRows = self.BuildPage3_AddAuctionOptions() 824 rows += auctionRows 825 elif self.IsFittedShipContract(contractType): 826 rows += self.BuildPage3_AddItemExchangeFittedShips() 827 elif contractType == const.conTypeItemExchange: 828 rows += self.BuildPage3_AddItemExchangeOptions() 829 elif contractType == const.conTypeCourier: 830 courierRows = self.BuildPage3_AddCourierOptions() 831 rows += courierRows 832 else: 833 raise RuntimeError('Contract type not implemented!') 834 self.WriteConfirm(rows) 835 self.sr.buttonNext.SetLabel(GetByLabel('UI/Contracts/ContractsWindow/Finish')) 836 837 def GetPaymentRows(self, numContract = 1): 838 feeTextAndAmounts = self.GetFeeTextAndAmounts() 839 depositText = feeTextAndAmounts['depositText'] 840 brokersFeeText = feeTextAndAmounts['brokersFeeText'] 841 salesTaxText = feeTextAndAmounts['salesTaxText'] 842 if numContract > 1: 843 totalDepoitText = FmtISK(numContract * feeTextAndAmounts['depositAmount'], 0) 844 totalBrokersFeeText = FmtISK(numContract * feeTextAndAmounts['brokersFeeAmount'], 0) 845 totalSalesTaxText = FmtISK(numContract * feeTextAndAmounts['salesTaxAmount'], 0) 846 brokersFeeText = GetByLabel('UI/Contracts/ContractsWindow/PerContract', amountText=brokersFeeText, totalText=totalBrokersFeeText, totalColor='red') 847 depositText = GetByLabel('UI/Contracts/ContractsWindow/PerContract', amountText=depositText, totalText=totalDepoitText, totalColor='red') 848 salesTaxText = GetByLabel('UI/Contracts/ContractsWindow/PerContract', amountText=salesTaxText, totalText=totalSalesTaxText, totalColor='red') 849 rows = [[GetByLabel('UI/Contracts/ContractsWindow/SalesTax'), salesTaxText]] 850 rows.append([GetByLabel('UI/Contracts/ContractsWindow/BrokersFee'), brokersFeeText]) 851 rows.append([GetByLabel('UI/Contracts/ContractsWindow/Deposit'), depositText]) 852 return rows 853 854 def GetFeeTextAndAmounts(self): 855 brokersFeeAmount = 0 856 depositAmount = 0 857 salesTaxAmount = 0 858 if self.data.avail > 0: 859 salesTax = GetByLabel('UI/Contracts/ContractEntry/NoneParen') 860 brokersFeeAmount = const_conBrokersFeeMinimum 861 brokersFee = FmtISK(brokersFeeAmount, 0) 862 deposit = FmtISK(0.0, 0) 863 else: 864 skillsSvc = sm.GetService('skills') 865 skillLevels = utillib.KeyVal() 866 skillLevels.brokerRelations = skillsSvc.GetEffectiveLevel(typeBrokerRelations) or 0 867 skillLevels.accounting = skillsSvc.GetEffectiveLevel(typeAccounting) or 0 868 ret = CalcContractFees(self.data.Get('price', 0), self.data.Get('reward', 0), self.data.type, self.data.avail, self.data.expiretime, skillLevels, session.solarsystemid2, session.warfactionid) 869 salesTaxAmount = ret.salesTaxAmt 870 brokersFeeAmount = ret.brokersFeeAmt 871 depositAmount = ret.depositAmt 872 salesTax = GetByLabel('UI/Contracts/ContractsService/ISKFollowedByPercent', numISK=FmtISK(salesTaxAmount, 0), percentage=ret.salesTax * 100.0) 873 if brokersFeeAmount == const_conBrokersFeeMinimum: 874 brokersFee = GetByLabel('UI/Contracts/ContractsService/ISKMinimumQuantity', numISK=FmtISK(brokersFeeAmount, 0)) 875 else: 876 brokersFee = GetByLabel('UI/Contracts/ContractsService/ISKFollowedByPercent', numISK=FmtISK(brokersFeeAmount, 0), percentage=ret.brokersFee * 100.0) 877 minDeposit = const_conDepositMinimum 878 if self.data.type == const.conTypeCourier: 879 minDeposit = minDeposit / 10 880 if depositAmount == minDeposit: 881 deposit = GetByLabel('UI/Contracts/ContractsService/ISKMinimumQuantity', numISK=FmtISK(depositAmount, 0)) 882 else: 883 deposit = GetByLabel('UI/Contracts/ContractsService/ISKFollowedByPercent', numISK=FmtISK(depositAmount, 0), percentage=ret.deposit * 100.0) 884 if self.data.type == const.conTypeAuction: 885 p = const_conSalesTax - float(skillLevels.accounting) * 0.001 886 buyout = self.data.collateral 887 if buyout < self.data.Get('price', 0): 888 buyout = MAX_AMOUNT 889 ret2 = CalcContractFees(buyout, self.data.Get('reward', 0), self.data.type, self.data.avail, self.data.expiretime, skillLevels, session.solarsystemid2, session.warfactionid) 890 maxSalesTax = ret2.salesTaxAmt 891 salesTax = GetByLabel('UI/Contracts/ContractsService/PercentOfSalesPriceAtTax', percent=100.0 * p, formattedISKWithUnits=FmtISKWithDescription(maxSalesTax, True)) 892 elif self.data.type == const.conTypeCourier: 893 salesTax = GetByLabel('UI/Contracts/ContractEntry/NoneParen') 894 return {'brokersFeeText': brokersFee, 895 'depositText': deposit, 896 'salesTaxText': salesTax, 897 'brokersFeeAmount': brokersFeeAmount, 898 'depositAmount': depositAmount, 899 'salesTaxAmount': salesTaxAmount} 900 901 def BuildPage3_AddAuctionOptions(self): 902 rows = [] 903 rows.append([GetByLabel('UI/Contracts/ContractsWindow/StartingBid'), FmtISKWithDescription(self.data.price)]) 904 buyout = GetByLabel('UI/Contracts/ContractEntry/NoneParen') 905 if self.data.collateral > 0: 906 buyout = FmtISKWithDescription(self.data.collateral) 907 rows.append([GetByLabel('UI/Contracts/ContractsWindow/BuyoutPrice'), buyout]) 908 itemList = [] 909 for i in self.data.items: 910 item = self.data.items[i] 911 itemLabel = self.GetItemQtyLabel(item[1], item[0]) 912 itemList.append(itemLabel) 913 chld = self.data.childItems.get(i, []) 914 for c in chld: 915 childItemLabel = GetByLabel('UI/Contracts/ContractsService/NameXQuantityChild', typeID=c[1], quantity=c[2]) 916 itemList.append(childItemLabel) 917 918 items = '<br>'.join(itemList) 919 rows.append([GetByLabel('UI/Contracts/ContractEntry/ItemsForSale'), items]) 920 return rows 921 922 def BuildPage3_AddItemExchangeOptions(self): 923 rows = [[GetByLabel('UI/Contracts/ContractEntry/IWillPay'), FmtISKWithDescription(self.data.reward)], [GetByLabel('UI/Contracts/ContractEntry/IWillRecieve'), FmtISKWithDescription(self.data.price)]] 924 itemList = [] 925 for i in self.data.items: 926 itemLabel = self.GetItemQtyLabel(self.data.items[i][1], self.data.items[i][0]) 927 itemList.append(itemLabel) 928 chld = self.data.childItems.get(i, []) 929 for c in chld: 930 childItemLabel = GetByLabel('UI/Contracts/ContractsService/NameXQuantityChild', typeID=c[1], quantity=c[2]) 931 itemList.append(childItemLabel) 932 933 items = '<br>'.join(itemList) 934 rows.append([GetByLabel('UI/Contracts/ContractEntry/ItemsForSale'), items]) 935 listToJoin = [] 936 for typeID, qty in self.data.reqItems.iteritems(): 937 labelToAppend = self.GetItemQtyLabel(qty, typeID) 938 listToJoin.append(labelToAppend) 939 940 itemStr = '<br>'.join(listToJoin) 941 rows.append([GetByLabel('UI/Contracts/ContractEntry/ItemsRequired'), itemStr]) 942 return rows 943 944 def BuildPage3_AddItemExchangeFittedShips(self): 945 numContracts = len(self.data.items) 946 rows = [] 947 rows += self.GetPaymentRows(numContracts) 948 pricePerContract = self.data.price 949 pricePerContractText = FmtISKWithDescription(pricePerContract) 950 if numContracts > 1: 951 totalPriceText = FmtISK(numContracts * pricePerContract, 0) 952 pricePerContractText = GetByLabel('UI/Contracts/ContractsWindow/PerContract', amountText=pricePerContractText, totalText=totalPriceText, totalColor='green') 953 rows += [[GetByLabel('UI/Contracts/ContractEntry/IWillRecieve'), pricePerContractText]] 954 rows.append([]) 955 itemList = [] 956 rows.append([GetByLabel('UI/Contracts/ContractsWindow/NumberOfContracts'), numContracts]) 957 numByContainerItemIDs = getattr(self.data, 'numByContainerItemIDs', {}) 958 for itemID, item in self.data.items.iteritems(): 959 iTypeID, iQty, iRow = item 960 if iQty > 1: 961 itemLabel = self.GetItemQtyLabel(iQty, iTypeID) 962 else: 963 itemLabel = evetypes.GetName(iTypeID) 964 shipLocationData = cfg.evelocations.GetIfExists(itemID) 965 if shipLocationData: 966 itemLabel += ' (%s)' % shipLocationData.name 967 numContained = numByContainerItemIDs.get(itemID, 0) 968 if numContained: 969 itemLabel += '<br><font color=grey>%s</font>' % GetByLabel('UI/Contracts/ContractsWindow/ContainsItemsPostText', numItems=numContained) 970 itemList.append('<li>%s</li>' % itemLabel) 971 972 items = ''.join(itemList) 973 if items: 974 items = '<ol>%s</ol>' % items 975 rows.append([GetByLabel('UI/Contracts/ContractEntry/ItemsForSale'), items]) 976 return rows 977 978 def BuildPage3_AddCourierOptions(self): 979 rows = [] 980 rows.append([GetByLabel('UI/Contracts/ContractsWindow/Reward'), FmtISKWithDescription(self.data.reward)]) 981 rows.append([GetByLabel('UI/Contracts/ContractsWindow/Collateral'), FmtISKWithDescription(self.data.collateral)]) 982 loc = '' 983 if self.data.startStation: 984 loc = cfg.evelocations.Get(self.data.endStation).name 985 if idCheckers.IsStation(self.data.endStation): 986 typeID = sm.GetService('ui').GetStationStaticInfo(self.data.endStation).stationTypeID 987 else: 988 typeID = sm.GetService('structureDirectory').GetStructureInfo(self.data.endStation).typeID 989 loc = GetShowInfoLink(typeID, loc, itemID=self.data.endStation) 990 rows.append([GetByLabel('UI/Common/Destination'), loc]) 991 rows.append([GetByLabel('UI/Contracts/ContractsWindow/DaysToComplete'), self.data.duration]) 992 volume = 0 993 for i in self.data.items: 994 volume += GetItemVolume(self.data.items[i][2], int(self.data.items[i][1])) 995 996 if 0 < volume < 1: 997 significantDigits = 2 998 decimalPlaces = int(-math.ceil(math.log10(volume)) + significantDigits) 999 else: 1000 decimalPlaces = 2 1001 volumeLabel = GetByLabel('UI/Contracts/ContractsWindow/NumericVolume', volume=FmtAmt(volume, showFraction=decimalPlaces)) 1002 rows.append([GetByLabel('UI/Inventory/ItemVolume'), volumeLabel]) 1003 items = '' 1004 itemList = [] 1005 for i in self.data.items: 1006 item = self.data.items[i] 1007 itemLabel = self.GetItemQtyLabel(item[1], item[0]) 1008 itemList.append(itemLabel) 1009 chld = self.data.childItems.get(i, []) 1010 for c in chld: 1011 childItemLabel = GetByLabel('UI/Contracts/ContractsService/NameXQuantityChild', typeID=c[1], quantity=c[2]) 1012 itemList.append(childItemLabel) 1013 1014 items = '<br>'.join(itemList) 1015 rows.append([GetByLabel('UI/Contracts/ContractEntry/Items'), items]) 1016 return rows 1017 1018 def OnChangePrivateName(self, privateCheckbox, text): 1019 if text: 1020 privateCheckbox.ToggleState() 1021 1022 def OnRequestItemsChange(self, chkbox, *args): 1023 if not chkbox.GetValue(): 1024 self.reqItemScroll.Clear() 1025 self.data.reqItems = {} 1026 self.ToggleShowRequestItems(not not chkbox.GetValue()) 1027 1028 def ToggleShowRequestItems(self, isIt): 1029 if isIt: 1030 self.sr.reqItemsParent.Show() 1031 else: 1032 self.sr.reqItemsParent.Hide() 1033 1034 def WriteNumContractsAndLimitsLazy(self): 1035 try: 1036 n, maxNumContracts = self.GetNumContractsAndLimits(getattr(self.data, 'forCorp', 0), getattr(self.data, 'assigneeID', 0)) 1037 outstandingLabel = GetByLabel('UI/Contracts/ContractsService/OutstandingContractsDisplay', numContracts=n, maxContracts=maxNumContracts) 1038 self.limitTextWnd.text = '<color=0xff999999>%s</color>' % outstandingLabel 1039 except: 1040 sys.exc_clear() 1041 1042 def OnForCorpChange(self, wnd, *args): 1043 self.data.forCorp = wnd.GetValue() 1044 self.OnAvailChange(None) 1045 self.data.items = {} 1046 1047 def OnAvailChange(self, wnd, *args): 1048 uthread.new(self._OnAvailChange, wnd) 1049 1050 def _OnAvailChange(self, wnd, *args): 1051 if self.destroyed: 1052 return 1053 if not wnd: 1054 key = getattr(self.data, 'lastAvailKey', 0) 1055 else: 1056 key = wnd.data.get('key') 1057 self.data.lastAvailKey = key 1058 if key == 2: 1059 n, maxNumContracts = self.GetNumContractsAndLimits(getattr(self.data, 'forCorp', 0), session.corpid) 1060 elif key == 1: 1061 n, maxNumContracts = self.GetNumContractsAndLimits(getattr(self.data, 'forCorp', 0), getattr(self.data, 'assigneeID', 0)) 1062 else: 1063 n, maxNumContracts = self.GetNumContractsAndLimits(getattr(self.data, 'forCorp', 0), 0) 1064 try: 1065 outstandingLabel = GetByLabel('UI/Contracts/ContractsService/OutstandingContractsDisplay', numContracts=n, maxContracts=maxNumContracts) 1066 self.limitTextWnd.text = '<color=0xff999999>%s</color>' % outstandingLabel 1067 except: 1068 sys.exc_clear() 1069 1070 def CreateContract(self): 1071 sm.GetService('loading').ProgressWnd(GetByLabel('UI/Contracts/ContractsWindow/CreatingContract'), '', 2, 10) 1072 try: 1073 self.itemsCurrentlyBeingContracted = None 1074 self.state = uiconst.UI_HIDDEN 1075 contractType = getattr(self.data, 'type', const.conTypeNothing) 1076 assigneeID = getattr(self.data, 'assigneeID', 0) 1077 startStationID = getattr(self.data, 'startStation', 0) 1078 startStationDivision = getattr(self.data, 'startStationDivision', None) 1079 endStationID = getattr(self.data, 'endStation', 0) 1080 forCorp = getattr(self.data, 'forCorp', 0) > 0 1081 if not forCorp: 1082 startStationDivision = 4 1083 price = getattr(self.data, 'price', 0) 1084 reward = getattr(self.data, 'reward', 0) 1085 collateral = getattr(self.data, 'collateral', 0) 1086 expiretime = getattr(self.data, 'expiretime', 0) 1087 duration = getattr(self.data, 'duration', 0) 1088 title = getattr(self.data, 'description', '') 1089 description = getattr(self.data, 'body', '') 1090 items = [] 1091 itemsReq = map(list, self.data.reqItems.items()) 1092 for i in self.data.items: 1093 items.append([i, self.data.items[i][1]]) 1094 1095 isPrivate = not not assigneeID 1096 contractIDs = None 1097 isMultiContract = self.IsFittedShipContract(contractType) 1098 expectedNumContracts = len(items) if isMultiContract else 1 1099 contractInfo = ContractStruct(contractType=contractType, isPrivate=isPrivate, assignedToID=assigneeID, minutesExpire=expiretime, numDays=duration, startStationID=startStationID, destinationID=endStationID, price=price, reward=reward, collateral=collateral, title=title, description=description, itemList=items, startStationDivision=startStationDivision, requestItemTypeList=itemsReq, forCorp=forCorp, multiContract=isMultiContract) 1100 try: 1101 if isMultiContract: 1102 self.itemsCurrentlyBeingContracted = (expectedNumContracts, {x[0] for x in items}) 1103 sm.RegisterForNotifyEvent(self, 'OnItemChange') 1104 sm.GetService('loading').ProgressWnd(GetByLabel('UI/Contracts/ContractsWindow/CreatingContract'), '%s / %s ' % (0, expectedNumContracts), 2, expectedNumContracts + 2) 1105 contractIDs = sm.GetService('contracts').CreateContract(contractInfo) 1106 except UserError as e: 1107 if e.msg == 'NotEnoughCargoSpace': 1108 if prompt_player_fsd_dialog('ConAskRemoveToHangar', {}, uiconst.YESNO) == uiconst.ID_YES: 1109 contractID = sm.GetService('contracts').CreateContract(contractInfo, confirm=CREATECONTRACT_CONFIRM_CHARGESTOHANGAR) 1110 else: 1111 raise 1112 elif e.msg == 'ConMultiContractAbortedDueToTidi': 1113 contractIDs = e.dict.get('createdContractIDs', []) 1114 self.UpdateContractItemsAfterFailedMultiContract() 1115 self.ShowCreatedContracts(contractIDs, expectedNumContracts, isMultiContract) 1116 raise 1117 else: 1118 raise 1119 1120 self.ShowCreatedContracts(contractIDs, expectedNumContracts, isMultiContract) 1121 finally: 1122 sm.UnregisterForNotifyEvent(self, 'OnItemChange') 1123 self.state = uiconst.UI_NORMAL 1124 if self.itemsCurrentlyBeingContracted: 1125 expectedNumContracts, itemsLeft = self.itemsCurrentlyBeingContracted 1126 itemsProcessed = expectedNumContracts - len(itemsLeft) 1127 sub = '%s / %s ' % (itemsProcessed, expectedNumContracts) 1128 steps = expectedNumContracts + 2 1129 else: 1130 sub = '' 1131 steps = 10 1132 sm.GetService('loading').ProgressWnd(GetByLabel('UI/Contracts/ContractsWindow/CreatingContract'), sub, steps, steps) 1133 self.itemsCurrentlyBeingContracted = None 1134 1135 def ShowCreatedContracts(self, contractIDs, expectedNumContracts = None, isMultiContract = False): 1136 if contractIDs: 1137 if len(contractIDs) == 1 or not isMultiContract: 1138 contractID = contractIDs[0] 1139 sm.GetService('contracts').ShowContract(contractID) 1140 else: 1141 sm.GetService('contracts').ShowManyContracts(contractIDs) 1142 if expectedNumContracts is None or len(contractIDs) >= expectedNumContracts: 1143 self.Close() 1144 1145 def UpdateContractItemsAfterFailedMultiContract(self): 1146 oldItems = set(self.data.items) 1147 itemsInStation = sm.GetService('contracts').GetItemsInDockableLocation(self.data.startStation, getattr(self.data, 'forCorp', 0)) 1148 itemIDsInStation = {x.itemID for x in itemsInStation} 1149 toRemove = oldItems - itemIDsInStation 1150 for toRemoveID in toRemove: 1151 self.data.items.pop(toRemoveID) 1152 1153 self.Refresh() 1154 1155 def OnItemChange(self, item, change, location): 1156 itemsCurrentlyBeingContracted = getattr(self, 'itemsCurrentlyBeingContracted', None) 1157 if not itemsCurrentlyBeingContracted: 1158 return 1159 expectedNumContracts, itemsLeft = self.itemsCurrentlyBeingContracted 1160 if item.itemID in itemsLeft: 1161 itemsLeft.discard(item.itemID) 1162 itemsProcessed = expectedNumContracts - len(itemsLeft) 1163 sm.GetService('loading').ProgressWnd(GetByLabel('UI/Contracts/ContractsWindow/CreatingContract'), '%s / %s ' % (itemsProcessed, expectedNumContracts), 2 + itemsProcessed, expectedNumContracts + 2) 1164 1165 def WriteConfirm(self, rows): 1166 body = '' 1167 for r in rows: 1168 if r == []: 1169 body += '<tr><td colspan=2><hr></td></tr>' 1170 elif len(r) == 1: 1171 body += '<tr><td colspan=2>%s</td></tr>' % r[0] 1172 else: 1173 boldKey = GetByLabel('UI/Contracts/ContractsService/BoldGenericLabel', labelText=r[0]) 1174 val = r[1] 1175 body += '<tr><td width=100 valign=top>%(key)s</td><td>%(val)s</td></tr>' % {'key': boldKey, 1176 'val': val} 1177 1178 message = '\n <TABLE width="98%%">%s</TABLE>\n ' % body 1179 messageArea = eveEdit.Edit(parent=self.formWnd, readonly=1, hideBackground=1) 1180 messageArea.SetValue(message) 1181 1182 def ParseItemType(self, editField, *args): 1183 if self.destroyed or getattr(self, 'parsingItemType', False): 1184 return 1185 try: 1186 self.parsingItemType = True 1187 txt = editField.GetValue() 1188 if len(txt) == 0 or not IsSearchStringLongEnough(txt): 1189 return 1190 types = [] 1191 for t in self.marketTypes: 1192 if MatchInvTypeName(txt, t.typeID): 1193 if CanRequestType(t.typeID): 1194 types.append(t.typeID) 1195 1196 typeID = SelectItemTypeDlg(types) 1197 if typeID: 1198 editField.SetValue(TypeName(typeID)) 1199 self.parsedItemType = typeID 1200 return typeID 1201 self.parsedItemType = typeID 1202 finally: 1203 self.parsingItemType = False 1204 1205 def AddRequestItem(self, *args): 1206 typeID = getattr(self, 'parsedItemType', None) or self.ParseItemType(self.reqItemTypeWnd) 1207 self.parsedItemType = None 1208 if not typeID: 1209 return 1210 qty = self.reqItemQtyWnd.GetValue() 1211 if qty < 1: 1212 return 1213 self.data.reqItems[typeID] = qty 1214 self.reqItemTypeWnd.SetValue('') 1215 self.reqItemQtyWnd.SetValue(1) 1216 self.PopulateReqItemScroll() 1217 1218 def RemoveRequestItem(self, nodes, *args): 1219 for node in nodes: 1220 self.data.reqItems.pop(node.typeID, None) 1221 1222 self.PopulateReqItemScroll() 1223 1224 def PopulateReqItemScroll(self): 1225 scrolllist = [] 1226 self.reqItemScroll.Clear() 1227 for typeID, qty in self.data.reqItems.iteritems(): 1228 data = utillib.KeyVal(label='%s<t>%s' % (evetypes.GetName(typeID), qty), typeID=typeID, getIcon=True, showinfo=False, GetMenu=self.GetReqItemMenu, ignoreRightClick=True) 1229 entry = GetFromClass(Item, data) 1230 scrolllist.append(entry) 1231 1232 self.reqItemScroll.Load(contentList=scrolllist, headers=[GetByLabel('UI/Inventory/InvItemNameShort'), GetByLabel('UI/Common/Quantity')], noContentHint=GetByLabel('UI/Contracts/ContractsWindow/AddItemsAbove')) 1233 1234 def GetReqItemMenu(self, entry, *args): 1235 node = entry.sr.node 1236 selectedNodes = node.scroll.GetSelectedNodes(node) 1237 menus = [] 1238 for node in selectedNodes: 1239 m = [(MenuLabel('UI/Generic/RemoveItem'), self.RemoveRequestItem, (selectedNodes,))] 1240 menus.append(m) 1241 1242 if len(selectedNodes) == 1: 1243 menus += [GetMenuService().GetMenuFromItemIDTypeID(None, node.typeID, includeMarketDetails=True)] 1244 return MergeMenus(menus) 1245 1246 def SearchStationFromEdit(self, editField): 1247 stationID = editField.draggedValue 1248 self.SearchStation(stationID) 1249 1250 @staticmethod 1251 def GetSearchScrollEntryData(searchResults, resultType): 1252 entryList = [] 1253 if resultType not in (search_const.ResultType.structure_with_inlined_data, search_const.ResultType.station): 1254 log.LogWarn('resultType %d not recognized') 1255 return entryList 1256 for entry in searchResults: 1257 if resultType == search_const.ResultType.structure_with_inlined_data: 1258 itemID = entry.structureID 1259 solarsystemID = entry.solarSystemID 1260 typeID = entry.typeID 1261 name = entry.itemName 1262 elif resultType == search_const.ResultType.station: 1263 itemID = entry 1264 station = cfg.stations.Get(itemID) 1265 solarsystemID = station.solarSystemID 1266 typeID = station.stationTypeID 1267 name = cfg.evelocations.Get(itemID).name 1268 else: 1269 continue 1270 data = {'sublevel': 1, 1271 'showinfo': True, 1272 'itemID': itemID, 1273 'listvalue': (itemID, name), 1274 'solarSystemID': solarsystemID, 1275 'typeID': typeID, 1276 'label': name} 1277 entryList.append(data) 1278 1279 return entryList 1280 1281 def SearchStation(self, stationID = None, *args): 1282 searchstr = self.form.sr.endStationName.GetValue().strip() 1283 if stationID is None and not IsSearchStringLongEnough(searchstr): 1284 return 1285 if stationID and not self.IsDockableLocation(stationID): 1286 stationID = None 1287 if stationID is None: 1288 with sm.GetService('loading').LoadCycle(GetByLabel('UI/Common/Searching'), GetByLabel('UI/Contracts/ContractsService/LoadingSearchHint', searchStr=searchstr)): 1289 searchResult = self.SearchGetStationID(searchstr) 1290 if searchResult is None: 1291 return 1292 stationID, locationName = searchResult 1293 else: 1294 locationName = cfg.evelocations.Get(stationID).name 1295 if stationID: 1296 self.courierDropLocation = stationID 1297 self.form.sr.endStationName.SetValue(locationName) 1298 self.data.endStation = stationID 1299 1300 def SearchGetStationID(self, searchstr): 1301 resultsByType = searchUtil.GetResultsByGroupID(searchstr.lower(), [search_const.ResultType.station, search_const.ResultType.structure_with_inlined_data]) 1302 if search_const.ResultType.structure_with_inlined_data in resultsByType: 1303 resultsByType[search_const.ResultType.structure_with_inlined_data] = [ structureInfo for structureInfo in resultsByType.get(search_const.ResultType.structure_with_inlined_data, []) if self.IsDockableType(structureInfo.typeID) ] 1304 totalResults = len(resultsByType.get(search_const.ResultType.station, [])) + len(resultsByType.get(search_const.ResultType.structure_with_inlined_data, [])) 1305 if totalResults == 1: 1306 stationID = resultsByType.get(search_const.ResultType.station, [None])[0] 1307 if stationID: 1308 return (stationID, cfg.evelocations.Get(stationID).name) 1309 else: 1310 structureInfo = resultsByType.get(search_const.ResultType.structure_with_inlined_data)[0] 1311 return (structureInfo.structureID, structureInfo.itemName) 1312 scroll = [] 1313 for resultType, results in resultsByType.iteritems(): 1314 if not results: 1315 continue 1316 entryList = self.GetSearchScrollEntryData(results, resultType) 1317 label = GetByLabel('UI/Common/LocationTypes/Stations') if resultType == search_const.ResultType.station else GetByLabel('UI/Common/LocationTypes/Structures') 1318 scroll.append(GetFromClass(ListGroup, {'GetSubContent': searchUtil.GetSearchSubContent, 1319 'label': GetByLabel('UI/Search/UniversalSearch/SectionHeader', resultType=label, numberReturned=len(entryList)), 1320 'groupItems': (SolarSystem, entryList), 1321 'id': ('search_cat', resultType), 1322 'sublevel': 0, 1323 'showlen': 0, 1324 'showicon': 'hide', 1325 'cat': resultType, 1326 'state': 'locked'})) 1327 1328 header = GetByLabel('UI/Common/SearchResults') 1329 top = GetByLabel('UI/Search/UniversalSearch/WindowHeaderNumResults', numResults=totalResults, searchStr=searchstr) 1330 if totalResults >= search_const.max_result_count: 1331 top = GetByLabel('UI/Search/UniversalSearch/WindowHeaderOverMax', maxNumber=search_const.max_result_count, searchStr=searchstr) 1332 return ListWindow.ShowList(scroll, 'generic', header, top, 0, isModal=1, windowName='contractEndpointSearch', lstDataIsGrouped=1, unstackable=1, noContentHint=GetByLabel('UI/Search/UniversalSearch/NoResultsReturned', searchStr=searchstr)) 1333 1334 @staticmethod 1335 def IsDockableLocation(dockableItemID): 1336 if idCheckers.IsStation(dockableItemID): 1337 return True 1338 structureInfo = sm.GetService('structureDirectory').GetStructureInfo(dockableItemID) 1339 return structureInfo is not None and not IsNPC(structureInfo.ownerID) and not IsFlexStructure(structureInfo.typeID) 1340 1341 @staticmethod 1342 def IsDockableType(typeID): 1343 if evetypes.GetGroupID(typeID) == groupStation: 1344 return True 1345 if evetypes.GetCategoryID(typeID) == categoryStructure: 1346 if IsFlexStructure(typeID): 1347 return False 1348 return True 1349 return False 1350 1351 def UpdateCourierHint(self): 1352 if self.data.endStation and self.data.startStation and self.sr.courierHint and not self.sr.courierHint.destroyed: 1353 hintList = [] 1354 startSolarSystemID = sm.GetService('contracts').GetSolarSystemIDForStationOrStructure(self.data.startStation) 1355 endSolarSystemID = sm.GetService('contracts').GetSolarSystemIDForStationOrStructure(self.data.endStation) 1356 numJumps = sm.GetService('clientPathfinderService').GetAutopilotJumpCount(endSolarSystemID, startSolarSystemID) 1357 perJump = self.formWnd.sr.reward.GetValue() / (numJumps or 1) 1358 sec = sm.GetService('contracts').GetRouteSecurityWarning(startSolarSystemID, endSolarSystemID) 1359 volumeHint = '' 1360 if numJumps == 0: 1361 hint = GetByLabel('UI/Contracts/ContractsService/CourierHintNoJumps', numISK=FmtISK(perJump)) 1362 elif numJumps == 1: 1363 hint = GetByLabel('UI/Contracts/ContractsService/CourierHintOneJump', numISK=FmtISK(perJump)) 1364 else: 1365 hint = GetByLabel('UI/Contracts/ContractsService/CourierHintManyJumps', numJumps=numJumps, numISK=FmtISK(perJump)) 1366 if numJumps != UNREACHABLE_JUMP_COUNT: 1367 hintList.append('- ' + hint) 1368 num, totalVolume = self.GetVolumeOfAllItems() 1369 if totalVolume: 1370 perM3 = self.formWnd.sr.reward.GetValue() / totalVolume 1371 v = FmtAmt(totalVolume, showFraction=1) 1372 hintList.append('- ' + GetByLabel('UI/Contracts/ContractsService/CourierHintIskM3', volume=v, numISK=FmtISK(perM3))) 1373 if sec: 1374 hintList.append('- ' + sec) 1375 hintText = '<br>'.join(hintList) 1376 self.sr.courierHint.SetText(hintText) 1377 1378 def GetNumContractsAndLimits(self, forCorp, assigneeID): 1379 skills = sm.GetService('skills').GetSkills() 1380 skillTypeID = [const.typeContracting, const.typeCorporationContracting][forCorp] 1381 skill = skills.get(skillTypeID, None) 1382 advSkill = skills.get(const.typeAdvancedContracting, None) 1383 if skill is None: 1384 lvl = 0 1385 else: 1386 lvl = skill.effectiveSkillLevel 1387 if advSkill is None: 1388 advlvl = 0 1389 else: 1390 advlvl = advSkill.effectiveSkillLevel 1391 if forCorp: 1392 maxNumContracts = NUM_CONTRACTS_BY_SKILL_CORP[lvl] 1393 else: 1394 maxNumContracts = NUM_CONTRACTS_BY_SKILL[lvl] + NUM_CONTRACTS_BY_ADVSKILL[advlvl] 1395 innerCorp = False 1396 if assigneeID > 0: 1397 if idCheckers.IsCorporation(assigneeID): 1398 if assigneeID == session.corpid: 1399 innerCorp = True 1400 elif idCheckers.IsCharacter(assigneeID): 1401 corpID = sm.RemoteSvc('corpmgr').GetCorporationIDForCharacter(assigneeID) 1402 if corpID == session.corpid and not idCheckers.IsNPC(session.corpid): 1403 innerCorp = True 1404 n = 0 1405 try: 1406 if getattr(self, 'numOutstandingContracts', None) is None: 1407 self.numOutstandingContracts = sm.GetService('contracts').NumOutstandingContracts() 1408 if forCorp: 1409 if innerCorp: 1410 n = self.numOutstandingContracts.myCorpTotal 1411 else: 1412 n = self.numOutstandingContracts.nonCorpForMyCorp 1413 elif innerCorp: 1414 n = self.numOutstandingContracts.myCharTotal 1415 else: 1416 n = self.numOutstandingContracts.nonCorpForMyChar 1417 finally: 1418 return (n, [maxNumContracts, MAX_NUM_CONTRACTS][innerCorp]) 1419 1420 def FinishStep(self, step): 1421 uthread.Lock(self) 1422 try: 1423 result = sm.GetService('form').ProcessForm(self.formdata[0], self.formdata[1]) 1424 lastType = getattr(self.data, 'type', None) 1425 if step == 0: 1426 contractType = result.get('type', None) 1427 if contractType is None: 1428 return False 1429 if contractType != lastType and not getattr(self, 'first', False): 1430 self.ResetWizard() 1431 setattr(self, 'first', False) 1432 for i in result: 1433 setattr(self.data, str(i), result[i]) 1434 1435 if step == 0: 1436 doContinue = self.FinishPage0() 1437 if not doContinue: 1438 return False 1439 elif step == 1: 1440 doContinue = self.FinishStep1() 1441 if not doContinue: 1442 return False 1443 else: 1444 if step == 2: 1445 return self.FinishStep2() 1446 raise RuntimeError('Illegal step (%s)' % step) 1447 return True 1448 finally: 1449 uthread.UnLock(self) 1450 1451 def FinishPage0(self): 1452 self.isMultiContract = False 1453 if self.data.type == const.conTypeItemExchange: 1454 fittedShipsCb = self.form.FindChild('contractTypeCb_fittedShip') 1455 if fittedShipsCb and fittedShipsCb.checked: 1456 self.isMultiContract = True 1457 ownerID = None 1458 if self.data.avail == 1: 1459 if IsSearchStringLongEnough(self.data.name): 1460 exact = getattr(self.data, 'searchBy', search_const.MatchBy.partial_terms) 1461 ownerID = searchOld.Search(self.data.name.lower(), const.groupCharacter, const.categoryOwner, exact=exact, hideNPC=1, searchWndName='contractFinishStepSearch', hideDustChars=True) 1462 if not ownerID: 1463 return False 1464 if self.data.type == const.conTypeAuction: 1465 owner = cfg.eveowners.Get(ownerID) 1466 if owner.IsCharacter() or owner.IsCorporation() and ownerID != session.corpid: 1467 raise UserError('CustomInfo', {'info': GetByLabel('UI/Contracts/ContractsService/UserErrorCannotCreatePrivateAuction')}) 1468 elif self.data.name != '': 1469 raise UserError('CustomInfo', {'info': GetByLabel('UI/Contracts/ContractsService/UserErrorPrivateNameAndStateDontMatch')}) 1470 elif self.data.avail == 2: 1471 ownerID = session.corpid 1472 elif self.data.avail == 3: 1473 ownerID = session.allianceid 1474 if not ownerID: 1475 raise UserError('CustomInfo', {'info': GetByLabel('UI/CapitalNavigation/CapitalNavigationWindow/CorporationNotInAllianceMessage')}) 1476 self.data.assigneeID = ownerID 1477 forCorp = bool(self.data.forCorp) 1478 n, maxNumContracts = self.GetNumContractsAndLimits(forCorp, self.data.assigneeID) 1479 if n >= maxNumContracts >= 0: 1480 if forCorp is True: 1481 skillLabel = GetByLabel('UI/Contracts/ContractsService/IncreaseSkillInfo', skillType=const.typeCorporationContracting) 1482 else: 1483 skillLabel = GetByLabel('UI/Contracts/ContractsService/IncreaseSkillInfo', skillType=const.typeContracting) 1484 errorLabel = GetByLabel('UI/Contracts/ContractsService/UserErrorMaxContractsReached', numContracts=maxNumContracts, skillInfo=skillLabel) 1485 raise UserError('CustomInfo', {'info': errorLabel}) 1486 return True 1487 1488 def FinishStep1(self): 1489 ILLEGAL_ITEMGROUPS = [const.groupCapsule] 1490 contractType = self.data.type 1491 self.data.numByContainerItemIDs = {} 1492 if self.IsFittedShipContract(contractType): 1493 numShips = len(self.data.items) 1494 isForCorp = self.data.forCorp 1495 currentNum, maxNumContracts = self.GetNumContractsAndLimits(isForCorp, getattr(self.data, 'assigneeID', 0)) 1496 maxMultiContracts = GetMaxShipsToContract(sm.GetService('machoNet')) 1497 maxMultiContract = min(maxMultiContracts, maxNumContracts - currentNum) 1498 if numShips > maxMultiContract: 1499 raise UserError('ConMultiContractExceedAvailable') 1500 if not numShips: 1501 raise UserError('ConMultiContractSelectShip') 1502 for itemID, item in self.data.items.iteritems(): 1503 itemTypeID = item[0] 1504 itemGroupID = evetypes.GetGroupID(itemTypeID) 1505 itemRow = item[2] 1506 if evetypes.GetCategoryID(itemTypeID) != const.categoryShip or not itemRow.singleton: 1507 raise UserError('ConMultiContractNotShip') 1508 if itemGroupID in ILLEGAL_ITEMGROUPS: 1509 raise UserError('ConIllegalType') 1510 if itemID in (session.shipid, eveCfg.GetActiveShip()): 1511 raise UserError('ConCannotTradeCurrentShip') 1512 1513 div = self.data.startStationDivision if isForCorp else const.flagHangar 1514 numByContainerItemIDs = sm.GetService('contracts').GetNumItemsInContainers(self.data.startStation, self.data.items.keys(), isForCorp, div) 1515 self.data.numByContainerItemIDs = numByContainerItemIDs 1516 totalItems = sum(numByContainerItemIDs.itervalues()) 1517 if totalItems: 1518 if prompt_player_fsd_dialog('ConMultiContractConfirmShipNumAndContent', {'numShips': len(numByContainerItemIDs), 1519 'numItems': totalItems}, buttons=uiconst.YESNO, modal=True, suppress=uiconst.ID_YES) != uiconst.ID_YES: 1520 return 1521 else: 1522 self.data.childItems = {} 1523 for i in self.data.items: 1524 typeID = self.data.items[i][0] 1525 groupID = evetypes.GetGroupID(typeID) 1526 categoryID = evetypes.GetCategoryID(typeID) 1527 if groupID in ILLEGAL_ITEMGROUPS: 1528 raise UserError('ConIllegalType') 1529 if i in (session.shipid, eveCfg.GetActiveShip()): 1530 raise UserError('ConCannotTradeCurrentShip') 1531 isContainer = categoryID == const.categoryShip or groupID in (const.groupCargoContainer, 1532 const.groupSecureCargoContainer, 1533 const.groupAuditLogSecureContainer, 1534 const.groupFreightContainer) 1535 if isContainer: 1536 div = const.flagHangar 1537 if self.data.forCorp: 1538 div = self.data.startStationDivision 1539 itemNameList = [] 1540 totalVolume = 0 1541 for l in sm.GetService('contracts').GetItemsInContainer(self.data.startStation, i, self.data.forCorp, div) or []: 1542 itemNameList.append(TypeName(l.typeID)) 1543 val = [l.itemID, l.typeID, l.stacksize] 1544 if i not in self.data.childItems: 1545 self.data.childItems[i] = [] 1546 self.data.childItems[i].append(val) 1547 totalVolume += GetItemVolume(l, l.stacksize) 1548 1549 if itemNameList: 1550 itemsText = ', '.join(itemNameList) 1551 msg = 'ConNonEmptyShip' if evetypes.GetCategoryID(typeID) == const.categoryShip else 'ConNonEmptyContainer2' 1552 if prompt_player_fsd_dialog(msg, {'container': typeID, 1553 'items': itemsText, 1554 'volume': totalVolume}, uiconst.YESNO, suppress=uiconst.ID_YES) != uiconst.ID_YES: 1555 return False 1556 1557 if contractType == const.conTypeCourier: 1558 volume = 0 1559 for i in self.data.items: 1560 evetypes.RaiseIFNotExists(self.data.items[i][0]) 1561 item = self.data.items[i][2] 1562 volume += GetItemVolume(item, int(self.data.items[i][1])) 1563 1564 if volume > const_conCourierMaxVolume: 1565 raise UserError('ConExceedsMaxVolume', {'max': const_conCourierMaxVolume, 1566 'vol': volume}) 1567 elif volume > const_conCourierWarningVolume: 1568 if prompt_player_fsd_dialog('ConNeedFreighter', {'vol': volume}, uiconst.YESNO, suppress=uiconst.ID_YES) != uiconst.ID_YES: 1569 return False 1570 if not self.data.startStation or self.data.startStation == 0: 1571 raise UserError('CustomInfo', {'info': GetByLabel('UI/Contracts/ContractsService/UserErrorSelectStartingPointForContract')}) 1572 elif contractType in [const.conTypeCourier, const.conTypeAuction] and len(self.data.items) == 0: 1573 raise UserError('CustomInfo', {'info': GetByLabel('UI/Contracts/ContractsService/UserErrorSelectItemsForContract')}) 1574 if contractType in [const.conTypeAuction, const.conTypeItemExchange]: 1575 insuranceContracts = [] 1576 for i in self.data.items: 1577 item = self.data.items[i] 1578 categoryID = evetypes.GetCategoryID(item[0]) 1579 if item[2].singleton and categoryID == const.categoryShip: 1580 contract = sm.GetService('insurance').GetContractForShip(i) 1581 if contract: 1582 insuranceContracts.append([contract, item[0]]) 1583 1584 for contract in insuranceContracts: 1585 example = contract[1] 1586 if (contract[0].ownerID == session.corpid or self.data.forCorp) and self.data.avail != const.conAvailPublic: 1587 if prompt_player_fsd_dialog('ConInsuredShipCorp', {'example': example}, uiconst.YESNO) != uiconst.ID_YES: 1588 doContinue = False 1589 return doContinue 1590 elif prompt_player_fsd_dialog('ConInsuredShip', {'example': example}, uiconst.YESNO) != uiconst.ID_YES: 1591 return False 1592 1593 for i in self.data.items: 1594 item = self.data.items[i] 1595 categoryID = evetypes.GetCategoryID(item[0]) 1596 if categoryID == const.categoryShip and item[2].singleton: 1597 sm.GetService('invCache').RemoveInventoryContainer(item[2]) 1598 1599 self.LockItems(self.data.items) 1600 return True 1601 1602 def FinishStep2(self): 1603 if hasattr(self.data, 'price'): 1604 self.data.price = int(self.data.price) 1605 if hasattr(self.data, 'reward'): 1606 self.data.reward = int(self.data.reward) 1607 if hasattr(self.data, 'collateral'): 1608 self.data.collateral = int(self.data.collateral) 1609 if len(self.data.description) > MAX_TITLE_LENGTH: 1610 errorLabel = GetByLabel('UI/Contracts/ContractsService/UserErrorContractTitleTooLong', length=len(self.data.description), maxLength=MAX_TITLE_LENGTH) 1611 raise UserError('CustomInfo', {'info': errorLabel}) 1612 if self.data.description: 1613 bannedwords.check_words_allowed(self.data.description) 1614 contractType = self.data.type 1615 if contractType == const.conTypeAuction: 1616 self.FinishStep2_AuctionContracts() 1617 elif contractType == const.conTypeCourier: 1618 doContinue = self.FinishStep2_CourierContract() 1619 if not doContinue: 1620 return False 1621 elif self.IsFittedShipContract(contractType): 1622 self.FinishStep2_FittedShip() 1623 elif contractType == const.conTypeItemExchange: 1624 self.FinishStep2_ItemExchangeContract() 1625 else: 1626 raise RuntimeError('Not implemented!') 1627 return True 1628 1629 def FinishStep2_AuctionContracts(self): 1630 if self.data.price < const_conBidMinimum and self.data.avail == 0: 1631 errorLabel = GetByLabel('UI/Contracts/ContractsWindow/ErrorMinimumBidTooLow', minimumBid=const_conBidMinimum) 1632 raise UserError('CustomInfo', {'info': errorLabel}) 1633 elif self.data.price > self.data.collateral and self.data.collateral > 0: 1634 errorLabel = GetByLabel('UI/Contracts/ContractsService/UserErrorCannotSpecifyBidOverBuyout') 1635 raise UserError('CustomInfo', {'info': errorLabel}) 1636 1637 def FinishStep2_CourierContract(self): 1638 if not self.data.endStation and len(self.form.sr.endStationName.GetValue()) > 0: 1639 self.SearchStationFromEdit(self.form.sr.endStationName) 1640 if not self.data.endStation: 1641 return False 1642 if not self.data.endStation: 1643 errorLabel = GetByLabel('UI/Contracts/ContractsService/UserErrorMustSpecifyContractDestination') 1644 raise UserError('CustomInfo', {'info': errorLabel}) 1645 if not self.data.assigneeID: 1646 if self.data.reward < MIN_CONTRACT_MONEY: 1647 errorLabel = GetByLabel('UI/Contracts/ContractsService/UserErrorMinimumRewardNotMet', minimum=MIN_CONTRACT_MONEY) 1648 raise UserError('CustomInfo', {'info': errorLabel}) 1649 if self.data.collateral < MIN_CONTRACT_MONEY: 1650 errorLabel = GetByLabel('UI/Contracts/ContractsService/UserErrorMinimumCollateralNotMet', minimum=MIN_CONTRACT_MONEY) 1651 raise UserError('CustomInfo', {'info': errorLabel}) 1652 return True 1653 1654 def FinishStep2_ItemExchangeContract(self): 1655 if self.data.price != 0.0 and self.data.reward != 0.0: 1656 errorLabel = GetByLabel('UI/Contracts/ContractsService/UserErrorCannotGiveAndReceiveISK') 1657 raise UserError('CustomInfo', {'info': errorLabel}) 1658 if not self.data.assigneeID: 1659 if self.data.reqItems == {} and self.data.price < MIN_CONTRACT_MONEY: 1660 errorLabel = GetByLabel('UI/Contracts/ContractsService/UserErrorExchangeContractRequestNotMet', minimum=MIN_CONTRACT_MONEY) 1661 raise UserError('CustomInfo', {'info': errorLabel}) 1662 if self.reqItemTypeWnd.GetValue() != '': 1663 errorLabel = GetByLabel('UI/Contracts/ContractsService/UserErrorMustClickAddItem') 1664 raise UserError('CustomInfo', {'info': errorLabel}) 1665 if not self.data.assigneeID: 1666 if (self.data.reqItems != {} or self.data.price > 0) and len(self.data.items) == 0 and self.data.reward == 0: 1667 errorLabel = GetByLabel('UI/Contracts/ContractsService/UserErrorCannotCreateOneSidedExchangeContract') 1668 raise UserError('CustomInfo', {'info': errorLabel}) 1669 1670 def FinishStep2_FittedShip(self): 1671 if getattr(self.data, 'reward', 0): 1672 raise UserError('ConMultiContracCannotOfferIsk') 1673 if self.data.reqItems: 1674 raise UserError('ConMultiContractCannotAskForItems') 1675 if not self.data.assigneeID: 1676 if self.data.price < MIN_CONTRACT_MONEY: 1677 errorLabel = GetByLabel('UI/Contracts/ContractsService/UserErrorExchangeContractRequestNotMet', minimum=MIN_CONTRACT_MONEY) 1678 raise UserError('CustomInfo', {'info': errorLabel}) 1679 if not len(self.data.items): 1680 raise UserError('CustomInfo', {'info': 'You need to include at least 1 ship'}) 1681 1682 def OnComboChange(self, wnd, *args): 1683 if wnd.name == 'startStation' or wnd.name == 'startStationDivision': 1684 if wnd.name == 'startStation': 1685 self.data.startStation = wnd.GetValue() 1686 else: 1687 self.data.startStationDivision = wnd.GetValue() 1688 self.data.items = {} 1689 self.GotoPage(self.currPage) 1690 1691 def OnStepChange(self, move, *args): 1692 if self.currPage + move >= 4: 1693 if prompt_player_fsd_dialog('ConConfirmCreateContract', {}, uiconst.YESNO, suppress=uiconst.ID_YES) == uiconst.ID_YES: 1694 try: 1695 self.CreateContract() 1696 except: 1697 self.Maximize() 1698 raise 1699 1700 elif self.currPage + move >= 0 and (move < 0 or self.FinishStep(self.currPage)): 1701 self.GotoPage(self.currPage + move) 1702 1703 def ClickItem(self, *args): 1704 pass 1705 1706 def OnDeleteContracts(self, *args): 1707 self.numOutstandingContracts = None 1708 1709 def OnCancel(self, *args): 1710 if prompt_player_fsd_dialog('ConAreYouSureYouWantToCancel', None, uiconst.YESNO, suppress=uiconst.ID_YES) == uiconst.ID_YES: 1711 self.Close() 1712 1713 def ResetWizard(self): 1714 self.data = utillib.KeyVal() 1715 self.data.items = {} 1716 self.data.reqItems = {} 1717 self.data.startStation = None 1718 self.data.endStation = None 1719 self.data.startStationDivision = 0 1720 self.data.type = const.conTypeNothing 1721 self.SetMainIcon(GetContractIcon(const.conTypeNothing)) 1722 1723 def WriteSelectItems(self, title): 1724 contractType = self.data.type 1725 forCorp = self.data.forCorp 1726 deliveriesRoles = const.corpRoleAccountant | const.corpRoleJuniorAccountant | const.corpRoleTrader 1727 if self.IsFittedShipContract(contractType): 1728 currentNum, maxNumContracts = self.GetNumContractsAndLimits(forCorp, getattr(self.data, 'assigneeID', 0)) 1729 maxMultiContracts = GetMaxShipsToContract(sm.GetService('machoNet')) 1730 maxMultiContract = min(maxMultiContracts, maxNumContracts - currentNum) 1731 text = GetByLabel('UI/Contracts/ContractsWindow/ItemExchangeSelectShips', numShips=maxMultiContract) 1732 eveLabel.EveLabelMedium(text=text, parent=self.formWnd, state=uiconst.UI_DISABLED, align=uiconst.TOTOP, padding=(7, 0, 7, 0)) 1733 itemIDsToRemove = set() 1734 for itemID, item in self.data.items.iteritems(): 1735 itemRow = item[2] 1736 if evetypes.GetCategoryID(item[0]) != const.categoryShip or not itemRow.singleton: 1737 itemIDsToRemove.add(itemID) 1738 1739 for eachItemID in itemIDsToRemove: 1740 self.data.items.pop(eachItemID) 1741 1742 if forCorp: 1743 rows = sm.RemoteSvc('corpmgr').GetAssetInventory(session.corpid, 'offices') 1744 sortops = [] 1745 for r in rows: 1746 stationName = cfg.evelocations.Get(r.locationID).name 1747 sortops.append((stationName, (stationName, r.locationID))) 1748 1749 if session.corprole & deliveriesRoles > 0: 1750 rows = sm.RemoteSvc('corpmgr').GetAssetInventory(session.corpid, 'deliveries') 1751 for r in rows: 1752 stationName = cfg.evelocations.Get(r.locationID).name 1753 stat = (stationName, (stationName, r.locationID)) 1754 if stat not in sortops: 1755 sortops.append(stat) 1756 1757 ops = [(title, 0)] + SortListOfTuples(sortops) 1758 else: 1759 stations = sm.GetService('invCache').GetInventory(const.containerGlobal).ListStations() 1760 primeloc = [] 1761 for station in stations: 1762 primeloc.append(station.stationID) 1763 1764 if len(primeloc): 1765 cfg.evelocations.Prime(primeloc) 1766 sortops = [] 1767 for station in stations: 1768 stationName = cfg.evelocations.Get(station.stationID).name 1769 itemCount = station.itemCount 1770 if station.stationID in (session.stationid, session.structureid): 1771 itemCount -= 1 1772 itemsInStationLabel = GetByLabel('UI/Contracts/ContractsService/ItemsInStation', station=station.stationID, numItems=itemCount) 1773 sortops.append((stationName.lower(), (itemsInStationLabel, station.stationID))) 1774 1775 ops = [(title, 0)] + SortListOfTuples(sortops) 1776 comboParent = Container(name='comboParent', parent=self.formWnd, align=uiconst.TOTOP, top=const.defaultPadding) 1777 Container(name='push', parent=comboParent, align=uiconst.TOLEFT, width=1) 1778 Container(name='push', parent=comboParent, align=uiconst.TORIGHT, width=1) 1779 combo = Combo(label=None, parent=comboParent, options=ops, name='startStation', select=None, callback=self.OnComboChange, align=uiconst.TOALL) 1780 comboParent.height = Combo.default_height 1781 if self.data.startStation is None: 1782 if session.stationid: 1783 self.data.startStation = session.stationid 1784 elif session.structureid: 1785 self.data.startStation = session.structureid 1786 if forCorp: 1787 divs = [(GetByLabel('UI/Contracts/ContractsWindow/SelectDivision'), 0)] 1788 divisions = sm.GetService('corp').GetDivisionNames() 1789 for flagID in const.flagCorpSAGs: 1790 divisionID = const.corpDivisionsByFlag[flagID] 1791 divisionName = divisions[divisionID + 1] 1792 divs.append((divisionName, flagID)) 1793 1794 if session.corprole & deliveriesRoles > 0: 1795 divs.append((GetByLabel('UI/Contracts/ContractsWindow/Deliveries'), const.flagCorpDeliveries)) 1796 comboDiv = Combo(label='', parent=comboParent, options=divs, name='startStationDivision', select=None, callback=self.OnComboChange, align=uiconst.TORIGHT, width=100, pos=(1, 0, 0, 0), idx=0) 1797 Container(name='push', parent=comboParent, align=uiconst.TORIGHT, width=4, idx=1) 1798 nudge = 18 1799 for i, entry in enumerate(combo.entries): 1800 if entry.returnValue == self.data.startStation: 1801 combo.SelectItemByIndex(i) 1802 break 1803 1804 if forCorp: 1805 for i, entry in enumerate(comboDiv.entries): 1806 if entry.returnValue == self.data.startStationDivision: 1807 comboDiv.SelectItemByIndex(i) 1808 break 1809 1810 c = Container(name='volume', parent=self.formWnd, align=uiconst.TOBOTTOM, width=6, height=20) 1811 numVolLabel = GetByLabel('UI/Contracts/ContractsService/NumberOfWithVolume', number=0, volume=0) 1812 self.sr.volumeText = eveLabel.EveLabelMedium(text=numVolLabel, parent=c, state=uiconst.UI_DISABLED, align=uiconst.CENTERRIGHT) 1813 self.UpdateNumberOfItems() 1814 self.sr.itemsScroll = eveScroll.Scroll(parent=self.formWnd, padTop=const.defaultPadding, padBottom=const.defaultPadding) 1815 self.toggleSelectAllCheckbox = Checkbox(parent=self.sr.itemsScroll, align=uiconst.TOPLEFT, checked=0, left=7, callback=self.OnSelectAllCheckboxClicked, idx=0, top=-1) 1816 self.toggleSelectAllCheckbox.display = False 1817 if forCorp: 1818 if not self.data.startStation: 1819 self.sr.itemsScroll.ShowHint(GetByLabel('UI/Search/SelectStation')) 1820 if self.data.startStationDivision == 0: 1821 self.sr.itemsScroll.ShowHint(GetByLabel('UI/Contracts/ContractEntry/SelectStationDivision')) 1822 elif self.data.startStationDivision == 0: 1823 self.sr.itemsScroll.ShowHint(GetByLabel('UI/Contracts/ContractsWindow/SelectDivision')) 1824 validStartStation = self.data.startStation and self.CanContractItemsFromLocation(self.data.startStation) 1825 if validStartStation and (not forCorp or self.data.startStationDivision): 1826 self.sr.itemsScroll.Load(contentList=[], headers=[], noContentHint=GetByLabel('UI/Contracts/ContractsWindow/NoItemsFound')) 1827 self.sr.itemsScroll.ShowHint(GetByLabel('UI/Contracts/ContractsWindow/GettingItems')) 1828 items = sm.GetService('contracts').GetItemsInDockableLocation(self.data.startStation, forCorp) 1829 self.sr.itemsScroll.hiliteSorted = 0 1830 scrolllist = [] 1831 1832 def sameFlag(itemFlag): 1833 if itemFlag == self.data.startStationDivision: 1834 return True 1835 if set((itemFlag, self.data.startStationDivision)) == set((const.flagHangar, const.flagCorpSAG1)): 1836 return True 1837 return False 1838 1839 isFittedShipContract = self.IsFittedShipContract(contractType) 1840 uix.PrimeEveLocationsBeforeGetItemName(items) 1841 contractType = self.data.type 1842 for item in items: 1843 if forCorp and not sameFlag(item.flagID): 1844 continue 1845 data = uix.GetItemData(item, 'list', viewOnly=1) 1846 volume = GetItemVolume(item) 1847 itemName = '' 1848 isContainer = item.groupID in (const.groupCargoContainer, 1849 const.groupSecureCargoContainer, 1850 const.groupAuditLogSecureContainer, 1851 const.groupFreightContainer) and item.singleton 1852 if item.categoryID == const.categoryShip or isContainer: 1853 if item.itemID == eveCfg.GetActiveShip(): 1854 continue 1855 shipName = cfg.evelocations.GetIfExists(item.itemID) 1856 if shipName is not None: 1857 itemName = shipName.locationName 1858 if isFittedShipContract and item.categoryID != const.categoryShip: 1859 continue 1860 scrolllist.append(GetFromClass(ContractItemSelect, {'info': item, 1861 'stationID': self.data.startStation, 1862 'forCorp': forCorp, 1863 'flag': item.flagID, 1864 'itemID': item.itemID, 1865 'typeID': item.typeID, 1866 'isCopy': item.categoryID == const.categoryBlueprint and item.singleton == const.singletonBlueprintCopy, 1867 'label': '%s<t>%s<t>%s<t>%s' % (evetypes.GetName(item.typeID), 1868 item.stacksize, 1869 volume, 1870 itemName), 1871 'quantity': item.stacksize, 1872 'getIcon': 1, 1873 'item': item, 1874 'checked': item.itemID in self.data.items, 1875 'cfgname': item.itemID, 1876 'itemData': (item, 1877 item.itemID, 1878 item.typeID, 1879 item.stacksize), 1880 'OnChange': self.OnItemSelectedChanged, 1881 'GetSortValue': self.GetItemNodeSortValue})) 1882 1883 if self.sr.itemsScroll is not None: 1884 if scrolllist: 1885 self.sr.itemsScroll.ShowHint() 1886 self.sr.itemsScroll.sr.id = 'itemsScroll' 1887 self.sr.itemsScroll.sr.lastSelected = None 1888 headers = [GetByLabel('UI/Common/Type'), 1889 GetByLabel('UI/Inventory/ItemQuantityShort'), 1890 GetByLabel('UI/Common/Volume'), 1891 GetByLabel('UI/Common/Details')] 1892 if combo.GetValue() == 0: 1893 noContentHint = GetByLabel('UI/Search/SelectStation') 1894 elif isFittedShipContract: 1895 noContentHint = GetByLabel('UI/Contracts/ContractsWindow/NoShipFound') 1896 else: 1897 noContentHint = GetByLabel('UI/Contracts/ContractsWindow/NoItemsFound') 1898 self.sr.itemsScroll.GetEffectiveColumnOffset = lambda *args: 24 1899 self.toggleSelectAllCheckbox.display = bool(scrolllist) 1900 self.sr.itemsScroll.Load(contentList=scrolllist, headers=headers, noContentHint=noContentHint) 1901 self.UpdateSelectAllCheckbox() 1902 1903 def GetItemNodeSortValue(self, node, by, sortDirection, idx): 1904 ret = self.sr.itemsScroll._GetSortValue(by, node, idx) 1905 if node.checked: 1906 return (sortDirection, ret) 1907 return (not sortDirection, ret) 1908 1909 def IsFittedShipContract(self, contractType): 1910 if not GetMaxShipsToContract(sm.GetService('machoNet')): 1911 return False 1912 return contractType == const.conTypeItemExchange and self.isMultiContract 1913 1914 def CanContractItemsFromLocation(self, locationID): 1915 if idCheckers.IsStation(locationID): 1916 return True 1917 return sm.GetService('structureDirectory').CanContractFrom(locationID) 1918 1919 def UpdateSelectAllCheckbox(self): 1920 self.UpdateSelectAllCheckbox_throttled() 1921 1922 @throttled(0.5) 1923 def UpdateSelectAllCheckbox_throttled(self): 1924 if not self or self.destroyed or not self.sr.itemsScroll or self.sr.itemsScroll.destroyed: 1925 return 1926 selectedValues = {x.checked for x in self.sr.itemsScroll.GetNodes()} 1927 if selectedValues == {1}: 1928 self.toggleSelectAllCheckbox.SetChecked(True, False) 1929 self.toggleSelectAllCheckbox.hint = GetByLabel('UI/Common/DeselectAll') 1930 else: 1931 self.toggleSelectAllCheckbox.SetChecked(False, False) 1932 self.toggleSelectAllCheckbox.hint = GetByLabel('UI/Common/SelectAll') 1933 1934 def OnSelectAllCheckboxClicked(self, cb, *args): 1935 if cb.GetValue(): 1936 self.SelectAll() 1937 else: 1938 self.DeselectAll() 1939 self.UpdateSelectAllCheckbox() 1940 1941 def DeselectAll(self, *args): 1942 self.ChangeCheckboxStates(onoff=False) 1943 1944 def SelectAll(self, *args): 1945 self.ChangeCheckboxStates(onoff=True) 1946 1947 def ChangeCheckboxStates(self, onoff): 1948 if not self.sr.itemsScroll: 1949 return 1950 for node in self.sr.itemsScroll.GetNodes(): 1951 if node: 1952 node.checked = onoff 1953 if node.panel: 1954 node.panel.sr.checkbox.SetChecked(onoff, 0) 1955 self.ChangeItemSelection(onoff, updateNumber=False, *node.itemData) 1956 1957 self.UpdateNumberOfItems() 1958 1959 def OnItemSelectedChanged(self, isChecked, itemData, *args): 1960 item, itemID, typeID, qty = itemData 1961 self.ChangeItemSelection(isChecked, item, itemID, typeID, qty) 1962 self.UpdateSelectAllCheckbox() 1963 1964 def ChangeItemSelection(self, checkboxSelected, item, itemID, typeID, qty, updateNumber = True): 1965 if checkboxSelected: 1966 self.data.items[itemID] = [typeID, qty, item] 1967 elif itemID in self.data.items: 1968 del self.data.items[itemID] 1969 if updateNumber: 1970 self.UpdateNumberOfItems() 1971 1972 def UpdateNumberOfItems(self): 1973 num, totalVolume = self.GetVolumeOfAllItems() 1974 numVolLabel = GetByLabel('UI/Contracts/ContractsService/NumberOfWithVolume', number=num, volume=FmtAmt(totalVolume)) 1975 maxItems = MAX_NUM_ITEMS 1976 if self.IsFittedShipContract(self.data.type): 1977 maxItems = GetMaxShipsToContract(sm.GetService('machoNet')) 1978 currentNum, maxNumContracts = self.GetNumContractsAndLimits(self.data.forCorp, getattr(self.data, 'assigneeID', 0)) 1979 maxItems = min(maxItems, maxNumContracts - currentNum) 1980 if num > maxItems: 1981 numVolLabel = '<color=red>' + numVolLabel + '</color>' 1982 self.sr.volumeText.text = numVolLabel 1983 1984 def GetVolumeOfAllItems(self): 1985 totalVolume = 0 1986 num = 0 1987 for itemID, item in self.data.items.iteritems(): 1988 totalVolume += GetItemVolume(item[2]) 1989 num += 1 1990 1991 return (num, totalVolume) 1992 1993 def GetTypePrice(self, typeID): 1994 return GetAveragePrice(typeID) or evetypes.GetBasePrice(typeID) 1995 1996 def CalcEstPrice(self): 1997 price = 0 1998 for item in self.data.items.itervalues(): 1999 price += int(float(self.GetTypePrice(item[0])) / evetypes.GetPortionSize(item[0]) * item[1]) 2000 2001 price = RoundISK(price) 2002 if price == 0: 2003 raise UserError('ConNoEstPrice') 2004 return price 2005 2006 def SetCollateralToEstPrice(self, *args): 2007 price = self.CalcEstPrice() 2008 if prompt_player_fsd_dialog('ConEstPrice', {'price': FmtISK(price, 0)}, uiconst.YESNO, suppress=uiconst.ID_YES) == uiconst.ID_YES: 2009 self.formWnd.sr.collateral.SetValue(price) 2010 2011 def SetPriceToEstPrice(self, *args): 2012 price = self.CalcEstPrice() 2013 if prompt_player_fsd_dialog('ConEstPrice', {'price': FmtISK(price, 0)}, uiconst.YESNO, suppress=uiconst.ID_YES) == uiconst.ID_YES: 2014 self.formWnd.sr.price.SetValue(price) 2015 2016 def OnItemSplit(self, itemID, amountRemoved): 2017 if itemID in self.data.items: 2018 self.data.items[itemID][1] -= amountRemoved 2019 if self.data.items[itemID][1] <= 0: 2020 del self.data.items[itemID]