Example #1
0
    def on_low_storage(self, _):
        """
        Dealing with low storage space available. First stop the downloads and the core manager and ask user to user to
        make free space.
        :return:
        """

        def close_tribler_gui():
            self.close_tribler()
            # Since the core has already stopped at this point, it will not terminate the GUI.
            # So, we quit the GUI separately here.
            if not QApplication.closingDown():
                QApplication.quit()

        self.downloads_page.stop_loading_downloads()
        self.core_manager.stop(False)
        close_dialog = ConfirmationDialog(
            self.window(),
            tr("<b>CRITICAL ERROR</b>"),
            tr(
                "You are running low on disk space (<100MB). Please make sure to have "
                "sufficient free space available and restart Tribler again."
            ),
            [(tr("Close Tribler"), BUTTON_TYPE_NORMAL)],
        )
        connect(close_dialog.button_clicked, lambda _: close_tribler_gui())
        close_dialog.show()
Example #2
0
    def on_start_download_action(self, action):
        if action == 1:
            if self.dialog and self.dialog.dialog_widget:
                self.window().perform_start_download_request(
                    self.download_uri,
                    self.dialog.dialog_widget.anon_download_checkbox.isChecked(),
                    self.dialog.dialog_widget.safe_seed_checkbox.isChecked(),
                    self.dialog.dialog_widget.destination_input.currentText(),
                    self.dialog.get_selected_files(),
                    self.dialog.dialog_widget.files_list_view.topLevelItemCount(),
                    add_to_channel=self.dialog.dialog_widget.add_to_channel_checkbox.isChecked(),
                )
            else:
                ConfirmationDialog.show_error(
                    self, tr("Tribler UI Error"), tr("Something went wrong. Please try again.")
                )
                logging.exception("Error while trying to download. Either dialog or dialog.dialog_widget is None")

        if self.dialog:
            self.dialog.close_dialog()
            self.dialog = None
            self.start_download_dialog_active = False

        if action == 0:  # We do this after removing the dialog since process_uri_request is blocking
            self.process_uri_request()
Example #3
0
    def on_channel_unsubscribe(self, channel_info):
        def _on_unsubscribe_action(action):
            if action == 0:
                patch_data = [{"public_key": channel_info['public_key'], "id": channel_info['id'], "subscribed": False}]
                TriblerNetworkRequest(
                    "metadata",
                    lambda data: self.core_manager.events_manager.node_info_updated.emit(data[0]),
                    raw_data=json.dumps(patch_data),
                    method='PATCH',
                )
            if self.dialog:
                self.dialog.close_dialog()
                self.dialog = None

        self.dialog = ConfirmationDialog(
            self,
            tr("Unsubscribe from channel"),
            tr("Are you sure you want to <b>unsubscribe</b> from channel<br/>")
            + '\"'
            + f"<b>{channel_info['name']}</b>"
            + '\"'
            + tr("<br/>and remove its contents?"),
            [(tr("UNSUBSCRIBE"), BUTTON_TYPE_NORMAL), (tr("CANCEL"), BUTTON_TYPE_CONFIRM)],
        )
        connect(self.dialog.button_clicked, _on_unsubscribe_action)
        self.dialog.show()
Example #4
0
    def on_channel_delete(self, channel_info):
        def _on_delete_action(action):
            if action == 0:
                delete_data = [{"public_key": channel_info['public_key'], "id": channel_info['id']}]
                TriblerNetworkRequest(
                    "metadata",
                    lambda data: self.core_manager.events_manager.node_info_updated.emit(data[0]),
                    raw_data=json.dumps(delete_data),
                    method='DELETE',
                )
            if self.dialog:
                self.dialog.close_dialog()
                self.dialog = None

        self.dialog = ConfirmationDialog(
            self,
            tr("Delete channel"),
            tr("Are you sure you want to <b>delete</b> your personal channel<br/>")
            + '\"'
            + f"<b>{channel_info['name']}</b>"
            + '\"'
            + tr("<br/>and all its contents?"),
            [(tr("DELETE"), BUTTON_TYPE_NORMAL), (tr("CANCEL"), BUTTON_TYPE_CONFIRM)],
        )
        connect(self.dialog.button_clicked, _on_delete_action)
        self.dialog.show()
