class AbstractListBody(): @warnWxThread def __init__(self, parent_list, columns, leftSpacer=0, rightSpacer=0, singleExpanded=False, showChange=False, list_item_max=None, hasFilter=True, listRateLimit=LIST_RATE_LIMIT): self.columns = columns self.leftSpacer = leftSpacer self.rightSpacer = rightSpacer self.parent_list = parent_list self.singleExpanded = singleExpanded self.showChange = showChange self.list_selected = LIST_SELECTED self.listRateLimit = listRateLimit if not list_item_max: list_item_max = LIST_ITEM_MAX_SIZE self.list_item_max = list_item_max self.list_cur_max = self.list_item_max self.hasFilter = hasFilter hSizer = wx.BoxSizer(wx.HORIZONTAL) self.listpanel = wx.Panel(self, name="LIST") #vertical sizer containing all items self.vSizer = wx.BoxSizer(wx.VERTICAL) self.listpanel.SetSizer(self.vSizer) hSizer.Add(self.listpanel, 1) self.SetSizer(hSizer) #messagePanel text self.messagePanel = wx.Panel(self.listpanel) self.messagePanel.SetBackgroundColour(DEFAULT_BACKGROUND) self.messagePanel.Show(False) messageVSizer = wx.BoxSizer(wx.VERTICAL) self.headerText = StaticText(self.messagePanel) _set_font(self.headerText, fontweight=wx.FONTWEIGHT_BOLD) self.messageText = StaticText(self.messagePanel) self.loadNext = wx.Button(self.messagePanel) self.loadNext.Bind(wx.EVT_BUTTON, self.OnLoadMore) self.loadNext.Hide() messageVSizer.Add(self.headerText, 0, wx.EXPAND) messageVSizer.Add(self.messageText, 0, wx.EXPAND) messageVSizer.Add(self.loadNext, 0, wx.ALIGN_CENTER) self.messageText.sizer = messageVSizer self.messageText.altControl = None messageSizer = wx.BoxSizer(wx.HORIZONTAL) messageSizer.AddStretchSpacer() messageSizer.Add(messageVSizer, 0, wx.TOP | wx.BOTTOM, 7) messageSizer.AddStretchSpacer() self.messagePanel.SetSizer(messageSizer) #vertical scrollrate self.rate = None #states self.cur_expanded = None #quick filter self.filter = None self.filterMessage = None #sorting self.sortcolumn = None #queue lists self.done = True self.lastData = 0 self.dataTimer = None self.data = None self.raw_data = None self.items = {} # Allow list-items to store the most recent mouse left-down events: self.lastMouseLeftDownEvent = None self.curWidth = -1 self.Bind(wx.EVT_SIZE, self.OnEventSize) @warnWxThread def SetBackgroundColour(self, colour): wx.Panel.SetBackgroundColour(self, DEFAULT_BACKGROUND) self.listpanel.SetBackgroundColour(colour) @warnWxThread def SetStyle(self, font=None, foregroundcolour=None, list_selected=LIST_SELECTED): if font: self.SetFont(font) if foregroundcolour: self.SetForegroundColour(foregroundcolour) self.list_selected = list_selected @warnWxThread def OnSort(self, column, reverse): self.Scroll(-1, 0) #Niels: translating between -1 and None conventions if column == -1: column = None self.sortcolumn = column self.sortreverse = reverse self.SetData(highlight=False, force=True) def DoSort(self): def sortby(b, a): if a[0] in self.items: a = self.items[a[0]].data[self.sortcolumn] else: a = a[1][self.sortcolumn] if b[0] in self.items: b = self.items[b[0]].data[self.sortcolumn] else: b = b[1][self.sortcolumn] if isinstance(a, basestring): a = a.lower() if isinstance(b, basestring): b = b.lower() return cmp(a, b) if self.sortcolumn != None: self.data = sorted(self.data, cmp=sortby, reverse=self.sortreverse) def SetFilter(self, filter, filterMessage, highlight): self.filterMessage = filterMessage if self.filter is not None or filter is not None: self.filter = filter self.Scroll(-1, 0) self.SetData(highlight=highlight) @warnWxThread def OnExpand(self, item, raise_event=False): self.Freeze() if self.singleExpanded: if self.cur_expanded: self.OnCollapse(self.cur_expanded, False) panel = self.parent_list.OnExpand(item) if panel and not isinstance(panel, bool): item.Expand(panel) self.OnChange() #Niels: Windows 7 needs this refresh otherwise it will show some paint errors self.Refresh() self.cur_expanded = item self.Thaw() return panel @warnWxThread def OnCollapse(self, item=None, onchange=True): self.Freeze() if not item: item = self.cur_expanded if item: panel = item.Collapse() self.parent_list.OnCollapse(item, panel) self.cur_expanded = None if onchange: self.OnChange() #Niels: Windows 7 needs this refresh otherwise it will show some paint errors self.Refresh() self.Thaw() @warnWxThread def OnChange(self, scrollToTop=False): self.Freeze() self.vSizer.Layout() self.listpanel.Layout() self.Layout() #Determine scrollrate if self.rate is None: nritems = len(self.vSizer.GetChildren()) if nritems > 0: height = self.vSizer.GetSize()[1] self.rate = height / nritems if DEBUG: print >> sys.stderr, "ListBody: setting scrollrate to", self.rate self.SetupScrolling(scrollToTop=scrollToTop, rate_y=self.rate) else: if DEBUG: print >> sys.stderr, "ListBody: setting scrollrate to default" self.SetupScrolling(scrollToTop=scrollToTop) else: if DEBUG: print >> sys.stderr, "ListBody: using scrollrate", self.rate self.SetupScrolling(scrollToTop=scrollToTop, rate_y=self.rate) self.Thaw() @warnWxThread def Reset(self): if DEBUG: print >> sys.stderr, "ListBody: reset" self.Freeze() self.filter = None self.filterMessage = None self.sortcolumn = None self.rate = None self.vSizer.ShowItems(False) self.vSizer.Clear() for key in self.items.keys(): self.items[key].Destroy() self.list_cur_max = self.list_item_max self.items = {} self.data = None self.lastData = 0 self.raw_data = None self.ShowLoading() self.OnChange() self.Thaw() def IsEmpty(self): return len(self.items) == 0 def InList(self, key, onlyCreated=True): if onlyCreated or not self.data: return key in self.items if key in self.items: return True return any(curdata[0] == key for curdata in self.data) @warnWxThread def ScrollToEnd(self, scroll_to_end): if scroll_to_end: self.Scroll(-1, self.vSizer.GetSize()[1]) else: self.Scroll(-1, 0) @warnWxThread def ScrollToId(self, id): if id in self.items: sy = self.items[id].GetPosition()[1] / self.GetScrollPixelsPerUnit( )[1] self.Scroll(-1, sy) @warnWxThread def ShowMessage(self, message, header=None, altControl=None): if DEBUG: print >> sys.stderr, "ListBody: ShowMessage", message self.Freeze() if header: self.headerText.SetLabel(header) self.headerText.Show() else: self.headerText.Hide() self.messageText.SetLabel(message) if self.messageText.altControl: self.messageText.sizer.Detach(self.messageText.altControl) if getattr(self.messageText.altControl, 'ShowItems', False): self.messageText.altControl.ShowItems(False) self.messageText.altControl.Clear(True) self.messageText.altControl = None if altControl: self.messageText.altControl = altControl self.messageText.sizer.Insert(2, altControl, 0, wx.EXPAND) self.loadNext.Hide() self.vSizer.ShowItems(False) self.vSizer.Clear() self.vSizer.Add(self.messagePanel, 0, wx.EXPAND | wx.BOTTOM, 1) self.messagePanel.Layout() if not self.messagePanel.IsShown(): self.messagePanel.Show() self.OnChange() self.Thaw() def GetMessage(self): header = message = None if self.headerText.IsShown(): header = self.headerText.GetLabel() if self.messageText.IsShown(): message = self.messageText.GetLabel() return header, message @warnWxThread def ShowLoading(self): self.ShowMessage('Loading, please wait.') @warnWxThread def RefreshData(self, key, data): if key in self.items: if DEBUG: print >> sys.stderr, "ListBody: refresh item", self.items[key] self.items[key].RefreshData(data) #forward update to expandedPanel panel = self.items[key].GetExpandedPanel() if panel and getattr(panel, 'RefreshData', False): if DEBUG: print >> sys.stderr, "ListBody: refresh item (Calling expandedPanel refreshdata)", self.items[ key] panel.RefreshData(data) @warnWxThread def SetData(self, data=None, highlight=None, force=False): if DEBUG: nr_items = 0 if data: nr_items = len(data) print >> sys.stderr, "ListBody: new data", time(), nr_items if data == None: data = self.raw_data else: self.raw_data = data assert len(data[0][1]) == len( self.columns ), 'Data does not have equal amount of columns %d/%d %s' % (len( data[0][1]), len(self.columns), type(self.parent_list)) if highlight is None: highlight = not self.IsEmpty() def doSetData(): self.lastData = time() self.dataTimer = None self.__SetData(highlight) if force: if self.dataTimer: self.dataTimer.Stop() doSetData() else: diff = time() - (self.listRateLimit + self.lastData) call_in = -diff * 1000 if call_in <= 0: doSetData() else: if self.dataTimer == None: self.dataTimer = wx.CallLater(call_in, doSetData) else: self.dataTimer.Restart(call_in) def __SetData(self, highlight=True): if DEBUG: print >> sys.stderr, "ListBody: __SetData", time() if __debug__ and currentThread().getName() != "MainThread": print >> sys.stderr, "ListBody: __SetData thread", currentThread( ).getName(), "is NOT MAIN THREAD" print_stack() self.Freeze() #apply quickfilter if self.filter: data = filter(self.filter, self.raw_data) if len(data) != len(self.raw_data): self.parent_list.SetFilteredResults(len(data)) else: self.parent_list.SetFilteredResults(None) else: self.parent_list.SetFilteredResults(None) data = self.raw_data if not data: data = [] self.highlightSet = set() cur_keys = set(self.items.keys()) for curdata in data[:self.list_cur_max]: key = curdata[0] if key not in cur_keys: if highlight: self.highlightSet.add(key) else: cur_keys.discard(key) #cur_keys now contains all removed items for key in cur_keys: self.items[key].Show(False) self.items[key].Destroy() del self.items[key] self.data = data self.DoSort() self.done = False if len(data) > 0: self.vSizer.ShowItems(False) self.vSizer.Clear() self.CreateItems(nr_items_to_create=3 * LIST_ITEM_BATCH_SIZE) #Try to yield try: wx.Yield() except: pass elif self.filter: self.ShowMessage(self.filterMessage(empty=True) + '.') if self.done: self.Unbind( wx.EVT_IDLE ) #unbinding unnecessary event handler seems to improve visual performance else: self.Bind(wx.EVT_IDLE, self.OnIdle) self.Thaw() def OnIdle(self, event): if not self.done: if self.data and len(self.data) > 0: self.CreateItems() else: self.done = True #idle event also paints search animation, use request more to show this update event.RequestMore(not self.done) if self.done: self.Unbind(wx.EVT_IDLE) def OnLoadMore(self, event): self.loadNext.Disable() self.list_cur_max += LIST_ITEM_MAX_SIZE wx.CallAfter(self.CreateItems) self.Bind(wx.EVT_IDLE, self.OnIdle) def OnLoadAll(self): self.loadNext.Disable() self.list_cur_max = sys.maxint wx.CallAfter(self.CreateItems) self.Bind(wx.EVT_IDLE, self.OnIdle) @warnWxThread def CreateItem(self, key): if not key in self.items and self.data: for curdata in self.data: if len(curdata) > 3: thiskey, item_data, original_data, create_method = curdata else: thiskey, item_data, original_data = curdata create_method = ListItem if key == thiskey: self.items[key] = create_method( self.listpanel, self, self.columns, item_data, original_data, self.leftSpacer, self.rightSpacer, showChange=self.showChange, list_selected=self.list_selected) if self.messagePanel.IsShown(): before = len(self.vSizer.GetChildren()) - 1 self.vSizer.Insert(before, self.items[key], 0, wx.EXPAND | wx.BOTTOM, 1) else: self.vSizer.Add(self.items[key], 0, wx.EXPAND | wx.BOTTOM, 1) self.OnChange() break @warnWxThread def CreateItems(self, nr_items_to_create=LIST_ITEM_BATCH_SIZE, nr_items_to_add=None): if not nr_items_to_add: nr_items_to_add = self.list_cur_max if DEBUG: print >> sys.stderr, "ListBody: Creating items", time() initial_nr_items_to_add = nr_items_to_add done = True if len(self.data) > 0: t1 = time() self.Freeze() #Check if we need to clear vSizer self.messagePanel.Show(False) self.loadNext.Show(False) self.vSizer.Remove(self.messagePanel) if self.filter: message = self.filterMessage() + '.' else: message = '' revertList = [] #Add created/cached items for curdata in self.data: if len(curdata) > 3: key, item_data, original_data, create_method = curdata else: key, item_data, original_data = curdata create_method = ListItem if nr_items_to_add > 0 and nr_items_to_create > 0: if key not in self.items: self.items[key] = create_method( self.listpanel, self, self.columns, item_data, original_data, self.leftSpacer, self.rightSpacer, showChange=self.showChange, list_selected=self.list_selected) nr_items_to_create -= 1 elif getattr(self.items[key], 'should_update', False): self.items[key].RefreshData(curdata) item = self.items[key] sizer = self.vSizer.GetItem(item) if not sizer: self.vSizer.Add(item, 0, wx.EXPAND | wx.BOTTOM, 1) item.Show() if key in self.highlightSet: self.highlightSet.remove(key) if item.Highlight(revert=False): revertList.append(key) nr_items_to_add -= 1 else: done = nr_items_to_add == 0 or initial_nr_items_to_add == sys.maxint if done: if message != '': message = 'Only showing the first %d of %d' % (len( self.vSizer.GetChildren() ), len(self.data)) + message[ 12:] + '\nFurther specify keywords to reduce the number of items, or click the button below.' else: message = 'Only showing the first %d of %d items in this list.' % ( len(self.vSizer.GetChildren()), len(self.data)) if self.hasFilter: message += '\nSearch within results to reduce the number of items, or click the button below.' remainingItems = min( LIST_ITEM_MAX_SIZE, len(self.data) - len(self.vSizer.GetChildren())) self.loadNext.SetLabel("Show next %d items" % remainingItems) self.loadNext.Enable() self.loadNext.Show() break if len(message) > 12: self.messageText.SetLabel(message) self.vSizer.Add(self.messagePanel, 0, wx.EXPAND | wx.BOTTOM, 1) self.messagePanel.Layout() self.messagePanel.Show() self.OnChange() self.Thaw() if len(revertList) > 0: wx.CallLater(1000, self.Revert, revertList) if len(revertList) > 0: wx.CallLater(1000, self.Revert, revertList) self.done = done if DEBUG: print >> sys.stderr, "List created", len( self.vSizer.GetChildren()), "rows of", len( self.data), "took", time() - t1, "done:", self.done def GetItem(self, key): return self.items[key] def GetItemPos(self, key): # Returns the index of the ListItem belonging to this key for i, data in enumerate(self.data): if key == data[0]: return i @warnWxThread def RemoveItem(self, remove): for key, item in self.items.iteritems(): if item == remove: self.RemoveKey(key) break @warnWxThread def RemoveKey(self, key): item = self.items.get(key, None) if item: self.items.pop(key) self.vSizer.Detach(item) item.Destroy() self.OnChange() for i, curdata in enumerate(self.raw_data): if curdata[0] == key: self.raw_data.pop(i) break def GetExpandedItem(self): return self.cur_expanded def GetExpandedItems(self): return [(key, item) for key, item in self.items.iteritems() if item.expanded] @warnWxThread def Select(self, key, raise_event=True): self.DeselectAll() #check if we need to create this item on the spot if not key in self.items: self.CreateItem(key) if key in self.items: if raise_event: self.items[key].OnClick(None) else: self.items[key].expanded = True self.cur_expanded = self.items[key] self.items[key].ShowSelected() @warnWxThread def DeselectAll(self): for _, item in self.items.iteritems(): item.Deselect() def Revert(self, revertList): for key in revertList: if key in self.items: self.items[key].Revert() def OnEventSize(self, event): width = self.GetSize()[0] if width != self.curWidth: doOnChange = False self.Freeze() self.curWidth = width for item in self.items.itervalues(): if item.OnEventSize(width): doOnChange = True if doOnChange: self.OnChange() self.Thaw() event.Skip()
class SearchSideBar(wx.Panel): INDENT = 7 HEADER_FONT_WEIGHT = wx.FONTWEIGHT_NORMAL def __init__(self, parent, parent_list, size): wx.Panel.__init__(self, parent, size = size) self.SetForegroundColour(parent.GetForegroundColour()) self.guiutility = GUIUtility.getInstance() self.torrentsearch_manager = self.guiutility.torrentsearch_manager self.parent = parent self.parent_list = parent_list self.nrfiltered = 0 self.family_filter = True self.bundlestates = [Bundler.ALG_MAGIC, Bundler.ALG_NAME, Bundler.ALG_NUMBERS, Bundler.ALG_SIZE, Bundler.ALG_OFF] self.bundlestates_str = {Bundler.ALG_NAME: 'Name', Bundler.ALG_NUMBERS: 'Numbers', Bundler.ALG_SIZE: 'Size', Bundler.ALG_MAGIC: 'Magic', Bundler.ALG_OFF: 'Off'} self.bundletexts = [] self.bundle_db = BundlerPreferenceDBHandler.getInstance() self.uelog = UserEventLogDBHandler.getInstance() self.vSizer = wx.BoxSizer(wx.VERTICAL) hSizer = wx.BoxSizer(wx.HORIZONTAL) header = StaticText(self, -1, 'Search') if SearchSideBar.HEADER_FONT_WEIGHT != wx.FONTWEIGHT_NORMAL: font = header.GetFont() font.SetWeight(SearchSideBar.HEADER_FONT_WEIGHT) header.SetFont(font) hSizer.Add(header, 0, wx.ALIGN_CENTER_VERTICAL) self.searchState = StaticText(self) hSizer.Add(self.searchState, 1, wx.ALIGN_CENTER_VERTICAL) ag_fname = os.path.join(self.guiutility.utility.getPath(), LIBRARYNAME, 'Main', 'vwxGUI', 'images', 'search_new.gif') self.ag = wx.animate.GIFAnimationCtrl(self, -1, ag_fname) self.ag.UseBackgroundColour(True) self.ag.Hide() hSizer.Add(self.ag, 0, wx.RESERVE_SPACE_EVEN_IF_HIDDEN) self.vSizer.Add(hSizer, 0, wx.EXPAND|wx.BOTTOM, 3) self.vSizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.BOTTOM, 3) self.searchGauge = wx.Gauge(self, size = (-1, 7)) self.vSizer.Add(self.searchGauge, 0, wx.EXPAND|wx.RESERVE_SPACE_EVEN_IF_HIDDEN) self.vSizer.AddSpacer((-1,15)) hSizer = wx.BoxSizer(wx.HORIZONTAL) header = StaticText(self, -1, 'Family Filter') if SearchSideBar.HEADER_FONT_WEIGHT != wx.FONTWEIGHT_NORMAL: font = header.GetFont() font.SetWeight(SearchSideBar.HEADER_FONT_WEIGHT) header.SetFont(font) hSizer.Add(header) self.ffstate = StaticText(self) hSizer.Add(self.ffstate) self.vSizer.Add(hSizer, 0, wx.EXPAND|wx.BOTTOM, 3) self.vSizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.BOTTOM, 3) self.ffblocked = StaticText(self) self.vSizer.Add(self.ffblocked, 0, wx.EXPAND|wx.LEFT, SearchSideBar.INDENT) self.ffbutton = LinkStaticText(self, '', None) self.ffbutton.Bind(wx.EVT_LEFT_UP, self.toggleFamilyFilter) self.vSizer.Add(self.ffbutton, 0, wx.EXPAND|wx.LEFT, SearchSideBar.INDENT) self.vSizer.AddSpacer((-1,15)) hSizer = wx.BoxSizer(wx.HORIZONTAL) header = StaticText(self, -1, 'Bundling') if SearchSideBar.HEADER_FONT_WEIGHT != wx.FONTWEIGHT_NORMAL: font = header.GetFont() font.SetWeight(SearchSideBar.HEADER_FONT_WEIGHT) header.SetFont(font) hSizer.Add(header) #keep longest text in bundlestatetext, to define bestsize (width) for sidepanel self.bundlestatetext = StaticText(self, -1, ' by Numbers') hSizer.Add(self.bundlestatetext) self.vSizer.Add(hSizer, 0, wx.EXPAND|wx.BOTTOM, 3) self.vSizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.BOTTOM, 3) self.bundleSizer = wx.FlexGridSizer(0, 2, 0, 0) self.SetBundleState(None, reset = True) self.vSizer.Add(self.bundleSizer, 0, wx.EXPAND|wx.LEFT, SearchSideBar.INDENT) self.vSizer.AddSpacer((-1,15)) header = StaticText(self, -1, 'Associated Channels') if SearchSideBar.HEADER_FONT_WEIGHT != wx.FONTWEIGHT_NORMAL: font = header.GetFont() font.SetWeight(SearchSideBar.HEADER_FONT_WEIGHT) header.SetFont(font) self.vSizer.Add(header, 0, wx.EXPAND|wx.BOTTOM, 3) self.vSizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.BOTTOM, 3) self.nochannels = StaticText(self, -1, 'None') self.vSizer.Add(self.nochannels, 0, wx.EXPAND|wx.LEFT, SearchSideBar.INDENT) self.channels = [LinkStaticText(self, '', icon = None) for _ in range(3)] for channel in self.channels: self.vSizer.Add(channel, 0, wx.EXPAND|wx.LEFT, SearchSideBar.INDENT) channel.Bind(wx.EVT_LEFT_UP, self.OnChannel) borderSizer = wx.BoxSizer(wx.VERTICAL) borderSizer.AddSpacer((-1, 3)) borderSizer.Add(self.vSizer, 1, wx.EXPAND|wx.LEFT|wx.RIGHT, 7) self.SetSizer(borderSizer) self.SetMinSize((self.GetBestSize()[0], -1)) self.Reset() def SetFF(self, family_filter, nrfiltered): self.family_filter = family_filter self.nrfiltered = nrfiltered self._SetLabels() @forceWxThread def SetMaxResults(self, max, remotekeywords): self.Freeze() self.searchGauge.SetRange(max) self.searchGauge.SetValue(0) self.searchGauge.Show() self.searchState.SetLabel(' in progress') wx.CallLater(10000, self.SetFinished, remotekeywords) self.ag.Play() self.ag.Show() self.Thaw() @forceWxThread def NewResult(self): maxValue = self.searchGauge.GetRange() newValue = min(self.searchGauge.GetValue() + 1, maxValue) if newValue == maxValue: self.SetFinished(None) else: self.searchGauge.SetValue(newValue) def SetFinished(self, keywords): curkeywords, hits, filtered = self.guiutility.torrentsearch_manager.getSearchKeywords() if not keywords or curkeywords == keywords: self.Freeze() self.ag.Stop() self.ag.Hide() self.searchGauge.Hide() self.searchState.SetLabel(' completed') self.Layout() self.Thaw() self.guiutility.frame.searchlist.SetFinished() @forceWxThread def SetAssociatedChannels(self, channels): #channels should be a list, of occurrences, name, permid self.Freeze() self.nochannels.Show(len(channels) == 0) for i in range(len(self.channels)): if i < len(channels): tooltip = "Click to go to %s's Channel."%channels[i][-1].name self.channels[i].SetLabel(channels[i][-1].name) self.channels[i].SetToolTipString(tooltip) self.channels[i].channel = channels[i][-1] else: self.channels[i].SetLabel('') self.channels[i].SetToolTipString('') self.Layout() self.Thaw() def toggleFamilyFilter(self, event): self.parent_list.toggleFamilyFilter() def _SetLabels(self): self.Freeze() if self.family_filter: if self.nrfiltered > 0: if self.nrfiltered > 1: self.ffblocked.SetLabel('%d results blocked'%self.nrfiltered) else: self.ffblocked.SetLabel('1 result blocked') self.vSizer.Detach(self.ffblocked) self.vSizer.Insert(6, self.ffblocked, 0, wx.EXPAND|wx.LEFT, 7) else: self.ffblocked.SetLabel('') self.vSizer.Detach(self.ffblocked) self.vSizer.Insert(7, self.ffblocked) self.ffstate.SetLabel(' is On') self.ffbutton.SetLabel('turn off') else: self.ffstate.SetLabel(' is Off') self.ffbutton.SetLabel('turn on') self.ffblocked.SetLabel('') self.Layout() self.Thaw() def Reset(self): self.SetBundleState(None,refresh=False,reset=True) self.nochannels.Show() self.searchState.SetLabel(' in progress') for channel in self.channels: channel.SetLabel('') channel.SetToolTipString('') def OnRebundle(self, event): curstate = self.bundlestate selectedByMagic = -1 for i, text in enumerate(self.bundletexts): if isinstance(text, LinkStaticText) and text.IsIconShown(): selectedByMagic = self.bundlestates[i] break newstate = event.GetEventObject().action self.SetBundleState(newstate) def db_callback(): keywords = self.torrentsearch_manager.getSearchKeywords()[0] self.bundle_db.storePreference(keywords, newstate) query = ' '.join(keywords) selectedByMagicStr = '' if selectedByMagic != -1: selectedByMagicStr = self.bundlestates_str[selectedByMagic] self.uelog.addEvent(message="Bundler GUI: %s -> %s; %s -> %s; selectedByMagic %s (%s); q=%s" % (curstate, newstate, self.bundlestates_str[curstate], self.bundlestates_str[newstate], selectedByMagic, selectedByMagicStr, query), type = 3) self.guiutility.frame.guiserver.add_task(db_callback) def SetBundleState(self, newstate, refresh=True, reset=False): if newstate is None: auto_guess = self.guiutility.utility.config.Read('use_bundle_magic', "boolean") newstate = Bundler.ALG_OFF # default stored_state = None if not reset: keywords = self.torrentsearch_manager.getSearchKeywords()[0] if keywords != '': try: stored_state = self.bundle_db.getPreference(keywords) except: pass #if db interaction fails, ignore local_override = stored_state is not None if local_override: newstate = stored_state elif auto_guess: newstate = Bundler.ALG_MAGIC self.bundlestate = newstate self.selected_bundle_mode = None self.Freeze() if newstate != Bundler.ALG_OFF: self.bundlestatetext.SetLabel(' by %s' % self.bundlestates_str[newstate]) else: self.bundlestatetext.SetLabel(' is %s' % self.bundlestates_str[newstate]) self.torrentsearch_manager.setBundleMode(newstate, refresh) self.bundleSizer.ShowItems(False) self.bundleSizer.Clear(deleteWindows = True) self.bundletexts = [] self.bundleSizer.Add(StaticText(self, -1, 'Bundle by ')) for i, state in enumerate(self.bundlestates): if newstate == state: text = StaticText(self, -1, self.bundlestates_str[state]) self.bundleSizer.Add(text) self.bundletexts.append(text) else: link = LinkStaticText(self, self.bundlestates_str[state], "wand.png") link.ShowIcon(False) link.SetIconToolTipString('Selected by Magic') link.Bind(wx.EVT_LEFT_UP, self.OnRebundle) link.action = state self.bundleSizer.Add(link) self.bundletexts.append(link) if i+1 < len(self.bundlestates): self.bundleSizer.AddSpacer((1, -1)) self.Layout() self.Thaw() def SetSelectedBundleMode(self, selected_bundle_mode): if self.bundlestate == Bundler.ALG_MAGIC: self.Freeze() self.selected_bundle_mode = selected_bundle_mode index = self.bundlestates.index(selected_bundle_mode) for i in range(len(self.bundletexts)): linkStaticText = self.bundletexts[i] if isinstance(linkStaticText, LinkStaticText): if i == index: if not linkStaticText.IsIconShown(): linkStaticText.ShowIcon(True) wx.CallAfter(linkStaticText.Blink) else: linkStaticText.ShowIcon(False) self.Thaw() def OnChannel(self, event): label = event.GetEventObject() channel_name = label.GetLabel() if channel_name != '': channel = label.channel self.guiutility.showChannel(channel) def SetBackgroundColour(self, colour): wx.Panel.SetBackgroundColour(self, colour) self.ffbutton.SetBackgroundColour(colour) self.ag.SetBackgroundColour(colour) for channel in self.channels: channel.SetBackgroundColour(colour) for sizeritem in self.bundleSizer.GetChildren(): if sizeritem.IsWindow(): child = sizeritem.GetWindow() if isinstance(child, wx.Panel): child.SetBackgroundColour(colour)