def TabPopup(self, user): popup = PopupMenu(self.frame) popup.setup( ("#" + _("Send _message"), popup.OnSendMessage), ("#" + _("Show IP a_ddress"), popup.OnShowIPaddress), ("#" + _("Get user i_nfo"), popup.OnGetUserInfo), ("#" + _("Brow_se files"), popup.OnBrowseUser), ("#" + _("Gi_ve privileges"), popup.OnGivePrivileges), ("#" + _("Client Version"), popup.OnVersion), ("", None), ("$" + _("Add user to list"), popup.OnAddToList), ("$" + _("Ban this user"), popup.OnBanUser), ("$" + _("Ignore this user"), popup.OnIgnoreUser), ("", None), ("#" + _("Detach this tab"), self.users[user].Detach), ("#" + _("Close this tab"), self.users[user].OnClose) ) popup.set_user(user) items = popup.get_children() items[7].set_active(user in [i[0] for i in self.frame.np.config.sections["server"]["userlist"]]) items[8].set_active(user in self.frame.np.config.sections["server"]["banlist"]) items[9].set_active(user in self.frame.np.config.sections["server"]["ignorelist"]) return popup
def OnPopupMenuUsers(self, widget): self.selected_transfers = [] self.selected_users = [] self.widget.get_selection().selected_foreach( self.SelectedTransfersCallback) self.popup_menu_users.clear() if len(self.selected_users) > 0: items = [] self.selected_users.sort(key=str.lower) for user in self.selected_users: popup = PopupMenu(self.frame) popup.setup( ("#" + _("Send _message"), popup.OnSendMessage), ("#" + _("Show IP a_ddress"), popup.OnShowIPaddress), ("#" + _("Get user i_nfo"), popup.OnGetUserInfo), ("#" + _("Brow_se files"), popup.OnBrowseUser), ("#" + _("Gi_ve privileges"), popup.OnGivePrivileges), ("", None), ("$" + _("_Add user to list"), popup.OnAddToList), ("$" + _("_Ban this user"), popup.OnBanUser), ("$" + _("_Ignore this user"), popup.OnIgnoreUser), ("#" + _("Select User's Transfers"), self.OnSelectUserTransfer)) popup.set_user(user) items.append((1, user, popup, self.OnPopupMenuUser, popup)) self.popup_menu_users.setup(*items) return True
def OnPopupMenuUsers(self, widget): self.select_results() self.popup_menu_users.clear() if len(self.selected_users) > 0: items = [] for user in self.selected_users: popup = PopupMenu(self.frame, False) popup.setup( ("#" + _("Send _message"), popup.OnSendMessage), ("#" + _("Show IP a_ddress"), popup.OnShowIPaddress), ("#" + _("Get user i_nfo"), popup.OnGetUserInfo), ("#" + _("Brow_se files"), popup.OnBrowseUser), ("#" + _("Gi_ve privileges"), popup.OnGivePrivileges), ("", None), ("$" + _("_Add user to list"), popup.OnAddToList), ("$" + _("_Ban this user"), popup.OnBanUser), ("$" + _("_Ignore this user"), popup.OnIgnoreUser), ("#" + _("Select User's Results"), self.OnSelectUserResults) ) popup.set_user(user) items.append((1, user, popup, self.OnPopupMenuUser, popup)) self.popup_menu_users.setup(*items) return True
def tab_popup(self, user): popup = PopupMenu(self.frame) popup.setup(("#" + _("Send _message"), popup.on_send_message), ("#" + _("Show IP a_ddress"), popup.on_show_ip_address), ("#" + _("Get user i_nfo"), popup.on_get_user_info), ("#" + _("Brow_se files"), popup.on_browse_user), ("#" + _("Gi_ve privileges"), popup.on_give_privileges), ("#" + _("Client Version"), popup.on_version), ("", None), ("$" + _("Add user to list"), popup.on_add_to_list), ("$" + _("Ban this user"), popup.on_ban_user), ("$" + _("Ignore this user"), popup.on_ignore_user), ("", None), ("#" + _("Close this tab"), self.users[user].on_close)) popup.set_user(user) items = popup.get_children() items[7].set_active(user in [ i[0] for i in self.frame.np.config.sections["server"]["userlist"] ]) items[8].set_active( user in self.frame.np.config.sections["server"]["banlist"]) items[9].set_active( user in self.frame.np.config.sections["server"]["ignorelist"]) return popup
def on_popup_menu_users(self, widget): self.select_results() self.popup_menu_users.clear() if len(self.selected_users) > 0: items = [] for user in self.selected_users: popup = PopupMenu(self.frame, False) popup.setup( ("#" + _("Send _message"), popup.on_send_message), ("#" + _("Show IP a_ddress"), popup.on_show_ip_address), ("#" + _("Get user i_nfo"), popup.on_get_user_info), ("#" + _("Brow_se files"), popup.on_browse_user), ("#" + _("Gi_ve privileges"), popup.on_give_privileges), ("", None), ("$" + _("_Add user to list"), popup.on_add_to_list), ("$" + _("_Ban this user"), popup.on_ban_user), ("$" + _("_Ignore this user"), popup.on_ignore_user), ("#" + _("Select User's Results"), self.on_select_user_results) ) popup.set_user(user) items.append((1, user, popup, self.on_popup_menu_user, popup)) self.popup_menu_users.setup(*items) return True
def TabPopup(self, id): popup = PopupMenu(self.frame) popup.setup( ("#" + _("Close this tab"), self.searches[id][2].OnClose) ) return popup
def tab_popup(self, search_id): popup = PopupMenu(self.frame) popup.setup( ("#" + _("Copy search term"), self.searches[search_id][2].on_copy_search_term), ("", None), ("#" + _("Close this tab"), self.searches[search_id][2].on_close) ) return popup
def TabPopup(self, id): popup = PopupMenu(self.frame) popup.setup( ("#" + _("Copy search term"), self.searches[id][2].OnCopySearchTerm), ("", None), ("#" + _("Close this tab"), self.searches[id][2].OnClose) ) return popup
def tab_popup(self, search_id): popup = PopupMenu(self.frame) popup.setup( ("#" + _("Copy Search Term"), self.searches[search_id][2].on_copy_search_term), ("", None), ("#" + _("Clear All Results"), self.searches[search_id][2].on_clear), ("#" + _("Close This Tab"), self.searches[search_id][2].on_close)) return popup
def on_tab_popup(self, widget, child): search_id = self.get_search_id(child) if search_id is None: log.add_warning(_("Search ID was none when clicking tab")) return False menu = PopupMenu(self.frame) menu.setup( ("#" + _("Copy Search Term"), self.searches[search_id]["tab"].on_copy_search_term), ("", None), ("#" + _("Clear All Results"), self.searches[search_id]["tab"].on_clear), ("#" + _("Close All Tabs"), menu.on_close_all_tabs, self), ("#" + _("_Close Tab"), self.searches[search_id]["tab"].on_close)) menu.popup() return True
def TabPopup(self, user): if user not in self.users: return popup = PopupMenu(self.frame) popup.setup( ("#" + _("Show IP a_ddress"), popup.OnShowIPaddress), ("#" + _("Get user i_nfo"), popup.OnGetUserInfo), ("#" + _("Brow_se files"), popup.OnBrowseUser), ("#" + _("Gi_ve privileges"), popup.OnGivePrivileges), ("#" + _("Client Version"), popup.OnVersion), ("", None), ("$" + _("Add user to list"), popup.OnAddToList), ("$" + _("Ban this user"), popup.OnBanUser), ("$" + _("Ignore this user"), popup.OnIgnoreUser), ("$" + _("B_lock this user's IP Address"), popup.OnBlockUser), ("$" + _("Ignore this user's IP Address"), popup.OnIgnoreIP), ("", None), ("#" + _("Detach this tab"), self.users[user].Detach), ("#" + _("Close this tab"), self.users[user].OnClose)) popup.set_user(user) me = (popup.user is None or popup.user == self.frame.np.config.sections["server"]["login"]) items = popup.get_children() items[6].set_active(user in [ i[0] for i in self.frame.np.config.sections["server"]["userlist"] ]) items[7].set_active( user in self.frame.np.config.sections["server"]["banlist"]) items[8].set_active( user in self.frame.np.config.sections["server"]["ignorelist"]) items[9].set_active(self.frame.UserIpIsBlocked(user)) items[9].set_sensitive(not me) items[10].set_active(self.frame.UserIpIsIgnored(user)) items[10].set_sensitive(not me) return popup
def tab_popup(self, user): if user not in self.users: return popup = PopupMenu(self.frame) popup.setup( ("#" + _("Show IP a_ddress"), popup.on_show_ip_address), ("#" + _("Get user i_nfo"), popup.on_get_user_info), ("#" + _("Brow_se files"), popup.on_browse_user), ("#" + _("Gi_ve privileges"), popup.on_give_privileges), ("#" + _("Client Version"), popup.on_version), ("", None), ("$" + _("Add user to list"), popup.on_add_to_list), ("$" + _("Ban this user"), popup.on_ban_user), ("$" + _("Ignore this user"), popup.on_ignore_user), ("$" + _("B_lock this user's IP Address"), popup.on_block_user), ("$" + _("Ignore this user's IP Address"), popup.on_ignore_ip), ("", None), ("#" + _("Close this tab"), self.users[user].on_close)) popup.set_user(user) me = (popup.user is None or popup.user == self.frame.np.config.sections["server"]["login"]) items = popup.get_children() items[6].set_active(user in ( i[0] for i in self.frame.np.config.sections["server"]["userlist"])) items[7].set_active( user in self.frame.np.config.sections["server"]["banlist"]) items[8].set_active( user in self.frame.np.config.sections["server"]["ignorelist"]) items[9].set_active(self.frame.user_ip_is_blocked(user)) items[9].set_sensitive(not me) items[10].set_active(self.frame.user_ip_is_ignored(user)) items[10].set_sensitive(not me) return popup
class Search: def __init__(self, searches, text, id, mode, remember, showtab): self.searches = searches self.frame = searches.frame # Build the window builder = Gtk.Builder() builder.set_translation_domain('nicotine') builder.add_from_file(os.path.join(os.path.dirname(os.path.realpath(__file__)), "ui", "search.ui")) self.search_tab = builder.get_object("SearchTab") for i in builder.get_objects(): try: self.__dict__[Gtk.Buildable.get_name(i)] = i except TypeError: pass self.search_tab.remove(self.Main) self.search_tab.destroy() builder.connect_signals(self) self.text = text self.searchterm_words_include = [p for p in text.lower().split() if not p.startswith('-')] self.searchterm_words_ignore = [p[1:] for p in text.lower().split() if p.startswith('-') and len(p) > 1] self.id = id self.mode = mode self.remember = remember self.showtab = showtab self.usersiters = {} self.directoryiters = {} self.users = set() self.all_data = [] self.filters = None self.resultslimit = 2000 self.numvisibleresults = 0 self.operators = { '<': operator.lt, '<=': operator.le, '==': operator.eq, '!=': operator.ne, '>=': operator.ge, '>': operator.gt } fill_file_grouping_combobox(self.ResultGrouping) self.ResultGrouping.set_active(self.frame.np.config.sections["searches"]["group_searches"]) self.ResultGrouping.connect("changed", self.on_group) self.ExpandButton.set_active(self.frame.np.config.sections["searches"]["expand_searches"]) self.ExpandButton.connect("toggled", self.on_toggle_expand_all) if mode > 0: self.RememberCheckButton.set_sensitive(False) self.RememberCheckButton.set_active(remember) """ Columns """ self.ResultsList.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE) self.ResultsList.set_enable_tree_lines(True) self.ResultsList.set_headers_clickable(True) self.ResultsList.set_rubber_banding(True) if self.ResultGrouping.get_active() > 0: # Group by folder or user self.ResultsList.set_show_expanders(True) else: self.ResultsList.set_show_expanders(False) self.resultsmodel = Gtk.TreeStore( GObject.TYPE_UINT64, # (0) num str, # (1) user GObject.TYPE_OBJECT, # (2) flag str, # (3) immediatedl str, # (4) h_speed str, # (5) h_queue str, # (6) directory str, # (7) filename str, # (8) h_size str, # (9) h_bitrate str, # (10) length GObject.TYPE_UINT64, # (11) bitrate str, # (12) fullpath str, # (13) country GObject.TYPE_UINT64, # (14) size GObject.TYPE_UINT64, # (15) speed GObject.TYPE_UINT64 # (16) queue ) widths = self.frame.np.config.sections["columns"]["filesearch_widths"] cols = initialise_columns( self.ResultsList, [_("ID"), widths[0], "text", self.cell_data_func], [_("User"), widths[1], "text", self.cell_data_func], [_("Country"), widths[2], "pixbuf"], [_("Immediate Download"), widths[3], "center", self.cell_data_func], [_("Speed"), widths[4], "number", self.cell_data_func], [_("In queue"), widths[5], "center", self.cell_data_func], [_("Directory"), widths[6], "text", self.cell_data_func], [_("Filename"), widths[7], "text", self.cell_data_func], [_("Size"), widths[8], "number", self.cell_data_func], [_("Bitrate"), widths[9], "number", self.cell_data_func], [_("Length"), widths[10], "number", self.cell_data_func] ) self.col_num, self.col_user, self.col_country, self.col_immediate, self.col_speed, self.col_queue, self.col_directory, self.col_file, self.col_size, self.col_bitrate, self.col_length = cols if self.ResultGrouping.get_active() > 0: # Group by folder or user self.ResultsList.get_columns()[0].set_visible(False) self.ExpandButton.show() hide_columns(cols, self.frame.np.config.sections["columns"]["filesearch_columns"]) self.col_num.set_sort_column_id(0) self.col_user.set_sort_column_id(1) self.col_country.set_sort_column_id(13) self.col_immediate.set_sort_column_id(3) self.col_speed.set_sort_column_id(15) self.col_queue.set_sort_column_id(16) self.col_directory.set_sort_column_id(6) self.col_file.set_sort_column_id(7) self.col_size.set_sort_column_id(14) self.col_bitrate.set_sort_column_id(11) self.col_length.set_sort_column_id(10) self.col_country.get_widget().hide() self.ResultsList.set_model(self.resultsmodel) self.ResultsList.connect("button_press_event", self.on_list_clicked) self.change_colours() """ Filters """ self.filter_bitrate_model = Gtk.ListStore(GObject.TYPE_STRING) self.FilterBitrate.set_model(self.filter_bitrate_model) self.FilterBitrate.set_entry_text_column(0) self.filter_size_model = Gtk.ListStore(GObject.TYPE_STRING) self.FilterSize.set_model(self.filter_size_model) self.FilterSize.set_entry_text_column(0) self.filter_country_model = Gtk.ListStore(GObject.TYPE_STRING) self.FilterCountry.set_model(self.filter_country_model) self.FilterCountry.set_entry_text_column(0) self.filter_in_model = Gtk.ListStore(GObject.TYPE_STRING) self.FilterIn.set_model(self.filter_in_model) self.FilterIn.set_entry_text_column(0) self.filter_out_model = Gtk.ListStore(GObject.TYPE_STRING) self.FilterOut.set_model(self.filter_out_model) self.FilterOut.set_entry_text_column(0) self.populate_filters() self.FilterSize.clear() sizecell = Gtk.CellRendererText() sizecell.set_property("xalign", 1) self.FilterSize.pack_start(sizecell, True) self.FilterSize.add_attribute(sizecell, "text", 0) self.FilterBitrate.clear() bit_cell = Gtk.CellRendererText() bit_cell.set_property("xalign", 1) self.FilterBitrate.pack_start(bit_cell, True) self.FilterBitrate.add_attribute(bit_cell, "text", 0) self.FilterIn.connect("changed", self.on_filter_changed) self.FilterOut.connect("changed", self.on_filter_changed) self.FilterSize.connect("changed", self.on_filter_changed) self.FilterBitrate.connect("changed", self.on_filter_changed) self.FilterCountry.connect("changed", self.on_filter_changed) self.FilterIn.get_child().connect("activate", self.on_refilter) self.FilterOut.get_child().connect("activate", self.on_refilter) self.FilterSize.get_child().connect("activate", self.on_refilter) self.FilterBitrate.get_child().connect("activate", self.on_refilter) self.FilterCountry.get_child().connect("activate", self.on_refilter) """ Popup """ self.popup_menu_users = PopupMenu(self.frame, False) self.popup_menu = popup = PopupMenu(self.frame) popup.setup( ("#" + _("_Download file(s)"), self.on_download_files), ("#" + _("Download file(s) _to..."), self.on_download_files_to), ("#" + _("Download _folder(s)"), self.on_download_folders), ("#" + _("Download f_older(s) to..."), self.on_download_folders_to), ("#" + _("View Metadata of file(s)"), self.on_search_meta), ("", None), ("#" + _("Copy _URL"), self.on_copy_url), ("#" + _("Copy folder U_RL"), self.on_copy_dir_url), ("", None), (1, _("User(s)"), self.popup_menu_users, self.on_popup_menu_users) ) def on_tooltip(self, widget, x, y, keyboard_mode, tooltip): return show_country_tooltip(widget, x, y, tooltip, 13, stripprefix='') def on_filter_changed(self, widget): iterator = widget.get_active_iter() if iterator: self.on_refilter(None) def populate_filters(self): if self.frame.np.config.sections["searches"]["enablefilters"]: sfilter = self.frame.np.config.sections["searches"]["defilter"] self.FilterIn.get_child().set_text(sfilter[0]) self.FilterOut.get_child().set_text(sfilter[1]) self.FilterSize.get_child().set_text(sfilter[2]) self.FilterBitrate.get_child().set_text(sfilter[3]) self.FilterFreeSlot.set_active(sfilter[4]) if(len(sfilter) > 5): self.FilterCountry.get_child().set_text(sfilter[5]) self.filtersCheck.set_active(1) for i in ['0', '128', '160', '192', '256', '320']: self.FilterBitrate.get_model().append([i]) for i in [">10MiB", "<10MiB", "<5MiB", "<1MiB", ">0"]: self.FilterSize.get_model().append([i]) s_config = self.frame.np.config.sections["searches"] for i in s_config["filterin"]: self.add_combo(self.FilterIn, i, True) for i in s_config["filterout"]: self.add_combo(self.FilterOut, i, True) for i in s_config["filtersize"]: self.add_combo(self.FilterSize, i, True) for i in s_config["filterbr"]: self.add_combo(self.FilterBitrate, i, True) for i in s_config["filtercc"]: self.add_combo(self.FilterCountry, i, True) def add_combo(self, combobox, text, list=False): text = text.strip() if not text: return False model = combobox.get_model() iterator = model.get_iter_first() match = False while iterator is not None: value = model.get_value(iterator, 0) if value.strip() == text: match = True iterator = model.iter_next(iterator) if not match: if list: model.append([text]) else: model.prepend([text]) def add_user_results(self, msg, user, country): if user in self.users: return self.users.add(user) counter = len(self.all_data) + 1 inqueue = msg.inqueue ulspeed = msg.ulspeed h_speed = human_speed(ulspeed) if msg.freeulslots: imdl = "Y" inqueue = 0 else: imdl = "N" h_queue = humanize(inqueue) append = False maxstoredresults = self.searches.maxstoredresults for result in msg.list: if counter > maxstoredresults: break fullpath = result[1] fullpath_lower = fullpath.lower() if any(word in fullpath_lower for word in self.searchterm_words_ignore): """ Filter out results with filtered words (e.g. nicotine -music) """ log.add_search(_("Filtered out excluded search result " + fullpath + " from user " + user)) continue if not any(word in fullpath_lower for word in self.searchterm_words_include): """ Some users may send us wrong results, filter out such ones """ log.add_search(_("Filtered out inexact or incorrect search result " + fullpath + " from user " + user)) continue fullpath_split = reversed(fullpath.split('\\')) name = next(fullpath_split) directory = '\\'.join(fullpath_split) size = result[2] h_size = human_size(size) h_bitrate, bitrate, h_length = get_result_bitrate_length(size, result[4]) self.append([counter, user, self.get_flag(user, country), imdl, h_speed, h_queue, directory, name, h_size, h_bitrate, h_length, bitrate, fullpath, country, size, ulspeed, inqueue]) append = True counter += 1 if append: # If this search wasn't initiated by us (e.g. wishlist), and the results aren't spoofed, show tab if not self.showtab: self.searches.show_tab(self, self.id, self.text, self.mode) self.showtab = True # Update counter self.Counter.set_text("Results: %d/%d" % (self.numvisibleresults, len(self.all_data))) # Update tab notification self.frame.searches.request_changed(self.Main) if self.frame.MainNotebook.get_current_page() != self.frame.MainNotebook.page_num(self.frame.searchvbox): self.frame.SearchTabLabel.get_child().set_image(self.frame.images["online"]) def get_flag(self, user, flag=None): if flag is not None: flag = "flag_" + flag.lower() self.frame.flag_users[user] = flag else: flag = self.frame.get_user_flag(user) return self.frame.get_flag_image(flag) def append(self, row): self.all_data.append(row) if self.numvisibleresults >= self.searches.maxdisplayedresults: return if not self.check_filter(row): return iterator = self.add_row_to_model(row) if self.ResultGrouping.get_active() > 0: # Group by folder or user if self.ExpandButton.get_active(): path = None if iterator is not None: path = self.resultsmodel.get_path(iterator) if path is not None: self.ResultsList.expand_to_path(path) else: collapse_treeview(self.ResultsList, self.ResultGrouping.get_active()) def add_row_to_model(self, row): counter, user, flag, immediatedl, h_speed, h_queue, directory, filename, h_size, h_bitrate, length, bitrate, fullpath, country, size, speed, queue = row if self.ResultGrouping.get_active() > 0: # Group by folder or user if user not in self.usersiters: self.usersiters[user] = self.resultsmodel.append( None, [0, user, self.get_flag(user, country), immediatedl, h_speed, h_queue, "", "", "", "", "", 0, "", country, 0, speed, queue] ) parent = self.usersiters[user] if self.ResultGrouping.get_active() == 1: # Group by folder if directory not in self.directoryiters: self.directoryiters[directory] = self.resultsmodel.append( self.usersiters[user], [0, user, self.get_flag(user, country), immediatedl, h_speed, h_queue, directory, "", "", "", "", 0, fullpath.rsplit('\\', 1)[0] + '\\', country, 0, speed, queue] ) row = row[:] row[6] = "" # Directory not visible for file row if "group by folder" is enabled parent = self.directoryiters[directory] else: parent = None try: iterator = self.resultsmodel.append(parent, row) self.numvisibleresults += 1 except Exception as e: types = [] for i in row: types.append(type(i)) log.add_warning(_("Search row error: %(exception)s %(row)s"), {'exception': e, 'row': row}) iterator = None return iterator def check_digit(self, sfilter, value, factorize=True): op = ">=" if sfilter[:1] in (">", "<", "="): op, sfilter = sfilter[:1] + "=", sfilter[1:] if not sfilter: return True factor = 1 if factorize: base = 1024 if sfilter[-1:].lower() == 'b': sfilter = sfilter[:-1] # stripping off the b, we always assume it means bytes if sfilter[-1:].lower() == 'i': base = 1000 sfilter = sfilter[:-1] if sfilter.lower()[-1:] == "g": factor = pow(base, 3) sfilter = sfilter[:-1] elif sfilter.lower()[-1:] == "m": factor = pow(base, 2) sfilter = sfilter[:-1] elif sfilter.lower()[-1:] == "k": factor = base sfilter = sfilter[:-1] if not sfilter: return True try: sfilter = int(sfilter) * factor except ValueError: return True operation = self.operators.get(op) return operation(value, sfilter) def check_filter(self, row): filters = self.filters if not self.filtersCheck.get_active(): return True # "Included text"-filter, check full file path (located at index 12 in row) if filters[0] and not filters[0].search(row[12].lower()): return False # "Excluded text"-filter, check full file path (located at index 12 in row) if filters[1] and filters[1].search(row[12].lower()): return False if filters[2] and not self.check_digit(filters[2], row[14]): return False if filters[3] and not self.check_digit(filters[3], row[11], False): return False if filters[4] and row[3] != "Y": return False if filters[5]: for cc in filters[5]: if not cc: continue if row[13] is None: return False if cc[0] == "-": if row[13].upper() == cc[1:].upper(): return False elif cc.upper() != row[13].upper(): return False return True def set_filters(self, enable, f_in, f_out, size, bitrate, freeslot, country): self.filters = [None, None, None, None, freeslot, None] if f_in: try: f_in = re.compile(f_in.lower()) self.filters[0] = f_in except sre_constants.error: self.frame.set_text_bg(self.FilterIn.get_child(), "red", "white") else: self.frame.set_text_bg(self.FilterIn.get_child()) if f_out: try: f_out = re.compile(f_out.lower()) self.filters[1] = f_out except sre_constants.error: self.frame.set_text_bg(self.FilterOut.get_child(), "red", "white") else: self.frame.set_text_bg(self.FilterOut.get_child()) if size: self.filters[2] = size if bitrate: self.filters[3] = bitrate if country: self.filters[5] = country.upper().split(" ") self.usersiters.clear() self.directoryiters.clear() self.resultsmodel.clear() self.numvisibleresults = 0 for row in self.all_data: if self.numvisibleresults >= self.searches.maxdisplayedresults: break if self.check_filter(row): self.add_row_to_model(row) self.Counter.set_text("Results: %d/%d" % (self.numvisibleresults, len(self.all_data))) def on_popup_menu_users(self, widget): self.select_results() self.popup_menu_users.clear() if len(self.selected_users) > 0: items = [] for user in self.selected_users: popup = PopupMenu(self.frame, False) popup.setup( ("#" + _("Send _message"), popup.on_send_message), ("#" + _("Show IP a_ddress"), popup.on_show_ip_address), ("#" + _("Get user i_nfo"), popup.on_get_user_info), ("#" + _("Brow_se files"), popup.on_browse_user), ("#" + _("Gi_ve privileges"), popup.on_give_privileges), ("", None), ("$" + _("_Add user to list"), popup.on_add_to_list), ("$" + _("_Ban this user"), popup.on_ban_user), ("$" + _("_Ignore this user"), popup.on_ignore_user), ("#" + _("Select User's Results"), self.on_select_user_results) ) popup.set_user(user) items.append((1, user, popup, self.on_popup_menu_user, popup)) self.popup_menu_users.setup(*items) return True def on_popup_menu_user(self, widget, popup=None): if popup is None: return menu = popup user = menu.user items = menu.get_children() act = False if len(self.selected_users) >= 1: act = True items[0].set_sensitive(act) items[1].set_sensitive(act) items[2].set_sensitive(act) items[3].set_sensitive(act) items[6].set_active(user in [i[0] for i in self.frame.np.config.sections["server"]["userlist"]]) items[7].set_active(user in self.frame.np.config.sections["server"]["banlist"]) items[8].set_active(user in self.frame.np.config.sections["server"]["ignorelist"]) for i in range(4, 9): items[i].set_sensitive(act) return True def on_select_user_results(self, widget): if len(self.selected_users) == 0: return selected_user = widget.get_parent().user sel = self.ResultsList.get_selection() fmodel = self.ResultsList.get_model() sel.unselect_all() iterator = fmodel.get_iter_first() select_user_row_iter(fmodel, sel, 1, selected_user, iterator) self.select_results() def select_results(self): self.selected_results = set() self.selected_users = set() self.ResultsList.get_selection().selected_foreach(self.selected_results_callback) def change_colours(self): self.frame.set_text_bg(self.FilterIn.get_child()) self.frame.set_text_bg(self.FilterOut.get_child()) self.frame.set_text_bg(self.FilterSize.get_child()) self.frame.set_text_bg(self.FilterBitrate.get_child()) self.frame.set_text_bg(self.FilterCountry.get_child()) font = self.frame.np.config.sections["ui"]["searchfont"] self.frame.change_list_font(self.ResultsList, font) def save_columns(self): columns = [] widths = [] for column in self.ResultsList.get_columns(): columns.append(column.get_visible()) widths.append(column.get_width()) self.frame.np.config.sections["columns"]["filesearch_columns"] = columns self.frame.np.config.sections["columns"]["filesearch_widths"] = widths def selected_results_callback(self, model, path, iterator): user = model.get_value(iterator, 1) if user is None: return self.selected_users.add(user) filepath = model.get_value(iterator, 12) if filepath == "": # Result is not a file or directory, don't add it return bitrate = model.get_value(iterator, 9) length = model.get_value(iterator, 10) size = model.get_value(iterator, 14) self.selected_results.add((user, filepath, size, bitrate, length)) def on_list_clicked(self, widget, event): if event.button == 3: return self.on_popup_menu(widget, event) else: pathinfo = widget.get_path_at_pos(event.x, event.y) if pathinfo is None: widget.get_selection().unselect_all() elif event.button == 1 and event.type == Gdk.EventType._2BUTTON_PRESS: self.select_results() self.on_download_files(widget) self.ResultsList.get_selection().unselect_all() return True return False def on_popup_menu(self, widget, event): if event.button != 3: return False set_treeview_selected_row(widget, event) self.select_results() items = self.popup_menu.get_children() users = len(self.selected_users) > 0 files = len(self.selected_results) > 0 for i in range(0, 5): items[i].set_sensitive(files) items[0].set_sensitive(False) items[1].set_sensitive(False) items[4].set_sensitive(False) items[6].set_sensitive(False) items[7].set_sensitive(files) items[8].set_sensitive(users) for result in self.selected_results: if not result[1].endswith('\\'): # At least one selected result is a file, activate file-related items items[0].set_sensitive(True) items[1].set_sensitive(True) items[4].set_sensitive(True) items[6].set_sensitive(True) break self.popup_menu.popup(None, None, None, None, event.button, event.time) widget.stop_emission_by_name("button_press_event") return True def cell_data_func(self, column, cellrenderer, model, iterator, dummy="dummy"): imdl = model.get_value(iterator, 3) color_id = imdl == "Y" and "search" or "searchq" color = self.frame.np.config.sections["ui"][color_id] if color: cellrenderer.set_property("foreground", color) else: cellrenderer.set_property("foreground-set", False) def meta_box(self, title="Meta Data", message="", data=None, modal=True): win = MetaDialog(self.frame, message, data, modal) win.set_title(title) win.show() Gtk.main() return win.ret def selected_results_all_data(self, model, path, iterator, data): filename = model.get_value(iterator, 7) # We only want to see the metadata of files, not directories if filename != "": num = model.get_value(iterator, 0) user = model.get_value(iterator, 1) immediate = model.get_value(iterator, 3) speed = model.get_value(iterator, 4) queue = model.get_value(iterator, 5) directory = model.get_value(iterator, 6) size = model.get_value(iterator, 8) bitratestr = model.get_value(iterator, 9) length = model.get_value(iterator, 10) fn = model.get_value(iterator, 12) country = model.get_value(iterator, 13) data[len(data)] = { "user": user, "fn": fn, "position": num, "filename": filename, "directory": directory, "size": size, "speed": speed, "queue": queue, "immediate": immediate, "bitrate": bitratestr, "length": length, "country": country } def on_search_meta(self, widget): if not self.frame.np.transfers: return data = {} self.ResultsList.get_selection().selected_foreach(self.selected_results_all_data, data) if data != {}: self.meta_box(title=_("Search Results"), message=_("<b>Metadata</b> for Search Query: <i>%s</i>") % self.text, data=data, modal=True) def on_download_files(self, widget, prefix=""): if not self.frame.np.transfers: return for file in self.selected_results: # Make sure the selected result is not a directory if not file[1].endswith('\\'): self.frame.np.transfers.get_file(file[0], file[1], prefix, size=file[2], bitrate=file[3], length=file[4], checkduplicate=True) def on_download_files_to(self, widget): folder = choose_dir(self.frame.MainWindow, self.frame.np.config.sections["transfers"]["downloaddir"], multichoice=False) if folder is None: return for folders in folder: self.on_download_files(widget, folders) break def on_download_folders(self, widget): requested_folders = {} for i in self.selected_results: user = i[0] folder = i[1].rsplit('\\', 1)[0] if user not in requested_folders: requested_folders[user] = [] if folder not in requested_folders[user]: """ Ensure we don't send folder content requests for a folder more than once, e.g. when several selected resuls belong to the same folder. """ self.frame.np.process_request_to_peer(user, slskmessages.FolderContentsRequest(None, folder)) requested_folders[user].append(folder) def on_download_folders_to(self, widget): directories = choose_dir(self.frame.MainWindow, self.frame.np.config.sections["transfers"]["downloaddir"], multichoice=False) if directories is None or directories == []: return destination = directories[0] for i in self.selected_results: user = i[0] folder = i[1].rsplit('\\', 1)[0] if user not in self.frame.np.requested_folders: self.frame.np.requested_folders[user] = {} if folder not in self.frame.np.requested_folders[user]: """ Ensure we don't send folder content requests for a folder more than once, e.g. when several selected resuls belong to the same folder. """ self.frame.np.requested_folders[user][folder] = destination self.frame.np.process_request_to_peer(user, slskmessages.FolderContentsRequest(None, folder)) def on_copy_url(self, widget): user, path = next(iter(self.selected_results))[:2] self.frame.set_clipboard_url(user, path) def on_copy_dir_url(self, widget): user, path = next(iter(self.selected_results))[:2] path = "\\".join(path.split("\\")[:-1]) if path[:-1] != "/": path += "/" self.frame.set_clipboard_url(user, path) def on_group(self, widget): self.on_refilter(widget) self.ResultsList.set_show_expanders(widget.get_active()) self.frame.np.config.sections["searches"]["group_searches"] = self.ResultGrouping.get_active() if widget.get_active(): self.ResultsList.get_columns()[0].set_visible(False) self.ExpandButton.show() else: self.ResultsList.get_columns()[0].set_visible(True) self.ExpandButton.hide() def on_toggle_expand_all(self, widget): active = self.ExpandButton.get_active() if active: self.ResultsList.expand_all() self.expand.set_from_icon_name("list-remove-symbolic", Gtk.IconSize.BUTTON) else: collapse_treeview(self.ResultsList, self.ResultGrouping.get_active()) self.expand.set_from_icon_name("list-add-symbolic", Gtk.IconSize.BUTTON) self.frame.np.config.sections["searches"]["expand_searches"] = active def on_toggle_filters(self, widget): if widget.get_active(): self.FiltersContainer.show() self.on_refilter(None) else: self.FiltersContainer.hide() self.ResultsList.set_model(None) self.set_filters(0, None, None, None, None, None, "") self.ResultsList.set_model(self.resultsmodel) if self.ResultGrouping.get_active() > 0: # Group by folder or user if self.ExpandButton.get_active(): self.ResultsList.expand_all() else: collapse_treeview(self.ResultsList, self.ResultGrouping.get_active()) def on_ignore(self, widget): self.searches.searches[self.id][5] = True # ignored self.searches.wish_list.remove_wish(self.text) widget.set_sensitive(False) def on_clear(self, widget): self.all_data = [] self.usersiters.clear() self.directoryiters.clear() self.resultsmodel.clear() def on_close(self, widget): if not self.frame.np.config.sections["searches"]["reopen_tabs"]: if self.text not in self.frame.np.config.sections["server"]["autosearch"]: self.on_ignore(widget) self.searches.remove_tab(self) def on_copy_search_term(self, widget): self.frame.clip.set_text(self.text, -1) def on_toggle_remember(self, widget): self.remember = widget.get_active() search = self.searches.searches[self.id] if not self.remember: self.searches.wish_list.remove_wish(search[1]) else: self.searches.wish_list.add_wish(search[1]) def push_history(self, widget, title): text = widget.get_child().get_text() if not text.strip(): return None text = text.strip() history = self.frame.np.config.sections["searches"][title] if text in history: history.remove(text) elif len(history) >= 5: del history[-1] history.insert(0, text) self.frame.np.config.write_configuration() self.add_combo(widget, text) widget.get_child().set_text(text) return text def on_refilter(self, widget): f_in = self.push_history(self.FilterIn, "filterin") f_out = self.push_history(self.FilterOut, "filterout") f_size = self.push_history(self.FilterSize, "filtersize") f_br = self.push_history(self.FilterBitrate, "filterbr") f_free = self.FilterFreeSlot.get_active() f_country = self.push_history(self.FilterCountry, "filtercc") self.ResultsList.set_model(None) self.set_filters(1, f_in, f_out, f_size, f_br, f_free, f_country) self.ResultsList.set_model(self.resultsmodel) if self.ResultGrouping.get_active() > 0: # Group by folder or user if self.ExpandButton.get_active(): self.ResultsList.expand_all() else: collapse_treeview(self.ResultsList, self.ResultGrouping.get_active()) def on_about_filters(self, widget): self.frame.on_about_filters(widget)
class UserBrowse: def __init__(self, userbrowses, user): self.userbrowses = userbrowses self.frame = userbrowses.frame # Build the window load_ui_elements(self, os.path.join(self.frame.gui_dir, "ui", "userbrowse.ui")) self.info_bar = InfoBar(self.InfoBar, Gtk.MessageType.INFO) self.user = user self.conn = None self.local_shares_type = None self.refreshing = True # selected_folder is the current selected folder self.selected_folder = None # queued_folder is a folder that should be opened once the share has loaded self.queued_folder = None self.search_list = [] self.query = None self.search_position = 0 self.selected_files = [] self.shares = [] # Iters for current DirStore self.directories = {} # Iters for current FileStore self.files = {} self.totalsize = 0 self.dir_store = Gtk.TreeStore(str, str) cols = initialise_columns( None, self.FolderTreeView, ["folders", _("Folders"), -1, "text", None, None] # 0 ) cols["folders"].set_sort_column_id(0) self.popup_menu_users = PopupMenu(self.frame, False) self.popup_menu_users2 = PopupMenu(self.frame, False) self.popup_menu_users_tab = PopupMenu(self.frame) for menu in (self.popup_menu_users, self.popup_menu_users2, self.popup_menu_users_tab): menu.setup_user_menu(user) menu.get_items()[_("Brow_se Files")].set_visible(False) menu.append_item(("", None)) menu.append_item(("#" + _("_Save Shares List To Disk"), self.on_save)) menu.append_item(("#" + _("Close All Tabs"), menu.on_close_all_tabs, self.userbrowses)) menu.append_item(("#" + _("_Close Tab"), self.on_close)) self.popup_menu_downloads_folders = PopupMenu(self.frame, False) self.popup_menu_downloads_folders.setup( ("#" + _("_Download Folder"), self.on_download_directory), ("#" + _("Download Folder _To..."), self.on_download_directory_to), ("#" + _("Download _Recursive"), self.on_download_directory_recursive), ("#" + _("Download R_ecursive To..."), self.on_download_directory_recursive_to) ) self.popup_menu_downloads_files = PopupMenu(self.frame, False) self.popup_menu_downloads_files.setup( ("#" + _("_Download File(s)"), self.on_download_files), ("#" + _("Download _To..."), self.on_download_files_to), ("", None), ("#" + _("_Download Folder"), self.on_download_directory), ("#" + _("Download Folder _To..."), self.on_download_directory_to), ("#" + _("Download _Recursive"), self.on_download_directory_recursive), ("#" + _("Download R_ecursive To..."), self.on_download_directory_recursive_to) ) self.popup_menu_uploads_folders = PopupMenu(self.frame, False) self.popup_menu_uploads_folders.setup( ("#" + _("Upload Folder To..."), self.on_upload_directory_to), ("#" + _("Upload Folder Recursive To..."), self.on_upload_directory_recursive_to) ) self.popup_menu_uploads_files = PopupMenu(self.frame, False) self.popup_menu_uploads_files.setup( ("#" + _("Upload Folder To..."), self.on_upload_directory_to), ("#" + _("Upload Folder Recursive To..."), self.on_upload_directory_recursive_to), ("#" + _("Up_load File(s)"), self.on_upload_files) ) self.folder_popup_menu = PopupMenu(self.frame) if user == self.frame.np.config.sections["server"]["login"]: self.folder_popup_menu.setup( ("#" + _("_Download Folder"), self.on_download_directory), ("#" + _("Download Folder _To..."), self.on_download_directory_to), ("#" + _("Download _Recursive"), self.on_download_directory_recursive), ("#" + _("Download R_ecursive To..."), self.on_download_directory_recursive_to), ("", None), ("#" + _("Upload Folder To..."), self.on_upload_directory_to), ("#" + _("Upload Folder Recursive To..."), self.on_upload_directory_recursive_to), ("", None), ("#" + _("Open in File _Manager"), self.on_file_manager), ("", None), ("#" + _("Copy _Folder Path"), self.on_copy_file_path, False), ("#" + _("Copy _URL"), self.on_copy_dir_url), ("", None), (1, _("User"), self.popup_menu_users, self.on_popup_menu_folder_user) ) else: self.folder_popup_menu.setup( ("#" + _("_Download Folder"), self.on_download_directory), ("#" + _("Download Folder _To..."), self.on_download_directory_to), ("#" + _("Download _Recursive"), self.on_download_directory_recursive), ("#" + _("Download R_ecursive To..."), self.on_download_directory_recursive_to), ("", None), ("#" + _("Copy _Folder Path"), self.on_copy_file_path, False), ("#" + _("Copy _URL"), self.on_copy_dir_url), ("", None), (1, _("User"), self.popup_menu_users, self.on_popup_menu_folder_user) ) self.FolderTreeView.get_selection().connect("changed", self.on_select_dir) self.file_store = Gtk.ListStore( str, # (0) file name str, # (1) hsize str, # (2) hbitrate str, # (3) hlength GObject.TYPE_UINT64, # (4) size GObject.TYPE_UINT64, # (5) bitrate GObject.TYPE_UINT64 # (6) length ) self.FileTreeView.set_model(self.file_store) cols = initialise_columns( "user_browse", self.FileTreeView, ["filename", _("Filename"), 600, "text", None, None], ["size", _("Size"), 100, "number", None, None], ["bitrate", _("Bitrate"), 100, "number", None, None], ["length", _("Length"), 100, "number", None, None] ) cols["filename"].set_sort_column_id(0) cols["size"].set_sort_column_id(4) cols["bitrate"].set_sort_column_id(5) cols["length"].set_sort_column_id(6) self.file_store.set_sort_column_id(0, Gtk.SortType.ASCENDING) self.file_popup_menu = PopupMenu(self.frame) if user == self.frame.np.config.sections["server"]["login"]: self.file_popup_menu.setup( ("#" + "selected_files", None), ("", None), (1, _("Download"), self.popup_menu_downloads_files, None), (1, _("Upload"), self.popup_menu_uploads_files, None), ("", None), ("#" + _("Send to _Player"), self.on_play_files), ("#" + _("Open in File _Manager"), self.on_file_manager), ("#" + _("File _Properties"), self.on_file_properties), ("", None), ("#" + _("Copy _File Path"), self.on_copy_file_path, True), ("#" + _("Copy _URL"), self.on_copy_url), ("", None), (1, "User", self.popup_menu_users2, self.on_popup_menu_file_user) ) else: self.file_popup_menu.setup( ("#" + "selected_files", None), ("", None), (1, _("Download"), self.popup_menu_downloads_files, None), ("", None), ("#" + _("File _Properties"), self.on_file_properties), ("", None), ("#" + _("Copy _File Path"), self.on_copy_file_path, True), ("#" + _("Copy _URL"), self.on_copy_url), ("", None), (1, "User", self.popup_menu_users2, self.on_popup_menu_file_user) ) self.update_visuals() for name, object in self.__dict__.items(): if isinstance(object, PopupMenu): object.set_user(self.user) def on_popup_menu_file_user(self, widget): self.on_popup_menu_users(self.popup_menu_users2) def on_popup_menu_folder_user(self, widget): self.on_popup_menu_users(self.popup_menu_users) def on_popup_menu_users(self, menu): menu.toggle_user_items() return True def update_visuals(self): for widget in self.__dict__.values(): update_widget_visuals(widget, list_font_target="browserfont") def on_expand(self, widget): if self.ExpandButton.get_active(): self.FolderTreeView.expand_all() self.expand.set_from_icon_name("go-up-symbolic", Gtk.IconSize.BUTTON) else: self.FolderTreeView.collapse_all() self.expand.set_from_icon_name("go-down-symbolic", Gtk.IconSize.BUTTON) dirs = sorted(self.directories.keys()) if dirs != []: self.set_directory(dirs[0]) else: self.set_directory(None) def on_folder_clicked(self, widget, event): if triggers_context_menu(event): set_treeview_selected_row(widget, event) return self.on_folder_popup_menu(widget) if event.button == 1 and event.type == Gdk.EventType._2BUTTON_PRESS: if self.user != self.frame.np.config.sections["server"]["login"]: self.on_download_directory(widget) return True return False def on_folder_popup_menu(self, widget): self.folder_popup_menu.popup() return True def select_files(self): self.selected_files = [] self.FileTreeView.get_selection().selected_foreach(self.selected_files_callback) def selected_files_callback(self, model, path, iterator): rawfilename = self.file_store.get_value(iterator, 0) self.selected_files.append(rawfilename) def on_file_clicked(self, widget, event): if triggers_context_menu(event): set_treeview_selected_row(widget, event) return self.on_file_popup_menu(widget) if event.button == 1 and event.type == Gdk.EventType._2BUTTON_PRESS: self.select_files() if self.user == self.frame.np.config.sections["server"]["login"]: self.on_play_files(widget) else: self.on_download_files(widget) return True return False def on_file_popup_menu(self, widget): self.select_files() num_selected_files = len(self.selected_files) if num_selected_files >= 1: files = True else: files = False items = self.file_popup_menu.get_items() if self.user == self.frame.np.config.sections["server"]["login"]: for i in (_("Download"), _("Upload"), _("Send to _Player"), _("File _Properties"), _("Copy _File Path"), _("Copy _URL")): items[i].set_sensitive(files) else: for i in (_("Download"), _("File _Properties"), _("Copy _File Path"), _("Copy _URL")): items[i].set_sensitive(files) items["selected_files"].set_sensitive(False) items["selected_files"].set_label(_("%s File(s) Selected") % num_selected_files) self.file_popup_menu.popup() return True def make_new_model(self, list): self.shares = list self.selected_folder = None self.selected_files = [] self.directories.clear() self.files.clear() self.dir_store.clear() # Compute the number of shared dirs and total size self.totalsize = 0 for dir, files in self.shares: for filedata in files: if filedata[2] < maxsize: self.totalsize += filedata[2] self.AmountShared.set_text(human_size(self.totalsize)) self.NumDirectories.set_text(str(len(self.shares))) # Generate the directory tree and select first directory currentdir = self.browse_get_dirs() sel = self.FolderTreeView.get_selection() sel.unselect_all() if currentdir in self.directories: path = self.dir_store.get_path(self.directories[currentdir]) if path is not None: sel.select_path(path) if self.ExpandButton.get_active(): self.FolderTreeView.expand_all() else: self.FolderTreeView.collapse_all() self.set_finished() def browse_get_dirs(self): directory = "" dirseparator = '\\' # If there is no share if self.shares == []: # Set the model of the treeviex self.FolderTreeView.set_model(self.dir_store) # Sort the DirStore self.dir_store.set_sort_column_id(0, Gtk.SortType.ASCENDING) return directory def builddicttree(p, s): """ Build recursively a hierarchical dict containing raw subdir 'p' is a reference to the parent 's' a list of the subdir of a path ex of 's': ['music', 'rock', 'doors'] """ if s: subdir = s.pop(0) if subdir not in p: p[subdir] = {} builddicttree(p[subdir], s) def buildgtktree(dictdir, parent, path): """ Build recursively self.directories with iters pointing to directories 'dictdir' is a hierarchical dict containing raw subdir 'parent' is the iter pointing to the parent 'path' is the current raw path """ # Foreach subdir for subdir in dictdir: if parent is None: # The first sudirs are attached to the root (None) current_path = subdir else: # Other sudirs futher down the path are attached to their parent current_path = dirseparator.join([path, subdir]) self.directories[current_path] = self.dir_store.append(parent, [subdir, current_path]) # If there are subdirs futher down the path: recurse if len(dictdir[subdir]): buildgtktree(dictdir[subdir], self.directories[current_path], current_path) # For each shared dir we will complete the dictionnary dictdir = {} for dirshares, f in self.shares: # Split the path s = dirshares.split(dirseparator) # and build a hierarchical dictionnary containing raw subdir if len(s) >= 1: builddicttree(dictdir, s) # Append data to the DirStore buildgtktree(dictdir, None, None) # Select the first directory sortlist = sorted(self.directories.keys()) directory = sortlist[0] # Sort the DirStore self.dir_store.set_sort_column_id(0, Gtk.SortType.ASCENDING) # Set the model of the treeviex self.FolderTreeView.set_model(self.dir_store) return directory def browse_folder(self, folder): """ Browse a specific folder in the share """ try: iterator = self.directories[folder] except KeyError: # Folder not found pass if folder: sel = self.FolderTreeView.get_selection() sel.unselect_all() path = self.dir_store.get_path(iterator) self.FolderTreeView.expand_to_path(path) sel.select_path(path) self.FolderTreeView.scroll_to_cell(path, None, True, 0.5, 0.5) self.queued_folder = None def set_directory(self, directory): self.selected_folder = directory self.file_store.clear() self.files.clear() found_dir = False for d, f in self.shares: if d == directory: found_dir = True files = f break if not found_dir: return for file in files: # Filename, HSize, Bitrate, HLength, Size, Length, RawFilename try: size = int(file[2]) # Some clients send incorrect file sizes if size < 0 or size > maxsize: size = 0 except ValueError: size = 0 f = [file[1], human_size(size)] h_bitrate, bitrate, h_length, length = get_result_bitrate_length(size, file[4]) f += [h_bitrate, h_length, int(size), bitrate, length] try: self.files[f[0]] = self.file_store.append(f) except Exception as msg: log.add(_("Error while attempting to display folder '%(folder)s', reported error: %(error)s"), {'folder': directory, 'error': msg}) def on_save(self, widget): sharesdir = os.path.join(self.frame.data_dir, "usershares") try: if not os.path.exists(sharesdir): os.mkdir(sharesdir) except Exception as msg: log.add(_("Can't create directory '%(folder)s', reported error: %(error)s"), {'folder': sharesdir, 'error': msg}) try: filepath = os.path.join(sharesdir, clean_file(self.user)) with open(filepath, "w", encoding="utf-8") as sharesfile: import json json.dump(self.shares, sharesfile, ensure_ascii=False) log.add(_("Saved list of shared files for user '%(user)s' to %(dir)s"), {'user': self.user, 'dir': sharesdir}) except Exception as msg: log.add(_("Can't save shares, '%(user)s', reported error: %(error)s"), {'user': self.user, 'error': msg}) def save_columns(self): save_columns("user_browse", self.FileTreeView.get_columns()) def show_user(self, msg, folder=None, indeterminate_progress=False, local_shares_type=None): self.set_in_progress(indeterminate_progress) if folder: self.queued_folder = folder # If this is our own share, remember if it's public or buddy # (needed for refresh button) if local_shares_type: self.local_shares_type = local_shares_type """ Update the list model if: 1. This is a new user browse tab 2. We're refreshing the file list 3. This is the list of our own shared files (local_shares_type set) """ if self.refreshing or local_shares_type: if msg is None: return self.conn = None self.make_new_model(msg.list) if msg and len(msg.list) == 0: self.info_bar.show_message( _("User's list of shared files is empty. Either the user is not sharing anything, or they are sharing files privately.") ) else: self.info_bar.set_visible(False) self.browse_folder(self.queued_folder) self.set_finished() def show_connection_error(self): self.info_bar.show_message( _("Unable to request shared files from user. Either the user is offline, you both have a closed listening port, or there's a temporary connectivity issue.") ) self.set_finished() def load_shares(self, list): self.make_new_model(list) def is_refreshing(self): return self.refreshing def set_in_progress(self, indeterminate_progress): if not indeterminate_progress: self.progressbar1.set_fraction(0.0) else: self.progressbar1.set_fraction(0.5) self.RefreshButton.set_sensitive(False) def set_finished(self): # Tab notification self.frame.request_tab_icon(self.frame.UserBrowseTabLabel) self.userbrowses.request_changed(self.Main) self.progressbar1.set_fraction(1.0) self.FolderTreeView.set_sensitive(True) self.FileTreeView.set_sensitive(True) self.RefreshButton.set_sensitive(True) self.refreshing = False def update_gauge(self, msg): if msg.total == 0 or msg.bytes == 0: fraction = 0.0 elif msg.bytes >= msg.total: fraction = 1.0 else: fraction = float(msg.bytes) / msg.total self.progressbar1.set_fraction(fraction) def tab_popup(self, user): self.popup_menu_users_tab.toggle_user_items() return self.popup_menu_users_tab def on_select_dir(self, selection): model, iterator = selection.get_selected() if iterator is None: self.selected_folder = None return path = model.get_path(iterator) directory = model.get_value(iterator, 1) self.FolderTreeView.expand_to_path(path) self.set_directory(directory) def selected_results_all_data(self, model, path, iterator, data): filename = model.get_value(iterator, 0) fn = "\\".join([self.selected_folder, filename]) size = model.get_value(iterator, 1) bitratestr = model.get_value(iterator, 2) length = model.get_value(iterator, 3) data.append({ "user": self.user, "fn": fn, "filename": filename, "directory": self.selected_folder, "size": size, "bitrate": bitratestr, "length": length, "immediate": None, "speed": None, "country": None }) def on_file_properties(self, widget): data = [] self.FileTreeView.get_selection().selected_foreach(self.selected_results_all_data, data) if data: FileProperties(self.frame, data).show() def on_download_directory(self, widget): if self.selected_folder is not None: self.download_directory(self.selected_folder) def on_download_directory_recursive(self, widget): self.download_directory(self.selected_folder, "", 1) def on_download_directory_to(self, widget): folder = choose_dir(self.frame.MainWindow, self.frame.np.config.sections["transfers"]["downloaddir"], multichoice=False) if folder is None: return try: self.download_directory(self.selected_folder, os.path.join(folder[0], "")) except IOError: # failed to open log.add('Failed to open %r for reading', folder[0]) # notify user def on_download_directory_recursive_to(self, widget): folder = choose_dir(self.frame.MainWindow, self.frame.np.config.sections["transfers"]["downloaddir"], multichoice=False) if folder is None: return try: self.download_directory(self.selected_folder, os.path.join(folder[0], ""), 1) except IOError: # failed to open log.add('Failed to open %r for reading', folder[0]) # notify user def download_directory(self, folder, prefix="", recurse=0): if self.frame.np.transfers is None or folder is None: return ldir = prefix + folder.split("\\")[-1] # Check if folder already exists on system ldir = self.frame.np.transfers.folder_destination(self.user, ldir) for d, files in self.shares: # Find the wanted directory if d != folder: continue if self.frame.np.config.sections["transfers"]["reverseorder"]: files.sort(key=lambda x: x[1], reverse=True) for file in files: path = "\\".join([folder, file[1]]) size = file[2] h_bitrate, bitrate, h_length, length = get_result_bitrate_length(size, file[4]) self.frame.np.transfers.get_file( self.user, path, ldir, size=size, bitrate=h_bitrate, length=h_length, checkduplicate=True ) if not recurse: return for subdir, subf in self.shares: if folder in subdir and folder != subdir: self.download_directory(subdir, os.path.join(ldir, "")) def on_download_files(self, widget, prefix=""): if not self.frame.np.transfers: return folder = self.selected_folder for d, f in self.shares: # Find the wanted directory if d != folder: continue for file in f: # Find the wanted file if file[1] not in self.selected_files: continue path = "\\".join([folder, file[1]]) size = file[2] h_bitrate, bitrate, h_length, length = get_result_bitrate_length(size, file[4]) # Get the file self.frame.np.transfers.get_file(self.user, path, prefix, size=size, bitrate=h_bitrate, length=h_length, checkduplicate=True) # We have found the wanted directory: we can break out of the loop break def on_download_files_to(self, widget): try: _, folder = self.selected_folder.rsplit("\\", 1) except ValueError: folder = self.selected_folder path = os.path.join(self.frame.np.config.sections["transfers"]["downloaddir"], folder) if os.path.exists(path) and os.path.isdir(path): ldir = choose_dir(self.frame.MainWindow, path, multichoice=False) else: ldir = choose_dir(self.frame.MainWindow, self.frame.np.config.sections["transfers"]["downloaddir"], multichoice=False) if ldir is None: return try: self.on_download_files(widget, ldir[0]) except IOError: # failed to open log.add('failed to open %r for reading', ldir[0]) # notify user def on_upload_directory_to(self, widget, recurse=0): folder = self.selected_folder if folder is None: return users = [] for entry in self.frame.np.config.sections["server"]["userlist"]: users.append(entry[0]) users.sort() user = combo_box_dialog( parent=self.frame.MainWindow, title=_("Upload Folder's Contents"), message=_('Enter the User you wish to upload to:'), droplist=users ) if user is None or user == "": return self.frame.np.send_message_to_peer(user, slskmessages.UploadQueueNotification(None)) self.upload_directory_to(user, folder, recurse) def on_upload_directory_recursive_to(self, widget): self.on_upload_directory_to(widget, recurse=1) def upload_directory_to(self, user, folder, recurse=0): if not self.frame.np.transfers: return if folder == "" or folder is None or user is None or user == "": return realpath = self.frame.np.shares.virtual2real(folder) ldir = folder.split("\\")[-1] for d, f in self.shares: # Find the wanted directory if d != folder: continue for file in f: filename = "\\".join([folder, file[1]]) realfilename = "\\".join([realpath, file[1]]) size = file[2] self.frame.np.transfers.push_file(user, filename, realfilename, ldir, size=size) self.frame.np.transfers.check_upload_queue() if not recurse: return for subdir, subf in self.shares: if folder in subdir and folder != subdir: self.upload_directory_to(user, subdir, recurse) def on_upload_files(self, widget, prefix=""): if not self.frame.np.transfers: return folder = self.selected_folder realpath = self.frame.np.shares.virtual2real(folder) users = [] for entry in self.frame.np.config.sections["server"]["userlist"]: users.append(entry[0]) users.sort() user = combo_box_dialog( parent=self.frame.MainWindow, title=_('Upload File(s)'), message=_('Enter the User you wish to upload to:'), droplist=users ) if user is None or user == "": return self.frame.np.send_message_to_peer(user, slskmessages.UploadQueueNotification(None)) for fn in self.selected_files: self.frame.np.transfers.push_file(user, "\\".join([folder, fn]), "\\".join([realpath, fn]), prefix) self.frame.np.transfers.check_upload_queue() def on_key_press_event(self, widget, event): key = Gdk.keyval_name(event.keyval) self.select_files() if key in ("C", "c") and event.state in (Gdk.ModifierType.CONTROL_MASK, Gdk.ModifierType.LOCK_MASK | Gdk.ModifierType.CONTROL_MASK): files = (widget == self.FileTreeView) self.on_copy_file_path(widget, files) else: # No key match, continue event return False widget.stop_emission_by_name("key_press_event") return True def on_play_files(self, widget, prefix=""): start_new_thread(self._on_play_files, (widget, prefix)) def _on_play_files(self, widget, prefix=""): path = self.frame.np.shares.virtual2real(self.selected_folder) for fn in self.selected_files: playfile = os.sep.join([path, fn]) if os.path.exists(playfile): command = self.frame.np.config.sections["players"]["default"] open_file_path(playfile, command) def find_matches(self): self.search_list = [] for directory, files in self.shares: if self.query in directory.lower(): if directory not in self.search_list: self.search_list.append(directory) for file in files: if self.query in file[1].lower(): if directory not in self.search_list: self.search_list.append(directory) def on_search(self, widget): query = self.SearchEntry.get_text().lower() if self.query == query: self.search_position += 1 else: self.search_position = 0 self.query = query if self.query == "": return self.find_matches() if self.search_list != []: if self.search_position not in list(range(len(self.search_list))): self.search_position = 0 self.search_list.sort() directory = self.search_list[self.search_position] path = self.dir_store.get_path(self.directories[directory]) self.FolderTreeView.expand_to_path(path) self.FolderTreeView.set_cursor(path) # Get matching files in the current directory resultfiles = [] for file in self.files: if query in file.lower(): resultfiles.append(file) sel = self.FileTreeView.get_selection() sel.unselect_all() not_selected = 1 resultfiles.sort() for fn in resultfiles: path = self.file_store.get_path(self.files[fn]) # Select each matching file in directory sel.select_path(path) if not_selected: # Position cursor at first match self.FileTreeView.scroll_to_cell(path, None, True, 0.5, 0.5) not_selected = 0 else: self.search_position = 0 def on_close(self, widget): del self.userbrowses.users[self.user] self.userbrowses.remove_page(self.Main) self.Main.destroy() def on_refresh(self, widget): self.refreshing = True self.info_bar.set_visible(False) self.FolderTreeView.set_sensitive(False) self.FileTreeView.set_sensitive(False) self.frame.browse_user(self.user, local_shares_type=self.local_shares_type) def on_copy_file_path(self, widget, files=False): text = self.selected_folder if files and self.selected_files: text = "\\".join([self.selected_folder, self.selected_files[0]]) self.frame.clip.set_text(text, -1) def on_copy_url(self, widget): if self.selected_files != [] and self.selected_files is not None: path = "\\".join([self.selected_folder, self.selected_files[0]]) self.frame.set_clipboard_url(self.user, path) def on_copy_dir_url(self, widget): if self.selected_folder is None: return path = self.selected_folder if path[:-1] != "/": path += "/" self.frame.set_clipboard_url(self.user, path) def on_file_manager(self, widget): if self.selected_folder is None: return path = self.frame.np.shares.virtual2real(self.selected_folder) command = self.frame.np.config.sections["ui"]["filemanager"] open_file_path(path, command)
class Uploads(TransferList): def __init__(self, frame): TransferList.__init__(self, frame, frame.UploadList, type='uploads') self.myvbox = self.frame.uploadsvbox self.frame.UploadList.set_property("rules-hint", True) self.popup_menu2 = popup2 = PopupMenu(frame) popup2.setup( ("#" + _("Clear finished/erred"), self.OnClearFinishedErred), ("#" + _("Clear finished/aborted"), self.OnClearFinishedAborted), ("#" + _("Clear finished"), self.OnClearFinished), ("#" + _("Clear aborted"), self.OnClearAborted), ("#" + _("Clear queued"), self.OnClearQueued), ("#" + _("Clear failed"), self.OnClearFailed)) self.popup_menu_users = PopupMenu(frame) self.popup_menu = popup = PopupMenu(frame) popup.setup( ("#" + _("Copy _URL"), self.OnCopyURL), ("#" + _("Copy folder URL"), self.OnCopyDirURL), ("#" + _("Send to _player"), self.OnPlayFiles), ("#" + _("Open Directory"), self.OnOpenDirectory), ("#" + _("Search"), self.OnFileSearch), (1, _("User(s)"), self.popup_menu_users, self.OnPopupMenuUsers), ("", None), ("#" + _("Abor_t"), self.OnAbortTransfer), ("#" + _("_Clear"), self.OnClearTransfer), ("#" + _("_Retry"), self.OnUploadTransfer), ("", None), (1, _("Clear Groups"), self.popup_menu2, None)) frame.UploadList.connect("button_press_event", self.OnPopupMenu, "mouse") frame.UploadList.connect("key-press-event", self.on_key_press_event) cols = frame.UploadList.get_columns() for i in range(10): parent = cols[i].get_widget().get_ancestor(gtk.Button) if parent: parent.connect("button_press_event", PressHeader) # Read Show / Hide column settings from last session cols[i].set_visible( self.frame.np.config.sections["columns"]["uploads_columns"][i]) frame.clearUploadFinishedErredButton.connect("clicked", self.OnClearFinishedErred) frame.clearUploadQueueButton.connect("clicked", self.OnTryClearQueued) frame.abortUploadButton.connect("clicked", self.OnAbortTransfer) frame.abortUserUploadButton.connect("clicked", self.OnAbortUser) frame.banUploadButton.connect("clicked", self.OnBan) frame.UploadList.expand_all() self.frame.ToggleAutoclear.set_active( self.frame.np.config.sections["transfers"]["autoclear_uploads"]) frame.ToggleAutoclear.connect("toggled", self.OnToggleAutoclear) self.frame.ToggleTreeUploads.set_active( self.frame.np.config.sections["transfers"]["groupuploads"]) frame.ToggleTreeUploads.connect("toggled", self.OnToggleTree) self.OnToggleTree(None) self.frame.ExpandUploads.set_active( self.frame.np.config.sections["transfers"]["uploadsexpanded"]) frame.ExpandUploads.connect("toggled", self.OnExpandUploads) self.OnExpandUploads(None) def saveColumns(self): columns = [] widths = [] for column in self.frame.UploadList.get_columns(): columns.append(column.get_visible()) widths.append(column.get_width()) self.frame.np.config.sections["columns"]["uploads_columns"] = columns self.frame.np.config.sections["columns"]["uploads_widths"] = widths def OnTryClearQueued(self, widget): direction = "up" win = OptionDialog(self.frame, _("Clear All Queued Uploads?"), modal=True, status=None, option=False, third="") win.connect("response", self.frame.on_clear_response, direction) win.set_title(_("Nicotine+") + ": " + _("Clear Queued Transfers")) win.set_icon(self.frame.images["n"]) win.show() def OnOpenDirectory(self, widget): downloaddir = self.frame.np.config.sections["transfers"]["downloaddir"] incompletedir = self.frame.np.config.sections["transfers"][ "incompletedir"] if incompletedir == "": incompletedir = downloaddir filemanager = self.frame.np.config.sections["ui"]["filemanager"] transfer = self.selected_transfers[0] if os.path.exists(transfer.path): executeCommand(filemanager, transfer.path) else: executeCommand(filemanager, incompletedir) def OnFileSearch(self, widget): self.select_transfers() for transfer in self.selected_transfers: self.frame.SearchEntry.set_text( transfer.filename.rsplit("\\", 1)[1]) self.frame.ChangeMainPage(None, "search") break def expandcollapse(self, path): if self.frame.ExpandUploads.get_active(): self.frame.UploadList.expand_row(path, True) else: self.frame.UploadList.collapse_row(path) def OnExpandUploads(self, widget): expanded = self.frame.ExpandUploads.get_active() if expanded: self.frame.UploadList.expand_all() self.frame.ExpandUploadsImage.set_from_stock(gtk.STOCK_REMOVE, 4) else: self.frame.UploadList.collapse_all() self.frame.ExpandUploadsImage.set_from_stock(gtk.STOCK_ADD, 4) self.frame.np.config.sections["transfers"][ "uploadsexpanded"] = expanded self.frame.np.config.writeConfiguration() def OnToggleAutoclear(self, widget): self.frame.np.config.sections["transfers"][ "autoclear_uploads"] = self.frame.ToggleAutoclear.get_active() def OnToggleTree(self, widget): self.TreeUsers = self.frame.ToggleTreeUploads.get_active() self.frame.np.config.sections["transfers"][ "groupuploads"] = self.TreeUsers self.RebuildTransfers() if not self.TreeUsers: self.frame.ExpandUploads.hide() else: self.frame.ExpandUploads.show() def RebuildTransfers(self): if self.frame.np.transfers is None: return self.Clear() self.update() def select_transfers(self): self.selected_transfers = [] self.selected_users = [] self.widget.get_selection().selected_foreach( self.SelectedTransfersCallback) def OnBan(self, widget): self.select_transfers() for user in self.selected_users: self.frame.BanUser(user) def OnAbortUser(self, widget): self.select_transfers() for user in self.selected_users: for i in self.list[:]: if i.user == user: if i not in self.selected_transfers: self.selected_transfers.append(i) TransferList.OnAbortTransfer(self, widget, False, False) self.frame.np.transfers.calcUploadQueueSizes() self.frame.np.transfers.checkUploadQueue() def OnUploadTransfer(self, widget): self.select_transfers() for transfer in self.selected_transfers: filename = transfer.filename path = transfer.path user = transfer.user if user in self.frame.np.transfers.getTransferringUsers(): continue self.frame.np.ProcessRequestToPeer( user, slskmessages.UploadQueueNotification(None)) self.frame.np.transfers.pushFile(user, filename, path, transfer) self.frame.np.transfers.checkUploadQueue() def OnSelectUserTransfer(self, widet): if len(self.selected_users) != 1: return selected_user = self.selected_users[0] sel = self.frame.UploadList.get_selection() fmodel = self.frame.UploadList.get_model() sel.unselect_all() for item in self.transfers: user_file, iter, transfer = item user, filepath = user_file if selected_user == user: ix = fmodel.get_path(iter) sel.select_path(ix, ) self.select_transfers() def on_key_press_event(self, widget, event): key = Gdk.keyval_name(event.keyval) if key in ("P", "p"): self.OnPopupMenu(widget, event, "keyboard") else: self.selected_transfers = [] self.selected_users = [] self.widget.get_selection().selected_foreach( self.SelectedTransfersCallback) if key in ("T", "t"): self.OnAbortTransfer(widget) elif key == "Delete": self.OnAbortTransfer(widget, False, True) def OnPlayFiles(self, widget, prefix=""): start_new_thread(self._OnPlayFiles, (widget, prefix)) def _OnPlayFiles(self, widget, prefix=""): executable = self.frame.np.config.sections["players"]["default"] if "$" not in executable: return for fn in self.selected_transfers: file = fn.filename.replace("\\", os.sep) if os.path.exists(file): executeCommand(executable, file, background=False) def OnPopupMenuUsers(self, widget): self.selected_transfers = [] self.selected_users = [] self.widget.get_selection().selected_foreach( self.SelectedTransfersCallback) self.popup_menu_users.clear() if len(self.selected_users) > 0: items = [] self.selected_users.sort(key=str.lower) for user in self.selected_users: popup = PopupMenu(self.frame) popup.setup( ("#" + _("Send _message"), popup.OnSendMessage), ("#" + _("Show IP a_ddress"), popup.OnShowIPaddress), ("#" + _("Get user i_nfo"), popup.OnGetUserInfo), ("#" + _("Brow_se files"), popup.OnBrowseUser), ("#" + _("Gi_ve privileges"), popup.OnGivePrivileges), ("", None), ("$" + _("_Add user to list"), popup.OnAddToList), ("$" + _("_Ban this user"), popup.OnBanUser), ("$" + _("_Ignore this user"), popup.OnIgnoreUser), ("#" + _("Select User's Transfers"), self.OnSelectUserTransfer)) popup.set_user(user) items.append((1, user, popup, self.OnPopupMenuUser, popup)) self.popup_menu_users.setup(*items) return True def OnPopupMenuUser(self, widget, popup=None): if popup is None: return menu = popup user = menu.user items = menu.get_children() act = False if len(self.selected_users) >= 1: act = True items[0].set_sensitive(act) items[1].set_sensitive(act) items[2].set_sensitive(act) items[3].set_sensitive(act) items[6].set_active(user in [ i[0] for i in self.frame.np.config.sections["server"]["userlist"] ]) items[7].set_active( user in self.frame.np.config.sections["server"]["banlist"]) items[8].set_active( user in self.frame.np.config.sections["server"]["ignorelist"]) for i in range(4, 9): items[i].set_sensitive(act) return True def OnPopupMenu(self, widget, event, kind): if kind == "mouse": if event.button != 3: if event.button == 1 and event.type == Gdk.EventType._2BUTTON_PRESS: self.DoubleClick(event) return False self.selected_transfers = [] self.selected_users = [] self.widget.get_selection().selected_foreach( self.SelectedTransfersCallback) self.SelectCurrentRow(event, kind) users = len(self.selected_users) > 0 multi_users = len(self.selected_users) > 1 # noqa: F841 files = len(self.selected_transfers) > 0 multi_files = len(self.selected_transfers) > 1 items = self.popup_menu.get_children() if users: items[5].set_sensitive(True) # Users Menu else: items[5].set_sensitive(False) # Users Menu if files and not multi_files: act = True else: act = False items[0].set_sensitive(act) items[1].set_sensitive(act) if users and files: act = True else: act = False for i in list(range(3, 5)) + list(range(6, 10)): items[i].set_sensitive(act) items[2].set_sensitive(act) # send to player self.popup_menu.popup(None, None, None, None, 3, event.time) if kind == "keyboard": widget.emit_stop_by_name("key_press_event") elif kind == "mouse": widget.emit_stop_by_name("button_press_event") return True def ClearByUser(self, user): for i in self.list[:]: if i.user == user: if i.transfertimer is not None: i.transfertimer.cancel() self.list.remove(i) self.frame.np.transfers.calcUploadQueueSizes() self.frame.np.transfers.checkUploadQueue() self.update() def DoubleClick(self, event): self.select_transfers() dc = self.frame.np.config.sections["transfers"]["upload_doubleclick"] if dc == 1: # Send to player self.OnPlayFiles(None) elif dc == 2: # File manager self.OnOpenDirectory(None) elif dc == 3: # Search self.OnFileSearch(None) elif dc == 4: # Abort self.OnAbortTransfer(None, False) elif dc == 5: # Clear self.OnClearTransfer(None) def OnAbortTransfer(self, widget, remove=False, clear=False): self.select_transfers() TransferList.OnAbortTransfer(self, widget, remove, clear) self.frame.np.transfers.calcUploadQueueSizes() self.frame.np.transfers.checkUploadQueue() self.update() def OnClearQueued(self, widget): self.select_transfers() TransferList.OnClearQueued(self, widget) self.frame.np.transfers.calcUploadQueueSizes() self.frame.np.transfers.checkUploadQueue() self.update() def OnClearFailed(self, widget): TransferList.OnClearFailed(self, widget) self.frame.np.transfers.calcUploadQueueSizes() self.frame.np.transfers.checkUploadQueue() self.update()
class Downloads(TransferList): def __init__(self, frame): TransferList.__init__(self, frame, frame.DownloadList, type='downloads') self.myvbox = self.frame.downloadsvbox self.frame.DownloadList.set_property("rules-hint", True) self.accel_group = gtk.AccelGroup() self.popup_menu_users = PopupMenu(self.frame, False) self.popup_menu_clear = popup2 = PopupMenu(self.frame, False) popup2.setup( ("#" + _("Clear finished/aborted"), self.OnClearFinishedAborted), ("#" + _("Clear finished"), self.OnClearFinished), ("#" + _("Clear aborted"), self.OnClearAborted), ("#" + _("Clear paused"), self.OnClearPaused), ("#" + _("Clear filtered"), self.OnClearFiltered), ("#" + _("Clear queued"), self.OnClearQueued)) self.popup_menu = popup = PopupMenu(frame) popup.setup( ("#" + _("Get place in _queue"), self.OnGetPlaceInQueue), ("", None), ("#" + _("Copy _URL"), self.OnCopyURL), ("#" + _("Copy folder URL"), self.OnCopyDirURL), ("#" + _("Send to _player"), self.OnPlayFiles), ("#" + _("View Metadata of file(s)"), self.OnDownloadMeta), ("#" + _("Open Directory"), self.OnOpenDirectory), ("#" + _("Search"), self.OnFileSearch), (1, _("User(s)"), self.popup_menu_users, self.OnPopupMenuUsers), ("", None), ("#" + _("_Retry"), self.OnRetryTransfer), ("", None), ("#" + _("Abor_t"), self.OnAbortTransfer), ("#" + _("Abort & Delete"), self.OnAbortRemoveTransfer), ("#" + _("_Clear"), self.OnClearTransfer), ("", None), (1, _("Clear Groups"), self.popup_menu_clear, None)) frame.DownloadList.connect("button_press_event", self.OnPopupMenu, "mouse") frame.DownloadList.connect("key-press-event", self.on_key_press_event) cols = frame.DownloadList.get_columns() try: for i in range(len(cols)): parent = cols[i].get_widget().get_ancestor(gtk.Button) if parent: parent.connect("button_press_event", PressHeader) # Read Show / Hide column settings from last session cols[i].set_visible(self.frame.np.config.sections["columns"] ["downloads_columns"][i]) except IndexError: # Column count in config is probably incorrect (outdated?), don't crash pass frame.clearFinishedAbortedButton.connect("clicked", self.OnClearFinishedAborted) frame.clearQueuedButton.connect("clicked", self.OnTryClearQueued) frame.retryTransferButton.connect("clicked", self.OnRetryTransfer) frame.abortTransferButton.connect("clicked", self.OnSelectAbortTransfer) frame.deleteTransferButton.connect("clicked", self.OnAbortRemoveTransfer) frame.banDownloadButton.connect("clicked", self.OnBan) frame.DownloadList.expand_all() self.frame.ToggleAutoRetry.set_active( self.frame.np.config.sections["transfers"]["autoretry_downloads"]) frame.ToggleAutoRetry.connect("toggled", self.OnToggleAutoRetry) self.frame.ToggleTreeDownloads.set_active( self.frame.np.config.sections["transfers"]["groupdownloads"]) frame.ToggleTreeDownloads.connect("toggled", self.OnToggleTree) self.OnToggleTree(None) self.frame.ExpandDownloads.set_active( self.frame.np.config.sections["transfers"]["downloadsexpanded"]) frame.ExpandDownloads.connect("toggled", self.OnExpandDownloads) self.OnExpandDownloads(None) def saveColumns(self): columns = [] widths = [] for column in self.frame.DownloadList.get_columns(): columns.append(column.get_visible()) widths.append(column.get_width()) self.frame.np.config.sections["columns"]["downloads_columns"] = columns self.frame.np.config.sections["columns"]["downloads_widths"] = widths def OnToggleAutoRetry(self, widget): self.frame.np.config.sections["transfers"][ "autoretry_downloads"] = self.frame.ToggleAutoRetry.get_active() def OnTryClearQueued(self, widget): direction = "down" win = OptionDialog(self.frame, _("Clear All Queued Downloads?"), modal=True, status=None, option=False, third="") win.connect("response", self.frame.on_clear_response, direction) win.set_title(_("Nicotine+") + ": " + _("Clear Queued Transfers")) win.set_icon(self.frame.images["n"]) win.show() def expandcollapse(self, path): if self.frame.ExpandDownloads.get_active(): self.frame.DownloadList.expand_row(path, True) else: self.frame.DownloadList.collapse_row(path) def OnExpandDownloads(self, widget): expanded = self.frame.ExpandDownloads.get_active() if expanded: self.frame.DownloadList.expand_all() self.frame.ExpandDownloadsImage.set_from_stock(gtk.STOCK_REMOVE, 4) else: self.frame.DownloadList.collapse_all() self.frame.ExpandDownloadsImage.set_from_stock(gtk.STOCK_ADD, 4) self.frame.np.config.sections["transfers"][ "downloadsexpanded"] = expanded self.frame.np.config.writeConfiguration() def OnToggleTree(self, widget): self.TreeUsers = self.frame.ToggleTreeDownloads.get_active() self.frame.np.config.sections["transfers"][ "groupdownloads"] = self.TreeUsers if not self.TreeUsers: self.frame.ExpandDownloads.hide() else: self.frame.ExpandDownloads.show() self.RebuildTransfers() def MetaBox(self, title="Meta Data", message="", data=None, modal=True, Search=False): win = MetaDialog(self.frame, message, data, modal, Search=Search) win.set_title(title) win.set_icon(self.frame.images["n"]) win.show() gtk.main() return win.ret def SelectedResultsAllData(self, model, path, iter, data): if iter in self.selected_users: return user = model.get_value(iter, 0) filename = model.get_value(iter, 1) fullname = model.get_value(iter, 10) size = speed = "0" length = bitrate = None # noqa: F841 queue = immediate = num = country = bitratestr = "" for transfer in self.frame.np.transfers.downloads: if transfer.user == user and fullname == transfer.filename: size = HumanSize(transfer.size) try: speed = str(int(transfer.speed)) speed += _(" KB/s") except Exception: pass bitratestr = str(transfer.bitrate) length = str(transfer.length) directory = fullname.rsplit("\\", 1)[0] data[len(data)] = { "user": user, "fn": fullname, "position": num, "filename": filename, "directory": directory, "size": size, "speed": speed, "queue": queue, "immediate": immediate, "bitrate": bitratestr, "length": length, "country": country } def OnDownloadMeta(self, widget): if not self.frame.np.transfers: return data = {} self.widget.get_selection().selected_foreach( self.SelectedResultsAllData, data) if data != {}: self.MetaBox(title=_("Nicotine+:") + " " + _("Downloads Metadata"), message=_("<b>Metadata</b> for Downloads"), data=data, modal=True, Search=False) def OnOpenDirectory(self, widget): downloaddir = self.frame.np.config.sections["transfers"]["downloaddir"] incompletedir = self.frame.np.config.sections["transfers"][ "incompletedir"] if incompletedir == "": incompletedir = downloaddir filemanager = self.frame.np.config.sections["ui"]["filemanager"] transfer = self.selected_transfers[0] complete_path = os.path.join(downloaddir, transfer.path) if transfer.path == "": if transfer.status == "Finished": executeCommand(filemanager, downloaddir) else: executeCommand(filemanager, incompletedir) elif os.path.exists(complete_path): # and tranfer.status is "Finished" executeCommand(filemanager, complete_path) else: executeCommand(filemanager, incompletedir) def RebuildTransfers(self): if self.frame.np.transfers is None: return self.Clear() self.update() def select_transfers(self): self.selected_transfers = [] self.selected_users = [] self.widget.get_selection().selected_foreach( self.SelectedTransfersCallback) def OnBan(self, widgets): self.select_transfers() for user in self.selected_users: self.frame.BanUser(user) def OnSelectAbortTransfer(self, widget): self.select_transfers() self.OnAbortTransfer(widget, False) def OnSelectUserTransfer(self, widget): if len(self.selected_users) == 0: return selected_user = widget.get_parent().user sel = self.frame.DownloadList.get_selection() fmodel = self.frame.DownloadList.get_model() sel.unselect_all() for item in self.transfers: user_file, iter, transfer = item user, filepath = user_file if selected_user == user: ix = fmodel.get_path(iter) sel.select_path(ix, ) self.select_transfers() def on_key_press_event(self, widget, event): key = Gdk.keyval_name(event.keyval) if key in ("P", "p"): self.OnPopupMenu(widget, event, "keyboard") else: self.select_transfers() if key in ("T", "t"): self.OnAbortTransfer(widget) elif key in ("R", "r"): self.OnRetryTransfer(widget) elif key == "Delete": self.OnAbortTransfer(widget, True, True) def OnPlayFiles(self, widget, prefix=""): start_new_thread(self._OnPlayFiles, (widget, prefix)) def _OnPlayFiles(self, widget, prefix=""): executable = self.frame.np.config.sections["players"]["default"] downloaddir = self.frame.np.config.sections["transfers"]["downloaddir"] if "$" not in executable: return for fn in self.selected_transfers: if fn.file is None: continue playfile = None if os.path.exists(fn.file.name): playfile = fn.file.name else: # If this file doesn't exist anymore, it may have finished downloading and have been renamed # try looking in the download directory and match the original filename. basename = str.split(fn.filename, '\\')[-1] path = os.sep.join([downloaddir, basename]) if os.path.exists(path): playfile = path if playfile: executeCommand(executable, playfile, background=False) def OnPopupMenuUsers(self, widget): self.selected_transfers = [] self.selected_users = [] self.widget.get_selection().selected_foreach( self.SelectedTransfersCallback) self.popup_menu_users.clear() if len(self.selected_users) > 0: items = [] self.selected_users.sort(key=str.lower) for user in self.selected_users: popup = PopupMenu(self.frame, False) popup.setup( ("#" + _("Send _message"), popup.OnSendMessage), ("#" + _("Show IP a_ddress"), popup.OnShowIPaddress), ("#" + _("Get user i_nfo"), popup.OnGetUserInfo), ("#" + _("Brow_se files"), popup.OnBrowseUser), ("#" + _("Gi_ve privileges"), popup.OnGivePrivileges), ("", None), ("$" + _("_Add user to list"), popup.OnAddToList), ("$" + _("_Ban this user"), popup.OnBanUser), ("$" + _("_Ignore this user"), popup.OnIgnoreUser), ("#" + _("Select User's Transfers"), self.OnSelectUserTransfer)) popup.set_user(user) items.append((1, user, popup, self.OnPopupMenuUser, popup)) self.popup_menu_users.setup(*items) return True def OnPopupMenuUser(self, widget, popup=None): if popup is None: return menu = popup user = menu.user items = menu.get_children() act = False if len(self.selected_users) >= 1: act = True items[0].set_sensitive(act) items[1].set_sensitive(act) items[2].set_sensitive(act) items[3].set_sensitive(act) items[6].set_active(user in [ i[0] for i in self.frame.np.config.sections["server"]["userlist"] ]) items[7].set_active( user in self.frame.np.config.sections["server"]["banlist"]) items[8].set_active( user in self.frame.np.config.sections["server"]["ignorelist"]) for i in range(4, 9): items[i].set_sensitive(act) return True def DoubleClick(self, event): self.select_transfers() dc = self.frame.np.config.sections["transfers"]["download_doubleclick"] if dc == 1: # Send to player self.OnPlayFiles(None) elif dc == 2: # File manager self.OnOpenDirectory(None) elif dc == 3: # Search self.OnFileSearch(None) elif dc == 4: # Abort self.OnAbortTransfer(None, False) elif dc == 5: # Clear self.OnClearTransfer(None) elif dc == 6: # Retry self.OnRetryTransfer(None) def OnPopupMenu(self, widget, event, kind): if kind == "mouse": if event.button != 3: if event.button == 1 and event.type == Gdk.EventType._2BUTTON_PRESS: self.DoubleClick(event) return False self.selected_transfers = [] self.selected_users = [] self.widget.get_selection().selected_foreach( self.SelectedTransfersCallback) users = len(self.selected_users) > 0 multi_users = len(self.selected_users) > 1 # noqa: F841 files = len(self.selected_transfers) > 0 multi_files = len(self.selected_transfers) > 1 self.SelectCurrentRow(event, kind) items = self.popup_menu.get_children() if users: items[7].set_sensitive(True) # Users Menu else: items[7].set_sensitive(False) # Users Menu if files: act = True else: act = False items[0].set_sensitive(act) # Place items[4].set_sensitive(act) # Send to player items[5].set_sensitive(act) # View Meta items[6].set_sensitive(act) # File manager items[8].set_sensitive(act) # Search filename act = False if not multi_files and files: act = True items[2].set_sensitive(act) # Copy URL items[3].set_sensitive(act) # Copy Folder URL if not users or not files: # Disable options # Abort, Abort and Remove, retry, clear act = False else: act = True for i in range(10, 15): items[i].set_sensitive(act) self.popup_menu.popup(None, None, None, None, 3, event.time) if kind == "keyboard": widget.emit_stop_by_name("key_press_event") elif kind == "mouse": widget.emit_stop_by_name("button_press_event") return True def update(self, transfer=None, forced=False): TransferList.update(self, transfer, forced) if transfer is None and self.frame.np.transfers is not None: self.frame.np.transfers.SaveDownloads() def OnGetPlaceInQueue(self, widget): self.select_transfers() for i in self.selected_transfers: if i.status != "Queued": continue self.frame.np.ProcessRequestToPeer( i.user, slskmessages.PlaceInQueueRequest(None, i.filename)) def OnFileSearch(self, widget): self.select_transfers() for transfer in self.selected_transfers: self.frame.SearchEntry.set_text( transfer.filename.rsplit("\\", 1)[1]) self.frame.ChangeMainPage(None, "search") break def OnRetryTransfer(self, widget): self.select_transfers() for transfer in self.selected_transfers: if transfer.status in ["Finished", "Old"]: continue self.frame.np.transfers.AbortTransfer(transfer) transfer.req = None self.frame.np.transfers.getFile(transfer.user, transfer.filename, transfer.path, transfer) self.frame.np.transfers.SaveDownloads() def OnAbortRemoveTransfer(self, widget): self.select_transfers() self.OnClearTransfer(widget)
class RoomList: def __init__(self, frame, joined_rooms, private_rooms): # Build the window self.frame = frame self.server_rooms = set() self.joined_rooms = joined_rooms self.private_rooms = private_rooms load_ui_elements( self, os.path.join(self.frame.gui_dir, "ui", "popovers", "roomlist.ui")) self.room_model = Gtk.ListStore(str, int, int) self.cols = initialise_columns( None, self.RoomsList, ["room", _("Room"), 260, "text", self.room_status, None], ["users", _("Users"), 0, "number", self.room_status, None]) self.cols["room"].set_sort_column_id(0) self.cols["users"].set_sort_column_id(1) self.popup_room = None self.popup_menu = PopupMenu(self.frame) self.popup_menu.setup( ("#" + _("Join Room"), self.on_popup_join), ("#" + _("Leave Room"), self.on_popup_leave), ("", None), ("#" + _("Disown Private Room"), self.on_popup_private_room_disown), ("#" + _("Cancel Room Membership"), self.on_popup_private_room_dismember), ("", None), ("#" + _("Join Public Room"), self.on_join_public_room)) self.RoomsList.connect("button_press_event", self.on_list_clicked) self.RoomsList.connect("popup-menu", self.on_popup_menu) self.RoomsList.connect("touch_event", self.on_list_clicked) self.RoomsList.set_headers_clickable(True) self.search_iter = None self.query = "" self.AcceptPrivateRoom.set_active( self.frame.np.config.sections["server"]["private_chatrooms"]) self.AcceptPrivateRoom.connect("toggled", self.on_toggle_accept_private_room) frame.RoomList.connect("clicked", self.show) self.RoomListPopover.set_relative_to(frame.RoomList) def get_selected_room(self, treeview): model, iterator = treeview.get_selection().get_selected() if iterator is None: return None return model.get_value(iterator, 0) def is_private_room_owned(self, room): if room in self.private_rooms: if self.private_rooms[room][ "owner"] == self.frame.np.config.sections["server"][ "login"]: return True return False def is_private_room_member(self, room): if room in self.private_rooms: return True return False def is_private_room_operator(self, room): if room in self.private_rooms: if self.frame.np.config.sections["server"][ "login"] in self.private_rooms[room]["operators"]: return True return False def private_rooms_sort(self, model, iter1, iter2, column): try: private1 = model.get_value(iter1, 2) * 10000 private1 += model.get_value(iter1, 1) except Exception: private1 = 0 try: private2 = model.get_value(iter2, 2) * 10000 private2 += model.get_value(iter2, 1) except Exception: private2 = 0 return (private1 > private2) - (private1 < private2) def room_match_function(self, model, iterator, data=None): query = self.SearchRooms.get_text().lower() value = model.get_value(iterator, 0) if query == "" or query in value.lower(): return True return False def room_status(self, column, cellrenderer, model, iterator, dummy='dummy'): if self.room_model_filtered.get_value(iterator, 2) >= 2: cellrenderer.set_property("underline", Pango.Underline.SINGLE) cellrenderer.set_property("weight", Pango.Weight.BOLD) elif self.room_model_filtered.get_value(iterator, 2) >= 1: cellrenderer.set_property("weight", Pango.Weight.BOLD) cellrenderer.set_property("underline", Pango.Underline.NONE) else: cellrenderer.set_property("weight", Pango.Weight.NORMAL) cellrenderer.set_property("underline", Pango.Underline.NONE) def set_room_list(self, rooms, owned_rooms, other_private_rooms): self.room_model.clear() for room, users in rooms: self.room_model.append([room, users, 0]) self.server_rooms = set() for room, users in rooms: self.server_rooms.add(room) self.set_private_rooms(owned_rooms, other_private_rooms) self.room_model.set_sort_func(1, self.private_rooms_sort, 1) self.room_model.set_sort_column_id(1, Gtk.SortType.DESCENDING) self.room_model.set_default_sort_func(self.private_rooms_sort) self.room_filter = self.room_model.filter_new() self.room_filter.set_visible_func(self.room_match_function) self.room_model_filtered = Gtk.TreeModelSort(self.room_filter) self.RoomsList.set_model(self.room_model_filtered) def set_private_rooms(self, ownedrooms=[], otherrooms=[]): myusername = self.frame.np.config.sections["server"]["login"] for room in ownedrooms: try: self.private_rooms[room[0]]['joined'] = room[1] if self.private_rooms[room[0]]['owner'] != myusername: log.add_warning( _("I remember the room %(room)s being owned by %(previous)s, but the server says its owned by %(new)s." ), { 'room': room[0], 'previous': self.private_rooms[room[0]]['owner'], 'new': myusername }) self.private_rooms[room[0]]['owner'] = myusername except KeyError: self.private_rooms[room[0]] = { "users": [], "joined": room[1], "operators": [], "owner": myusername } for room in otherrooms: try: self.private_rooms[room[0]]['joined'] = room[1] if self.private_rooms[room[0]]['owner'] == myusername: log.add_warning( _("I remember the room %(room)s being owned by %(old)s, but the server says that's not true." ), { 'room': room[0], 'old': self.private_rooms[room[0]]['owner'], }) self.private_rooms[room[0]]['owner'] = None except KeyError: self.private_rooms[room[0]] = { "users": [], "joined": room[1], "operators": [], "owner": None } iterator = self.room_model.get_iter_first() while iterator: room = self.room_model.get_value(iterator, 0) if self.is_private_room_owned(room) or self.is_private_room_member( room): self.room_model.remove(iterator) iterator = self.room_model.iter_next(iterator) for room in self.private_rooms: num = self.private_rooms[room]["joined"] if self.is_private_room_owned(room): self.room_model.prepend([room, num, 2]) elif self.is_private_room_member(room): self.room_model.prepend([room, num, 1]) def update_room(self, room, user_count): if room in self.server_rooms: iterator = self.room_model.get_iter_first() while iterator: if self.room_model.get_value(iterator, 0) == room: self.room_model.set(iterator, 1, user_count) break iterator = self.room_model.iter_next(iterator) else: self.room_model.append([room, user_count, 0]) self.server_rooms.add(room) def on_list_clicked(self, widget, event): set_treeview_selected_row(widget, event) if triggers_context_menu(event): return self.on_popup_menu(widget) if event.button == 1 and event.type == Gdk.EventType._2BUTTON_PRESS: room = self.get_selected_room(widget) if room is not None and room not in self.joined_rooms: self.popup_room = room self.on_popup_join(widget) return True return False def on_popup_menu(self, widget): if self.room_model is None: return False room = self.get_selected_room(widget) if room is not None: if room in self.joined_rooms: act = (False, True) else: act = (True, False) else: act = (False, False) self.popup_room = room prooms_enabled = True items = self.popup_menu.get_items() items[_("Join Room")].set_sensitive(act[0]) items[_("Leave Room")].set_sensitive(act[1]) items[_("Disown Private Room")].set_sensitive( self.is_private_room_owned(self.popup_room)) items[_("Cancel Room Membership")].set_sensitive( (prooms_enabled and self.is_private_room_member(self.popup_room))) self.popup_menu.popup() return True def on_popup_join(self, widget): self.frame.np.queue.put(slskmessages.JoinRoom(self.popup_room)) def on_join_public_room(self, widget): self.frame.chatrooms.join_room(slskmessages.JoinRoom("Public ")) self.frame.np.queue.put(slskmessages.JoinPublicRoom()) def on_popup_private_room_disown(self, widget): if self.is_private_room_owned(self.popup_room): self.frame.np.queue.put( slskmessages.PrivateRoomDisown(self.popup_room)) del self.private_rooms[self.popup_room] def on_popup_private_room_dismember(self, widget): if self.is_private_room_member(self.popup_room): self.frame.np.queue.put( slskmessages.PrivateRoomDismember(self.popup_room)) del self.private_rooms[self.popup_room] def on_popup_leave(self, widget): self.frame.np.queue.put(slskmessages.LeaveRoom(self.popup_room)) def on_search_room(self, widget): self.room_filter.refilter() def on_refresh(self, widget): self.frame.np.queue.put(slskmessages.RoomList()) def on_toggle_accept_private_room(self, widget): value = self.AcceptPrivateRoom.get_active() self.frame.np.queue.put(slskmessages.PrivateRoomToggle(value)) def update_visuals(self): for widget in self.__dict__.values(): update_widget_visuals(widget) def clear(self): self.room_model.clear() def show(self, *args): self.RoomListPopover.popup()
class UserBrowse: def __init__(self, userbrowses, user, conn): _config_dir, self.data_dir = GetUserDirectories() # Build the window builder = gtk.Builder() builder.set_translation_domain('nicotine') builder.add_from_file(os.path.join(os.path.dirname(os.path.realpath(__file__)), "ui", "userbrowse.ui")) self.UserBrowseTab = builder.get_object("UserBrowseTab") for i in builder.get_objects(): try: self.__dict__[gtk.Buildable.get_name(i)] = i except TypeError: pass self.UserBrowseTab.remove(self.Main) self.UserBrowseTab.destroy() builder.connect_signals(self) self.userbrowses = userbrowses self.frame = userbrowses.frame self.user = user self.conn = conn # selected_folder is the current selected folder self.selected_folder = None self.search_list = [] self.query = None self.search_position = 0 self.selected_files = [] self.shares = [] # Iters for current DirStore self.directories = {} # Iters for current FileStore self.files = {} self.totalsize = 0 self.DirStore = gtk.TreeStore(str, str) self.FolderTreeView.set_headers_visible(True) self.FolderTreeView.set_enable_tree_lines(True) cols = InitialiseColumns( self.FolderTreeView, [_("Directories"), -1, "text", self.CellDataFunc] # 0 ) cols[0].set_sort_column_id(0) self.popup_menu_users = PopupMenu(self.frame, False) self.popup_menu_users2 = PopupMenu(self.frame, False) for menu in [self.popup_menu_users, self.popup_menu_users2]: menu.setup( ("#" + _("Send _message"), menu.OnSendMessage), ("#" + _("Show IP a_ddress"), menu.OnShowIPaddress), ("#" + _("Get user i_nfo"), menu.OnGetUserInfo), ("#" + _("Gi_ve privileges"), menu.OnGivePrivileges), ("", None), ("$" + _("_Add user to list"), menu.OnAddToList), ("$" + _("_Ban this user"), menu.OnBanUser), ("$" + _("_Ignore this user"), menu.OnIgnoreUser) ) self.popup_menu_downloads_folders = PopupMenu(self.frame, False) self.popup_menu_downloads_folders.setup( ("#" + _("_Download directory"), self.OnDownloadDirectory), ("#" + _("Download directory _to..."), self.OnDownloadDirectoryTo), ("#" + _("Download _recursive"), self.OnDownloadDirectoryRecursive), ("#" + _("Download r_ecursive to..."), self.OnDownloadDirectoryRecursiveTo) ) self.popup_menu_downloads_files = PopupMenu(self.frame, False) self.popup_menu_downloads_files.setup( ("#" + _("_Download file(s)"), self.OnDownloadFiles), ("#" + _("Download _to..."), self.OnDownloadFilesTo), ("", None), ("#" + _("_Download directory"), self.OnDownloadDirectory), ("#" + _("Download directory _to..."), self.OnDownloadDirectoryTo), ("#" + _("Download _recursive"), self.OnDownloadDirectoryRecursive), ("#" + _("Download r_ecursive to..."), self.OnDownloadDirectoryRecursiveTo) ) self.popup_menu_uploads_folders = PopupMenu(self.frame, False) self.popup_menu_uploads_folders.setup( ("#" + _("Upload Directory to..."), self.OnUploadDirectoryTo), ("#" + _("Upload Directory recursive to..."), self.OnUploadDirectoryRecursiveTo) ) self.popup_menu_uploads_files = PopupMenu(self.frame, False) self.popup_menu_uploads_files.setup( ("#" + _("Upload Directory to..."), self.OnUploadDirectoryTo), ("#" + _("Upload Directory recursive to..."), self.OnUploadDirectoryRecursiveTo), ("#" + _("Up_load file(s)"), self.OnUploadFiles) ) self.folder_popup_menu = PopupMenu(self.frame) self.folder_popup_menu.set_user(user) if user == self.frame.np.config.sections["server"]["login"]: self.folder_popup_menu.setup( ("USERMENU", _("User"), self.popup_menu_users, self.OnPopupMenuFolderUser), ("", None), (1, _("Download"), self.popup_menu_downloads_folders, self.OnPopupMenuDummy), (1, _("Upload"), self.popup_menu_uploads_folders, self.OnPopupMenuDummy), ("", None), ("#" + _("Copy _URL"), self.OnCopyDirURL), ("#" + _("Open in File Manager"), self.OnFileManager) ) else: self.folder_popup_menu.setup( ("USERMENU", _("User"), self.popup_menu_users, self.OnPopupMenuFolderUser), ("", None), (1, _("Download"), self.popup_menu_downloads_folders, self.OnPopupMenuDummy), ("", None), ("#" + _("Copy _URL"), self.OnCopyDirURL) ) self.FolderTreeView.connect("button_press_event", self.OnFolderClicked) self.FolderTreeView.get_selection().connect("changed", self.OnSelectDir) # Filename, HSize, Bitrate, HLength, Size, Length, RawFilename self.FileStore = gtk.ListStore(str, str, str, str, gobject.TYPE_INT64, int, str) self.FileTreeView.set_model(self.FileStore) widths = self.frame.np.config.sections["columns"]["userbrowse_widths"] cols = InitialiseColumns( self.FileTreeView, [_("Filename"), widths[0], "text", self.CellDataFunc], [_("Size"), widths[1], "text", self.CellDataFunc], [_("Bitrate"), widths[2], "text", self.CellDataFunc], [_("Length"), widths[3], "text", self.CellDataFunc] ) cols[0].set_sort_column_id(0) cols[1].set_sort_column_id(4) cols[2].set_sort_column_id(2) cols[3].set_sort_column_id(5) self.FileStore.set_sort_column_id(0, gtk.SortType.ASCENDING) try: for i in range(len(cols)): parent = cols[i].get_widget().get_ancestor(gtk.Button) if parent: parent.connect("button_press_event", PressHeader) # Read Show / Hide column settings from last session cols[i].set_visible(self.frame.np.config.sections["columns"]["userbrowse"][i]) except IndexError: # Column count in config is probably incorrect (outdated?), don't crash pass self.FileTreeView.get_selection().set_mode(gtk.SelectionMode.MULTIPLE) self.FileTreeView.set_headers_clickable(True) self.FileTreeView.set_property("rules-hint", True) self.file_popup_menu = PopupMenu(self.frame) if user == self.frame.np.config.sections["server"]["login"]: self.file_popup_menu.setup( ("USERMENU", "User", self.popup_menu_users2, self.OnPopupMenuFileUser), ("", None), (1, _("Download"), self.popup_menu_downloads_files, self.OnPopupMenuDummy), (1, _("Upload"), self.popup_menu_uploads_files, self.OnPopupMenuDummy), ("", None), ("#" + _("Copy _URL"), self.OnCopyURL), ("#" + _("Send to _player"), self.OnPlayFiles), ("#" + _("Open in File Manager"), self.OnFileManager) ) else: self.file_popup_menu.setup( ("USERMENU", "User", self.popup_menu_users2, self.OnPopupMenuFileUser), ("", None), (1, _("Download"), self.popup_menu_downloads_files, self.OnPopupMenuDummy), ("", None), ("#" + _("Copy _URL"), self.OnCopyURL) ) self.FileTreeView.connect("button_press_event", self.OnFileClicked) self.ChangeColours() for name, object in list(self.__dict__.items()): if type(object) is PopupMenu: object.set_user(self.user) def OnPopupMenuDummy(self, widget): pass def Attach(self, widget=None): self.userbrowses.attach_tab(self.Main) def Detach(self, widget=None): self.userbrowses.detach_tab( self.Main, _("Nicotine+ User Browse: %(user)s (%(status)s)") % { 'user': self.user, 'status': [_("Offline"), _("Away"), _("Online")][self.status] } ) def ConnClose(self): pass def OnPopupMenuFileUser(self, widget): self.OnPopupMenuUsers(self.popup_menu_users2) def OnPopupMenuFolderUser(self, widget): self.OnPopupMenuUsers(self.popup_menu_users) def OnPopupMenuUsers(self, menu): items = menu.get_children() act = True items[0].set_sensitive(act) items[1].set_sensitive(act) items[2].set_sensitive(act) items[5].set_active(self.user in [i[0] for i in self.frame.np.config.sections["server"]["userlist"]]) items[6].set_active(self.user in self.frame.np.config.sections["server"]["banlist"]) items[7].set_active(self.user in self.frame.np.config.sections["server"]["ignorelist"]) for i in range(3, 8): items[i].set_sensitive(act) return True def ChangeColours(self): self.frame.SetTextBG(self.FileTreeView) self.frame.SetTextBG(self.FolderTreeView) self.frame.SetTextBG(self.entry4) self.frame.ChangeListFont(self.FolderTreeView, self.frame.np.config.sections["ui"]["browserfont"]) self.frame.ChangeListFont(self.FileTreeView, self.frame.np.config.sections["ui"]["browserfont"]) def CellDataFunc(self, column, cellrenderer, model, iter, dummy="dummy"): colour = self.frame.np.config.sections["ui"]["search"] if colour == "": colour = None cellrenderer.set_property("foreground", colour) def OnExpand(self, widget): if self.ExpandButton.get_active(): self.FolderTreeView.expand_all() self.ExpandDirectoriesImage.set_from_stock(gtk.STOCK_REMOVE, 4) else: self.FolderTreeView.collapse_all() self.ExpandDirectoriesImage.set_from_stock(gtk.STOCK_ADD, 4) dirs = list(self.directories.keys()) dirs.sort() if dirs != []: self.SetDirectory(dirs[0]) else: self.SetDirectory(None) def OnFolderClicked(self, widget, event): if event.button == 1 and event.type == Gdk.EventType._2BUTTON_PRESS: self.OnDownloadDirectory(widget) return True elif event.button == 3: return self.OnFolderPopupMenu(widget, event) return False def OnFolderPopupMenu(self, widget, event): act = True if self.selected_folder is None: act = False items = self.folder_popup_menu.get_children() for item in items[1:]: item.set_sensitive(act) self.folder_popup_menu.popup(None, None, None, None, event.button, event.time) def SelectedFilesCallback(self, model, path, iter): rawfilename = self.FileStore.get_value(iter, 6) self.selected_files.append(rawfilename) def OnFileClicked(self, widget, event): if event.button == 1 and event.type == Gdk.EventType._2BUTTON_PRESS: self.selected_files = [] self.FileTreeView.get_selection().selected_foreach(self.SelectedFilesCallback) self.OnDownloadFiles(widget) self.FileTreeView.get_selection().unselect_all() return True elif event.button == 3: return self.OnFilePopupMenu(widget, event) return False def OnFilePopupMenu(self, widget, event): self.selected_files = [] self.FileTreeView.get_selection().selected_foreach(self.SelectedFilesCallback) files = True multiple = False if len(self.selected_files) > 1: multiple = True if len(self.selected_files) >= 1: files = True else: files = False items = self.file_popup_menu.get_children() if self.user == self.frame.np.config.sections["server"]["login"]: items[2].set_sensitive(files) # Downloads items[3].set_sensitive(files) # Uploads items[5].set_sensitive(not multiple and files) # Copy URL items[6].set_sensitive(files) # Send to player else: items[2].set_sensitive(files) # Downloads items[4].set_sensitive(not multiple and files) # Copy URL self.FileTreeView.emit_stop_by_name("button_press_event") self.file_popup_menu.popup(None, None, None, None, event.button, event.time) return True def MakeNewModel(self, list): self.shares = list self.selected_folder = None self.selected_files = [] self.directories.clear() self.files.clear() self.DirStore.clear() # Compute the number of shared dirs and total size self.totalsize = 0 for dir, files in self.shares: for filedata in files: if filedata[2] < 18446744000000000000: self.totalsize += filedata[2] else: print("Unbelievable filesize: %s, %s" % (HumanSize(filedata[2]), repr(filedata))) self.AmountShared.set_text(_("Shared: %s") % HumanSize(self.totalsize)) self.NumDirectories.set_text(_("Dirs: %s") % len(self.shares)) # Generate the directory tree and select first directory currentdir = self.BrowseGetDirs() sel = self.FolderTreeView.get_selection() sel.unselect_all() if currentdir in self.directories: path = self.DirStore.get_path(self.directories[currentdir]) if path is not None: sel.select_path(path) self.FolderTreeView.set_sensitive(True) self.FileTreeView.set_sensitive(True) self.SaveButton.set_sensitive(True) if self.ExpandButton.get_active(): self.FolderTreeView.expand_all() else: self.FolderTreeView.collapse_all() def BrowseGetDirs(self): directory = "" dirseparator = '\\' # If there is no share if self.shares == []: # Set the model of the treeviex self.FolderTreeView.set_model(self.DirStore) # Sort the DirStore self.DirStore.set_sort_column_id(0, gtk.SortType.ASCENDING) return directory def builddicttree(p, s): """ Build recursively a hierarchical dict containing raw subdir 'p' is a reference to the parent 's' a list of the subdir of a path ex of 's': ['music', 'rock', 'doors'] """ if s: subdir = s.pop(0) if subdir not in p: p[subdir] = {} builddicttree(p[subdir], s) def buildgtktree(dictdir, parent, path): """ Build recursively self.directories with iters pointing to directories 'dictdir' is a hierarchical dict containing raw subdir 'parent' is the iter pointing to the parent 'path' is the current raw path """ # Foreach subdir for subdir in list(dictdir.keys()): if parent is None: # The first sudirs are attached to the root (None) current_path = subdir else: # Other sudirs futher down the path are attached to their parent current_path = dirseparator.join([path, subdir]) self.directories[current_path] = self.DirStore.append(parent, [subdir, current_path]) # If there are subdirs futher down the path: recurse if len(dictdir[subdir]): buildgtktree(dictdir[subdir], self.directories[current_path], current_path) # For each shared dir we will complete the dictionnary dictdir = {} for dirshares, f in self.shares: # Split the path s = dirshares.split(dirseparator) # and build a hierarchical dictionnary containing raw subdir if len(s) >= 1: builddicttree(dictdir, s) # Append data to the DirStore buildgtktree(dictdir, None, None) # Select the first directory sortlist = list(self.directories.keys()) sortlist.sort() directory = sortlist[0] # Sort the DirStore self.DirStore.set_sort_column_id(0, gtk.SortType.ASCENDING) # Set the model of the treeviex self.FolderTreeView.set_model(self.DirStore) return directory def SetDirectory(self, directory): self.selected_folder = directory self.FileStore.clear() self.files.clear() found_dir = False for d, f in self.shares: if d == directory: found_dir = True files = f break if not found_dir: return for file in files: # Filename, HSize, Bitrate, HLength, Size, Length, RawFilename rl = 0 try: size = int(file[2]) except ValueError: size = 0 f = [file[1], Humanize(size)] if file[3] == "": f += ["", ""] else: # file[4] is for file types such as 'mp3' attrs = file[4] if attrs != [] and type(attrs) is list: if len(attrs) >= 3: br = str(attrs[0]) if attrs[2]: br = br + " (vbr)" try: rl = int(attrs[1]) except ValueError: rl = 0 l = "%i:%02i" % (rl / 60, rl % 60) # noqa: E741 f += [br, l] else: f += ["", ""] else: f += ["", ""] f += [int(size), rl, file[1]] try: self.files[f[0]] = self.FileStore.append(f) except Exception as error: # noqa: F841 displayTraceback() def OnSave(self, widget): sharesdir = os.path.join(self.data_dir, "usershares") try: if not os.path.exists(sharesdir): os.mkdir(sharesdir) except Exception as msg: error = _("Can't create directory '%(folder)s', reported error: %(error)s" % {'folder': sharesdir, 'error': msg}) self.frame.logMessage(error) try: import pickle as mypickle import bz2 sharesfile = bz2.BZ2File(os.path.join(sharesdir, CleanFile(self.user)), 'w') mypickle.dump(self.shares, sharesfile, mypickle.HIGHEST_PROTOCOL) sharesfile.close() except Exception as msg: error = _("Can't save shares, '%(user)s', reported error: %(error)s" % {'user': self.user, 'error': msg}) self.frame.logMessage(error) def saveColumns(self): columns = [] widths = [] for column in self.FileTreeView.get_columns(): columns.append(column.get_visible()) widths.append(column.get_width()) self.frame.np.config.sections["columns"]["userbrowse"] = columns self.frame.np.config.sections["columns"]["userbrowse_widths"] = widths def ShowInfo(self, msg): self.conn = None self.MakeNewModel(msg.list) def LoadShares(self, list): self.MakeNewModel(list) def UpdateGauge(self, msg): if msg.total == 0 or msg.bytes == 0: fraction = 0.0 elif msg.bytes >= msg.total: fraction = 1.0 else: fraction = float(msg.bytes) / msg.total self.progressbar1.set_fraction(fraction) def OnSelectDir(self, selection): model, iter = selection.get_selected() if iter is None: self.selected_folder = None return path = model.get_path(iter) directory = model.get_value(iter, 1) self.FolderTreeView.expand_to_path(path) self.SetDirectory(directory) def OnResort(self, column, column_id): model = self.FileTreeView.get_model() if model.sort_col == column_id: order = model.sort_order if order == gtk.SortType.ASCENDING: order = gtk.SortType.DESCENDING else: order = gtk.SortType.ASCENDING column.set_sort_order(order) model.sort_order = order self.FileTreeView.set_model(None) model.sort() self.FileTreeView.set_model(model) return cols = self.FileTreeView.get_columns() cols[model.sort_col].set_sort_indicator(False) cols[column_id].set_sort_indicator(True) model.sort_col = column_id self.OnResort(column, column_id) def OnDownloadDirectory(self, widget): if self.selected_folder is not None: self.DownloadDirectory(self.selected_folder) def OnDownloadDirectoryRecursive(self, widget): self.DownloadDirectory(self.selected_folder, "", 1) def OnDownloadDirectoryTo(self, widget): dir = ChooseDir(self.frame.MainWindow, self.frame.np.config.sections["transfers"]["downloaddir"]) if dir is None: return try: self.DownloadDirectory(self.selected_folder, os.path.join(dir[0], "")) except IOError: # failed to open self.frame.logMessage('Failed to open %r for reading', dir[0]) # notify user def OnDownloadDirectoryRecursiveTo(self, widget): dir = ChooseDir(self.frame.MainWindow, self.frame.np.config.sections["transfers"]["downloaddir"]) if dir is None: return try: self.DownloadDirectory(self.selected_folder, os.path.join(dir[0], ""), 1) except IOError: # failed to open self.frame.logMessage('Failed to open %r for reading', dir[0]) # notify user def DownloadDirectory(self, dir, prefix="", recurse=0): if dir is None: return for d, f in self.shares: # Find the wanted directory if d != dir: continue ldir = prefix + dir.split("\\")[-1] priorityfiles = [] normalfiles = [] if self.frame.np.config.sections["transfers"]["prioritize"]: for file in f: parts = file[1].rsplit('.', 1) if len(parts) == 2 and parts[1] in ['sfv', 'md5', 'nfo']: priorityfiles.append(file) else: normalfiles.append(file) else: normalfiles = f if self.frame.np.config.sections["transfers"]["reverseorder"]: deco = [(x[1], x) for x in normalfiles] deco.sort(reverse=True) normalfiles = [x for junk, x in deco] for file in priorityfiles + normalfiles: path = "\\".join([dir, file[1]]) size = file[2] length = bitrate = None attrs = file[4] if attrs != []: bitrate = str(attrs[0]) if len(attrs) > 2 and attrs[2]: bitrate += " (vbr)" try: rl = int(attrs[1]) except ValueError: rl = 0 length = "%i:%02i" % (int(rl // 60), rl % 60) self.frame.np.transfers.getFile(self.user, path, ldir, size=size, bitrate=bitrate, length=length) if not recurse: break for subdir, subf in self.shares: if dir in subdir and dir != subdir: self.DownloadDirectory(subdir, os.path.join(ldir, ""), recurse) def OnDownloadFiles(self, widget, prefix=""): dir = self.selected_folder for d, f in self.shares: # Find the wanted directory if d != dir: continue for file in f: # Find the wanted file if file[1] not in self.selected_files: continue path = "\\".join([dir, file[1]]) size = file[2] length = bitrate = None attrs = file[4] if attrs != []: bitrate = str(attrs[0]) if len(attrs) > 2 and attrs[2]: bitrate += " (vbr)" try: rl = int(attrs[1]) except ValueError: rl = 0 length = "%i:%02i" % (int(rl // 60), rl % 60) # Get the file self.frame.np.transfers.getFile(self.user, path, prefix, size=size, bitrate=bitrate, length=length) # We have found the wanted directory: we can break out of the loop break def OnDownloadFilesTo(self, widget): basedir, subdir = self.selected_folder.rsplit("\\", 1) path = os.path.join(self.frame.np.config.sections["transfers"]["downloaddir"], subdir) if os.path.exists(path) and os.path.isdir(path): ldir = ChooseDir(self.frame.MainWindow, path) else: ldir = ChooseDir(self.frame.MainWindow, self.frame.np.config.sections["transfers"]["downloaddir"]) if ldir is None: return try: self.OnDownloadFiles(widget, ldir[0]) except IOError: # failed to open self.frame.logMessage('failed to open %r for reading', ldir[0]) # notify user def OnUploadDirectoryTo(self, widget, recurse=0): dir = self.selected_folder if dir is None: return users = [] for entry in self.frame.np.config.sections["server"]["userlist"]: users.append(entry[0]) users.sort() user = input_box( self.frame, title=_("Nicotine+: Upload Directory's Contents"), message=_('Enter the User you wish to upload to:'), droplist=users ) if user is None or user == "": return self.frame.np.ProcessRequestToPeer(user, slskmessages.UploadQueueNotification(None)) self.UploadDirectoryTo(user, dir, recurse) def OnUploadDirectoryRecursiveTo(self, widget): self.OnUploadDirectoryTo(widget, recurse=1) def UploadDirectoryTo(self, user, dir, recurse=0): if dir == "" or dir is None or user is None or user == "": return ldir = dir.split("\\")[-1] for d, f in self.shares: # Find the wanted directory if d != dir: continue for file in f: path = "\\".join([dir, file[1]]) size = file[2] self.frame.np.transfers.pushFile(user, path, ldir, size=size) self.frame.np.transfers.checkUploadQueue() if not recurse: return for subdir, subf in self.shares: if dir in subdir and dir != subdir: self.UploadDirectoryTo(user, subdir, recurse) def OnUploadFiles(self, widget, prefix=""): dir = self.selected_folder users = [] for entry in self.frame.np.config.sections["server"]["userlist"]: users.append(entry[0]) users.sort() user = input_box( self.frame, title=_('Nicotine+: Upload File(s)'), message=_('Enter the User you wish to upload to:'), droplist=users ) if user is None or user == "": return self.frame.np.ProcessRequestToPeer(user, slskmessages.UploadQueueNotification(None)) for fn in self.selected_files: self.frame.np.transfers.pushFile(user, "\\".join([dir, fn]), prefix) self.frame.np.transfers.checkUploadQueue() def OnPlayFiles(self, widget, prefix=""): start_new_thread(self._OnPlayFiles, (widget, prefix)) def _OnPlayFiles(self, widget, prefix=""): path = self.frame.np.shares.virtual2real(self.selected_folder) executable = self.frame.np.config.sections["players"]["default"] if "$" not in executable: return for fn in self.selected_files: file = os.sep.join([path, fn]) if os.path.exists(file): executeCommand(executable, file, background=False) def FindMatches(self): self.search_list = [] for directory, files in self.shares: if self.query in directory.lower(): if directory not in self.search_list: self.search_list.append(directory) for file in files: if self.query in file[1].lower(): if directory not in self.search_list: self.search_list.append(directory) def OnSearch(self, widget): query = widget.get_text().lower() if self.query == query: self.search_position += 1 else: self.search_position = 0 self.query = query if self.query == "": return self.FindMatches() if self.search_list != []: if self.search_position not in list(range(len(self.search_list))): self.search_position = 0 self.search_list.sort() directory = self.search_list[self.search_position] path = self.DirStore.get_path(self.directories[directory]) self.FolderTreeView.expand_to_path(path) self.FolderTreeView.set_cursor(path) # Get matching files in the current directory resultfiles = [] for file in list(self.files.keys()): if query in file.lower(): resultfiles.append(file) sel = self.FileTreeView.get_selection() sel.unselect_all() l = 1 # noqa: E741 resultfiles.sort() for fn in resultfiles: path = self.FileStore.get_path(self.files[fn]) # Select each matching file in directory sel.select_path(path) if l: # Position cursor at first match self.FileTreeView.scroll_to_cell(path, None, True, 0.5, 0.5) l = 0 # noqa: E741 else: self.search_position = 0 def OnClose(self, widget): del self.userbrowses.users[self.user] self.frame.np.ClosePeerConnection(self.conn) if self.userbrowses.is_tab_detached(self.Main): self.Main.get_parent_window().destroy() else: self.userbrowses.remove_page(self.Main) self.Main.destroy() def OnRefresh(self, widget): self.FolderTreeView.set_sensitive(False) self.FileTreeView.set_sensitive(False) self.SaveButton.set_sensitive(False) self.frame.BrowseUser(self.user) def OnCopyURL(self, widget): if self.selected_files != [] and self.selected_files is not None: path = "\\".join([self.selected_folder, self.selected_files[0]]) self.frame.SetClipboardURL(self.user, path) def OnCopyDirURL(self, widget): if self.selected_folder is None: return path = self.selected_folder if path[:-1] != "/": path += "/" self.frame.SetClipboardURL(self.user, path) def OnFileManager(self, widget): if self.selected_folder is None: return path = self.frame.np.shares.virtual2real(self.selected_folder) executable = self.frame.np.config.sections["ui"]["filemanager"] if "$" in executable: executeCommand(executable, path)
class Search: def __init__(self, searches, text, id, mode, remember, showtab): self.searches = searches self.frame = searches.frame # Build the window load_ui_elements(self, os.path.join(self.frame.gui_dir, "ui", "search.ui")) self.text = text self.searchterm_words_include = [ p for p in text.lower().split() if not p.startswith('-') ] self.searchterm_words_ignore = [ p[1:] for p in text.lower().split() if p.startswith('-') and len(p) > 1 ] self.id = id self.mode = mode self.remember = remember self.showtab = showtab self.usersiters = {} self.directoryiters = {} self.users = set() self.all_data = [] self.filters = None self.clearing_filters = False self.resultslimit = 2000 self.numvisibleresults = 0 self.active_filter_count = 0 self.operators = { '<': operator.lt, '<=': operator.le, '==': operator.eq, '!=': operator.ne, '>=': operator.ge, '>': operator.gt } if mode not in ("global", "wishlist"): self.RememberCheckButton.set_sensitive(False) self.RememberCheckButton.set_active(remember) """ Columns """ self.ResultsList.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE) self.ResultsList.set_enable_tree_lines(True) self.ResultsList.set_headers_clickable(True) self.ResultsList.set_rubber_banding(True) self.resultsmodel = Gtk.TreeStore( GObject.TYPE_UINT64, # (0) num str, # (1) user GObject.TYPE_OBJECT, # (2) flag str, # (3) immediatedl str, # (4) h_speed str, # (5) h_queue str, # (6) directory str, # (7) filename str, # (8) h_size str, # (9) h_bitrate str, # (10) length GObject.TYPE_UINT64, # (11) bitrate str, # (12) fullpath str, # (13) country GObject.TYPE_UINT64, # (14) size GObject.TYPE_UINT64, # (15) speed GObject.TYPE_UINT64 # (16) queue ) self.cols = cols = initialise_columns( "file_search", self.ResultsList, ["id", _("ID"), 50, "text", self.cell_data_func, None], ["user", _("User"), 200, "text", self.cell_data_func, None], ["country", _("Country"), 25, "pixbuf", None, None], [ "immediate_download", _("Immediate Download"), 50, "center", self.cell_data_func, None ], ["speed", _("Speed"), 90, "number", self.cell_data_func, None], [ "in_queue", _("In Queue"), 90, "center", self.cell_data_func, None ], ["folder", _("Folder"), 400, "text", self.cell_data_func, None], [ "filename", _("Filename"), 400, "text", self.cell_data_func, None ], ["size", _("Size"), 100, "number", self.cell_data_func, None], [ "bitrate", _("Bitrate"), 100, "number", self.cell_data_func, None ], ["length", _("Length"), 0, "number", self.cell_data_func, None]) cols["id"].set_sort_column_id(0) cols["user"].set_sort_column_id(1) cols["country"].set_sort_column_id(13) cols["immediate_download"].set_sort_column_id(3) cols["speed"].set_sort_column_id(15) cols["in_queue"].set_sort_column_id(16) cols["folder"].set_sort_column_id(6) cols["filename"].set_sort_column_id(7) cols["size"].set_sort_column_id(14) cols["bitrate"].set_sort_column_id(11) cols["length"].set_sort_column_id(10) cols["country"].get_widget().hide() self.ResultsList.set_model(self.resultsmodel) self.update_visuals() """ Filters """ self.ShowFilters.set_active( self.frame.np.config.sections["searches"]["filters_visible"]) self.populate_filters() """ Popup """ self.popup_menu_users = PopupMenu(self.frame, False) self.popup_menu = popup = PopupMenu(self.frame) popup.setup( ("#" + _("_Download File(s)"), self.on_download_files), ("#" + _("Download File(s) _To..."), self.on_download_files_to), ("#" + _("Download _Folder(s)"), self.on_download_folders), ("#" + _("Download F_older(s) To..."), self.on_download_folders_to), ("#" + _("_Browse Folder"), self.on_browse_folder), ("#" + _("File _Properties"), self.on_file_properties), ("", None), ("#" + _("Copy _File Path"), self.on_copy_file_path), ("#" + _("Copy _URL"), self.on_copy_url), ("#" + _("Copy Folder U_RL"), self.on_copy_dir_url), ("", None), (1, _("User(s)"), self.popup_menu_users, self.on_popup_menu_users)) """ Grouping """ self.ResultGrouping.set_active( self.frame.np.config.sections["searches"]["group_searches"]) self.ExpandButton.set_active( self.frame.np.config.sections["searches"]["expand_searches"]) def on_tooltip(self, widget, x, y, keyboard_mode, tooltip): return show_country_tooltip(widget, x, y, tooltip, 13, stripprefix='') def populate_filters(self, set_default_filters=True): for combobox in (self.FilterIn, self.FilterOut, self.FilterSize, self.FilterBitrate, self.FilterCountry): combobox.remove_all() if set_default_filters and self.frame.np.config.sections["searches"][ "enablefilters"]: sfilter = self.frame.np.config.sections["searches"]["defilter"] self.FilterInEntry.set_text(sfilter[0]) self.FilterOutEntry.set_text(sfilter[1]) self.FilterSizeEntry.set_text(sfilter[2]) self.FilterBitrateEntry.set_text(sfilter[3]) self.FilterFreeSlot.set_active(sfilter[4]) if (len(sfilter) > 5): self.FilterCountryEntry.set_text(sfilter[5]) self.on_refilter(None) for i in ['0', '128', '160', '192', '256', '320']: self.FilterBitrate.append_text(i) for i in [">10MiB", "<10MiB", "<5MiB", "<1MiB", ">0"]: self.FilterSize.append_text(i) s_config = self.frame.np.config.sections["searches"] for i in s_config["filterin"]: self.add_combo(self.FilterIn, i, True) for i in s_config["filterout"]: self.add_combo(self.FilterOut, i, True) for i in s_config["filtersize"]: self.add_combo(self.FilterSize, i, True) for i in s_config["filterbr"]: self.add_combo(self.FilterBitrate, i, True) for i in s_config["filtercc"]: self.add_combo(self.FilterCountry, i, True) def focus_combobox(self, button): self.frame.focus_combobox(button) def add_combo(self, combobox, text, list=False): text = text.strip() if not text: return False model = combobox.get_model() iterator = model.get_iter_first() match = False while iterator is not None: value = model.get_value(iterator, 0) if value.strip() == text: match = True iterator = model.iter_next(iterator) if not match: if list: combobox.append_text(text) else: combobox.prepend_text(text) def add_user_results(self, msg, user, country): if user in self.users: return self.users.add(user) counter = len(self.all_data) + 1 inqueue = msg.inqueue ulspeed = msg.ulspeed h_speed = human_speed(ulspeed) if msg.freeulslots: imdl = "Y" inqueue = 0 else: imdl = "N" h_queue = humanize(inqueue) append = False maxstoredresults = self.searches.maxstoredresults for result in msg.list: if counter > maxstoredresults: break fullpath = result[1] fullpath_lower = fullpath.lower() if any(word in fullpath_lower for word in self.searchterm_words_ignore): """ Filter out results with filtered words (e.g. nicotine -music) """ log.add_search( _("Filtered out excluded search result " + fullpath + " from user " + user)) continue if not any(word in fullpath_lower for word in self.searchterm_words_include): """ Some users may send us wrong results, filter out such ones """ log.add_search( _("Filtered out inexact or incorrect search result " + fullpath + " from user " + user)) continue fullpath_split = reversed(fullpath.split('\\')) name = next(fullpath_split) directory = '\\'.join(fullpath_split) size = result[2] h_size = human_size(size) h_bitrate, bitrate, h_length = get_result_bitrate_length( size, result[4]) self.append([ counter, user, self.get_flag(user, country), imdl, h_speed, h_queue, directory, name, h_size, h_bitrate, h_length, bitrate, fullpath, country, size, ulspeed, inqueue ]) append = True counter += 1 if append: # If this search wasn't initiated by us (e.g. wishlist), and the results aren't spoofed, show tab if not self.showtab: self.searches.show_tab(self, self.id, self.text, self.mode) self.showtab = True # Update number of results self.update_result_counter() # Update tab notification self.frame.searches.request_changed(self.Main) self.frame.request_tab_icon(self.frame.SearchTabLabel) def get_flag(self, user, flag=None): if flag is not None: flag = "flag_" + flag.lower() self.frame.flag_users[user] = flag else: flag = self.frame.get_user_flag(user) return self.frame.get_flag_image(flag) def append(self, row): self.all_data.append(row) if self.numvisibleresults >= self.searches.maxdisplayedresults: return if not self.check_filter(row): return iterator = self.add_row_to_model(row) if self.ResultGrouping.get_active_id() != "ungrouped": # Group by folder or user if self.ExpandButton.get_active(): path = None if iterator is not None: path = self.resultsmodel.get_path(iterator) if path is not None: self.ResultsList.expand_to_path(path) else: collapse_treeview(self.ResultsList, self.ResultGrouping.get_active_id()) def add_row_to_model(self, row): counter, user, flag, immediatedl, h_speed, h_queue, directory, filename, h_size, h_bitrate, length, bitrate, fullpath, country, size, speed, queue = row if self.ResultGrouping.get_active_id() != "ungrouped": # Group by folder or user if user not in self.usersiters: self.usersiters[user] = self.resultsmodel.append( None, [ 0, user, self.get_flag( user, country), immediatedl, h_speed, h_queue, "", "", "", "", "", 0, "", country, 0, speed, queue ]) parent = self.usersiters[user] if self.ResultGrouping.get_active_id() == "folder_grouping": # Group by folder if directory not in self.directoryiters: self.directoryiters[directory] = self.resultsmodel.append( self.usersiters[user], [ 0, user, self.get_flag(user, country), immediatedl, h_speed, h_queue, directory, "", "", "", "", 0, fullpath.rsplit('\\', 1)[0] + '\\', country, 0, speed, queue ]) row = row[:] row[6] = "" # Directory not visible for file row if "group by folder" is enabled parent = self.directoryiters[directory] else: parent = None try: iterator = self.resultsmodel.append(parent, row) self.numvisibleresults += 1 except Exception as e: types = [] for i in row: types.append(type(i)) log.add_warning(_("Search row error: %(exception)s %(row)s"), { 'exception': e, 'row': row }) iterator = None return iterator def check_digit(self, sfilter, value, factorize=True): op = ">=" if sfilter[:1] in (">", "<", "="): op, sfilter = sfilter[:1] + "=", sfilter[1:] if not sfilter: return True factor = 1 if factorize: base = 1024 # Default to binary for "k", "m", "g" suffixes if sfilter[-1:].lower() == 'b': base = 1000 # Byte suffix detected, prepare to use decimal if necessary sfilter = sfilter[:-1] if sfilter[-1:].lower() == 'i': base = 1024 # Binary requested, stop using decimal sfilter = sfilter[:-1] if sfilter.lower()[-1:] == "g": factor = pow(base, 3) sfilter = sfilter[:-1] elif sfilter.lower()[-1:] == "m": factor = pow(base, 2) sfilter = sfilter[:-1] elif sfilter.lower()[-1:] == "k": factor = base sfilter = sfilter[:-1] if not sfilter: return True try: sfilter = int(sfilter) * factor except ValueError: return True operation = self.operators.get(op) return operation(value, sfilter) def check_filter(self, row): filters = self.filters if self.active_filter_count == 0: return True # "Included text"-filter, check full file path (located at index 12 in row) if filters[0] and not filters[0].search(row[12].lower()): return False # "Excluded text"-filter, check full file path (located at index 12 in row) if filters[1] and filters[1].search(row[12].lower()): return False if filters[2] and not self.check_digit(filters[2], row[14]): return False if filters[3] and not self.check_digit(filters[3], row[11], False): return False if filters[4] and row[3] != "Y": return False if filters[5]: for cc in filters[5]: if not cc: continue if row[13] is None: return False if cc[0] == "-": if row[13].upper() == cc[1:].upper(): return False elif cc.upper() != row[13].upper(): return False return True def set_filters(self, enable, f_in, f_out, size, bitrate, freeslot, country): self.filters = [None, None, None, None, freeslot, None] self.active_filter_count = 0 if f_in: try: f_in = re.compile(f_in.lower()) self.filters[0] = f_in except sre_constants.error: set_widget_fg_bg_css(self.FilterInEntry, "red", "white") else: set_widget_fg_bg_css(self.FilterInEntry) self.active_filter_count += 1 if f_out: try: f_out = re.compile(f_out.lower()) self.filters[1] = f_out except sre_constants.error: set_widget_fg_bg_css(self.FilterOutEntry, "red", "white") else: set_widget_fg_bg_css(self.FilterOutEntry) self.active_filter_count += 1 if size: self.filters[2] = size self.active_filter_count += 1 if bitrate: self.filters[3] = bitrate self.active_filter_count += 1 if country: self.filters[5] = country.upper().split(" ") self.active_filter_count += 1 if freeslot: self.active_filter_count += 1 self.usersiters.clear() self.directoryiters.clear() self.resultsmodel.clear() self.numvisibleresults = 0 for row in self.all_data: if self.numvisibleresults >= self.searches.maxdisplayedresults: break if self.check_filter(row): self.add_row_to_model(row) # Update number of visible results self.update_result_counter() self.update_filter_counter(self.active_filter_count) def on_popup_menu_users(self, widget): self.select_results() self.popup_menu_users.clear() if len(self.selected_users) > 0: items = [] for user in self.selected_users: popup = PopupMenu(self.frame, False) popup.setup_user_menu(user) popup.append_item(("", None)) popup.append_item(("#" + _("Select User's Transfers"), self.on_select_user_results)) items.append((1, user, popup, self.on_popup_menu_user, popup)) self.popup_menu_users.setup(*items) return True def on_popup_menu_user(self, widget, popup=None): if popup is None: return popup.toggle_user_items() return True def on_select_user_results(self, widget): if len(self.selected_users) == 0: return selected_user = widget.get_parent().user sel = self.ResultsList.get_selection() fmodel = self.ResultsList.get_model() sel.unselect_all() iterator = fmodel.get_iter_first() select_user_row_iter(fmodel, sel, 1, selected_user, iterator) self.select_results() def select_results(self): self.selected_results = set() self.selected_users = set() self.ResultsList.get_selection().selected_foreach( self.selected_results_callback) def update_result_counter(self): self.Counter.set_markup("<b>%d</b>" % self.numvisibleresults) def update_visuals(self): for widget in self.__dict__.values(): update_widget_visuals(widget, list_font_target="searchfont") def save_columns(self): save_columns("file_search", self.ResultsList.get_columns()) def selected_results_callback(self, model, path, iterator): user = model.get_value(iterator, 1) if user is None: return self.selected_users.add(user) filepath = model.get_value(iterator, 12) if filepath == "": # Result is not a file or directory, don't add it return bitrate = model.get_value(iterator, 9) length = model.get_value(iterator, 10) size = model.get_value(iterator, 14) self.selected_results.add((user, filepath, size, bitrate, length)) def on_list_clicked(self, widget, event): if triggers_context_menu(event): set_treeview_selected_row(widget, event) return self.on_popup_menu(widget) pathinfo = widget.get_path_at_pos(event.x, event.y) if pathinfo is None: widget.get_selection().unselect_all() elif event.button == 1 and event.type == Gdk.EventType._2BUTTON_PRESS: self.select_results() self.on_download_files(widget) self.ResultsList.get_selection().unselect_all() return True return False def on_key_press_event(self, widget, event): key = Gdk.keyval_name(event.keyval) self.select_results() if key in ("C", "c") and event.state in ( Gdk.ModifierType.CONTROL_MASK, Gdk.ModifierType.LOCK_MASK | Gdk.ModifierType.CONTROL_MASK): self.on_copy_file_path(widget) else: # No key match, continue event return False widget.stop_emission_by_name("key_press_event") return True def on_popup_menu(self, widget): self.select_results() items = self.popup_menu.get_items() users = len(self.selected_users) > 0 files = len(self.selected_results) > 0 for i in (_("_Download File(s)"), _("Download File(s) _To..."), _("File _Properties"), _("Copy _URL")): items[i].set_sensitive(False) for i in (_("Download _Folder(s)"), _("Download F_older(s) To..."), _("_Browse Folder"), _("Copy _File Path"), _("Copy Folder U_RL")): items[i].set_sensitive(files) items[_("User(s)")].set_sensitive(users) for result in self.selected_results: if not result[1].endswith('\\'): # At least one selected result is a file, activate file-related items for i in (_("_Download File(s)"), _("Download File(s) _To..."), _("File _Properties"), _("Copy _URL")): items[i].set_sensitive(True) break self.popup_menu.popup() return True def cell_data_func(self, column, cellrenderer, model, iterator, dummy="dummy"): imdl = model.get_value(iterator, 3) color_id = imdl == "Y" and "search" or "searchq" color = self.frame.np.config.sections["ui"][color_id] if color: cellrenderer.set_property("foreground", color) else: cellrenderer.set_property("foreground-set", False) def on_browse_folder(self, widget): requested_folders = set() for file in self.selected_results: user = file[0] folder = file[1].rsplit('\\', 1)[0] if folder not in requested_folders: self.frame.browse_user(user, folder) requested_folders.add(folder) def selected_results_all_data(self, model, path, iterator, data): filename = model.get_value(iterator, 7) # We only want to see the metadata of files, not directories if filename != "": num = model.get_value(iterator, 0) user = model.get_value(iterator, 1) immediate = model.get_value(iterator, 3) speed = model.get_value(iterator, 4) queue = model.get_value(iterator, 5) size = model.get_value(iterator, 8) bitratestr = model.get_value(iterator, 9) length = model.get_value(iterator, 10) fn = model.get_value(iterator, 12) directory = fn.rsplit('\\', 1)[0] cc = model.get_value(iterator, 13) country = "%s / %s" % (cc, code2name(cc)) data.append({ "user": user, "fn": fn, "position": num, "filename": filename, "directory": directory, "size": size, "speed": speed, "queue": queue, "immediate": immediate, "bitrate": bitratestr, "length": length, "country": country }) def on_file_properties(self, widget): if not self.frame.np.transfers: return data = [] self.ResultsList.get_selection().selected_foreach( self.selected_results_all_data, data) if data: FileProperties(self.frame, data).show() def on_download_files(self, widget, prefix=""): if not self.frame.np.transfers: return for file in self.selected_results: # Make sure the selected result is not a directory if not file[1].endswith('\\'): self.frame.np.transfers.get_file(file[0], file[1], prefix, size=file[2], bitrate=file[3], length=file[4], checkduplicate=True) def on_download_files_to(self, widget): folder = choose_dir( self.frame.MainWindow, self.frame.np.config.sections["transfers"]["downloaddir"], multichoice=False) if folder is None: return for folders in folder: self.on_download_files(widget, folders) break def on_download_folders(self, widget): requested_folders = {} for i in self.selected_results: user = i[0] folder = i[1].rsplit('\\', 1)[0] if user not in requested_folders: requested_folders[user] = [] if folder not in requested_folders[user]: """ Ensure we don't send folder content requests for a folder more than once, e.g. when several selected resuls belong to the same folder. """ self.frame.np.send_message_to_peer( user, slskmessages.FolderContentsRequest(None, folder)) requested_folders[user].append(folder) def on_download_folders_to(self, widget): directories = choose_dir( self.frame.MainWindow, self.frame.np.config.sections["transfers"]["downloaddir"], multichoice=False) if directories is None or directories == []: return destination = directories[0] for i in self.selected_results: user = i[0] folder = i[1].rsplit('\\', 1)[0] if user not in self.frame.np.requested_folders: self.frame.np.requested_folders[user] = {} if folder not in self.frame.np.requested_folders[user]: """ Ensure we don't send folder content requests for a folder more than once, e.g. when several selected resuls belong to the same folder. """ self.frame.np.requested_folders[user][folder] = destination self.frame.np.send_message_to_peer( user, slskmessages.FolderContentsRequest(None, folder)) def on_copy_file_path(self, widget): if not self.selected_results: return user, path = next(iter(self.selected_results))[:2] self.frame.clip.set_text(path, -1) def on_copy_url(self, widget): user, path = next(iter(self.selected_results))[:2] self.frame.set_clipboard_url(user, path) def on_copy_dir_url(self, widget): user, path = next(iter(self.selected_results))[:2] path = "\\".join(path.split("\\")[:-1]) if path[:-1] != "/": path += "/" self.frame.set_clipboard_url(user, path) def on_group(self, widget): self.on_refilter(widget) self.ResultsList.set_show_expanders(widget.get_active()) self.frame.np.config.sections["searches"][ "group_searches"] = widget.get_active() if widget.get_active(): self.cols["id"].set_visible(False) self.ExpandButton.show() else: self.cols["id"].set_visible(True) self.ExpandButton.hide() def on_toggle_expand_all(self, widget): active = self.ExpandButton.get_active() if active: self.ResultsList.expand_all() self.expand.set_from_icon_name("go-up-symbolic", Gtk.IconSize.BUTTON) else: collapse_treeview(self.ResultsList, self.ResultGrouping.get_active_id()) self.expand.set_from_icon_name("go-down-symbolic", Gtk.IconSize.BUTTON) self.frame.np.config.sections["searches"]["expand_searches"] = active def on_toggle_filters(self, widget): visible = widget.get_active() self.FiltersContainer.set_visible(visible) self.frame.np.config.sections["searches"]["filters_visible"] = visible def on_clear(self, widget): self.all_data = [] self.usersiters.clear() self.directoryiters.clear() self.resultsmodel.clear() self.numvisibleresults = 0 # Update number of visible results self.update_result_counter() def on_close(self, widget): self.searches.remove_tab(self) def on_copy_search_term(self, widget): self.frame.clip.set_text(self.text, -1) def on_toggle_remember(self, widget): self.remember = widget.get_active() search = self.searches.searches[self.id] if not self.remember: self.searches.wish_list.remove_wish(search["term"]) else: self.searches.wish_list.add_wish(search["term"]) def push_history(self, widget, title): text = widget.get_child().get_text() if not text.strip(): return None text = text.strip() history = self.frame.np.config.sections["searches"][title] if text in history: history.remove(text) elif len(history) >= 5: del history[-1] history.insert(0, text) self.frame.np.config.write_configuration() self.add_combo(widget, text) widget.get_child().set_text(text) return text def on_refilter(self, widget, *args): if self.clearing_filters: return f_in = self.push_history(self.FilterIn, "filterin") f_out = self.push_history(self.FilterOut, "filterout") f_size = self.push_history(self.FilterSize, "filtersize") f_br = self.push_history(self.FilterBitrate, "filterbr") f_free = self.FilterFreeSlot.get_active() f_country = self.push_history(self.FilterCountry, "filtercc") self.ResultsList.set_model(None) self.set_filters(1, f_in, f_out, f_size, f_br, f_free, f_country) self.ResultsList.set_model(self.resultsmodel) if self.ResultGrouping.get_active_id() != "ungrouped": # Group by folder or user if self.ExpandButton.get_active(): self.ResultsList.expand_all() else: collapse_treeview(self.ResultsList, self.ResultGrouping.get_active_id()) def on_clear_filters(self, widget): self.clearing_filters = True self.FilterInEntry.set_text("") self.FilterOutEntry.set_text("") self.FilterSizeEntry.set_text("") self.FilterBitrateEntry.set_text("") self.FilterCountryEntry.set_text("") self.FilterFreeSlot.set_active(False) self.clearing_filters = False self.FilterInEntry.grab_focus() self.on_refilter(widget) def on_about_filters(self, widget): if not hasattr(self, "AboutSearchFiltersPopover"): load_ui_elements( self, os.path.join(self.frame.gui_dir, "ui", "popovers", "searchfilters.ui")) self.AboutSearchFiltersPopover.set_relative_to(self.ShowChatHelp) self.AboutSearchFiltersPopover.popup() def update_filter_counter(self, count): if count > 0: self.FilterLabel.set_text(_("Result Filters") + " *") else: self.FilterLabel.set_text(_("Result Filters")) self.FilterLabel.set_tooltip_text("%d active filter(s)" % count)
class UserBrowse: def __init__(self, userbrowses, user, conn): # Build the window builder = Gtk.Builder() builder.set_translation_domain('nicotine') builder.add_from_file(os.path.join(os.path.dirname(os.path.realpath(__file__)), "ui", "userbrowse.ui")) self.user_browse_tab = builder.get_object("UserBrowseTab") for i in builder.get_objects(): try: self.__dict__[Gtk.Buildable.get_name(i)] = i except TypeError: pass self.user_browse_tab.remove(self.Main) self.user_browse_tab.destroy() builder.connect_signals(self) self.userbrowses = userbrowses self.frame = userbrowses.frame self.user = user self.conn = conn # selected_folder is the current selected folder self.selected_folder = None self.search_list = [] self.query = None self.search_position = 0 self.selected_files = [] self.shares = [] # Iters for current DirStore self.directories = {} # Iters for current FileStore self.files = {} self.totalsize = 0 self.dir_store = Gtk.TreeStore(str, str) self.FolderTreeView.set_headers_visible(True) self.FolderTreeView.set_enable_tree_lines(True) cols = initialise_columns( self.FolderTreeView, [_("Directories"), -1, "text", self.cell_data_func] # 0 ) cols[0].set_sort_column_id(0) self.popup_menu_users = PopupMenu(self.frame, False) self.popup_menu_users2 = PopupMenu(self.frame, False) for menu in [self.popup_menu_users, self.popup_menu_users2]: menu.setup( ("#" + _("Send _message"), menu.on_send_message), ("#" + _("Show IP a_ddress"), menu.on_show_ip_address), ("#" + _("Get user i_nfo"), menu.on_get_user_info), ("#" + _("Gi_ve privileges"), menu.on_give_privileges), ("", None), ("$" + _("_Add user to list"), menu.on_add_to_list), ("$" + _("_Ban this user"), menu.on_ban_user), ("$" + _("_Ignore this user"), menu.on_ignore_user) ) self.popup_menu_downloads_folders = PopupMenu(self.frame, False) self.popup_menu_downloads_folders.setup( ("#" + _("_Download directory"), self.on_download_directory), ("#" + _("Download directory _to..."), self.on_download_directory_to), ("#" + _("Download _recursive"), self.on_download_directory_recursive), ("#" + _("Download r_ecursive to..."), self.on_download_directory_recursive_to) ) self.popup_menu_downloads_files = PopupMenu(self.frame, False) self.popup_menu_downloads_files.setup( ("#" + _("_Download file(s)"), self.on_download_files), ("#" + _("Download _to..."), self.on_download_files_to), ("", None), ("#" + _("_Download directory"), self.on_download_directory), ("#" + _("Download directory _to..."), self.on_download_directory_to), ("#" + _("Download _recursive"), self.on_download_directory_recursive), ("#" + _("Download r_ecursive to..."), self.on_download_directory_recursive_to) ) self.popup_menu_uploads_folders = PopupMenu(self.frame, False) self.popup_menu_uploads_folders.setup( ("#" + _("Upload Directory to..."), self.on_upload_directory_to), ("#" + _("Upload Directory recursive to..."), self.on_upload_directory_recursive_to) ) self.popup_menu_uploads_files = PopupMenu(self.frame, False) self.popup_menu_uploads_files.setup( ("#" + _("Upload Directory to..."), self.on_upload_directory_to), ("#" + _("Upload Directory recursive to..."), self.on_upload_directory_recursive_to), ("#" + _("Up_load file(s)"), self.on_upload_files) ) self.folder_popup_menu = PopupMenu(self.frame) self.folder_popup_menu.set_user(user) if user == self.frame.np.config.sections["server"]["login"]: self.folder_popup_menu.setup( ("USERMENU", _("User"), self.popup_menu_users, self.on_popup_menu_folder_user), ("", None), (1, _("Download"), self.popup_menu_downloads_folders, None), (1, _("Upload"), self.popup_menu_uploads_folders, None), ("", None), ("#" + _("Copy _URL"), self.on_copy_dir_url), ("#" + _("Open in File Manager"), self.on_file_manager) ) else: self.folder_popup_menu.setup( ("USERMENU", _("User"), self.popup_menu_users, self.on_popup_menu_folder_user), ("", None), (1, _("Download"), self.popup_menu_downloads_folders, None), ("", None), ("#" + _("Copy _URL"), self.on_copy_dir_url) ) self.FolderTreeView.connect("button_press_event", self.on_folder_clicked) self.FolderTreeView.get_selection().connect("changed", self.on_select_dir) # Filename, HSize, Bitrate, HLength, Size, Length, RawFilename self.file_store = Gtk.ListStore(str, str, str, str, GObject.TYPE_INT64, int, str) self.FileTreeView.set_model(self.file_store) widths = self.frame.np.config.sections["columns"]["userbrowse_widths"] cols = initialise_columns( self.FileTreeView, [_("Filename"), widths[0], "text", self.cell_data_func], [_("Size"), widths[1], "number", self.cell_data_func], [_("Bitrate"), widths[2], "number", self.cell_data_func], [_("Length"), widths[3], "number", self.cell_data_func] ) cols[0].set_sort_column_id(0) cols[1].set_sort_column_id(4) cols[2].set_sort_column_id(2) cols[3].set_sort_column_id(5) self.file_store.set_sort_column_id(0, Gtk.SortType.ASCENDING) hide_columns(cols, self.frame.np.config.sections["columns"]["userbrowse"]) self.FileTreeView.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE) self.FileTreeView.set_headers_clickable(True) self.FileTreeView.set_rubber_banding(True) self.file_popup_menu = PopupMenu(self.frame) if user == self.frame.np.config.sections["server"]["login"]: self.file_popup_menu.setup( ("USERMENU", "User", self.popup_menu_users2, self.on_popup_menu_file_user), ("", None), (1, _("Download"), self.popup_menu_downloads_files, None), (1, _("Upload"), self.popup_menu_uploads_files, None), ("", None), ("#" + _("Copy _URL"), self.on_copy_url), ("#" + _("Send to _player"), self.on_play_files), ("#" + _("Open in File Manager"), self.on_file_manager) ) else: self.file_popup_menu.setup( ("USERMENU", "User", self.popup_menu_users2, self.on_popup_menu_file_user), ("", None), (1, _("Download"), self.popup_menu_downloads_files, None), ("", None), ("#" + _("Copy _URL"), self.on_copy_url) ) self.FileTreeView.connect("button_press_event", self.on_file_clicked) self.change_colours() for name, object in list(self.__dict__.items()): if isinstance(object, PopupMenu): object.set_user(self.user) def on_popup_menu_file_user(self, widget): self.on_popup_menu_users(self.popup_menu_users2) def on_popup_menu_folder_user(self, widget): self.on_popup_menu_users(self.popup_menu_users) def on_popup_menu_users(self, menu): items = menu.get_children() act = True items[0].set_sensitive(act) items[1].set_sensitive(act) items[2].set_sensitive(act) items[5].set_active(self.user in [i[0] for i in self.frame.np.config.sections["server"]["userlist"]]) items[6].set_active(self.user in self.frame.np.config.sections["server"]["banlist"]) items[7].set_active(self.user in self.frame.np.config.sections["server"]["ignorelist"]) for i in range(3, 8): items[i].set_sensitive(act) return True def change_colours(self): self.frame.set_text_bg(self.SearchEntry) self.frame.change_list_font(self.FolderTreeView, self.frame.np.config.sections["ui"]["browserfont"]) self.frame.change_list_font(self.FileTreeView, self.frame.np.config.sections["ui"]["browserfont"]) def cell_data_func(self, column, cellrenderer, model, iterator, dummy="dummy"): colour = self.frame.np.config.sections["ui"]["search"] if colour == "": colour = None cellrenderer.set_property("foreground", colour) def on_expand(self, widget): if self.ExpandButton.get_active(): self.FolderTreeView.expand_all() self.expand.set_from_icon_name("list-remove-symbolic", Gtk.IconSize.BUTTON) else: self.FolderTreeView.collapse_all() self.expand.set_from_icon_name("list-add-symbolic", Gtk.IconSize.BUTTON) dirs = sorted(self.directories.keys()) if dirs != []: self.set_directory(dirs[0]) else: self.set_directory(None) def on_folder_clicked(self, widget, event): pathinfo = widget.get_path_at_pos(event.x, event.y) if pathinfo is not None: if event.button == 1 and event.type == Gdk.EventType._2BUTTON_PRESS: self.on_download_directory(widget) return True elif event.button == 3: return self.on_folder_popup_menu(widget, event) return False def on_folder_popup_menu(self, widget, event): act = True if self.selected_folder is None: act = False items = self.folder_popup_menu.get_children() for item in items[1:]: item.set_sensitive(act) self.folder_popup_menu.popup(None, None, None, None, event.button, event.time) def selected_files_callback(self, model, path, iterator): rawfilename = self.file_store.get_value(iterator, 6) self.selected_files.append(rawfilename) def on_file_clicked(self, widget, event): if event.button == 3: return self.on_file_popup_menu(widget, event) else: pathinfo = widget.get_path_at_pos(event.x, event.y) if pathinfo is None: widget.get_selection().unselect_all() elif event.button == 1 and event.type == Gdk.EventType._2BUTTON_PRESS: self.selected_files = [] self.FileTreeView.get_selection().selected_foreach(self.selected_files_callback) self.on_download_files(widget) self.FileTreeView.get_selection().unselect_all() return True return False def on_file_popup_menu(self, widget, event): set_treeview_selected_row(widget, event) self.selected_files = [] self.FileTreeView.get_selection().selected_foreach(self.selected_files_callback) files = True multiple = False if len(self.selected_files) > 1: multiple = True if len(self.selected_files) >= 1: files = True else: files = False items = self.file_popup_menu.get_children() if self.user == self.frame.np.config.sections["server"]["login"]: items[2].set_sensitive(files) # Downloads items[3].set_sensitive(files) # Uploads items[5].set_sensitive(not multiple and files) # Copy URL items[6].set_sensitive(files) # Send to player else: items[2].set_sensitive(files) # Downloads items[4].set_sensitive(not multiple and files) # Copy URL self.FileTreeView.stop_emission_by_name("button_press_event") self.file_popup_menu.popup(None, None, None, None, event.button, event.time) return True def make_new_model(self, list): self.shares = list self.selected_folder = None self.selected_files = [] self.directories.clear() self.files.clear() self.dir_store.clear() # Compute the number of shared dirs and total size self.totalsize = 0 for dir, files in self.shares: for filedata in files: if filedata[2] < maxsize: self.totalsize += filedata[2] self.AmountShared.set_text(_("Shared: %s") % human_size(self.totalsize)) self.NumDirectories.set_text(_("Dirs: %s") % len(self.shares)) # Generate the directory tree and select first directory currentdir = self.browse_get_dirs() sel = self.FolderTreeView.get_selection() sel.unselect_all() if currentdir in self.directories: path = self.dir_store.get_path(self.directories[currentdir]) if path is not None: sel.select_path(path) self.FolderTreeView.set_sensitive(True) self.FileTreeView.set_sensitive(True) self.SaveButton.set_sensitive(True) if self.ExpandButton.get_active(): self.FolderTreeView.expand_all() else: self.FolderTreeView.collapse_all() def browse_get_dirs(self): directory = "" dirseparator = '\\' # If there is no share if self.shares == []: # Set the model of the treeviex self.FolderTreeView.set_model(self.dir_store) # Sort the DirStore self.dir_store.set_sort_column_id(0, Gtk.SortType.ASCENDING) return directory def builddicttree(p, s): """ Build recursively a hierarchical dict containing raw subdir 'p' is a reference to the parent 's' a list of the subdir of a path ex of 's': ['music', 'rock', 'doors'] """ if s: subdir = s.pop(0) if subdir not in p: p[subdir] = {} builddicttree(p[subdir], s) def buildgtktree(dictdir, parent, path): """ Build recursively self.directories with iters pointing to directories 'dictdir' is a hierarchical dict containing raw subdir 'parent' is the iter pointing to the parent 'path' is the current raw path """ # Foreach subdir for subdir in dictdir: if parent is None: # The first sudirs are attached to the root (None) current_path = subdir else: # Other sudirs futher down the path are attached to their parent current_path = dirseparator.join([path, subdir]) self.directories[current_path] = self.dir_store.append(parent, [subdir, current_path]) # If there are subdirs futher down the path: recurse if len(dictdir[subdir]): buildgtktree(dictdir[subdir], self.directories[current_path], current_path) # For each shared dir we will complete the dictionnary dictdir = {} for dirshares, f in self.shares: # Split the path s = dirshares.split(dirseparator) # and build a hierarchical dictionnary containing raw subdir if len(s) >= 1: builddicttree(dictdir, s) # Append data to the DirStore buildgtktree(dictdir, None, None) # Select the first directory sortlist = sorted(self.directories.keys()) directory = sortlist[0] # Sort the DirStore self.dir_store.set_sort_column_id(0, Gtk.SortType.ASCENDING) # Set the model of the treeviex self.FolderTreeView.set_model(self.dir_store) return directory def set_directory(self, directory): self.selected_folder = directory self.file_store.clear() self.files.clear() found_dir = False for d, f in self.shares: if d == directory: found_dir = True files = f break if not found_dir: return for file in files: # Filename, HSize, Bitrate, HLength, Size, Length, RawFilename rl = 0 try: size = int(file[2]) # Some clients send incorrect file sizes if size < 0 or size > maxsize: size = 0 except ValueError: size = 0 f = [file[1], human_size(size)] h_bitrate, bitrate, h_length = get_result_bitrate_length(size, file[4]) f += [h_bitrate, h_length] f += [int(size), rl, file[1]] try: self.files[f[0]] = self.file_store.append(f) except Exception as msg: log.add(_("Error while attempting to display folder '%(folder)s', reported error: %(error)s"), {'folder': directory, 'error': msg}) def on_save(self, widget): sharesdir = os.path.join(self.frame.data_dir, "usershares") try: if not os.path.exists(sharesdir): os.mkdir(sharesdir) except Exception as msg: log.add(_("Can't create directory '%(folder)s', reported error: %(error)s"), {'folder': sharesdir, 'error': msg}) try: import pickle as mypickle import bz2 sharesfile = bz2.BZ2File(os.path.join(sharesdir, clean_file(self.user)), 'w') mypickle.dump(self.shares, sharesfile, protocol=mypickle.HIGHEST_PROTOCOL) sharesfile.close() log.add(_("Saved list of shared files for user '%(user)s' to %(dir)s"), {'user': self.user, 'dir': sharesdir}) except Exception as msg: log.add(_("Can't save shares, '%(user)s', reported error: %(error)s"), {'user': self.user, 'error': msg}) def save_columns(self): columns = [] widths = [] for column in self.FileTreeView.get_columns(): columns.append(column.get_visible()) widths.append(column.get_width()) self.frame.np.config.sections["columns"]["userbrowse"] = columns self.frame.np.config.sections["columns"]["userbrowse_widths"] = widths def show_info(self, msg): self.conn = None self.make_new_model(msg.list) def load_shares(self, list): self.make_new_model(list) def update_gauge(self, msg): if msg.total == 0 or msg.bytes == 0: fraction = 0.0 elif msg.bytes >= msg.total: fraction = 1.0 else: fraction = float(msg.bytes) / msg.total self.progressbar1.set_fraction(fraction) def on_select_dir(self, selection): model, iterator = selection.get_selected() if iterator is None: self.selected_folder = None return path = model.get_path(iterator) directory = model.get_value(iterator, 1) self.FolderTreeView.expand_to_path(path) self.set_directory(directory) def on_resort(self, column, column_id): model = self.FileTreeView.get_model() if model.sort_col == column_id: order = model.sort_order if order == Gtk.SortType.ASCENDING: order = Gtk.SortType.DESCENDING else: order = Gtk.SortType.ASCENDING column.set_sort_order(order) model.sort_order = order self.FileTreeView.set_model(None) model.sort() self.FileTreeView.set_model(model) return cols = self.FileTreeView.get_columns() cols[model.sort_col].set_sort_indicator(False) cols[column_id].set_sort_indicator(True) model.sort_col = column_id self.on_resort(column, column_id) def on_download_directory(self, widget): if self.selected_folder is not None: self.download_directory(self.selected_folder) def on_download_directory_recursive(self, widget): self.download_directory(self.selected_folder, "", 1) def on_download_directory_to(self, widget): folder = choose_dir(self.frame.MainWindow, self.frame.np.config.sections["transfers"]["downloaddir"], multichoice=False) if folder is None: return try: self.download_directory(self.selected_folder, os.path.join(folder[0], "")) except IOError: # failed to open log.add('Failed to open %r for reading', folder[0]) # notify user def on_download_directory_recursive_to(self, widget): folder = choose_dir(self.frame.MainWindow, self.frame.np.config.sections["transfers"]["downloaddir"], multichoice=False) if folder is None: return try: self.download_directory(self.selected_folder, os.path.join(folder[0], ""), 1) except IOError: # failed to open log.add('Failed to open %r for reading', folder[0]) # notify user def download_directory(self, folder, prefix="", recurse=0): if folder is None: return ldir = prefix + folder.split("\\")[-1] # Check if folder already exists on system ldir = self.frame.np.transfers.folder_destination(self.user, ldir) for d, f in self.shares: # Find the wanted directory if d != folder: continue priorityfiles = [] normalfiles = [] if self.frame.np.config.sections["transfers"]["prioritize"]: for file in f: parts = file[1].rsplit('.', 1) if len(parts) == 2 and parts[1] in ['sfv', 'md5', 'nfo']: priorityfiles.append(file) else: normalfiles.append(file) else: normalfiles = f if self.frame.np.config.sections["transfers"]["reverseorder"]: deco = [(x[1], x) for x in normalfiles] deco.sort(reverse=True) normalfiles = [x for junk, x in deco] for file in priorityfiles + normalfiles: path = "\\".join([folder, file[1]]) size = file[2] h_bitrate, bitrate, h_length = get_result_bitrate_length(size, file[4]) self.frame.np.transfers.get_file( self.user, path, ldir, size=size, bitrate=h_bitrate, length=h_length, checkduplicate=True ) if not recurse: return for subdir, subf in self.shares: if dir in subdir and dir != subdir: self.download_directory(subdir, os.path.join(ldir, "")) def on_download_files(self, widget, prefix=""): folder = self.selected_folder for d, f in self.shares: # Find the wanted directory if d != folder: continue for file in f: # Find the wanted file if file[1] not in self.selected_files: continue path = "\\".join([folder, file[1]]) size = file[2] h_bitrate, bitrate, h_length = get_result_bitrate_length(size, file[4]) # Get the file self.frame.np.transfers.get_file(self.user, path, prefix, size=size, bitrate=h_bitrate, length=h_length, checkduplicate=True) # We have found the wanted directory: we can break out of the loop break def on_download_files_to(self, widget): try: _, folder = self.selected_folder.rsplit("\\", 1) except ValueError: folder = self.selected_folder path = os.path.join(self.frame.np.config.sections["transfers"]["downloaddir"], folder) if os.path.exists(path) and os.path.isdir(path): ldir = choose_dir(self.frame.MainWindow, path, multichoice=False) else: ldir = choose_dir(self.frame.MainWindow, self.frame.np.config.sections["transfers"]["downloaddir"], multichoice=False) if ldir is None: return try: self.on_download_files(widget, ldir[0]) except IOError: # failed to open log.add('failed to open %r for reading', ldir[0]) # notify user def on_upload_directory_to(self, widget, recurse=0): folder = self.selected_folder if folder is None: return users = [] for entry in self.frame.np.config.sections["server"]["userlist"]: users.append(entry[0]) users.sort() user = combo_box_dialog( parent=self.frame.MainWindow, title=_("Upload Directory's Contents"), message=_('Enter the User you wish to upload to:'), droplist=users ) if user is None or user == "": return self.frame.np.process_request_to_peer(user, slskmessages.UploadQueueNotification(None)) self.upload_directory_to(user, folder, recurse) def on_upload_directory_recursive_to(self, widget): self.on_upload_directory_to(widget, recurse=1) def upload_directory_to(self, user, folder, recurse=0): if folder == "" or folder is None or user is None or user == "": return realpath = self.frame.np.shares.virtual2real(folder) ldir = folder.split("\\")[-1] for d, f in self.shares: # Find the wanted directory if d != folder: continue for file in f: filename = "\\".join([folder, file[1]]) realfilename = "\\".join([realpath, file[1]]) size = file[2] self.frame.np.transfers.push_file(user, filename, realfilename, ldir, size=size) self.frame.np.transfers.check_upload_queue() if not recurse: return for subdir, subf in self.shares: if folder in subdir and folder != subdir: self.upload_directory_to(user, subdir, recurse) def on_upload_files(self, widget, prefix=""): folder = self.selected_folder realpath = self.frame.np.shares.virtual2real(folder) users = [] for entry in self.frame.np.config.sections["server"]["userlist"]: users.append(entry[0]) users.sort() user = combo_box_dialog( parent=self.frame.MainWindow, title=_('Upload File(s)'), message=_('Enter the User you wish to upload to:'), droplist=users ) if user is None or user == "": return self.frame.np.process_request_to_peer(user, slskmessages.UploadQueueNotification(None)) for fn in self.selected_files: self.frame.np.transfers.push_file(user, "\\".join([folder, fn]), "\\".join([realpath, fn]), prefix) self.frame.np.transfers.check_upload_queue() def on_play_files(self, widget, prefix=""): start_new_thread(self._on_play_files, (widget, prefix)) def _on_play_files(self, widget, prefix=""): path = self.frame.np.shares.virtual2real(self.selected_folder) executable = self.frame.np.config.sections["players"]["default"] if "$" not in executable: return for fn in self.selected_files: file = os.sep.join([path, fn]) if os.path.exists(file): execute_command(executable, file, background=False) def find_matches(self): self.search_list = [] for directory, files in self.shares: if self.query in directory.lower(): if directory not in self.search_list: self.search_list.append(directory) for file in files: if self.query in file[1].lower(): if directory not in self.search_list: self.search_list.append(directory) def on_search(self, widget): query = self.SearchEntry.get_text().lower() if self.query == query: self.search_position += 1 else: self.search_position = 0 self.query = query if self.query == "": return self.find_matches() if self.search_list != []: if self.search_position not in list(range(len(self.search_list))): self.search_position = 0 self.search_list.sort() directory = self.search_list[self.search_position] path = self.dir_store.get_path(self.directories[directory]) self.FolderTreeView.expand_to_path(path) self.FolderTreeView.set_cursor(path) # Get matching files in the current directory resultfiles = [] for file in list(self.files.keys()): if query in file.lower(): resultfiles.append(file) sel = self.FileTreeView.get_selection() sel.unselect_all() not_selected = 1 resultfiles.sort() for fn in resultfiles: path = self.file_store.get_path(self.files[fn]) # Select each matching file in directory sel.select_path(path) if not_selected: # Position cursor at first match self.FileTreeView.scroll_to_cell(path, None, True, 0.5, 0.5) not_selected = 0 else: self.search_position = 0 def on_close(self, widget): del self.userbrowses.users[self.user] self.frame.np.close_peer_connection(self.conn) self.userbrowses.remove_page(self.Main) self.Main.destroy() def on_refresh(self, widget): self.FolderTreeView.set_sensitive(False) self.FileTreeView.set_sensitive(False) self.SaveButton.set_sensitive(False) self.frame.browse_user(self.user) def on_copy_url(self, widget): if self.selected_files != [] and self.selected_files is not None: path = "\\".join([self.selected_folder, self.selected_files[0]]) self.frame.set_clipboard_url(self.user, path) def on_copy_dir_url(self, widget): if self.selected_folder is None: return path = self.selected_folder if path[:-1] != "/": path += "/" self.frame.set_clipboard_url(self.user, path) def on_file_manager(self, widget): if self.selected_folder is None: return path = self.frame.np.shares.virtual2real(self.selected_folder) executable = self.frame.np.config.sections["ui"]["filemanager"] if "$" in executable: execute_command(executable, path)