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

quote.py (29439B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\market\quote.py
      2 import sys
      3 import blue
      4 import carbonui.const as uiconst
      5 import evetypes
      6 import localization
      7 import locks
      8 import structures
      9 import utillib
     10 from carbon.common.lib.const import DAY, MIN
     11 from carbon.common.script.sys.row import Row
     12 from carbon.common.script.sys.service import Service
     13 from carbon.common.script.sys.serviceConst import ROLE_GMH
     14 from carbon.common.script.util.commonutils import StripTags
     15 from carbon.common.script.util.format import FmtAmt, FmtDate
     16 from carbonui.uicore import uicore
     17 from eve.client.script.ui.shared.market.util import does_global_market_apply
     18 from eve.client.script.ui.shared.market.buyThisTypeWindow import MarketActionWindow
     19 from eve.client.script.ui.shared.market.marketbase import RegionalMarket
     20 from eve.client.script.ui.shared.market.util import should_show_location_info, should_show_region, get_best_match_text
     21 from eve.client.script.ui.structure.structureBrowser.filterCont import locationToName
     22 from eve.client.script.ui.util import uix, utilWindows
     23 from eve.common.lib.appConst import locationTemp, locationSystem
     24 from eve.common.script.sys import idCheckers
     25 from eve.common.script.sys.idCheckers import IsStation
     26 from eve.common.script.util.eveFormat import FmtISK
     27 from eveexceptions import UserError
     28 from inventorycommon.const import containerGlobal, typePlex
     29 from inventoryrestrictions import can_view_market_details
     30 from marketgroups.data import get_market_group_ids, get_market_group_parent_id, MarketGroupObject
     31 from marketutil.const import rangeRegion, rangeStation, rangeSolarSystem
     32 from marketutil.feature_flags.client import is_global_plex_market_experiment_enabled
     33 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     34 
     35 class MarketUtils(Service):
     36     __guid__ = 'svc.marketutils'
     37     __servicename__ = 'Market Utils'
     38     __displayname__ = 'Market Utils'
     39     __dependencies__ = []
     40     __notifyevents__ = ['OnShowMarketDetails', 'ProcessUIRefresh']
     41 
     42     def __init__(self):
     43         super(MarketUtils, self).__init__()
     44         self.marketgroups = None
     45         self.allgroups = None
     46         self.regionUpAt = None
     47         self.marketTypeIDFinder = None
     48 
     49     def Run(self, memStream = None):
     50         self.Reset()
     51 
     52     def Reset(self):
     53         self.marketgroups = None
     54         self.allgroups = None
     55         self.regionUpAt = None
     56 
     57     def ProcessUIRefresh(self):
     58         self.Reset()
     59 
     60     def StartupCheck(self):
     61         now = blue.os.GetWallclockTime()
     62         if self.regionUpAt is not None:
     63             if self.regionUpAt.time < now - 2 * MIN:
     64                 return
     65             raise UserError(self.regionUpAt.msg, self.regionUpAt.dict)
     66         try:
     67             sm.ProxySvc('marketProxy').StartupCheck()
     68         except UserError as e:
     69             if session.role & ROLE_GMH == 0:
     70                 self.regionUpAt = Row(['time', 'msg', 'dict'], [now, e.msg, e.dict])
     71             sys.exc_clear()
     72             raise UserError(e.msg, e.dict)
     73 
     74     @staticmethod
     75     def GetMarketRange():
     76         if session.stationid or session.structureid:
     77             r = settings.user.ui.Get('marketRangeFilterStation', rangeRegion)
     78         else:
     79             r = settings.user.ui.Get('marketRangeFilterSpace', rangeRegion)
     80         return r
     81 
     82     @staticmethod
     83     def SetMarketRange(value):
     84         if session.stationid or session.structureid:
     85             r = settings.user.ui.Set('marketRangeFilterStation', value)
     86         else:
     87             r = settings.user.ui.Set('marketRangeFilterSpace', value)
     88         return r
     89 
     90     def BuyStationAsk(self, typeID):
     91         if session.stationid:
     92             asks = sm.GetService('marketQuote').GetStationAsks()
     93             for ask in asks.itervalues():
     94                 if ask.typeID == typeID:
     95                     self.Buy(typeID, ask)
     96                     return
     97 
     98     def FindMarketGroup(self, typeID, groupInfo = None, trace = None):
     99         groupInfo = groupInfo or self.GetMarketGroups()[None]
    100         trace = trace or ''
    101         for _groupInfo in groupInfo:
    102             if typeID in _groupInfo.types:
    103                 trace += _groupInfo.marketGroupName.strip() + ' / '
    104                 if not _groupInfo.hasTypes:
    105                     return self.FindMarketGroup(typeID, self.GetMarketGroups()[_groupInfo.marketGroupID], trace)
    106                 else:
    107                     return (_groupInfo, trace)
    108 
    109         return (None, trace)
    110 
    111     def ProcessRequest(self, subMethod, typeID = None, orderID = None):
    112         if subMethod == 'Buy':
    113             self.Buy(typeID, orderID)
    114         elif subMethod == 'ShowMarketDetails':
    115             self.ShowMarketDetails(typeID, orderID)
    116         else:
    117             raise RuntimeError('Unsupported subMethod call. Possible h4x0r attempt.')
    118 
    119     def MatchOrder(self, typeID, orderID):
    120         order = None
    121         if orderID:
    122             order = sm.GetService('marketQuote').GetOrder(orderID, typeID)
    123         self.Buy(typeID, order, placeOrder=order is None)
    124 
    125     @staticmethod
    126     def ShowMarketDetails(typeID, orderID = None, silently = False):
    127         marketWnd = RegionalMarket.GetIfOpen()
    128         if marketWnd and not marketWnd.destroyed:
    129             stack = marketWnd.GetStack()
    130             if not silently or stack and stack.GetActiveWindow() != marketWnd or marketWnd.IsMinimized():
    131                 marketWnd.Maximize()
    132         else:
    133             uicore.cmd.OpenMarket()
    134         marketWnd = RegionalMarket.GetIfOpen()
    135         if marketWnd:
    136             marketWnd.LoadTypeID_Ext(typeID)
    137 
    138     def AddMarketDetailsMenuOption(self, menuEntries, typeID):
    139         from carbonui.control.contextMenu.menuEntryData import MenuEntryData
    140         from menu import MenuLabel
    141         menuEntries.append(MenuEntryData(MenuLabel('UI/Inventory/ItemActions/ViewTypesMarketDetails'), lambda : self.ShowMarketDetails(typeID=typeID), internalName='ViewMarketDetails', typeID=typeID))
    142 
    143     def ShowMarketGroupWithTypes(self, marketGroupID):
    144         groupListData = self.GetMarketGroupByID(marketGroupID)
    145         if not groupListData.hasTypes:
    146             raise RuntimeError('Opening non-hasType market group. This can be too types for the market to handle')
    147         marketWnd = RegionalMarket.GetIfOpen()
    148         if marketWnd:
    149             marketWnd.LoadMarketGroup(marketGroupID)
    150         else:
    151             RegionalMarket.Open(marketGroupID=marketGroupID)
    152 
    153     def AddTypesToMarketGroups(self):
    154         typeIDsByMktGrp = {}
    155 
    156         def ExtractTypes(marketGroups, groupID):
    157             ids = {}
    158             if groupID not in marketGroups:
    159                 return {}
    160             for gr in marketGroups[groupID]:
    161                 explicits = {}
    162                 for typeID in evetypes.GetTypeIDsByMarketGroup(gr.marketGroupID):
    163                     blue.pyos.BeNice()
    164                     if evetypes.IsPublished(typeID):
    165                         explicits[typeID] = 1
    166 
    167                 subids = ExtractTypes(marketGroups, gr.marketGroupID)
    168                 subids.update(explicits)
    169                 gr.types = subids.keys()
    170                 typeIDsByMktGrp[gr.marketGroupID] = explicits.keys()
    171                 ids.update(subids)
    172 
    173             return ids
    174 
    175         try:
    176             ExtractTypes(self.marketgroups, None)
    177         finally:
    178             ExtractTypes = None
    179 
    180     def GetMarketGroups(self):
    181         with locks.TempLock('PrimeMarketGroups'):
    182             if self.marketgroups is None:
    183                 self.marketgroups = {}
    184                 self.marketGroupsByID = {}
    185                 for marketGroupID in get_market_group_ids():
    186                     parentID = get_market_group_parent_id(marketGroupID)
    187                     marketGroup = MarketGroupObject(marketGroupID)
    188                     if marketGroupID not in self.marketgroups:
    189                         self.marketgroups[marketGroupID] = []
    190                     if parentID not in self.marketgroups:
    191                         self.marketgroups[parentID] = [marketGroup]
    192                     else:
    193                         self.marketgroups[parentID].append(marketGroup)
    194                     self.marketGroupsByID[marketGroupID] = marketGroup
    195 
    196                 self.AddTypesToMarketGroups()
    197         return self.marketgroups
    198 
    199     def GetMarketTypes(self):
    200         t = []
    201         for each in self.GetMarketGroups()[None]:
    202             t += each.types
    203 
    204         return t
    205 
    206     def GetMarketTypeIDFinder(self):
    207         with locks.TempLock('GetMarketTypeIDFinder'):
    208             if self.marketTypeIDFinder is None:
    209                 typeIDs = self.GetMarketTypes()
    210                 from textImporting.textToTypeIDFinder import TextToTypeIDFinder
    211                 from textImporting import IsUsingDefaultLanguage
    212                 usingDefaultLanguage = IsUsingDefaultLanguage(session)
    213                 self.marketTypeIDFinder = TextToTypeIDFinder(typeIDs, usingDefaultLanguage)
    214         return self.marketTypeIDFinder
    215 
    216     def GetMarketGroup(self, findMarketGroupID):
    217         allGroups = self.GetMarketGroups()
    218         return allGroups.get(findMarketGroupID, None)
    219 
    220     def GetMarketGroupByID(self, marketGroupID):
    221         self.GetMarketGroups()
    222         return self.marketGroupsByID[marketGroupID]
    223 
    224     @staticmethod
    225     def AllowTrade(typeID, order = None, locationID = None):
    226         if does_global_market_apply(typeID):
    227             return True
    228         limits = sm.GetService('marketQuote').GetSkillLimits(None)
    229         bidLimit = limits['bid']
    230         if session.structureid or session.stationid:
    231             if locationID != session.solarsystemid2:
    232                 pass
    233             return True
    234         if bidLimit == rangeStation and order is None:
    235             raise UserError('CustomError', {'error': localization.GetByLabel('UI/Market/MarketQuote/OutOfRange')})
    236 
    237     def Buy(self, typeID, order = None, duration = 1, placeOrder = 0, prePickedLocationID = None, ignoreAdvanced = False, quantity = 1):
    238         locationID = None
    239         self.AllowTrade(typeID, order)
    240         if order is None:
    241             if prePickedLocationID:
    242                 locationID = prePickedLocationID
    243             elif session.stationid:
    244                 locationID = session.stationid
    245             elif session.structureid:
    246                 locationID = session.structureid
    247             elif does_global_market_apply(typeID):
    248                 locationID = sm.GetService('charactersheet').GetHomeStationRow().stationID
    249             else:
    250                 stationData = sm.GetService('marketutils').PickStation()
    251                 if stationData:
    252                     locationID = stationData
    253             if locationID is None:
    254                 return
    255         sm.GetService('marketutils').StartupCheck()
    256         if locationID is None and order.stationID is not None:
    257             locationID = order.stationID
    258         wnd = MarketActionWindow.Open()
    259         advancedBuyWnd = settings.char.ui.Get('advancedBuyWnd', 0)
    260         if uicore.uilib.Key(uiconst.VK_SHIFT) or placeOrder or advancedBuyWnd and not ignoreAdvanced:
    261             wnd.LoadBuy_Detailed(typeID, order, duration, locationID, forceRange=True, quantity=quantity)
    262         else:
    263             if locationID is not None:
    264                 sm.GetService('marketQuote').RefreshJumps(typeID, locationID)
    265             wnd.TradeSimple(typeID=typeID, order=order, locationID=locationID, ignoreAdvanced=ignoreAdvanced, quantity=quantity)
    266         uicore.registry.SetFocus(wnd)
    267 
    268     def ModifyOrder(self, order):
    269         if not self.HasAccessToMarketAtLocation(order.stationID):
    270             raise UserError(structures.GetAccessErrorLabel(structures.SETTING_MARKET_TAX), {'structureName': cfg.evelocations.Get(order.stationID).locationName})
    271         wnd = MarketActionWindow.Open(windowID='marketmodifyaction')
    272         wnd.LoadModify(order)
    273 
    274     @staticmethod
    275     def HasAccessToMarketAtLocation(dockableLocationID):
    276         if idCheckers.IsStation(dockableLocationID):
    277             return True
    278         return sm.GetService('structureSettings').CharacterHasService(dockableLocationID, structures.SERVICE_MARKET)
    279 
    280     @staticmethod
    281     def CancelOffer(order):
    282         if prompt_player_fsd_dialog('CancelMarketOrder', {}, uiconst.YESNO, suppress=uiconst.ID_YES) != uiconst.ID_YES:
    283             return
    284         sm.GetService('marketQuote').CancelOrder(order.orderID, order.regionID)
    285 
    286     @staticmethod
    287     def PickStation():
    288         if not session.solarsystemid2:
    289             return
    290         structureDirectory = sm.GetService('structureDirectory')
    291         markets = structureDirectory.GetMarketDockableLocationsInRegion()
    292         quote = sm.GetService('marketQuote')
    293         uiService = sm.GetService('ui')
    294         limits = quote.GetSkillLimits(None)
    295         bidDistance = limits['bid']
    296         marketsToList = []
    297         for marketID in markets:
    298             distance = quote.GetStationDistance(marketID)
    299             if distance <= bidDistance:
    300                 if IsStation(marketID):
    301                     stationInfo = cfg.stations.Get(marketID)
    302                     stationTypeID = stationInfo.stationTypeID
    303                     stationName = uiService.GetStationName(marketID)
    304                     solarsystemID = stationInfo.solarSystemID
    305                     position = (stationInfo.x, stationInfo.y, stationInfo.z)
    306                 else:
    307                     structureInfo = structureDirectory.GetStructureInfo(marketID)
    308                     stationTypeID = structureInfo.typeID
    309                     stationName = structureInfo.itemName
    310                     solarsystemID = structureInfo.solarSystemID
    311                     locationInfo = cfg.evelocations.Get(marketID)
    312                     position = (locationInfo.x, locationInfo.y, locationInfo.z)
    313                 marketsToList.append((utillib.KeyVal(stationID=marketID, stationName=stationName, stationTypeID=stationTypeID, solarSystemID=solarsystemID, x=position[0], y=position[1], z=position[2]), distance))
    314 
    315         if len(marketsToList) == 0:
    316             return
    317         for each, distance in marketsToList:
    318             itemID = each.stationID
    319             if itemID not in cfg.evelocations:
    320                 staData = [itemID,
    321                  each.stationName,
    322                  each.solarSystemID,
    323                  each.x,
    324                  each.y,
    325                  each.z,
    326                  None]
    327                 cfg.evelocations.Hint(itemID, staData)
    328 
    329         headers = [localization.GetByLabel('UI/Common/LocationTypes/Station'), localization.GetByLabel('UI/Market/Marketbase/Jumps')]
    330         stationLst = []
    331         for station, distance in marketsToList:
    332             data = utillib.KeyVal()
    333             data.label = '%s<t>%s' % (cfg.evelocations.Get(station.stationID).name, distance)
    334             data.listvalue = station.stationID
    335             data.showinfo = 1
    336             data.typeID = station.stationTypeID
    337             data.itemID = station.stationID
    338             data.Set('sort_' + headers[1], distance)
    339             stationLst.append(data)
    340 
    341         station = uix.ListWnd(stationLst, 'pickStation', localization.GetByLabel('UI/Search/SelectStation'), hint=localization.GetByLabel('UI/Market/MarketQuote/ChouseStation'), isModal=1, ordered=0, scrollHeaders=headers, minw=450)
    342         if station:
    343             return station
    344 
    345     def PickItem(self, typeID, quantity = None):
    346         stations = sm.GetService('invCache').GetInventory(containerGlobal).ListStations()
    347         primeloc = []
    348         for station in stations:
    349             primeloc.append(station.stationID)
    350 
    351         if len(primeloc):
    352             cfg.evelocations.Prime(primeloc)
    353         else:
    354             return None
    355         stationLst = [ (cfg.evelocations.Get(station.stationID).name + ' (' + str(station.itemCount) + ' items)', station.stationID) for station in stations ]
    356         station = uix.ListWnd(stationLst, 'generic', localization.GetByLabel('UI/Search/SelectStation'), hint=localization.GetByLabel('UI/Market/MarketQuote/SellFromStations'), isModal=1)
    357         if station:
    358             items = sm.GetService('invCache').GetInventory(containerGlobal).ListStationItems(station[1])
    359             badLocations = [locationTemp, locationSystem, session.charid]
    360             valid = []
    361             for each in items:
    362                 if each.typeID != typeID:
    363                     continue
    364                 if idCheckers.IsJunkLocation(each.locationID) or each.locationID in badLocations:
    365                     continue
    366                 if each.stacksize == 0 or each.stacksize < quantity:
    367                     continue
    368                 valid.append(each)
    369 
    370             if len(valid) == 1:
    371                 return valid[0]
    372             scrolllist = []
    373             for each in valid:
    374                 scrolllist.append(('%s<t>%s' % (evetypes.GetName(each.typeID), FmtAmt(each.stacksize)), each))
    375 
    376             if not scrolllist:
    377                 if prompt_player_fsd_dialog('CustomQuestion', {'header': localization.GetByLabel('UI/Market/MarketQuote/headerTryAnotherStation'),
    378                  'question': localization.GetByLabel('UI/Market/MarketQuote/NoItemsAtStations', typeID=typeID, stationName=station[0])}, uiconst.YESNO) == uiconst.ID_YES:
    379                     return self.PickItem(typeID, quantity)
    380                 return None
    381             item = uix.ListWnd(scrolllist, 'generic', localization.GetByLabel('UI/Search/SelectItem'), hint=localization.GetByLabel('UI/Market/MarketQuote/SelectItemsToSell'), isModal=1, scrollHeaders=[localization.GetByLabel('UI/Common/Type'), localization.GetByLabel('UI/Common/Quantity')])
    382             if item:
    383                 return item[1]
    384 
    385     @staticmethod
    386     def GetFuncMaps():
    387         return {StripTags(localization.GetByLabel('UI/Common/Type'), stripOnly=['localized']): 'GetType',
    388          StripTags(localization.GetByLabel('UI/Common/Quantity'), stripOnly=['localized']): 'GetQuantity',
    389          StripTags(localization.GetByLabel('UI/Market/MarketQuote/headerPrice'), stripOnly=['localized']): 'GetPrice',
    390          StripTags(localization.GetByLabel('UI/Common/Location'), stripOnly=['localized']): 'GetLocation',
    391          StripTags(localization.GetByLabel('UI/Common/Station'), stripOnly=['localized']): 'GetStation',
    392          StripTags(localization.GetByLabel('UI/Common/LocationTypes/Region'), stripOnly=['localized']): 'GetRegion',
    393          StripTags(localization.GetByLabel('UI/Common/Range'), stripOnly=['localized']): 'GetRange',
    394          StripTags(localization.GetByLabel('UI/Market/MarketQuote/HeaderMinVolumn'), stripOnly=['localized']): 'GetMinVolume',
    395          StripTags(localization.GetByLabel('UI/Market/Marketbase/ExpiresIn'), stripOnly=['localized']): 'GetExpiresIn',
    396          StripTags(localization.GetByLabel('UI/Market/MarketQuote/headerIssuedBy'), stripOnly=['localized']): 'GetIssuedBy',
    397          StripTags(localization.GetByLabel('UI/Market/Marketbase/Jumps'), stripOnly=['localized']): 'GetJumps',
    398          StripTags(localization.GetByLabel('UI/Market/MarketQuote/headerWalletDivision'), stripOnly=['localized']): 'GetWalletDivision'}
    399 
    400     @staticmethod
    401     def GetJumps(record, data):
    402         sortJumps = record.jumps
    403         if record.jumps == 0:
    404             if record.stationID in (session.stationid, session.structureid):
    405                 data.label += '%s<t>' % localization.GetByLabel('UI/Common/LocationTypes/Station')
    406                 sortJumps = -1
    407             else:
    408                 data.label += '%s<t>' % localization.GetByLabel('UI/Common/LocationTypes/System')
    409         elif record.jumps == 1000000:
    410             data.label += '%s<t>' % localization.GetByLabel('UI/Common/LocationTypes/Unreachable')
    411         else:
    412             data.label += '<right>%i<t>' % record.jumps
    413         data.Set('sort_%s' % localization.GetByLabel('UI/Market/Marketbase/Jumps'), sortJumps)
    414 
    415     @staticmethod
    416     def GetWalletDivision(record, data):
    417         data.label += '%s <t>' % sm.GetService('corp').GetDivisionNames()[record.keyID - 1000 + 8]
    418 
    419     @staticmethod
    420     def GetPrice(record, data):
    421         data.label += "<right><color='0xFFFFFFFF'>%s</color></right><t>" % FmtISK(record.price)
    422         data.Set('sort_%s' % localization.GetByLabel('UI/Market/MarketQuote/headerPrice'), record.price)
    423 
    424     @staticmethod
    425     def GetType(record, data):
    426         name = evetypes.GetNameOrNone(record.typeID)
    427         if name is not None:
    428             data.label += name + '<t>'
    429             data.Set('sort_%s' % localization.GetByLabel('UI/Common/Type'), name.lower())
    430         else:
    431             data.label += localization.GetByLabel('UI/Market/MarketQuote/UnknowenTypeError', typeIDText=str(record.typeID)) + '<t>'
    432             data.Set('sort_%s' % localization.GetByLabel('UI/Common/Type'), localization.GetByLabel('UI/Market/MarketQuote/UnknowenTypeError', typeIDText=str(record.typeID)))
    433 
    434     @staticmethod
    435     def GetLocation(record, data):
    436         if should_show_location_info(record.typeID):
    437             locationName = cfg.evelocations.Get(record.stationID).name
    438         else:
    439             locationName = '-'
    440         data.label += locationName + '<t>'
    441         data.Set('sort_%s' % localization.GetByLabel('UI/Common/Location'), locationName.lower())
    442 
    443     @staticmethod
    444     def GetStation(record, data):
    445         if should_show_location_info(record.typeID):
    446             locationName = cfg.evelocations.Get(record.stationID).name
    447         else:
    448             locationName = '-'
    449         data.label += locationName + '<t>'
    450         data.Set('sort_%s' % localization.GetByLabel('UI/Common/Station'), locationName.lower())
    451 
    452     @staticmethod
    453     def GetExpiresIn(record, data):
    454         exp = record.issueDate + record.duration * DAY - blue.os.GetWallclockTime()
    455         if exp < 0:
    456             data.label += '%s<t>' % localization.GetByLabel('UI/Market/MarketQuote/Expired')
    457         else:
    458             data.label += FmtDate(exp, 'ss') + '<t>'
    459         data.Set('sort_%s' % localization.GetByLabel('UI/Market/Marketbase/ExpiresIn'), record.issueDate + record.duration * DAY)
    460 
    461     @staticmethod
    462     def GetQuantity(record, data):
    463         data.label += '<right>%s<t>' % FmtAmt(int(record.volRemaining))
    464         data.Set('sort_%s' % localization.GetByLabel('UI/Common/Quantity'), int(record.volRemaining))
    465 
    466     @staticmethod
    467     def GetQuantitySlashVolume(record, data):
    468         data.label += '<right>%s/%s<t>' % (FmtAmt(int(record.volRemaining)), FmtAmt(int(record.volEntered)))
    469         data.Set('sort_%s' % localization.GetByLabel('UI/Common/Quantity'), (int(record.volRemaining), record.volEntered))
    470 
    471     @staticmethod
    472     def GetMinVolume(record, data):
    473         vol = int(min(record.volRemaining, record.minVolume))
    474         data.label += '<right>%s<t>' % FmtAmt(vol)
    475         data.Set('sort_%s' % localization.GetByLabel('UI/Market/MarketQuote/HeaderMinVolumn'), vol)
    476 
    477     @staticmethod
    478     def GetSolarsystem(record, data):
    479         solarsystemName = cfg.evelocations.Get(record.solarSystemID).name
    480         data.label += solarsystemName + '<t>'
    481         data.Set('sort_%s' % localization.GetByLabel('UI/Common/LocationTypes/SolarSystem'), solarsystemName.lower())
    482 
    483     @staticmethod
    484     def GetRegion(record, data):
    485         if should_show_location_info(record.typeID) or should_show_region():
    486             regionName = cfg.evelocations.Get(record.regionID).name
    487         else:
    488             regionName = '-'
    489         data.label += regionName + '<t>'
    490         data.Set('sort_%s' % localization.GetByLabel('UI/Common/LocationTypes/Region'), regionName.lower())
    491 
    492     @staticmethod
    493     def GetConstellation(record, data):
    494         constellationName = cfg.evelocations.Get(record.constellationID).name
    495         data.label += constellationName + '<t>'
    496         data.Set('sort_%s' % localization.GetByLabel('UI/Common/LocationTypes/Constellation'), constellationName.lower())
    497 
    498     @staticmethod
    499     def GetRange(record, data):
    500         if should_show_location_info(record.typeID):
    501             if record.range == rangeStation:
    502                 rangeText = localization.GetByLabel('UI/Common/LocationTypes/Station')
    503                 sortval = 0
    504             elif record.range == rangeSolarSystem:
    505                 rangeText = localization.GetByLabel('UI/Common/LocationTypes/SolarSystem')
    506                 sortval = 0.5
    507             elif record.range == rangeRegion:
    508                 rangeText = localization.GetByLabel('UI/Common/LocationTypes/Region')
    509                 sortval = sys.maxint
    510             else:
    511                 rangeText = localization.GetByLabel('UI/Market/MarketQuote/NumberOfJumps', num=record.range)
    512                 sortval = record.range
    513         else:
    514             rangeText = '-'
    515             sortval = 0
    516         data.label += rangeText + '<t>'
    517         data.Set('sort_%s' % localization.GetByLabel('UI/Common/Range'), sortval)
    518 
    519     @staticmethod
    520     def GetIssuedBy(record, data):
    521         name = cfg.eveowners.Get(record.charID).name
    522         data.label += name + '<t>'
    523         data.Set('sort_%s' % localization.GetByLabel('UI/Market/MarketQuote/headerIssuedBy'), name.lower())
    524 
    525     def GetFilterops(self, marketGroupID):
    526         mg = self.GetMarketGroups()
    527         ret = []
    528         for level1 in mg[marketGroupID]:
    529             ret.append((level1.marketGroupName, level1.marketGroupID))
    530 
    531         ret.sort()
    532         ret.insert(0, (localization.GetByLabel('UI/Market/MarketQuote/All'), None))
    533         return ret
    534 
    535     def GetTypeFilterIDs(self, marketGroupID, checkcategory = 1):
    536         c = []
    537         mg = self.GetMarketGroups()[marketGroupID]
    538         if mg:
    539             for each in mg:
    540                 for typeID in each.types:
    541                     groupID = evetypes.GetGroupID(typeID)
    542                     if checkcategory:
    543                         categoryID = evetypes.GetCategoryID(typeID)
    544                         if categoryID not in c:
    545                             c.append(categoryID)
    546                     elif groupID not in c:
    547                         c.append(groupID)
    548 
    549         else:
    550             typeIDs = evetypes.GetTypeIDsByMarketGroup(marketGroupID)
    551             for typeID in typeIDs:
    552                 if checkcategory:
    553                     categoryID = evetypes.GetCategoryID(typeID)
    554                     if categoryID not in c:
    555                         c.append(categoryID)
    556                 groupID = evetypes.GetGroupID(typeID)
    557                 if not checkcategory and groupID not in c:
    558                     c.append(groupID)
    559 
    560         return c
    561 
    562     @staticmethod
    563     def GetProducableGroups(lineGroups, lineCategs):
    564         valid = [ group.groupID for group in lineGroups ]
    565         validcategs = [ categ.categoryID for categ in lineCategs ]
    566         return (valid, validcategs)
    567 
    568     @staticmethod
    569     def GetProducableCategories(lineGroups, lineCategs):
    570         valid = [ categ.categoryID for categ in lineCategs ]
    571         for group in lineGroups:
    572             categoryID = evetypes.GetCategoryIDByGroup(group.groupID)
    573             if categoryID not in valid:
    574                 valid.append(categoryID)
    575 
    576         return valid
    577 
    578     @staticmethod
    579     def GetBestMatchText(typeID, price, averagePrice, percentage):
    580         if price < averagePrice:
    581             aboveBelow = 'UI/Market/MarketQuote/PercentBelow'
    582             color = '<color=0xff00ff00>'
    583         else:
    584             aboveBelow = 'UI/Market/MarketQuote/PercentAbove'
    585             color = '<color=0xffff5050>'
    586         p = {'colorText': color,
    587          'percentage': round(100 * percentage, 2),
    588          'aboveBelow': localization.GetByLabel(aboveBelow),
    589          'colorTextEnd': '</color>'}
    590         return get_best_match_text(typeID, **p)
    591 
    592     def AddTypeToQuickBar(self, typeID, parentID = 0, fromMarket = False, extraText = ''):
    593         if typeID is None:
    594             return
    595         self.AddToQuickBar(typeID, parentID, fromMarket=fromMarket, extraText=extraText)
    596 
    597     @staticmethod
    598     def AddToQuickBar(typeID, parent = 0, fromMarket = False, scatter = True, extraText = ''):
    599         evetypes.RaiseIFNotExists(typeID)
    600         dynamicItemSvc = sm.GetService('dynamicItemSvc')
    601         if dynamicItemSvc.IsDynamicItem(typeID) or not can_view_market_details(typeID):
    602             raise UserError('cannotTradeOnMarket', {'typeID': typeID})
    603         current = settings.user.ui.Get('quickbar', {})
    604         lastid = settings.user.ui.Get('quickbar_lastid', 0)
    605         for _, data in current.items():
    606             if data.parent == parent and data.label == typeID:
    607                 return None
    608 
    609         n = utillib.KeyVal()
    610         n.parent = parent
    611         n.id = lastid + 1
    612         n.label = typeID
    613         n.extraText = extraText
    614         lastid += 1
    615         settings.user.ui.Set('quickbar_lastid', lastid)
    616         current[n.id] = n
    617         settings.user.ui.Set('quickbar', current)
    618         if scatter:
    619             sm.ScatterEvent('OnMarketQuickbarChange', fromMarket=fromMarket)
    620 
    621     @staticmethod
    622     def AddNewQuickbarFolder(folderID = 0, *args):
    623         folderNameLabel = localization.GetByLabel('UI/Market/Marketbase/FolderName')
    624         typeFolderNameLabel = localization.GetByLabel('UI/Market/Marketbase/TypeFolderName')
    625         ret = utilWindows.NamePopup(folderNameLabel, typeFolderNameLabel, maxLength=20)
    626         if ret is not None:
    627             current = settings.user.ui.Get('quickbar', {})
    628             lastid = settings.user.ui.Get('quickbar_lastid', 0)
    629             lastid += 1
    630             n = utillib.KeyVal()
    631             n.parent = folderID
    632             n.id = lastid
    633             n.label = ret
    634             current[n.id] = n
    635             settings.user.ui.Set('quickbar', current)
    636             settings.user.ui.Set('quickbar_lastid', lastid)
    637             sm.ScatterEvent('OnMarketQuickbarChange')
    638             return n
    639 
    640     def OnShowMarketDetails(self, typeID):
    641         self.ShowMarketDetails(typeID, silently=True)