Example #5
0
    def on_settings_saved(self, data):
        if not data:
            return
        # Now save the GUI settings
        self.window().gui_settings.setValue(
            "family_filter",
            self.window().family_filter_checkbox.isChecked())
        self.window().gui_settings.setValue(
            "autocommit_enabled",
            self.window().channel_autocommit_checkbox.isChecked())
        self.window().gui_settings.setValue(
            "ask_download_settings",
            self.window().always_ask_location_checkbox.isChecked())
        self.window().gui_settings.setValue(
            "use_monochrome_icon",
            self.window().use_monochrome_icon_checkbox.isChecked())

        self.saved_dialog = ConfirmationDialog(
            TriblerRequestManager.window,
            tr("Settings saved"),
            tr("Your settings have been saved."),
            [(tr("CLOSE"), BUTTON_TYPE_NORMAL)],
        )
        connect(self.saved_dialog.button_clicked,
                self.on_dialog_cancel_clicked)
        self.saved_dialog.show()
        self.window().fetch_settings()
Example #6
0
    def item_txt(self, index, role):
        # ACHTUNG! Dumb workaround for some mysterious race condition
        try:
            item = self.data_items[index.row()]
        except IndexError:
            return ""

        column = self.columns[index.column()]
        column_type = self.columns_shown[index.column()]
        data = item.get(column.dict_key, '')

        # Print number of torrents in the channel for channel rows in the "size" column
        if (column_type == Column.SIZE and "torrents" not in self.columns
                and "torrents" in item
                and item["type"] in (CHANNEL_TORRENT, COLLECTION_NODE)):
            return item["torrents"]

        # 'subscribed' column gets special treatment in case of ToolTipRole, because
        # its tooltip uses information from both 'subscribed' and 'state' keys
        if role == Qt.ToolTipRole and column_type == Column.SUBSCRIBED and 'subscribed' in item and 'state' in item:
            state_message = f" ({item['state']})" if item[
                'state'] != CHANNEL_STATE.COMPLETE.value else ""
            tooltip_txt = (tr("Subscribed.%s\n(Click to unsubscribe)") %
                           state_message if item['subscribed'] else
                           tr("Not subscribed.\n(Click to subscribe)"))
            return tooltip_txt

        return (column.tooltip_filter
                if role == Qt.ToolTipRole else column.display_filter)(data)
Example #7
0
    def perform_files_request(self):
        if self.closed:
            return

        direct = not self.dialog_widget.anon_download_checkbox.isChecked()
        request = f"torrentinfo?uri={quote_plus_unicode(self.download_uri)}"
        if direct is True:
            request = request + f"&hops=0"
        self.rest_request = TriblerNetworkRequest(request,
                                                  self.on_received_metainfo,
                                                  capture_core_errors=False)

        if self.metainfo_retries <= METAINFO_MAX_RETRIES:
            fetch_mode = tr("directly") if direct else tr("anonymously")
            loading_message = tr("Loading torrent files %s...") % fetch_mode
            timeout_message = tr(
                "Timeout in fetching files %s. Retrying  %i/%i") % (
                    fetch_mode,
                    self.metainfo_retries,
                    METAINFO_MAX_RETRIES,
                )

            self.dialog_widget.loading_files_label.setText(
                loading_message
                if not self.metainfo_retries else timeout_message)
            self.metainfo_fetch_timer = QTimer()
            connect(self.metainfo_fetch_timer.timeout,
                    self.perform_files_request)
            self.metainfo_fetch_timer.setSingleShot(True)
            self.metainfo_fetch_timer.start(METAINFO_TIMEOUT)

            self.metainfo_retries += 1
