?? btdownloadgui.py
字號:
self.sw.set_shadow_type(gtk.SHADOW_IN) self.win.add(self.sw) column_header = ['IP address', 'Client', 'Connection', 'KB/s down', 'KB/s up', 'MB downloaded', 'MB uploaded', '% complete', 'KB/s est. peer download'] pre_size_list = ['666.666.666.666', 'TorrentStorm 1.3', 'bad peer', 66666, 66666, '1666.66', '1666.66', '100.0', 6666] numeric_cols = [3,4,5,6,7,8] store_types = [gobject.TYPE_STRING]*3 + [gobject.TYPE_INT]*2 + [gobject.TYPE_STRING]*3 + [gobject.TYPE_INT] if advanced_ui: column_header[2:2] = ['Peer ID'] pre_size_list[2:2] = ['-AZ2104-'] store_types[2:2] = [gobject.TYPE_STRING] column_header[5:5] = ['Interested','Choked','Snubbed'] pre_size_list[5:5] = ['*','*','*'] store_types[5:5] = [gobject.TYPE_STRING]*3 column_header[9:9] = ['Interested','Choked','Optimistic upload'] pre_size_list[9:9] = ['*','*','*'] store_types[9:9] = [gobject.TYPE_STRING]*3 numeric_cols = [4,8,12,13,14,15] num_columns = len(column_header) self.store = gtk.ListStore(*store_types) self.store.append(pre_size_list) def makesortfunc(sort_func): def sortfunc(treemodel, iter1, iter2, column): a_str = treemodel.get_value(iter1, column) b_str = treemodel.get_value(iter2, column) if a_str is not None and b_str is not None: return sort_func(a_str,b_str) else: return 0 return sortfunc def ip_sort(a_str,b_str): a = map(int, a_str.split('.')) b = map(int, b_str.split('.')) return cmp(a,b) def float_sort(a_str,b_str): a,b = 0,0 try: a = float(a_str) except ValueError: pass try: b = float(b_str) except ValueError: pass return cmp(a,b) self.store.set_sort_func(0, makesortfunc(ip_sort), 0) for i in range(2,5): self.store.set_sort_func(num_columns-i, makesortfunc(float_sort), num_columns-i) self.treeview = gtk.TreeView(self.store) cs = [] for i, name in enumerate(column_header): r = gtk.CellRendererText() if i in numeric_cols: r.set_property('xalign', 1) column = gtk.TreeViewColumn(name, r, text = i) column.set_resizable(True) column.set_min_width(5) column.set_sort_column_id(i) self.treeview.append_column(column) cs.append(column) self.treeview.set_rules_hint(True) self.sw.add(self.treeview) self.treeview.set_headers_visible(False) self.treeview.columns_autosize() self.sw.show_all() self.treeview.realize() for column in cs: column.set_fixed_width(column.get_width()) column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) self.treeview.set_headers_visible(True) self.store.clear() self.treeview.get_selection().set_mode(gtk.SELECTION_NONE) width = self.treeview.size_request()[0] self.win.set_default_size(width+SCROLLBAR_WIDTH, 300) self.win.show_all() self.prev = [] def update(self, peers, bad_peers): fields = [] def p_bool(value): return value and '*' or '' for peer in peers: field = [] field.append(peer['ip']) client, version = ClientIdentifier.identify_client(peer['id']) field.append(client + ' ' + version) if advanced_ui: field.append(quote(peer['id'])) field.append(peer['initiation'] == 'R' and 'remote' or 'local') dl = peer['download'] ul = peer['upload'] for l in (dl, ul): rate = l[1] if rate > 100: field.append(int(round(rate/(2**10)))) else: field.append(0) if advanced_ui: field.append(p_bool(l[2])) field.append(p_bool(l[3])) if len(l) > 4: field.append(p_bool(l[4])) else: field.append(p_bool(peer['is_optimistic_unchoke'])) field.append('%.2f'%round(dl[0] / 2**20, 2)) field.append('%.2f'%round(ul[0] / 2**20, 2)) field.append('%.1f'%round(int(peer['completed']*1000)/10, 1)) field.append(int(peer['speed']//(2**10))) fields.append(field) for (ip, (is_banned, stats)) in bad_peers.iteritems(): field = [] field.append(ip) client, version = ClientIdentifier.identify_client(stats.peerid) field.append(client + ' ' + version) if advanced_ui: field.append(quote(stats.peerid)) field.append('bad peer') # the sortable peer list won't take strings in these fields field.append(0) if advanced_ui: field.extend([0] * 7) # upRate, * fields else: field.extend([0] * 1) # upRate field.append("%d ok" % stats.numgood) field.append("%d bad" % len(stats.bad)) if is_banned: # completion field.append('banned') else: field.append('ok') field.append(0) # peer dl rate fields.append(field) if self.store.get_sort_column_id() < 0: # ListStore is unsorted, it might be faster to set only modified fields it = self.store.get_iter_first() for old, new in itertools.izip(self.prev, fields): if old != new: for i, value in enumerate(new): if value != old[i]: self.store.set_value(it, i, value) it = self.store.iter_next(it) for i in range(len(fields), len(self.prev)): self.store.remove(it) for i in range(len(self.prev), len(fields)): self.store.append(fields[i]) self.prev = fields else: # ListStore is sorted, no reason not to to reset all fields self.store.clear() for field in fields: self.store.append(field) def close(self): self.win.destroy()class TorrentInfoWindow(object): def __init__(self, torrent_box, closefunc): self.win = Window() self.torrent_box = torrent_box name = self.torrent_box.metainfo.name self.win.set_title('Info for "%s"'%name) self.win.set_size_request(-1,-1) self.win.set_border_width(SPACING) self.win.set_resizable(False) self.win.connect('destroy', closefunc) self.vbox = gtk.VBox(spacing=SPACING) self.table = gtk.Table(rows=4, columns=3, homogeneous=False) self.table.set_row_spacings(SPACING) self.table.set_col_spacings(SPACING) y = 0 def add_item(key, val, y): self.table.attach(ralign(gtk.Label(key)), 0, 1, y, y+1) v = gtk.Label(val) v.set_selectable(True) self.table.attach(lalign(v), 1, 2, y, y+1) add_item('Torrent name:', name, y) y+=1 add_item('Announce url:', self.torrent_box.metainfo.announce, y) y+=1 size = Size(self.torrent_box.metainfo.total_bytes) num_files = ', in one file' if self.torrent_box.is_batch: num_files = ', in %d files' % len(self.torrent_box.metainfo.sizes) add_item('Total size:', str(size)+num_files, y) y+=1 if advanced_ui: pl = self.torrent_box.metainfo.piece_length count, lastlen = divmod(size, pl) sizedetail = '%d x %d + %d = %d' % (count, pl, lastlen, int(size)) add_item('Pieces:', sizedetail, y) y+=1 add_item('Info hash:', self.torrent_box.infohash.encode('hex'), y) y+=1 path = self.torrent_box.dlpath filename = '' if not self.torrent_box.is_batch: path,filename = os.path.split(self.torrent_box.dlpath) if path[-1] != os.sep: path += os.sep path = path_wrap(path) add_item('Save in:', path, y) y+=1 if not self.torrent_box.is_batch: add_item('File name:', filename, y) y+=1 self.vbox.pack_start(self.table) self.vbox.pack_start(gtk.HSeparator(), expand=False, fill=False) self.hbox = gtk.HBox(spacing=SPACING) lbbox = gtk.HButtonBox() rbbox = gtk.HButtonBox() lbbox.set_spacing(SPACING) if OpenPath.can_open_files: opendirbutton = IconButton("Open directory", stock=gtk.STOCK_OPEN) opendirbutton.connect('clicked', self.torrent_box.open_dir) lbbox.pack_start(opendirbutton, expand=False, fill=False) opendirbutton.set_sensitive(self.torrent_box.can_open_dir()) filelistbutton = IconButton("Show file list", stock='gtk-index') if self.torrent_box.is_batch: filelistbutton.connect('clicked', self.torrent_box.open_filelist) else: filelistbutton.set_sensitive(False) lbbox.pack_start(filelistbutton, expand=False, fill=False) closebutton = gtk.Button(stock='gtk-close') closebutton.connect('clicked', lambda w: self.close()) rbbox.pack_end(closebutton, expand=False, fill=False) self.hbox.pack_start(lbbox, expand=False, fill=False) self.hbox.pack_end( rbbox, expand=False, fill=False) self.vbox.pack_end(self.hbox, expand=False, fill=False) self.win.add(self.vbox) self.win.show_all() def close(self): self.win.destroy()class TorrentBox(gtk.EventBox): def __init__(self, infohash, metainfo, dlpath, completion, main): gtk.EventBox.__init__(self) self.infohash = infohash self.metainfo = metainfo self.dlpath = dlpath self.completion = completion self.main = main self.uptotal = self.main.torrents[self.infohash].uptotal self.downtotal = self.main.torrents[self.infohash].downtotal if self.downtotal > 0: self.up_down_ratio = self.uptotal / self.downtotal else: self.up_down_ratio = None self.infowindow = None self.filelistwindow = None self.is_batch = metainfo.is_batch self.menu = None self.menu_handler = None self.vbox = gtk.VBox(homogeneous=False, spacing=SPACING) self.label = gtk.Label() self.set_name() self.vbox.pack_start(lalign(self.label), expand=False, fill=False) self.hbox = gtk.HBox(homogeneous=False, spacing=SPACING) self.icon = gtk.Image() self.icon.set_size_request(-1, 29) self.iconbox = gtk.VBox() self.iconevbox = gtk.EventBox() self.iconevbox.add(self.icon) self.iconbox.pack_start(self.iconevbox, expand=False, fill=False) self.hbox.pack_start(self.iconbox, expand=False, fill=False) self.vbox.pack_start(self.hbox) self.infobox = gtk.VBox(homogeneous=False) self.progressbarbox = gtk.HBox(homogeneous=False, spacing=SPACING) self.progressbar = gtk.ProgressBar() self.reset_progressbar_color() if self.completion is not None: self.progressbar.set_fraction(self.completion) if self.completion >= 1: done_label = self.make_done_label() self.progressbar.set_text(done_label) else: self.progressbar.set_text('%.1f%%'%(self.completion*100)) else: self.progressbar.set_text('?') self.progressbarbox.pack_start(self.progressbar, expand=True, fill=True) self.buttonevbox = gtk.EventBox() self.buttonbox = gtk.HBox(homogeneous=True, spacing=SPACING) self.infobutton = gtk.Button() self.infoimage = gtk.Image() self.infoimage.set_from_stock('bt-info', gtk.ICON_SIZE_BUTTON) self.infobutton.add(self.infoimage) self.infobutton.connect('clicked', self.open_info) self.main.tooltips.set_tip(self.infobutton, 'Torrent info') self.buttonbox.pack_start(self.infobutton, expand=True)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -