fittingBrowser.py (35395B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\fittingScreen\browsers\fittingBrowser.py 2 import itertools 3 from collections import defaultdict 4 import blue 5 import log 6 import evetypes 7 from carbon.common.script.sys.serviceConst import ROLE_WORLDMOD, ROLEMASK_ELEVATEDPLAYER 8 from carbonui import uiconst 9 from carbonui.button.const import HEIGHT_NORMAL 10 from carbonui.control.contextMenu.menuData import MenuData 11 from carbonui.control.dragdrop.dragdata import TypeDragData 12 from carbonui.primitives.container import Container 13 from carbonui.primitives.fill import Fill 14 from carbonui.primitives.sprite import Sprite 15 from carbonui.uicore import uicore 16 from carbonui.util.various_unsorted import SortListOfTuples 17 from characterdata.races import get_race 18 from characterdata.races import get_race_name 19 from eve.client.script.ui.control.entries.fitting import FittingEntry 20 from eve.client.script.ui.control.entries.generic import Generic 21 from eve.client.script.ui.control.entries.util import GetFromClass 22 from eve.client.script.ui.control.eveLabel import EveLabelMedium 23 from eve.client.script.ui.control.listgroup import ListGroup as Group, ListGroup 24 from eve.client.script.ui.shared.fitting.fittingUtil import CanDeleteFit, GetDeletableNodes, DeleteFittings 25 from eve.client.script.ui.shared.fittingMgmtWindow import OpenOrLoadMultiFitWnd 26 from eve.client.script.ui.shared.fittingScreen import FITTING_OWNER_CORP, FITTING_OWNER_COMMUNITY, FITTING_OWNER_PERSONAL, FITTING_OWNER_ALLIANCE, BROWSE_FITTINGS 27 from eve.client.script.ui.shared.fittingScreen.shipFittingSimulationButton import ShipFittingSimulationButton 28 from eve.client.script.ui.shared.traits import HasTraits, TraitsContainer 29 from eve.client.script.ui.util import uix 30 from eve.common.lib import appConst 31 from eve.common.script.sys.eveCfg import IsControllingStructure 32 from eve.common.script.sys.eveCfg import IsDocked 33 from eveservices.menu import GetMenuService 34 from globalConfig.getFunctions import AreCommunityFittingsEnabled, GetMaxShipsToFit 35 from localization import GetByLabel 36 from menu import MenuLabel 37 from utillib import KeyVal 38 NON_EMPIRE = -1 39 MARKET_GROUP_CITADEL = 2199 40 MARKET_GROUP_ENGINEERING_COMPLEX = 2324 41 MARKET_GROUP_REFINERY = 2327 42 MARKET_GROUP_NAVIGATION_STRUCTURES = 2511 43 MARKET_GROUP_SPECIAL_SHIPS = 1612 44 45 class HullBrowserListProvider(object): 46 show_fitted_ships = True 47 48 def __init__(self, onDropDataFunc, browserID = None): 49 self.onDropDataFunc = onDropDataFunc 50 self.fittingSvc = sm.GetService('fittingSvc') 51 self.ghostFittingSvc = sm.GetService('ghostFittingSvc') 52 self.specialTypeIDs = None 53 self.currentShipTypeID = None 54 self.browserID = browserID 55 if session.role & ROLEMASK_ELEVATEDPLAYER: 56 try: 57 self.fittingSpawner = sm.GetService('fittingspawner') 58 except: 59 self.fittingSpawner = None 60 61 def GetFittingScrolllist(self, currentShipTypeID, hull_filter_settings, *args): 62 communityFittingEnabled = AreCommunityFittingsEnabled(sm.GetService('machoNet')) 63 self.currentShipTypeID = currentShipTypeID 64 showPersonalFittings = hull_filter_settings.fittings_show_personal.is_enabled() 65 showCorpFittings = hull_filter_settings.fittings_show_corp.is_enabled() 66 showAllianceFittings = bool(session.allianceid) and hull_filter_settings.fittings_show_alliance.is_enabled() 67 onlyShowCurrentShip = hull_filter_settings.fittings_show_only_for_current_ship.is_enabled() 68 onlyWithSkillsFor = hull_filter_settings.fittings_show_only_if_have_skills.is_enabled() 69 showCommunityFittings = communityFittingEnabled and hull_filter_settings.fittings_show_community.is_enabled() 70 ownerFilterIsSet = showPersonalFittings or showCorpFittings or showAllianceFittings or showCommunityFittings 71 if not ownerFilterIsSet: 72 showCorpFittings = True 73 showPersonalFittings = True 74 showAllianceFittings = True 75 if communityFittingEnabled: 76 showCommunityFittings = True 77 personalFittings, corpFittings, communityFittings, allianceFittings = self.fittingSvc.GetAllFittingsForCharacter() 78 if hull_filter_settings.tab_selected_setting.get() != BROWSE_FITTINGS: 79 return 80 fittingNumByTypeID = self.GetNumShipsByTypeID(personalFittings, corpFittings, communityFittings, allianceFittings) 81 filterText = hull_filter_settings.text_filter.get().lower() 82 filteringSettings = KeyVal(filterTextLower=filterText, personalFittings=personalFittings, corpFittings=corpFittings, allianceFittings=allianceFittings, communityFittings=communityFittings, showPersonalFittings=showPersonalFittings, showCorpFittings=showCorpFittings, showCommunityFittings=showCommunityFittings, showAllianceFittings=showAllianceFittings, onlyShowCurrentShip=onlyShowCurrentShip, onlyWithSkillsFor=onlyWithSkillsFor, ownerFilterIsSet=ownerFilterIsSet) 83 fittings = self.FilterOutFittings(filteringSettings) 84 self.PopulatedSpecialEditionShips() 85 fittingsByGroupID, shipsByGroupID, shipGroups, shipsByGroupAndRaceIDs, fittingsByGroupAndRaceIDs, unsupportedFittings = self.GetShipsAndGroups(filteringSettings, fittings) 86 scrolllist = [] 87 noFittingsFound = len(fittings) == 0 and ownerFilterIsSet 88 if noFittingsFound: 89 scrolllist.append(GetFromClass(Generic, {'label': GetByLabel('UI/Common/NothingFound')})) 90 else: 91 92 def GetScrollListForShipGroups(groupsToGet, sublevel = 0, groupPrefix = ''): 93 listOfGroups = [] 94 for groupName, groupID in groupsToGet: 95 shipsForGroup = shipsByGroupAndRaceIDs[groupID] 96 isGroupForCurrentShip = any((self.currentShipTypeID in x for x in shipsForGroup.itervalues())) 97 fittingsByRaceID = fittingsByGroupAndRaceIDs[groupID] 98 groupNameForID = '%s%s' % (groupPrefix, groupName) 99 type_ids = list(itertools.chain(*[ type_ids for type_ids in itertools.chain(shipsForGroup.values()) ])) 100 data = {'GetSubContent': self.GetRacesForGroup, 101 'label': groupName, 102 'groupItems': shipsForGroup, 103 'fittingsByRaceID': fittingsByRaceID, 104 'shipsByRaceID': shipsForGroup, 105 'id': (self.browserID, groupNameForID), 106 'showlen': 0, 107 'sublevel': sublevel, 108 'fittingNumByTypeID': fittingNumByTypeID, 109 'showCommunityFits': communityFittingEnabled, 110 'isGroupForCurrentShip': isGroupForCurrentShip, 111 'typeIDs': type_ids} 112 data.update(self.GetCommonGroupData()) 113 groupEntry = (groupName, GetFromClass(ShipParentGroup, data)) 114 listOfGroups.append(groupEntry) 115 116 listOfGroups = SortListOfTuples(listOfGroups) 117 return listOfGroups 118 119 normalShips = {(groupName, groupID) for groupName, groupID in shipGroups if groupID > 0} 120 shipScrollList = GetScrollListForShipGroups(normalShips) 121 specialShips = {(groupName, groupID) for groupName, groupID in shipGroups if groupID < 0} 122 if specialShips: 123 124 def GetSpecialShipGroup(nodedata): 125 return GetScrollListForShipGroups(nodedata.groupItems, sublevel=1, groupPrefix='special') 126 127 data = {'GetSubContent': GetSpecialShipGroup, 128 'groupItems': specialShips, 129 'label': GetByLabel('UI/Fitting/FittingWindow/SpecialEditionShips'), 130 'id': (self.browserID, 'specialShips'), 131 'showlen': 0, 132 'isGroupForCurrentShip': self.currentShipTypeID in self.specialTypeIDs, 133 'typeIds': ()} 134 data.update(self.GetCommonGroupData()) 135 groupEntry = GetFromClass(ShipParentGroup, data) 136 shipScrollList.append(groupEntry) 137 if ownerFilterIsSet and unsupportedFittings: 138 shipScrollList += self.AddUnsupportedGroup(unsupportedFittings) 139 if shipScrollList: 140 scrolllist.extend(shipScrollList) 141 else: 142 scrolllist.append(GetFromClass(Generic, {'label': GetByLabel('UI/Common/NothingFound')})) 143 return scrolllist 144 145 def AddUnsupportedGroup(self, unsupportedFittings): 146 data = {'GetSubContent': self.GetScrollListForUnsupportedFittings, 147 'groupItems': unsupportedFittings, 148 'label': GetByLabel('UI/Fitting/FittingWindow/UnsupportedShip'), 149 'id': (self.browserID, 'unsupportedFittings'), 150 'showlen': 0} 151 data.update(self.GetCommonGroupData()) 152 groupEntry = GetFromClass(ListGroup, data) 153 return [groupEntry] 154 155 def GetScrollListForUnsupportedFittings(self, nodedata): 156 fittings = nodedata.groupItems 157 scrollList = [] 158 for eachFitting in fittings: 159 shipTypeExists = evetypes.Exists(eachFitting.shipTypeID) 160 if shipTypeExists and session.role & ROLEMASK_ELEVATEDPLAYER: 161 scrollList += self.GetFittingEntriesForType([eachFitting], sublevel=0) 162 continue 163 fittingName = eachFitting.name 164 if shipTypeExists: 165 shipTypeName = evetypes.GetName(eachFitting.shipTypeID) 166 else: 167 shipTypeName = GetByLabel('UI/Fitting/FittingWindow/UnknownShipType') 168 fittingName = '%s (%s) - %s' % (fittingName, shipTypeName, 'unsupported') 169 scrollList.append(GetFromClass(Generic, {'label': fittingName, 170 'GetMenu': self.GetFittingMenuForUnsupportedFittings, 171 'sublevel': 1, 172 'ownerID': eachFitting.ownerID, 173 'fittingID': eachFitting.fittingID})) 174 175 return scrollList 176 177 def GetFittingMenuForUnsupportedFittings(self, entry): 178 node = entry.sr.node 179 node.scroll.SelectNode(node) 180 selectedNodes = node.scroll.GetSelectedNodes(node) 181 if CanDeleteFit(node.ownerID): 182 m = [(MenuLabel('UI/Fitting/FittingWindow/FittingManagement/DeleteFitting'), self.DeleteFitting, [entry, selectedNodes])] 183 return m 184 185 def GetCommonGroupData(self, showIcon = 'hide'): 186 return {'state': 'locked', 187 'BlockOpenWindow': 1, 188 'showicon': showIcon, 189 'DropData': self.onDropDataFunc} 190 191 def GetNumShipsByTypeID(self, personalFittings, corpFittings, communityFittings, allianceFittings): 192 fittingNumByTypeID = defaultdict(lambda : defaultdict(int)) 193 for owner, fittingDict in [(FITTING_OWNER_PERSONAL, personalFittings), 194 (FITTING_OWNER_CORP, corpFittings), 195 (FITTING_OWNER_COMMUNITY, communityFittings), 196 (FITTING_OWNER_ALLIANCE, allianceFittings)]: 197 for fitting in fittingDict.itervalues(): 198 fittingNumByTypeID[fitting.shipTypeID][owner] += 1 199 200 return fittingNumByTypeID 201 202 def GetRacesForGroup(self, nodedata): 203 shipScrollist = [] 204 fittingsByRaceID = nodedata.fittingsByRaceID 205 shipsByRaceID = nodedata.shipsByRaceID 206 sublevel = nodedata.sublevel + 1 207 parentGroupNameForID = nodedata.id[1] 208 for raceID, fittingsForRace in nodedata.groupItems.iteritems(): 209 raceIconID, raceName = self.GetNameAndIconIDForRace(raceID) 210 groupNameForID = '%s_%s' % (parentGroupNameForID, raceID) 211 isGroupForCurrentShip = self.currentShipTypeID in fittingsForRace 212 data = {'GetSubContent': self.GetShipGroupSubContent, 213 'label': raceName, 214 'fittings': fittingsByRaceID[raceID], 215 'groupItems': fittingsForRace, 216 'allShips': shipsByRaceID[raceID], 217 'id': (self.browserID, groupNameForID), 218 'iconID': raceIconID, 219 'sublevel': sublevel, 220 'fittingNumByTypeID': nodedata.fittingNumByTypeID, 221 'showCommunityFits': nodedata.showCommunityFits, 222 'isGroupForCurrentShip': isGroupForCurrentShip, 223 'typeIDs': shipsByRaceID[raceID]} 224 data.update(self.GetCommonGroupData()) 225 groupEntry = ((raceIconID == NON_EMPIRE, raceName), GetFromClass(ShipParentGroup, data)) 226 shipScrollist.append(groupEntry) 227 228 shipScrollist = SortListOfTuples(shipScrollist) 229 return shipScrollist 230 231 def GetNameAndIconIDForRace(self, raceID): 232 if raceID == NON_EMPIRE: 233 raceName = GetByLabel('UI/Fitting/FittingWindow/NonEmpireFaction') 234 raceIconID = 1443 235 else: 236 race = get_race(raceID) 237 raceName = get_race_name(raceID, race) 238 raceIconID = race.iconID 239 return (raceIconID, raceName) 240 241 def GetMaxFittingNumber(self, ownerID): 242 maxFittings = None 243 if ownerID == session.charid: 244 maxFittings = appConst.maxCharFittings 245 elif ownerID == session.corpid: 246 maxFittings = appConst.maxCorpFittings 247 return maxFittings 248 249 def FilterOutFittings(self, filteringSettings): 250 fittings = {} 251 if filteringSettings.showPersonalFittings: 252 fittings.update(filteringSettings.personalFittings) 253 if filteringSettings.showCorpFittings: 254 fittings.update(filteringSettings.corpFittings) 255 if filteringSettings.showCommunityFittings: 256 fittings.update(filteringSettings.communityFittings) 257 if filteringSettings.showAllianceFittings: 258 fittings.update(filteringSettings.allianceFittings) 259 if filteringSettings.onlyWithSkillsFor: 260 withSkillsFor = {} 261 for eachFittingID, eachFitting in fittings.iteritems(): 262 if self.fittingSvc.HasSkillForFit(eachFitting): 263 withSkillsFor[eachFittingID] = eachFitting 264 265 fittings = withSkillsFor 266 if not filteringSettings.filterTextLower and not filteringSettings.onlyShowCurrentShip: 267 return fittings 268 validFittings = {} 269 for fittingID, fitting in fittings.iteritems(): 270 if filteringSettings.onlyShowCurrentShip and self.currentShipTypeID and fitting.shipTypeID != self.currentShipTypeID: 271 continue 272 if self.TextMatched(filteringSettings.filterTextLower, fitting): 273 validFittings[fittingID] = fitting 274 275 return validFittings 276 277 def TextMatched(self, filterTextLower, fitting): 278 if not filterTextLower: 279 return True 280 if self.MatchedWithFittingName(filterTextLower, fitting): 281 return True 282 if self.MatchedWithShipOrGroupName(filterTextLower, fitting.shipTypeID): 283 return True 284 return False 285 286 def MatchedWithShipOrGroupName(self, filterTextLower, shipTypeID): 287 try: 288 shipTypeName = evetypes.GetName(shipTypeID) 289 except evetypes.TypeNotFoundException: 290 return False 291 292 matchedWithShipName = shipTypeName.lower().find(filterTextLower) >= 0 293 if matchedWithShipName: 294 return True 295 try: 296 shipGroupName = evetypes.GetGroupName(shipTypeID) 297 except evetypes.TypeNotFoundException: 298 return False 299 300 return shipGroupName.lower().find(filterTextLower) >= 0 301 302 def MatchedWithFittingName(self, filterTextLower, fitting): 303 foundTextInFittingName = fitting.name.lower().find(filterTextLower) >= 0 304 return foundTextInFittingName 305 306 def GetShipsAndGroups(self, filteringSettings, fittings): 307 fittingsByGroupID = defaultdict(list) 308 fittingsByGroupAndRaceIDs = defaultdict(lambda : defaultdict(set)) 309 if not filteringSettings.ownerFilterIsSet: 310 shipGroups, shipsByGroupID, shipsByGroupAndRaceIDs = self.GetAllShipGroupsAndShipsByGroupID(filteringSettings) 311 else: 312 shipGroups = set() 313 shipsByGroupID = defaultdict(set) 314 shipsByGroupAndRaceIDs = defaultdict(lambda : defaultdict(set)) 315 unsupportedFittings = [] 316 for fittingID, fitting in fittings.iteritems(): 317 shipTypeID = fitting.shipTypeID 318 if not evetypes.Exists(shipTypeID): 319 log.LogError('Ship in stored fittings does not exist, shipID=%s, fittingID=%s' % (shipTypeID, fittingID)) 320 unsupportedFittings.append(fitting) 321 continue 322 if not evetypes.IsPublished(shipTypeID): 323 unsupportedFittings.append(fitting) 324 continue 325 groupID = evetypes.GetGroupID(shipTypeID) 326 if shipTypeID in self.specialTypeIDs: 327 groupID = -groupID 328 fittingsByGroupID[groupID].append(fitting) 329 groupName = evetypes.GetGroupName(shipTypeID) 330 shipGroups.add((groupName, groupID)) 331 raceID = self._GetShipRaceID(shipTypeID) 332 shipsByGroupAndRaceIDs[groupID][raceID].add(shipTypeID) 333 fittingsByGroupAndRaceIDs[groupID][raceID].add(fitting) 334 335 return (fittingsByGroupID, 336 shipsByGroupID, 337 shipGroups, 338 shipsByGroupAndRaceIDs, 339 fittingsByGroupAndRaceIDs, 340 unsupportedFittings) 341 342 def _GetShipRaceID(self, shipTypeID): 343 factionID = evetypes.GetFactionID(shipTypeID) 344 raceID = appConst.raceByFaction.get(factionID, NON_EMPIRE) 345 return raceID 346 347 def GetAllShipGroupsAndShipsByGroupID(self, filteringSettings): 348 shipGroups = set() 349 shipsByGroupID = defaultdict(set) 350 shipsByGroupAndRaceIDs = defaultdict(lambda : defaultdict(set)) 351 grouplist = self._GetGroupList() 352 shipTypesIDsFromMarket = {i for i in itertools.chain.from_iterable([ x.types for x in grouplist ])} 353 godma = sm.GetService('godma') 354 for shipTypeID in shipTypesIDsFromMarket: 355 if filteringSettings.filterTextLower and not self.MatchedWithShipOrGroupName(filteringSettings.filterTextLower, shipTypeID): 356 continue 357 if filteringSettings.onlyShowCurrentShip and self.currentShipTypeID != shipTypeID: 358 continue 359 if filteringSettings.onlyWithSkillsFor and not godma.CheckSkillRequirementsForType(shipTypeID): 360 continue 361 groupID = evetypes.GetGroupID(shipTypeID) 362 if shipTypeID in self.specialTypeIDs: 363 groupID = -groupID 364 groupName = evetypes.GetGroupName(shipTypeID) 365 shipGroups.add((groupName, groupID)) 366 shipsByGroupID[groupID].add(shipTypeID) 367 raceID = self._GetShipRaceID(shipTypeID) 368 shipsByGroupAndRaceIDs[groupID][raceID].add(shipTypeID) 369 370 return (shipGroups, shipsByGroupID, shipsByGroupAndRaceIDs) 371 372 def _GetGroupList(self): 373 marketGroups = sm.GetService('marketutils').GetMarketGroups() 374 grouplist = marketGroups[appConst.marketCategoryShips][:] 375 return grouplist 376 377 def _GetStructureGroups(self, marketGroups): 378 structureGroups = [] 379 groupsToFind = [MARKET_GROUP_ENGINEERING_COMPLEX, 380 MARKET_GROUP_CITADEL, 381 MARKET_GROUP_REFINERY, 382 MARKET_GROUP_NAVIGATION_STRUCTURES] 383 for m in marketGroups[appConst.marketCategoryStarBaseStructures]: 384 if m.marketGroupID in groupsToFind: 385 structureGroups.append(m) 386 387 return structureGroups 388 389 def GetShipGroupSubContent(self, nodedata, *args): 390 scrolllist = [] 391 fittingsByType = defaultdict(list) 392 fittingNumByTypeID = nodedata.fittingNumByTypeID 393 for fitting in nodedata.fittings: 394 shipTypeID = fitting.shipTypeID 395 if not evetypes.Exists(shipTypeID): 396 log.LogError('Ship in stored fittings does not exist, shipID=%s, fittingID=%s' % (shipTypeID, fitting.fittingID)) 397 continue 398 fittingsByType[shipTypeID].append(fitting) 399 400 showCommunityFits = nodedata.showCommunityFits 401 allShips = nodedata.allShips 402 sublevel = nodedata.sublevel + 1 403 for typeID in allShips: 404 typeName = evetypes.GetName(typeID) 405 numFittingForType = fittingNumByTypeID[typeID] 406 fittingsForType = fittingsByType.get(typeID, []) 407 entry = self.GetShipTypeGroup(typeID, typeName, fittingsForType, numFittingForType, sublevel, showCommunityFits) 408 metaGroupID = evetypes.GetMetaGroupID(typeID) 409 scrolllist.append(((metaGroupID, typeName), entry)) 410 411 scrolllist = SortListOfTuples(scrolllist) 412 return scrolllist 413 414 def GetShipTypeGroup(self, typeID, typeName, fittingsForType, numFittingForType, sublevel, showCommunityFits = False): 415 numPersonal = numFittingForType[FITTING_OWNER_PERSONAL] 416 numCorp = numFittingForType[FITTING_OWNER_CORP] 417 numCommunity = numFittingForType[FITTING_OWNER_COMMUNITY] 418 numAlliance = numFittingForType[FITTING_OWNER_ALLIANCE] 419 label = '<b>%s</b>' % typeName 420 subContentFunc = self.GetFittingSubContent if self.show_fitted_ships else None 421 data = {'label': label, 422 'typeID': typeID, 423 'getIcon': True, 424 'sublevel': sublevel, 425 'maxLines': 2, 426 'GetSubContent': subContentFunc, 427 'hideExpander': not self.show_fitted_ships, 428 'id': ('FittingShipTypeListGroup', typeID), 429 'showlen': 0, 430 'typeName': typeName, 431 'fittings': fittingsForType, 432 'numPersonal': numPersonal, 433 'numCorp': numCorp, 434 'numCommunity': numCommunity, 435 'numAlliance': numAlliance, 436 'showCommunityFits': showCommunityFits, 437 'isCurrentShipType': typeID == self.currentShipTypeID} 438 data.update(self.GetCommonGroupData('')) 439 return GetFromClass(self.GetHullListEntryClass(), data) 440 441 def GetHullListEntryClass(self): 442 return HullTypeListGroup 443 444 def GetFittingSubContent(self, nodedata, *args): 445 return self.GetFittingEntriesForType(nodedata.fittings) 446 447 def GetFittingEntriesForType(self, fittings, sublevel = 3, *args): 448 scrolllist = [] 449 for eachFitting in fittings: 450 fittingName = eachFitting.name 451 if eachFitting.ownerID == session.corpid: 452 fittingOwnerType = FITTING_OWNER_CORP 453 elif eachFitting.ownerID == appConst.COMMUNITY_FITTING_CORP: 454 fittingOwnerType = FITTING_OWNER_COMMUNITY 455 elif eachFitting.ownerID == session.allianceid: 456 fittingOwnerType = FITTING_OWNER_ALLIANCE 457 else: 458 fittingOwnerType = FITTING_OWNER_PERSONAL 459 sortBy = (fittingOwnerType, fittingName.lower()) 460 entry = GetFromClass(FittingEntry, {'label': fittingName, 461 'fittingID': eachFitting.fittingID, 462 'fitting': eachFitting, 463 'ownerID': eachFitting.ownerID, 464 'showinfo': 1, 465 'showicon': 'hide', 466 'sublevel': sublevel, 467 'ignoreRightClick': 1, 468 'OnClick': self.OnFittingClicked, 469 'OnDropData': self.onDropDataFunc, 470 'GetMenu': self.GetFittingMenu, 471 'ownerType': fittingOwnerType}) 472 scrolllist.append((sortBy, entry)) 473 474 scrolllist = SortListOfTuples(scrolllist) 475 return scrolllist 476 477 def OnFittingClicked(self, entry, *args): 478 if uicore.uilib.Key(uiconst.VK_SHIFT) or uicore.uilib.Key(uiconst.VK_CONTROL): 479 return 480 fitting = entry.sr.node.fitting 481 typesInUse = {x[0] for x in fitting.fitData} 482 obsoleteSubSystems = {x for x in typesInUse if evetypes.GetGroupID(x) == appConst.groupElectronicSubSystems} 483 if obsoleteSubSystems: 484 self.fittingSvc.DisplayFitting(fitting) 485 else: 486 self.ghostFittingSvc.SimulateFitting(fitting) 487 488 def GetFittingMenu(self, entry): 489 node = entry.sr.node 490 selectedNodes = node.scroll.GetSelectedNodes(node) 491 multiSelected = len(selectedNodes) > 1 492 fittingID = entry.sr.node.fittingID 493 ownerID = entry.sr.node.ownerID 494 maxShipsAllowed = GetMaxShipsToFit(sm.GetService('machoNet')) 495 m = [] 496 if not multiSelected: 497 m += [(GetByLabel('UI/Fitting/FittingWindow/ViewFitting'), self.ViewFitting, [node])] 498 m += [(GetByLabel('UI/Fitting/FittingWindow/SimulateFitting'), self.OnFittingClicked, [entry])] 499 if not IsControllingStructure() and evetypes.GetCategoryID(node.fitting.shipTypeID) != appConst.categoryStructure: 500 m += [(MenuLabel('UI/Fitting/FittingWindow/FitFittingToActiveShip'), self.FitToActiveShip, [ownerID, fittingID])] 501 m += [(MenuLabel('UI/Market/MarketQuote/BuyAll'), self.BuyItemsForFit, [node.fitting])] 502 if maxShipsAllowed and IsDocked(): 503 m += [(MenuLabel('UI/Fitting/FittingWindow/FittingManagement/OpenMultifit'), self.DoBulkFit, [entry])] 504 if session.role & ROLE_WORLDMOD: 505 fittingSpawner = sm.GetService('fittingspawner') 506 m.append(None) 507 m.append(('DEV Hax This Together!', fittingSpawner.SpawnFitting, [ownerID, node.fitting])) 508 m.append(('DEV: fittingID=%s' % fittingID, blue.pyos.SetClipboardData, (str(fittingID),))) 509 m += [None] 510 deletable = GetDeletableNodes(selectedNodes) 511 if deletable: 512 m += [(MenuLabel('UI/Fitting/FittingWindow/FittingManagement/DeleteFitting'), self.DeleteFitting, [entry, deletable])] 513 return m 514 515 def DeleteFitting(self, entry, selectedNodes): 516 DeleteFittings(selectedNodes) 517 518 def DoBulkFit(self, entry): 519 fitting = entry.sr.node.fitting 520 OpenOrLoadMultiFitWnd(fitting) 521 522 def ViewFitting(self, node): 523 fitting = node.fitting 524 self.fittingSvc.DisplayFitting(fitting) 525 526 def PopulatedSpecialEditionShips(self): 527 if self.specialTypeIDs is None: 528 specialCategory = sm.GetService('marketutils').GetMarketGroup(MARKET_GROUP_SPECIAL_SHIPS) 529 typeIDs = set() 530 for eachGroup in specialCategory: 531 typeIDs.update(eachGroup.types) 532 533 self.specialTypeIDs = typeIDs 534 535 def FitToActiveShip(self, ownerID, fittingID): 536 self.fittingSvc.LoadFittingFromFittingIDAndGetBuyOptionOnFailure(ownerID, fittingID) 537 538 def BuyItemsForFit(self, fitting): 539 shipTypeID = fitting.shipTypeID 540 fitData = fitting.fitData 541 from shipfitting.multiBuyUtil import BuyFit 542 BuyFit(shipTypeID, fitData) 543 544 545 class ShipParentGroup(Group): 546 isDragObject = True 547 548 def Load(self, node): 549 Group.Load(self, node) 550 containesMyShip = node.isGroupForCurrentShip 551 if containesMyShip: 552 self.sr.expander.icon.ignoreColorBlindMode = False 553 self.sr.expander.SetRGBA(0.0, 0.5, 0.0, 0.8) 554 555 def GetDragData(self): 556 return [ TypeDragData(type_id) for type_id in self.sr.node.typeIDs ] 557 558 def GetMenu(self): 559 menuData = MenuData() 560 menuData.AddEntry(MenuLabel('UI/Compare/CompareButton'), lambda : GetMenuService().CompareTypes(self.sr.node.typeIDs)) 561 menuData.AddSeparator() 562 return menuData + super(ShipParentGroup, self).GetMenu() 563 564 565 class FittingHullBrowserListProvider(HullBrowserListProvider): 566 567 def GetHullListEntryClass(self): 568 return FittingHullTypeListGroup 569 570 def _GetGroupList(self): 571 groupList = super(FittingHullBrowserListProvider, self)._GetGroupList() 572 marketGroups = sm.GetService('marketutils').GetMarketGroups() 573 groupList.extend(self._GetStructureGroups(marketGroups)) 574 return groupList 575 576 577 class ComparisonHullBrowserListProvider(HullBrowserListProvider): 578 show_fitted_ships = False 579 580 581 class HullTypeListGroup(Group): 582 iconSize = 32 583 default_iconSize = iconSize 584 isDragObject = True 585 586 def Startup(self, *etc): 587 Group.Startup(self, etc) 588 self.sr.myShipSelection = Fill(name='myShipSelection', bgParent=self, padding=(0, 1, 0, 1), color=(0.0, 0.5, 0.0, 0.1)) 589 self.sr.myShipSelection.display = False 590 self.sr.label.maxLines = 2 591 self.sr.label.align = uiconst.TOPLEFT 592 self.sr.label.top = 2 593 self.techIcon = Sprite(name='techIcon', parent=self, left=1, width=16, height=16, idx=0) 594 self.ConstructFittingIcons() 595 self.ConstructRightIcons() 596 597 def ConstructRightIcons(self): 598 pass 599 600 def ConstructFittingIcons(self): 601 self.fittingIconCont = Container(name='fittingIconCont', parent=self, align=uiconst.TOBOTTOM_NOPUSH, height=12, state=uiconst.UI_PICKCHILDREN, padBottom=2) 602 self.personalCont = Container(name='personalCont', parent=self.fittingIconCont, align=uiconst.TOLEFT, width=40) 603 personalSprite = Sprite(parent=self.personalCont, align=uiconst.CENTERLEFT, pos=(0, 0, 12, 12), texturePath='res:/UI/Texture/WindowIcons/member.png', state=uiconst.UI_NORMAL) 604 self.personalLabel = EveLabelMedium(parent=self.personalCont, text='0', align=uiconst.CENTERLEFT, left=personalSprite.width + 2, state=uiconst.UI_NORMAL) 605 personalSprite.hint = self.personalLabel.hint = GetByLabel('UI/Fitting/FittingWindow/SavedPersonalFittings') 606 self.corpCont = Container(name='corpCont', parent=self.fittingIconCont, align=uiconst.TOLEFT, width=40) 607 corpSprite = Sprite(parent=self.corpCont, align=uiconst.CENTERLEFT, pos=(0, 0, 9, 9), texturePath='res:/UI/Texture/classes/FlagIcon/2.png', state=uiconst.UI_NORMAL) 608 self.corpLabel = EveLabelMedium(parent=self.corpCont, text='0', align=uiconst.CENTERLEFT, left=corpSprite.width + 2, state=uiconst.UI_NORMAL) 609 corpSprite.hint = self.corpLabel.hint = GetByLabel('UI/Fitting/FittingWindow/SavedCorpFittings') 610 self.communityCont = Container(name='communityCont', parent=self.fittingIconCont, align=uiconst.TOLEFT, width=40) 611 communitySprite = Sprite(parent=self.communityCont, align=uiconst.CENTERLEFT, pos=(0, 0, 12, 12), texturePath='res:/UI/Texture/classes/Fitting/iconCommunityFitsSmall.png', state=uiconst.UI_NORMAL) 612 self.communityLabel = EveLabelMedium(parent=self.communityCont, text='0', align=uiconst.CENTERLEFT, left=communitySprite.width + 2, state=uiconst.UI_NORMAL) 613 communitySprite.hint = self.communityLabel.hint = GetByLabel('UI/Fitting/FittingWindow/SavedCommunityFittings') 614 self.allianceCont = Container(name='allianceCont', parent=self.fittingIconCont, align=uiconst.TOLEFT, width=40) 615 allianceSprite = Sprite(parent=self.allianceCont, align=uiconst.CENTERLEFT, pos=(0, 0, 12, 12), texturePath='res:/UI/Texture/classes/Fitting/iconAllianceSmall.png', state=uiconst.UI_NORMAL) 616 self.allianceLabel = EveLabelMedium(parent=self.allianceCont, text='0', align=uiconst.CENTERLEFT, left=allianceSprite.width + 2, state=uiconst.UI_NORMAL) 617 allianceSprite.hint = self.allianceLabel.hint = GetByLabel('UI/Fitting/FittingWindow/SavedAllianceFittings') 618 619 def Load(self, node): 620 Group.Load(self, node) 621 typeID = node.typeID 622 self.sr.icon.LoadIconByTypeID(typeID=typeID, size=self.iconSize, ignoreSize=True, isCopy=False) 623 self.sr.icon.SetSize(self.iconSize, self.iconSize) 624 techSprite = uix.GetTechLevelIcon(self.techIcon, 1, typeID) 625 self.techIcon.left = self.sr.icon.left 626 labelLeft = self.sr.icon.left + self.sr.icon.width + 4 627 self.sr.label.left = labelLeft 628 self.fittingIconCont.padLeft = labelLeft 629 numPersonal = node.numPersonal 630 if numPersonal: 631 self.personalLabel.text = numPersonal 632 self.personalCont.display = bool(numPersonal) 633 numCorp = node.numCorp 634 if numCorp: 635 self.corpLabel.text = numCorp 636 self.corpCont.display = bool(numCorp) 637 numCommunity = node.numCommunity 638 if numCommunity: 639 self.communityLabel.text = numCommunity 640 self.communityCont.display = bool(numCommunity) and bool(node.showCommunityFits) 641 numAlliance = node.numAlliance 642 if numAlliance: 643 self.allianceLabel.text = numAlliance 644 self.allianceCont.display = bool(numCorp) 645 self.sr.myShipSelection.display = node.isCurrentShipType 646 647 def GetHeight(self, *args): 648 node, _ = args 649 textwidth, textheight = EveLabelMedium.MeasureTextSize(node.label, maxLines=2) 650 node.height = max(textheight + 6, HEIGHT_NORMAL) 651 return node.height 652 653 def GetMenu(self): 654 typeID = self.sr.node.typeID 655 return GetMenuService().GetMenuFromItemIDTypeID(None, typeID, includeMarketDetails=True) 656 657 def GetDragData(self): 658 typeID = self.sr.node.typeID 659 keyVal = KeyVal(__guid__='listentry.GenericMarketItem', typeID=typeID, label=evetypes.GetName(typeID)) 660 return [keyVal] 661 662 def LoadTooltipPanel(self, tooltipPanel, *args): 663 node = self.sr.node 664 typeID = node.typeID 665 tooltipPanel.LoadGeneric1ColumnTemplate() 666 tooltipPanel.AddLabelLarge(text='<b>%s</b>' % evetypes.GetName(typeID)) 667 numFittingOwners = bool(node.numPersonal) + bool(node.numCorp) + bool(node.numCommunity) + bool(node.numAlliance) 668 useShortText = numFittingOwners >= 2 669 if useShortText: 670 tooltipPanel.AddLabelMedium(text='<b>%s</b>' % GetByLabel('UI/Fitting/FittingWindow/SavedFittings')) 671 numAndPaths = [(node.numPersonal, 'UI/Fitting/FittingWindow/PersonalFittingsNum', 'UI/Fitting/FittingWindow/PersonalFittingsNumShort'), (node.numCorp, 'UI/Fitting/FittingWindow/CorpFittingsNum', 'UI/Fitting/FittingWindow/CorpFittingsNumShort')] 672 if node.showCommunityFits: 673 numAndPaths += [(node.numCommunity, 'UI/Fitting/FittingWindow/CommunityFittingsNum', 'UI/Fitting/FittingWindow/CommunityFittingsNumShort')] 674 if session.allianceid: 675 numAndPaths += [(node.numAlliance, 'UI/Fitting/FittingWindow/AllianceFittingsNum', 'UI/Fitting/FittingWindow/AllianceFittingsNumShort')] 676 for numFittings, longPath, shortPath in numAndPaths: 677 if not numFittings: 678 continue 679 labelPath = shortPath if useShortText else longPath 680 text = GetByLabel(labelPath, numFittings=numFittings) 681 tooltipPanel.AddLabelMedium(text=text) 682 683 if not numFittingOwners: 684 tooltipPanel.AddLabelMedium(text=GetByLabel('UI/Fitting/FittingWindow/NoFittingsSaved')) 685 if HasTraits(typeID): 686 tooltipPanel.AddSpacer(width=300, height=1) 687 TraitsContainer(parent=tooltipPanel, typeID=typeID, padding=7) 688 689 690 class FittingHullTypeListGroup(HullTypeListGroup): 691 692 def ConstructRightIcons(self): 693 iconSize = 24 694 switchCont = Container(name='switchCont', parent=self, align=uiconst.TORIGHT, width=iconSize, padRight=4) 695 simulateBtn = ShipFittingSimulationButton(parent=switchCont, align=uiconst.CENTERLEFT, pos=(0, 696 0, 697 iconSize, 698 iconSize), func=self.SimulateShip, iconSize=iconSize) 699 simulateBtn.hint = GetByLabel('UI/Fitting/FittingWindow/SimulateShip') 700 701 def SimulateShip(self): 702 ghostFittingSvc = sm.GetService('ghostFittingSvc') 703 shipTypeID = self.sr.node.typeID 704 ghostFittingSvc.SimulateFitting(KeyVal(shipTypeID=shipTypeID, fitData=[]))