Example #8
0
 def on_add_torrent_browse_file(self, index):
     filenames = QFileDialog.getOpenFileNames(
         self, tr("Please select the .torrent file"), QDir.homePath(), tr("Torrent files%s") % " (*.torrent)"
     )
     if len(filenames[0]) > 0:
         for filename in filenames[0]:
             self.pending_uri_requests.append(f"file:{quote(filename)}")
         self.process_uri_request()
Example #9
0
    def on_received_metainfo(self, response):
        if not response or not self or self.closed:
            return

        if 'error' in response:
            if response['error'] == 'metainfo error':
                # If it failed to load metainfo for max number of times, show an error message in red.
                if self.metainfo_retries > METAINFO_MAX_RETRIES:
                    self.dialog_widget.loading_files_label.setStyleSheet(
                        "color:#ff0000;")
                    self.dialog_widget.loading_files_label.setText(
                        tr("Failed to load files. Click to retry again."))
                    return
                self.perform_files_request()

            elif 'code' in response['error'] and response['error'][
                    'code'] == 'IOError':
                self.dialog_widget.loading_files_label.setText(
                    tr("Unable to read torrent file data"))
            else:
                self.dialog_widget.loading_files_label.setText(
                    tr("Error: %s") % response['error'])
            return

        metainfo = json.loads(unhexlify(response['metainfo']))
        if 'files' in metainfo['info']:  # Multi-file torrent
            files = metainfo['info']['files']
        else:
            files = [{
                'path': [metainfo['info']['name']],
                'length': metainfo['info']['length']
            }]

        # Show if the torrent already exists in the downloads
        if response.get('download_exists'):
            self.dialog_widget.existing_download_info_label.setText(
                tr("Note: this torrent already exists in the Downloads"))
        else:
            self.dialog_widget.existing_download_info_label.setText("")

        self.dialog_widget.files_list_view.clear()
        for filename in files:
            item = DownloadFileTreeWidgetItem(
                self.dialog_widget.files_list_view)
            item.setText(0, '/'.join(filename['path']))
            item.setText(1, format_size(float(filename['length'])))
            item.setData(0, Qt.UserRole, filename)
            item.setCheckState(2, Qt.Checked)
            self.dialog_widget.files_list_view.addTopLevelItem(item)

        self.has_metainfo = True
        self.dialog_widget.loading_files_label.setHidden(True)
        self.dialog_widget.download_files_container.setHidden(False)
        self.dialog_widget.files_list_view.setHidden(False)
        self.dialog_widget.adjustSize()
        self.on_main_window_resize()

        self.received_metainfo.emit(metainfo)
Example #10
0
 def on_add_button_pressed(channel_id):
     TriblerNetworkRequest(
         f"collections/mychannel/{channel_id}/torrents",
         lambda _: self.tray_show_message(
             tr("Channels update"), tr("%s added to your channel") % self.chosen_dir
         ),
         method='PUT',
         data={"torrents_dir": self.chosen_dir},
     )
Example #11
0
 def on_confirm_clicked(channel_id):
     TriblerNetworkRequest(
         f"collections/mychannel/{channel_id}/copy",
         lambda _: self.table_view.window().tray_show_message(
             tr("Channel update"),
             tr("Torrent(s) added to your channel")),
         raw_data=dumps(entries),
         method='POST',
     )
Example #12
0
    def create_personal_menu(self):
        menu = TriblerActionMenu(self)
        delete_action = QAction(tr("Delete channel"), self)
        connect(delete_action.triggered, self._on_delete_action)
        menu.addAction(delete_action)

        rename_action = QAction(tr("Rename channel"), self)
        connect(rename_action.triggered, self._trigger_name_editor)
        menu.addAction(rename_action)
        return menu
