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()
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": f"Search results for {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), ) ) self.clicked_search_bar() # Trigger remote search self.search_results_page.preview_clicked() self.last_search_query = query self.last_search_time = current_ts
def initialize_personal_channels_page(self): autocommit_enabled = (get_gui_setting( self.gui_settings, "autocommit_enabled", True, is_bool=True) if self.gui_settings else True) self.personal_channel_page.initialize_content_page(self.gui_settings, edit_enabled=True) self.personal_channel_page.default_channel_model = ( SimplifiedPersonalChannelsModel if autocommit_enabled else PersonalChannelsModel) self.personal_channel_page.initialize_root_model( self.personal_channel_page.default_channel_model( hide_xxx=False, channel_info={ "name": "My channels", "state": "Personal" }, endpoint_url="channels/mychannel/0", exclude_deleted=autocommit_enabled, )) def on_dirty_response(response): if response and "dirty" in response: self.personal_channel_page.update_labels( dirty=response.get("dirty", False)) TriblerNetworkRequest("channels/mychannel/0/commit", on_dirty_response, method='GET')
def event(self, event): # Minimize to tray if (not DARWIN and event.type() == QtCore.QEvent.WindowStateChange and self.window().isMinimized() and get_gui_setting( self.gui_settings, "minimize_to_tray", False, is_bool=True)): self.window().hide() return True return super().event(event)
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, "Download Error", "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()
def get_bool_gui_setting(self, setting_name: str, default: bool = False): """ Get a particular boolean GUI setting. The reason why this is a separate method is that there are some additional checks that need to be done when accessing the GUI settings in the window. """ try: return get_gui_setting(self.table_view.window().gui_settings, setting_name, False, is_bool=True) except AttributeError: # It could happen that the window is unloaded, e.g., when closing down Tribler. return default
def update_recent_download_locations(self, destination): # Save the download location to the GUI settings current_settings = get_gui_setting(self.gui_settings, "recent_download_locations", "") recent_locations = current_settings.split(",") if len(current_settings) > 0 else [] if isinstance(destination, str): destination = destination.encode('utf-8') encoded_destination = hexlify(destination) if encoded_destination in recent_locations: recent_locations.remove(encoded_destination) recent_locations.insert(0, encoded_destination) if len(recent_locations) > 5: recent_locations = recent_locations[:5] self.gui_settings.setValue("recent_download_locations", ','.join(recent_locations))
def __init__(self, core_args=None, core_env=None, api_port=None, api_key=None): QMainWindow.__init__(self) self._logger = logging.getLogger(self.__class__.__name__) QCoreApplication.setOrganizationDomain("nl") QCoreApplication.setOrganizationName("TUDelft") QCoreApplication.setApplicationName("Tribler") self.setWindowIcon(QIcon(QPixmap(get_image_path('tribler.png')))) self.gui_settings = QSettings('nl.tudelft.tribler') api_port = api_port or int(get_gui_setting(self.gui_settings, "api_port", DEFAULT_API_PORT)) api_key = api_key or get_gui_setting(self.gui_settings, "api_key", hexlify(os.urandom(16)).encode('utf-8')) self.gui_settings.setValue("api_key", api_key) api_port = get_first_free_port(start=api_port, limit=100) request_manager.port, request_manager.key = api_port, api_key self.tribler_started = False self.tribler_settings = None # TODO: move version_id to tribler_common and get core version in the core crash message self.tribler_version = version_id self.debug_window = None self.error_handler = ErrorHandler(self) self.core_manager = CoreManager(api_port, api_key, self.error_handler) self.pending_requests = {} self.pending_uri_requests = [] self.download_uri = None self.dialog = None self.create_dialog = None self.chosen_dir = None self.new_version_dialog = None self.start_download_dialog_active = False self.selected_torrent_files = [] self.has_search_results = False self.last_search_query = None self.last_search_time = None self.start_time = time.time() self.token_refresh_timer = None self.shutdown_timer = None self.add_torrent_url_dialog_active = False sys.excepthook = self.error_handler.gui_error uic.loadUi(get_ui_file_path('mainwindow.ui'), self) TriblerRequestManager.window = self self.tribler_status_bar.hide() self.token_balance_widget.mouseReleaseEvent = self.on_token_balance_click def on_state_update(new_state): self.loading_text_label.setText(new_state) connect(self.core_manager.core_state_update, on_state_update) self.magnet_handler = MagnetHandler(self.window) QDesktopServices.setUrlHandler("magnet", self.magnet_handler, "on_open_magnet_link") self.debug_pane_shortcut = QShortcut(QKeySequence("Ctrl+d"), self) connect(self.debug_pane_shortcut.activated, self.clicked_menu_button_debug) self.import_torrent_shortcut = QShortcut(QKeySequence("Ctrl+o"), self) connect(self.import_torrent_shortcut.activated, self.on_add_torrent_browse_file) self.add_torrent_url_shortcut = QShortcut(QKeySequence("Ctrl+i"), self) connect(self.add_torrent_url_shortcut.activated, self.on_add_torrent_from_url) connect(self.top_search_bar.clicked, self.clicked_search_bar) # Remove the focus rect on OS X for widget in self.findChildren(QLineEdit) + self.findChildren(QListWidget) + self.findChildren(QTreeWidget): widget.setAttribute(Qt.WA_MacShowFocusRect, 0) self.menu_buttons = [ self.left_menu_button_downloads, self.left_menu_button_discovered, self.left_menu_button_trust_graph, self.left_menu_button_popular, ] hide_xxx = get_gui_setting(self.gui_settings, "family_filter", True, is_bool=True) self.search_results_page.initialize_content_page(hide_xxx=hide_xxx) self.search_results_page.channel_torrents_filter_input.setHidden(True) self.settings_page.initialize_settings_page() self.downloads_page.initialize_downloads_page() self.loading_page.initialize_loading_page() self.discovering_page.initialize_discovering_page() self.discovered_page.initialize_content_page(hide_xxx=hide_xxx) self.popular_page.initialize_content_page(hide_xxx=hide_xxx) self.trust_page.initialize_trust_page() self.trust_graph_page.initialize_trust_graph() self.stackedWidget.setCurrentIndex(PAGE_LOADING) # Create the system tray icon if QSystemTrayIcon.isSystemTrayAvailable(): self.tray_icon = QSystemTrayIcon() use_monochrome_icon = get_gui_setting(self.gui_settings, "use_monochrome_icon", False, is_bool=True) self.update_tray_icon(use_monochrome_icon) # Create the tray icon menu menu = self.create_add_torrent_menu() show_downloads_action = QAction('Show downloads', self) connect(show_downloads_action.triggered, self.clicked_menu_button_downloads) token_balance_action = QAction('Show token balance', self) connect(token_balance_action.triggered, lambda _: self.on_token_balance_click(None)) quit_action = QAction('Quit Tribler', self) connect(quit_action.triggered, self.close_tribler) menu.addSeparator() menu.addAction(show_downloads_action) menu.addAction(token_balance_action) menu.addSeparator() menu.addAction(quit_action) self.tray_icon.setContextMenu(menu) else: self.tray_icon = None self.left_menu_button_debug.setHidden(True) self.top_menu_button.setHidden(True) self.left_menu.setHidden(True) self.token_balance_widget.setHidden(True) self.settings_button.setHidden(True) self.add_torrent_button.setHidden(True) self.top_search_bar.setHidden(True) # Set various icons self.top_menu_button.setIcon(QIcon(get_image_path('menu.png'))) self.search_completion_model = QStringListModel() completer = QCompleter() completer.setModel(self.search_completion_model) completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) self.item_delegate = QStyledItemDelegate() completer.popup().setItemDelegate(self.item_delegate) completer.popup().setStyleSheet( """ QListView { background-color: #404040; } QListView::item { color: #D0D0D0; padding-top: 5px; padding-bottom: 5px; } QListView::item:hover { background-color: #707070; } """ ) self.top_search_bar.setCompleter(completer) # Toggle debug if developer mode is enabled self.window().left_menu_button_debug.setHidden( not get_gui_setting(self.gui_settings, "debug", False, is_bool=True) ) # Start Tribler self.core_manager.start(core_args=core_args, core_env=core_env) connect(self.core_manager.events_manager.torrent_finished, self.on_torrent_finished) connect(self.core_manager.events_manager.new_version_available, self.on_new_version_available) connect(self.core_manager.events_manager.tribler_started, self.on_tribler_started) connect(self.core_manager.events_manager.low_storage_signal, self.on_low_storage) connect(self.core_manager.events_manager.tribler_shutdown_signal, self.on_tribler_shutdown_state_update) connect(self.core_manager.events_manager.config_error_signal, self.on_config_error_signal) # Install signal handler for ctrl+c events def sigint_handler(*_): self.close_tribler() signal.signal(signal.SIGINT, sigint_handler) # Resize the window according to the settings center = QApplication.desktop().availableGeometry(self).center() pos = self.gui_settings.value("pos", QPoint(center.x() - self.width() * 0.5, center.y() - self.height() * 0.5)) size = self.gui_settings.value("size", self.size()) self.move(pos) self.resize(size) self.show() self.add_to_channel_dialog = AddToChannelDialog(self.window()) self.add_torrent_menu = self.create_add_torrent_menu() self.add_torrent_button.setMenu(self.add_torrent_menu) self.channels_menu_list = self.findChild(ChannelsMenuListWidget, "channels_menu_list") connect(self.channels_menu_list.itemClicked, self.open_channel_contents_page) # The channels content page is only used to show subscribed channels, so we always show xxx # contents in it. connect( self.core_manager.events_manager.node_info_updated, lambda data: self.channels_menu_list.reload_if_necessary([data]), ) connect(self.left_menu_button_new_channel.clicked, self.create_new_channel)
def initialize_with_settings(self, settings): if not settings: return self.settings = settings = settings["settings"] gui_settings = self.window().gui_settings self.window().settings_stacked_widget.show() self.window().settings_tab.show() self.window().settings_save_button.show() # General settings self.window().family_filter_checkbox.setChecked( get_gui_setting(gui_settings, 'family_filter', True, is_bool=True)) self.window().use_monochrome_icon_checkbox.setChecked( get_gui_setting(gui_settings, "use_monochrome_icon", False, is_bool=True)) self.window().download_location_input.setText( settings['download_defaults']['saveas']) self.window().always_ask_location_checkbox.setChecked( get_gui_setting(gui_settings, "ask_download_settings", True, is_bool=True)) self.window().download_settings_anon_checkbox.setChecked( settings['download_defaults']['anonymity_enabled']) self.window().download_settings_anon_seeding_checkbox.setChecked( settings['download_defaults']['safeseeding_enabled']) self.window().download_settings_add_to_channel_checkbox.setChecked( settings['download_defaults']['add_download_to_channel']) self.window().watchfolder_enabled_checkbox.setChecked( settings['watch_folder']['enabled']) self.window().watchfolder_location_input.setText( settings['watch_folder']['directory']) # Channel settings self.window().channel_autocommit_checkbox.setChecked( get_gui_setting(gui_settings, "autocommit_enabled", True, is_bool=True)) # Log directory self.window().log_location_input.setText( settings['general']['log_dir']) # Connection settings self.window().lt_proxy_type_combobox.setCurrentIndex( settings['libtorrent']['proxy_type']) if settings['libtorrent']['proxy_server']: proxy_server = settings['libtorrent']['proxy_server'].split(":") self.window().lt_proxy_server_input.setText(proxy_server[0]) self.window().lt_proxy_port_input.setText(proxy_server[1]) if settings['libtorrent']['proxy_auth']: proxy_auth = settings['libtorrent']['proxy_auth'].split(":") self.window().lt_proxy_username_input.setText(proxy_auth[0]) self.window().lt_proxy_password_input.setText(proxy_auth[1]) self.window().lt_utp_checkbox.setChecked(settings['libtorrent']['utp']) max_conn_download = settings['libtorrent']['max_connections_download'] if max_conn_download == -1: max_conn_download = 0 self.window().max_connections_download_input.setText( str(max_conn_download)) self.window().api_port_input.setText( f"{get_gui_setting(gui_settings, 'api_port', DEFAULT_API_PORT)}") # Bandwidth settings self.window().upload_rate_limit_input.setText( str(settings['libtorrent']['max_upload_rate'] // 1024)) self.window().download_rate_limit_input.setText( str(settings['libtorrent']['max_download_rate'] // 1024)) # Seeding settings getattr( self.window(), "seeding_" + settings['download_defaults']['seeding_mode'] + "_radio").setChecked(True) self.window().seeding_time_input.setText( seconds_to_hhmm_string( settings['download_defaults']['seeding_time'])) ind = self.window().seeding_ratio_combobox.findText( str(settings['download_defaults']['seeding_ratio'])) if ind != -1: self.window().seeding_ratio_combobox.setCurrentIndex(ind) # Anonymity settings self.window().allow_exit_node_checkbox.setChecked( settings['tunnel_community']['exitnode_enabled']) self.window().number_hops_slider.setValue( int(settings['download_defaults']['number_hops'])) connect(self.window().number_hops_slider.valueChanged, self.update_anonymity_cost_label) self.update_anonymity_cost_label( int(settings['download_defaults']['number_hops'])) # Data settings self.load_settings_data_tab() # Debug self.window().developer_mode_enabled_checkbox.setChecked( get_gui_setting(gui_settings, "debug", False, is_bool=True)) self.window().checkbox_enable_resource_log.setChecked( settings['resource_monitor']['enabled']) cpu_priority = 1 if 'cpu_priority' in settings['resource_monitor']: cpu_priority = int(settings['resource_monitor']['cpu_priority']) self.window().slider_cpu_level.setValue(cpu_priority) self.window().cpu_priority_value.setText( f"Current Priority = {cpu_priority}") connect(self.window().slider_cpu_level.valueChanged, self.show_updated_cpu_priority) self.window().checkbox_enable_network_statistics.setChecked( settings['ipv8']['statistics'])
def __init__(self, parent, download_uri): DialogContainer.__init__(self, parent) torrent_name = download_uri if torrent_name.startswith('file:'): torrent_name = torrent_name[5:] elif torrent_name.startswith('magnet:'): torrent_name = unquote_plus(torrent_name) self.download_uri = download_uri self.has_metainfo = False self.metainfo_fetch_timer = None self.metainfo_retries = 0 uic.loadUi(get_ui_file_path('startdownloaddialog.ui'), self.dialog_widget) self.dialog_widget.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) connect(self.dialog_widget.browse_dir_button.clicked, self.on_browse_dir_clicked) connect(self.dialog_widget.cancel_button.clicked, lambda _: self.button_clicked.emit(0)) connect(self.dialog_widget.download_button.clicked, self.on_download_clicked) connect(self.dialog_widget.select_all_files_button.clicked, self.on_all_files_selected_clicked) connect(self.dialog_widget.deselect_all_files_button.clicked, self.on_all_files_deselected_clicked) connect(self.dialog_widget.loading_files_label.clicked, self.on_reload_torrent_info) connect(self.dialog_widget.anon_download_checkbox.clicked, self.on_reload_torrent_info) self.dialog_widget.destination_input.setStyleSheet(""" QComboBox { background-color: #444; border: none; color: #C0C0C0; padding: 4px; } QComboBox::drop-down { width: 20px; border: 1px solid #999; border-radius: 2px; } QComboBox QAbstractItemView { selection-background-color: #707070; color: #C0C0C0; } QComboBox::down-arrow { width: 12px; height: 12px; image: url('%s'); } """ % get_image_path('down_arrow_input.png')) # self.dialog_widget.add_to_channel_checkbox.setStyleSheet(get_checkbox_style()) checkbox_style = get_checkbox_style() for checkbox in [ self.dialog_widget.add_to_channel_checkbox, self.dialog_widget.safe_seed_checkbox, self.dialog_widget.anon_download_checkbox, ]: checkbox.setStyleSheet(checkbox_style) if self.window().tribler_settings: # Set the most recent download locations in the QComboBox current_settings = get_gui_setting(self.window().gui_settings, "recent_download_locations", "") if len(current_settings) > 0: recent_locations = [ unhexlify(url).decode('utf-8') for url in current_settings.split(",") ] self.dialog_widget.destination_input.addItems(recent_locations) else: self.dialog_widget.destination_input.setCurrentText( self.window().tribler_settings['download_defaults'] ['saveas']) self.dialog_widget.torrent_name_label.setText(torrent_name) connect(self.dialog_widget.anon_download_checkbox.stateChanged, self.on_anon_download_state_changed) self.dialog_widget.anon_download_checkbox.setChecked( self.window().tribler_settings['download_defaults'] ['anonymity_enabled']) self.dialog_widget.safe_seed_checkbox.setChecked( self.window().tribler_settings['download_defaults'] ['safeseeding_enabled']) self.dialog_widget.add_to_channel_checkbox.setChecked( self.window().tribler_settings['download_defaults'] ['add_download_to_channel']) self.dialog_widget.safe_seed_checkbox.setEnabled( self.dialog_widget.anon_download_checkbox.isChecked()) self.perform_files_request() self.dialog_widget.files_list_view.setHidden(True) self.dialog_widget.download_files_container.setHidden(True) self.dialog_widget.adjustSize() self.on_anon_download_state_changed(None) self.on_main_window_resize() self.rest_request = None
def hide_xxx(self): return get_gui_setting(self.gui_settings, "family_filter", True, is_bool=True)
def perform_start_download_request( self, uri, anon_download, safe_seeding, destination, selected_files, total_files=0, add_to_channel=False, callback=None, ): # Check if destination directory is writable is_writable, error = is_dir_writable(destination) if not is_writable: gui_error_message = ( "Insufficient write permissions to <i>%s</i> directory. Please add proper " "write permissions on the directory and add the torrent again. %s" % (destination, error)) ConfirmationDialog.show_message(self.window(), "Download error <i>%s</i>" % uri, gui_error_message, "OK") return selected_files_list = [] if len(selected_files) != total_files: # Not all files included selected_files_list = [filename for filename in selected_files] anon_hops = int(self.tribler_settings['download_defaults'] ['number_hops']) if anon_download else 0 safe_seeding = 1 if safe_seeding else 0 post_data = { "uri": uri, "anon_hops": anon_hops, "safe_seeding": safe_seeding, "destination": destination, "selected_files": selected_files_list, } TriblerNetworkRequest("downloads", callback if callback else self.on_download_added, method='PUT', data=post_data) # Save the download location to the GUI settings current_settings = get_gui_setting(self.gui_settings, "recent_download_locations", "") recent_locations = current_settings.split( ",") if len(current_settings) > 0 else [] if isinstance(destination, str): destination = destination.encode('utf-8') encoded_destination = hexlify(destination) if encoded_destination in recent_locations: recent_locations.remove(encoded_destination) recent_locations.insert(0, encoded_destination) if len(recent_locations) > 5: recent_locations = recent_locations[:5] self.gui_settings.setValue("recent_download_locations", ','.join(recent_locations)) if add_to_channel: 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( "Channel update", "Torrent(s) added to your channel"), method='PUT', data=post_data, ) self.window().add_to_channel_dialog.show_dialog( on_add_button_pressed, confirm_button_text="Add torrent")