assetsWindow.py (45351B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\assetsWindow.py 2 import sys 3 from collections import defaultdict 4 import blue 5 import eveicon 6 import evetypes 7 import localization 8 import log 9 import uthread 10 import uthread2 11 import utillib 12 from carbonui.control.contextMenu.menuData import MenuData 13 from carbonui.util.sortUtil import SortListOfTuples 14 from player_messaging.client.ui_message import message_player 15 from evePathfinder.core import IsUnreachableJumpCount 16 from carbonui import TextColor, uiconst 17 from carbonui.control.button import Button 18 from carbonui.control.combo import Combo 19 from carbonui.control.window import Window 20 from carbonui.primitives.container import Container 21 from carbonui.primitives.containerAutoSize import ContainerAutoSize 22 from carbonui.primitives.sprite import Sprite 23 from carbonui.uianimations import animations 24 from carbonui.uicore import uicore 25 from carbonui.util.dpi import reverse_scale_dpi 26 from carbonui.window.header.tab_navigation import TabNavigationWindowHeader 27 from carbonui.window.settings import WindowMarginMode 28 from eve.client.script.ui.control import eveScroll 29 from eve.client.script.ui.control.entries.util import GetFromClass 30 from eve.client.script.ui.control.infoIcon import MoreInfoIcon 31 from eve.client.script.ui.control.listgroup import ListGroup 32 from carbonui.control.tabGroup import TabGroup 33 from eve.client.script.ui.control.entries.universe import LocationGroup 34 from eve.client.script.ui.shared.assets.assetSafety import AssetSafetyCont 35 from eve.client.script.ui.shared.assets.assetSafetyControllers import SafetyControllerCharacter 36 from eve.client.script.ui.shared.assetsSearch import SearchBox 37 from eve.client.script.ui.shared.inventory.invWindow import Inventory as InventoryWindow 38 from eve.client.script.ui.shared.item import InvAssetItem 39 from eve.client.script.ui.util import uix 40 from eve.client.script.ui.util.uix import IsValidNamedItem 41 from eve.common.lib import appConst as const 42 from eve.common.script.sys import idCheckers, eveCfg 43 from eve.common.script.sys.idCheckers import IsWormholeSystem, IsTriglavianSystem 44 from eveAssets.assetSearchUtil import SearchNamesHelper, AssetKeywordSearch, IsPartOfText, ParseString 45 from eveAssets.assetSearching import GetSearchResults, GetFakeRowset 46 from eveformat.client import solar_system_security_status 47 from eveservices.menu import GetMenuService, StartMenuService 48 from eveui import skip_if_destroyed 49 from localization import GetByLabel 50 from menu import MenuLabel 51 from menucheckers.itemCheckers import ItemChecker 52 SORT_BY_NAME = 0 53 SORT_BY_JUMPS = 1 54 SORT_BY_ITEMS = 2 55 SORT_BY_OPTIONS = [(GetByLabel('UI/Common/Name'), SORT_BY_NAME), (GetByLabel('UI/Common/NumberOfJumps'), SORT_BY_JUMPS), (GetByLabel('UI/Common/NumberOfItems'), SORT_BY_ITEMS)] 56 TYPE_ALLITEMS = 'allitems' 57 TYPE_REGION = 'regitems' 58 TYPE_CONSTELLATION = 'conitems' 59 TYPE_SYSTEM = 'sysitems' 60 FILTER_TYPE_OPTIONS = ((GetByLabel('UI/Inventory/AssetsWindow/AllItems'), TYPE_ALLITEMS), 61 (GetByLabel('UI/Common/LocationTypes/Region'), TYPE_REGION), 62 (GetByLabel('UI/Common/LocationTypes/Constellation'), TYPE_CONSTELLATION), 63 (GetByLabel('UI/Common/LocationTypes/SolarSystem'), TYPE_SYSTEM)) 64 WINDOW_CAPTION_LABEL = 'UI/Inventory/AssetsWindow/PersonalAssets' 65 WINDOW_SUBCAPTION_LABEL = 'UI/Inventory/AssetsWindow/DelayedFiveMinutes' 66 NO_CONTENT_HIT_BY_KEY = {'allitems': GetByLabel('UI/Inventory/AssetsWindow/NoAssetsAtStation'), 67 'regitems': GetByLabel('UI/Inventory/AssetsWindow/NoAssetsInRegion'), 68 'conitems': GetByLabel('UI/Inventory/AssetsWindow/NoAssetsInConstellation'), 69 'sysitems': GetByLabel('UI/Inventory/AssetsWindow/NoAssetsInSolarSystem')} 70 IMPORTANCE_NONE = 0 71 IMPORTANCE_PINNED = 1 72 IMPORTANCE_HIDDEN = -1 73 74 class AssetsWindow(Window): 75 __guid__ = 'form.AssetsWindow' 76 __notifyevents__ = ['OnDestinationSet'] 77 default_width = 550 78 default_height = 450 79 default_minSize = (395, 256) 80 default_windowID = 'assets' 81 default_captionLabelPath = 'Tooltips/Neocom/PersonalAssets' 82 default_descriptionLabelPath = 'Tooltips/Neocom/PersonalAssets_description' 83 default_iconNum = 'res:/ui/Texture/WindowIcons/assets.png' 84 _update_delay_hint = None 85 86 def __init__(self, **kwargs): 87 self._loading_thread = None 88 super(AssetsWindow, self).__init__(**kwargs) 89 90 def ApplyAttributes(self, attributes): 91 super(AssetsWindow, self).ApplyAttributes(attributes) 92 self.pathfinder = sm.GetService('clientPathfinderService') 93 self.key = None 94 self.invalidateOpenState_regitems = 1 95 self.invalidateOpenState_allitems = 1 96 self.invalidateOpenState_conitems = 1 97 self.invalidateOpenState_sysitems = 1 98 self.safetyCont = None 99 self.searchCont = None 100 self.filterCont = None 101 self.searchlist = None 102 self.stationTabs = None 103 self.searchEditBox = None 104 self.filterValueCombo = None 105 self.pending = None 106 self.loading = 0 107 self.station_inited = False 108 self.search_inited = False 109 self.filt_inited = False 110 self.nameHelper = SearchNamesHelper(sm.GetService('ui')) 111 self.assetKeywordSearch = AssetKeywordSearch(self.nameHelper, sm.GetService('ui'), sm.GetService('map'), sm.GetService('godma'), sm.GetService('structureDirectory'), localization, cfg) 112 self.searchKeywords = self.assetKeywordSearch.GetSearchKeywords() 113 if attributes.exactTypeID: 114 autoSelectTab = False 115 self.searchText = self.GetSearchTextForTypeID(attributes.exactTypeID) 116 else: 117 self.searchText = None 118 autoSelectTab = True 119 self.scrollPosition = defaultdict(float) 120 self.ReconstructLayout(autoSelectTab) 121 self._update_delay_hint = UpdateDelayHint(parent=self.header.extra_content, align=uiconst.TORIGHT, padding=self._get_update_delay_hint_padding()) 122 self.on_margin_mode_changed.connect(self._on_margin_mode_changed) 123 self.on_stacked_changed.connect(self._on_stacked_changed) 124 125 def _get_update_delay_hint_padding(self): 126 if self.stacked: 127 return (0, 0, 0, 0) 128 else: 129 return (8, 0, 8, 0) 130 131 def _update_update_delay_hint_padding(self): 132 if self._update_delay_hint: 133 self._update_delay_hint.padding = self._get_update_delay_hint_padding() 134 135 def _on_stacked_changed(self, window): 136 self._update_update_delay_hint_padding() 137 138 def OnDestinationSet(self, destinationID = None): 139 self.ReconstructLayout() 140 141 def ReloadTabs(self, *args): 142 self.tabGroup.ReloadVisible() 143 144 @skip_if_destroyed 145 def ReconstructLayout(self, autoSelectTab = True, *args): 146 self.station_inited = False 147 self.search_inited = False 148 self.filt_inited = False 149 try: 150 self.scrollPosition[self.key] = self.scroll.GetScrollProportion() 151 except Exception: 152 self.scrollPosition[self.key] = 0.0 153 154 self._RecoverSearchText() 155 self.sr.main.Flush() 156 self.scroll = eveScroll.Scroll(parent=self.sr.main, padding=(0, 8, 0, 0)) 157 self.scroll.sr.id = 'assets' 158 self.scroll.sr.minColumnWidth = {GetByLabel('UI/Common/Name'): 44} 159 self.scroll.allowFilterColumns = 1 160 self.scroll.OnNewHeaders = self.ReloadTabs 161 self.scroll.sortGroups = True 162 self.scroll.SetColumnsHiddenByDefault(uix.GetInvItemDefaultHiddenHeaders()) 163 self._ReconstructTabs() 164 if autoSelectTab: 165 self.tabGroup.AutoSelect(silently=True) 166 167 @skip_if_destroyed 168 def _ReconstructTabs(self): 169 self.tabGroup = self.header.tab_group 170 tabs = [(GetByLabel(self.default_captionLabelPath), 171 self.scroll, 172 self, 173 'allitems')] 174 tabs += [(GetByLabel('UI/Common/Buttons/Search'), 175 self.scroll, 176 self, 177 'search'), (GetByLabel('UI/Inventory/AssetSafety/AssetSafety'), 178 self.scroll, 179 self, 180 'safety', 181 None, 182 GetByLabel('UI/Inventory/AssetSafety/AssetSafetyHint'))] 183 self.tabGroup.Flush() 184 for tab in tabs: 185 self.tabGroup.AddTab(*tab) 186 187 def Prepare_Header_(self): 188 self.header = TabNavigationWindowHeader() 189 190 def _RecoverSearchText(self): 191 assetSearchBox = self.searchEditBox 192 if assetSearchBox: 193 self.searchText = assetSearchBox.GetValue() 194 195 def Load(self, key, reloadStationID = None): 196 if self.loading: 197 self.pending = (key, reloadStationID) 198 return 199 uthread.new(self._Load, key, reloadStationID) 200 201 def _Load(self, key, reloadStationID = None): 202 self.loading = 1 203 self.pending = None 204 if key != self.key: 205 self.scrollPosition[self.key] = self.scroll.GetScrollProportion() 206 self.key = key 207 if self.safetyCont: 208 self.safetyCont.display = False 209 if key == 'safety': 210 self.LoadAssetSafety() 211 elif key[:7] == 'station': 212 self.LoadCurrStation(key) 213 elif key in ('allitems', 'regitems', 'conitems', 'sysitems'): 214 self.LoadAssets(key) 215 elif key == 'search': 216 self.LoadSearch() 217 self.loading = 0 218 if self.pending: 219 self.Load(*self.pending) 220 221 def LoadAssetSafety(self): 222 223 def Hide(cont): 224 if cont: 225 cont.display = False 226 227 Hide(self.scroll) 228 Hide(self.searchCont) 229 Hide(self.filterCont) 230 Hide(self.stationTabs) 231 if self.safetyCont is None or self.safetyCont.destroyed: 232 self.safetyCont = AssetSafetyCont(parent=self.sr.main, controller=SafetyControllerCharacter()) 233 self.safetyCont.display = True 234 self.safetyCont.Load() 235 236 def LoadCurrStation(self, key): 237 if not self.station_inited: 238 self.stationTabs = TabGroup(name='tabparent2', parent=self.sr.main, idx=2) 239 tabs = [[GetByLabel('UI/Common/ItemTypes/Ships'), 240 self.scroll, 241 self, 242 '%sships' % key], 243 [GetByLabel('UI/Common/ItemTypes/Modules'), 244 self.scroll, 245 self, 246 '%smodules' % key], 247 [GetByLabel('UI/Common/ItemTypes/Charges'), 248 self.scroll, 249 self, 250 '%scharges' % key], 251 [GetByLabel('UI/Common/ItemTypes/Minerals'), 252 self.scroll, 253 self, 254 '%sminerals' % key], 255 [GetByLabel('UI/Common/Other'), 256 self.scroll, 257 self, 258 '%sother' % key]] 259 self.station_inited = 1 260 self.stationTabs.Startup(tabs, 'assetsatstation', silently=True) 261 if self.filterCont: 262 self.filterCont.state = uiconst.UI_HIDDEN 263 self.stationTabs.state = uiconst.UI_NORMAL 264 if self.searchCont: 265 self.searchCont.state = uiconst.UI_HIDDEN 266 if key != 'station': 267 self.ShowStationItems(key[7:]) 268 else: 269 self.stationTabs.AutoSelect(1) 270 271 def LoadAssets(self, key): 272 if not self.filt_inited: 273 self.ConstructFilterCont() 274 self.filt_inited = True 275 else: 276 self.filterCont.Show() 277 if self.stationTabs: 278 self.stationTabs.Hide() 279 if self.searchCont: 280 self.searchCont.Hide() 281 key = self.filterTypeCombo.GetValue() 282 self.PopulateScroll(key, None, None) 283 284 def ConstructFilterCont(self): 285 self.filterCont = Container(name='filterContainer', align=uiconst.TOTOP, state=uiconst.UI_PICKCHILDREN, height=Combo.default_height, parent=self.sr.main, padding=self._get_top_cont_padding(), idx=self.scroll.GetOrder()) 286 self.sortByCombo = Combo(label=GetByLabel('UI/Common/SortBy'), parent=self.filterCont, options=SORT_BY_OPTIONS, name='sortcombo', align=uiconst.TORIGHT, select=None, callback=self.Filter, width=115, padRight=4) 287 self.filterTypeCombo = Combo(name='filterTypeCombo', parent=self.filterCont, align=uiconst.TOLEFT, width=115, padRight=4, options=FILTER_TYPE_OPTIONS, select=settings.char.ui.Get('assets_window_filter_type', None), prefskey=('char', 'ui', 'assets_window_filter_type'), callback=self.OnFilterTypeCombo) 288 self.filterValueCombo = Combo(parent=self.filterCont, options=[], name='filtcombo', select=None, callback=self.Filter, width=115, align=uiconst.TOLEFT, padRight=4) 289 self.UpdateFilterValueComboVisibility() 290 291 def OnFilterTypeCombo(self, *args): 292 self.filterTypeCombo.UpdateSettings() 293 self.UpdateFilterValueComboVisibility() 294 self.Filter() 295 296 def UpdateFilterValueComboVisibility(self): 297 self.filterValueCombo.display = self.filterTypeCombo.GetValue() != TYPE_ALLITEMS 298 299 def _get_top_cont_padding(self): 300 if self.margin_mode == WindowMarginMode.COMPACT: 301 return (0, 12, 0, 0) 302 else: 303 return (0, 4, 0, 0) 304 305 def _on_margin_mode_changed(self, window): 306 if self.searchCont is not None: 307 self.searchCont.padding = self._get_top_cont_padding() 308 if self.filterCont is not None: 309 self.filterCont.padding = self._get_top_cont_padding() 310 311 def LoadSearch(self): 312 if self.stationTabs: 313 self.stationTabs.state = uiconst.UI_HIDDEN 314 if not self.search_inited: 315 self.searchCont = Container(name='searchCont', align=uiconst.TOTOP, height=32, parent=self.sr.main, idx=self.scroll.GetOrder(), padding=self._get_top_cont_padding()) 316 Container(name='comboCont', align=uiconst.TOLEFT, parent=self.searchCont, width=108) 317 self.sortByCombosearch = Combo(label=GetByLabel('UI/Common/SortBy'), parent=self.searchCont, options=SORT_BY_OPTIONS, name='sortcombosearch', select=settings.char.ui.Get('assetsSearchSortKey', None), callback=self.Search, width=100, pos=(0, 0, 0, 0)) 318 buttonCont = ContainerAutoSize(name='bottonCont', parent=self.searchCont, align=uiconst.TORIGHT) 319 infoIcon = MoreInfoIcon(name='infoIcon', parent=buttonCont, align=uiconst.CENTERRIGHT) 320 infoIcon.LoadTooltipPanel = self.LoadInfoTooltip 321 button = Button(name='searchButton', parent=buttonCont, align=uiconst.CENTERRIGHT, left=infoIcon.left + infoIcon.width + 8, label=GetByLabel('UI/Common/Buttons/Search'), func=self.Search) 322 self.searchEditBox = SearchBox(name='assetssearchtype', parent=self.searchCont, align=uiconst.TOALL, width=0, padding=(0, 0, 8, 0), label=GetByLabel('UI/Common/SearchText'), maxLength=100, OnReturn=self.Search, OnClearFilter=self.Search, keywords=self.searchKeywords, isTypeField=True) 323 self.searchEditBox.ShowClearButton() 324 self.searchEditBox.SetValueAfterDragging = self.SetSearchTypeValueAfterDragging 325 self._RestoreSearchText() 326 self.search_inited = 1 327 if self.filterCont: 328 self.filterCont.state = uiconst.UI_HIDDEN 329 self.searchCont.state = uiconst.UI_PICKCHILDREN 330 sortKeySearch = settings.char.ui.Get('assetsSearchSortKey', None) 331 searchlist = getattr(self, 'searchlist', []) 332 if searchlist: 333 self._start_loading_thread(self._LoadSearch, sortKeySearch) 334 else: 335 self.Search() 336 337 def SetSearchTypeValueAfterDragging(self, name, draggedValue): 338 name = self.GetSearchTextForTypeID(draggedValue) 339 SearchBox.SetValueAfterDragging(self.searchEditBox, name, draggedValue) 340 341 def _RestoreSearchText(self): 342 if self.searchText: 343 searchBox = self.searchEditBox 344 if searchBox: 345 searchBox.SetValue(self.searchText) 346 347 def Filter(self, *args): 348 key = self.filterTypeCombo.GetValue() 349 keyID = self.filterValueCombo.GetValue() 350 sortKey = self.sortByCombo.GetValue() 351 self.PopulateScroll(key, keyID, sortKey) 352 353 def GetConditions(self, advancedMatches): 354 conditions = [] 355 for word, value in advancedMatches: 356 try: 357 for kw in self.searchKeywords: 358 if IsPartOfText(kw.keyword, word): 359 kw.matchFunction(conditions, value) 360 break 361 362 except: 363 import log 364 log.LogException() 365 sm.GetService('assets').LogInfo('Failed parsing keyword', word, 'value', value, 'and happily ignoring it') 366 367 return conditions 368 369 def Search(self, *args): 370 self._start_loading_thread(self.Search_thread) 371 372 def Search_thread(self, *args): 373 self.ShowLoad() 374 try: 375 if self.tabGroup.GetSelectedArgs() == 'search': 376 self.scroll.Load(contentList=[], noContentHint=GetByLabel('UI/Common/GettingData')) 377 blue.pyos.synchro.Yield() 378 log.LogNotice('Asset Search - fetch items') 379 invContainer = sm.GetService('invCache').GetInventory(const.containerGlobal) 380 allitems = invContainer.ListIncludingContainers() 381 log.LogNotice('Asset Search - items fetched =', len(allitems)) 382 itemRowset = GetFakeRowset(allitems) 383 log.LogNotice('Asset Search - fake rows created') 384 blue.pyos.synchro.Yield() 385 if self.tabGroup.GetSelectedArgs() == 'search': 386 self.scroll.Load(contentList=[], noContentHint=GetByLabel('UI/Common/Searching')) 387 blue.pyos.synchro.Yield() 388 searchtype = unicode(self.searchEditBox.GetValue() or '').lower() 389 searchtype, advancedMatches = ParseString(searchtype) 390 conditions = self.GetConditions(advancedMatches) 391 self.assetKeywordSearch.ResetPerRunDicts() 392 allContainersByItemIDs, itemsByContainerID, stations = GetSearchResults(conditions, itemRowset, searchtype) 393 containersInfoByStations = defaultdict(lambda : defaultdict(tuple)) 394 for containerID, itemsInContainer in itemsByContainerID.iteritems(): 395 containerItem = allContainersByItemIDs.get(containerID) 396 if containerItem and containerItem.typeID == const.typePlasticWrap: 397 continue 398 if containerItem: 399 containersInfoByStations[containerItem.locationID][containerID] = (containerItem, itemsInContainer) 400 401 for stationID in containersInfoByStations.iterkeys(): 402 stations[stationID].extend([]) 403 404 sortlocations = [] 405 ownerStations = sm.GetService('invCache').GetInventory(const.containerGlobal).ListStations().Index('stationID') 406 for stationID, stationItems in stations.iteritems(): 407 stationData = ownerStations.get(stationID, None) 408 if stationData is None: 409 continue 410 stationsContainersInfo = containersInfoByStations.get(stationID, {}) 411 sortlocations.append((stationData.solarSystemID, 412 stationID, 413 stationItems, 414 stationsContainersInfo)) 415 416 sortlocations.sort() 417 sortlocations = sortlocations 418 self.searchlist = sortlocations 419 sortKey = self.sortByCombosearch.GetValue() 420 self._LoadSearch(sortKey) 421 finally: 422 self.HideLoad() 423 424 def PopulateScroll(self, key, keyID, sortKey, *args): 425 if keyID is None: 426 keyID = settings.char.ui.Get('assetsKeyID_%s' % key, None) 427 oldSortKey = settings.char.ui.Get('assetsSortKey', None) 428 if sortKey is not None: 429 if oldSortKey != sortKey: 430 for k in self.scrollPosition.keys(): 431 self.scrollPosition[k] = 0.0 432 433 else: 434 sortKey = oldSortKey 435 settings.char.ui.Set('assetsKeyID_%s' % key, keyID) 436 settings.char.ui.Set('assetsSortKey', sortKey) 437 self.ShowLoad() 438 self.SetHint() 439 closed = [0, 1][getattr(self, 'invalidateOpenState_%s' % key, 0)] 440 sortlocations = sm.GetService('assets').GetAll(key, keyID=keyID, sortKey=sortKey) 441 try: 442 options = self.GetFilterValueComboOptions(key) 443 self.filterValueCombo.LoadOptions(options, None) 444 if keyID: 445 self.filterValueCombo.SelectItemByLabel(cfg.evelocations.Get(keyID).name) 446 if sortKey: 447 self.sortByCombo.SelectItemByIndex(sortKey) 448 except (Exception,): 449 sys.exc_clear() 450 451 allImportanceSettings = settings.char.ui.Get('assets_window_importance', {}) 452 destPathList = sm.GetService('starmap').GetDestinationPath() 453 scrolllist = [] 454 hiddenEntries = [] 455 for solarsystemID, station in sortlocations: 456 importanceValue = allImportanceSettings.get(station.stationID, IMPORTANCE_NONE) 457 data = self.GetLocationData(solarsystemID, station, key, forceClosed=closed, scrollID=self.scroll.sr.id, sortKey=sortKey, path=destPathList, importanceValue=importanceValue) 458 blue.pyos.BeNice() 459 entry = GetFromClass(LocationGroup, data) 460 if importanceValue == IMPORTANCE_HIDDEN: 461 hiddenEntries.append(entry) 462 else: 463 scrolllist.append(entry) 464 465 if hiddenEntries: 466 scrolllist.append(self.GetHiddenEntry(hiddenEntries)) 467 if self.destroyed: 468 return 469 setattr(self, 'invalidateOpenState_%s' % key, 0) 470 scrollPosition = self.scrollPosition[key] 471 self.scroll.Load(contentList=scrolllist, headers=uix.GetInvItemDefaultHeaders(), noContentHint=NO_CONTENT_HIT_BY_KEY[key], scrollTo=scrollPosition, showCollapseIcon=True) 472 self.HideLoad() 473 474 def GetHiddenSubContent(self, nodedata, *args): 475 return nodedata.groupItems 476 477 def GetHiddenEntry(self, hiddenEntries): 478 data = {'GetSubContent': self.GetHiddenSubContent, 479 'label': 'Hidden', 480 'groupItems': hiddenEntries, 481 'id': 'assetslocations_hiddenEntries', 482 'state': 'locked', 483 'showicon': eveicon.hidden, 484 'showlen': 1, 485 'BlockOpenWindow': 1} 486 return GetFromClass(ListGroup, data) 487 488 def GetFilterValueComboOptions(self, key): 489 key = self.filterTypeCombo.GetValue() 490 options = [(GetByLabel('UI/Common/Current'), 0)] 491 opts = {} 492 for r in sm.GetService('assets').locationCache.iterkeys(): 493 if key == 'regitems' and idCheckers.IsRegion(r) or key == 'conitems' and idCheckers.IsConstellation(r) or key == 'sysitems' and idCheckers.IsSolarSystem(r): 494 opts[cfg.evelocations.Get(r).name] = r 495 496 keys = opts.keys() 497 keys.sort() 498 for k in keys: 499 options.append((k, opts[k])) 500 501 return options 502 503 def ShowStationItems(self, key): 504 self.ShowLoad() 505 hangarInv = sm.GetService('invCache').GetInventory(const.containerHangar) 506 items = hangarInv.List(const.flagHangar) 507 if not len(items): 508 self.SetHint(GetByLabel('UI/Inventory/AssetsWindow/NoAssets')) 509 return 510 assetsList = [] 511 self.scroll.Load(fixedEntryHeight=42, contentList=[], headers=uix.GetInvItemDefaultHeaders()) 512 itemname = ' ' + key 513 itemSet = set() 514 for each in items: 515 if each.flagID not in (const.flagHangar, const.flagWallet): 516 continue 517 if key == 'ships': 518 if each.categoryID != const.categoryShip: 519 continue 520 elif key == 'modules': 521 if not evetypes.IsCategoryHardwareByCategory(evetypes.GetCategoryID(each.typeID)): 522 continue 523 elif key == 'minerals': 524 if each.groupID != const.groupMineral: 525 continue 526 elif key == 'charges': 527 if each.categoryID != const.categoryCharge: 528 continue 529 else: 530 itemname = None 531 if each.categoryID == const.categoryShip or evetypes.IsCategoryHardwareByCategory(evetypes.GetCategoryID(each.typeID)) or each.groupID == const.groupMineral or each.categoryID == const.categoryCharge: 532 continue 533 itemSet.add(each) 534 535 self.PrimeLocationNames(itemSet) 536 for eachItem in itemSet: 537 assetsList.append(GetFromClass(InvAssetItem, uix.GetItemData(eachItem, 'details', scrollID=self.scroll.sr.id))) 538 539 locText = {'ships': GetByLabel('UI/Inventory/AssetsWindow/NoShipsAtStation'), 540 'modules': GetByLabel('UI/Inventory/AssetsWindow/NoModulesAtStation'), 541 'minerals': GetByLabel('UI/Inventory/AssetsWindow/NoMineralsAtStation'), 542 'charges': GetByLabel('UI/Inventory/AssetsWindow/NoChargesAtStation')} 543 if not assetsList: 544 if not itemname: 545 self.SetHint(GetByLabel('UI/Inventory/AssetsWindow/NoAssetsInCategoryAtStation')) 546 else: 547 self.SetHint(locText[key]) 548 else: 549 self.SetHint() 550 self.scroll.Load(contentList=assetsList, sortby='label', headers=uix.GetInvItemDefaultHeaders(), noContentHint=GetByLabel('UI/Common/NothingFound')) 551 self.HideLoad() 552 553 def GetLocationData(self, solarsystemID, station, key, forceClosed = 0, scrollID = None, sortKey = None, fakeItems = None, path = (), importanceValue = IMPORTANCE_NONE): 554 isHidden = importanceValue == IMPORTANCE_HIDDEN 555 isPinned = importanceValue == IMPORTANCE_PINNED 556 location = cfg.evelocations.Get(station.stationID) 557 if forceClosed: 558 uicore.registry.SetListGroupOpenState(('assetslocations_%s' % key, location.locationID), 0) 559 autopilotNumJumps = self.pathfinder.GetAutopilotJumpCount(session.solarsystemid2, solarsystemID) 560 itemCount = fakeItems or station.itemCount 561 secStatus = solar_system_security_status(solarsystemID) 562 if IsUnreachableJumpCount(autopilotNumJumps): 563 label = GetByLabel('UI/Inventory/AssetsWindow/LocationDataLabelNoRoute', location=location.locationID, itemCount=itemCount, secStatus=secStatus) 564 elif key is not 'sysitems': 565 label = GetByLabel('UI/Inventory/AssetsWindow/LocationDataLabel', location=location.locationID, itemCount=itemCount, jumps=autopilotNumJumps, secStatus=secStatus) 566 else: 567 label = GetByLabel('UI/Inventory/AssetsWindow/LocationDataLabelNoJump', location=location.locationID, itemCount=itemCount, secStatus=secStatus) 568 if sortKey == SORT_BY_JUMPS: 569 sortVal = (-isPinned, 570 autopilotNumJumps, 571 location.name, 572 itemCount) 573 elif sortKey == SORT_BY_ITEMS: 574 sortVal = (-isPinned, 575 -itemCount, 576 location.name, 577 autopilotNumJumps) 578 else: 579 sortVal = (-isPinned, 580 location.name, 581 itemCount, 582 autopilotNumJumps) 583 inMyPath = self._IsInMyPath(path, solarsystemID, location.locationID) 584 sublevel = 1 if isHidden else 0 585 data = {'GetSubContent': self.GetSubContent, 586 'DragEnterCallback': self.OnGroupDragEnter, 587 'DeleteCallback': self.OnGroupDeleted, 588 'MenuFunction': self.GetMenuLocationMenu, 589 'GetDragDataFunc': self.GetLocationDragData, 590 'label': label, 591 'jumps': autopilotNumJumps, 592 'itemCount': station.itemCount, 593 'groupItems': [], 594 'id': ('assetslocations_%s' % key, location.locationID), 595 'tabs': [], 596 'state': 'locked', 597 'location': location, 598 'showicon': 'hide', 599 'showlen': 0, 600 'key': key, 601 'scrollID': scrollID, 602 'inMyPath': inMyPath, 603 'itemID': station.stationID, 604 'upkeepState': getattr(station, 'upkeepState', None), 605 'charIndex': location.name, 606 'sublevel': sublevel} 607 if isPinned: 608 data['rightIconInfo'] = (eveicon.pinned, GetByLabel('UI/Inventory/AssetsWindow/PinnedLocation')) 609 headers = uix.GetInvItemDefaultHeaders() 610 for each in headers: 611 data['sort_%s' % each] = sortVal 612 613 return data 614 615 def _IsInMyPath(self, path, solarsystemID, locationID): 616 if solarsystemID in path: 617 return True 618 if locationID in path: 619 return True 620 if not eveCfg.IsDocked() and solarsystemID == session.solarsystemid2: 621 return True 622 return False 623 624 def GetLocationDragData(self, node): 625 solarSystemID, stationTypeID = self.GetStationSolarSystemIDAndTypeID(node) 626 stationInfo = sm.GetService('ui').GetStationStaticInfo(node.itemID) 627 if stationInfo: 628 node['typeID'] = stationInfo.stationTypeID 629 node['genericDisplayLabel'] = cfg.evelocations.Get(node.itemID).name 630 elif stationTypeID: 631 node['typeID'] = stationTypeID 632 node['genericDisplayLabel'] = cfg.evelocations.Get(node.itemID).name 633 return [node] 634 635 def GetContainerSubContent(self, nodedata, *args): 636 scrollList = [] 637 self.PrimeLocationNames(nodedata.groupItems) 638 for each in nodedata.groupItems: 639 data = uix.GetItemData(each, 'details', scrollID=nodedata.scrollID) 640 data.sublevel = nodedata.sublevel 641 scrollList.append(GetFromClass(InvAssetItem, data)) 642 643 return scrollList 644 645 def GetContainerMenu(self, node): 646 return GetMenuService().InvItemMenu(node.item) 647 648 def OnDblClickContainer(self, groupEntry): 649 nodedata = groupEntry.sr.node 650 if ItemChecker(nodedata.item).IsInPilotLocation(): 651 invID = ('StationContainer', nodedata.itemID) 652 InventoryWindow.OpenOrShow(invID=invID, openFromWnd=self) 653 654 def GetContainerGroupEntries(self, containersInfo, scrollID): 655 scrollList = [] 656 cfg.evelocations.Prime(containersInfo.keys()) 657 for containerID, infoOnContainer in containersInfo.iteritems(): 658 containerItem, itemsInContainer = infoOnContainer 659 scrollList.append(GetFromClass(ListGroup, {'GetSubContent': self.GetContainerSubContent, 660 'label': uix.GetItemName(containerItem), 661 'MenuFunction': self.GetContainerMenu, 662 'groupItems': itemsInContainer, 663 'id': ('assetslocations_%s' % containerID, containerID), 664 'state': 'locked', 665 'showicon': 'hide', 666 'showlen': 1, 667 'itemID': containerID, 668 'item': containerItem, 669 'sublevel': 1, 670 'scrollID': scrollID, 671 'OnDblClick': self.OnDblClickContainer})) 672 673 return scrollList 674 675 def GetSubContent(self, data, *args): 676 if data.key == 'search': 677 scrolllist = [] 678 items = [] 679 containersInfo = {} 680 for solarsystemID, stationID, stationItems, stationsContainersInfo in self.searchlist: 681 if stationID == data.location.locationID: 682 items = stationItems 683 containersInfo = stationsContainersInfo 684 break 685 686 self.PrimeLocationNames(items) 687 groupEntries = self.GetContainerGroupEntries(containersInfo, data.scrollID) 688 scrolllist.extend(groupEntries) 689 for each in items: 690 if each.flagID not in (const.flagHangar, const.flagWallet, const.flagAssetSafety): 691 continue 692 scrolllist.append(GetFromClass(InvAssetItem, uix.GetItemData(each, 'details', scrollID=data.scrollID))) 693 blue.pyos.BeNice() 694 695 return scrolllist 696 sublevel = data.get('sublevel', 0) 697 if session.stationid and data.location.locationID in (session.stationid, session.structureid): 698 hangarInv = sm.GetService('invCache').GetInventory(const.containerHangar) 699 items = hangarInv.List() 700 scrolllist = [] 701 self.PrimeLocationNames(items) 702 for each in items: 703 if each.flagID not in (const.flagHangar, const.flagWallet, const.flagAssetSafety): 704 continue 705 scrolllist.append(GetFromClass(InvAssetItem, uix.GetItemData(each, 'details', scrollID=data.scrollID, sublevel=sublevel))) 706 707 return scrolllist 708 items = sm.GetService('invCache').GetInventory(const.containerGlobal).ListStationItems(data.location.locationID) 709 badLocations = [const.locationTemp, const.locationSystem, session.charid] 710 scrolllist = [] 711 self.PrimeLocationNames(items) 712 for each in items: 713 if idCheckers.IsJunkLocation(each.locationID) or each.locationID in badLocations: 714 continue 715 if each.stacksize == 0: 716 continue 717 data = uix.GetItemData(each, 'details', scrollID=data.scrollID, sublevel=sublevel) 718 if idCheckers.IsStation(each.locationID): 719 station = sm.GetService('ui').GetStationStaticInfo(each.locationID) 720 if station: 721 data.factionID = sm.GetService('faction').GetFactionOfSolarSystem(station.solarSystemID) 722 scrolllist.append(GetFromClass(InvAssetItem, data)) 723 724 return scrolllist 725 726 def PrimeLocationNames(self, items): 727 itemLocationToPrime = set() 728 for each in items: 729 if IsValidNamedItem(each): 730 itemLocationToPrime.add(each.itemID) 731 732 cfg.evelocations.Prime(itemLocationToPrime) 733 734 def UpdateLite(self, stationID, key, fromID): 735 if not self or self.destroyed: 736 return 737 self.ShowLoad() 738 try: 739 destPathList = sm.GetService('starmap').GetDestinationPath() 740 assetStations = sm.GetService('assets').GetStations().Index('stationID') 741 searchKey = 'assetslocations_%s' % key 742 affectedNodes = [ node for node in self.scroll.GetNodes() if node.Get('id', None) in ((searchKey, stationID), (searchKey, fromID)) ] 743 for node in affectedNodes: 744 locationID = node.Get('id')[1] 745 station = assetStations.get(locationID, None) 746 if station is None: 747 station = utillib.KeyVal(solarSystemID=node.location.solarSystemID, stationID=locationID, itemCount=node.itemCount) 748 node.data = self.GetLocationData(station.solarSystemID, station, key, scrollID=self.scroll.sr.id, path=destPathList) 749 if node.panel: 750 node.panel.Load(node) 751 self.scroll.PrepareSubContent(node) 752 self.scroll.ScrollToProportion(self.scroll.GetScrollProportion()) 753 754 finally: 755 self.ReconstructLayout() 756 self.HideLoad() 757 758 def ShowSearch(self, sortKey = None, *args): 759 uthread2.start_tasklet(self._LoadSearch, sortKey) 760 761 def _LoadSearch(self, sortKey): 762 if sortKey is None: 763 sortKey = settings.char.ui.Get('assetsSearchSortKey', None) 764 settings.char.ui.Set('assetsSearchSortKey', sortKey) 765 if sortKey: 766 self.sortByCombosearch.SelectItemByIndex(sortKey) 767 self.SetHint() 768 self.scroll.ShowLoading() 769 try: 770 scrolllist = [] 771 searchlist = getattr(self, 'searchlist', []) or [] 772 sortedList = [] 773 for solarsystemID, stationID, items, stationsContainersInfo in searchlist: 774 numContainerItems = sum([ len(y) for x, y in stationsContainersInfo.values() ]) 775 station = utillib.KeyVal() 776 station.stationID = stationID 777 station.solarsystemID = solarsystemID 778 station.stationName = cfg.evelocations.Get(stationID).name 779 station.itemCount = len(items) + numContainerItems 780 sortedList.append(station) 781 782 allImportanceSettings = settings.char.ui.Get('assets_window_importance', {}) 783 destPathList = sm.GetService('starmap').GetDestinationPath() 784 hiddenEntries = [] 785 for station in sortedList: 786 importanceValue = allImportanceSettings.get(station.stationID, IMPORTANCE_NONE) 787 data = self.GetLocationData(station.solarsystemID, station, 'search', scrollID=self.scroll.sr.id, sortKey=sortKey, path=destPathList, importanceValue=importanceValue) 788 entry = GetFromClass(LocationGroup, data) 789 if importanceValue == IMPORTANCE_HIDDEN: 790 hiddenEntries.append(entry) 791 else: 792 scrolllist.append(entry) 793 blue.pyos.BeNice() 794 795 if hiddenEntries: 796 scrolllist.append(self.GetHiddenEntry(hiddenEntries)) 797 scrollPosition = 0 798 if self.tabGroup.GetSelectedArgs() == 'search': 799 scrollPosition = self.scrollPosition.get('search', 0) 800 self.scroll.Load(contentList=scrolllist, headers=uix.GetInvItemDefaultHeaders(), noContentHint=GetByLabel('UI/Common/NothingFound'), scrollTo=scrollPosition, showCollapseIcon=True) 801 finally: 802 self.scroll.HideLoading() 803 self.HideLoad() 804 805 def GetMenuLocationMenu(self, node): 806 locationID = node.location.locationID 807 solarSystemID, stationTypeID = self.GetStationSolarSystemIDAndTypeID(node) 808 menu = StartMenuService().CelestialMenu(node.location.locationID, typeID=stationTypeID, parentID=solarSystemID) 809 menu += self._GetImportanceMenu(locationID, solarSystemID) 810 if not idCheckers.IsStation(locationID): 811 if session.structureid != locationID: 812 if IsWormholeSystem(solarSystemID) or IsTriglavianSystem(solarSystemID): 813 label = MenuLabel('UI/Inventory/AssetSafety/MoveItemsToSpace') 814 else: 815 label = MenuLabel('UI/Inventory/AssetSafety/MoveItemsToSafety') 816 menu.append((label, self.MoveItemsInStructureToAssetSafety, (solarSystemID, locationID))) 817 return menu 818 819 def _GetImportanceMenu(self, locationID, solarSystemID): 820 m = MenuData() 821 importanceSetting = settings.char.ui.Get('assets_window_importance', {}).get(locationID, None) 822 if importanceSetting == IMPORTANCE_PINNED: 823 label = MenuLabel('UI/Inventory/AssetsWindow/UnpinPersonalAssets') 824 m.AddEntry(label, lambda : self.Unpin(locationID), texturePath=eveicon.unpin) 825 elif importanceSetting == IMPORTANCE_HIDDEN: 826 label = MenuLabel('UI/Inventory/AssetsWindow/UnhidePersonalAssets') 827 m.AddEntry(label, lambda : self.Unhide(locationID), texturePath=eveicon.hidden) 828 else: 829 label = MenuLabel('UI/Inventory/AssetsWindow/PinPersonalAssets') 830 m.AddEntry(label, lambda : self.Pin(locationID), texturePath=eveicon.pinned) 831 label = MenuLabel('UI/Inventory/AssetsWindow/HidePersonalAssets') 832 m.AddEntry(label, lambda : self.Hide(locationID), texturePath=eveicon.visibility) 833 return m 834 835 def Pin(self, locationID, *args): 836 if self._SetLocationImportance(locationID, IMPORTANCE_PINNED): 837 message_player(GetByLabel('UI/Inventory/AssetsWindow/PersonalAssetLocationPinned')) 838 839 def Unpin(self, locationID, *args): 840 if self._SetLocationImportance(locationID, IMPORTANCE_NONE): 841 message_player(GetByLabel('UI/Inventory/AssetsWindow/PersonalAssetLocationUnpinned')) 842 843 def Hide(self, locationID, *args): 844 if self._SetLocationImportance(locationID, IMPORTANCE_HIDDEN): 845 message_player(GetByLabel('UI/Inventory/AssetsWindow/PersonalAssetLocationHidden')) 846 847 def Unhide(self, locationID, *args): 848 if self._SetLocationImportance(locationID, IMPORTANCE_NONE): 849 message_player(GetByLabel('UI/Inventory/AssetsWindow/PersonalAssetLocationUnhidden')) 850 851 def _SetLocationImportance(self, locationID, newImportanceValue): 852 allImportanceSettings = settings.char.ui.Get('assets_window_importance', {}) 853 importanceSetting = allImportanceSettings.get(locationID, IMPORTANCE_NONE) 854 if importanceSetting == newImportanceValue: 855 return False 856 if newImportanceValue == IMPORTANCE_NONE: 857 allImportanceSettings.pop(locationID, None) 858 else: 859 allImportanceSettings[locationID] = newImportanceValue 860 settings.char.ui.Set('assets_window_importance', allImportanceSettings) 861 self.ReloadTabs() 862 return True 863 864 def GetStationSolarSystemIDAndTypeID(self, node): 865 locationID = node.location.locationID 866 solarSystemID = stationTypeID = None 867 if idCheckers.IsStation(locationID): 868 stationInfo = sm.GetService('ui').GetStationStaticInfo(locationID) 869 stationTypeID = stationInfo.stationTypeID 870 solarSystemID = stationInfo.solarSystemID 871 else: 872 stations = sm.GetService('invCache').GetInventory(const.containerGlobal).ListStations() 873 for station in stations: 874 if station.stationID == locationID: 875 stationTypeID = station.typeID 876 solarSystemID = station.solarSystemID 877 break 878 879 return (solarSystemID, stationTypeID) 880 881 def MoveItemsInStructureToAssetSafety(self, solarSystemID, structureID): 882 sm.GetService('assetSafety').MoveItemsInStructureToAssetSafetyForCharacter(solarSystemID, structureID) 883 884 def SetHint(self, hintstr = None): 885 if self.scroll: 886 self.scroll.ShowHint(hintstr) 887 888 def OnGroupDeleted(self, ids): 889 pass 890 891 def OnGroupDragEnter(self, group, drag): 892 pass 893 894 def LoadInfoTooltip(self, tooltipPanel, *args): 895 tooltipPanel.LoadGeneric2ColumnTemplate() 896 tooltipPanel.cellSpacing = 1 897 tooltipPanel.AddLabelLarge(text=GetByLabel('UI/Inventory/AssetsWindow/AdvancedSearch'), colSpan=2) 898 tooltipPanel.AddLabelMedium(text='<b>%s' % GetByLabel('UI/Inventory/AssetsWindow/AdvancedSearchKeywords')) 899 tooltipPanel.AddLabelMedium(wrapWidth=200, text='<b>%s' % GetByLabel('UI/Inventory/AssetsWindow/AdvancedSearchHints'), padLeft=20) 900 for keywordOption in self.searchKeywords: 901 tooltipPanel.AddLabelSmall(text='<b>%s:</b>' % keywordOption.keyword, opacity=0.85) 902 tooltipPanel.AddLabelSmall(wrapWidth=200, text=keywordOption.optionDescription, padLeft=20, opacity=0.75) 903 904 tooltipPanel.AddSpacer(width=0, height=10, colSpan=3) 905 tooltipPanel.AddLabelMedium(text='<b>%s:' % GetByLabel('UI/Inventory/AssetsWindow/AdvancedSearchExamples'), colSpan=3) 906 text = '%s:%s' % (GetByLabel('UI/Inventory/AssetSearch/KeywordType'), evetypes.GetName(1230)[:5]) 907 tooltipPanel.AddLabelSmall(text=text, opacity=0.75, colSpan=3, padLeft=10) 908 text = '%s:%s %s:2 %s:9 %s:0.9' % (GetByLabel('UI/Inventory/AssetSearch/KeywordCategory'), 909 evetypes.GetCategoryNameByCategory(const.categoryShip), 910 GetByLabel('UI/Inventory/AssetSearch/KeywordTechLevel'), 911 GetByLabel('UI/Inventory/AssetSearch/KeywordMetalevel'), 912 GetByLabel('UI/Inventory/AssetSearch/KeywordMinSecurityLevel')) 913 tooltipPanel.AddLabelSmall(text=text, opacity=0.75, colSpan=2, padLeft=10) 914 915 def SearchTypeID(self, typeID): 916 self.tabGroup.SelectByID('search') 917 searchText = self.GetSearchTextForTypeID(typeID) 918 if self.search_inited: 919 self.searchEditBox.SetValue(searchText) 920 self.searchText = searchText 921 self.Search() 922 923 def GetSearchTextForTypeID(self, typeID): 924 return '%s:%s' % (GetByLabel('UI/Inventory/AssetSearch/KeywordTypeExact'), evetypes.GetName(typeID)) 925 926 def UnloadTabPanel(self, args, panel, tabgroup): 927 self._kill_loading_thread_maybe() 928 929 def _start_loading_thread(self, func, *args, **kwargs): 930 self._kill_loading_thread_maybe() 931 932 def loading_thread(): 933 try: 934 func(*args, **kwargs) 935 finally: 936 self._loading_thread = None 937 938 self._loading_thread = uthread2.start_tasklet(loading_thread) 939 940 def _kill_loading_thread_maybe(self): 941 if self._loading_thread is not None: 942 self._loading_thread.kill() 943 944 def ShowLoad(self, doBlock = True): 945 pass 946 947 def HideLoad(self): 948 pass 949 950 951 class UpdateDelayHint(ContainerAutoSize): 952 ICON_SIZE = 16 953 _visible = True 954 955 def __init__(self, **kwargs): 956 super(UpdateDelayHint, self).__init__(**kwargs) 957 self._layout() 958 959 def _layout(self): 960 Sprite(parent=self, align=uiconst.CENTER, width=self.ICON_SIZE, height=self.ICON_SIZE, texturePath=eveicon.clock, hint=localization.GetByLabel('UI/Inventory/AssetsWindow/CachedFor5Min'), color=TextColor.DISABLED) 961 962 def UpdateAlignment(self, budgetLeft = 0, budgetTop = 0, budgetWidth = 0, budgetHeight = 0, updateChildrenOnly = False): 963 required_budget = self.left + self.padLeft + self.ICON_SIZE + self.padRight 964 if reverse_scale_dpi(budgetWidth) < required_budget: 965 if self._visible: 966 self._visible = False 967 animations.FadeOut(self, duration=0.3) 968 elif not self._visible: 969 self._visible = True 970 animations.FadeIn(self, duration=0.3) 971 return super(UpdateDelayHint, self).UpdateAlignment(budgetLeft, budgetTop, budgetWidth, budgetHeight, updateChildrenOnly)