Example #13
0
class PopularTorrentsModel(ChannelContentModel):
    columns = ['category', 'name', 'size', 'updated']
    column_headers = ['', tr('Name'), tr('Size'), tr('Updated')]

    column_width = dict(ChannelContentModel.column_width,
                        **{'name': lambda table_width: table_width - 280})

    def __init__(self, *args, **kwargs):
        kwargs["endpoint_url"] = 'channels/popular_torrents'
        super().__init__(*args, **kwargs)
Example #14
0
    def on_add_torrent_browse_file(self, checked):  # pylint: disable=W0613
        filenames = QFileDialog.getOpenFileNames(
            self,
            tr("Please select the .torrent file"),
            filter=(tr("Torrent files %s") % '(*.torrent)'))
        if not filenames[0]:
            return

        for filename in filenames[0]:
            self.add_torrent_to_channel(filename)
Example #15
0
    def on_tribler_started(self, version):
        if self.tribler_started:
            logging.warning("Received duplicate Tribler Core started event")
            return

        self.tribler_started = True
        self.tribler_version = version

        self.top_menu_button.setHidden(False)
        self.left_menu.setHidden(False)
        self.token_balance_widget.setHidden(False)
        self.settings_button.setHidden(False)
        self.add_torrent_button.setHidden(False)
        self.top_search_bar.setHidden(False)

        self.fetch_settings()

        self.downloads_page.start_loading_downloads()

        self.setAcceptDrops(True)
        self.setWindowTitle(f"Tribler {self.tribler_version}")

        autocommit_enabled = (
            get_gui_setting(self.gui_settings, "autocommit_enabled", True, is_bool=True) if self.gui_settings else True
        )
        self.channel_contents_page.initialize_content_page(autocommit_enabled=autocommit_enabled, hide_xxx=False)

        hide_xxx = get_gui_setting(self.gui_settings, "family_filter", True, is_bool=True)
        self.discovered_page.initialize_root_model(
            DiscoveredChannelsModel(
                channel_info={"name": tr("Discovered channels")}, endpoint_url="channels", hide_xxx=hide_xxx
            )
        )
        connect(self.core_manager.events_manager.discovered_channel, self.discovered_page.model.on_new_entry_received)

        self.popular_page.initialize_root_model(
            PopularTorrentsModel(channel_info={"name": "Popular torrents"}, hide_xxx=hide_xxx)
        )
        self.popular_page.explanation_text.setText(
            tr("This page show the list of popular torrents collected by Tribler during the last 24 hours.")
        )
        self.popular_page.explanation_container.setHidden(False)

        self.add_to_channel_dialog.load_channel(0)

        if not self.gui_settings.value("first_discover", False) and not self.core_manager.use_existing_core:
            connect(self.core_manager.events_manager.discovered_channel, self.stop_discovering)
            self.window().gui_settings.setValue("first_discover", True)
            self.discovering_page.is_discovering = True
            self.stackedWidget.setCurrentIndex(PAGE_DISCOVERING)
        else:
            self.clicked_menu_button_discovered()
            self.left_menu_button_discovered.setChecked(True)

        self.channels_menu_list.load_channels()
Example #16
0
 def on_add_button_pressed(channel_id):
     for selected_item in self.selected_items:
         infohash = selected_item.download_info["infohash"]
         name = selected_item.download_info["name"]
         TriblerNetworkRequest(
             f"channels/mychannel/{channel_id}/torrents",
             lambda _: self.window().tray_show_message(
                 tr("Channel update"),
                 tr("Torrent(s) added to your channel")),
             method='PUT',
             data={"uri": compose_magnetlink(infohash, name=name)},
         )
