def addColumn(strkey, strtooltip): # strkey = key.replace("_", " ").capitalize() header = StaticText(self.panel, -1, strkey) _set_font(header, fontweight=wx.FONTWEIGHT_BOLD) self.gridSizer.Add(header) self.textdict[strkey] = StaticText(self.panel, -1, '') self.textdict[strkey].SetMinSize((200, -1)) self.gridSizer.Add(self.textdict[strkey]) if strtooltip: header.SetToolTipString(strtooltip) self.textdict[strkey].SetToolTipString(strtooltip)
class NetworkPanel(HomePanel): def __init__(self, parent): HomePanel.__init__(self, parent, 'Network info', SEPARATOR_GREY, (0, 1)) self.torrentdb = parent.guiutility.utility.session.open_dbhandler( NTFY_TORRENTS) self.channelcastdb = parent.guiutility.utility.session.open_dbhandler( NTFY_CHANNELCAST) self.remotetorrenthandler = parent.guiutility.utility.session.lm.rtorrent_handler self.timer = None session = Session.get_instance() session.add_observer(self.OnNotify, NTFY_TORRENTS, [NTFY_INSERT]) self.UpdateStats() def CreatePanel(self): panel = wx.Panel(self) panel.SetBackgroundColour(DEFAULT_BACKGROUND) vSizer = wx.BoxSizer(wx.VERTICAL) self.nrTorrents = StaticText(panel) self.nrFiles = StaticText(panel) self.totalSize = StaticText(panel) self.queueSize = StaticText(panel) self.queueSize.SetToolTipString('Number of torrents queued per prio') self.queueSuccess = StaticText(panel) self.queueBW = StaticText(panel) self.queueBW.SetToolTipString( 'Bandwidth spent on collecting .torrents') self.nrChannels = StaticText(panel) self.freeMem = None try: if wx.GetFreeMemory() != -1: self.freeMem = StaticText(panel) except: pass gridSizer = wx.FlexGridSizer(0, 2, 3, 10) gridSizer.AddGrowableCol(1) gridSizer.Add(StaticText(panel, -1, 'Number files')) gridSizer.Add(self.nrFiles, 0, wx.EXPAND) gridSizer.Add(StaticText(panel, -1, 'Total size')) gridSizer.Add(self.totalSize, 0, wx.EXPAND) gridSizer.Add(StaticText(panel, -1, 'Torrents collected')) gridSizer.Add(self.nrTorrents, 0, wx.EXPAND) gridSizer.Add(StaticText(panel, -1, 'Torrents in queue')) gridSizer.Add(self.queueSize, 0, wx.EXPAND) gridSizer.Add(StaticText(panel, -1, 'Torrent queue success')) gridSizer.Add(self.queueSuccess, 0, wx.EXPAND) gridSizer.Add(StaticText(panel, -1, 'Torrent queue bw')) gridSizer.Add(self.queueBW, 0, wx.EXPAND) gridSizer.Add(StaticText(panel, -1, 'Channels found')) gridSizer.Add(self.nrChannels, 0, wx.EXPAND) if self.freeMem: gridSizer.Add(StaticText(panel, -1, 'WX:Free memory')) gridSizer.Add(self.freeMem, 0, wx.EXPAND) vSizer.Add(gridSizer, 0, wx.EXPAND | wx.LEFT, 7) panel.SetSizer(vSizer) return panel def OnNotify(self, subject, type, infohash): try: if self.IsShownOnScreen(): self.UpdateStats() except wx.PyDeadObjectError: pass def UpdateStats(self): def db_callback(): stats = self.torrentdb.getTorrentsStats() nr_channels = self.channelcastdb.getNrChannels() self._UpdateStats(stats, nr_channels) startWorker(None, db_callback, uId=u"NetworkPanel_UpdateStats", priority=GUI_PRI_DISPERSY) @forceWxThread def _UpdateStats(self, stats, nr_channels): self.nrTorrents.SetLabel(str(stats[0])) if stats[1] is None: self.totalSize.SetLabel(str(stats[1])) else: self.totalSize.SetLabel(size_format(stats[1])) self.nrFiles.SetLabel(str(stats[2])) self.queueSize.SetLabel(self.remotetorrenthandler.getQueueSize()) self.queueBW.SetLabel(self.remotetorrenthandler.getBandwidthSpent()) qsuccess = self.remotetorrenthandler.getQueueSuccess() qlabel = ", ".join(label for label, tooltip in qsuccess) qtooltip = ", ".join(tooltip for label, tooltip in qsuccess) self.queueSuccess.SetLabel(qlabel) self.queueSuccess.SetToolTipString(qtooltip) self.nrChannels.SetLabel(str(nr_channels)) if self.freeMem: self.freeMem.SetLabel(size_format(wx.GetFreeMemory())) if self.timer: self.timer.Restart(10000) else: self.timer = wx.CallLater(10000, self.UpdateStats)
class BundlePanel(wx.BoxSizer): COLLAPSED, PARTIAL, FULL = range(3) icons = None @classmethod def load_icons(cls): if not cls.icons: icons = cls.icons = {} guiUtility = GUIUtility.getInstance() utility = guiUtility.utility base_path = os.path.join(utility.getPath(), LIBRARYNAME, "Main", "vwxGUI", "images") icons['info'] = wx.Bitmap(os.path.join(base_path, "info.png"), wx.BITMAP_TYPE_ANY) def __init__(self, parent, parent_list, hits, general_description=None, description=None, font_increment=0): wx.BoxSizer.__init__(self, wx.HORIZONTAL) # preload icons self.load_icons() self.parent = parent self.parent_listitem = parent self.parent_list = parent_list listbody_width = parent_list.GetSize()[0] if listbody_width < BUNDLE_GRID_COLLAPSE: self.num_cols = 1 else: self.num_cols = BUNDLE_NUM_COLS # logging self.guiutility = GUIUtility.getInstance() self.uelog = UserEventLogDBHandler.getInstance() self.state = BundlePanel.COLLAPSED self.nrhits = -1 self.bundlelist = None self.font_increment = font_increment self.vsizer = wx.BoxSizer(wx.VERTICAL) self.SetBackgroundColour(DEFAULT_BACKGROUND) self.indent = 3 + 3 + self.parent_list.leftSpacer # width of 3px left spacer + 3px right spacer self.AddHeader() self.AddGrid() self.SetHits(hits, noChange=True) self.UpdateHeader(general_description, description) self.AddSpacer((self.indent, -1)) self.Add(self.vsizer, 1, wx.EXPAND | wx.BOTTOM, 7) def AddHeader(self): sizer = wx.BoxSizer(wx.HORIZONTAL) self.header = StaticText(self.parent, -1, ' ') self.info_icon = wx.StaticBitmap(self.parent, -1, self.icons['info']) sizer.Add(self.header, 0, wx.RIGHT, 7) sizer.Add(self.info_icon, 0, wx.ALIGN_CENTER_VERTICAL) self.vsizer.Add(sizer, 0, wx.BOTTOM, 3) def UpdateHeader(self, general_description, description): self.SetGeneralDescription(general_description) self.SetDescription(description) def AddGrid(self): self.grid = wx.FlexGridSizer(0, self.num_cols, 3, 7) self.grid.SetFlexibleDirection(wx.HORIZONTAL) self.grid.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_NONE) self.grid.SetMinSize((1, -1)) for i in xrange(BUNDLE_NUM_ROWS): self.grid.AddGrowableRow(i, 1) for j in xrange(self.num_cols): self.grid.AddGrowableCol(j, 1) self.vsizer.Add(self.grid, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 14 + self.indent) def RebuildGrid(self, new_cols): if self.num_cols != new_cols: self.num_cols = new_cols children = self.grid.GetChildren() children_controls = [] for child in children: children_controls.append(child.GetWindow() or child.GetSizer()) for child in children_controls: self.grid.Detach(child) self.vsizer.Detach(self.grid) self.grid.Destroy() self.grid = wx.FlexGridSizer(0, self.num_cols, 3, 7) for child in children_controls: self.grid.Add(child, 0, wx.EXPAND) for j in xrange(self.num_cols): self.grid.AddGrowableCol(j, 1) self.vsizer.Add(self.grid, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 14 + self.indent) self.Layout() self.parent_listitem.Layout() return True return False def UpdateGrid(self, hits, noChange=False): N = BUNDLE_NUM_ROWS * BUNDLE_NUM_COLS items_to_add = min(N, self.nrhits) if self.nrhits > N: items_to_add -= 1 self.parent.Freeze() children = self.grid.GetChildren() didChange = len(children) < min(N, self.nrhits) if not didChange: if DEBUG: print >> sys.stderr, "*** BundlePanel.UpdateGrid: total nr items did not change, updating labels only" # total nr items did not change for i in range(items_to_add): link_static_text = children[i].GetWindow( ) or children[i].GetSizer() if link_static_text and getattr(link_static_text, 'SetLabel', False): link_static_text.SetLabel(hits[i].name) link_static_text.action = hits[i] else: didChange = True break if self.nrhits > N: more_caption = '(%s more...)' % (self.nrhits - N + 1) link_static_text = children[i + 1].GetWindow() or children[ i + 1].GetSizer() if link_static_text and getattr(link_static_text, 'SetLabel', False): link_static_text.SetLabel(more_caption) link_static_text.Unbind(wx.EVT_LEFT_UP) link_static_text.Bind(wx.EVT_LEFT_UP, self.OnMoreClick) else: didChange = True if didChange: if DEBUG: print >> sys.stderr, "*** BundlePanel.UpdateGrid: something did change rebuilding grid", len( children), min(N, self.nrhits) curRows = len(children) / BUNDLE_NUM_COLS newRows = min(self.nrhits / BUNDLE_NUM_COLS, BUNDLE_NUM_ROWS) rowsChanged = curRows != newRows self.grid.ShowItems(False) self.grid.Clear(deleteWindows=True) for i in range(items_to_add): hit = hits[i] new_text = LinkStaticText(self.parent, hit.name, icon=False, icon_align=wx.ALIGN_LEFT, font_increment=self.font_increment, font_colour=BUNDLE_FONT_COLOR) new_text.Bind(wx.EVT_LEFT_UP, self.OnBundleLinkClick) new_text.SetMinSize((1, -1)) new_text.action = hit self.grid.Add(new_text, 0, wx.EXPAND) if self.nrhits > N: caption = '(%s more...)' % (self.nrhits - N + 1) more_label = LinkStaticText(self.parent, caption, icon=False, icon_align=wx.ALIGN_LEFT, font_increment=self.font_increment, font_colour=BUNDLE_FONT_COLOR) more_label.Bind(wx.EVT_LEFT_UP, self.OnMoreClick) self.grid.Add(more_label, 0, wx.EXPAND) self.parent_listitem.AddEvents(self.grid) if self.state != self.COLLAPSED: self.ShowGrid(False) if rowsChanged and not noChange: self.parent_listitem.OnChange() self.parent.Thaw() return didChange def OnEventSize(self, width): if width < BUNDLE_GRID_COLLAPSE: return self.RebuildGrid(1) return self.RebuildGrid(BUNDLE_NUM_COLS) def ShowGrid(self, show): if show: self.grid.ShowItems(True) else: self.grid.ShowItems(False) def UpdateList(self, hits): self.hits = hits if self.bundlelist: self.bundlelist.SetData(hits) if self.state == BundlePanel.FULL: self.bundlelist.OnLoadAll() def ShowList(self, show): if self.bundlelist is None and show: max_list = BUNDLE_NUM_ROWS * BUNDLE_NUM_COLS if len(self.hits) != BUNDLE_NUM_ROWS * BUNDLE_NUM_COLS: max_list -= 1 self.bundlelist = BundleListView(parent=self.parent, list_item_max=max_list) self.vsizer.Add(self.bundlelist, 0, wx.EXPAND | wx.BOTTOM, self.indent - 7) #a 7px spacer is already present # SetData does wx.Yield, which could cause a collapse event to be processed within the setdata # method. Thus we have to do this after the add to the sizer self.bundlelist.SetData(self.hits) elif self.bundlelist is not None and not show: self.vsizer.Detach(self.bundlelist) self.bundlelist.Show(False) self.bundlelist.Destroy() self.bundlelist = None def CollapseExpandedItem(self): if self.state != BundlePanel.COLLAPSED: self.bundlelist.list.OnCollapse() def RefreshDataBundleList(self, key, data): if self.bundlelist is not None: self.bundlelist.RefreshData(key, data) def SetDescription(self, description): self.header.SetToolTipString(description) self.info_icon.SetToolTipString(description) def SetGeneralDescription(self, general_description): if general_description: general_description = unicode(general_description) else: general_description = u'Similar' self.header.SetLabel(u'%s items (%s):' % (general_description, self.nrhits)) def SetHits(self, hits, noChange=False): self.nrhits = len(hits) gridChanged = self.UpdateGrid(hits, noChange) self.UpdateList(hits) self.Layout() return gridChanged def ChangeState(self, new_state, doLayout=True): if self.state != new_state: old_state = self.state self.state = new_state if new_state == BundlePanel.COLLAPSED: self.ShowList(False) self.ShowGrid(True) else: if new_state == BundlePanel.PARTIAL or new_state == BundlePanel.FULL: self.ShowGrid(False) if old_state == BundlePanel.COLLAPSED: self.ShowList(True) if new_state == BundlePanel.FULL and self.bundlelist: self.bundlelist.OnLoadAll() if DEBUG: statestr = lambda st: ['COLLAPSED', 'PARTIAL', 'FULL'][st] print >> sys.stderr, '*** BundlePanel.ChangeState: %s --> %s' % ( statestr(old_state), statestr(new_state)) def ExpandHit(self, hit): id = hit.infohash self.bundlelist.ExpandItem(id) self.parent_listitem.ShowSelected() def OnBundleLinkClick(self, event): # do expand # self.ExpandAndHideParent() staticText = event.GetEventObject() action = getattr(staticText, 'action', None) if action is not None: # Reason for non-persistence (for now) is least-surprise. # If the user collapses a bundled listitem, the previously # clicked item is still at the same location. if action in self.hits: self.hits.remove(action) self.hits.insert(0, action) # self.ChangeState(BundlePanel.PARTIAL) # self.ExpandHit(action) self.SetBackgroundColour(self.parent.GetBackgroundColour()) from __init__ import TRIBLER_RED, LIST_HIGHTLIGHT event.GetEventObject().SetBackgroundColour(LIST_HIGHTLIGHT) for item in self.parent_listitem.bundle: if action.infohash == item.infohash: td = TorrentDetails( self.guiutility.frame.splitter_bottom_window, item) item.expandedPanel = td self.guiutility.SetBottomSplitterWindow(td) def db_callback(): self.uelog.addEvent( message="Bundler GUI: BundleLink click; %s; %s;" % (self.nrhits, self.parent_listitem.general_description), type=3) self.guiutility.frame.guiserver.add_task(db_callback) def OnMoreClick(self, event): return # do expand self.ExpandAndHideParent() self.ChangeState(BundlePanel.FULL) def db_callback(): self.uelog.addEvent( message="Bundler GUI: More click; %s; %s;" % (self.nrhits, self.parent_listitem.general_description), type=3) self.guiutility.frame.guiserver.add_task(db_callback) def ExpandAndHideParent(self): self.parent.Freeze() if not self.parent_listitem.expanded: # Make sure the listitem is marked as expanded self.parent_listitem.OnClick() # but hide the panel self.parent_listitem.ShowExpandedPanel(False) self.parent.Thaw() # Called from GUI to get expanded torrentdetails panel def GetExpandedPanel(self): if self.bundlelist: item = self.bundlelist.GetExpandedItem() if item: return item.GetExpandedPanel() def SetBackgroundColour(self, colour): self.parent.Freeze() if getattr(self, 'grid', False): for sizeritem in self.grid.GetChildren(): child = sizeritem.GetWindow() or sizeritem.GetSizer() if child and getattr(child, 'SetBackgroundColour', False): child.SetBackgroundColour(colour) self.parent.Thaw()