invWindow.py (78376B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\inventory\invWindow.py 2 from math import pi 3 import blue 4 import eve.client.script.ui.shared.pointerTool.pointerToolConst as pConst 5 import eveformat 6 import eveicon 7 import functools 8 import inventorycommon.const as invConst 9 import logging 10 import telemetry 11 import threadutils 12 import weakref 13 from carbon.common.script.sys.serviceConst import ROLE_GML, ROLE_WORLDMOD 14 from carbonui import AxisAlignment, Density, TextColor, uiconst 15 from carbonui.button.menu import MenuButtonIcon 16 from carbonui.control.button import Button 17 from carbonui.control.buttonIcon import ButtonIcon 18 from carbonui.control.contextMenu.menuData import MenuData 19 from carbonui.control.dragResizeCont import DragResizeCont 20 from carbonui.control.scrollContainer import ScrollContainer 21 from carbonui.control.window import Window 22 from carbonui.decorative.panelUnderlay import PanelUnderlay 23 from carbonui.primitives.container import Container 24 from carbonui.primitives.containerAutoSize import ContainerAutoSize 25 from carbonui.uianimations import animations 26 from carbonui.uicore import uicore 27 from carbonui.util.various_unsorted import IsUnder 28 from carbonui.window.settings import GetRegisteredState 29 from clientsettings.setting import UserSettingBool 30 from eve.client.script.environment.invControllers import AssetSafetyDeliveries as AssetSafetyDeliveriesController, AssetSafetyContainer as AssetSafetyContainerController, GetInvCtrlFromInvID, ItemWreck, ItemFloatingCargo, LOOT_GROUPS, LOOT_GROUPS_NOCLOSE, ShipCargo as ShipCargoController, StationCorpDeliveries as StationCorpDeliveriesController, CapsuleerDeliveries as CapsuleerDeliveriesController, StationItems as StationItemsController, StationShips as StationShipsController, StructureItemHangar as StructureItemsController, StructureShipHangar as StructureShipsController 31 from eve.client.script.parklife.states import flagWreckEmpty, mouseOver, selected 32 from eve.client.script.ui import eveColor 33 from eve.client.script.ui.control import eveLabel 34 from eve.client.script.ui.control.eveLoadingWheel import LoadingWheel 35 from eve.client.script.ui.control.historyBuffer import HistoryBuffer 36 from eve.client.script.ui.inflight.bracketsAndTargets.bracketVarious import GetIconColor 37 from eve.client.script.ui.plex.textures import PLEX_WINDOW_ICON 38 from eve.client.script.ui.shared.container import InvContCapacityGauge, InvContQuickFilter 39 from eve.client.script.ui.shared.inventory.invCommon import CONTAINERGROUPS 40 from eve.client.script.ui.shared.inventory.invFilters import InvFilters 41 from eve.client.script.ui.shared.inventory.invSettings import always_open_secondary_inventory_setting, keep_inv_quick_filter_setting, always_show_full_tree_setting, show_training_details 42 from eve.client.script.ui.shared.inventory.treeData import TreeDataInv, TreeDataInvFolder, GetTreeDataClassByInvName 43 from eve.client.script.ui.shared.inventory.treeViewEntries import GetTreeViewEntryClassByDataType 44 from eve.common.lib import appConst 45 from eve.common.lib import appConst as const 46 from eve.common.script.sys.eveCfg import GetActiveShip, InShipInSpace, InStructure 47 from eve.common.script.sys.idCheckers import IsStarbase 48 from eve.common.script.util.eveFormat import FmtISKAndRound, GetAveragePrice 49 from eveexceptions import UserError 50 from localization import GetByLabel 51 from omega.client.clone_grade_svc import get_clone_grade_svc 52 from player_messaging.client.ui_message import prompt_player_fsd_dialog 53 from signals import Signal 54 from uthread2 import StartTasklet 55 logger = logging.getLogger(__name__) 56 HISTORY_LENGTH = 50 57 TREE_DEFAULT_WIDTH = 160 58 SORT_OPTIONS = [('UI/Common/Name', 'UI/Inventory/NameReversed', 'name'), 59 ('UI/Inventory/ItemQuantity', 'UI/Inventory/QuantityReversed', 'qty'), 60 ('UI/Common/Type', 'UI/Inventory/TypeReversed', 'type'), 61 ('UI/Inventory/EstPrice', 'UI/Inventory/EstPriceReversed', 'estPrice')] 62 63 class Inventory(Window): 64 __guid__ = 'form.Inventory' 65 __notifyevents__ = ['OnSessionChanged', 66 'OnPrimaryViewChanged', 67 'OnItemNameChange', 68 'OnMultipleItemChange', 69 'ProcessActiveShipChanged', 70 'OnBeforeActiveShipChanged', 71 'OnOfficeRentalChanged', 72 'OnStateChange', 73 'OnInvContDragEnter', 74 'OnInvContDragExit', 75 'DoBallsAdded', 76 'DoBallRemove', 77 'ProcessTempInvLocationAdded', 78 'ProcessTempInvLocationRemoved', 79 'OnSlimItemChange', 80 'OnInvFiltersChanged', 81 'OnInvContRefreshed', 82 'OnCapacityChange', 83 'OnWreckLootAll', 84 'OnShowFullInvTreeChanged', 85 'DoBallsRemove', 86 'OnInvTreeUpdatingChanged'] 87 default_windowID = 'Inventory' 88 default_width = 600 89 default_height = 450 90 default_minSize = (100, 140) 91 default_iconNum = 'res:/UI/Texture/WindowIcons/items.png' 92 default_isCompactable = True 93 default_caption = None 94 default_left = 80 95 _filter_bottom_button = None 96 _search_field = None 97 _search_field_header_parent = None 98 _search_field_top_parent = None 99 _sort_by_button = None 100 _top_action_container = None 101 _view_mode_button = None 102 103 def __init__(self, **kwargs): 104 self.invController = None 105 super(Inventory, self).__init__(**kwargs) 106 107 @classmethod 108 def Open(cls, invID = None, *args, **kwds): 109 if invID: 110 invController = GetInvCtrlFromInvID(invID) 111 if invController and not invController.IsPrimed(): 112 if not invController.IsInRange(): 113 raise UserError('FakeItemNotFound') 114 try: 115 invController.GetItems() 116 except RuntimeError: 117 raise UserError('FakeItemNotFound') 118 119 return super(Inventory, cls).Open(invID=invID, *args, **kwds) 120 121 def ApplyAttributes(self, attributes): 122 self.currInvID = attributes.Get('invID', None) 123 self.rootInvID = attributes.Get('rootInvID', self.currInvID) 124 self.invController = GetInvCtrlFromInvID(self.currInvID) 125 super(Inventory, self).ApplyAttributes(attributes) 126 sm.GetService('inv').Register(self) 127 self.treeEntryByID = {} 128 self.tempTreeEntryByID = {} 129 self.dragHoverThread = None 130 self.refreshTreeThread = None 131 self.updateSelectedItemsThread = None 132 self.updateSelectedItemsPending = None 133 self.invCont = None 134 self.loadingTreeView = False 135 self.loadingInvCont = False 136 self.dragOpenNewWindowCookie = None 137 self.treeData = None 138 self.treeDataTemp = None 139 self.containersInRangeUpdater = None 140 self.history = HistoryBuffer(HISTORY_LENGTH) 141 self.breadcrumbInvIDs = [] 142 self.needsUpdate = True 143 self._is_tree_expanded = True 144 self._is_tree_expanded_setting = TreeExpandedSetting(self) 145 self.onDividerMoved = Signal(signalName='onDividerMoved') 146 if session.stationid: 147 StationItemsController().GetItems() 148 self.dividerCont = DragResizeCont(name='dividerCont', settingsID='invTreeViewWidth_%s' % self.GetWindowSettingsID(), parent=self.sr.main, align=uiconst.TOLEFT, minSize=45, maxSize=None, defaultSize=TREE_DEFAULT_WIDTH, onResizeCallback=self.OnDividerContResize, onDragCallback=self.OnDividerContDragged, handle_cross_axis_alignment=AxisAlignment.START) 149 StartTasklet(self.OnDividerContResize) 150 self._search_field_header_parent = ContainerAutoSize(parent=self.header.extra_content, align=uiconst.TORIGHT) 151 treeCont = None 152 treeCont = Container(parent=self.dividerCont.mainCont, align=uiconst.TOALL) 153 self._tree_underlay = PanelUnderlay(parent=self.dividerCont.mainCont, align=uiconst.TOALL, padding=self._get_tree_underlay_padding()) 154 self.on_content_padding_changed.connect(self._update_tree_padding) 155 self.treeBottomCont = InvFilters(parent=treeCont, settingsID='invFiltersHeight_%s' % self.GetWindowSettingsID(), minSize=100, maxSize=0.5, defaultSize=150, windowID=self.GetWindowSettingsID(), show_filter_toggle_button=False) 156 self.treeBottomCont.on_filters_updated.connect(self.UpdateFilters) 157 self.treeBottomCont.on_expand_collapse_animation.connect(self.ChangeTreeWhenAnimating) 158 self.tree = ScrollContainer(name='tree', parent=treeCont, innerPadding=self._get_tree_inner_padding(), padLeft=-8) 159 self.tree.GetMenu = self.GetMenu 160 self.tree.Paste = self.Paste 161 self.rightCont = Container(name='rightCont', parent=self.sr.main, padding=(-8, 0, 0, 0)) 162 self.noInventoryLabel = eveLabel.EveCaptionMedium(name='noInventoryLabel', parent=self.rightCont, state=uiconst.UI_HIDDEN, text=GetByLabel('UI/Inventory/NoInventoryLocationSelected'), pos=(17, 78, 0, 0), opacity=0.5) 163 self.topRightCont2 = Container(name='topRightCont2', parent=self.rightCont, align=uiconst.TOTOP, height=24, padBottom=16, clipChildren=True) 164 self.bottomRightCont = Container(name='bottomRightcont', parent=self.rightCont, align=uiconst.TOBOTTOM, height=24, padding=self._get_bottom_right_cont_padding(), clipChildren=True) 165 self.specialActionsCont = ContainerAutoSize(name='specialActionsCont', parent=self.bottomRightCont, align=uiconst.TORIGHT, padding=(16, 0, 0, 0)) 166 self._top_action_container = ContainerAutoSize(parent=self.topRightCont2, align=uiconst.TOLEFT, padding=self._get_top_action_container_padding()) 167 ButtonIcon(parent=ContainerAutoSize(parent=self._top_action_container, align=uiconst.TOLEFT), align=uiconst.CENTER, width=24, height=24, iconSize=16, texturePath=eveicon.stack, hint=GetByLabel('UI/Inventory/StackAll'), func=self._stack_all, name=pConst.UNIQUE_NAME_INVENTORY_STACK_ALL, uniqueUiName=pConst.UNIQUE_NAME_INVENTORY_STACK_ALL) 168 self._view_mode_button = MenuButtonIcon(parent=ContainerAutoSize(parent=self._top_action_container, align=uiconst.TOLEFT), align=uiconst.CENTER, width=24, height=24, iconSize=16, texturePath=eveicon.grid_view, get_menu_func=self._get_view_mode_menu, hint=self._get_view_mode_button_hint(), uniqueUiName=pConst.UNIQUE_NAME_INVENTORY_VIEW) 169 self._sort_by_button = MenuButtonIcon(parent=ContainerAutoSize(parent=self._top_action_container, align=uiconst.TOLEFT), align=uiconst.CENTER, width=24, height=24, iconSize=16, texturePath=eveicon.bars_sort_ascending, get_menu_func=self._get_sort_menu, hint=GetByLabel('UI/Common/SortBy')) 170 self._update_sort_by_button_display() 171 dividerParent = Container(name='dividerParent', parent=self.topRightCont2, align=uiconst.TOALL, clipChildren=True) 172 self.searchDividerCont = DragResizeCont(name='searchDividerCont', settingsID='searchDividerCont', parent=dividerParent, align=uiconst.TORIGHT, minSize=128, maxSize=0.9, favorMinSize=True, clipChildren=True, show_line=True) 173 self._search_field_top_parent = Container(parent=self.searchDividerCont.mainCont, align=uiconst.TOALL) 174 self.quickFilter = self._search_field = InvContQuickFilter(parent=self._get_search_field_parent(), align=self._get_search_field_align(), width=120) 175 self._search_field.UpdateInputBoxAlign(self._get_search_field_align()) 176 self.capacityGauge = InvContCapacityGauge(parent=dividerParent, align=uiconst.TOALL) 177 self.bottomRightLabelCont = Container(name='bottomRightLabelCont', parent=self.bottomRightCont, align=uiconst.TOALL, clipChildren=True) 178 self.numItemsLabel = eveLabel.EveLabelMediumBold(name='numItemsLabel', parent=ContainerAutoSize(parent=self.bottomRightLabelCont, align=uiconst.TOLEFT), align=uiconst.CENTERLEFT, color=TextColor.SECONDARY) 179 self.totalPriceLabel = eveLabel.EveLabelMedium(name='totalPriceLabel', parent=ContainerAutoSize(parent=self.bottomRightLabelCont, align=uiconst.TOLEFT, left=8), align=uiconst.CENTERLEFT, color=TextColor.SECONDARY) 180 expanded = False 181 if self._is_tree_expanded_setting.is_default_determined: 182 expanded = self._is_tree_expanded_setting.get() 183 if expanded: 184 self._ExpandTree(animate=False) 185 else: 186 self._CollapseTree(animate=False) 187 self._is_tree_expanded_setting.on_change.connect(self._on_tree_expanded_setting_changed) 188 self.treeBottomCont.ExpandOrCollapeFilters() 189 if not self.currInvID: 190 self.currInvID = settings.user.ui.Get('invLastOpenContainerData_%s' % self.GetWindowSettingsID(), None) 191 self.ShowInvContLoadingWheel() 192 StartTasklet(self.ConstructFilters) 193 shouldUpdateCorpHangarNodes = self._IsCorpHangarNode(self.currInvID) 194 if self._IsCurrentInventoryValid(): 195 if shouldUpdateCorpHangarNodes: 196 self.currInvID = None 197 else: 198 self.currInvID = None 199 StartTasklet(self.RefreshTree, corpHangarsChanged=shouldUpdateCorpHangarNodes) 200 if self.compact: 201 self.OnCompactModeEnabled() 202 self.on_content_padding_changed.connect(self._on_content_padding_changed) 203 self.on_compact_mode_changed.connect(self._on_compact_mode_changed) 204 205 def _get_top_action_container_padding(self): 206 if self.compact: 207 return (0, 0, 0, 0) 208 elif self._is_tree_expanded_setting.get(): 209 return (12, 0, 8, 0) 210 else: 211 return (-4, 0, 8, 0) 212 213 def _update_top_action_container_padding(self, animate = True): 214 if animate: 215 for attr, value in zip(['padLeft', 216 'padTop', 217 'padRight', 218 'padBottom'], self._get_top_action_container_padding()): 219 animations.MorphScalar(self._top_action_container, attr, endVal=value, duration=0.3) 220 221 else: 222 self._top_action_container.padding = self._get_top_action_container_padding() 223 224 def _get_top_action_container_display(self): 225 return not self.compact and self.invCont and self.invCont.IsViewModesEnabled() 226 227 def _update_top_action_container_display(self): 228 self._top_action_container.display = self._get_top_action_container_display() 229 230 def _get_view_mode_menu(self): 231 menu = MenuData() 232 for viewMode in self.invCont.availableViewModes: 233 menu.AddEntry(text=self.invCont.GetViewModeName(viewMode), texturePath=self.invCont.GetViewModeIcon(viewMode), func=functools.partial(self.SetInvContViewMode, viewMode)) 234 235 return menu 236 237 def _get_sort_menu(self): 238 active_criteria, active_direction = self._get_container_sort_by() 239 menu = MenuData() 240 for i, (label_ascending, label_descending, criteria) in enumerate(SORT_OPTIONS): 241 if i > 0: 242 menu.AddSeparator() 243 for direction, label in ((0, label_ascending), (1, label_descending)): 244 245 def select_sort_order(_criteria = criteria, _direction = direction): 246 self._sort_container_by(_criteria, _direction) 247 248 icon = eveicon.checkmark if active_criteria == criteria and active_direction == direction else None 249 menu.AddEntry(text=GetByLabel(label), texturePath=icon, func=select_sort_order) 250 251 return menu 252 253 def _get_container_sort_by(self): 254 if self._has_sort_by(): 255 return (self.invCont.sortIconsBy, self.invCont.sortIconsDir) 256 else: 257 return (None, None) 258 259 def _sort_container_by(self, criteria, direction): 260 if self._has_sort_by(): 261 self.invCont.SortIconsBy(criteria, direction) 262 263 def _update_sort_by_button_display(self): 264 self._sort_by_button.display = self._has_sort_by() 265 266 def _has_sort_by(self): 267 return bool(self.invCont and self.invCont.ShouldShowSortBy()) 268 269 def _get_view_mode_icon(self): 270 if self.invCont: 271 return self.invCont.GetActiveViewModeIcon() or eveicon.eye 272 return eveicon.eye 273 274 def _get_view_mode_button_hint(self): 275 if self.invCont: 276 view_mode_name = self.invCont.GetActiveViewModeName() 277 return GetByLabel('UI/Inventory/ViewModeWithCurrent', current_view_mode=view_mode_name) 278 279 def _update_view_mode_button(self): 280 icon = self._get_view_mode_icon() 281 self._view_mode_button.SetTexturePath(icon) 282 self._view_mode_button.hint = self._get_view_mode_button_hint() 283 284 def _stack_all(self): 285 if self.invCont: 286 self.invCont.StackAll() 287 288 def _get_search_field_parent(self): 289 if self.compact: 290 return self._search_field_header_parent 291 else: 292 return self._search_field_top_parent 293 294 def _get_search_field_align(self): 295 if self.compact: 296 return uiconst.CENTER 297 else: 298 return uiconst.TOTOP 299 300 def _update_search_field(self): 301 parent = self._get_search_field_parent() 302 align = self._get_search_field_align() 303 if parent != self._search_field.parent: 304 self._search_field.SetParent(None) 305 self._search_field.align = align 306 self._search_field.SetParent(parent) 307 elif align != self._search_field.align: 308 self._search_field.align = align 309 self._search_field.UpdateInputBoxAlign(align) 310 311 def _create_filter_bottom_button(self): 312 if self._filter_bottom_button is None: 313 self._filter_bottom_button = ButtonIcon(parent=Container(parent=self.bottomRightCont, align=uiconst.TOLEFT, idx=0), align=uiconst.TOPLEFT, width=24, height=24, iconSize=16, texturePath=eveicon.filter, hint=GetByLabel('UI/Inventory/FilterChipClear'), func=self._clear_all_filters) 314 315 def _update_filter_bottom_button(self): 316 if self.destroyed: 317 return 318 if self._is_filtered(): 319 if self._filter_bottom_button is None: 320 self._create_filter_bottom_button() 321 animations.FadeIn(self._filter_bottom_button, duration=0.2) 322 parent = self._filter_bottom_button.parent 323 animations.MorphScalar(parent, 'width', startVal=parent.width, endVal=24, duration=0.2) 324 animations.MorphScalar(parent, 'padRight', startVal=parent.padRight, endVal=4, duration=0.2) 325 elif self._filter_bottom_button: 326 animations.FadeOut(self._filter_bottom_button, duration=0.2) 327 parent = self._filter_bottom_button.parent 328 animations.MorphScalar(parent, 'width', startVal=parent.width, endVal=0, duration=0.2) 329 animations.MorphScalar(parent, 'padRight', startVal=parent.padRight, endVal=0, duration=0.2) 330 331 def _is_filtered(self): 332 return self.invCont and (len(self.GetActiveFilters()) > 0 or self.quickFilter.GetQuickFilterInput()) 333 334 @threadutils.threaded 335 def _on_tree_expanded_setting_changed(self, expanded): 336 if expanded: 337 self._ExpandTree() 338 else: 339 self._CollapseTree() 340 341 def _get_tree_underlay_padding(self): 342 pad_left, pad_top, _, pad_bottom = self.content_padding 343 return (-pad_left, 344 -pad_top, 345 0, 346 -pad_bottom) 347 348 def _get_tree_inner_padding(self): 349 _, content_pad_top, _, _ = self.content_padding 350 pad_top = 0 if content_pad_top > 0 else 16 351 return (0, 352 pad_top, 353 0, 354 0) 355 356 def _get_bottom_right_cont_padding(self): 357 pad_top = self.content_padding[3] 358 if self._is_tree_expanded: 359 if self.compact: 360 pad_left = 8 361 else: 362 pad_left = 16 363 else: 364 pad_left = 0 365 return (pad_left, 366 pad_top, 367 0, 368 0) 369 370 def _on_content_padding_changed(self, window): 371 self._update_bottom_right_cont_padding(animate=False) 372 373 def _on_compact_mode_changed(self, window): 374 self._update_bottom_right_cont_padding(animate=False) 375 376 def _update_bottom_right_cont_padding(self, animate = True): 377 if animate: 378 for attr, value in zip(['padLeft', 379 'padTop', 380 'padRight', 381 'padBottom'], self._get_bottom_right_cont_padding()): 382 animations.MorphScalar(obj=self.bottomRightCont, attrName=attr, startVal=getattr(self.bottomRightCont, attr), endVal=value, duration=0.2) 383 384 else: 385 self.bottomRightCont.padding = self._get_bottom_right_cont_padding() 386 387 def _update_tree_padding(self, window): 388 if self._tree_underlay is not None and not self._tree_underlay.destroyed: 389 self._tree_underlay.padding = self._get_tree_underlay_padding() 390 if self.tree is not None and not self.tree.destroyed: 391 self.tree.innerPadding = self._get_tree_inner_padding() 392 393 def _IsCurrentInventoryValid(self): 394 if not session.structureid and not session.stationid: 395 return True 396 if self.currInvID: 397 currInvCtrl = GetInvCtrlFromInvID(self.currInvID) 398 if currInvCtrl: 399 try: 400 invItem = currInvCtrl.GetInventoryItem() 401 if invItem: 402 return sm.GetService('invCache').ValidateItemCanBeOpened(invItem) 403 except (KeyError, RuntimeError, UserError): 404 return False 405 406 return True 407 408 def GetMenuMoreOptions(self): 409 menuData = super(Inventory, self).GetMenuMoreOptions() 410 menuData.AddCheckbox(text=GetByLabel('UI/Inventory/ShowSidebar'), setting=self._is_tree_expanded_setting) 411 menuData.AddCheckbox(text=GetByLabel('UI/Inventory/AlwaysOpenSeparate'), setting=always_open_secondary_inventory_setting) 412 menuData.AddCheckbox(text=GetByLabel('UI/Inventory/KeepQuickFilterValue'), setting=keep_inv_quick_filter_setting) 413 menuData.AddCheckbox(text=GetByLabel('UI/Inventory/AlwaysShowFullTree'), setting=always_show_full_tree_setting) 414 if get_clone_grade_svc().is_omega_with_grace_period(): 415 menuData.AddCheckbox(text=GetByLabel('UI/Inventory/ShowTrainingDetails'), setting=show_training_details) 416 if self.compact and self.invCont and self.invCont.IsViewModesEnabled(): 417 menuData.AddSeparator() 418 menuData.AddCaption(text=GetByLabel('UI/Inventory/ViewMode')) 419 for viewMode in self.invCont.availableViewModes: 420 menuData.AddRadioButton(text=self.invCont.GetViewModeName(viewMode), value=viewMode, setting=self.invCont.view_mode_setting) 421 422 return menuData 423 424 def OnSettingChangedSecondaryWnd(self, openSecondary, *args): 425 settings.user.ui.Set('openSecondaryInv', openSecondary) 426 427 def OnSettingChangedKeepQuickFilter(self, keepQuickFilterInput, *args): 428 settings.user.ui.Set('keepInvQuickFilterInput', keepQuickFilterInput) 429 430 def OnSettingChangedAlwaysShowFullTree(self, alwaysShowFullTree, *args): 431 settings.user.ui.Set('alwaysShowFullInvTree', alwaysShowFullTree) 432 sm.ScatterEvent('OnShowFullInvTreeChanged') 433 434 def OnShowFullInvTreeChanged(self): 435 self.RefreshTree() 436 437 def GetRegisteredPositionAndSize(self): 438 return self.GetRegisteredPositionAndSizeByClass(self.windowID) 439 440 def RegisterPositionAndSize(self, key = None, windowID = None): 441 windowID = self.windowID 442 Window.RegisterPositionAndSize(self, key, windowID) 443 444 def ShowTreeLoadingWheel(self): 445 if self.loadingTreeView: 446 return 447 self.loadingTreeView = True 448 StartTasklet(self._ShowTreeLoadingWheel) 449 450 def _ShowTreeLoadingWheel(self): 451 blue.synchro.SleepWallclock(500) 452 wheelCont = Container(parent=self.dividerCont.mainCont) 453 LoadingWheel(parent=wheelCont, align=uiconst.CENTER) 454 while self.loadingTreeView: 455 blue.synchro.Yield() 456 457 wheelCont.Close() 458 459 def HideTreeLoadingWheel(self): 460 self.loadingTreeView = False 461 462 def ShowInvContLoadingWheel(self): 463 if self.loadingInvCont: 464 return 465 self.loadingInvCont = True 466 StartTasklet(self._ShowInvContLoadingWheel) 467 468 def _ShowInvContLoadingWheel(self): 469 blue.synchro.SleepWallclock(500) 470 wheel = LoadingWheel(parent=self.rightCont, align=uiconst.CENTER) 471 while self.loadingInvCont: 472 blue.synchro.Yield() 473 474 wheel.Close() 475 476 def HideInvContLoadingWheel(self): 477 self.loadingInvCont = False 478 479 def OnInvFiltersChanged(self): 480 self.ConstructFilters() 481 self.UpdateFilters() 482 483 @telemetry.ZONE_METHOD 484 def ConstructFilters(self): 485 self.treeBottomCont.ConstructFilters() 486 487 def RemoveTreeEntry(self, entry, byUser = False, checkRemoveParent = False): 488 parent = entry.data.GetParent() 489 if entry.childCont: 490 for childEntry in entry.childCont.children[:]: 491 self.RemoveTreeEntry(childEntry) 492 493 invID = entry.data.GetID() 494 sm.GetService('inv').RemoveTemporaryInvLocation(invID, byUser) 495 if invID == self.rootInvID: 496 self.Close() 497 return 498 if invID in self.treeEntryByID: 499 self.treeEntryByID.pop(invID) 500 if invID in self.tempTreeEntryByID: 501 self.tempTreeEntryByID.pop(invID) 502 if entry.data in self.treeData.GetChildren(): 503 self.treeData.RemoveChild(entry.data) 504 if invID == self.currInvID: 505 if not self.IsInvTreeExpanded(): 506 self.Close() 507 return 508 self.ShowInvContainer(self.GetDefaultInvID()) 509 entry.Close() 510 if checkRemoveParent and isinstance(parent, TreeDataInvFolder) and not parent.GetChildren(): 511 parEntry = self.treeEntryByID.get(parent.GetID(), None) 512 if parEntry: 513 self.RemoveTreeEntry(parEntry, checkRemoveParent=True) 514 515 def OnInvContScrollSelectionChanged(self, nodes): 516 items = [] 517 for node in nodes: 518 items.append(node.rec) 519 520 self.UpdateSelectedItems(items) 521 522 @telemetry.ZONE_METHOD 523 def UpdateSelectedItems(self, items = None): 524 if not session.IsItSafe(): 525 return 526 if not self.invCont: 527 return 528 self.updateSelectedItemsPending = items or [] 529 if self.updateSelectedItemsThread: 530 return 531 self.updateSelectedItemsThread = StartTasklet(self._UpdateSelectedItems) 532 533 @telemetry.ZONE_METHOD 534 def _UpdateSelectedItems(self): 535 try: 536 while self.updateSelectedItemsPending is not None and not self.destroyed: 537 if session.mutating: 538 break 539 items = self.updateSelectedItemsPending 540 if not items and self.invCont: 541 iskItems = self.invCont.items 542 self.UpdateIskPriceLabel(iskItems) 543 else: 544 self.UpdateIskPriceLabel(items) 545 self.capacityGauge.SetSecondaryVolume(items) 546 self.capacityGauge.SetAdditionalVolume() 547 self.UpdateNumberOfItems(items) 548 self._update_filter_bottom_button() 549 self.updateSelectedItemsPending = None 550 blue.synchro.SleepWallclock(500) 551 552 finally: 553 self.updateSelectedItemsThread = None 554 555 def SetInvContViewMode(self, value): 556 if self.invCont: 557 self.invCont.SetInvContViewMode(value) 558 self.UpdateSelectedItems() 559 560 @telemetry.ZONE_METHOD 561 def UpdateNumberOfItems(self, items = None): 562 items = items or [] 563 item_count_selected = len(items) 564 item_count_filtered = self.invCont.numFilteredItems 565 item_count_total = len(self.invCont.invController.GetItems()) 566 item_count_remaining = item_count_total - item_count_filtered 567 if item_count_filtered > 0: 568 filtered_text = GetByLabel('UI/Inventory/NumFiltered', numFiltered=item_count_filtered) 569 else: 570 filtered_text = '' 571 if item_count_selected > 0: 572 text = GetByLabel('UI/Inventory/NumItemsAndSelected2', numItems=item_count_remaining, numSelected=item_count_selected, numFilteredTxt=filtered_text) 573 else: 574 text = GetByLabel('UI/Inventory/NumItems2', numItems=item_count_remaining, numFilteredTxt=filtered_text) 575 if item_count_filtered > 0: 576 text = eveformat.color(text, eveColor.SUCCESS_GREEN) 577 self.numItemsLabel.text = text 578 579 def OnInvContDragEnter(self, invID, nodes): 580 if not session.IsItSafe(): 581 return 582 if invID != self.currInvID or self.invCont is None: 583 return 584 items = [] 585 for node in nodes: 586 if getattr(node, 'item', None): 587 if self.invController.IsItemHereVolume(node.item): 588 return 589 items.append(node.item) 590 591 self.capacityGauge.SetAdditionalVolume(items) 592 593 def OnInvContDragExit(self, invID, nodes): 594 if not session.IsItSafe(): 595 return 596 self.capacityGauge.SetAdditionalVolume() 597 598 @telemetry.ZONE_METHOD 599 def UpdateIskPriceLabel(self, items): 600 total = 0 601 for item in items: 602 if item is None: 603 continue 604 price = GetAveragePrice(item) 605 if price: 606 total += price * item.stacksize 607 608 self.totalPriceLabel.text = GetByLabel('UI/Inventory/EstIskPrice2', iskString=FmtISKAndRound(total, False)) 609 610 def UpdateSpecialActionButtons(self): 611 self.specialActionsCont.Flush() 612 actions = self.invCont.invController.GetSpecialActions() 613 for label, func, name, isDefaultBtn in actions: 614 button = Button(parent=self.specialActionsCont, label=label, func=func, align=uiconst.CENTERLEFT, name=name, btn_default=isDefaultBtn, density=Density.COMPACT) 615 self.invCont.RegisterSpecialActionButton(button) 616 617 self.specialActionsCont.display = len(self.specialActionsCont.children) > 0 618 619 def RegisterID(self, entry, invID): 620 if id in self.treeEntryByID: 621 raise ValueError('Duplicate inventory location ids: %s' % repr(invID)) 622 self.treeEntryByID[invID] = entry 623 624 def UnregisterID(self, invID): 625 if id in self.treeEntryByID: 626 self.treeEntryByID.pop(invID) 627 628 def OnTreeViewClick(self, entry, *args): 629 if session.solarsystemid and hasattr(entry.data, 'GetItemID'): 630 itemID = entry.data.GetItemID() 631 isCurrStation = itemID in (session.stationid, session.structureid) 632 bp = sm.GetService('michelle').GetBallpark() 633 if bp and itemID in bp.slimItems and not isCurrStation: 634 sm.GetService('stateSvc').SetState(itemID, selected, 1) 635 if hasattr(entry.data, 'OpenNewWindow') and uicore.uilib.Key(uiconst.VK_SHIFT) and entry.canAccess: 636 entry.data.OpenNewWindow() 637 elif isinstance(entry.data, TreeDataInv) and entry.data.HasInvCont(): 638 self.ShowInvContainer(entry.data.GetID()) 639 elif entry.data.HasChildren(): 640 entry.ToggleChildren() 641 642 def OnTreeViewDblClick(self, entry, *args): 643 if isinstance(entry.data, TreeDataInv) and entry.data.HasInvCont(): 644 if always_open_secondary_inventory_setting.is_enabled() and entry.canAccess: 645 entry.data.OpenNewWindow() 646 else: 647 entry.ToggleChildren() 648 649 def OnTreeViewMouseEnter(self, entry, *args): 650 if not session.solarsystemid: 651 return 652 if hasattr(entry.data, 'GetItemID'): 653 sm.GetService('stateSvc').SetState(entry.data.GetItemID(), mouseOver, 1) 654 655 def OnTreeViewMouseExit(self, entry, *args): 656 if not session.solarsystemid: 657 return 658 if hasattr(entry.data, 'GetItemID'): 659 sm.GetService('stateSvc').SetState(entry.data.GetItemID(), mouseOver, 0) 660 661 def OnTreeViewDragEnter(self, entry, dragObj, nodes): 662 self.dragHoverThread = StartTasklet(self._OnTreeViewDragEnter, entry, dragObj, nodes) 663 664 def OnTreeViewDragExit(self, entry, dragObj, nodes): 665 sm.ScatterEvent('OnInvContDragExit', dragObj, nodes) 666 if self.dragHoverThread: 667 self.dragHoverThread.kill() 668 self.dragHoverThread = None 669 670 def _OnTreeViewDragEnter(self, entry, dragObj, nodes): 671 blue.synchro.SleepWallclock(1000) 672 if uicore.uilib.mouseOver == entry and uicore.uilib.leftbtn: 673 entry.ShowChildren() 674 675 def OnTreeViewGetDragData(self, entry): 676 self.dragOpenNewWindowCookie = uicore.uilib.RegisterForTriuiEvents(uiconst.UI_MOUSEMOVEDRAG, self.OnGlobalDragExit, entry) 677 678 def OnGlobalDragExit(self, entry, *args): 679 if not uicore.IsDragging(): 680 return False 681 else: 682 mo = uicore.uilib.mouseOver 683 if IsUnder(mo, self) or mo == self: 684 return True 685 if entry.canAccess and hasattr(entry.data, 'OpenNewWindow'): 686 entry.CancelDrag() 687 invID = entry.data.GetID() 688 windowID = '%s_%s' % (invID[0], entry.settingsID) 689 windowInstanceID = '%s_%s' % (invID[1], entry.settingsID) 690 wnd = uicore.registry.GetWindow(windowID, windowInstanceID) 691 if wnd and wnd.InStack(): 692 wnd.GetStack().RemoveWnd(wnd, (0, 5), dragging=True) 693 elif wnd: 694 StartTasklet(wnd._OpenDraggingThread) 695 else: 696 StartTasklet(entry.data.OpenNewWindow, True) 697 return False 698 699 @telemetry.ZONE_METHOD 700 def ShowInvContainer(self, invID, branchHistory = True): 701 if invID and not self.IsInvIDLegit(invID): 702 invID = self.GetDefaultInvID(startFromInvID=invID) 703 if invID not in self.treeEntryByID: 704 invID = None 705 if invID is None: 706 if self.invCont: 707 self.invCont.Close() 708 self.invCont = None 709 self.noInventoryLabel.Show() 710 self.HideInvContLoadingWheel() 711 self._ExpandTree(animate=False) 712 return 713 self.noInventoryLabel.Hide() 714 if self.invCont is not None and invID == self.invCont.invController.GetInvID(): 715 return 716 entry = self.treeEntryByID.get(invID, None) 717 if entry is None: 718 return 719 try: 720 entry.data.invController.GetItems() 721 except UserError: 722 self.HideInvContLoadingWheel() 723 if not self.invCont: 724 defaultInvID = self.GetDefaultInvID() 725 if defaultInvID != invID: 726 self.ShowInvContainer(defaultInvID) 727 raise 728 729 if self.invCont: 730 self.invCont.Close() 731 self.ShowInvContLoadingWheel() 732 if keep_inv_quick_filter_setting.is_enabled(): 733 quickFilterInput = self.quickFilter.GetQuickFilterInput() 734 else: 735 quickFilterInput = None 736 self.invCont = entry.data.GetInvCont(parent=self.rightCont, activeFilters=self.GetActiveFilters(), name=self.GetWindowSettingsID(), quickFilterInput=quickFilterInput, padding=(0 if not self._is_tree_expanded else (8 if self.compact else 16), 737 0, 738 0, 739 0)) 740 self.invController = self.invCont.invController 741 self.HideInvContLoadingWheel() 742 self.invCont.view_mode_setting.on_change.connect(self._on_inv_cont_view_mode_changed) 743 self.rightCont.state = uiconst.UI_NORMAL 744 if hasattr(self.invCont, 'scroll') and self.invCont.scroll: 745 self.rightCont.OnMouseDown = self.invCont.scroll.OnMouseDown 746 self.rightCont.OnMouseUp = self.invCont.scroll.OnMouseUp 747 self.invCont.GetRubberbandParentContainer = lambda : self.rightCont 748 self.invCont.scroll.OnSelectionChange = self.OnInvContScrollSelectionChanged 749 self.UpdateIskPriceLabel(self.invCont.invController.GetItems()) 750 self.UpdateSpecialActionButtons() 751 self._update_view_mode_button() 752 self._update_sort_by_button_display() 753 self._update_filter_bottom_button() 754 self.UpdateQuickFilter() 755 self.UpdateCapacityGauge() 756 self.UpdateTopRightCont() 757 self.UpdateBottomRightCont() 758 if branchHistory: 759 self.history.Append(invID) 760 previousInvID = self.currInvID 761 self.currInvID = invID 762 self.RegisterLastOpenInvID(invID) 763 self.UpdateSelectedState() 764 self.UpdateNumberOfItems() 765 self.UpdateUIForCompactMode() 766 sm.ScatterEvent('OnInventoryContainerShown', invID, previousInvID) 767 768 def _on_inv_cont_view_mode_changed(self, view_mode): 769 self._update_view_mode_button() 770 self._update_sort_by_button_display() 771 772 def UpdateQuickFilter(self): 773 if self.invCont.IsQuickFilterEnabled(): 774 self.quickFilter.SetInvCont(self.invCont) 775 if self.invCont.IsQuickFilterEnabled(): 776 self.quickFilter.Show() 777 else: 778 self.quickFilter.Hide() 779 780 def UpdateCapacityGauge(self): 781 if self.invCont.IsCapacityEnabled(): 782 self.capacityGauge.SetInvCont(self.invCont) 783 self.capacityGauge.Show() 784 else: 785 self.capacityGauge.Hide() 786 787 def UpdateTopRightCont(self): 788 if self.invCont.IsCapacityEnabled() or self.invCont.IsQuickFilterEnabled() or self.invCont.IsViewModesEnabled(): 789 self.topRightCont2.Show() 790 else: 791 self.topRightCont2.Hide() 792 793 def UpdateBottomRightCont(self): 794 self.bottomRightCont.display = self.invCont is not None and self.invCont.IsEstimatedValueEnabled() 795 796 def GetMenu(self): 797 m = [] 798 if session.role & (ROLE_GML | ROLE_WORLDMOD): 799 m.append(('GM / WM Extras', ('isDynamic', self.GetGMMenu, ()))) 800 m.extend(Window.GetMenu(self)) 801 return m 802 803 def GetGMMenu(self): 804 return [('Clear client inventory cache', sm.GetService('invCache').InvalidateCache, ()), ('Toggle inventory priming debug mode (Red means primed)', self.ToggleInventoryPrimingDebug, ()), ('Clear crystal dmg tracking', sm.GetService('inv').crystalDamageTracker.ClearDamageTrackingCache, ())] 805 806 def ToggleInventoryPrimingDebug(self): 807 isOn = settings.user.ui.Get('invPrimingDebugMode', False) 808 settings.user.ui.Set('invPrimingDebugMode', not isOn) 809 810 def OnBack(self): 811 invID = self.history.GoBack() 812 if invID: 813 if invID in self.treeEntryByID: 814 self.ShowInvContainer(invID, branchHistory=False) 815 else: 816 self.history.GoForward() 817 818 def OnForward(self): 819 invID = self.history.GoForward() 820 if invID: 821 if invID in self.treeEntryByID: 822 self.ShowInvContainer(invID, branchHistory=False) 823 else: 824 self.history.GoBack() 825 826 def Close(self, setClosed = False, *args, **kwds): 827 super(Inventory, self).Close(setClosed, *args, **kwds) 828 sm.ScatterEvent('OnInventoryClosed', self.currInvID) 829 830 def OnResize_(self, *args): 831 if self.InStack(): 832 width = self.GetStack().width 833 else: 834 width = self.width 835 self.dividerCont.SetMaxSize(width - 10) 836 self.treeBottomCont.UpdateSize() 837 self.searchDividerCont.UpdateSize() 838 839 def OnDividerContResize(self): 840 minWidth, minHeight = self.default_minSize 841 minWidth = max(self.dividerCont.width + 10, minWidth) 842 minSize = (minWidth, minHeight) 843 self.SetMinSize(minSize) 844 845 def OnDividerContDragged(self): 846 self.onDividerMoved() 847 848 def RegisterLastOpenInvID(self, invID): 849 settings.user.ui.Set('invLastOpenContainerData_%s' % self.GetWindowSettingsID(), invID) 850 851 def DeselectAllFilters(self): 852 self.treeBottomCont.DeselectAllFilters() 853 854 def UpdateFilters(self): 855 if self.invCont: 856 self.SetActiveFilters(self.GetActiveFilters()) 857 858 def SetActiveFilters(self, filters): 859 self.invCont.SetFilters(filters) 860 self.treeBottomCont.SetActiveFilters(filters) 861 self._update_filter_bottom_button() 862 863 def OnInvContRefreshed(self, invCont): 864 if self.invCont == invCont: 865 self.UpdateSelectedItems() 866 867 def GetActiveFilters(self): 868 return self.treeBottomCont.GetActiveFilters() 869 870 def ChangeTreeWhenAnimating(self, animationStart): 871 if animationStart: 872 self.tree.DisableScrollbars() 873 else: 874 self.tree.EnableScrollbars() 875 876 def OnBreadcrumbLinkClicked(self, linkNum): 877 invID = self.breadcrumbInvIDs[linkNum] 878 if self.IsInvIDLegit(invID): 879 self.ShowInvContainer(invID) 880 881 def GetNeocomGroupIcon(self): 882 return 'res:/UI/Texture/WindowIcons/folder_cargo.png' 883 884 def GetNeocomGroupLabel(self): 885 return GetByLabel('UI/Neocom/InventoryBtn') 886 887 def GetDefaultWndIcon(self): 888 if self.invController: 889 return self.invController.GetIconName() 890 return self.default_iconNum 891 892 def GetWindowSettingsID(self): 893 return self.windowID 894 895 @staticmethod 896 def GetWindowIDFromInvID(invID = None): 897 invCtrlName = invID[0] 898 if invID == (invConst.INVENTORY_ID_SHIP_CARGO, GetActiveShip()): 899 return 'ActiveShipCargo' 900 return invCtrlName 901 902 @staticmethod 903 def GetWindowIDPrimary(): 904 if session.stationid: 905 return invConst.INVENTORY_ID_STATION 906 elif session.structureid: 907 return invConst.INVENTORY_ID_STRUCTURE 908 else: 909 return invConst.INVENTORY_ID_SPACE 910 911 @staticmethod 912 def OpenOrShow(invID = None, usePrimary = True, toggle = False, openFromWnd = None, windowID = None, windowInstanceID = None, **kw): 913 if uicore.uilib.Key(uiconst.VK_SHIFT) or always_open_secondary_inventory_setting.is_enabled(): 914 usePrimary = False 915 openFromWnd = None 916 if not Inventory.IsPrimaryInvTreeExpanded(): 917 usePrimary = False 918 if openFromWnd: 919 if not isinstance(openFromWnd, Inventory): 920 openFromWnd = None 921 else: 922 usePrimary = False 923 if usePrimary or not invID: 924 cls = InventoryPrimary 925 if not windowID: 926 windowID = Inventory.GetWindowIDPrimary() 927 rootInvID = None 928 else: 929 if invID == (invConst.INVENTORY_ID_SHIP_CARGO, GetActiveShip()): 930 cls = ActiveShipCargo 931 else: 932 import form 933 cls = getattr(form, invID[0], Inventory) 934 if not windowID: 935 windowID = Inventory.GetWindowIDFromInvID(invID) 936 if not windowInstanceID: 937 windowInstanceID = invID[1] 938 rootInvID = invID 939 if toggle: 940 wnd = cls.ToggleOpenClose(windowID=windowID, windowInstanceID=windowInstanceID, invID=invID, rootInvID=rootInvID, **kw) 941 else: 942 if openFromWnd: 943 wnd = openFromWnd 944 else: 945 wnd = cls.GetIfOpen(windowID=windowID, windowInstanceID=windowInstanceID) 946 if wnd: 947 wnd.Maximize() 948 if wnd.currInvID != invID: 949 if invID not in wnd.treeEntryByID: 950 wnd.RefreshTree(invID) 951 else: 952 wnd.ShowInvContainer(invID) 953 else: 954 wnd = cls.Open(windowID=windowID, windowInstanceID=windowInstanceID, invID=invID, rootInvID=rootInvID, **kw) 955 if wnd: 956 wnd.ScrollToActiveEntry() 957 return wnd 958 959 def ScrollToActiveEntry(self): 960 StartTasklet(self._ScrollToActiveEntry) 961 962 def _ScrollToActiveEntry(self): 963 blue.synchro.Yield() 964 _, h = self.tree.GetAbsoluteSize() 965 if h <= 0: 966 return 967 entry = self.treeEntryByID.get(self.currInvID, None) 968 if not entry: 969 return 970 _, topEntry = entry.GetAbsolutePosition() 971 _, topScroll, _, height = self.tree.mainCont.GetAbsolute() 972 denum = height - entry.topRightCont.height 973 if denum: 974 fraction = float(topEntry - topScroll) / denum 975 self.tree.ScrollToVertical(fraction) 976 977 def OnDropData(self, dragObj, nodes): 978 if self.invCont: 979 return self.invCont.OnDropData(dragObj, nodes) 980 981 def OnTreeViewDropData(self, entry, obj, nodes): 982 if self.dragHoverThread: 983 self.dragHoverThread.kill() 984 self.dragHoverThread = None 985 if self.dragOpenNewWindowCookie: 986 uicore.uilib.UnregisterForTriuiEvents(self.dragOpenNewWindowCookie) 987 self.dragOpenNewWindowCookie = None 988 if isinstance(entry.data, TreeDataInv): 989 sm.ScatterEvent('OnInvContDragExit', obj, nodes) 990 StartTasklet(self._MoveItems, entry, nodes) 991 992 def _MoveItems(self, entry, nodes): 993 if not nodes: 994 return 995 if isinstance(nodes[0], TreeDataInv): 996 item = nodes[0].invController.GetInventoryItem() 997 else: 998 item = getattr(nodes[0], 'item', None) 999 if item and entry.data.invController.IsItemHere(item): 1000 return 1001 if isinstance(nodes[0], TreeDataInv) and not nodes[0].invController.IsMovable(): 1002 return 1003 if entry.data.invController.OnDropData(nodes): 1004 entry.Blink() 1005 1006 def GetTreeEntryByItemID(self, itemID): 1007 ret = [] 1008 for _, entry in self.treeEntryByID.iteritems(): 1009 if hasattr(entry.data, 'GetItemID') and entry.data.GetItemID() == itemID: 1010 ret.append(entry) 1011 1012 return ret 1013 1014 def GetTreeEntryByID(self, dataID): 1015 ret = [] 1016 for _, entry in self.treeEntryByID.iteritems(): 1017 if hasattr(entry.data, 'GetID') and entry.data.GetID() == dataID: 1018 ret.append(entry) 1019 1020 return ret 1021 1022 def ProcessTempInvLocationAdded(self, invID): 1023 if invID in self.treeEntryByID: 1024 return 1025 if self.rootInvID in sm.GetService('inv').GetTemporaryInvLocations(): 1026 return 1027 invName, itemID = invID 1028 cls = GetTreeDataClassByInvName(invName) 1029 data = cls(invName, parent=self.treeDataTemp, itemID=itemID, isRemovable=True) 1030 entry = self.CreateTreeViewEntry(data) 1031 self.UpdateCelestialEntryStatus(entry) 1032 1033 def ProcessTempInvLocationRemoved(self, invID, byUser): 1034 if invID == self.currInvID and not byUser: 1035 self.Close() 1036 else: 1037 entry = self.treeEntryByID.get(invID, None) 1038 if entry: 1039 if self.treeDataTemp: 1040 self.treeDataTemp.RemoveChild(entry.data) 1041 if entry.data.IsRemovable(): 1042 self.RemoveTreeEntry(entry) 1043 1044 def OnSessionChanged(self, isRemote, sess, change): 1045 if change.keys() == ['shipid']: 1046 return 1047 shouldUpdateCorpHangarNodes = False 1048 if not self._IsCurrentInventoryValid(): 1049 shouldUpdateCorpHangarNodes = self._IsCorpHangarNode(self.currInvID) 1050 self.currInvID = None 1051 elif 'corprole' in change or 'corpid' in change: 1052 shouldUpdateCorpHangarNodes = self._IsCorpHangarNode(self.currInvID) 1053 if shouldUpdateCorpHangarNodes: 1054 self.currInvID = None 1055 self.RefreshTree(corpHangarsChanged=shouldUpdateCorpHangarNodes) 1056 1057 def _IsCorpHangarNode(self, invID): 1058 if not invID or not (session.stationid or session.structureid): 1059 return False 1060 if not self.treeData: 1061 return False 1062 invData = self.treeData.GetChildByID(invID) 1063 if not invData: 1064 return False 1065 office = sm.GetService('officeManager').GetCorpOfficeAtLocation() 1066 if not office: 1067 return False 1068 invAncestorsData = invData.GetAncestors() 1069 invAncestorsData.append(invData) 1070 invAncestorsIDs = [ invData.GetID() for invData in invAncestorsData ] 1071 invClass = 'StationCorpHangars' if session.stationid else 'StructureCorpHangar' 1072 corpHangarItemID = office.officeID 1073 corpHangarInvID = (invClass, corpHangarItemID) 1074 return corpHangarInvID in invAncestorsIDs 1075 1076 def OnPrimaryViewChanged(self, *args): 1077 self.RefreshTree() 1078 1079 def _IsInventoryItem(self, item): 1080 if item.groupID in CONTAINERGROUPS: 1081 return True 1082 if item.categoryID == const.categoryShip: 1083 return True 1084 if item.typeID == const.typeAssetSafetyWrap: 1085 return True 1086 return False 1087 1088 @telemetry.ZONE_METHOD 1089 def OnMultipleItemChange(self, items, change): 1090 self.UpdateSelectedItems() 1091 1092 @telemetry.ZONE_METHOD 1093 def OnInvChangeAny(self, item = None, change = None): 1094 if not self._IsInventoryItem(item): 1095 return 1096 if item.itemID == GetActiveShip(): 1097 return 1098 if item.categoryID == const.categoryShip and not session.stationid and not session.structureid: 1099 return 1100 if const.ixSingleton in change: 1101 self.RefreshTree() 1102 return 1103 if not item.singleton: 1104 return 1105 if const.ixLocationID in change or const.ixFlag in change: 1106 if session.stationid and item.categoryID == const.categoryShip: 1107 if session.charid in (item.ownerID, change.get(const.ixOwnerID, None)): 1108 self.RefreshTree() 1109 elif session.solarsystemid and item.groupID in CONTAINERGROUPS and not InStructure(): 1110 ownerIDs = (item.ownerID, change.get(const.ixOwnerID, None)) 1111 if ownerIDs[0] == ownerIDs[1] == session.corpid: 1112 return 1113 if session.corpid in ownerIDs and session.charid not in ownerIDs: 1114 return 1115 self.RefreshTree() 1116 else: 1117 shouldUpdateCorpHangarNodes = False 1118 if not self._IsCurrentInventoryValid(): 1119 shouldUpdateCorpHangarNodes = self._IsCorpHangarNode(self.currInvID) 1120 self.currInvID = None 1121 self.RefreshTree(corpHangarsChanged=shouldUpdateCorpHangarNodes) 1122 if const.ixOwnerID in change and item.typeID == const.typePlasticWrap: 1123 self.RefreshTree() 1124 1125 def GetSlimItem(self): 1126 itemID = self.invController.itemID 1127 bp = sm.GetService('michelle').GetBallpark() 1128 if bp: 1129 return bp.slimItems.get(itemID, None) 1130 1131 @telemetry.ZONE_METHOD 1132 def RemoveItem(self, item): 1133 if session.solarsystemid and not self.invController.GetItems(): 1134 slimItem = self.GetSlimItem() 1135 if slimItem is not None and slimItem.groupID in LOOT_GROUPS: 1136 self.RemoveWreckEntryOrClose() 1137 1138 def OnWreckLootAll(self, invID, items): 1139 if invID == self.currInvID: 1140 self.RemoveWreckEntryOrClose() 1141 treeEntry = self.treeEntryByID.get((invConst.INVENTORY_ID_SHIP_CARGO, GetActiveShip())) 1142 if treeEntry and items: 1143 treeEntry.Blink() 1144 1145 def RemoveWreckEntryOrClose(self): 1146 if self.IsInvTreeExpanded(): 1147 entry = self.treeEntryByID.get(self.currInvID, None) 1148 if entry: 1149 self.SwitchToOtherLootable(entry) 1150 if entry.data.IsRemovable(): 1151 self.RemoveTreeEntry(entry, byUser=True) 1152 else: 1153 slimItem = self.GetSlimItem() 1154 if slimItem is not None and slimItem.groupID not in LOOT_GROUPS_NOCLOSE: 1155 self.CloseByUser() 1156 1157 def SwitchToOtherLootable(self, oldEntry): 1158 lootableData = [ data for data in self.treeDataTemp.GetChildren() if data.GetID()[0] in ('ItemWreck', 'ItemFloatingCargo') ] 1159 if oldEntry.data not in lootableData: 1160 return 1161 idx = lootableData.index(oldEntry.data) 1162 lootableData.remove(oldEntry.data) 1163 if lootableData: 1164 newIdx = min(len(lootableData) - 1, idx) 1165 invID = lootableData[newIdx].GetID() 1166 self.ShowInvContainer(invID) 1167 1168 def OnStateChange(self, itemID, flag, isSet, *args): 1169 if flag == flagWreckEmpty: 1170 entries = self.GetTreeEntryByItemID(itemID) 1171 for entry in entries: 1172 self.RemoveTreeEntry(entry) 1173 1174 def OnSlimItemChange(self, oldSlim, newSlim): 1175 if IsStarbase(newSlim.categoryID): 1176 if oldSlim.posState != newSlim.posState: 1177 self.RefreshTree() 1178 1179 def OnCapacityChange(self, itemID): 1180 if self.invController and itemID == self.invController.itemID: 1181 self.UpdateSelectedItems() 1182 self.capacityGauge.RefreshCapacity() 1183 1184 def DoBallsAdded(self, data): 1185 for _, slimItem in data: 1186 if slimItem.categoryID == const.categoryStarbase: 1187 self.RefreshTree() 1188 return 1189 1190 @telemetry.ZONE_METHOD 1191 def DoBallsRemove(self, pythonBalls, isRelease): 1192 for ball, slimItem, terminal in pythonBalls: 1193 self.DoBallRemove(ball, slimItem, terminal) 1194 1195 def DoBallRemove(self, ball, slimItem, terminal): 1196 StartTasklet(self._DoBallRemove, ball, slimItem, terminal) 1197 1198 def _DoBallRemove(self, ball, slimItem, terminal): 1199 if self and self.destroyed: 1200 return 1201 invID = (invConst.INVENTORY_ID_SHIP_CARGO, GetActiveShip()) 1202 if slimItem.itemID in (session.structureid, session.stationid): 1203 return 1204 for entry in self.GetTreeEntryByItemID(slimItem.itemID): 1205 if entry.data.GetID() == invID: 1206 continue 1207 if entry.data.IsDescendantOf(invID): 1208 continue 1209 self.RemoveTreeEntry(entry, checkRemoveParent=True) 1210 1211 def OnItemNameChange(self, *args): 1212 self.RefreshTree() 1213 1214 def ProcessActiveShipChanged(self, shipID, oldShipID): 1215 self.RefreshTree() 1216 1217 def OnCompactModeEnabled(self): 1218 super(Inventory, self).OnCompactModeEnabled() 1219 self.UpdateUIForCompactMode() 1220 self.UpdateBottomRightCont() 1221 1222 def OnCompactModeDisabled(self): 1223 super(Inventory, self).OnCompactModeDisabled() 1224 self.UpdateUIForCompactMode() 1225 self.UpdateBottomRightCont() 1226 1227 def UpdateUIForCompactMode(self): 1228 if self.invController is None: 1229 return 1230 self.invController.SetCompactMode(self.IsCompact()) 1231 self._update_search_field() 1232 self._update_top_action_container_padding(animate=False) 1233 self._update_top_action_container_display() 1234 if self.IsCompact(): 1235 self.searchDividerCont.Hide() 1236 show_capacity = self.invCont and self.invCont.IsCapacityEnabled() 1237 if show_capacity: 1238 self.topRightCont2.Show() 1239 self.capacityGauge.padding = 0 1240 self.capacityGauge.HideLabel() 1241 self.topRightCont2.height = 5 1242 else: 1243 self.topRightCont2.Hide() 1244 self.capacityGauge.state = uiconst.UI_NORMAL 1245 self.rightCont.padLeft = -8 if self._is_tree_expanded else 0 1246 if self.invCont: 1247 self.invCont.padLeft = 8 if self._is_tree_expanded else 0 1248 self.topRightCont2.padLeft = 8 if self._is_tree_expanded else 0 1249 self.topRightCont2.padBottom = 8 1250 else: 1251 self.searchDividerCont.Show() 1252 if self.invCont and self.invCont.IsCapacityEnabled(): 1253 self.topRightCont2.Show() 1254 self.capacityGauge.padding = (0, 0, 0, 0) 1255 self.capacityGauge.ShowLabel() 1256 self.topRightCont2.height = 24 1257 if self.invCont: 1258 self.invCont.padLeft = 16 if self._is_tree_expanded else 0 1259 self.capacityGauge.state = uiconst.UI_PICKCHILDREN 1260 self.rightCont.padLeft = -8 if self._is_tree_expanded else 0 1261 self.topRightCont2.padLeft = 0 1262 self.topRightCont2.padBottom = 16 1263 1264 def CollapseFilters(self, animate = True): 1265 self.filterCont.Disable() 1266 self.expandFiltersBtn.Disable() 1267 self.expandFiltersBtn.SetRotation(pi) 1268 self.treeBottomCont.DisableDragResize() 1269 height = self.filterHeaderCont.height + 6 1270 self.treeBottomCont.minSize = self.treeBottomCont.maxSize = height 1271 self.filterCont.DisableScrollbars() 1272 if animate: 1273 self.tree.DisableScrollbars() 1274 animations.MorphScalar(self.treeBottomCont, 'height', self.treeBottomCont.height, height, duration=0.3) 1275 animations.FadeOut(self.filterCont, duration=0.3, sleep=True) 1276 self.tree.EnableScrollbars() 1277 self.treeBottomCont.height = height 1278 self.filterCont.opacity = 0.0 1279 self.expandFiltersBtn.Enable() 1280 settings.user.ui.Set('invFiltersExpanded_%s' % self.GetWindowSettingsID(), False) 1281 1282 def CollapseFilters(self, animate = True): 1283 self.filterCont.Disable() 1284 self.expandFiltersBtn.Disable() 1285 self.expandFiltersBtn.SetRotation(pi) 1286 self.treeBottomCont.DisableDragResize() 1287 height = self.filterHeaderCont.height + 16 1288 self.treeBottomCont.minSize = self.treeBottomCont.maxSize = height 1289 self.filterCont.DisableScrollbars() 1290 if animate: 1291 self.tree.DisableScrollbars() 1292 animations.MorphScalar(self.treeBottomCont, 'height', self.treeBottomCont.height, height, duration=0.3) 1293 animations.FadeOut(self.filterCont, duration=0.3, sleep=True) 1294 self.tree.EnableScrollbars() 1295 self.treeBottomCont.height = height 1296 self.filterCont.opacity = 0.0 1297 self.expandFiltersBtn.Enable() 1298 settings.user.ui.Set('invFiltersExpanded_%s' % self.GetWindowSettingsID(), False) 1299 1300 def Paste(self, value): 1301 if self.invCont: 1302 self.invCont.Paste(value) 1303 1304 def OnOfficeRentalChanged(self, corporationID, officeID): 1305 if corporationID == session.corpid: 1306 self.RefreshTree() 1307 1308 @telemetry.ZONE_METHOD 1309 def RefreshTree(self, invID = None, corpHangarsChanged = False): 1310 if invID: 1311 self.currInvID = invID 1312 while not session.IsItSafe(): 1313 blue.pyos.synchro.SleepSim(250) 1314 1315 if not sm.GetService('inv').IsTreeUpdatingEnabled() or self.refreshTreeThread and self.refreshTreeThread.tasklet.alive: 1316 self.needsUpdate = True 1317 return 1318 if self.refreshTreeThread: 1319 self.refreshTreeThread.kill() 1320 self.refreshTreeThread = StartTasklet(self._RefreshTree, corpHangarsChanged) 1321 1322 @telemetry.ZONE_METHOD 1323 def _RefreshTree(self, corpHangarsChanged = False): 1324 needsUpdate = True 1325 while needsUpdate: 1326 if self.destroyed: 1327 return 1328 self.needsUpdate = False 1329 if self.invCont: 1330 self.invCont.Disable() 1331 self.tree.Disable() 1332 try: 1333 self.ConstructTree(corpHangarsChanged) 1334 finally: 1335 self.tree.Enable() 1336 if self.invCont: 1337 self.invCont.Enable() 1338 1339 self.UpdateRangeUpdater() 1340 needsUpdate = self.needsUpdate 1341 1342 def IsInvIDLegit(self, invID): 1343 data = self.treeData.GetDescendants().get(invID, None) 1344 if data is None: 1345 data = self.treeDataTemp.GetDescendants().get(invID, None) 1346 if invID == self.treeData.GetID(): 1347 data = self.treeData 1348 return data is not None and isinstance(data, TreeDataInv) and data.HasInvCont() 1349 1350 def GetDefaultInvID(self, startFromInvID = None): 1351 treeData = None 1352 if startFromInvID: 1353 treeData = self.treeData.GetChildByID(startFromInvID) or self.treeData 1354 else: 1355 treeData = self.treeData 1356 invID = self._GetDefaultInvID([treeData]) 1357 if startFromInvID and invID is None: 1358 return self.GetDefaultInvID() 1359 else: 1360 return invID 1361 1362 def _IsValidDefaultInvID(self, data): 1363 if isinstance(data, TreeDataInv) and data.HasInvCont(): 1364 if not data.IsValidDefaultSelection(): 1365 return False 1366 invController = GetInvCtrlFromInvID(data.GetID()) 1367 if invController.IsInRange(): 1368 return True 1369 return False 1370 1371 def _GetDefaultInvID(self, dataNodes): 1372 settingsInvID = settings.user.ui.Get('invLastOpenContainerData_%s' % self.GetWindowSettingsID(), None) 1373 if settingsInvID: 1374 for data in dataNodes: 1375 if data.GetID() == settingsInvID and self._IsValidDefaultInvID(data): 1376 return data.GetID() 1377 1378 for data in dataNodes: 1379 if self._IsValidDefaultInvID(data): 1380 return data.GetID() 1381 if data.HasChildren(): 1382 ret = self._GetDefaultInvID(data.GetChildren()) 1383 if ret: 1384 return ret 1385 1386 def ConstructTree(self, corpHangarsChanged = False): 1387 self.treeEntryByID = {} 1388 self.tree.Flush() 1389 self.ShowTreeLoadingWheel() 1390 try: 1391 self.treeData = sm.GetService('inv').GetInvLocationTreeData(self.rootInvID) 1392 except RuntimeError as e: 1393 if e.args[0] == 'CharacterNotAtStation': 1394 return 1395 raise 1396 1397 self.treeDataTemp = sm.GetService('inv').GetInvLocationTreeDataTemp(self.rootInvID) 1398 if not self.caption and self.rootInvID: 1399 data = self.GetTreeDataByInvID(self.rootInvID) 1400 if data: 1401 self.SetCaption(data.GetLabel()) 1402 if self.currInvID is None or not self.IsInvIDLegit(self.currInvID): 1403 self.currInvID = self.GetDefaultInvID(self.currInvID) 1404 if self.currInvID: 1405 GetInvCtrlFromInvID(self.currInvID).GetItems() 1406 self.treeData = sm.GetService('inv').GetInvLocationTreeData(self.rootInvID) 1407 if self.rootInvID and not always_show_full_tree_setting.is_enabled(): 1408 tempData = self.treeDataTemp.GetChildByID(self.rootInvID) 1409 rootNodes = [] 1410 if tempData: 1411 self.treeData = tempData 1412 rootNodes.append(self.treeData) 1413 else: 1414 childData = self.treeData.GetChildByID(self.rootInvID) 1415 if childData: 1416 self.treeData = childData 1417 rootNodes.append(self.treeData) 1418 rootNodes.extend(self.treeDataTemp.GetChildren()) 1419 else: 1420 rootNodes = self.treeData.GetChildren() 1421 rootNodes.extend(self.treeDataTemp.GetChildren()) 1422 expanded = self._is_tree_expanded_setting.get() 1423 if expanded: 1424 self._ExpandTree(animate=False) 1425 self.tree.opacity = 0.0 1426 for data in rootNodes: 1427 self.CreateTreeViewEntry(data) 1428 1429 self.HideTreeLoadingWheel() 1430 animations.FadeIn(self.tree, duration=0.2) 1431 if self.currInvID: 1432 self.UpdateSelectedState() 1433 self.ScrollToActiveEntry() 1434 if self.rootInvID is not None and self.rootInvID not in self.treeEntryByID: 1435 self.Close() 1436 else: 1437 self.ShowInvContainer(self.currInvID) 1438 if corpHangarsChanged: 1439 if self.rootInvID: 1440 self._CloseCorpHangars() 1441 else: 1442 self._CollapseCorpHangars() 1443 1444 def CreateTreeViewEntry(self, data): 1445 treeEntryClass = GetTreeViewEntryClassByDataType(data) 1446 treeEntry = treeEntryClass(name=getattr(data, 'clsName', ''), parent=self.tree, level=0, eventListener=self, data=data, settingsID=self.GetWindowSettingsID(), onDividerMoved=self.onDividerMoved) 1447 return treeEntry 1448 1449 def _CloseCorpHangars(self): 1450 if self._IsCorpHangarNode(self.rootInvID): 1451 self.Close() 1452 1453 def _CollapseCorpHangars(self): 1454 corpHangarsNodeID = None 1455 if session.structureid or session.stationid: 1456 office = sm.GetService('officeManager').GetCorpOfficeAtLocation() 1457 if office: 1458 corpHangarsNodeID = ('StationCorpHangars', office.officeID) 1459 if not corpHangarsNodeID: 1460 return 1461 entries = self.GetTreeEntryByID(corpHangarsNodeID) 1462 for entry in entries: 1463 entry.HideChildren() 1464 1465 def UpdateSelectedState(self): 1466 selectedIDs = self.treeData.GetPathToDescendant(self.currInvID) or self.treeDataTemp.GetPathToDescendant(self.currInvID) or [] 1467 selectedIDs = [ node.GetID() for node in selectedIDs ] 1468 if selectedIDs: 1469 for entry in self.treeEntryByID.values(): 1470 entry.UpdateSelectedState(selectedIDs=selectedIDs) 1471 1472 def UpdateRangeUpdater(self): 1473 if InShipInSpace() and not self.containersInRangeUpdater: 1474 self.containersInRangeUpdater = StartTasklet(self.UpdateTreeViewEntriesInRange) 1475 elif (session.structureid or session.stationid) and self.containersInRangeUpdater: 1476 self.containersInRangeUpdater.kill() 1477 self.containersInRangeUpdater = None 1478 1479 def UpdateTreeViewEntriesInRange(self): 1480 while not self.destroyed: 1481 if session.solarsystemid is None: 1482 self.containersInRangeUpdater = None 1483 return 1484 self._UpdateTreeViewEntriesInRange() 1485 1486 def _UpdateTreeViewEntriesInRange(self): 1487 for entry in self.treeEntryByID.values(): 1488 if not entry.display or entry.IsCompletelyClipped(self.tree): 1489 continue 1490 self.UpdateCelestialEntryStatus(entry) 1491 blue.pyos.BeNice() 1492 1493 blue.synchro.Sleep(500) 1494 1495 def UpdateCelestialEntryStatus(self, entry): 1496 if hasattr(entry.data, 'GetLabelWithDistance'): 1497 entry.label.text = entry.data.GetLabelWithDistance() 1498 invController = getattr(entry.data, 'invController', None) 1499 if invController is None: 1500 canAccess = True 1501 else: 1502 canAccess = invController.IsInRange() 1503 if isinstance(entry.data.invController, (ItemWreck, ItemFloatingCargo)): 1504 data = entry.data 1505 entry.icon.LoadIcon(data.GetIcon(), ignoreSize=True) 1506 slimItem = sm.GetService('michelle').GetBallpark().slimItems[data.invController.itemID] 1507 entry.iconColor = GetIconColor(slimItem) 1508 entry.SetAccessability(canAccess) 1509 1510 def OnExpandTreeBtn(self, *args): 1511 if self.dividerCont.pickState: 1512 self.CollapseTree() 1513 else: 1514 self.ExpandTree() 1515 self.OnDividerContResize() 1516 1517 def GetTreeDataByInvID(self, invID): 1518 for root in (self.treeData, self.treeDataTemp): 1519 data = root.GetChildByID(invID) 1520 if data: 1521 return data 1522 1523 def SetInvTreeExpandedSetting(self, isExpanded): 1524 self._is_tree_expanded_setting.set(isExpanded) 1525 1526 def IsInvTreeExpanded(self, getDefault = True): 1527 return self._is_tree_expanded_setting.get() 1528 1529 @staticmethod 1530 def IsPrimaryInvTreeExpanded(): 1531 windowID = Inventory.GetWindowIDPrimary() 1532 return bool(settings.user.ui.Get('invTreeExpanded_%s' % windowID, True)) 1533 1534 @staticmethod 1535 def IsPrimaryInvCompacted(): 1536 windowID = Inventory.GetWindowIDPrimary() 1537 return GetRegisteredState(windowID, 'compact') 1538 1539 def GetDefaultInvTreeExpanded(self): 1540 if not self.rootInvID: 1541 return True 1542 if not self.treeData: 1543 return None 1544 data = self.treeData.GetChildByID(self.rootInvID) 1545 if data: 1546 return data.HasChildren() 1547 1548 def ExpandTree(self, animate = True): 1549 self._ExpandTree(animate) 1550 self.SetInvTreeExpandedSetting(True) 1551 1552 def _ExpandTree(self, animate = True): 1553 if self._is_tree_expanded: 1554 return 1555 self._is_tree_expanded = True 1556 width = settings.user.ui.Get('invTreeViewWidth_%s' % self.GetWindowSettingsID(), TREE_DEFAULT_WIDTH) 1557 self._update_top_action_container_padding(animate) 1558 self._update_bottom_right_cont_padding(animate) 1559 if animate: 1560 DURATION = 0.3 1561 animations.MorphScalar(self.dividerCont, 'width', self.dividerCont.width, width, duration=DURATION) 1562 animations.MorphScalar(self.rightCont, 'padLeft', endVal=-8, duration=DURATION) 1563 if self.invCont: 1564 animations.MorphScalar(self.invCont, 'padLeft', endVal=8 if self.compact else 16, duration=DURATION) 1565 if self.compact: 1566 animations.MorphScalar(self.topRightCont2, 'padLeft', endVal=8, duration=DURATION) 1567 animations.FadeIn(self.dividerCont, duration=0.3, sleep=True) 1568 else: 1569 self.dividerCont.width = width 1570 self.rightCont.padLeft = -8 1571 if self.invCont: 1572 self.invCont.padLeft = 8 if self.compact else 16 1573 if self.compact: 1574 self.topRightCont2.padLeft = 8 1575 self.dividerCont.state = uiconst.UI_PICKCHILDREN 1576 self.OnDividerContResize() 1577 1578 def CollapseTree(self, animate = True): 1579 self._CollapseTree(animate) 1580 self.SetInvTreeExpandedSetting(False) 1581 1582 def _CollapseTree(self, animate = True): 1583 if not self._is_tree_expanded: 1584 return 1585 self._is_tree_expanded = False 1586 self.dividerCont.state = uiconst.UI_DISABLED 1587 self._update_top_action_container_padding(animate) 1588 self._update_bottom_right_cont_padding(animate) 1589 if animate: 1590 DURATION = 0.3 1591 animations.MorphScalar(self.dividerCont, 'width', self.dividerCont.width, 0.0, duration=DURATION) 1592 animations.MorphScalar(self.rightCont, 'padLeft', endVal=0, duration=DURATION) 1593 if self.invCont: 1594 animations.MorphScalar(self.invCont, 'padLeft', endVal=0, duration=DURATION) 1595 if self.compact: 1596 animations.MorphScalar(self.topRightCont2, 'padLeft', endVal=0, duration=DURATION) 1597 animations.FadeOut(self.dividerCont, duration=DURATION, sleep=True) 1598 else: 1599 self.dividerCont.width = 0 1600 self.rightCont.padLeft = 0 1601 if self.invCont: 1602 self.invCont.padLeft = 0 1603 if self.compact: 1604 self.topRightCont2.padLeft = 0 1605 self.OnDividerContResize() 1606 1607 def OnInvTreeUpdatingChanged(self, newState): 1608 if newState and self.needsUpdate: 1609 self.RefreshTree() 1610 1611 def _clear_all_filters(self): 1612 self.DeselectAllFilters() 1613 if self.invCont: 1614 self.quickFilter.ClearFilter() 1615 self._update_filter_bottom_button() 1616 1617 1618 class InventoryPrimary(Inventory): 1619 __guid__ = 'form.InventoryPrimary' 1620 default_windowID = 'InventoryPrimary' 1621 default_caption = 'UI/Neocom/InventoryBtn' 1622 1623 def GetDefaultWndIcon(self): 1624 return self.default_iconNum 1625 1626 def ProcessActiveShipChanged(self, shipID, oldShipID): 1627 if self.currInvID == (invConst.INVENTORY_ID_SHIP_CARGO, oldShipID): 1628 invID = (invConst.INVENTORY_ID_SHIP_CARGO, shipID) 1629 else: 1630 invID = None 1631 self.RefreshTree(invID) 1632 1633 def ApplyAttributes(self, attributes): 1634 super(InventoryPrimary, self).ApplyAttributes(attributes) 1635 if session.stationid: 1636 self.SetScope(uiconst.SCOPE_STATION) 1637 elif session.structureid: 1638 self.SetScope(uiconst.SCOPE_STRUCTURE) 1639 else: 1640 self.SetScope(uiconst.SCOPE_INFLIGHT) 1641 1642 @classmethod 1643 def Open(cls, windowID = None, *args, **kwds): 1644 if not windowID: 1645 windowID = Inventory.GetWindowIDPrimary() 1646 return super(InventoryPrimary, cls).Open(windowID=windowID, *args, **kwds) 1647 1648 @classmethod 1649 def GetIfOpen(cls, windowID = None, windowInstanceID = None): 1650 if not windowID: 1651 windowID = Inventory.GetWindowIDPrimary() 1652 return super(InventoryPrimary, cls).GetIfOpen(windowID, windowInstanceID) 1653 1654 1655 class InventorySecondary(Inventory): 1656 1657 @classmethod 1658 def Open(cls, invID = None, *args, **kwds): 1659 if not invID: 1660 invID = (kwds.get('windowID', cls.default_windowID), kwds.get('windowInstanceID', None)) 1661 return super(InventorySecondary, cls).Open(invID=invID, *args, **kwds) 1662 1663 1664 class StationItems(InventorySecondary): 1665 __guid__ = 'form.' + invConst.INVENTORY_ID_STATION_ITEMS 1666 default_windowID = invConst.INVENTORY_ID_STATION_ITEMS 1667 default_scope = uiconst.SCOPE_DOCKED 1668 default_iconNum = StationItemsController.iconName 1669 1670 @classmethod 1671 def OnDropDataCls(cls, dragObj, nodes): 1672 return StationItemsController().OnDropData(nodes) 1673 1674 1675 class StructureItems(InventorySecondary): 1676 __guid__ = 'form.' + invConst.INVENTORY_ID_STRUCTURE_ITEMS 1677 default_windowID = invConst.INVENTORY_ID_STRUCTURE_ITEMS 1678 default_scope = uiconst.SCOPE_DOCKED 1679 default_iconNum = StructureItemsController.iconName 1680 1681 @classmethod 1682 def OnDropDataCls(cls, dragObj, nodes): 1683 return StructureItemsController().OnDropData(nodes) 1684 1685 1686 class PlexVaultWindow(InventorySecondary): 1687 __guid__ = 'form.PlexVault' 1688 default_windowID = invConst.INVENTORY_ID_PLEX_VAULT 1689 default_iconNum = PLEX_WINDOW_ICON 1690 1691 1692 class StationShips(InventorySecondary): 1693 __guid__ = 'form.' + invConst.INVENTORY_ID_STATION_SHIPS 1694 default_windowID = invConst.INVENTORY_ID_STATION_SHIPS 1695 default_scope = uiconst.SCOPE_DOCKED 1696 default_iconNum = StationShipsController.iconName 1697 1698 @classmethod 1699 def OnDropDataCls(cls, dragObj, nodes): 1700 return StationShipsController().OnDropData(nodes) 1701 1702 def ShowInvContainer(self, invID, *args, **kw): 1703 if invID[1] == GetActiveShip(): 1704 InventorySecondary.OpenOrShow(invID, usePrimary=False) 1705 else: 1706 InventorySecondary.ShowInvContainer(self, invID, *args, **kw) 1707 1708 1709 class StructureShips(StationShips): 1710 __guid__ = 'form.' + invConst.INVENTORY_ID_STRUCTURE_SHIPS 1711 default_windowID = invConst.INVENTORY_ID_STRUCTURE_SHIPS 1712 default_scope = uiconst.SCOPE_DOCKED 1713 default_iconNum = StructureShipsController.iconName 1714 1715 @classmethod 1716 def OnDropDataCls(cls, dragObj, nodes): 1717 return StructureShipsController().OnDropData(nodes) 1718 1719 1720 class StationCorpHangars(InventorySecondary): 1721 __guid__ = 'form.StationCorpHangars' 1722 default_windowID = invConst.INVENTORY_ID_STATION_CORP_HANGARS 1723 default_scope = uiconst.SCOPE_DOCKED 1724 default_iconNum = 'res:/ui/Texture/WindowIcons/corpHangar.png' 1725 1726 def GetDefaultWndIcon(self): 1727 return self.default_iconNum 1728 1729 1730 class StationCorpDeliveries(InventorySecondary): 1731 __guid__ = 'form.StationCorpDeliveries' 1732 default_windowID = invConst.INVENTORY_ID_STATION_CORP_DELIVERIES 1733 default_scope = uiconst.SCOPE_DOCKED 1734 default_iconNum = StationCorpDeliveriesController.iconName 1735 1736 @classmethod 1737 def OnDropDataCls(cls, dragObj, nodes): 1738 return StationCorpDeliveriesController().OnDropData(nodes) 1739 1740 @classmethod 1741 def Open(cls, invID = None, *args, **kwds): 1742 deliveryRoles = appConst.corpRoleAccountant | appConst.corpRoleJuniorAccountant | appConst.corpRoleTrader 1743 if session.corprole & deliveryRoles == 0: 1744 prompt_player_fsd_dialog('CrpAccessDenied', {'reason': GetByLabel('UI/Commands/CorpRoleMissing')}) 1745 allOpen = settings.char.windows.Get('openWindows', {}) 1746 allOpen.pop('CorpMarketHangar', None) 1747 settings.char.windows.Set('openWindows', allOpen) 1748 return 1749 return super(StationCorpDeliveries, cls).Open(invID, *args, **kwds) 1750 1751 1752 class CapsuleerDeliveries(InventorySecondary): 1753 __guid__ = 'form.CapsuleerDeliveries' 1754 default_windowID = invConst.INVENTORY_ID_CORPORATION_ITEM_DELIVERIES 1755 default_scope = uiconst.SCOPE_DOCKED 1756 default_iconNum = CapsuleerDeliveriesController.iconName 1757 1758 @classmethod 1759 def OnDropDataCls(cls, _dragObj, nodes): 1760 return CapsuleerDeliveriesController().OnDropData(nodes) 1761 1762 @classmethod 1763 def Open(cls, invID = None, *args, **kwds): 1764 deliveryRoles = appConst.corpRoleProjectManager | appConst.corpRoleDirector 1765 if session.corprole & deliveryRoles == 0: 1766 prompt_player_fsd_dialog('CrpAccessDenied', {'reason': GetByLabel('UI/Commands/ProjectManagerOrDirectorRoleMissing')}) 1767 allOpen = settings.char.windows.Get('openWindows', {}) 1768 allOpen.pop('CapsuleerDeliveries', None) 1769 settings.char.windows.Set('openWindows', allOpen) 1770 return 1771 return super(CapsuleerDeliveries, cls).Open(invID, *args, **kwds) 1772 1773 1774 class AssetSafetyDeliveries(InventorySecondary): 1775 __guid__ = 'form.AssetSafetyDeliveries' 1776 default_windowID = 'AssetSafetyDeliveries' 1777 default_scope = uiconst.SCOPE_DOCKED 1778 default_iconNum = AssetSafetyDeliveriesController.iconName 1779 1780 @classmethod 1781 def OnDropDataCls(cls, dragObj, nodes): 1782 return None 1783 1784 1785 class AssetSafetyContainer(InventorySecondary): 1786 __guid__ = 'form.AssetSafetyContainer' 1787 default_windowID = 'AssetSafetyContainer' 1788 default_scope = uiconst.SCOPE_DOCKED 1789 default_iconNum = AssetSafetyContainerController.iconName 1790 1791 @classmethod 1792 def OnDropDataCls(cls, dragObj, nodes): 1793 return None 1794 1795 1796 class ActiveShipCargo(InventorySecondary): 1797 __guid__ = 'form.ActiveShipCargo' 1798 default_windowID = 'ActiveShipCargo' 1799 default_iconNum = 'res:/UI/Texture/WindowIcons/cargo.png' 1800 default_caption = 'UI/Neocom/ActiveShipCargoBtn' 1801 1802 def ProcessActiveShipChanged(self, shipID, oldShipID): 1803 self.rootInvID = (invConst.INVENTORY_ID_SHIP_CARGO, shipID) 1804 self.RefreshTree() 1805 1806 def GetDefaultWndIcon(self): 1807 return self.default_iconNum 1808 1809 @classmethod 1810 def OnDropDataCls(cls, dragObj, nodes): 1811 return ShipCargoController(GetActiveShip()).OnDropData(nodes) 1812 1813 1814 class TreeExpandedSetting(UserSettingBool): 1815 1816 def __init__(self, window): 1817 self._window_ref = weakref.ref(window) 1818 super(TreeExpandedSetting, self).__init__(settings_key='invTreeExpanded_{}'.format(window.windowID), default_value=self._get_default_value) 1819 1820 @property 1821 def is_default_determined(self): 1822 window = self._window_ref() 1823 if window is None: 1824 return False 1825 if not window.rootInvID: 1826 return True 1827 return bool(window.treeData) 1828 1829 def set(self, value): 1830 if self.is_default_determined: 1831 super(TreeExpandedSetting, self).set(value) 1832 1833 def _get_default_value(self): 1834 window = self._window_ref() 1835 if window is None: 1836 return False 1837 if not window.rootInvID: 1838 return True 1839 if not window.treeData: 1840 return False 1841 data = window.treeData.GetChildByID(window.rootInvID) 1842 if data: 1843 return data.HasChildren() 1844 return False