Example #17
0
 def on_torrent_created(self, result):
     if not result:
         return
     self.dialog_widget.btn_create.setEnabled(True)
     self.dialog_widget.edit_channel_create_torrent_progress_label.setText(
         tr("Created torrent"))
     if 'torrent' in result:
         self.create_torrent_notification.emit(
             {"msg": tr("Torrent successfully created")})
         if self.dialog_widget.add_to_channel_checkbox.isChecked():
             self.add_torrent_to_channel(result['torrent'])
         self.close_dialog()
Example #18
0
 def on_remove_download_clicked(self, checked):
     self.dialog = ConfirmationDialog(
         self,
         tr("Remove download"),
         tr("Are you sure you want to remove this download?"),
         [
             (tr("remove download"), BUTTON_TYPE_NORMAL),
             (tr("remove download + data"), BUTTON_TYPE_NORMAL),
             (tr("cancel"), BUTTON_TYPE_CONFIRM),
         ],
     )
     connect(self.dialog.button_clicked, self.on_remove_download_dialog)
     self.dialog.show()
Example #19
0
 def on_add_torrent_from_url(self, checked):  # pylint: disable=W0613
     self.dialog = ConfirmationDialog(
         self,
         tr("Add torrent from URL/magnet link"),
         tr("Please enter the URL/magnet link in the field below:"),
         [(tr("ADD"), BUTTON_TYPE_NORMAL),
          (tr("CANCEL"), BUTTON_TYPE_CONFIRM)],
         show_input=True,
     )
     self.dialog.dialog_widget.dialog_input.setPlaceholderText(
         tr("URL/magnet link"))
     connect(self.dialog.button_clicked,
             self.on_torrent_from_url_dialog_done)
     self.dialog.show()
Example #20
0
    def create_channel_options_menu(self):
        browse_files_action = QAction(tr("Add .torrent file"), self)
        browse_dir_action = QAction(tr("Add torrent(s) directory"), self)
        add_url_action = QAction(tr("Add URL/magnet links"), self)

        connect(browse_files_action.triggered, self.on_add_torrent_browse_file)
        connect(browse_dir_action.triggered, self.on_add_torrents_browse_dir)
        connect(add_url_action.triggered, self.on_add_torrent_from_url)

        channel_options_menu = TriblerActionMenu(self)
        channel_options_menu.addAction(browse_files_action)
        channel_options_menu.addAction(browse_dir_action)
        channel_options_menu.addAction(add_url_action)
        return channel_options_menu
Example #21
0
class SimplifiedPersonalChannelsModel(PersonalChannelsModel):
    columns = [ACTION_BUTTONS, 'category', 'name', 'size', 'health', 'updated']
    column_headers = [
        '', '', tr('Name'),
        tr('Size'),
        tr('Health'),
        tr('Updated')
    ]

    column_width = dict(ChannelContentModel.column_width,
                        **{'name': lambda table_width: table_width - 440})

    def __init__(self, *args, **kwargs):
        kwargs["exclude_deleted"] = kwargs.get("exclude_deleted", True)
        super().__init__(*args, **kwargs)
Example #22
0
 def clicked_skip_conversion(self):
     self.dialog = ConfirmationDialog(
         self,
         tr("Abort the conversion of Channels database"),
         tr(
             "The upgrade procedure is now <b>converting your personal channel</b> and channels "
             "collected by the previous installation of Tribler.<br>"
             "Are you sure you want to abort the conversion process?<br><br>"
             "<p style='color:red'><b> !!! WARNING !!! <br>"
             "You will lose your personal channel and subscribed channels if you ABORT now! </b> </p> <br>"
         ),
         [(tr("ABORT"), BUTTON_TYPE_CONFIRM), (tr("CONTINUE"), BUTTON_TYPE_NORMAL)],
     )
     connect(self.dialog.button_clicked, self.on_skip_conversion_dialog)
     self.dialog.show()
