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

marketbase.py (157259B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\market\marketbase.py
      2 import sys
      3 from collections import defaultdict
      4 import eveicon
      5 import blue
      6 import telemetry
      7 import carbonui.const as uiconst
      8 import dogma.data
      9 import utillib
     10 from carbon.common.script.sys.serviceConst import ROLEMASK_ELEVATEDPLAYER
     11 from carbon.common.script.util.commonutils import StripTags
     12 from carbon.common.script.util.format import FmtAmt
     13 from carbonui import AxisAlignment, ButtonVariant, Density, fontconst, TextColor
     14 from carbonui.control.dragdrop.dragdata import TypeDragData
     15 from carbonui.control.scroll_const import SortDirection
     16 from carbonui.control.singlelineedits.singleLineEditFloat import SingleLineEditFloat
     17 from carbonui.control.singlelineedits.singleLineEditInteger import SingleLineEditInteger
     18 from carbonui.decorative.divider_line import DividerLine
     19 from carbonui.decorative.panelUnderlay import PanelUnderlay
     20 from carbonui.primitives.sprite import Sprite
     21 from carbonui.util.bunch import Bunch
     22 from carbonui.util.various_unsorted import ConvertDecimal, GetClipboardData
     23 from dogma.const import attributeDataTypeTypeMirror
     24 from carbonui.button.group import ButtonGroup
     25 from carbonui.control.buttonIcon import ButtonIcon
     26 from carbonui.control.checkbox import Checkbox
     27 from carbonui.control.radioButton import RadioButton
     28 from eve.client.script.ui.comparison import comparisonUtil
     29 from eve.client.script.ui.control.divider import Divider
     30 from eve.client.script.ui.control.entries.generic import Generic
     31 from eve.client.script.ui.control.entries.util import GetFromClass
     32 from eve.client.script.ui.control.eveTabgroupUtil import FixedTabName
     33 from carbonui.control.window import Window
     34 from eve.client.script.ui.control.listgroup import ListGroup
     35 from carbonui.control.tabGroup import TabGroup, GetTabData
     36 from eve.client.script.ui.control.utilMenu import UtilMenu
     37 from eve.client.script.ui.quickFilter import QuickFilterEdit
     38 from eve.client.script.ui.shared.cloneGrade import ORIGIN_MARKET
     39 from eve.client.script.ui.shared.cloneGrade.omegaCloneOverlayIcon import OmegaCloneOverlayIcon
     40 from eve.client.script.ui.shared.market.marketOrdersUtil import DumpOrdersForType
     41 from eve.client.script.ui.shared.market.util import does_global_market_apply, get_best_price_in_place_text, get_units_available_text
     42 import evetypes
     43 import inventorycommon.typeHelpers
     44 import localization
     45 import log
     46 import threadutils
     47 from eve.client.script.ui.shared.market.entries import GenericMarketItem, MarketMetaGroupEntry, MarketOrder, QuickbarGroup, QuickbarItem, MarketListGroup
     48 from eve.client.script.ui.shared.market.qa import add_qa_menu, SETTING_SHOULD_SEE_PLEX_ORDERS_LOCATION_INFO, SETTING_SHOULD_SEE_ORDER_REGION
     49 from eve.client.script.ui.shared.market.util import should_show_location_info, should_show_region
     50 from eve.client.script.ui.shared.market.wallet_balance import get_wallet_balance_options_menu, WalletBalance
     51 from eve.client.script.ui.util import uix, utilWindows
     52 import uthread
     53 import uthread2
     54 from carbonui.control.scrollContainer import ScrollContainer
     55 from carbonui.primitives.container import Container
     56 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     57 from carbonui.primitives.layoutGrid import LayoutGrid
     58 from eve.client.script.ui.control import eveLabel, eveScroll
     59 from eve.client.script.ui.control.eveImage import Image
     60 from eve.client.script.ui.control.eveLabel import EveLabelSmall
     61 from eve.client.script.ui.control.infoIcon import InfoIcon
     62 from eve.client.script.ui.control.listwindow import ListWindow
     63 from carbonui.control.button import Button
     64 from eve.client.script.ui.shared.fitting.fittingUtil import FITKEYS
     65 from eve.client.script.ui.shared.market import GetTypeIDFromDragItem
     66 from eve.client.script.ui.shared.market.requirements import RequirementsContainer
     67 from eve.client.script.ui.shared.market.ticker import MarketTicker, ticker_enabled_setting
     68 from eve.client.script.ui.shared.traits import TraitsContainer, HasTraits
     69 from eve.common.lib import appConst as const
     70 from eve.common.script.sys import eveCfg, idCheckers
     71 from eve.common.script.util import industryCommon
     72 from eve.common.script.util.eveFormat import FmtISK
     73 from eveexceptions import ExceptionEater, UserError
     74 import expertSystems.client
     75 from eveuniverse.security import is_high_sec_or_higher, is_zero_sec
     76 from fastcheckout.client.purchasepanels.purchaseButton import PurchaseButton
     77 from fsdBuiltData.common.iconIDs import GetIconFile
     78 from inventorycommon.const import typePlex
     79 from inventoryrestrictions import can_view_market_details
     80 from localization import GetByLabel
     81 from marketgroups.data import MarketGroupObject
     82 from marketutil import ConvertTuplesToBestByOrders
     83 from marketutil.const import MAX_ORDER_PRICE
     84 from marketutil.feature_flags.client import is_global_plex_market_experiment_enabled_changed, is_global_plex_market_experiment_enabled
     85 from marketutil.quickbarUtil import TICKER_SETTING_NAME
     86 import metaGroups
     87 from omega.client.clone_grade_svc import get_clone_grade_svc
     88 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     89 from shipfitting.multiBuyUtil import BuyMultipleTypesWithQty
     90 from fastcheckout.const import FROM_MARKET_WINDOW, FROM_PLEX_MARKET_GROUP
     91 from carbonui.uicore import uicore
     92 from eveservices.menu import GetMenuService
     93 from menu import MenuLabel
     94 from eveprefs import boot
     95 from textImporting import IsUsingDefaultLanguage
     96 from textImporting.exportQuickbar import QuickbarExporter
     97 from textImporting.importQuickbar import QuickbarImporter
     98 from textImporting.textToTypeIDFinder import SEARCH_LOCALIZED, SEARCH_BOTH
     99 import eve.client.script.ui.shared.pointerTool.pointerToolConst as pConst
    100 ACTION_ICON = 'res:/UI/Texture/classes/UtilMenu/BulletIcon.png'
    101 INFINITY = 999999999999999999L
    102 MARKET_NES_BUTTON_ANALYTIC_ID = 'MarketNESButton'
    103 CATEGORIES_WITH_FACTION_AND_STORYLINE_SUBFOLDERS = (const.categoryModule,
    104  const.categoryStructureModule,
    105  const.categoryDrone,
    106  const.categoryStarbase,
    107  const.categoryFighter)
    108 
    109 def GetNumericValueFromSetting(configName, defaultValue = 0):
    110     value = settings.user.ui.Get(configName, defaultValue)
    111     if value == '-':
    112         return defaultValue
    113     return value
    114 
    115 
    116 class RegionalMarket(Window):
    117     __guid__ = 'form.RegionalMarket'
    118     __notifyevents__ = ['OnSessionChanged']
    119     default_width = 900
    120     default_height = 768
    121     default_windowID = 'market'
    122     default_captionLabelPath = 'Tooltips/StationServices/Market'
    123     default_descriptionLabelPath = 'Tooltips/StationServices/Market_description'
    124     default_iconNum = 'res:/ui/Texture/WindowIcons/market.png'
    125     default_minSize = (650, 435)
    126     default_apply_content_padding = False
    127 
    128     def ApplyAttributes(self, attributes):
    129         Window.ApplyAttributes(self, attributes)
    130         typeID = attributes.typeID
    131         marketGroupID = attributes.marketGroupID
    132         WalletBalance(parent=self.header.extra_content, align=uiconst.TORIGHT)
    133         self.sr.market = MarketBase(name='marketbase', parent=self.sr.main, state=uiconst.UI_PICKCHILDREN, content_padding=self.content_padding)
    134         self.sr.market.Startup(marketGroupID=marketGroupID)
    135         self.on_content_padding_changed.connect(self._on_content_padding_changed)
    136         if typeID:
    137             self.LoadTypeID_Ext(typeID)
    138         sm.RegisterNotify(self)
    139 
    140     def InitializeCaption(self, attributes):
    141         self.caption = self._get_caption()
    142 
    143     @staticmethod
    144     def _get_caption():
    145         return GetByLabel('UI/Market/MarketQuote/RegionalMarket', regionName=cfg.evelocations.Get(session.regionid).name)
    146 
    147     def OnSessionChanged(self, isRemove, session, change):
    148         if self.destroyed:
    149             return
    150         if 'solarsystemid2' in change:
    151             self.caption = self._get_caption()
    152 
    153     def LoadTypeID_Ext(self, typeID):
    154         self.sr.market.LoadTypeID_Ext(typeID)
    155         self.sr.market.OpenOnTypeID(typeID)
    156         self.SetOrder(0)
    157 
    158     def LoadMarketGroup(self, marketGroupID):
    159         self.sr.market.LoadMarketGroup(marketGroupID)
    160 
    161     def OnBack(self, *args):
    162         self.sr.market.GoBack()
    163 
    164     def OnForward(self, *args):
    165         self.sr.market.GoForward()
    166 
    167     @classmethod
    168     def OpenAndSearch(cls, searchString):
    169         window = cls.Open()
    170         market = window.sr.market
    171         market.sr.searchInput.SetValue(searchString)
    172         market.sr.sbTabs.SelectByIdx(0)
    173         market.ReloadMarketListTab()
    174 
    175     def GetMenuMoreOptions(self):
    176         menu = super(RegionalMarket, self).GetMenuMoreOptions()
    177         wallet_balance_menu = get_wallet_balance_options_menu()
    178         if wallet_balance_menu:
    179             menu += wallet_balance_menu
    180         menu.AddCheckbox(text=localization.GetByLabel('UI/Market/ShowMarketTicker'), setting=ticker_enabled_setting, hint=localization.GetByLabel('UI/Market/TickerHint'))
    181         add_qa_menu(menu)
    182         return menu
    183 
    184     def _on_content_padding_changed(self, window):
    185         self.sr.market.content_padding = self.content_padding
    186 
    187 
    188 class MarketBase(Container):
    189     __guid__ = 'form.Market'
    190     __nonpersistvars__ = []
    191     __notifyevents__ = ['OnMarketQuickbarChange', 'OnOwnOrdersChanged', 'OnSessionChanged']
    192     __update_on_reload__ = 1
    193 
    194     def __init__(self, content_padding = (0,
    195  0,
    196  0,
    197  0), **kwargs):
    198         self._content_padding = content_padding
    199         self._details_panel = None
    200         self._group_panel = None
    201         self._left_side = None
    202         self._left_side_divider = None
    203         self._left_side_fill = None
    204         self._main_tab_container = None
    205         self._ticker = None
    206         self._typeID = None
    207         super(MarketBase, self).__init__(**kwargs)
    208         is_global_plex_market_experiment_enabled_changed.connect(self._OnRefreshPlexOrdersRequired)
    209         SETTING_SHOULD_SEE_PLEX_ORDERS_LOCATION_INFO.on_change.connect(self._OnRefreshPlexOrdersRequired)
    210         SETTING_SHOULD_SEE_ORDER_REGION.on_change.connect(self._OnShowRegionChanged)
    211 
    212     def ApplyAttributes(self, attributes):
    213         super(MarketBase, self).ApplyAttributes(attributes)
    214         self.inited = 0
    215         self.searchAsksForMyRange = None
    216         self.pendingType = None
    217         self.loadingType = 0
    218         self.loadingMarketData = None
    219         self.lastdetailTab = localization.GetByLabel('UI/Market/MarketData')
    220         self.lastOnOrderChangeTime = None
    221         self.refreshOrdersTimer = None
    222         self.groupListData = None
    223         self.sr.lastSearchResult = []
    224         self.sr.lastBrowseResult = []
    225         self.sr.marketgroups = None
    226         self.sr.quickType = None
    227         self.sr.pricehistory = None
    228         self.sr.grouplist = None
    229         self.sr.marketdata = None
    230         self.detailsInited = 0
    231         self.updatingGroupsThread = None
    232         self.settingsInited = 0
    233         self.OnChangeFuncs = {}
    234         self.SetChangeFuncs()
    235         self.lastid = 0
    236         self.marketItemList = []
    237         self.name = 'MarketBase'
    238         self.sr.detailTypeID = None
    239         self.parentDictionary = {}
    240         self.historyData = []
    241         self.historyIdx = None
    242 
    243     @property
    244     def content_padding(self):
    245         return self._content_padding
    246 
    247     @content_padding.setter
    248     def content_padding(self, value):
    249         if value != self._content_padding:
    250             self._content_padding = value
    251             self._update_content_padding()
    252 
    253     def _update_content_padding(self):
    254         self._left_side.padding = self._get_left_side_padding()
    255         self._left_side_divider.padding = self._get_left_side_divider_padding()
    256         self._main_tab_container.padding = self._get_main_tab_container_padding()
    257         self._group_panel.padding = self._get_group_panel_padding()
    258         self._details_panel.padding = self._get_details_panel_padding()
    259         self._left_side_fill.padding = self._get_left_side_fill_padding()
    260 
    261     def _get_left_side_padding(self):
    262         pad_left, pad_top, _, _ = self.content_padding
    263         return (pad_left,
    264          pad_top,
    265          0,
    266          0)
    267 
    268     def _get_left_side_divider_padding(self):
    269         _, pad_top, _, _ = self.content_padding
    270         return (0,
    271          pad_top,
    272          8,
    273          0)
    274 
    275     def _get_main_tab_container_padding(self):
    276         _, pad_top, pad_right, _ = self.content_padding
    277         return (0,
    278          pad_top,
    279          pad_right,
    280          8)
    281 
    282     def _get_group_panel_padding(self):
    283         _, _, pad_right, pad_bottom = self.content_padding
    284         if ticker_enabled_setting.is_enabled():
    285             pad_bottom = 0
    286         return (0,
    287          0,
    288          pad_right,
    289          pad_bottom)
    290 
    291     def _get_details_panel_padding(self):
    292         _, _, pad_right, pad_bottom = self.content_padding
    293         if ticker_enabled_setting.is_enabled():
    294             pad_bottom = 0
    295         return (0,
    296          0,
    297          pad_right,
    298          pad_bottom)
    299 
    300     def _get_left_side_fill_padding(self):
    301         pad_left, pad_top, _, _ = self.content_padding
    302         return (-pad_left,
    303          -pad_top,
    304          0,
    305          0)
    306 
    307     def _OnClose(self, *args):
    308         if self.groupListData is not None:
    309             settings.char.ui.Set('marketGroupID_groupList', self.groupListData.marketGroupID)
    310         if self._left_side is not None:
    311             settings.user.ui.Set('marketselectorwidth_%s' % self.idName, self._left_side.width)
    312         settings.user.ui.Set('quickbar_lastid', self.lastid)
    313         settings.user.ui.Set('quickbar', self.folders)
    314         sm.UnregisterNotify(self)
    315         is_global_plex_market_experiment_enabled_changed.disconnect(self._OnRefreshPlexOrdersRequired)
    316         SETTING_SHOULD_SEE_PLEX_ORDERS_LOCATION_INFO.on_change.disconnect(self._OnRefreshPlexOrdersRequired)
    317         SETTING_SHOULD_SEE_ORDER_REGION.on_change.disconnect(self._OnShowRegionChanged)
    318 
    319     def Startup(self, isStationMarket = 0, marketGroupID = None):
    320         self.idName = 'region'
    321         if marketGroupID:
    322             self.groupListData = sm.GetService('marketutils').GetMarketGroupByID(marketGroupID)
    323         else:
    324             marketGroupID = settings.char.ui.Get('marketGroupID_groupList', None)
    325             if marketGroupID:
    326                 try:
    327                     self.groupListData = MarketGroupObject(marketGroupID)
    328                 except Exception:
    329                     self.groupListData = None
    330 
    331             else:
    332                 self.groupListData = None
    333         with ExceptionEater('AddMarketTicker'):
    334             self.AddMarketTicker()
    335         self._left_side = Container(name='leftSide', parent=self, align=uiconst.TOLEFT, width=settings.user.ui.Get('marketselectorwidth_%s' % self.idName, 180), padding=self._get_left_side_padding())
    336         self._left_side_divider = Divider(name='divider', parent=self, align=uiconst.TOLEFT, state=uiconst.UI_NORMAL, width=8, padding=self._get_left_side_divider_padding(), cross_axis_alignment=AxisAlignment.START)
    337         self._left_side_divider.Startup(self._left_side, 'width', 'x', 180, 450)
    338         tabs = TabGroup(name='tabparent', parent=self._left_side, padding=0)
    339         self.sr.sbTabs = tabs
    340         self._main_tab_container = Container(parent=self, align=uiconst.TOTOP, height=32, padding=self._get_main_tab_container_padding())
    341         self.sr.tabs = TabGroup(name='tabparent', parent=self._main_tab_container, align=uiconst.TOLEFT, padBottom=0, auto_size=True)
    342         button_group = ButtonGroup(parent=self._main_tab_container, align=uiconst.TOBOTTOM, padLeft=24, density=Density.COMPACT, button_alignment=AxisAlignment.END)
    343         self.marketNESButton = Button(parent=button_group, label=GetByLabel('UI/VirtualGoodsStore/VgsName'), hint=GetByLabel('Tooltips/Neocom/Vgs_description'), func=uicore.cmd.ToggleAurumStore, variant=ButtonVariant.GHOST)
    344         self.marketNESButton.analyticID = MARKET_NES_BUTTON_ANALYTIC_ID
    345         Button(parent=button_group, label=GetByLabel('Tooltips/StationServices/MarketOrders'), hint=GetByLabel('Tooltips/StationServices/MarketOrders_description'), func=uicore.cmd.OpenMarketOrders, variant=ButtonVariant.GHOST)
    346         multiBuyBtn = Button(parent=button_group, label=GetByLabel('UI/Market/Multibuy'), hint=GetByLabel('UI/Market/Multibuy_description'), func=self.OnOpenMultiBuyBtn, variant=ButtonVariant.GHOST)
    347         multiBuyBtn.OnDropData = self.OnDropOnMultibuyBtn
    348         self._group_panel = ScrollContainer(name='groupScroll', parent=self, align=uiconst.TOALL, padding=self._get_group_panel_padding())
    349         searchAndSettingParent = Container(name='searchAndSettingParent', parent=self._left_side, align=uiconst.TOTOP, height=24, padding=(0, 8, 8, 8))
    350         collapseParent = ContainerAutoSize(parent=searchAndSettingParent, align=uiconst.TORIGHT)
    351         ButtonIcon(name='collapse', parent=collapseParent, align=uiconst.CENTER, pos=(0, 0, 24, 24), iconSize=12, texturePath='res:/UI/Texture/classes/Scroll/Collapse.png', func=self.CollapseAll, hint=localization.GetByLabel('UI/Common/Buttons/CollapseAll'))
    352         searchparent = Container(name='searchparent', parent=searchAndSettingParent, align=uiconst.TOALL)
    353         filterParent = ContainerAutoSize(parent=searchAndSettingParent, align=uiconst.TORIGHT, idx=0)
    354         self.sr.filtericon = UtilMenu(parent=filterParent, align=uiconst.CENTER, GetUtilMenu=self.SettingMenu, texturePath=eveicon.tune, width=24, height=24, iconSize=16, uniqueUiName=pConst.UNIQUE_NAME_MARKET_BROWSE_SETTINGS)
    355         padRight = self.sr.filtericon.width + 4
    356         searchText = settings.char.ui.Get('market_searchText', '')
    357         inpt = QuickFilterEdit(name='searchField', parent=searchparent, setvalue=searchText, hintText=localization.GetByLabel('UI/Common/Search'), pos=(0, 0, 0, 18), padRight=4, maxLength=64, align=uiconst.TOALL, OnClearFilter=self.LoadMarketListOrSearch, isTypeField=True, triggerFilterOnCreation=False)
    358         inpt.ReloadFunction = self.OnSearchFieldChanged
    359         inpt.OnReturn = self.LoadMarketListOrSearch
    360         self.sr.searchInput = inpt
    361         self.sr.searchparent = searchparent
    362         self.sr.quickbarBtnsParent = Container(name='quickbarBtnsParent', parent=searchAndSettingParent, align=uiconst.TOALL)
    363         self.sr.quickbarBtnsParent.display = False
    364         ButtonIcon(parent=ContainerAutoSize(parent=self.sr.quickbarBtnsParent, align=uiconst.TOLEFT), align=uiconst.CENTER, width=24, height=24, texturePath=eveicon.add_folder, iconSize=16, hint=localization.GetByLabel('Tooltips/Market/MarketQuickbarNewFolder'), func=self.NewFolder, args=())
    365         importMenuParent = ContainerAutoSize(parent=self.sr.quickbarBtnsParent, align=uiconst.TOLEFT)
    366         UtilMenu(name='importMenu', menuAlign=uiconst.TOPLEFT, parent=importMenuParent, align=uiconst.CENTER, pos=(0, 0, 24, 24), GetUtilMenu=self.GetImportMenu, texturePath=eveicon.load, iconSize=16, hint=GetByLabel('UI/Market/Marketbase/ImportQuickbar'))
    367         exportMenuParent = ContainerAutoSize(parent=self.sr.quickbarBtnsParent, align=uiconst.TOLEFT)
    368         UtilMenu(name='exportMenu', menuAlign=uiconst.TOPLEFT, parent=exportMenuParent, align=uiconst.CENTER, pos=(0, 0, 24, 24), GetUtilMenu=self.GetExportMenu, texturePath=eveicon.export, iconSize=16, hint=GetByLabel('UI/Market/Marketbase/ExportQuickbar'))
    369         ButtonIcon(parent=ContainerAutoSize(parent=self.sr.quickbarBtnsParent, align=uiconst.TOLEFT), align=uiconst.CENTER, width=24, height=24, texturePath=eveicon.trashcan, iconSize=16, hint=localization.GetByLabel('Tooltips/Market/MarketQuickbarReset'), func=self.ResetQuickbar, args=())
    370         self._details_panel = Container(name='details', parent=self, padding=self._get_details_panel_padding(), clipChildren=True)
    371         maintabs = [GetTabData(label=localization.GetByLabel('UI/Market/Browse'), code=self, tabID='browse', hint=localization.GetByLabel('Tooltips/Market/MarketBrowseTab')), GetTabData(label=localization.GetByLabel('UI/Market/QuickBar'), code=self, tabID='quickbar', hint=localization.GetByLabel('Tooltips/Market/MarketQuickbarTab'))]
    372         subtabs = [GetTabData(label=FixedTabName('UI/Common/Details'), panel=self._details_panel, code=self, tabID='details', hint=localization.GetByLabel('Tooltips/Market/MarketDetailsTab'), uniqueName=pConst.UNIQUE_NAME_MARKET_DETAILS), GetTabData(label=FixedTabName('UI/Common/Groups'), panel=self._group_panel, code=self, tabID='groups', hint=localization.GetByLabel('Tooltips/Market/MarketGroupsTab'))]
    373         if self.destroyed:
    374             return
    375         scrollParent = Container(parent=self._left_side, align=uiconst.TOALL)
    376         self._left_side_fill = PanelUnderlay(bgParent=self._left_side, padding=self._get_left_side_fill_padding())
    377         self.sr.typescroll = eveScroll.Scroll(name='typescroll', parent=scrollParent, multiSelect=False, innerPadding=(0, 0, 0, 16))
    378         self.sr.typescroll.OnSelectionChange = self.CheckTypeScrollSelection
    379         self.sr.typescroll.GetContentContainer().OnDropData = self.OnScrollDrop
    380         self.sr.sbTabs.Startup(maintabs, 'tbselectortabs_%s' % self.idName, autoselecttab=1, UIIDPrefix='marketTab')
    381         quickbarTab = self.sr.sbTabs.GetTabs()[1]
    382         quickbarTab.OnTabDropData = self.OnQuickbarScrollDrop
    383         autoSelect = marketGroupID is None
    384         self.sr.tabs.Startup(subtabs, 'marketsubtabs_%s' % self.idName, autoselecttab=autoSelect, UIIDPrefix='marketTab')
    385         sm.RegisterNotify(self)
    386         self.inited = 1
    387         self.folders = settings.user.ui.Get('quickbar', {})
    388         self.lastid = settings.user.ui.Get('quickbar_lastid', 0)
    389         self.SetupFilters()
    390         self.SetFilterHint()
    391         self.maxdepth = 99
    392         if marketGroupID:
    393             uthread.new(self.sr.tabs.ShowPanelByName, localization.GetByLabel('UI/Common/Groups'))
    394 
    395     def ConstructTopContainer(self):
    396         pass
    397 
    398     def AddMarketTicker(self):
    399         self._ticker = MarketTicker(parent=self, align=uiconst.TOBOTTOM, height=28 * fontconst.fontSizeFactor)
    400         ticker_enabled_setting.on_change.connect(self._on_ticker_toggled)
    401 
    402     def _on_ticker_toggled(self, enabled):
    403         self._update_content_padding()
    404 
    405     def OnDropOnMultibuyBtn(self, dragObj, nodes):
    406         buyDict = {}
    407         for node in nodes:
    408             typeID = GetTypeIDFromDragItem(node)
    409             if not typeID:
    410                 continue
    411             try:
    412                 qty = int(node.extraText)
    413             except:
    414                 qty = 1
    415 
    416             buyDict[typeID] = qty
    417 
    418         if buyDict:
    419             self.OpenMultiBuy(buyDict)
    420 
    421     def OnOpenMultiBuyBtn(self, *args):
    422         self.OpenMultiBuy({})
    423 
    424     def OpenMultiBuy(self, buyDict = None):
    425         if buyDict is None:
    426             buyDict = {}
    427         wnd = BuyMultipleTypesWithQty(buyDict)
    428         if wnd:
    429             wnd.Maximize()
    430 
    431     def CollapseAll(self, *args):
    432         self.sr.typescroll.CollapseAll()
    433 
    434     def SettingMenu(self, menuParent):
    435         menuParent.AddCheckBox(text=localization.GetByLabel('UI/Market/ShowOnlyAvailable'), checked=bool(settings.user.ui.Get('showonlyavailable', 1)), callback=(self.OnCheckboxChange, 'showonlyavailable'))
    436         menuParent.AddSpace()
    437         menuParent.AddText(text=localization.GetByLabel('UI/Market/RangeFilter'))
    438         if session.stationid or session.structureid:
    439             menuParent.AddRadioButton(text=localization.GetByLabel('UI/Common/LocationTypes/Station'), checked=self.GetRange() == const.rangeStation, callback=(self.OnComboChange, const.rangeStation))
    440         menuParent.AddRadioButton(text=localization.GetByLabel('UI/Common/LocationTypes/SolarSystem'), checked=self.GetRange() == const.rangeSolarSystem, callback=(self.OnComboChange, const.rangeSolarSystem))
    441         menuParent.AddRadioButton(text=localization.GetByLabel('UI/Common/LocationTypes/Region'), checked=self.GetRange() == const.rangeRegion, callback=(self.OnComboChange, const.rangeRegion))
    442         menuParent.AddSpace()
    443         menuParent.AddCheckBox(text=localization.GetByLabel('UI/Market/Marketbase/FilterBySkills'), checked=bool(settings.user.ui.Get('showonlyskillsfor', 0)), callback=(self.OnCheckboxChange, 'showonlyskillsfor'))
    444         menuParent.AddCheckBox(text=localization.GetByLabel('UI/Market/Marketbase/FilterByCPUAndPowergrid'), checked=bool(settings.user.ui.Get('showhavecpuandpower', 0)), callback=(self.OnCheckboxChange, 'showhavecpuandpower'))
    445         menuParent.AddCheckBox(text=localization.GetByLabel('UI/Market/Marketbase/FilterByUntrainedSkills'), checked=bool(settings.user.ui.Get('shownewskills', 0)), callback=(self.OnCheckboxChange, 'shownewskills'))
    446         menuParent.AddSpace()
    447         menuParent.AddButton(text=GetByLabel('UI/Browser/BrowserSettings/ResetCacheLocation'), callback=self.ResetFilterSettings)
    448 
    449     def CheckTypeScrollSelection(self, sel):
    450         if len(sel) == 1:
    451             entry = sel[0]
    452             if entry.__guid__ == 'listentry.GenericMarketItem' or entry.__guid__ == 'listentry.QuickbarItem':
    453                 self.OnTypeClick(entry.typeID)
    454 
    455     def GetOptions(self):
    456         if session.stationid:
    457             options = [(localization.GetByLabel('UI/Common/LocationTypes/Station'), const.rangeStation), (localization.GetByLabel('UI/Common/LocationTypes/SolarSystem'), const.rangeSolarSystem), (localization.GetByLabel('UI/Common/LocationTypes/Region'), const.rangeRegion)]
    458         else:
    459             options = [(localization.GetByLabel('UI/Common/LocationTypes/SolarSystem'), const.rangeSolarSystem), (localization.GetByLabel('UI/Common/LocationTypes/Region'), const.rangeRegion)]
    460         return options
    461 
    462     def GetRange(self):
    463         return sm.StartService('marketutils').GetMarketRange()
    464 
    465     def OnComboChange(self, value, *args):
    466         if self.inited:
    467             sm.GetService('marketutils').SetMarketRange(value)
    468             self.sr.lastSearchResult = []
    469             uthread.new(self.ReloadMarketListTab)
    470 
    471     def ReloadMarketListTab(self, *args):
    472         if self.sr.sbTabs.GetSelectedArgs() == 'browse':
    473             self.LoadMarketListOrSearch()
    474         self.sr.tabs.ReloadVisible()
    475 
    476     def SetFilterHint(self, *args):
    477         filtersInUse, filterUsed = self.FiltersInUse1()
    478         self.sr.filtericon.hint = filtersInUse
    479 
    480     def OnCheckboxChange(self, sender, *args):
    481         c = settings.user.ui.Get(sender, 0)
    482         settings.user.ui.Set(sender, not c)
    483         self.SetFilterHint()
    484         if self.sr.sbTabs.GetSelectedArgs() == 'browse':
    485             self.LoadMarketListOrSearch()
    486         if self.sr.tabs.GetSelectedArgs() == 'browse':
    487             self.LoadMarketListOrSearch()
    488 
    489     def OnCheckboxChangeSett(self, sender, *args):
    490         settings.user.ui.Set(sender.name, bool(sender.checked))
    491         self.LoadMarketData()
    492         self.ShowFiltersInUse()
    493 
    494     def OnMarketQuickbarChange(self, fromMarket = 0, *args):
    495         if self and not self.destroyed:
    496             if not fromMarket:
    497                 self.lastid = settings.user.ui.Get('quickbar_lastid', 0)
    498                 self.folders = settings.user.ui.Get('quickbar', {})
    499             if self.sr.sbTabs.GetSelectedArgs() == 'quickbar':
    500                 self.LoadQuickBar()
    501 
    502     def OnOwnOrdersChanged(self, orders, reason, isCorp):
    503         if self and not self.destroyed:
    504             showAutoRefresh = False
    505             for order in orders:
    506                 if not settings.user.ui.Get('autorefresh', True) and self.sr.detailTypeID:
    507                     if order.typeID == self.sr.detailTypeID:
    508                         showAutoRefresh = True
    509                 if reason != 'Expiry':
    510                     self._OnOwnOrderChanged()
    511 
    512             if showAutoRefresh:
    513                 self.sr.reloadBtn.display = True
    514 
    515     @threadutils.throttled(5)
    516     def _OnOwnOrderChanged(self):
    517         if self and not self.destroyed:
    518             try:
    519                 if settings.user.ui.Get('autorefresh', True):
    520                     if self.sr.sbTabs.GetSelectedArgs() == 'browse':
    521                         self.LoadMarketListOrSearch()
    522                     self.sr.tabs.ReloadVisible()
    523             except AttributeError:
    524                 if not self or self.destoyed:
    525                     return
    526                 raise
    527 
    528     def OnSessionChanged(self, isremote, session, change):
    529         if 'solarsystemid' in change and self and not self.destroyed:
    530             combo = self.FindChild('marketComboRangeFilter')
    531             if combo:
    532                 oldValue = combo.GetValue()
    533                 newValue = self.GetRange()
    534                 combo.LoadOptions(self.GetOptions(), newValue)
    535                 if oldValue != newValue:
    536                     self.ReloadMarketListTab()
    537 
    538     def GetQuickItemMenu(self, btn, *args):
    539         if btn.sr.node.extraText:
    540             menuText = 'UI/Market/Marketbase/EditAdditionalText'
    541         else:
    542             menuText = 'UI/Market/Marketbase/AddAdditionalText'
    543         m = [(MenuLabel(menuText), self.EditExtraText, (btn.sr.node.id, btn.sr.node.extraText, btn.sr.node.label))]
    544         m += [None]
    545         m += [(MenuLabel('UI/Market/Remove'), self.RemoveFromQuickBar, (btn.sr.node,))]
    546         if session.role & ROLEMASK_ELEVATEDPLAYER:
    547             m.append(None)
    548             m += sm.GetService('menu').GetGMTypeMenu(btn.sr.node.typeID)
    549         return m
    550 
    551     def RemoveFromQuickBar(self, node):
    552         nodes = node.scroll.GetSelectedNodes(node)
    553         for each in nodes:
    554             GetMenuService().RemoveFromQuickBar(each)
    555 
    556     def EditExtraText(self, groupID, extraText, label, *args):
    557         typeNewTextLabel = localization.GetByLabel('UI/Market/Marketbase/TypeInAdditionalText')
    558         extraText = utilWindows.NamePopup(label, typeNewTextLabel, setvalue=unicode(extraText), maxLength=25, validator=self.ValidateExtraText)
    559         if extraText is None:
    560             return
    561         self.folders[groupID[1]].extraText = extraText
    562         sm.ScatterEvent('OnMarketQuickbarChange')
    563 
    564     def ValidateExtraText(self, *args):
    565         pass
    566 
    567     def OnSearchFieldChanged(self, *args):
    568         inputValue = self.sr.searchInput.GetValue().strip()
    569         if inputValue == '':
    570             return self.LoadMarketListOrSearch()
    571         if len(inputValue) > 1:
    572             self.DoSearch()
    573 
    574     def DoSearch(self):
    575         if self.destroyed:
    576             return
    577         self.PopulateSeachAsksForMyRange()
    578         settings.char.ui.Set('market_searchText', self.sr.searchInput.GetValue())
    579         self.Search()
    580 
    581     def LoadMarketListOrSearch(self):
    582         if self.destroyed:
    583             return
    584         settings.char.ui.Set('market_searchText', self.sr.searchInput.GetValue())
    585         self.SetFilterHint()
    586         self.mine = self.GetMySkills()
    587         self.PopulateAsksForMyRange()
    588         if self.sr.searchInput.GetValue().strip():
    589             self.Search()
    590         else:
    591             if not self.sr.filtericon.enabled:
    592                 self.sr.filtericon.Enable()
    593                 self.SetFilterHint()
    594             self.LoadMarketList()
    595 
    596     def LoadMarketList(self):
    597         scrolllist = self.GetGroupListForBrowse()
    598         if self.destroyed:
    599             return
    600         self.sr.typescroll.Load(contentList=scrolllist, scrollTo=self.sr.typescroll.GetScrollProportion())
    601 
    602     @telemetry.ZONE_METHOD
    603     def PopulateAsksForMyRange(self):
    604         asksForMyRange = self._GetAsksForRange()
    605         self.searchAsksForMyRange = asksForMyRange
    606         marketRange = self.GetRange()
    607         if marketRange in (const.rangeStation, const.rangeSolarSystem) or idCheckers.IsWormholeRegion(session.regionid):
    608             asksForMyRange = ConvertTuplesToBestByOrders(asksForMyRange)
    609         self.asksForMyRange = asksForMyRange
    610 
    611     def _GetAsksForRange(self):
    612         quote = sm.StartService('marketQuote')
    613         marketRange = self.GetRange()
    614         if marketRange == const.rangeStation:
    615             asksForMyRange = quote.GetStationAsks()
    616         elif marketRange == const.rangeSolarSystem or idCheckers.IsWormholeRegion(session.regionid):
    617             asksForMyRange = quote.GetSystemAsks()
    618         else:
    619             asksForMyRange = quote.GetRegionBest()
    620         return asksForMyRange
    621 
    622     def _GetPlexAsks(self):
    623         return sm.StartService('marketQuote').GetPlexBest()
    624 
    625     def PopulateSeachAsksForMyRange(self):
    626         self.searchAsksForMyRange = self._GetAsksForRange()
    627 
    628     def GetScrollListFromTypeList(self, nodedata, *args):
    629         typeIDs = nodedata.invTypes
    630         sublevel = nodedata.sublevel
    631         return self._GetScrollListFromTypeList(typeIDs, sublevel)
    632 
    633     def _GetScrollListFromTypeList(self, typeIDs, sublevel):
    634         subList = []
    635         for typeID in typeIDs:
    636             typeName = evetypes.GetName(typeID)
    637             subList.append((typeName, GetFromClass(GenericMarketItem, {'label': typeName,
    638               'invtype': typeID,
    639               'sublevel': sublevel + 1,
    640               'GetMenu': self.OnTypeMenu,
    641               'ignoreRightClick': 1,
    642               'showinfo': 1,
    643               'typeID': typeID})))
    644 
    645         subList = [ item[1] for item in localization.util.Sort(subList, key=lambda x: x[0]) ]
    646         return subList
    647 
    648     def GetTypesByMetaGroups(self, typeIDs):
    649         typesByMetaGroupID = defaultdict(list)
    650         for typeID in typeIDs:
    651             if evetypes.GetVariationParentTypeIDOrNone(typeID) is None:
    652                 metaGroupID = None
    653             else:
    654                 metaGroupID = evetypes.GetMetaGroupID(typeID)
    655                 if metaGroupID == const.metaGroupStoryline:
    656                     metaGroupID = const.metaGroupFaction
    657             typesByMetaGroupID[metaGroupID].append(typeID)
    658 
    659         return typesByMetaGroupID
    660 
    661     def OnMetaGroupClicked(self, *args):
    662         self.sr.tabs.ShowPanelByName(localization.GetByLabel('UI/Common/Groups'))
    663 
    664     def GetGroupListForBrowse(self, nodedata = None, newitems = 0):
    665         scrolllist = []
    666         if nodedata and nodedata.marketGroupInfo.hasTypes:
    667             typesByMetaGroupID = self.GetTypesByMetaGroups(nodedata.typeIDs)
    668             for metaGroupID, types in sorted(typesByMetaGroupID.items()):
    669                 subList = []
    670                 if len(types) == 0:
    671                     continue
    672                 categoryID = evetypes.GetCategoryID(types[0])
    673                 if metaGroupID in (const.metaGroupStoryline,
    674                  const.metaGroupFaction,
    675                  const.metaGroupOfficer,
    676                  const.metaGroupDeadspace) and categoryID in CATEGORIES_WITH_FACTION_AND_STORYLINE_SUBFOLDERS:
    677                     if metaGroupID in (const.metaGroupStoryline, const.metaGroupFaction):
    678                         label = localization.GetByLabel('UI/Market/FactionAndStoryline')
    679                     else:
    680                         label = metaGroups.get_name(metaGroupID)
    681                     marketGroupID = nodedata.marketGroupInfo.marketGroupID if nodedata is not None else None
    682                     subList.append((label, GetFromClass(MarketMetaGroupEntry, {'GetSubContent': self.GetScrollListFromTypeList,
    683                       'label': label,
    684                       'id': (marketGroupID, metaGroupID),
    685                       'showlen': 0,
    686                       'metaGroupID': metaGroupID,
    687                       'invTypes': types,
    688                       'sublevel': nodedata.sublevel + 1,
    689                       'showicon': GetIconFile(metaGroups.get_icon_id(metaGroupID)),
    690                       'state': 'locked',
    691                       'BlockOpenWindow': True,
    692                       'OnToggle': self.OnMetaGroupClicked,
    693                       'typeIDs': types})))
    694                     subList = [ item[1] for item in localization.util.Sort(subList, key=lambda x: x[0]) ]
    695                 else:
    696                     subList = self._GetScrollListFromTypeList(types, nodedata.sublevel)
    697                 scrolllist += subList
    698 
    699         else:
    700             marketGroupID = None
    701             level = 0
    702             if nodedata:
    703                 marketGroupID = nodedata.marketGroupInfo.marketGroupID
    704                 level = nodedata.sublevel + 1
    705             grouplist = sm.GetService('marketutils').GetMarketGroups()[marketGroupID]
    706             for marketGroupInfo in grouplist:
    707                 if not len(marketGroupInfo.types):
    708                     continue
    709                 if self.destroyed:
    710                     return
    711                 typeIDs = self.FilterItemsForBrowse(marketGroupInfo)
    712                 if len(typeIDs) == 0:
    713                     continue
    714                 if level in (0, 1):
    715                     groupHint = marketGroupInfo.description
    716                 else:
    717                     groupHint = ''
    718                 groupID = (marketGroupInfo.marketGroupName, marketGroupInfo.marketGroupID)
    719                 data = {'GetSubContent': self.GetGroupListForBrowse,
    720                  'label': marketGroupInfo.marketGroupName,
    721                  'id': groupID,
    722                  'typeIDs': typeIDs,
    723                  'iconMargin': 18,
    724                  'showlen': 0,
    725                  'marketGroupInfo': marketGroupInfo,
    726                  'sublevel': level,
    727                  'state': 'locked',
    728                  'OnClick': self.OnMarketGroupClicked,
    729                  'showicon': None if not marketGroupInfo.hasTypes else 'hide',
    730                  'iconID': marketGroupInfo.iconID,
    731                  'selected': False,
    732                  'BlockOpenWindow': 1,
    733                  'MenuFunction': self.SelectFolderMenu,
    734                  'hint': groupHint}
    735                 if not level and marketGroupInfo.description:
    736                     data['hint'] = marketGroupInfo.description
    737                 if marketGroupInfo.hasTypes and getattr(self, 'groupListData', None) and self.groupListData.marketGroupID != marketGroupInfo.marketGroupID:
    738                     uicore.registry.SetListGroupOpenState(groupID, 0)
    739                 scrolllist.append((marketGroupInfo.marketGroupName, GetFromClass(MarketListGroup, data)))
    740 
    741             scrolllist = [ item[1] for item in localization.util.Sort(scrolllist, key=lambda x: x[0]) ]
    742         return scrolllist
    743 
    744     def OnMarketGroupClicked(self, entry, openGroup = True):
    745         if not openGroup:
    746             return
    747         marketGroup = entry.sr.node.marketGroupInfo
    748         self._LoadMarketGroup(marketGroup)
    749 
    750     def LoadMarketGroup(self, marketGroupID):
    751         self.groupListData = sm.GetService('marketutils').GetMarketGroupByID(marketGroupID)
    752         self.sr.tabs.ShowPanelByName(localization.GetByLabel('UI/Common/Groups'))
    753 
    754     def _LoadMarketGroup(self, marketGroup):
    755         self.state = uiconst.UI_DISABLED
    756         try:
    757             if marketGroup.hasTypes:
    758                 groupID = marketGroup.marketGroupID
    759                 for entry in self.sr.typescroll.GetNodes():
    760                     if not (entry.marketGroupInfo and entry.marketGroupInfo.hasTypes):
    761                         continue
    762                     if entry.marketGroupInfo.marketGroupID == groupID:
    763                         if not entry.panel:
    764                             entry.open = 1
    765                             self.sr.typescroll.PrepareSubContent(entry)
    766                         self.sr.typescroll.SelectNode(entry)
    767                         self.sr.typescroll.ShowNodeIdx(entry.idx)
    768                         if entry.open or self.groupListData is None or self.groupListData.marketGroupID != groupID:
    769                             self.groupListData = entry.marketGroupInfo
    770                             self.sr.tabs.ShowPanelByName(localization.GetByLabel('UI/Common/Groups'))
    771                     else:
    772                         if not entry.open:
    773                             continue
    774                         if entry.panel:
    775                             entry.panel.Toggle()
    776                         else:
    777                             entry.open = 0
    778                             if entry.subNodes:
    779                                 rm = entry.subNodes
    780                                 entry.subNodes = []
    781                                 entry.open = 0
    782                                 self.sr.typescroll.RemoveEntries(rm)
    783 
    784         finally:
    785             self.state = uiconst.UI_PICKCHILDREN
    786 
    787     def GetAttrDict(self, typeID):
    788         ret = {}
    789         for each in dogma.data.get_type_attributes(typeID):
    790             attribute = dogma.data.get_attribute(each.attributeID)
    791             if attribute.dataType == attributeDataTypeTypeMirror:
    792                 ret[each.attributeID] = evetypes.GetAttributeForType(typeID, attribute.name)
    793             else:
    794                 ret[each.attributeID] = each.value
    795 
    796         if const.attributeCapacity not in ret and evetypes.GetCapacity(typeID):
    797             ret[const.attributeCapacity] = evetypes.GetCapacity(typeID)
    798         attrInfo = sm.GetService('godma').GetType(typeID)
    799         for each in attrInfo.displayAttributes:
    800             ret[each.attributeID] = each.value
    801 
    802         return ret
    803 
    804     def GetActiveShipSlots(self):
    805         ship = sm.GetService('godma').GetItem(session.shipid)
    806         if ship is None:
    807             return 0
    808         hiSlots = getattr(ship, 'hiSlots', 0)
    809         medSlots = getattr(ship, 'medSlots', 0)
    810         lowSlots = getattr(ship, 'lowSlots', 0)
    811         rigSlots = getattr(ship, 'rigSlots', 0)
    812         flags = []
    813         for gidx in xrange(3):
    814             for sidx in xrange(8):
    815                 flags.append(getattr(const, 'flag%sSlot%s' % (FITKEYS[gidx], sidx)))
    816 
    817         for module in ship.modules:
    818             if module.flagID not in flags:
    819                 continue
    820             for effect in module.effects.itervalues():
    821                 if effect.effectID == const.effectHiPower:
    822                     hiSlots -= 1
    823                 elif effect.effectID == const.effectMedPower:
    824                     medSlots -= 1
    825                 elif effect.effectID == const.effectLoPower:
    826                     lowSlots -= 1
    827                 elif effect.effectID == const.effectRigSlot:
    828                     rigSlots -= 1
    829 
    830         return (hiSlots,
    831          medSlots,
    832          lowSlots,
    833          rigSlots)
    834 
    835     def GetMySkills(self):
    836         return sm.GetService('skills').MyEffectiveSkillLevelsByID()
    837 
    838     def KillGroupPageThread(self):
    839         if self.updatingGroupsThread and self.updatingGroupsThread.IsAlive():
    840             self.updatingGroupsThread.Kill()
    841 
    842     @telemetry.ZONE_METHOD
    843     def ShowGroupPage(self, *args):
    844         self.KillGroupPageThread()
    845         self.updatingGroupsThread = uthread2.StartTasklet(self.ShowGroupPage_thread)
    846 
    847     def ShowGroupPage_thread(self, *args):
    848         self.PopulateAsksForMyRange()
    849         try:
    850             self._group_panel.Flush()
    851             group = self.groupListData
    852             if group:
    853                 self._group_panel.ShowNoContentHint(localization.GetByLabel('UI/Market/Marketbase/Loading'))
    854                 freeslots = self.GetActiveShipSlots()
    855                 self.mine = mySkills = self.GetMySkills()
    856                 dataByTypeID = {data.typeID:data for data in self.FilterItemsForGroupPage(group)}
    857                 typesByMetaGroupID = self.GetTypesByMetaGroups(dataByTypeID.keys())
    858                 scrolllist = []
    859                 for _, typeIDs in sorted(typesByMetaGroupID.iteritems()):
    860                     subList = []
    861                     if len(typeIDs) == 0:
    862                         continue
    863                     for typeID in typeIDs:
    864                         subList.append((evetypes.GetName(typeID), dataByTypeID[typeID]))
    865 
    866                     subList = [ item[1] for item in localization.util.Sort(subList, key=lambda x: x[0]) ]
    867                     scrolllist += subList
    868 
    869                 if not scrolllist:
    870                     noItemsText = localization.GetByLabel('UI/Market/Marketbase/NoItemsAvailable')
    871                     if settings.user.ui.Get('showonlyavailable', 1):
    872                         noItemsText += '<br><br>' + localization.GetByLabel('UI/Market/Marketbase/DisableShowOnlyAvailable')
    873                     self._group_panel.ShowNoContentHint(noItemsText)
    874                 marketRange = self.GetRange()
    875                 if marketRange == const.rangeStation:
    876                     bestPriceLocation = localization.GetByLabel('UI/Common/LocationTypes/Station')
    877                 elif marketRange == const.rangeSolarSystem:
    878                     bestPriceLocation = localization.GetByLabel('UI/Common/LocationTypes/System')
    879                 else:
    880                     bestPriceLocation = localization.GetByLabel('UI/Common/LocationTypes/Region')
    881                 for data in scrolllist:
    882                     entryData = Bunch()
    883                     entryData.marketData = data
    884                     entryData.invType = data.typeID
    885                     entryData.typeImageAttributes = Bunch(width=64, height=64, src='typeicon:%s' % data.typeID, bumped=True, showfitting=True, showtechlevel=True)
    886                     entryData.freeslots = freeslots
    887                     entryData.mySkills = mySkills
    888                     desc = evetypes.GetDescription(data.typeID).replace('\r\n', '<br>').strip()
    889                     if desc.endswith('<br>'):
    890                         desc = desc[:len(desc) - 4]
    891                     entryData.description = desc
    892                     jump = ''
    893                     if data.qty:
    894                         jumps = int(data.jumps)
    895                         if jumps == 0:
    896                             jump = localization.GetByLabel('UI/Market/Marketbase/InThisSystem')
    897                         elif jumps == -1:
    898                             jump = localization.GetByLabel('UI/Market/Marketbase/InThisStation')
    899                         else:
    900                             jump = localization.GetByLabel('UI/Market/Marketbase/JumpsAway', jumps=data.jumps)
    901                     if data.qty > 0:
    902                         entryData.unitsAvailable = get_units_available_text(data.typeID, int(data.qty), jump)
    903                     entryData.bestPrice = get_best_price_in_place_text(data.typeID, bestPriceLocation)
    904                     MarketGroupEntry(parent=self._group_panel, data=entryData)
    905                     blue.pyos.BeNice()
    906 
    907                 self._group_panel.HideNoContentHint()
    908             else:
    909                 self._group_panel.ShowNoContentHint(localization.GetByLabel('UI/Market/Marketbase/SelectGroupToBrowse'))
    910         finally:
    911             if self.destroyed:
    912                 return
    913 
    914     def Load(self, key):
    915         if key == 'marketdata':
    916             self.lastdetailTab = localization.GetByLabel('UI/Market/MarketData')
    917             self.LoadMarketData()
    918         elif key == 'quickbar':
    919             self.sr.searchparent.display = False
    920             self.sr.quickbarBtnsParent.display = True
    921             self.sr.typescroll.multiSelect = 1
    922             self.LoadQuickBar()
    923         elif key == 'details':
    924             self.KillGroupPageThread()
    925             self.LoadDetails()
    926         elif key == 'pricehistory':
    927             self.lastdetailTab = localization.GetByLabel('UI/Market/Marketbase/PriceHistory')
    928             self.LoadPriceHistory()
    929         elif key == 'browse':
    930             self.sr.searchparent.display = True
    931             self.sr.quickbarBtnsParent.display = False
    932             self.sr.typescroll.multiSelect = 0
    933             self.LoadMarketListOrSearch()
    934         elif key == 'groups':
    935             self.ShowGroupPage()
    936 
    937     def Search(self, *args):
    938         self.sr.searchInput.RegisterHistory()
    939         self.sr.filtericon.Disable()
    940         self.sr.filtericon.hint = localization.GetByLabel('UI/Market/FiltersDontApply')
    941         search = self.sr.searchInput.GetValue().lower()
    942         if not search or search == ' ':
    943             self.LoadMarketListOrSearch()
    944             return
    945         self.sr.typescroll.Load(contentList=[])
    946         self.sr.typescroll.ShowHint(localization.GetByLabel('UI/Common/Searching'))
    947         t = uix.TakeTime('Market::GetSearchResult', self.GetSearchResult)
    948         if not t:
    949             t = [GetFromClass(Generic, {'label': localization.GetByLabel('UI/Market/NothingFoundWithSearch', search=search)})]
    950         self.sr.typescroll.ShowHint()
    951         self.sr.typescroll.Load(contentList=t)
    952 
    953     def SetChangeFuncs(self):
    954         self.OnChangeFuncs['market_filter_price_min'] = self.OnChange_minEdit_market_filter_price
    955         self.OnChangeFuncs['market_filter_price_max'] = self.OnChange_maxEdit_market_filter_price
    956         self.OnChangeFuncs['market_filter_jumps_min'] = self.OnChange_minEdit_market_filter_jump
    957         self.OnChangeFuncs['market_filter_jumps_max'] = self.OnChange_maxEdit_market_filter_jumps
    958         self.OnChangeFuncs['market_filter_quantity_min'] = self.OnChange_minEdit_market_filter_quantity
    959         self.OnChangeFuncs['market_filter_quantity_max'] = self.OnChange_maxEdit_market_filter_quantity
    960         self.OnChangeFuncs['market_filters_sellorderdev_min'] = self.OnChange_minEdit_market_filters_sellorderdev
    961         self.OnChangeFuncs['market_filters_sellorderdev_max'] = self.OnChange_maxEdit_market_filters_sellorderdev
    962         self.OnChangeFuncs['market_filters_buyorderdev_min'] = self.OnChange_minEdit_market_filters_buyorderdev
    963         self.OnChangeFuncs['market_filters_buyorderdev_max'] = self.OnChange_maxEdit_market_filters_buyorderdev
    964 
    965     def LoadDetails(self):
    966         if not self.detailsInited:
    967             topPar = ContainerAutoSize(name='topCont', parent=self._details_panel, align=uiconst.TOTOP, alignMode=uiconst.TOTOP)
    968             buttons = ContainerAutoSize(parent=topPar, align=uiconst.TORIGHT, padLeft=4)
    969             self.goBackBtn = ButtonIcon(parent=ContainerAutoSize(parent=buttons, align=uiconst.TOLEFT), align=uiconst.TOPLEFT, width=24, height=24, iconSize=16, texturePath=eveicon.navigate_back, func=self.GoBack, hint=localization.GetByLabel('UI/Control/EveWindow/Previous'))
    970             self.DisableArrow(self.goBackBtn)
    971             self.goForwardBtn = ButtonIcon(parent=ContainerAutoSize(parent=buttons, align=uiconst.TOLEFT), align=uiconst.TOPLEFT, width=24, height=24, iconSize=16, texturePath=eveicon.navigate_forward, func=self.GoForward, hint=localization.GetByLabel('UI/Control/EveWindow/Next'))
    972             self.DisableArrow(self.goForwardBtn)
    973             self.sr.reloadBtn = ButtonIcon(parent=ContainerAutoSize(parent=buttons, align=uiconst.TOLEFT), align=uiconst.TOPLEFT, width=24, height=24, iconSize=16, texturePath=eveicon.arrow_rotate_right, func=self.OnReload, hint=localization.GetByLabel('UI/Market/Marketbase/Reload'))
    974             self.sr.reloadBtn.display = False
    975             self.settingsIcon = UtilMenu(parent=ContainerAutoSize(parent=buttons, align=uiconst.TOLEFT), align=uiconst.TOPLEFT, GetUtilMenu=self.DetailsSettingsMenu, texturePath=eveicon.tune, width=24, height=24, iconSize=16)
    976             top = ContainerAutoSize(name='typeNameCont', align=uiconst.TOTOP, parent=topPar)
    977             topDetailsCont = ContainerAutoSize(parent=top, align=uiconst.TOTOP, alignMode=uiconst.TOTOP, minHeight=64)
    978             self.mainIconContainer = Container(name='mainIconContainer', parent=Container(parent=topDetailsCont, align=uiconst.TOLEFT, width=64, padRight=8), align=uiconst.TOTOP, height=64)
    979             self.sr.detailIcon = MarketGroupItemImage(parent=self.mainIconContainer, align=uiconst.TOALL, name='detailIcon', height=64, width=64)
    980             self.sr.detailIcon.Hide()
    981             self.sr.detailGroupTrace = eveLabel.EveLabelMedium(parent=topDetailsCont, align=uiconst.TOTOP, state=uiconst.UI_NORMAL, text='', color=TextColor.SECONDARY)
    982             self.sr.detailGroupTrace.OnClick = (self.ClickGroupTrace, self.sr.detailGroupTrace)
    983             captionGrid = LayoutGrid(parent=ContainerAutoSize(parent=topDetailsCont, align=uiconst.TOTOP), align=uiconst.TOPLEFT, columns=3, cellSpacing=(8, 0))
    984             self.sr.detailTop = eveLabel.EveCaptionMedium(parent=captionGrid, align=uiconst.CENTERLEFT, text=localization.GetByLabel('UI/Market/Marketbase/NoTypeSelected'), state=uiconst.UI_NORMAL)
    985             self.sr.detailInfoicon = InfoIcon(parent=captionGrid, align=uiconst.CENTER, state=uiconst.UI_HIDDEN)
    986             self.sr.detailInfoicon.OnClick = self.ShowInfoFromDetails
    987             self.sr.detailTypeID = None
    988             self.browseBtn = ButtonIcon(name='browseBtn', parent=captionGrid, align=uiconst.CENTER, width=16, height=16, iconSize=16, texturePath='res:/UI/Texture/classes/MapView/focusIcon.png', hint=localization.GetByLabel('UI/Market/Marketbase/FindInBrowseTab'), func=self.OpenOnType, args=self.sr.detailGroupTrace, uniqueUiName=pConst.UNIQUE_NAME_MARKET_FIND_IN_BROWSER)
    989             self.browseBtn.display = False
    990             self.sr.requirements = RequirementsContainer(parent=ContainerAutoSize(parent=topDetailsCont, align=uiconst.TOTOP), align=uiconst.TOPLEFT, top=4, width=200)
    991             self.buyPlexButton = PurchaseButton(name='buyPlexButton', parent=ContainerAutoSize(parent=topDetailsCont, align=uiconst.TOTOP), align=uiconst.TOPLEFT, state=uiconst.UI_HIDDEN, top=4, width=70, height=20, fontsize=12, func=lambda *args: uicore.cmd.CmdBuyPlex(logContext=FROM_MARKET_WINDOW), text=localization.GetByLabel('UI/VirtualGoodsStore/Buttons/BuyPlex'))
    992             self.sr.filtersText = eveLabel.EveLabelMedium(parent=top, align=uiconst.TOTOP, state=uiconst.UI_NORMAL, padding=(0, 8, 0, 0))
    993             self.ShowFiltersInUse()
    994             self.sr.detailtabs = TabGroup(name='tabparent', parent=self._details_panel)
    995             self.sr.marketdata = Container(name='marketinfo', parent=self._details_panel, pos=(0, 0, 0, 0))
    996             from eve.client.script.ui.shared.market.pricehistorychart import PriceHistoryParent
    997             self.sr.pricehistory = PriceHistoryParent(name='pricehistory', parent=self._details_panel, pos=(0, 0, 0, 0))
    998             detailtabs = [GetTabData(label=localization.GetByLabel('UI/Market/MarketData'), panel=self.sr.marketdata, code=self, tabID='marketdata', hint=localization.GetByLabel('Tooltips/Market/MarketDetailsData'), uniqueName=pConst.UNIQUE_NAME_MARKET_DATA), GetTabData(label=FixedTabName('UI/Market/Marketbase/PriceHistory'), panel=self.sr.pricehistory, code=self, tabID='pricehistory', hint=localization.GetByLabel('Tooltips/Market/MarketDetailsHistory'), uniqueName=pConst.UNIQUE_NAME_MARKET_PRICE_HISTORY)]
    999             self.sr.detailtabs.Startup(detailtabs, 'marketdetailtabs', autoselecttab=1, UIIDPrefix='marketDetailsTab')
   1000             self.detailsInited = 1
   1001             return
   1002         if self.lastdetailTab:
   1003             self.sr.detailtabs.ShowPanelByName(self.lastdetailTab)
   1004         self.ShowFiltersInUse()
   1005 
   1006     def ShowFiltersInUse(self):
   1007         filtersInUse = self.FiltersInUse2()
   1008         if filtersInUse:
   1009             self.sr.filtersText.display = True
   1010             self.sr.filtersText.text = localization.GetByLabel('UI/Market/Marketbase/MarketFilters')
   1011             self.sr.filtersText.hint = filtersInUse
   1012         else:
   1013             self.sr.filtersText.display = False
   1014             self.sr.filtersText.text = ''
   1015             self.sr.filtersText.hint = None
   1016 
   1017     def DetailsSettingsMenu(self, menuParent):
   1018         grid = menuParent.AddLayoutGrid(columns=4, cellPadding=4)
   1019         priceConfig = settings.user.ui.Get('market_filter_price', 0)
   1020         Checkbox(text=GetByLabel('UI/Market/Marketbase/Price'), settingsKey='market_filter_price', checked=priceConfig, parent=grid, align=uiconst.TOPLEFT, callback=self.OnCheckboxChangeSett, wrapLabel=False)
   1021         self.MakeFloatEdit('market_filter_price', isMin=True, parent=grid)
   1022         eveLabel.EveLabelSmall(text='-', parent=grid, align=uiconst.CENTER)
   1023         self.MakeFloatEdit('market_filter_price', isMin=False, parent=grid)
   1024         if not does_global_market_apply(self._typeID):
   1025             jumpsConfig = settings.user.ui.Get('market_filter_jumps', 0)
   1026             Checkbox(text=GetByLabel('UI/Market/Marketbase/Jumps'), settingsKey='market_filter_jumps', checked=jumpsConfig, parent=grid, align=uiconst.TOPLEFT, callback=self.OnCheckboxChangeSett, wrapLabel=False)
   1027             self.MakeIntEdit('market_filter_jumps', isMin=True, parent=grid, ints=[0, None])
   1028             eveLabel.EveLabelSmall(text='-', parent=grid, align=uiconst.CENTER)
   1029             self.MakeIntEdit('market_filter_jumps', isMin=False, parent=grid, ints=[0, None])
   1030         qtyConfig = settings.user.ui.Get('market_filter_quantity', 0)
   1031         Checkbox(text=GetByLabel('UI/Common/Quantity'), settingsKey='market_filter_quantity', checked=qtyConfig, parent=grid, align=uiconst.TOPLEFT, callback=self.OnCheckboxChangeSett, wrapLabel=False)
   1032         self.MakeIntEdit('market_filter_quantity', isMin=True, parent=grid, ints=[0, None])
   1033         eveLabel.EveLabelSmall(text='-', parent=grid, align=uiconst.CENTER)
   1034         self.MakeIntEdit('market_filter_quantity', isMin=False, parent=grid, ints=[0, None])
   1035         if not does_global_market_apply(self._typeID):
   1036             subGrid = LayoutGrid(columns=3, cellPadding=(0, 0, 20, 0))
   1037             showOrdersLabel = EveLabelSmall(text=GetByLabel('UI/Market/Marketbase/ShowOrdersIn'), left=2)
   1038             subGrid.AddCell(cellObject=showOrdersLabel, colSpan=3)
   1039             boxes = self.GetSecStatusBoxes()
   1040             for label, configname, retval, checked, hint in boxes:
   1041                 Checkbox(text='%s' % label, parent=subGrid, settingsKey=configname, checked=checked, callback=self.OnCheckboxChangeSett, align=uiconst.TOPLEFT, wrapLabel=False)
   1042 
   1043             subGrid.RefreshGridLayout()
   1044             grid.AddCell(cellObject=subGrid, colSpan=4)
   1045         sellConfig = settings.user.ui.Get('market_filters_sellorderdev', 0)
   1046         Checkbox(text=GetByLabel('UI/Market/Marketbase/SellOrdersDeviation'), settingsKey='market_filters_sellorderdev', checked=sellConfig, parent=grid, align=uiconst.TOPLEFT, hint=GetByLabel('UI/Market/Marketbase/SellOrdersDeviationToolTip'), callback=self.OnCheckboxChangeSett, wrapLabel=False)
   1047         self.MakeIntEdit('market_filters_sellorderdev', isMin=True, parent=grid, ints=[-100, None])
   1048         eveLabel.EveLabelSmall(text='-', parent=grid, align=uiconst.CENTER)
   1049         self.MakeIntEdit('market_filters_sellorderdev', isMin=False, parent=grid, ints=[-100, None])
   1050         buyConfig = settings.user.ui.Get('market_filters_buyorderdev', 0)
   1051         Checkbox(text=GetByLabel('UI/Market/Marketbase/BuyOrdersDeviation'), settingsKey='market_filters_buyorderdev', checked=buyConfig, parent=grid, align=uiconst.TOPLEFT, hint=GetByLabel('UI/Market/Marketbase/BuyOrdersDeviationToolTip'), callback=self.OnCheckboxChangeSett, wrapLabel=False)
   1052         self.MakeIntEdit('market_filters_buyorderdev', isMin=True, parent=grid, ints=[-100, None])
   1053         eveLabel.EveLabelSmall(text='-', parent=grid, align=uiconst.CENTER)
   1054         self.MakeIntEdit('market_filters_buyorderdev', isMin=False, parent=grid, ints=[-100, None])
   1055         currentMyOrdersValue = settings.user.ui.Get('hilitemyorders', True)
   1056         mmo = Checkbox(text=GetByLabel('UI/Market/Marketbase/MarkMyOrders'), settingsKey='hilitemyorders', checked=currentMyOrdersValue, hint=GetByLabel('UI/Market/Marketbase/MarkMyOrdersHint'), callback=self.OnCheckboxChangeSett)
   1057         grid.AddCell(cellObject=mmo, colSpan=4)
   1058         menuParent.AddCheckBox(text=localization.GetByLabel('UI/Market/Marketbase/AutoRefresh'), checked=bool(settings.user.ui.Get('autorefresh', 0)), callback=(self.OnCheckboxChange, 'autorefresh'))
   1059         menuParent.AddButton(text=GetByLabel('UI/Browser/BrowserSettings/ResetCacheLocation'), callback=self.ResetDetailsSettings)
   1060 
   1061     def MakeIntEdit(self, configName, isMin, parent, ints):
   1062         if isMin:
   1063             funcKey = '%s_min' % configName
   1064             editName = 'minEdit_%s' % configName
   1065         else:
   1066             funcKey = '%s_max' % configName
   1067             editName = 'maxEdit_%s' % configName
   1068         edit = SingleLineEditInteger(name=editName, setvalue=GetNumericValueFromSetting(editName), parent=parent, minValue=ints[0], maxValue=ints[1], OnChange=self.OnChangeFuncs[funcKey])
   1069         edit.AutoFitToText(FmtAmt(sys.maxint))
   1070         return edit
   1071 
   1072     def MakeFloatEdit(self, configName, isMin, parent):
   1073         if isMin:
   1074             funcKey = '%s_min' % configName
   1075             editName = 'minEdit_%s' % configName
   1076         else:
   1077             funcKey = '%s_max' % configName
   1078             editName = 'maxEdit_%s' % configName
   1079         edit = SingleLineEditFloat(name=editName, setvalue=GetNumericValueFromSetting(editName), parent=parent, maxValue=MAX_ORDER_PRICE, decimalPlaces=2, OnChange=self.OnChangeFuncs[funcKey])
   1080         edit.AutoFitToText(FmtAmt(sys.maxint))
   1081         return edit
   1082 
   1083     def GetSecStatusBoxes(self):
   1084         highSecurityLabel = GetByLabel('UI/Common/HighSec')
   1085         highSecurityToolTipLabel = GetByLabel('UI/Market/Marketbase/FilterHighSecurityToolTip')
   1086         lowSecurityLabel = GetByLabel('UI/Common/LowSec')
   1087         lowSecurityToolTipLabel = GetByLabel('UI/Market/Marketbase/FilterLowSecurityToolTip')
   1088         zeroSecurityLabel = GetByLabel('UI/Common/NullSec')
   1089         zeroSecurityToolTipLabel = GetByLabel('UI/Market/Marketbase/FilterZeroSecurityToolTip')
   1090         boxes = [(highSecurityLabel,
   1091           'market_filter_highsec',
   1092           settings.user.ui.Get('market_filter_highsec', 0) == 1,
   1093           settings.user.ui.Get('market_filter_highsec', 0),
   1094           highSecurityToolTipLabel), (lowSecurityLabel,
   1095           'market_filter_lowsec',
   1096           settings.user.ui.Get('market_filter_lowsec', 0) == 1,
   1097           settings.user.ui.Get('market_filter_lowsec', 0),
   1098           lowSecurityToolTipLabel), (zeroSecurityLabel,
   1099           'market_filter_zerosec',
   1100           settings.user.ui.Get('market_filter_zerosec', 0) == 1,
   1101           settings.user.ui.Get('market_filter_zerosec', 0),
   1102           zeroSecurityToolTipLabel)]
   1103         return boxes
   1104 
   1105     def OnReload(self, *args):
   1106         self.sr.reloadBtn.display = False
   1107         self.sr.marketdata.children[0].OnReload()
   1108         if self.sr.sbTabs.GetSelectedArgs() == 'browse':
   1109             self.LoadMarketListOrSearch()
   1110         self.OnOrderChangeTimer = None
   1111         self.lastOnOrderChangeTime = blue.os.GetWallclockTime()
   1112 
   1113     def _OnRefreshPlexOrdersRequired(self, *args):
   1114         typeID = self.GetSelection()
   1115         if typeID and typeID == typePlex:
   1116             self.ReloadType()
   1117 
   1118     def _OnShowRegionChanged(self, *args):
   1119         self.ReloadType()
   1120 
   1121     def ShowInfoFromDetails(self, *args):
   1122         typeID = self.GetTypeIDFromDetails()
   1123         if typeID is not None:
   1124             sm.GetService('info').ShowInfo(typeID)
   1125 
   1126     def PreviewFromDetails(self, *args):
   1127         typeID = self.GetTypeIDFromDetails()
   1128         if typeID is not None:
   1129             sm.GetService('preview').PreviewType(typeID)
   1130 
   1131     def GetTypeIDFromDetails(self):
   1132         typeID = None
   1133         invtype = self.GetSelection()
   1134         if invtype:
   1135             typeID = invtype
   1136         if typeID is None:
   1137             if self.sr.Get('detailTypeID'):
   1138                 typeID = self.sr.detailTypeID
   1139         return typeID
   1140 
   1141     def ClickGroupTrace(self, trace, *args):
   1142         if trace.sr.marketGroupInfo:
   1143             self.groupListData = trace.sr.marketGroupInfo
   1144             self.sr.tabs.ShowPanelByName(localization.GetByLabel('UI/Common/Groups'))
   1145 
   1146     def OpenOnType(self, trace, *args):
   1147         typeID = trace.typeID
   1148         if trace.sr.marketGroupInfo:
   1149             self.groupListData = trace.sr.marketGroupInfo
   1150         searchValueBefore = self.sr.searchInput.GetValue().strip()
   1151         if searchValueBefore:
   1152             self.sr.searchInput.SetText('')
   1153             self.sr.searchInput.caretIndex = (0, 0)
   1154             self.sr.searchInput.CheckHintText()
   1155             self.sr.searchInput.RefreshCaretPosition()
   1156         reloadingDone = False
   1157         if not self.sr.sbTabs.GetSelectedArgs() == 'browse':
   1158             self.sr.sbTabs.ShowPanelByName(localization.GetByLabel('UI/Market/Browse'))
   1159             reloadingDone = True
   1160         if settings.user.ui.Get('showonlyavailable', True):
   1161             settings.user.ui.Set('showonlyavailable', False)
   1162             self.LoadMarketListOrSearch()
   1163             reloadingDone = True
   1164         if searchValueBefore and not reloadingDone:
   1165             self.LoadMarketListOrSearch()
   1166         if self.sr.typescroll:
   1167             self.OpenOnTypeID(typeID)
   1168 
   1169     def OpenOnTypeID(self, typeID, groupsToSkip = [], *args):
   1170         for node in self.sr.typescroll.GetNodes():
   1171             if typeID in node.get('typeIDs', []) and node.id not in groupsToSkip:
   1172                 if self.sr.typescroll.scrollingRange:
   1173                     position = node.scroll_positionFromTop / float(self.sr.typescroll.scrollingRange)
   1174                     self.sr.typescroll.ScrollToProportion(position, threaded=False)
   1175                 groupsToSkipCopy = groupsToSkip[:] + [node.id]
   1176                 if not node.open:
   1177                     if node.panel is not None:
   1178                         node.panel.OnClick(openGroup=False)
   1179                     else:
   1180                         uicore.registry.SetListGroupOpenState(node.id, True)
   1181                     blue.synchro.Yield()
   1182                     return self.OpenOnTypeID(typeID, groupsToSkipCopy)
   1183             elif node.get('typeID', None) == typeID:
   1184                 self.sr.typescroll.SelectNode(node)
   1185                 break
   1186 
   1187     def LoadQuickBar(self, selectFolder = 0, *args):
   1188         self.selectFolder = selectFolder
   1189         self.folders = settings.user.ui.Get('quickbar', {})
   1190         if not self.folders:
   1191             if settings.user.ui.Get('marketquickbar', 0):
   1192                 self.LoadOldQuickBar()
   1193         scrolllist = self.LoadQuickBarItems(selectFolder)
   1194         if self.selectFolder:
   1195             selectAFolderLabel = localization.GetByLabel('UI/Market/Marketbase/SelectAFolder')
   1196             result = self.ListWnd([], 'item', selectAFolderLabel, None, 1, contentList=scrolllist)
   1197             if not result:
   1198                 return False
   1199             id, parentDepth = result
   1200             if self.depth + 1 + parentDepth + 1 > 7:
   1201                 msg = localization.GetByLabel('UI/Market/Marketbase/DeepQuickbarFolder', folderDepth=self.depth + 1 + parentDepth + 1)
   1202                 yesNo = prompt_player_fsd_dialog('AskAreYouSure', {'cons': msg}, uiconst.YESNO)
   1203                 return [False, id][yesNo == uiconst.ID_YES]
   1204             return id
   1205         self.sr.typescroll.Load(contentList=scrolllist, noContentHint=localization.GetByLabel('UI/Common/NothingFound'))
   1206 
   1207     def LoadOldQuickBar(self):
   1208         items = settings.user.ui.Get('marketquickbar', [])
   1209         for each in items:
   1210             n = utillib.KeyVal()
   1211             n.parent = 0
   1212             n.id = self.lastid
   1213             n.label = each
   1214             self.folders[n.id] = n
   1215             self.lastid += 1
   1216 
   1217         settings.user.ui.Delete('marketquickbar')
   1218 
   1219     def LoadMarketData(self, *args):
   1220         invtype = self.GetSelection()
   1221         if self.sr.marketdata:
   1222             if not len(self.sr.marketdata.children):
   1223                 MarketData(name='marketdata', parent=self.sr.marketdata, pos=(0, 0, 0, 0))
   1224             marketDataChild = self.sr.marketdata.children[0]
   1225             self.loadingMarketData = marketDataChild.GetInvTypeID()
   1226             if invtype:
   1227                 marketDataChild.LoadType(invtype)
   1228                 self.StoreTypeInHistory(invtype)
   1229             else:
   1230                 marketDataChild.ReloadType()
   1231             self.sr.reloadBtn.display = False
   1232         self.loadingMarketData = None
   1233 
   1234     def LoadPriceHistory(self, invtype = None, *args):
   1235         invtype = invtype or self.GetSelection()
   1236         if not invtype:
   1237             return
   1238         if self.sr.pricehistory:
   1239             self.sr.reloadBtn.display = False
   1240             if not self.sr.pricehistory.inited:
   1241                 self.sr.pricehistory.Startup()
   1242             self.sr.pricehistory.LoadType(invtype)
   1243             self.StoreTypeInHistory(invtype)
   1244 
   1245     @telemetry.ZONE_METHOD
   1246     def GetSearchResult(self):
   1247         search = self.sr.searchInput.GetValue().lower()
   1248         showOnlyAvailable = settings.user.ui.Get('showonlyavailable', 1)
   1249         if self.sr.lastSearchResult and self.sr.lastSearchResult[0] == search and self.sr.lastSearchResult[2] == showOnlyAvailable:
   1250             scrollList = self.sr.lastSearchResult[1][:]
   1251         else:
   1252             scrollList = []
   1253             byCategories = {}
   1254             if search:
   1255                 searchWhat = SEARCH_LOCALIZED
   1256                 if not IsUsingDefaultLanguage(session):
   1257                     bilingualSettings = localization.settings.bilingualSettings
   1258                     importantNameSetting = bilingualSettings.GetValue('localizationImportantNames')
   1259                     if importantNameSetting == bilingualSettings.IMPORTANT_NAME_ENGLISH:
   1260                         searchWhat = SEARCH_BOTH
   1261                     elif bilingualSettings.GetValue('languageTooltip'):
   1262                         searchWhat = SEARCH_BOTH
   1263                 typeIDFinder = sm.GetService('marketutils').GetMarketTypeIDFinder()
   1264                 res = typeIDFinder.FindTypeIDsWithPartialMatch(search, searchWhat)
   1265                 allMarketGroups = sm.GetService('marketutils').GetMarketGroups()[None]
   1266                 myCategories = {}
   1267                 for typeID in res:
   1268                     for mg in allMarketGroups:
   1269                         if typeID in mg.types:
   1270                             topMarketCategory = mg
   1271                             break
   1272                     else:
   1273                         topMarketCategory = None
   1274 
   1275                     if topMarketCategory is None:
   1276                         continue
   1277                     if topMarketCategory.marketGroupID in byCategories:
   1278                         byCategories[topMarketCategory.marketGroupID].append(typeID)
   1279                     else:
   1280                         byCategories[topMarketCategory.marketGroupID] = [typeID]
   1281                         myCategories[topMarketCategory.marketGroupID] = topMarketCategory
   1282 
   1283                 if len(byCategories) > 1:
   1284                     for categoryID, categoryTypeIDs in byCategories.iteritems():
   1285                         category = myCategories[categoryID]
   1286                         group = GetFromClass(ListGroup, {'GetSubContent': self.GetSeachCategory,
   1287                          'label': category.marketGroupName,
   1288                          'id': ('searchGroups', categoryID),
   1289                          'showlen': 0,
   1290                          'sublevel': 0,
   1291                          'state': 'locked',
   1292                          'BlockOpenWindow': True,
   1293                          'categoryID': category.marketGroupID,
   1294                          'typeIDs': categoryTypeIDs,
   1295                          'iconID': category.iconID,
   1296                          'hint': category.description})
   1297                         scrollList.append(group)
   1298 
   1299                 else:
   1300                     for categoryID, categoryTypeIDs in byCategories.iteritems():
   1301                         fakeNodeData = utillib.KeyVal(typeIDs=categoryTypeIDs, sublevel=-1, categoryID=categoryID)
   1302                         results = self.GetSeachCategory(fakeNodeData)
   1303                         scrollList.extend(results)
   1304 
   1305         self.sr.lastSearchResult = (search, scrollList[:], showOnlyAvailable)
   1306         return scrollList
   1307 
   1308     def GetSeachCategory(self, nodedata, *args):
   1309         types = nodedata.typeIDs
   1310         typesByMetaGroupID = self.GetTypesByMetaGroups(types)
   1311         sublevel = nodedata.sublevel
   1312         categoryID = nodedata.categoryID
   1313         scrollList = []
   1314         for metaGroupID, types in sorted(typesByMetaGroupID.items()):
   1315             specialItemGroups = (const.metaGroupStoryline,
   1316              const.metaGroupFaction,
   1317              const.metaGroupOfficer,
   1318              const.metaGroupDeadspace)
   1319             if metaGroupID in specialItemGroups:
   1320                 searchGroup = self.GetSearchSubGroup(metaGroupID, types, sublevel=sublevel + 1, categoryID=categoryID)
   1321                 scrollList.append((searchGroup.label, searchGroup))
   1322             else:
   1323                 for typeID in types:
   1324                     searchEntry = self.GetSearchEntry(typeID, sublevel=sublevel + 1)
   1325                     scrollList.append((' ' + evetypes.GetName(typeID), searchEntry))
   1326                     blue.pyos.BeNice()
   1327 
   1328         scrollList = [ item[1] for item in localization.util.Sort(scrollList, key=lambda x: x[0]) ]
   1329         return scrollList
   1330 
   1331     def GetSearchSubGroup(self, metaGroupID, types, sublevel = 0, categoryID = -1, *args):
   1332         if metaGroupID in (const.metaGroupStoryline, const.metaGroupFaction):
   1333             label = localization.GetByLabel('UI/Market/FactionAndStoryline')
   1334         else:
   1335             label = metaGroups.get_name(metaGroupID)
   1336         groupEntry = GetFromClass(MarketMetaGroupEntry, {'GetSubContent': self.GetSearchScrollListFromTypeList,
   1337          'label': label,
   1338          'id': ('searchGroups', (metaGroupID, categoryID)),
   1339          'showlen': 0,
   1340          'metaGroupID': metaGroupID,
   1341          'invTypes': types,
   1342          'sublevel': sublevel,
   1343          'showicon': GetIconFile(metaGroups.get_icon_id(metaGroupID)),
   1344          'state': 'locked',
   1345          'BlockOpenWindow': True,
   1346          'OnToggle': self.OnMetaGroupClicked,
   1347          'typeIDs': types})
   1348         return groupEntry
   1349 
   1350     def GetSearchScrollListFromTypeList(self, nodedata):
   1351         subList = []
   1352         invTypes = nodedata.invTypes
   1353         sublevel = nodedata.sublevel
   1354         for typeID in invTypes:
   1355             searchEntry = self.GetSearchEntry(typeID, sublevel=sublevel + 1)
   1356             subList.append((evetypes.GetName(typeID), searchEntry))
   1357 
   1358         subList = [ item[1] for item in localization.util.Sort(subList, key=lambda x: x[0]) ]
   1359         return subList
   1360 
   1361     def GetSearchEntry(self, typeID, sublevel = 0, *args):
   1362         data = utillib.KeyVal()
   1363         data.label = evetypes.GetName(typeID)
   1364         data.GetMenu = self.OnTypeMenu
   1365         data.invtype = typeID
   1366         data.showinfo = 1
   1367         data.sublevel = sublevel
   1368         data.typeID = typeID
   1369         data.ignoreRightClick = 1
   1370         onlyShowAvailable = settings.user.ui.Get('showonlyavailable', 0)
   1371         if onlyShowAvailable and not self.IsTypeIdInCurrentRange(typeID):
   1372             data.inRange = False
   1373         else:
   1374             data.inRange = True
   1375         entry = GetFromClass(GenericMarketItem, data)
   1376         return entry
   1377 
   1378     def IsTypeIdInCurrentRange(self, typeID):
   1379         if self.searchAsksForMyRange:
   1380             return typeID in self.searchAsksForMyRange
   1381         return False
   1382 
   1383     def OnTypeClick(self, typeID, *args):
   1384         if not self.sr.typescroll.GetSelected():
   1385             return
   1386         if self.loadingType:
   1387             self.pendingType = 1
   1388             return
   1389         self.sr.quickType = typeID
   1390         self.ReloadType()
   1391 
   1392     def OnTypeMenu(self, entry):
   1393         typeID = entry.sr.node.invtype
   1394         categoryID = evetypes.GetCategoryID(typeID)
   1395         menu = [(MenuLabel('UI/Inventory/ItemActions/AddTypeToMarketQuickbar'), self.AddTypeToQuickBar, (entry.sr.node.typeID,)), (MenuLabel('UI/Commands/ShowInfo'), self.ShowInfo, (typeID,))]
   1396         if categoryID in const.previewCategories and inventorycommon.typeHelpers.GetIcon(typeID) and inventorycommon.typeHelpers.GetIcon(typeID).iconFile != '':
   1397             previewLabel = MenuLabel('UI/Market/Marketbase/Preview')
   1398             menu.append((previewLabel, sm.GetService('preview').PreviewType, (typeID,)))
   1399         if industryCommon.IsBlueprintCategory(categoryID):
   1400             from eve.client.script.ui.shared.industry.industryWnd import Industry
   1401             menu.append((localization.GetByLabel('UI/Industry/ViewInIndustry'), Industry.OpenOrShowBlueprint, (None, typeID)))
   1402         if session.role & ROLEMASK_ELEVATEDPLAYER:
   1403             menu.append(None)
   1404             menu += sm.GetService('menu').GetGMTypeMenu(typeID)
   1405         return menu
   1406 
   1407     def ShowInfo(self, typeID):
   1408         sm.GetService('info').ShowInfo(typeID)
   1409 
   1410     def AddTypeToQuickBar(self, typeID, parent = 0, extraText = ''):
   1411         settings.user.ui.Set('quickbar', self.folders)
   1412         settings.user.ui.Set('quickbar_lastid', self.lastid)
   1413         sm.GetService('marketutils').AddTypeToQuickBar(typeID, parent, fromMarket=True, extraText=extraText)
   1414         self.lastid = settings.user.ui.Get('quickbar_lastid', 0)
   1415         self.folders = settings.user.ui.Get('quickbar', {})
   1416 
   1417     def LoadQuickType(self, quick = None, *args):
   1418         if quick:
   1419             self.sr.quickType = quick.invType
   1420             self.ReloadType()
   1421 
   1422     def LoadTypeID_Ext(self, typeID):
   1423         self.sr.quickType = typeID
   1424         self.ReloadType()
   1425 
   1426     def ReloadType(self):
   1427         self._typeID = self.GetSelection()
   1428         sm.ScatterEvent('OnMarketTypeSelectionChanged', self._typeID)
   1429         if not self._typeID:
   1430             self.loadingType = 0
   1431             return
   1432         self.KillGroupPageThread()
   1433         marketTypes = sm.GetService('marketutils').GetMarketTypes()
   1434         if self._typeID not in marketTypes:
   1435             self.loadingType = 0
   1436             return
   1437         if self.loadingMarketData and self.loadingMarketData != self._typeID:
   1438             uthread2.call_after_wallclocktime_delay(self.ReloadType, 0.1)
   1439             return
   1440         self.pendingType = 0
   1441         self.loadingType = 1
   1442         blue.pyos.synchro.Yield()
   1443         try:
   1444             self.sr.tabs.ShowPanelByName(localization.GetByLabel('UI/Common/Details'))
   1445         except Exception as e:
   1446             self.loadingType = 0
   1447             raise e
   1448 
   1449         blue.pyos.synchro.Yield()
   1450         typeName = evetypes.GetName(self._typeID)
   1451         self.sr.detailTop.text = typeName
   1452         self.sr.detailIcon.attrs = Bunch(width=64, height=64, src='typeicon:%s' % self._typeID, bumped=True, showfitting=True, showtechlevel=True)
   1453         self.sr.detailIcon.typeName = typeName
   1454         self.sr.detailIcon.LoadTypeIcon(self._typeID)
   1455         self.sr.detailIcon.SetOmegaIconState(self._typeID)
   1456         self.sr.detailIcon.SetState(uiconst.UI_NORMAL)
   1457         self.sr.detailIcon.Show()
   1458         self.sr.detailInfoicon.state = uiconst.UI_NORMAL
   1459         self.browseBtn.display = True
   1460         self.sr.detailTypeID = self._typeID
   1461         self.sr.requirements.LoadTypeRequirements(self.sr.detailTypeID)
   1462         if self._typeID == const.typePlex:
   1463             self.buyPlexButton.Show()
   1464         else:
   1465             self.buyPlexButton.Hide()
   1466         marketGroup, trace = sm.GetService('marketutils').FindMarketGroup(self._typeID)
   1467         if marketGroup:
   1468             self.sr.detailGroupTrace.sr.marketGroupInfo = marketGroup
   1469             self.sr.detailGroupTrace.text = trace
   1470             self.sr.detailGroupTrace.typeID = self._typeID
   1471             self.sr.detailGroupTrace.display = True
   1472         else:
   1473             self.sr.detailGroupTrace.display = False
   1474             self.sr.detailGroupTrace.sr.marketGroupInfo = None
   1475             self.sr.detailGroupTrace.typeID = None
   1476         self.loadingType = 0
   1477         if self.pendingType:
   1478             self.ReloadType()
   1479 
   1480     def GetSelection(self):
   1481         if self.sr.quickType:
   1482             return self.sr.quickType
   1483         selection = self.sr.typescroll.GetSelected()
   1484         if not selection:
   1485             return None
   1486         if hasattr(selection[0], 'invtype'):
   1487             return selection[0].invtype
   1488 
   1489     def ResetQuickbar(self):
   1490         if prompt_player_fsd_dialog('ResetQuickbar', buttons=uiconst.YESNO) != uiconst.ID_YES:
   1491             return
   1492         self.folders = {}
   1493         settings.user.ui.Set('quickbar', self.folders)
   1494         self.lastid = 0
   1495         settings.user.ui.Set('quickbar_lastid', self.lastid)
   1496         sm.ScatterEvent('OnMarketQuickbarChange')
   1497 
   1498     def ResetFilterSettings(self):
   1499         settings.user.ui.Set('showonlyskillsfor', False)
   1500         settings.user.ui.Set('showhavecpuandpower', False)
   1501         settings.user.ui.Set('shownewskills', False)
   1502         settings.user.ui.Set('showonlyavailable', True)
   1503         settings.user.ui.Set('autorefresh', True)
   1504         if self.sr.sbTabs.GetSelectedArgs() == 'browse':
   1505             self.LoadMarketListOrSearch()
   1506 
   1507     def ResetDetailsSettings(self):
   1508         settings.user.ui.Set('market_filter_price', False)
   1509         settings.user.ui.Set('minEdit_market_filter_price', 0)
   1510         settings.user.ui.Set('maxEdit_market_filter_price', 100000)
   1511         settings.user.ui.Set('market_filter_jumps', False)
   1512         settings.user.ui.Set('minEdit_market_filter_jumps', 0)
   1513         settings.user.ui.Set('maxEdit_market_filter_jumps', 20)
   1514         settings.user.ui.Set('market_filter_quantity', False)
   1515         settings.user.ui.Set('minEdit_market_filter_quantity', 0)
   1516         settings.user.ui.Set('maxEdit_market_filter_quantity', 1000)
   1517         settings.user.ui.Set('market_filter_zerosec', True)
   1518         settings.user.ui.Set('market_filter_lowsec', True)
   1519         settings.user.ui.Set('market_filter_highsec', True)
   1520         settings.user.ui.Set('market_filters_sellorderdev', False)
   1521         settings.user.ui.Set('minEdit_market_filters_sellorderdev', 0)
   1522         settings.user.ui.Set('maxEdit_market_filters_sellorderdev', 0)
   1523         settings.user.ui.Set('market_filters_buyorderdev', False)
   1524         settings.user.ui.Set('minEdit_market_filters_buyorderdev', 0)
   1525         settings.user.ui.Set('maxEdit_market_filters_buyorderdev', 0)
   1526         self.LoadMarketData()
   1527         self.ShowFiltersInUse()
   1528 
   1529     def LoadQuickBarItems(self, selectFolder = 0, *args):
   1530         import types
   1531         scrolllist = []
   1532         notes = self.GetItems(parent=0)
   1533         tickerFolderID = settings.char.ui.Get(TICKER_SETTING_NAME, 0)
   1534         for id, n in notes.items():
   1535             try:
   1536                 if type(n.label) == types.UnicodeType:
   1537                     groupID = ('quickbar', id)
   1538                     data = {'GetSubContent': self.GetGroupSubContent,
   1539                      'label': n.label,
   1540                      'id': groupID,
   1541                      'groupItems': self.GroupGetContentIDList(groupID),
   1542                      'iconMargin': 18,
   1543                      'showlen': 0,
   1544                      'state': 0,
   1545                      'sublevel': 0,
   1546                      'MenuFunction': [self.GroupMenu, self.SelectFolderMenu][self.selectFolder],
   1547                      'BlockOpenWindow': 1,
   1548                      'DropData': self.GroupDropNode,
   1549                      'ChangeLabel': self.GroupChangeLabel,
   1550                      'DeleteFolder': self.GroupDeleteFolder,
   1551                      'selected': 1,
   1552                      'hideNoItem': self.selectFolder,
   1553                      'allowGuids': ['listentry.QuickbarGroup', 'listentry.QuickbarItem'],
   1554                      'selectGroup': selectFolder,
   1555                      'isTickerFolder': tickerFolderID == id}
   1556                     if self.selectFolder:
   1557                         data['OnDblClick'] = self.OnDblClick
   1558                         if data.get('sublevel', 0) + self.depth >= self.maxdepth:
   1559                             return []
   1560                     scrolllist.append((n.label, GetFromClass(QuickbarGroup, data)))
   1561             except Exception as e:
   1562                 log.LogWarn('Failed to load quickbar folder, reason: ', e)
   1563                 continue
   1564 
   1565         if scrolllist:
   1566             scrolllist = [ item[1] for item in localization.util.Sort(scrolllist, key=lambda x: x[0]) ]
   1567         tempScrolllist = []
   1568         if not self.selectFolder:
   1569             for id, n in notes.items():
   1570                 try:
   1571                     if type(n.label) == types.IntType:
   1572                         groupID = ('quickbar', id)
   1573                         tempScrolllist.append((evetypes.GetName(n.label), GetFromClass(QuickbarItem, {'label': evetypes.GetName(n.label),
   1574                           'typeID': n.label,
   1575                           'id': groupID,
   1576                           'itemID': None,
   1577                           'getIcon': 0,
   1578                           'sublevel': 0,
   1579                           'showinfo': 1,
   1580                           'GetMenu': self.GetQuickItemMenu,
   1581                           'DropData': self.GroupDropNode,
   1582                           'parent': n.parent,
   1583                           'selected': 1,
   1584                           'invtype': n.label,
   1585                           'extraText': n.get('extraText', '')})))
   1586                 except Exception as e:
   1587                     log.LogWarn('Failed to load_ quickbar type, reason: ', e)
   1588                     continue
   1589 
   1590         if tempScrolllist:
   1591             tempScrolllist = [ item[1] for item in localization.util.Sort(tempScrolllist, key=lambda x: x[0]) ]
   1592             scrolllist.extend(tempScrolllist)
   1593         return scrolllist
   1594 
   1595     def GroupMenu(self, node):
   1596         m = []
   1597         if node.sublevel < self.maxdepth:
   1598             m.append((MenuLabel('UI/Market/NewFolder'), self.NewFolder, (node.id[1], node)))
   1599         return m
   1600 
   1601     def QuickbarHasFolder(self):
   1602         import types
   1603         if settings.user.ui.Get('quickbar', {}):
   1604             for id, node in settings.user.ui.Get('quickbar', {}).items():
   1605                 if type(node.label) == types.UnicodeType:
   1606                     return True
   1607 
   1608         return False
   1609 
   1610     def SelectFolderMenu(self, node):
   1611         m = []
   1612         if node.sublevel < self.maxdepth:
   1613             if self.QuickbarHasFolder():
   1614                 m.append((MenuLabel('UI/Market/Marketbase/AddGroupToQuickbarFolder'), self.FolderPopUp, (node,)))
   1615             m.append((MenuLabel('UI/Market/Marketbase/AddGroupToQuickbarRoot'), self.FolderPopUp, (node, True)))
   1616         return m
   1617 
   1618     def FolderPopUp(self, node, root = False):
   1619         self.tempLastid = self.lastid
   1620         self.tempFolders = {}
   1621         self.depth, firstID = self.AddGroupParent(nodedata=node)
   1622         if root:
   1623             id = 0
   1624         else:
   1625             id = self.LoadQuickBar(selectFolder=1)
   1626         if id is not None and id is not False:
   1627             self.tempFolders[firstID].parent = id
   1628             for each in range(firstID, self.tempLastid + 1):
   1629                 self.folders[each] = self.tempFolders[each]
   1630 
   1631             self.lastid = self.tempLastid
   1632             settings.user.ui.Set('quickbar_lastid', self.lastid)
   1633 
   1634     def GetGroupSubContent(self, nodedata, newitems = 0):
   1635         scrolllist = []
   1636         notelist = self.GetItems(nodedata.id[1])
   1637         if len(notelist):
   1638             qi = 1
   1639             NoteListLength = len(notelist)
   1640             import types
   1641             for id, note in notelist.items():
   1642                 if type(note.label) == types.UnicodeType:
   1643                     entry = self.GroupCreateEntry((note.label, id), nodedata.sublevel + 1, selectGroup=self.selectFolder)
   1644                     if entry:
   1645                         scrolllist.append((note.label, entry))
   1646 
   1647             if scrolllist:
   1648                 scrolllist = [ item[1] for item in localization.util.Sort(scrolllist, key=lambda x: x[0]) ]
   1649             tempScrolllist = []
   1650             if not self.selectFolder:
   1651                 for id, note in notelist.items():
   1652                     if type(note.label) == types.IntType:
   1653                         entry = self.GroupCreateEntry((note.label, id), nodedata.sublevel + 1)
   1654                         if entry:
   1655                             tempScrolllist.append((evetypes.GetName(note.label), entry))
   1656 
   1657             if tempScrolllist:
   1658                 tempScrolllist = [ item[1] for item in localization.util.Sort(tempScrolllist, key=lambda x: x[0]) ]
   1659                 scrolllist.extend(tempScrolllist)
   1660             if len(nodedata.groupItems) != len(scrolllist):
   1661                 nodedata.groupItems = self.GroupGetContentIDList(nodedata.id)
   1662         return scrolllist
   1663 
   1664     def GroupCreateEntry(self, id, sublevel, selectGroup = 0):
   1665         note, id = self.folders[id[1]], id[1]
   1666         import types
   1667         tickerFolderID = settings.char.ui.Get(TICKER_SETTING_NAME, 0)
   1668         if type(note.label) == types.UnicodeType:
   1669             groupID = ('quickbar', id)
   1670             data = {'GetSubContent': self.GetGroupSubContent,
   1671              'label': note.label,
   1672              'id': groupID,
   1673              'groupItems': self.GroupGetContentIDList(groupID),
   1674              'iconMargin': 18,
   1675              'showlen': 0,
   1676              'state': 0,
   1677              'sublevel': sublevel,
   1678              'BlockOpenWindow': 1,
   1679              'parent': note.parent,
   1680              'MenuFunction': self.GroupMenu,
   1681              'ChangeLabel': self.GroupChangeLabel,
   1682              'DeleteFolder': self.GroupDeleteFolder,
   1683              'selected': 1,
   1684              'DropData': self.GroupDropNode,
   1685              'hideNoItem': self.selectFolder,
   1686              'allowGuids': ['listentry.QuickbarGroup', 'listentry.QuickbarItem'],
   1687              'selectGroup': selectGroup,
   1688              'isTickerFolder': tickerFolderID == id}
   1689             if self.selectFolder:
   1690                 data['OnDblClick'] = self.OnDblClick
   1691                 if data.get('sublevel', 0) + self.depth >= self.maxdepth:
   1692                     return []
   1693             return GetFromClass(QuickbarGroup, data)
   1694         if type(note.label) == types.IntType:
   1695             groupID = ('quickbar', id)
   1696             return GetFromClass(QuickbarItem, {'label': evetypes.GetName(note.label),
   1697              'typeID': note.label,
   1698              'id': groupID,
   1699              'itemID': None,
   1700              'getIcon': 0,
   1701              'sublevel': sublevel,
   1702              'showinfo': 1,
   1703              'GetMenu': self.GetQuickItemMenu,
   1704              'DropData': self.GroupDropNode,
   1705              'parent': note.parent,
   1706              'selected': 1,
   1707              'invtype': note.label,
   1708              'extraText': note.get('extraText', '')})
   1709         del self.folders[id]
   1710 
   1711     def OnDblClick(self, *args):
   1712         pass
   1713 
   1714     def GroupGetContentIDList(self, id):
   1715         ids = self.GetItems(id[1])
   1716         test = [ (self.folders[id].label, id) for id in ids ]
   1717         return test
   1718 
   1719     def GetItems(self, parent):
   1720         dict = {}
   1721         for id in self.folders:
   1722             if self.folders[id].parent == parent:
   1723                 dict[id] = self.folders[id]
   1724 
   1725         return dict
   1726 
   1727     def NewFolderClick(self, *args):
   1728         self.NewFolder(0)
   1729 
   1730     def GroupChangeLabel(self, id, newname):
   1731         self.RenameFolder(id[1], name=newname)
   1732 
   1733     def RenameFolder(self, folderID = 0, entry = None, name = None, *args):
   1734         if name is None:
   1735             folderNameLabel = localization.GetByLabel('UI/Market/Marketbase/FolderName')
   1736             typeNewFolderNameLabel = localization.GetByLabel('UI/Market/Marketbase/TypeNewFolderName')
   1737             ret = utilWindows.NamePopup(folderNameLabel, typeNewFolderNameLabel, maxLength=20)
   1738             if ret is None:
   1739                 return self.folders[folderID].label
   1740             name = ret
   1741         self.folders[folderID].label = name
   1742         sm.ScatterEvent('OnMarketQuickbarChange')
   1743         return name
   1744 
   1745     def NewFolder(self, folderID = 0, node = None, *args):
   1746         folderNameLabel = localization.GetByLabel('UI/Market/Marketbase/FolderName')
   1747         typeFolderNameLabel = localization.GetByLabel('UI/Market/Marketbase/TypeFolderName')
   1748         ret = utilWindows.NamePopup(folderNameLabel, typeFolderNameLabel, maxLength=20)
   1749         if ret is not None:
   1750             self.lastid += 1
   1751             n = utillib.KeyVal()
   1752             n.parent = folderID
   1753             n.id = self.lastid
   1754             n.label = ret
   1755             self.folders[n.id] = n
   1756             settings.user.ui.Set('quickbar', self.folders)
   1757             settings.user.ui.Set('quickbar_lastid', self.lastid)
   1758             sm.ScatterEvent('OnMarketQuickbarChange')
   1759             return n
   1760 
   1761     def GroupDeleteFolder(self, id):
   1762         import types
   1763         noteID = id[1]
   1764         notes = self.GetItems(noteID)
   1765         for id, note in notes.items():
   1766             if type(note.label) == types.UnicodeType:
   1767                 self.GroupDeleteFolder((0, id))
   1768                 continue
   1769             self.DeleteFolderNote(id)
   1770 
   1771         self.DeleteFolderNote(noteID)
   1772         sm.ScatterEvent('OnMarketQuickbarChange')
   1773 
   1774     def DeleteFolderNote(self, noteID):
   1775         del self.folders[noteID]
   1776 
   1777     def GroupDropNode(self, id, nodes):
   1778         for node in nodes:
   1779             if getattr(node, 'id', None) and id[1] in self.folders:
   1780                 parent = self.folders[id[1]].parent
   1781                 shouldContinue = False
   1782                 while parent:
   1783                     if node.id[1] == parent or node.id[1] == id[1]:
   1784                         shouldContinue = True
   1785                         break
   1786                     parent = self.folders[parent].parent
   1787 
   1788                 if shouldContinue:
   1789                     continue
   1790             guid = getattr(node, '__guid__', None)
   1791             if guid in ('listentry.FittingEntry',):
   1792                 self.AddFittingFolder(node, id[1])
   1793                 continue
   1794             shouldContinue = False
   1795             for folderID, data in self.folders.items():
   1796                 if data.label == node.typeID and data.parent == id[1]:
   1797                     shouldContinue = True
   1798                     break
   1799 
   1800             if shouldContinue:
   1801                 continue
   1802             if guid in ('listentry.QuickbarItem', 'listentry.QuickbarGroup'):
   1803                 noteID = node.id[1]
   1804                 if uicore.uilib.Key(uiconst.VK_CONTROL):
   1805                     self.AddTypeToQuickBar(node.typeID, parent=id[1])
   1806                 elif noteID in self.folders and noteID != id[1]:
   1807                     self.folders[noteID].parent = id[1]
   1808             elif guid == 'listentry.GenericMarketItem':
   1809                 self.AddTypeToQuickBar(node.typeID, parent=id[1])
   1810             elif guid in ('xtriui.ShipUIModule', 'xtriui.InvItem', 'listentry.InvItem', 'listentry.InvAssetItem'):
   1811                 self.AddTypeToQuickBar(node.rec.typeID, parent=id[1])
   1812             elif isinstance(node, TypeDragData):
   1813                 typeID = node.typeID
   1814                 if can_view_market_details(typeID):
   1815                     self.AddTypeToQuickBar(typeID, parent=id[1])
   1816 
   1817         sm.ScatterEvent('OnMarketQuickbarChange')
   1818 
   1819     def OnScrollDrop(self, dropObj, nodes):
   1820         if self.sr.sbTabs.GetSelectedArgs() != 'quickbar':
   1821             return
   1822         self.OnQuickbarScrollDrop(dropObj, nodes)
   1823 
   1824     def OnQuickbarScrollDrop(self, dropObj, nodes):
   1825         for node in nodes:
   1826             guid = getattr(node, '__guid__', None)
   1827             if isinstance(node, TypeDragData):
   1828                 typeID = node.typeID
   1829                 if can_view_market_details(typeID):
   1830                     self.AddTypeToQuickBar(typeID)
   1831             elif guid == 'listentry.GenericMarketItem':
   1832                 self.AddTypeToQuickBar(node.typeID)
   1833             elif guid in ('xtriui.ShipUIModule', 'xtriui.InvItem', 'listentry.InvItem', 'listentry.InvAssetItem'):
   1834                 self.AddTypeToQuickBar(node.rec.typeID)
   1835             elif guid in ('listentry.QuickbarItem', 'listentry.QuickbarGroup'):
   1836                 self.folders[node.id[1]].parent = 0
   1837                 sm.ScatterEvent('OnMarketQuickbarChange')
   1838             elif guid == 'listentry.FittingEntry':
   1839                 self.AddFittingFolder(node)
   1840 
   1841     def AddFittingFolder(self, node, parent = 0):
   1842         self.lastid += 1
   1843         fittingGroup = utillib.KeyVal()
   1844         fittingGroup.parent = parent
   1845         fittingGroup.id = self.lastid
   1846         fittingGroup.label = node.label
   1847         self.folders[fittingGroup.id] = fittingGroup
   1848         settings.user.ui.Set('quickbar', self.folders)
   1849         settings.user.ui.Set('quickbar_lastid', self.lastid)
   1850         rackTypes = sm.GetService('fittingSvc').GetTypesByRack(node.fitting)
   1851         rackNames = {'hiSlots': const.effectHiPower,
   1852          'medSlots': const.effectMedPower,
   1853          'lowSlots': const.effectLoPower,
   1854          'rigSlots': const.effectRigSlot,
   1855          'subSystems': const.effectSubSystem,
   1856          'serviceSlots': const.effectServiceSlot}
   1857         for rack, contents in rackTypes.iteritems():
   1858             if len(contents):
   1859                 name = None
   1860                 if rack == 'drones':
   1861                     name = localization.GetByLabel('UI/Drones/Drones')
   1862                 elif rack == 'charges':
   1863                     name = localization.GetByLabel('UI/Generic/Charges')
   1864                 elif rack == 'ice':
   1865                     name = localization.GetByLabel('UI/Market/Marketbase/IceProducts')
   1866                 elif rack in rackNames:
   1867                     name = dogma.data.get_effect_display_name(rackNames[rack])
   1868                 self.lastid += 1
   1869                 n = utillib.KeyVal()
   1870                 n.parent = fittingGroup.id
   1871                 n.id = self.lastid
   1872                 n.label = name
   1873                 self.folders[n.id] = n
   1874                 cannotAddToQuickbar = []
   1875                 for typeID, count in contents.iteritems():
   1876                     if count > 1:
   1877                         extraText = count
   1878                     else:
   1879                         extraText = ''
   1880                     try:
   1881                         self.AddTypeToQuickBar(typeID, parent=n.id, extraText=extraText)
   1882                     except UserError as e:
   1883                         if e.msg == 'cannotTradeOnMarket':
   1884                             cannotAddToQuickbar.append(typeID)
   1885                         else:
   1886                             raise
   1887 
   1888                 settings.user.ui.Set('quickbar', self.folders)
   1889                 settings.user.ui.Set('quickbar_lastid', self.lastid)
   1890 
   1891         self.AddTypeToQuickBar(node.fitting.shipTypeID, parent=fittingGroup.id)
   1892         sm.ScatterEvent('OnMarketQuickbarChange')
   1893 
   1894     def ShouldShowType(self, typeID):
   1895         filterSkills = settings.user.ui.Get('showonlyskillsfor', 0)
   1896         filterCpuPower = settings.user.ui.Get('showhavecpuandpower', 0)
   1897         filterKnownSkills = settings.user.ui.Get('shownewskills', 0)
   1898         doesMeetReq = True
   1899         if filterSkills or filterCpuPower or filterKnownSkills:
   1900             currShip = sm.StartService('godma').GetItem(session.shipid)
   1901             doesMeetReq, hasSkills, hasPower, hasCpu, hasSkill = self.MeetsRequirements(typeID, ship=currShip, reqTypeSkills=filterSkills, reqTypeCpuPower=filterCpuPower, hasSkill=filterKnownSkills)
   1902         return doesMeetReq
   1903 
   1904     def FilterItemsForBrowse(self, marketGroupInfo):
   1905         filterNone = settings.user.ui.Get('showonlyavailable', 0)
   1906         ret = []
   1907         for typeID in marketGroupInfo.types:
   1908             ask = self.asksForMyRange.get(typeID, None)
   1909             if (not filterNone or ask) and self.ShouldShowType(typeID):
   1910                 ret.append(typeID)
   1911             elif typeID == typePlex and is_global_plex_market_experiment_enabled():
   1912                 ret.append(typeID)
   1913 
   1914         return ret
   1915 
   1916     def FilterItemsForGroupPage(self, marketGroupInfo):
   1917         filterNone = settings.user.ui.Get('showonlyavailable', 0)
   1918         marketSvc = sm.StartService('marketQuote')
   1919         ret = []
   1920         marketGroupID = marketGroupInfo.marketGroupID
   1921         for typeID in evetypes.GetTypeIDsByMarketGroup(marketGroupID):
   1922             if not evetypes.IsPublished(typeID):
   1923                 continue
   1924             ask = self.asksForMyRange.get(typeID, None)
   1925             if ask is None and typeID == typePlex and is_global_plex_market_experiment_enabled():
   1926                 plexAsks = self._GetPlexAsks()
   1927                 if typePlex in plexAsks:
   1928                     self.asksForMyRange[typePlex] = plexAsks[typePlex]
   1929             if ask is None and filterNone:
   1930                 continue
   1931             shouldShow = self.ShouldShowType(typeID)
   1932             if not shouldShow:
   1933                 continue
   1934             data = utillib.KeyVal()
   1935             data.typeID = typeID
   1936             data.price = getattr(ask, 'price', 0)
   1937             data.qty = getattr(ask, 'volRemaining', 0)
   1938             data.fmt_price = FmtISK(data.price) if data.price else localization.GetByLabel('UI/Market/Marketbase/NoneAvailable')
   1939             data.fmt_qty = FmtAmt(data.qty) if data.qty else '0'
   1940             data.jumps = marketSvc.GetStationDistance(ask.stationID, False) if ask else None
   1941             ret.append(data)
   1942 
   1943         return ret
   1944 
   1945     def MeetsRequirements(self, typeID, ship = None, reqTypeSkills = 0, reqTypeCpuPower = 0, hasSkill = 0):
   1946         haveReqSkill = True
   1947         haveReqPower = True
   1948         haveReqCpu = True
   1949         haveSkillAlready = True
   1950         categoryID = evetypes.GetCategoryID(typeID)
   1951         if hasSkill:
   1952             isSkill = categoryID == const.categorySkill
   1953             if isSkill:
   1954                 if self.mine.get(typeID, None) is not None:
   1955                     haveSkillAlready = False
   1956         if reqTypeSkills:
   1957             requiredSkills = sm.GetService('clientDogmaStaticSvc').GetRequiredSkills(typeID)
   1958             if requiredSkills:
   1959                 for skillID, level in requiredSkills.iteritems():
   1960                     if skillID not in self.mine or self.mine[skillID] < level:
   1961                         haveReqSkill = False
   1962                         break
   1963 
   1964             else:
   1965                 haveReqSkill = True
   1966         if reqTypeCpuPower:
   1967             havePower = 0
   1968             haveCpu = 0
   1969             isHardware = evetypes.IsCategoryHardwareByCategory(categoryID)
   1970             if isHardware:
   1971                 powerEffect = None
   1972                 powerIdx = None
   1973                 powerEffects = [const.effectHiPower, const.effectMedPower, const.effectLoPower]
   1974                 for effect in dogma.data.get_type_effects(typeID):
   1975                     if effect.effectID in powerEffects:
   1976                         powerEffect = dogma.data.get_effect(effect.effectID)
   1977                         powerIdx = powerEffects.index(effect.effectID)
   1978                         break
   1979 
   1980                 powerLoad = 0
   1981                 cpuLoad = 0
   1982                 shipID = eveCfg.GetActiveShip()
   1983                 if shipID is not None and powerIdx is not None:
   1984                     dgmAttr = sm.GetService('godma').GetType(typeID)
   1985                     for attribute in dgmAttr.displayAttributes:
   1986                         if attribute.attributeID in (const.attributeCpuLoad, const.attributeCpu):
   1987                             cpuLoad += attribute.value
   1988                         elif attribute.attributeID in (const.attributePowerLoad, const.attributePower):
   1989                             powerLoad += attribute.value
   1990 
   1991                     dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation()
   1992                     havePower = dogmaLocation.GetAttributeValue(shipID, const.attributePowerOutput) > powerLoad
   1993                     haveCpu = dogmaLocation.GetAttributeValue(shipID, const.attributeCpuOutput) > cpuLoad
   1994                 if powerEffect:
   1995                     haveReqPower = havePower
   1996                     haveReqCpu = haveCpu
   1997         meetsReq = haveReqSkill and haveReqPower and haveReqCpu and haveSkillAlready
   1998         return (meetsReq,
   1999          haveReqSkill,
   2000          haveReqPower,
   2001          haveReqCpu,
   2002          haveSkillAlready)
   2003 
   2004     def OnChange_minEdit_market_filter_price(self, value, *args):
   2005         newValue = self.ConvertInput(value, 2)
   2006         settings.user.ui.Set('minEdit_market_filter_price', newValue)
   2007 
   2008     def OnChange_maxEdit_market_filter_price(self, value, *args):
   2009         newValue = self.ConvertInput(value, 2)
   2010         settings.user.ui.Set('maxEdit_market_filter_price', newValue)
   2011 
   2012     def OnChange_minEdit_market_filter_jump(self, value, *args):
   2013         newValue = self.ConvertInput(value)
   2014         settings.user.ui.Set('minEdit_market_filter_jumps', newValue)
   2015 
   2016     def OnChange_maxEdit_market_filter_jumps(self, value, *args):
   2017         newValue = self.ConvertInput(value)
   2018         settings.user.ui.Set('maxEdit_market_filter_jumps', newValue)
   2019 
   2020     def OnChange_minEdit_market_filter_quantity(self, value, *args):
   2021         newValue = self.ConvertInput(value)
   2022         settings.user.ui.Set('minEdit_market_filter_quantity', newValue)
   2023 
   2024     def OnChange_maxEdit_market_filter_quantity(self, value, *args):
   2025         newValue = self.ConvertInput(value)
   2026         settings.user.ui.Set('maxEdit_market_filter_quantity', newValue)
   2027 
   2028     def OnChange_minEdit_market_filters_sellorderdev(self, value, *args):
   2029         newValue = self.ConvertInput(value)
   2030         settings.user.ui.Set('minEdit_market_filters_sellorderdev', newValue)
   2031 
   2032     def OnChange_maxEdit_market_filters_sellorderdev(self, value, *args):
   2033         newValue = self.ConvertInput(value)
   2034         settings.user.ui.Set('maxEdit_market_filters_sellorderdev', newValue)
   2035 
   2036     def OnChange_minEdit_market_filters_buyorderdev(self, value, *args):
   2037         newValue = self.ConvertInput(value)
   2038         settings.user.ui.Set('minEdit_market_filters_buyorderdev', newValue)
   2039 
   2040     def OnChange_maxEdit_market_filters_buyorderdev(self, value, *args):
   2041         newValue = self.ConvertInput(value)
   2042         settings.user.ui.Set('maxEdit_market_filters_buyorderdev', newValue)
   2043 
   2044     def ConvertInput(self, value, numDecimals = None):
   2045         if not value or value == '-':
   2046             value = 0
   2047         value = self.ConvertToPoint(value, numDecimals)
   2048         return value
   2049 
   2050     def FiltersInUse1(self):
   2051         filterUsed = False
   2052         browseFilters = [(localization.GetByLabel('UI/Market/ShowOnlyAvailable'), 'showonlyavailable'),
   2053          (localization.GetByLabel('UI/Market/Marketbase/FilterBySkills'), 'showonlyskillsfor'),
   2054          (localization.GetByLabel('UI/Market/Marketbase/FilterByCPUAndPowergrid'), 'showhavecpuandpower'),
   2055          (localization.GetByLabel('UI/Market/Marketbase/FilterByUntrainedSkills'), 'shownewskills')]
   2056         retBrowse = ''
   2057         for label, filter in browseFilters:
   2058             if settings.user.ui.Get('%s' % filter, 0):
   2059                 filterUsed = True
   2060                 temp = '%s<br>' % label
   2061                 retBrowse += temp
   2062 
   2063         if retBrowse == '' and not settings.user.ui.Get('showonlyavailable', 0):
   2064             temp = '%s<br>' % localization.GetByLabel('UI/Common/Show all')
   2065             retBrowse += temp
   2066         if retBrowse:
   2067             retBrowse = '%s<br>%s' % (localization.GetByLabel('UI/Market/Marketbase/BrowseFilters'), retBrowse)
   2068             retBrowse = retBrowse[:-1]
   2069         return (retBrowse, filterUsed)
   2070 
   2071     def FiltersInUse2(self, *args):
   2072         ret = ''
   2073         jumpFilter = [(localization.GetByLabel('UI/Market/Marketbase/Jumps'), 'market_filter_jumps')]
   2074         detailFilters = [(localization.GetByLabel('UI/Common/Quantity'), 'market_filter_quantity'),
   2075          (localization.GetByLabel('UI/Market/Marketbase/Price'), 'market_filter_price'),
   2076          (localization.GetByLabel('UI/Market/Marketbase/SellOrdersDeviation'), 'market_filters_sellorderdev'),
   2077          (localization.GetByLabel('UI/Market/Marketbase/BuyOrdersDeviation'), 'market_filters_buyorderdev')]
   2078         secFilters = [(localization.GetByLabel('UI/Market/Marketbase/NoHighSecurity'), 'market_filter_highsec'), (localization.GetByLabel('UI/Market/Marketbase/NoLowSecurity'), 'market_filter_lowsec'), (localization.GetByLabel('UI/Market/Marketbase/NoZeroSecurity'), 'market_filter_zerosec')]
   2079         retJump = ''
   2080         if not does_global_market_apply(self._typeID):
   2081             for label, filter in jumpFilter:
   2082                 if settings.user.ui.Get('%s' % filter, 0):
   2083                     min = float(GetNumericValueFromSetting('minEdit_%s' % filter))
   2084                     max = float(GetNumericValueFromSetting('maxEdit_%s' % filter))
   2085                     andUp = False
   2086                     if min > max:
   2087                         andUp = True
   2088                         temp = '%s<br>' % localization.GetByLabel('UI/Market/Marketbase/FilterRangeAndUp', filterType=label, minValue=min)
   2089                     else:
   2090                         temp = '%s<br>' % localization.GetByLabel('UI/Market/Marketbase/FilterRangeTo', filterType=label, minValue=min, maxValue=max)
   2091                     retJump += temp
   2092 
   2093         retDetail = retJump
   2094         for label, filter in detailFilters:
   2095             if settings.user.ui.Get('%s' % filter, 0):
   2096                 min = float(GetNumericValueFromSetting('minEdit_%s' % filter))
   2097                 max = float(GetNumericValueFromSetting('maxEdit_%s' % filter))
   2098                 andUp = False
   2099                 if min >= max:
   2100                     andUp = filter not in ('market_filters_sellorderdev', 'market_filters_buyorderdev')
   2101                     if andUp:
   2102                         temp = '%s<br>' % localization.GetByLabel('UI/Market/Marketbase/FilterRangeAndUp', filterType=label, minValue=min)
   2103                 if not andUp:
   2104                     temp = '%s<br>' % localization.GetByLabel('UI/Market/Marketbase/FilterRangeTo', filterType=label, minValue=min, maxValue=max)
   2105                 retDetail += temp
   2106 
   2107         if retDetail:
   2108             retDetail = '%s<br>%s' % (localization.GetByLabel('UI/Market/Marketbase/DetailFilters'), retDetail)
   2109         retSecurity = ''
   2110         if not does_global_market_apply(self._typeID):
   2111             for label, filter in secFilters:
   2112                 if not settings.user.ui.Get('%s' % filter, 0):
   2113                     temp = '%s<br>' % label
   2114                     retSecurity += temp
   2115 
   2116             if retSecurity:
   2117                 retSecurity = '%s<br>%s' % (localization.GetByLabel('UI/Market/Marketbase/SecurityFilters'), retSecurity)
   2118         for each in [retDetail, retSecurity]:
   2119             if each:
   2120                 ret += '%s<br>' % each
   2121 
   2122         if ret:
   2123             ret = ret[:-1]
   2124         return ret
   2125 
   2126     def CheckboxRange(self, boxes, container):
   2127         for height, label, configname, retval, checked, groupname, numRange, hint, isFloat in boxes:
   2128             box = Container(name='checkbox_%s' % configname, parent=container, align=uiconst.TOTOP, padBottom=const.defaultPadding)
   2129             rbox = Container(name='checkbox_%s' % configname, parent=box, align=uiconst.TORIGHT, width=180)
   2130             cb = RadioButton(text='%s' % label, parent=box, settingsKey=configname, retval=retval, checked=checked, groupname=groupname, callback=self.OnCheckboxChangeSett, align=uiconst.TOPLEFT, height=height, width=150)
   2131             if numRange:
   2132                 funcKey = '%s_min' % configname
   2133                 fromLabel = localization.GetByLabel('UI/Common/FromNumber')
   2134                 minText = eveLabel.EveLabelMedium(text=fromLabel, parent=rbox, align=uiconst.CENTERLEFT, state=uiconst.UI_NORMAL)
   2135                 minSetValue = GetNumericValueFromSetting('minEdit_%s' % configname)
   2136                 if not isFloat:
   2137                     minEdit = SingleLineEditInteger(name='minEdit_%s' % configname, setvalue=minSetValue, parent=rbox, left=minText.left + minText.textwidth + const.defaultPadding, top=0, align=uiconst.CENTERLEFT, minValue=numRange[0], maxValue=numRange[1], OnChange=self.OnChangeFuncs[funcKey])
   2138                     minEdit.AutoFitToText(FmtAmt(sys.maxint))
   2139                 else:
   2140                     minEdit = SingleLineEditFloat(name='minEdit_%s' % configname, setvalue=minSetValue, parent=rbox, left=minText.left + minText.textwidth + const.defaultPadding, top=0, align=uiconst.CENTERLEFT, minValue=numRange[0], maxValue=numRange[1], decimalPlaces=2, OnChange=self.OnChangeFuncs[funcKey])
   2141                     minEdit.AutoFitToText(FmtAmt(float(MAX_ORDER_PRICE), showFraction=2))
   2142                 funcKey = '%s_max' % configname
   2143                 maxText = eveLabel.EveLabelMedium(text=localization.GetByLabel('UI/Common/ToNumber'), parent=rbox, left=minEdit.left + minEdit.width + const.defaultPadding, align=uiconst.CENTERLEFT, state=uiconst.UI_NORMAL)
   2144                 maxSetValue = GetNumericValueFromSetting('maxEdit_%s' % configname)
   2145                 if not isFloat:
   2146                     maxEdit = SingleLineEditInteger(name='maxEdit_%s' % configname, setvalue=maxSetValue, parent=rbox, left=maxText.left + maxText.textwidth + const.defaultPadding, top=0, align=uiconst.CENTERLEFT, minValue=numRange[0], maxValue=numRange[1], OnChange=self.OnChangeFuncs[funcKey])
   2147                     maxEdit.AutoFitToText(FmtAmt(sys.maxint))
   2148                 else:
   2149                     maxEdit = SingleLineEditFloat(name='maxEdit_%s' % configname, setvalue=maxSetValue, parent=rbox, left=maxText.left + maxText.textwidth + const.defaultPadding, top=0, align=uiconst.CENTERLEFT, minValue=numRange[0], maxValue=numRange[1], decimalPlaces=2, OnChange=self.OnChangeFuncs[funcKey])
   2150                     maxEdit.AutoFitToText(FmtAmt(float(MAX_ORDER_PRICE), showFraction=2))
   2151                 rbox.width = maxEdit.left + maxEdit.width + const.defaultPadding
   2152                 box.height = rbox.height = max(cb.height, minEdit.height, minText.height, maxEdit.height, maxText.height)
   2153             if hint:
   2154                 cb.hint = hint
   2155 
   2156     def SetupFilters(self):
   2157         settings.user.ui.Set('showonlyavailable', settings.user.ui.Get('showonlyavailable', True))
   2158         settings.user.ui.Set('showonlyskillsfor', settings.user.ui.Get('showonlyskillsfor', False))
   2159         settings.user.ui.Set('showhavecpuandpower', settings.user.ui.Get('showhavecpuandpower', False))
   2160         settings.user.ui.Set('shownewskills', settings.user.ui.Get('shownewskills', False))
   2161         settings.user.ui.Set('market_filter_price', settings.user.ui.Get('market_filter_price', False))
   2162         settings.user.ui.Set('minEdit_market_filter_price', GetNumericValueFromSetting('minEdit_market_filter_price'))
   2163         settings.user.ui.Set('maxEdit_market_filter_price', GetNumericValueFromSetting('maxEdit_market_filter_price', 100000))
   2164         settings.user.ui.Set('market_filter_jumps', settings.user.ui.Get('market_filter_jumps', False))
   2165         settings.user.ui.Set('minEdit_market_filter_jumps', GetNumericValueFromSetting('minEdit_market_filter_jumps'))
   2166         settings.user.ui.Set('maxEdit_market_filter_jumps', GetNumericValueFromSetting('maxEdit_market_filter_jumps', 20))
   2167         settings.user.ui.Set('market_filter_quantity', settings.user.ui.Get('market_filter_quantity', False))
   2168         settings.user.ui.Set('minEdit_market_filter_quantity', GetNumericValueFromSetting('minEdit_market_filter_quantity'))
   2169         settings.user.ui.Set('maxEdit_market_filter_quantity', GetNumericValueFromSetting('maxEdit_market_filter_quantity', 1000))
   2170         settings.user.ui.Set('market_filter_zerosec', settings.user.ui.Get('market_filter_zerosec', True))
   2171         settings.user.ui.Set('market_filter_lowsec', settings.user.ui.Get('market_filter_lowsec', True))
   2172         settings.user.ui.Set('market_filter_highsec', settings.user.ui.Get('market_filter_highsec', True))
   2173         settings.user.ui.Set('market_filters_sellorderdev', settings.user.ui.Get('market_filters_sellorderdev', False))
   2174         settings.user.ui.Set('minEdit_market_filters_sellorderdev', GetNumericValueFromSetting('minEdit_market_filters_sellorderdev'))
   2175         settings.user.ui.Set('maxEdit_market_filters_sellorderdev', GetNumericValueFromSetting('maxEdit_market_filters_sellorderdev'))
   2176         settings.user.ui.Set('market_filters_buyorderdev', settings.user.ui.Get('market_filters_buyorderdev', False))
   2177         settings.user.ui.Set('minEdit_market_filters_buyorderdev', GetNumericValueFromSetting('minEdit_market_filters_buyorderdev'))
   2178         settings.user.ui.Set('maxEdit_market_filters_buyorderdev', GetNumericValueFromSetting('maxEdit_market_filters_buyorderdev'))
   2179         settings.user.ui.Set('quickbar', settings.user.ui.Get('quickbar', {}))
   2180         settings.user.ui.Set('autorefresh', settings.user.ui.Get('autorefresh', True))
   2181 
   2182     def AddGroupParent(self, nodedata = None, newitems = 0):
   2183         marketGroupID = None
   2184         self.parentDictionary = {}
   2185         if nodedata:
   2186             marketGroupID = nodedata.marketGroupInfo.marketGroupID
   2187         firstID = self.InsertQuickbarGroupItem(nodedata.marketGroupInfo.marketGroupName, 0)
   2188         self.parentDictionary[marketGroupID] = self.tempLastid
   2189         scrolllist = self.AddGroupChildren(nodedata=nodedata)
   2190         self.test = QuickbarEntries()
   2191         depth = self.test.Load(contentList=scrolllist, maxDepth=5, parentDepth=nodedata.sublevel)
   2192         self.test.Close()
   2193         return (depth, firstID)
   2194 
   2195     def AddGroupChildren(self, nodedata = None):
   2196         scrolllist = []
   2197         if nodedata and nodedata.marketGroupInfo.hasTypes:
   2198             parent = self.parentDictionary.get(nodedata.marketGroupInfo.marketGroupID, 0)
   2199             for typeID in nodedata.typeIDs:
   2200                 self.InsertQuickbarGroupItem(typeID, parent)
   2201 
   2202         else:
   2203             marketGroupID = None
   2204             level = 0
   2205             if nodedata:
   2206                 marketGroupID = nodedata.marketGroupInfo.marketGroupID
   2207                 level = nodedata.sublevel + 1
   2208             grouplist = sm.GetService('marketutils').GetMarketGroups()[marketGroupID]
   2209             for marketGroupInfo in grouplist:
   2210                 if not len(marketGroupInfo.types):
   2211                     continue
   2212                 if self.destroyed:
   2213                     return
   2214                 items = [ typeID for typeID in marketGroupInfo.types ]
   2215                 groupID = (marketGroupInfo.marketGroupName, marketGroupInfo.marketGroupID)
   2216                 data = {'GetSubContent': self.AddGroupChildren,
   2217                  'id': groupID,
   2218                  'typeIDs': items,
   2219                  'marketGroupInfo': marketGroupInfo,
   2220                  'sublevel': level}
   2221                 parent = self.parentDictionary.get(marketGroupInfo.parentGroupID, 0)
   2222                 self.InsertQuickbarGroupItem(marketGroupInfo.marketGroupName, parent)
   2223                 self.parentDictionary[marketGroupInfo.marketGroupID] = self.tempLastid
   2224                 scrolllist.append(((marketGroupInfo.hasTypes, marketGroupInfo.marketGroupName.lower()), GetFromClass(QuickbarGroup, data)))
   2225 
   2226         return scrolllist
   2227 
   2228     def InsertQuickbarGroupItem(self, label, parent, extraText = ''):
   2229         self.tempLastid += 1
   2230         n = utillib.KeyVal()
   2231         n.parent = parent
   2232         n.id = self.tempLastid
   2233         n.label = label
   2234         n.extraText = extraText
   2235         self.tempFolders[n.id] = n
   2236         return n.id
   2237 
   2238     def ListWnd(self, lst, listtype = None, caption = None, hint = None, ordered = 0, minw = 200, minh = 256, minChoices = 1, maxChoices = 1, initChoices = [], validator = None, isModal = 1, scrollHeaders = [], iconMargin = 0, contentList = None):
   2239         if caption is None:
   2240             caption = localization.GetByLabel('UI/Market/Marketbase/SelectAFolder')
   2241         if not isModal:
   2242             SelectFolderWindow.CloseIfOpen()
   2243         wnd = SelectFolderWindow.Open(lst=[], listtype=listtype, ordered=ordered, minw=minw, minh=minh, caption=caption, minChoices=minChoices, maxChoices=maxChoices, initChoices=initChoices, validator=validator, scrollHeaders=scrollHeaders, iconMargin=iconMargin)
   2244         wnd.scroll.Load(contentList=contentList)
   2245         wnd.Error(wnd.GetError(checkNumber=0))
   2246         if hint:
   2247             wnd.SetHint('<center>' + hint)
   2248         if isModal:
   2249             wnd.DefineButtons(uiconst.OKCANCEL)
   2250             if wnd.ShowModal() == uiconst.ID_OK:
   2251                 return wnd.result
   2252             else:
   2253                 return
   2254         else:
   2255             wnd.DefineButtons(uiconst.CLOSE)
   2256             wnd.Maximize()
   2257 
   2258     def ConvertToPoint(self, value, numDigits = 0):
   2259         ret = ConvertDecimal(value, ',', '.', numDigits)
   2260         if numDigits is not None:
   2261             ret = '%.*f' % (numDigits, float(ret))
   2262         return ret
   2263 
   2264     def StoreTypeInHistory(self, typeID):
   2265         if len(self.historyData) > 0:
   2266             newHistory = self.historyData[:self.historyIdx + 1]
   2267             lastTypeID = newHistory[min(self.historyIdx, len(self.historyData) - 1)]
   2268             if lastTypeID != typeID:
   2269                 newHistory.append(typeID)
   2270                 self.historyIdx += 1
   2271                 self.historyData = newHistory
   2272         else:
   2273             self.historyData.append(typeID)
   2274             self.historyIdx = 0
   2275         self.ChangeBackAndForwardButtons()
   2276 
   2277     def GoBack(self, *args):
   2278         if len(self.historyData) > 1 and self.historyIdx > 0:
   2279             self.historyIdx = max(0, self.historyIdx - 1)
   2280             typeID = self.historyData[min(self.historyIdx, len(self.historyData) - 1)]
   2281             marketWnd = RegionalMarket.GetIfOpen()
   2282             if marketWnd:
   2283                 marketWnd.LoadTypeID_Ext(typeID)
   2284 
   2285     def GoForward(self, *args):
   2286         if self.historyIdx is None:
   2287             return
   2288         if len(self.historyData) > self.historyIdx + 1:
   2289             self.historyIdx = max(0, self.historyIdx + 1)
   2290             typeID = self.historyData[min(self.historyIdx, len(self.historyData) - 1)]
   2291             marketWnd = RegionalMarket.GetIfOpen()
   2292             if marketWnd:
   2293                 marketWnd.LoadTypeID_Ext(typeID)
   2294 
   2295     def ChangeBackAndForwardButtons(self):
   2296         if self.historyIdx == 0:
   2297             self.DisableArrow(self.goBackBtn)
   2298         else:
   2299             self.EnableArrow(self.goBackBtn)
   2300         if self.historyIdx >= len(self.historyData) - 1:
   2301             self.DisableArrow(self.goForwardBtn)
   2302         else:
   2303             self.EnableArrow(self.goForwardBtn)
   2304 
   2305     def DisableArrow(self, btn):
   2306         btn.Disable()
   2307 
   2308     def EnableArrow(self, btn):
   2309         btn.Enable()
   2310 
   2311     def GetImportMenu(self, menuParent):
   2312         hint = GetByLabel('UI/Market/Marketbase/ImportQuickbarFormatHint', typeID=const.typeSpaceshipCommand)
   2313         menuParent.AddIconEntry(icon=ACTION_ICON, text=GetByLabel('UI/Market/Marketbase/ImportNewQuickbar'), callback=self.ImportQuickbar, hint=hint)
   2314         menuParent.AddIconEntry(icon=ACTION_ICON, text=GetByLabel('UI/Market/Marketbase/ImportQuickbarReplace'), callback=self.ImportQuickbarReplace, hint=hint)
   2315 
   2316     def ImportQuickbarReplace(self):
   2317         self.ImportQuickbar(replace=True)
   2318 
   2319     def ImportQuickbar(self, replace = False):
   2320         typeIDFinder = sm.GetService('marketutils').GetMarketTypeIDFinder()
   2321         quickbarImporter = QuickbarImporter(typeIDFinder)
   2322         text = GetClipboardData()
   2323         if replace:
   2324             lastID = 0
   2325         else:
   2326             lastID = self.lastid
   2327         bundleDict = quickbarImporter.ImportText(text, lastID + 1)
   2328         if bundleDict:
   2329             quickbar = {} if replace else settings.user.ui.Get('quickbar', {})
   2330             newQuickbarItems = {k:utillib.KeyVal(v) for k, v in bundleDict.iteritems()}
   2331             quickbar.update(newQuickbarItems)
   2332             settings.user.ui.Set('quickbar', quickbar)
   2333             settings.user.ui.Set('quickbar_lastid', max(bundleDict))
   2334             sm.ScatterEvent('OnMarketQuickbarChange')
   2335 
   2336     def GetExportMenu(self, menuParent):
   2337         menuParent.AddIconEntry(icon=ACTION_ICON, text=GetByLabel('UI/Market/Marketbase/CopyQuickbarToClipboard'), callback=self.GetExportedQuickbarLocalized)
   2338         if self.AreExtraExportOptionsAvailable():
   2339             menuParent.AddIconEntry(icon=ACTION_ICON, text=GetByLabel('UI/Market/Marketbase/CopyQuickbarToClipboardInEnglish'), callback=self.GetExportedQuickbar)
   2340 
   2341     def GetExportedQuickbarLocalized(self):
   2342         return self._GetExportedQuickbar(True)
   2343 
   2344     def GetExportedQuickbar(self, *args):
   2345         return self._GetExportedQuickbar(False)
   2346 
   2347     def _GetExportedQuickbar(self, isLocalized = True):
   2348         quickbar = settings.user.ui.Get('quickbar', {})
   2349         exporter = QuickbarExporter()
   2350         exportText = exporter.ExportQuickbarToClipboard(quickbar, isLocalized)
   2351         blue.pyos.SetClipboardData(exportText)
   2352 
   2353     def AreExtraExportOptionsAvailable(self):
   2354         extraOptions = boot.region != 'optic' and session.languageID != 'EN'
   2355         return extraOptions
   2356 
   2357 
   2358 class MarketGroupEntry(ContainerAutoSize):
   2359     default_name = 'MarketGroupEntry'
   2360     default_align = uiconst.TOTOP
   2361     PADDING_GENERIC = const.defaultPadding * 2
   2362 
   2363     def ApplyAttributes(self, attributes):
   2364         ContainerAutoSize.ApplyAttributes(self, attributes)
   2365         data = attributes.data
   2366         typeID = data.invType
   2367         self.topCont = ContainerAutoSize(name='topCont', parent=self, align=uiconst.TOTOP)
   2368         typeImage = MarketGroupItemImage(parent=self.topCont, align=uiconst.TOPLEFT, width=64, height=64, state=uiconst.UI_NORMAL)
   2369         typeImage.attrs = data.typeImageAttributes
   2370         typeImage.typeName = evetypes.GetName(typeID)
   2371         typeImage.LoadTypeIcon(typeID)
   2372         typeImage.SetOmegaIconState(typeID)
   2373         typeNameLabel = eveLabel.EveCaptionMedium(parent=self.topCont, align=uiconst.TOPLEFT, left=typeImage.left + typeImage.width + self.PADDING_GENERIC, text=typeImage.typeName, name='typeNameLabel')
   2374         InfoIcon(parent=self.topCont, align=uiconst.TOPLEFT, typeID=typeID, left=typeNameLabel.left + typeNameLabel.width + const.defaultPadding, top=typeNameLabel.top + (typeNameLabel.height - 16) / 2)
   2375         RequirementsContainer(parent=self.topCont, align=uiconst.TOPLEFT, top=typeNameLabel.top + typeNameLabel.height + const.defaultPadding, left=typeNameLabel.left, width=200, typeID=typeID)
   2376         if typeID == const.typePlex:
   2377             PurchaseButton(name='buyPlexButton', parent=self.topCont, align=uiconst.TOPLEFT, top=typeNameLabel.top + typeNameLabel.height + 8, left=typeNameLabel.left, width=70, height=20, fontsize=12, func=lambda *args: uicore.cmd.CmdBuyPlex(logContext=FROM_PLEX_MARKET_GROUP), text=localization.GetByLabel('UI/VirtualGoodsStore/Buttons/BuyPlex'))
   2378         combinedDescription = data.bestPrice + '<br><fontsize=16><b>' + data.marketData.fmt_price + '</b></fontsize>'
   2379         if data.unitsAvailable:
   2380             combinedDescription += '<br>' + data.unitsAvailable
   2381         if HasTraits(data.invType):
   2382             TraitsContainer(parent=self, typeID=data.invType, align=uiconst.TOTOP, padding=(self.PADDING_GENERIC,
   2383              4,
   2384              self.PADDING_GENERIC,
   2385              self.PADDING_GENERIC))
   2386         elif data.description:
   2387             combinedDescription = data.description + '<br><br>' + combinedDescription
   2388         eveLabel.Label(parent=self, align=uiconst.TOTOP, padding=(0,
   2389          4,
   2390          self.PADDING_GENERIC,
   2391          0), state=uiconst.UI_NORMAL, name='descriptionLabel', text=combinedDescription)
   2392         button_group = ButtonGroup(name='buttonCont', parent=self, align=uiconst.TOTOP, top=16, button_alignment=AxisAlignment.START, density=Density.COMPACT)
   2393         Button(parent=button_group, label=localization.GetByLabel('UI/Market/Marketbase/CommandViewDetails'), func=sm.GetService('marketutils').ShowMarketDetails, args=(typeID, None), hint=localization.GetByLabel('Tooltips/Market/MarketGroupsViewDetails'), variant=ButtonVariant.GHOST)
   2394         if comparisonUtil.is_comparable(typeID):
   2395             Button(parent=button_group, label=localization.GetByLabel('UI/Compare/CompareButton'), func=sm.GetService('menu').CompareType, args=(typeID, None), variant=ButtonVariant.GHOST)
   2396         if data.marketData.qty:
   2397             buyLabel = localization.GetByLabel('UI/Market/MarketQuote/CommandBuy')
   2398             buttonName = 'Buy_Btn'
   2399         else:
   2400             buyLabel = localization.GetByLabel('UI/Market/Marketbase/CommandPlaceBuyOrder')
   2401             buttonName = 'Place Buy Order_Btn'
   2402         if data.marketData.qty:
   2403             buyHint = localization.GetByLabel('Tooltips/Market/MarketGroupsBuyButton')
   2404         else:
   2405             buyHint = localization.GetByLabel('Tooltips/Market/MarketGroupsPlaceBuy')
   2406         Button(parent=button_group, name=buttonName, label=buyLabel, func=sm.GetService('marketutils').Buy, args=(typeID, None), hint=buyHint, variant=ButtonVariant.NORMAL)
   2407         if industryCommon.IsBlueprintCategory(evetypes.GetCategoryID(typeID)):
   2408             from eve.client.script.ui.shared.industry.industryWnd import Industry
   2409             Button(parent=button_group, label=localization.GetByLabel('UI/Industry/ViewInIndustry'), func=Industry.OpenOrShowBlueprint, args=(None, typeID), variant=ButtonVariant.GHOST)
   2410         DividerLine(parent=self, align=uiconst.TOTOP, top=16, padBottom=16)
   2411 
   2412 
   2413 class MarketData(Container):
   2414     __guid__ = 'form.MarketData'
   2415     __notifyevents__ = ['OnPathfinderSettingsChange', 'OnSessionChanged']
   2416 
   2417     def ApplyAttributes(self, attributes):
   2418         Container.ApplyAttributes(self, attributes)
   2419         self.name = 'marketQuote'
   2420         self.caption = 'Market Data'
   2421         self.prefs = 'marketquote'
   2422         self.invType = None
   2423         self.loading = None
   2424         self.scrollHeight = 0
   2425         self.allMyOrderIDs = set()
   2426         self.buyheadersPointers = {localization.GetByLabel('UI/Market/Marketbase/Jumps'): pConst.UNIQUE_NAME_MARKET_SELLERS_JUMP_COL,
   2427          localization.GetByLabel('UI/Common/Quantity'): pConst.UNIQUE_NAME_MARKET_SELLERS_QTY_COL,
   2428          localization.GetByLabel('UI/Market/Marketbase/Price'): pConst.UNIQUE_NAME_MARKET_SELLERS_PRICE_COL}
   2429         self.sellheadersPointers = {localization.GetByLabel('UI/Market/Marketbase/Jumps'): pConst.UNIQUE_NAME_MARKET_BUYERS_JUMP_COL,
   2430          localization.GetByLabel('UI/Common/Quantity'): pConst.UNIQUE_NAME_MARKET_BUYERS_QTY_COL,
   2431          localization.GetByLabel('UI/Market/Marketbase/Price'): pConst.UNIQUE_NAME_MARKET_BUYERS_PRICE_COL}
   2432         self.avgSellPrice = None
   2433         self.avgBuyPrice = None
   2434         self.sr.buyParent = Container(name='buyParent', parent=self, align=uiconst.TOTOP, height=64, uniqueUiName=pConst.UNIQUE_NAME_MARKET_SELLER_LIST)
   2435         buyLeft = Container(name='buyLeft', parent=self.sr.buyParent, align=uiconst.TOTOP, height=20)
   2436         sellersLabel = localization.GetByLabel('UI/Market/Marketbase/Sellers')
   2437         cap = eveLabel.EveCaptionMedium(text=sellersLabel, parent=buyLeft, align=uiconst.TOPLEFT)
   2438         buyLeft.height = max(buyLeft.height, cap.textheight)
   2439         a = eveLabel.EveLabelSmall(text='', parent=buyLeft, left=24, top=0, state=uiconst.UI_NORMAL, align=uiconst.TOPRIGHT)
   2440         a.OnClick = self.BuyClick
   2441         a.GetMenu = None
   2442         self.buyFiltersActive1 = a
   2443         a = eveLabel.EveLabelSmall(text='', parent=buyLeft, left=24, top=14, state=uiconst.UI_NORMAL, align=uiconst.TOPRIGHT)
   2444         a.OnClick = self.BuyClick
   2445         a.GetMenu = None
   2446         self.buyFiltersActive2 = a
   2447         self.sr.buyIcon = Sprite(name='buyIcon', parent=buyLeft, width=16, height=16, left=6, top=0, align=uiconst.TOPRIGHT)
   2448         self.sr.buyIcon.OnClick = self.BuyClick
   2449         self.sr.buyIcon.state = uiconst.UI_HIDDEN
   2450         button_group = ButtonGroup(parent=self, align=uiconst.TOBOTTOM, padTop=16, button_alignment=AxisAlignment.END)
   2451         Button(parent=button_group, name='Place Buy Order_Btn', label=localization.GetByLabel('UI/Market/Marketbase/CommandPlaceBuyOrder'), func=self.PlaceOrder, args=('buy',), variant=ButtonVariant.PRIMARY, texturePath=eveicon.isk)
   2452         Button(parent=button_group, label=localization.GetByLabel('UI/Inventory/ItemActions/FindInContracts'), func=self.FindInContracts, args=())
   2453         Button(parent=button_group, label=localization.GetByLabel('UI/Market/Marketbase/ExportToFile'), func=self.ExportToFile, hint=localization.GetByLabel('Tooltips/Market/MarketDetailsExportFile'), variant=ButtonVariant.GHOST)
   2454         divider = Divider(name='divider', parent=self, align=uiconst.TOTOP, state=uiconst.UI_NORMAL, height=16, show_line=True)
   2455         divider.Startup(self.sr.buyParent, 'height', 'y', 64, self.scrollHeight)
   2456         divider.OnSizeChanged = self.OnDetailScrollSizeChanged
   2457         self.sr.divider = divider
   2458         self.sr.buyscroll = eveScroll.Scroll(name='buyscroll', parent=self.sr.buyParent, rowPadding=1)
   2459         self.sr.buyscroll.multiSelect = 0
   2460         self.sr.buyscroll.smartSort = 1
   2461         self.sr.buyscroll.ignoreHeaderWidths = 1
   2462         self.sr.buyscroll.sr.id = '%sBuyScroll' % self.prefs
   2463         self.sr.buyscroll.OnColumnChanged = self.OnBuyColumnChanged
   2464         self.sr.buyscroll.SetDefaultSmartSorting(GetByLabel('UI/Market/MarketQuote/headerPrice'), SortDirection.ASCENDING, self._get_buy_headers(self.invType))
   2465         Container(name='divider', align=uiconst.TOTOP, height=const.defaultPadding, parent=self)
   2466         self.sr.sellParent = Container(name='sellParent', parent=self, align=uiconst.TOALL, uniqueUiName=pConst.UNIQUE_NAME_MARKET_BUYER_LIST)
   2467         sellLeft = Container(name='sellLeft', parent=self.sr.sellParent, align=uiconst.TOTOP, height=20)
   2468         buyersLabel = localization.GetByLabel('UI/Market/Marketbase/Buyers')
   2469         cap = eveLabel.EveCaptionMedium(text=buyersLabel, parent=sellLeft, align=uiconst.TOPLEFT)
   2470         sellLeft.height = max(sellLeft.height, cap.textheight)
   2471         a = eveLabel.EveLabelSmall(text='', parent=sellLeft, left=24, top=0, align=uiconst.TOPRIGHT, state=uiconst.UI_NORMAL)
   2472         a.OnClick = self.SellClick
   2473         a.GetMenu = None
   2474         self.sellFiltersActive1 = a
   2475         a = eveLabel.EveLabelSmall(text='', parent=sellLeft, left=24, top=14, state=uiconst.UI_NORMAL, align=uiconst.TOPRIGHT)
   2476         a.OnClick = self.SellClick
   2477         a.GetMenu = None
   2478         self.sellFiltersActive2 = a
   2479         self.sr.sellIcon = Sprite(name='sellIcon', parent=sellLeft, width=16, height=16, left=6, top=0, align=uiconst.TOPRIGHT)
   2480         self.sr.sellIcon.OnClick = self.SellClick
   2481         self.sr.sellIcon.state = uiconst.UI_HIDDEN
   2482         self.sr.sellscroll = eveScroll.Scroll(name='sellscroll', parent=self.sr.sellParent, rowPadding=1)
   2483         self.sr.sellscroll.multiSelect = 0
   2484         self.sr.sellscroll.smartSort = 1
   2485         self.sr.sellscroll.ignoreHeaderWidths = 1
   2486         self.sr.sellscroll.sr.id = '%sSellScroll' % self.prefs
   2487         self.sr.sellscroll.OnColumnChanged = self.OnSellColumnChanged
   2488         self.sr.sellscroll.SetDefaultSmartSorting(GetByLabel('UI/Market/MarketQuote/headerPrice'), SortDirection.DESCENDING, self._get_sell_headers(self.invType))
   2489         self._OnResize()
   2490         sm.RegisterNotify(self)
   2491         self.inited = 1
   2492         self.sr.buy_ActiveFilters = 1
   2493         self.sr.sell_ActiveFilters = 1
   2494 
   2495     def _GetButtonDataForExportToFile(self):
   2496         return (localization.GetByLabel('UI/Market/Marketbase/ExportToFile'),
   2497          self.ExportToFile,
   2498          (),
   2499          84,
   2500          False,
   2501          False,
   2502          False,
   2503          localization.GetByLabel('Tooltips/Market/MarketDetailsExportFile'),
   2504          None,
   2505          Button,
   2506          'ExportToFileButton')
   2507 
   2508     def _GetButtonDataForPlaceOrder(self):
   2509         return (localization.GetByLabel('UI/Market/Marketbase/CommandPlaceBuyOrder'),
   2510          self.PlaceOrder,
   2511          ('buy',),
   2512          84,
   2513          False,
   2514          False,
   2515          False,
   2516          localization.GetByLabel('Tooltips/Market/MarketDetailsPlaceBuyOrder'),
   2517          None,
   2518          Button,
   2519          'Place Buy Order_Btn')
   2520 
   2521     def OnDetailScrollSizeChanged(self):
   2522         h = self.sr.buyParent.height
   2523         absHeight = self.absoluteBottom - self.absoluteTop
   2524         if h > absHeight - self.height - 64:
   2525             h = absHeight - self.height - 64
   2526             ratio = float(h) / absHeight
   2527             settings.user.ui.Set('detailScrollHeight', ratio)
   2528             self._OnResize()
   2529             return
   2530         ratio = float(h) / absHeight
   2531         settings.user.ui.Set('detailScrollHeight', ratio)
   2532 
   2533     def SellClick(self, *args):
   2534         self.sr.sell_ActiveFilters = not self.sr.sell_ActiveFilters
   2535         self.Reload('sell')
   2536 
   2537     def BuyClick(self, *args):
   2538         self.sr.buy_ActiveFilters = not self.sr.buy_ActiveFilters
   2539         self.Reload('buy')
   2540 
   2541     def ExportToFile(self, *args):
   2542         if not self.invType:
   2543             return
   2544         DumpOrdersForType(self.invType)
   2545 
   2546     def OnPathfinderSettingsChange(self, *args):
   2547         self.ReloadType()
   2548 
   2549     def OnSessionChanged(self, isremote, session, change):
   2550         if 'solarsystemid' in change:
   2551             self.ReloadType()
   2552 
   2553     def _OnResize(self, *args):
   2554         if self and not self.destroyed and self.sr.buyParent:
   2555             self.scrollHeight = self.absoluteBottom - self.absoluteTop - 34 - 64
   2556             height = (self.absoluteBottom - self.absoluteTop - 46) / 2
   2557             absHeight = self.absoluteBottom - self.absoluteTop
   2558             ratio = settings.user.ui.Get('detailScrollHeight', 0.5)
   2559             h = int(ratio * absHeight)
   2560             if h > self.scrollHeight:
   2561                 h = self.scrollHeight
   2562             self.sr.buyParent.height = max(64, h)
   2563             self.sr.divider.max = self.scrollHeight
   2564 
   2565     def OnBuyColumnChanged(self, tabstops):
   2566         if self.loading != 'buy':
   2567             self.Reload('buy')
   2568 
   2569     def OnSellColumnChanged(self, tabstops):
   2570         if self.loading != 'sell':
   2571             self.Reload('sell')
   2572 
   2573     def PlaceOrder(self, what, *args):
   2574         if not self.invType:
   2575             prompt_player_fsd_dialog('CustomNotify', {'notify': localization.GetByLabel('UI/Market/Marketbase/NoTypeToBuy')})
   2576             return
   2577         if what == 'buy':
   2578             sm.GetService('marketutils').Buy(self.invType, placeOrder=True)
   2579         elif what == 'sell':
   2580             uicore.cmd.OpenAssets()
   2581 
   2582     def FindInContracts(self):
   2583         sm.GetService('contracts').FindRelated(self.invType, None, None, None, None, None)
   2584 
   2585     def Reload(self, what):
   2586         records = self.sr.Get('%sItems' % what, None)
   2587         scrollList = []
   2588         scroll = self.sr.Get('%sscroll' % what, None)
   2589         self.loading = what
   2590         if what == 'sell':
   2591             headers = self._get_sell_headers(self.invType)
   2592             columnNameAndPointersDict = self.sellheadersPointers
   2593         else:
   2594             headers = self._get_buy_headers(self.invType)
   2595             columnNameAndPointersDict = self.buyheadersPointers
   2596         marketUtil = sm.GetService('marketutils')
   2597         marketQuoteSvc = sm.GetService('marketQuote')
   2598         funcs = marketUtil.GetFuncMaps()
   2599 
   2600         def IsOrderASellWithinReach(order):
   2601             if what != 'sell':
   2602                 return False
   2603             dockedLocationID = session.stationid or session.structureid
   2604             if marketQuoteSvc.SkipBidDueToStructureRestrictions(order, dockedLocationID):
   2605                 return False
   2606             if does_global_market_apply(order.typeID):
   2607                 return True
   2608             if order.jumps <= order.range:
   2609                 return True
   2610             if session.stationid and order.range == -1 and order.stationID == session.stationid:
   2611                 return True
   2612             if session.solarsystemid and order.jumps == 0:
   2613                 return True
   2614             return False
   2615 
   2616         usingFilters = self.GetFilters2()[0]
   2617         foundCounter = 0
   2618         destPathList = sm.GetService('starmap').GetDestinationPath()
   2619         if self.invType and records:
   2620             dataList = []
   2621             scroll.sr.headers = headers
   2622             visibleHeaders = scroll.GetColumns()
   2623             accumPrice = 0
   2624             count = 0
   2625             hasMarker = False
   2626             for order in records[0]:
   2627                 data = utillib.KeyVal()
   2628                 data.label = ''
   2629                 data.typeID = order.typeID
   2630                 data.order = order
   2631                 data.mode = what
   2632                 data.inMyPath = self._IsInMyPath(destPathList, order.solarSystemID, order.stationID)
   2633                 accumPrice += order.price * order.volRemaining
   2634                 count += order.volRemaining
   2635                 data.flag = IsOrderASellWithinReach(order)
   2636                 data.markAsMine = order.orderID in self.allMyOrderIDs
   2637                 if data.flag or data.markAsMine or data.inMyPath:
   2638                     hasMarker = True
   2639                 expires = order.issueDate + order.duration * const.DAY - blue.os.GetWallclockTime()
   2640                 if expires < 0:
   2641                     continue
   2642                 for header in visibleHeaders:
   2643                     header = StripTags(header, stripOnly=['localized'])
   2644                     funcName = funcs.get(header, None)
   2645                     if funcName and hasattr(marketUtil, funcName):
   2646                         getattr(marketUtil, funcName, None)(order, data)
   2647                     else:
   2648                         log.LogWarn('Unsupported header in record', header, order)
   2649                         data.label += '###<t>'
   2650 
   2651                 self.SetDataValues(order, data)
   2652                 data.label = data.label[:-3]
   2653                 dataList.append(data)
   2654 
   2655             avg = None
   2656             if count > 0:
   2657                 avg = round(float(accumPrice / count), 2)
   2658             if what == 'sell':
   2659                 self.avgSellPrice = avg
   2660             else:
   2661                 self.avgBuyPrice = avg
   2662             for data in dataList:
   2663                 if self.ApplyDetailFilters(data, self.sr.Get('%s_ActiveFilters' % what, None)):
   2664                     data.isLabelOffset = hasMarker
   2665                     scrollList.append(GetFromClass(MarketOrder, data))
   2666                 else:
   2667                     foundCounter += 1
   2668 
   2669         hintText = ''
   2670         if not scrollList:
   2671             if self.invType:
   2672                 if (usingFilters or settings.user.ui.Get('market_filters_%sorderdev' % ['buy', 'sell'][what == 'buy'], 0)) and self.sr.Get('%s_ActiveFilters' % what, None):
   2673                     hintText = localization.GetByLabel('UI/Market/Marketbase/NoOrdersMatched')
   2674                 else:
   2675                     hintText = localization.GetByLabel('UI/Market/Orders/NoOrdersFound')
   2676             else:
   2677                 hintText = localization.GetByLabel('UI/Market/Marketbase/NoTypeToBuy')
   2678                 self.sr.filtersText.text = ''
   2679                 self.sr.filtersText.hint = ''
   2680         scroll.Load(contentList=scrollList, headers=headers, noContentHint=hintText)
   2681         pConst.SetUniqueNamesForColumns(scroll, columnNameAndPointersDict)
   2682         if what == 'buy':
   2683             if usingFilters or settings.user.ui.Get('market_filters_sellorderdev', 0):
   2684                 if self.sr.buy_ActiveFilters:
   2685                     text1 = localization.GetByLabel('UI/Market/Marketbase/AdditionalEntriesFound', foundCounter=foundCounter)
   2686                     text2 = localization.GetByLabel('UI/Market/Marketbase/TurnFiltersOff')
   2687                 else:
   2688                     text1 = localization.GetByLabel('UI/Market/Marketbase/TurnFiltersOn')
   2689                     text2 = ''
   2690                 self.buyFiltersActive1.text = text1
   2691                 self.buyFiltersActive2.text = text2
   2692                 self.sr.buyIcon.state = uiconst.UI_NORMAL
   2693                 self.SetFilterIcon2(self.sr.buyIcon, on=bool(self.sr.buy_ActiveFilters))
   2694             else:
   2695                 self.buyFiltersActive1.text = ''
   2696                 self.buyFiltersActive2.text = ''
   2697                 self.sr.buyIcon.state = uiconst.UI_HIDDEN
   2698         if what == 'sell':
   2699             if usingFilters or settings.user.ui.Get('market_filters_buyorderdev', 0):
   2700                 if self.sr.sell_ActiveFilters:
   2701                     text1 = localization.GetByLabel('UI/Market/Marketbase/AdditionalEntriesFound', foundCounter=foundCounter)
   2702                     text2 = localization.GetByLabel('UI/Market/Marketbase/TurnFiltersOff')
   2703                 else:
   2704                     text1 = localization.GetByLabel('UI/Market/Marketbase/TurnFiltersOn')
   2705                     text2 = ''
   2706                 self.sellFiltersActive1.text = text1
   2707                 self.sellFiltersActive2.text = text2
   2708                 self.sr.sellIcon.state = uiconst.UI_NORMAL
   2709                 self.SetFilterIcon2(self.sr.sellIcon, on=bool(self.sr.sell_ActiveFilters))
   2710             else:
   2711                 self.sellFiltersActive1.text = ''
   2712                 self.sellFiltersActive2.text = ''
   2713                 self.sr.sellIcon.state = uiconst.UI_HIDDEN
   2714         self.loading = None
   2715 
   2716     def _IsInMyPath(self, path, solarsystemID, locationID):
   2717         if solarsystemID in path:
   2718             return True
   2719         if locationID in path:
   2720             return True
   2721         if not eveCfg.IsDocked() and solarsystemID == session.solarsystemid2:
   2722             return True
   2723         return False
   2724 
   2725     def SetFilterIcon2(self, icon, on, *args):
   2726         if on:
   2727             iconNo = 'ui_38_16_205'
   2728         else:
   2729             iconNo = 'ui_38_16_204'
   2730         icon.LoadIcon(iconNo)
   2731 
   2732     def SetDataValues(self, record, data):
   2733         data.Set('filter_Price', record.price)
   2734         filterJumps = record.jumps
   2735         if record.jumps == 0:
   2736             filterJumps = -1
   2737         data.Set('filter_Jumps', filterJumps)
   2738         data.Set('filter_Quantity', int(record.volRemaining))
   2739 
   2740     def GetFilters2(self):
   2741         self.filter_jumps_min = int(GetNumericValueFromSetting('minEdit_market_filter_jumps'))
   2742         self.filter_jumps_max = int(GetNumericValueFromSetting('maxEdit_market_filter_jumps'))
   2743         if self.filter_jumps_min == None or self.filter_jumps_min == '':
   2744             self.filter_jumps_min = 0
   2745         if self.filter_jumps_max == None or self.filter_jumps_max == '':
   2746             self.filter_jumps_max = INFINITY
   2747         if self.filter_jumps_min > self.filter_jumps_max:
   2748             self.filter_jumps_max = INFINITY
   2749         self.filter_quantity_min = int(GetNumericValueFromSetting('minEdit_market_filter_quantity'))
   2750         self.filter_quantity_max = int(GetNumericValueFromSetting('maxEdit_market_filter_quantity'))
   2751         if self.filter_quantity_min == None or self.filter_quantity_min == '':
   2752             self.filter_quantity_min = 0
   2753         if self.filter_quantity_max == None or self.filter_quantity_max == '':
   2754             self.filter_quantity_max = INFINITY
   2755         if self.filter_quantity_min >= self.filter_quantity_max:
   2756             self.filter_quantity_max = INFINITY
   2757         self.filter_price_min = float(GetNumericValueFromSetting('minEdit_market_filter_price'))
   2758         self.filter_price_max = float(GetNumericValueFromSetting('maxEdit_market_filter_price'))
   2759         if self.filter_price_min == None or self.filter_price_min == '':
   2760             self.filter_price_min = 0
   2761         if self.filter_price_max == None or self.filter_price_max == '':
   2762             self.filter_price_max = INFINITY
   2763         if self.filter_price_min >= self.filter_price_max:
   2764             self.filter_price_max = INFINITY
   2765         self.ignore_sellorder_min = GetNumericValueFromSetting('minEdit_market_filters_sellorderdev')
   2766         if self.ignore_sellorder_min == None or self.ignore_sellorder_min == '':
   2767             self.ignore_sellorder_min = 0
   2768         self.ignore_sellorder_max = GetNumericValueFromSetting('maxEdit_market_filters_sellorderdev')
   2769         if self.ignore_sellorder_max == None or self.ignore_sellorder_max == '':
   2770             self.ignore_sellorder_max = 0
   2771         self.ignore_buyorder_min = GetNumericValueFromSetting('minEdit_market_filters_buyorderdev')
   2772         if self.ignore_buyorder_min == None or self.ignore_buyorder_min == '':
   2773             self.ignore_buyorder_min = 0
   2774         self.ignore_buyorder_max = GetNumericValueFromSetting('maxEdit_market_filters_buyorderdev')
   2775         if self.ignore_buyorder_max == None or self.ignore_buyorder_max == '':
   2776             self.ignore_buyorder_max = 0
   2777         filters = [settings.user.ui.Get('market_filter_jumps', 0),
   2778          settings.user.ui.Get('market_filter_quantity', 0),
   2779          settings.user.ui.Get('market_filter_price', 0),
   2780          not settings.user.ui.Get('market_filter_zerosec', 0),
   2781          not settings.user.ui.Get('market_filter_highsec', 0),
   2782          not settings.user.ui.Get('market_filter_lowsec', 0)]
   2783         usingFilters = False
   2784         for each in filters:
   2785             if each:
   2786                 usingFilters = True
   2787                 break
   2788 
   2789         return [usingFilters,
   2790          self.filter_jumps_min,
   2791          self.filter_jumps_max,
   2792          self.filter_quantity_min,
   2793          self.filter_quantity_max,
   2794          self.filter_price_min,
   2795          self.filter_price_max,
   2796          self.ignore_sellorder_min,
   2797          self.ignore_sellorder_max,
   2798          self.ignore_buyorder_min,
   2799          self.ignore_buyorder_max]
   2800 
   2801     def ApplyDetailFilters(self, data, activeFilters = 1):
   2802         if not activeFilters:
   2803             return True
   2804         if not does_global_market_apply(self.invType):
   2805             if settings.user.ui.Get('market_filter_jumps', 0):
   2806                 if data.filter_Jumps:
   2807                     if self.filter_jumps_min > data.filter_Jumps or self.filter_jumps_max < data.filter_Jumps:
   2808                         if not (self.filter_jumps_min == 0 and data.filter_Jumps == -1):
   2809                             return False
   2810         if settings.user.ui.Get('market_filter_quantity', 0):
   2811             if data.filter_Quantity:
   2812                 if self.filter_quantity_min > data.filter_Quantity or self.filter_quantity_max < data.filter_Quantity:
   2813                     return False
   2814         if settings.user.ui.Get('market_filter_price', 0):
   2815             if data.filter_Price:
   2816                 if self.filter_price_min > data.filter_Price or self.filter_price_max < data.filter_Price:
   2817                     return False
   2818         if not does_global_market_apply(self.invType):
   2819             secClass = sm.GetService('securitySvc').get_modified_security_class(data.order.solarSystemID)
   2820             if is_zero_sec(secClass):
   2821                 if not settings.user.ui.Get('market_filter_zerosec', 0):
   2822                     return False
   2823             elif is_high_sec_or_higher(secClass):
   2824                 if not settings.user.ui.Get('market_filter_highsec', 0):
   2825                     return False
   2826             elif not settings.user.ui.Get('market_filter_lowsec', 0):
   2827                 return False
   2828         if data.filter_Price:
   2829             if settings.user.ui.Get('market_filters_sellorderdev', 0) and data.mode == 'buy':
   2830                 if self.avgBuyPrice:
   2831                     percentage = (data.filter_Price - self.avgBuyPrice) / self.avgBuyPrice
   2832                     if float(self.ignore_sellorder_max) < percentage * 100 or float(self.ignore_sellorder_min) > percentage * 100:
   2833                         return False
   2834             if settings.user.ui.Get('market_filters_buyorderdev', 0) and data.mode == 'sell':
   2835                 if self.avgSellPrice:
   2836                     percentage = (data.filter_Price - self.avgSellPrice) / self.avgSellPrice
   2837                     if float(self.ignore_buyorder_max) < percentage * 100 or float(self.ignore_buyorder_min) > percentage * 100:
   2838                         return False
   2839         return True
   2840 
   2841     def LoadType(self, invType):
   2842         self.invType = invType
   2843         self.ReloadType()
   2844 
   2845     def OnReload(self):
   2846         self.ReloadType()
   2847 
   2848     def GetInvTypeID(self):
   2849         return self.invType
   2850 
   2851     def ReloadType(self, *args):
   2852         if self.invType:
   2853             self.sr.sellscroll.Load(contentList=[], fixedEntryHeight=18, headers=self._get_sell_headers(self.invType))
   2854             self.sr.buyscroll.Load(contentList=[], fixedEntryHeight=18, headers=self._get_buy_headers(self.invType))
   2855             self.sr.sellscroll.ShowHint(localization.GetByLabel('UI/Market/Marketbase/FetchingOrders'))
   2856             self.sr.buyscroll.ShowHint(localization.GetByLabel('UI/Market/Marketbase/FetchingOrders'))
   2857             self.sr.buyItems, self.sr.sellItems = sm.GetService('marketQuote').GetOrders(self.invType)
   2858             if settings.user.ui.Get('hilitemyorders', True):
   2859                 self.allMyOrderIDs = {order.orderID for order in sm.GetService('marketQuote').GetMyOrders()}
   2860             else:
   2861                 self.allMyOrderIDs = set()
   2862             self.Reload('buy')
   2863             self.Reload('sell')
   2864         else:
   2865             self.sr.sellscroll.Load(contentList=[], fixedEntryHeight=18)
   2866             self.sr.buyscroll.Load(contentList=[], fixedEntryHeight=18)
   2867 
   2868     @staticmethod
   2869     def _get_buy_headers(type_id):
   2870         if not should_show_location_info(type_id):
   2871             headers = [localization.GetByLabel('UI/Common/Quantity'), localization.GetByLabel('UI/Market/Marketbase/Price'), localization.GetByLabel('UI/Market/Marketbase/ExpiresIn')]
   2872         else:
   2873             headers = [localization.GetByLabel('UI/Market/Marketbase/Jumps'),
   2874              localization.GetByLabel('UI/Common/Quantity'),
   2875              localization.GetByLabel('UI/Market/Marketbase/Price'),
   2876              localization.GetByLabel('UI/Common/Location'),
   2877              localization.GetByLabel('UI/Market/Marketbase/ExpiresIn')]
   2878         if should_show_region():
   2879             headers.append(localization.GetByLabel('UI/Common/LocationTypes/Region'))
   2880         return headers
   2881 
   2882     @staticmethod
   2883     def _get_sell_headers(type_id):
   2884         if not should_show_location_info(type_id):
   2885             headers = [localization.GetByLabel('UI/Common/Quantity'),
   2886              localization.GetByLabel('UI/Market/Marketbase/Price'),
   2887              localization.GetByLabel('UI/Market/MarketQuote/HeaderMinVolumn'),
   2888              localization.GetByLabel('UI/Market/Marketbase/ExpiresIn')]
   2889         else:
   2890             headers = [localization.GetByLabel('UI/Market/Marketbase/Jumps'),
   2891              localization.GetByLabel('UI/Common/Quantity'),
   2892              localization.GetByLabel('UI/Market/Marketbase/Price'),
   2893              localization.GetByLabel('UI/Common/Location'),
   2894              localization.GetByLabel('UI/Common/Range'),
   2895              localization.GetByLabel('UI/Market/MarketQuote/HeaderMinVolumn'),
   2896              localization.GetByLabel('UI/Market/Marketbase/ExpiresIn')]
   2897         if should_show_region():
   2898             headers.append(localization.GetByLabel('UI/Common/LocationTypes/Region'))
   2899         return headers
   2900 
   2901 
   2902 class QuickbarEntries(Container):
   2903     __guid__ = 'xtriui.QuickbarEntries'
   2904     __nonpersistvars__ = []
   2905 
   2906     def ApplyAttributes(self, attributes):
   2907         Container.ApplyAttributes(self, attributes)
   2908         self.sr.nodes = []
   2909         self.tooDeep = False
   2910 
   2911     def __Load(self, contentList = [], maxDepth = 99, parentDepth = 0):
   2912         if self.destroyed:
   2913             return
   2914         self.sr.nodes = []
   2915         self.maxDepth = maxDepth
   2916         self.parentDepth = parentDepth
   2917         self.depth = 0
   2918         self.AddEntries(0, contentList)
   2919         if self.destroyed:
   2920             return
   2921         return [0, self.depth - parentDepth][bool(self.depth)]
   2922 
   2923     Load = LoadContent = __Load
   2924 
   2925     def AddEntry(self, idx, entry, update = 0, isSub = 0, fromW = None):
   2926         _idx = idx
   2927         if idx == -1:
   2928             idx = len(self.GetNodes())
   2929         entry.idx = idx
   2930         if not self or not getattr(self, 'sr', None):
   2931             return
   2932         self.ReloadEntry(entry)
   2933         return entry
   2934 
   2935     def ReloadEntry(self, entry):
   2936         if entry.id and entry.GetSubContent:
   2937             self.depth = max(self.depth, entry.sublevel)
   2938             subcontent = entry.GetSubContent(entry)
   2939             if self.destroyed:
   2940                 return
   2941             self.AddEntries(entry.idx + 1, subcontent, entry)
   2942 
   2943     def AddEntries(self, fromIdx, entriesData, parentEntry = None):
   2944         if self.parentDepth > self.maxDepth:
   2945             self.tooDeep = True
   2946             return
   2947         if fromIdx == -1:
   2948             fromIdx = len(self.GetNodes())
   2949         isSub = 0
   2950         if parentEntry:
   2951             isSub = getattr(parentEntry, 'sublevel', 0) + 1
   2952         entries = []
   2953         idx = fromIdx
   2954         for crap, data in entriesData:
   2955             newentry = self.AddEntry(idx, data, isSub=isSub)
   2956             if newentry is None:
   2957                 continue
   2958             idx = newentry.idx + 1
   2959             entries.append(newentry)
   2960 
   2961         if self.destroyed:
   2962             return
   2963 
   2964     def _OnClose(self):
   2965         for each in self.GetNodes():
   2966             each.scroll = None
   2967             each.data = None
   2968 
   2969         self.sr.nodes = []
   2970 
   2971     def GetNodes(self):
   2972         return self.sr.nodes
   2973 
   2974 
   2975 class SelectFolderWindow(ListWindow):
   2976     default_windowID = 'SelectFolderWindow'
   2977 
   2978     def GetError(self, checkNumber = 1):
   2979         result = None
   2980         if self.scroll.GetSelected():
   2981             result = [self.scroll.GetSelected()[0].id[1], self.scroll.GetSelected()[0].sublevel]
   2982         if hasattr(self, 'customValidator'):
   2983             ret = self.customValidator and self.customValidator(result) or ''
   2984             if ret:
   2985                 return ret
   2986         try:
   2987             if checkNumber:
   2988                 if result == None:
   2989                     if self.minChoices == self.maxChoices:
   2990                         label = localization.GetByLabel('UI/Control/ListWindow/MustSelectError', num=self.minChoices)
   2991                     else:
   2992                         label = localization.GetByLabel('UI/Control/ListWindow/SelectTooFewError', num=self.minChoices)
   2993                     return label
   2994         except ValueError as e:
   2995             log.LogException()
   2996             sys.exc_clear()
   2997             return
   2998 
   2999         return ''
   3000 
   3001     def Confirm(self, *etc):
   3002         if not self.isModal:
   3003             return
   3004         self.Error(self.GetError(checkNumber=0))
   3005         if not self.GetError():
   3006             if self.scroll.GetSelected():
   3007                 if hasattr(self.scroll.GetSelected()[0], 'id'):
   3008                     self.result = [self.scroll.GetSelected()[0].id[1], self.scroll.GetSelected()[0].sublevel]
   3009             self.SetModalResult(uiconst.ID_OK)
   3010 
   3011     def Error(self, error):
   3012         ep = self.GetChild('errorParent')
   3013         ep.Flush()
   3014         if error:
   3015             t = eveLabel.EveLabelMedium(text='<center>' + error, top=-3, parent=ep, width=self.minsize[0] - 32, state=uiconst.UI_DISABLED, color=(1.0, 0.0, 0.0, 1.0), align=uiconst.CENTER)
   3016             ep.state = uiconst.UI_DISABLED
   3017             ep.height = t.height + 8
   3018         else:
   3019             ep.state = uiconst.UI_HIDDEN
   3020 
   3021 
   3022 class MarketGroupItemImage(Image):
   3023     isDragObject = True
   3024 
   3025     def ApplyAttributes(self, attributes):
   3026         super(MarketGroupItemImage, self).ApplyAttributes(attributes)
   3027         self.omegaIcon = OmegaCloneOverlayIcon(name='OmegaIcon', parent=self, state=uiconst.UI_DISABLED, align=uiconst.TOALL, opacity=0, origin=ORIGIN_MARKET)
   3028 
   3029     def LoadTypeIcon(self, typeID):
   3030         Image.LoadTypeIcon(self)
   3031         self.SetOmegaIconState(typeID)
   3032         self.typeID = typeID
   3033         self.omegaIcon.reason = typeID
   3034         self.isUnlockedWithExpertSystem = sm.GetService('skills').IsUnlockedWithExpertSystem(self.typeID)
   3035 
   3036     def GetDragData(self, *args):
   3037         return [Bunch(typeID=self.typeID, __guid__='listentry.GenericMarketItem', label=self.typeName, invtype=self.typeID)]
   3038 
   3039     def OnMouseMove(self, *args):
   3040         if self.IsBeingDragged():
   3041             self.cursor = self.default_cursor
   3042         Container.OnMouseMove(self)
   3043 
   3044     def OnMouseEnter(self, *args):
   3045         self.omegaIcon.OnMouseEnter()
   3046         if eveCfg.IsPreviewable(self.typeID):
   3047             self.cursor = uiconst.UICURSOR_MAGNIFIER
   3048         else:
   3049             self.cursor = self.default_cursor
   3050         if evetypes.GetGroupID(self.typeID) == const.groupSkillInjectors:
   3051             sm.ScatterEvent('OnSkillInjectorMouseEnter', self.typeID)
   3052 
   3053     def OnMouseExit(self, *args):
   3054         self.omegaIcon.OnMouseExit()
   3055         self.cursor = self.default_cursor
   3056         if evetypes.GetGroupID(self.typeID) == const.groupSkillInjectors:
   3057             sm.ScatterEvent('OnSkillInjectorMouseExit')
   3058 
   3059     def OnClick(self, *args):
   3060         if eveCfg.IsPreviewable(self.typeID):
   3061             sm.GetService('preview').PreviewType(self.typeID)
   3062 
   3063     def SetOmegaIconState(self, typeID):
   3064         if get_clone_grade_svc().is_restricted_for_alpha(typeID):
   3065             self.omegaIcon.SetOpacity(1)
   3066         else:
   3067             self.omegaIcon.SetOpacity(0)
   3068 
   3069     def LoadTooltipPanel(self, tooltipPanel, *args):
   3070         if get_clone_grade_svc().is_restricted(self.typeID):
   3071             self.omegaIcon.LoadTooltipPanel(tooltipPanel, args)
   3072         else:
   3073             tooltipPanel.LoadGeneric1ColumnTemplate()
   3074         expertSystems.add_type_unlocked_by_expert_systems(tooltipPanel, self.typeID)