Exemple #1
0
    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
Exemple #2
0
    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
Exemple #3
0
    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
Exemple #4
0
    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
Exemple #5
0
    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
Exemple #6
0
    def TabPopup(self, id):

        popup = PopupMenu(self.frame)
        popup.setup(
            ("#" + _("Close this tab"), self.searches[id][2].OnClose)
        )

        return popup
Exemple #7
0
    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
Exemple #8
0
    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
Exemple #9
0
    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
Exemple #10
0
    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
Exemple #11
0
    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
Exemple #12
0
    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
Exemple #13
0
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)
Exemple #14
0
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)
Exemple #15
0
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()
Exemple #16
0
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)
Exemple #17
0
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()
Exemple #18
0
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)
Exemple #19
0
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)
Exemple #20
0
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)