Example #23
0
            def on_add_button_pressed(channel_id):
                post_data = {}
                if uri.startswith("file:"):
                    with open(uri[5:], "rb") as torrent_file:
                        post_data['torrent'] = b64encode(torrent_file.read()).decode('utf8')
                elif uri.startswith("magnet:"):
                    post_data['uri'] = uri

                if post_data:
                    TriblerNetworkRequest(
                        f"channels/mychannel/{channel_id}/torrents",
                        lambda _: self.tray_show_message(tr("Channel update"), tr("Torrent(s) added to your channel")),
                        method='PUT',
                        data=post_data,
                    )
Example #24
0
    def close_tribler(self, checked=False):
        if self.core_manager.shutting_down:
            return

        def show_force_shutdown():
            self.window().force_shutdown_btn.show()

        self.delete_tray_icon()
        self.show_loading_screen()
        self.hide_status_bar()
        self.loading_text_label.setText(tr("Shutting down..."))
        if self.debug_window:
            self.debug_window.setHidden(True)

        self.shutdown_timer = QTimer()
        connect(self.shutdown_timer.timeout, show_force_shutdown)
        self.shutdown_timer.start(SHUTDOWN_WAITING_PERIOD)

        self.gui_settings.setValue("pos", self.pos())
        self.gui_settings.setValue("size", self.size())

        if self.core_manager.use_existing_core:
            # Don't close the core that we are using
            QApplication.quit()

        self.core_manager.stop()
        self.core_manager.shutting_down = True
        self.downloads_page.stop_loading_downloads()
        request_manager.clear()

        # Stop the token balance timer
        if self.token_refresh_timer:
            self.token_refresh_timer.stop()
Example #25
0
    def on_confirm_add_directory_dialog(self, action):
        if action == 0:
            if self.dialog.checkbox.isChecked():
                # TODO: add recursive directory scanning
                def on_add_button_pressed(channel_id):
                    TriblerNetworkRequest(
                        f"collections/mychannel/{channel_id}/torrents",
                        lambda _: self.tray_show_message(
                            tr("Channels update"), tr("%s added to your channel") % self.chosen_dir
                        ),
                        method='PUT',
                        data={"torrents_dir": self.chosen_dir},
                    )

                self.window().add_to_channel_dialog.show_dialog(
                    on_add_button_pressed, confirm_button_text=tr("Add torrent(s)")
                )

            for torrent_file in self.selected_torrent_files:
                self.perform_start_download_request(
                    f"file:{torrent_file}",
                    self.window().tribler_settings['download_defaults']['anonymity_enabled'],
                    self.window().tribler_settings['download_defaults']['safeseeding_enabled'],
                    self.tribler_settings['download_defaults']['saveas'],
                    [],
                )

        if self.dialog:
            self.dialog.close_dialog()
            self.dialog = None
Example #26
0
    def on_top_search_button_click(self):
        current_ts = time.time()
        query = self.top_search_bar.text()

        if (
            self.last_search_query
            and self.last_search_time
            and self.last_search_query == self.top_search_bar.text()
            and current_ts - self.last_search_time < 1
        ):
            logging.info("Same search query already sent within 500ms so dropping this one")
            return

        if not query:
            return

        self.has_search_results = True
        self.search_results_page.initialize_root_model(
            SearchResultsModel(
                channel_info={"name": (tr("Search results for %s") % query) if len(query) < 50 else f"{query[:50]}..."},
                endpoint_url="search",
                hide_xxx=get_gui_setting(self.gui_settings, "family_filter", True, is_bool=True),
                text_filter=to_fts_query(query),
                type_filter=[REGULAR_TORRENT, CHANNEL_TORRENT, COLLECTION_NODE],
            )
        )

        self.clicked_search_bar()

        # Trigger remote search
        self.search_results_page.preview_clicked()

        self.last_search_query = query
        self.last_search_time = current_ts
