import wx from logbook import Logger import gui.builtinMarketBrowser.pfSearchBox as SBox import gui.globalEvents as GE from config import slotColourMap, slotColourMapDark from eos.saveddata.module import Module from gui.builtinMarketBrowser.events import ItemSelected, RECENTLY_USED_MODULES, CHARGES_FOR_FIT from gui.contextMenu import ContextMenu from gui.display import Display from gui.utils.staticHelpers import DragDropHelper from gui.utils.dark import isDark from service.fit import Fit from service.market import Market from service.ammo import Ammo pyfalog = Logger(__name__) class ItemView(Display): DEFAULT_COLS = ["Base Icon", "Base Name", "attr:power,,,True", "attr:cpu,,,True"] def __init__(self, parent, marketBrowser): Display.__init__(self, parent, style=wx.LC_SINGLE_SEL) pyfalog.debug("Initialize ItemView") marketBrowser.Bind(wx.EVT_TREE_SEL_CHANGED, self.treeSelectionChanged) self.unfilteredStore = set() self.filteredStore = set() self.sMkt = marketBrowser.sMkt self.sFit = Fit.getInstance() self.sAmmo = Ammo.getInstance() self.marketBrowser = marketBrowser self.marketView = marketBrowser.marketView # Set up timer for delaying search on every EVT_TEXT self.searchTimer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.scheduleSearch, self.searchTimer) # Make sure our search actually does interesting stuff self.marketBrowser.search.Bind(SBox.EVT_TEXT_ENTER, self.scheduleSearch) self.marketBrowser.search.Bind(SBox.EVT_SEARCH_BTN, self.scheduleSearch) self.marketBrowser.search.Bind(SBox.EVT_CANCEL_BTN, self.clearSearch) self.marketBrowser.search.Bind(SBox.EVT_TEXT, self.delaySearch) # Make sure WE do interesting stuff too self.Bind(wx.EVT_CONTEXT_MENU, self.contextMenu) self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.itemActivated) self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.startDrag) # the "charges for active fitting" needs to listen to fitting changes self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) self.active = [] def delaySearch(self, evt): sFit = Fit.getInstance() self.searchTimer.Stop() self.searchTimer.Start(sFit.serviceFittingOptions["marketSearchDelay"], True) def startDrag(self, event): row = self.GetFirstSelected() if row != -1: data = wx.TextDataObject() dataStr = "market:" + str(self.active[row].ID) pyfalog.debug("Dragging from market: " + dataStr) data.SetText(dataStr) dropSource = wx.DropSource(self) dropSource.SetData(data) DragDropHelper.data = dataStr dropSource.DoDragDrop() def itemActivated(self, event=None): # Check if something is selected, if so, spawn the menu for it sel = self.GetFirstSelected() if sel == -1: return if self.mainFrame.getActiveFit(): wx.PostEvent(self.mainFrame, ItemSelected(itemID=self.active[sel].ID)) def treeSelectionChanged(self, event=None): self.selectionMade('tree') def selectionMade(self, context): self.marketBrowser.mode = 'normal' # Grab the threeview selection and check if it's fine sel = self.marketView.GetSelection() if sel.IsOk(): # Get data field of the selected item (which is a marketGroup ID if anything was selected) seldata = self.marketView.GetItemData(sel) if seldata == RECENTLY_USED_MODULES: items = self.sMkt.getRecentlyUsed() elif seldata == CHARGES_FOR_FIT: items = self.getChargesForActiveFit() elif seldata is not None: # If market group treeview item doesn't have children (other market groups or dummies), # then it should have items in it and we want to request them if self.marketView.ItemHasChildren(sel) is False: sMkt = self.sMkt # Get current market group mg = sMkt.getMarketGroup(seldata, eager=("items", "items.metaGroup")) # Get all its items items = sMkt.getItemsByMarketGroup(mg) else: items = set() else: items = set() # Fill store self.updateItemStore(items) # Set toggle buttons / use search mode flag if recently used modules category is selected (in order to have all modules listed and not filtered) if seldata == RECENTLY_USED_MODULES: self.marketBrowser.mode = 'recent' if seldata == CHARGES_FOR_FIT: self.marketBrowser.mode = 'charges' self.setToggles() if context == 'tree' and self.marketBrowser.settings.get('marketMGMarketSelectMode') == 1: for btn in self.marketBrowser.metaButtons: if not btn.GetValue(): btn.setUserSelection(True) self.filterItemStore() def getChargesForActiveFit(self): fitId = self.mainFrame.getActiveFit() # no active fit => no charges if fitId is None: return set() fit = self.sFit.getFit(fitId) # use a set so we only add one entry for each charge items = set() for mod in fit.modules: charges = self.sAmmo.getModuleFlatAmmo(mod) for charge in charges: items.add(charge) return items def fitChanged(self, event): # skip the event so the other handlers also get called event.Skip() if self.marketBrowser.mode != 'charges': return activeFitID = self.mainFrame.getActiveFit() # if it was not the active fitting that was changed, do not do anything if activeFitID is not None and activeFitID not in event.fitIDs: return items = self.getChargesForActiveFit() # update the UI self.updateItemStore(items) self.filterItemStore() def updateItemStore(self, items): self.unfilteredStore = items def filterItemStore(self): filteredItems = self.filterItems() if len(filteredItems) == 0 and len(self.unfilteredStore) > 0: setting = self.marketBrowser.settings.get('marketMGEmptyMode') # Enable leftmost available if setting == 1: for btn in self.marketBrowser.metaButtons: if btn.IsEnabled() and not btn.userSelected: btn.setUserSelection(True) break filteredItems = self.filterItems() # Enable all elif setting == 2: for btn in self.marketBrowser.metaButtons: if btn.IsEnabled() and not btn.userSelected: btn.setUserSelection(True) filteredItems = self.filterItems() self.filteredStore = filteredItems self.update(self.filteredStore) def filterItems(self): sMkt = self.sMkt selectedMetas = set() for btn in self.marketBrowser.metaButtons: if btn.userSelected: selectedMetas.update(sMkt.META_MAP[btn.metaName]) filteredItems = sMkt.filterItemsByMeta(self.unfilteredStore, selectedMetas) return filteredItems def setToggles(self): metaIDs = set() sMkt = self.sMkt for item in self.unfilteredStore: metaIDs.add(sMkt.getMetaGroupIdByItem(item)) for btn in self.marketBrowser.metaButtons: btn.reset() btnMetas = sMkt.META_MAP[btn.metaName] if len(metaIDs.intersection(btnMetas)) > 0: btn.setMetaAvailable(True) else: btn.setMetaAvailable(False) def scheduleSearch(self, event=None): self.searchTimer.Stop() # Cancel any pending timers search = self.marketBrowser.search.GetLineText(0) # Make sure we do not count wildcards as search symbol realsearch = search.replace('*', '').replace('?', '') # Re-select market group if search query has zero length if len(realsearch) == 0: self.selectionMade('search') return self.marketBrowser.mode = 'search' self.sMkt.searchItems(search, self.populateSearch, 'market') def clearSearch(self, event=None): # Wipe item store and update everything to accomodate with it # If clearSearch was generated by SearchCtrl's Cancel button, clear the content also if event: self.marketBrowser.search.Clear() if self.marketBrowser.mode == 'search': self.marketBrowser.mode = 'normal' self.updateItemStore(set()) self.setToggles() self.filterItemStore() def populateSearch(self, itemIDs): # If we're no longer searching, dump the results if self.marketBrowser.mode != 'search': return items = Market.getItems(itemIDs) self.updateItemStore(items) self.setToggles() self.filterItemStore() def contextMenu(self, event): clickedPos = self.getRowByAbs(event.Position) self.ensureSelection(clickedPos) # Check if something is selected, if so, spawn the menu for it if clickedPos == -1: return item = self.active[clickedPos] sMkt = self.sMkt sourceContext = "marketItemMisc" if self.marketBrowser.mode in ("search", "recent") else "marketItemGroup" itemContext = sMkt.getCategoryByItem(item).displayName menu = ContextMenu.getMenu(self, item, (item,), (sourceContext, itemContext)) self.PopupMenu(menu) def populate(self, items): if len(items) > 0: # Clear selection self.unselectAll() # Perform sorting, using item's meta levels besides other stuff if self.marketBrowser.mode != 'recent': items.sort(key=self.sMkt.itemSort) # Mark current item list as active self.active = items # Show them Display.populate(self, items) def refresh(self, items): if len(items) > 1: # Re-sort stuff if self.marketBrowser.mode != 'recent': items.sort(key=self.sMkt.itemSort) for i, item in enumerate(items[:9]): # set shortcut info for first 9 modules item.marketShortcut = i + 1 Display.refresh(self, items) def columnBackground(self, colItem, item): if self.sFit.serviceFittingOptions["colorFitBySlot"]: colorMap = slotColourMapDark if isDark() else slotColourMap return colorMap.get(Module.calculateSlot(item)) or self.GetBackgroundColour() else: return self.GetBackgroundColour()