Example #27
0
 def on_export_download_request_done(self, filename, data):
     dest_path = os.path.join(self.export_dir, filename)
     try:
         torrent_file = open(dest_path, "wb")
         torrent_file.write(data)
         torrent_file.close()
     except OSError as exc:
         ConfirmationDialog.show_error(
             self.window(),
             tr("Error when exporting file"),
             tr("An error occurred when exporting the torrent file: %s") %
             str(exc),
         )
     else:
         self.window().tray_show_message(
             tr("Torrent file exported"),
             tr("Torrent file exported to %s") % str(dest_path))
Example #28
0
    def on_choose_log_dir_clicked(self, checked):
        previous_log_dir = self.window().log_location_input.text() or ""
        log_dir = QFileDialog.getExistingDirectory(
            self.window(), tr("Please select the log directory"),
            previous_log_dir, QFileDialog.ShowDirsOnly)

        if not log_dir or log_dir == previous_log_dir:
            return

        is_writable, error = is_dir_writable(log_dir)
        if not is_writable:
            gui_error_message = f"<i>{log_dir}</i> is not writable. [{error}]"
            ConfirmationDialog.show_message(self.window(),
                                            tr("Insufficient Permissions"),
                                            gui_error_message, "OK")
        else:
            self.window().log_location_input.setText(log_dir)
Example #29
0
    def on_add_torrent_from_url(self, checked=False):
        # Make sure that the window is visible (this action might be triggered from the tray icon)
        self.raise_window()

        if not self.add_torrent_url_dialog_active:
            self.dialog = ConfirmationDialog(
                self,
                tr("Add torrent from URL/magnet link"),
                tr("Please enter the URL/magnet link in the field below:"),
                [(tr("ADD"), BUTTON_TYPE_NORMAL), (tr("CANCEL"), BUTTON_TYPE_CONFIRM)],
                show_input=True,
            )
            self.dialog.dialog_widget.dialog_input.setPlaceholderText(tr("URL/magnet link"))
            self.dialog.dialog_widget.dialog_input.setFocus()
            connect(self.dialog.button_clicked, self.on_torrent_from_url_dialog_done)
            self.dialog.show()
            self.add_torrent_url_dialog_active = True
Example #30
0
    def start_download_from_uri(self, uri):
        uri = uri.decode('utf-8') if isinstance(uri, bytes) else uri
        self.download_uri = uri

        if get_gui_setting(self.gui_settings, "ask_download_settings", True, is_bool=True):
            # FIXME: instead of using this workaround, make sure the settings are _available_ by this moment
            # If tribler settings is not available, fetch the settings and inform the user to try again.
            if not self.tribler_settings:
                self.fetch_settings()
                self.dialog = ConfirmationDialog.show_error(
                    self,
                    tr("Download Error"),
                    tr("Tribler settings is not available yet. Fetching it now. Please try again later."),
                )
                # By re-adding the download uri to the pending list, the request is re-processed
                # when the settings is received
                self.pending_uri_requests.append(uri)
                return
            # Clear any previous dialog if exists
            if self.dialog:
                self.dialog.close_dialog()
                self.dialog = None

            self.dialog = StartDownloadDialog(self, self.download_uri)
            connect(self.dialog.button_clicked, self.on_start_download_action)
            self.dialog.show()
            self.start_download_dialog_active = True
        else:
            # FIXME: instead of using this workaround, make sure the settings are _available_ by this moment
            # In the unlikely scenario that tribler settings are not available yet, try to fetch settings again and
            # add the download uri back to self.pending_uri_requests to process again.
            if not self.tribler_settings:
                self.fetch_settings()
                if self.download_uri not in self.pending_uri_requests:
                    self.pending_uri_requests.append(self.download_uri)
                return

            self.window().perform_start_download_request(
                self.download_uri,
                self.window().tribler_settings['download_defaults']['anonymity_enabled'],
                self.window().tribler_settings['download_defaults']['safeseeding_enabled'],
                self.tribler_settings['download_defaults']['saveas'],
                [],
            )
            self.process_uri_request()