def __init__(self, parent=None): super(widget_class, self).__init__(parent=parent) # FIXME!!! This is a dumb workaround for a bug(?) in PyQT bindings in Python 3.7 # When more than a single instance of a class is created, every next setupUi # triggers connectSlotsByName error. There are some reports that it is specific to # 3.7 and there is a fix in the 10.08.2019 PyQt bindings snapshot. try: self.setupUi(self) except SystemError: pass # ! ACHTUNG ! # There is a bug in PyQT bindings that prevents uic.loadUiType from correctly # detecting paths to external resources used in .ui files. Therefore, # for each external resource (e.g. image/icon), we must reload it manually here. self.channel_options_button.setIcon( QIcon(get_image_path('ellipsis.png'))) self.channel_preview_button.setIcon( QIcon(get_image_path('refresh.png'))) self.channel_preview_button.setToolTip( 'Click to load preview contents') self.default_channel_model = ChannelContentModel self.initialized = False self.chosen_dir = None self.dialog = None self.controller = None self.commit_timer = None self.autocommit_enabled = None self.channel_options_menu = None self.channels_stack = [] self_ref = self self.hide_xxx = None # This context manager is used to freeze the state of controls in the models stack to # prevent signals from triggering for inactive models. class freeze_controls_class: objects_to_freeze = [ self_ref.category_selector, self_ref.content_table.horizontalHeader(), self_ref.channel_torrents_filter_input, ] def __enter__(self): for obj in self.objects_to_freeze: obj.blockSignals(True) def __exit__(self, *args): for obj in self.objects_to_freeze: obj.blockSignals(False) self.freeze_controls = freeze_controls_class self.setStyleSheet( "QToolTip { color: #222222; background-color: #eeeeee; border: 0px; }" )
def update_tray_icon(self, use_monochrome_icon): if not QSystemTrayIcon.isSystemTrayAvailable() or not self.tray_icon: return if use_monochrome_icon: self.tray_icon.setIcon(QIcon(QPixmap(get_image_path('monochrome_tribler.png')))) else: self.tray_icon.setIcon(QIcon(QPixmap(get_image_path('tribler.png')))) self.tray_icon.show()
def __init__(self, column_name, parent=None): ToggleControl.__init__( self, column_name, QIcon(get_image_path("subscribed_yes.png")), QIcon(get_image_path("subscribed_not.png")), QIcon(get_image_path("subscribed.png")), parent=parent, )
class ChannelStateMixin: wait_png = QIcon(get_image_path("wait.png")) share_icon = QIcon(get_image_path("share.png")) downloading_icon = QIcon(get_image_path("downloads.png")) @staticmethod def get_indicator_rect(rect): r = rect indicator_border = 1 indicator_side = (r.height() if r.width() > r.height() else r.width()) - indicator_border * 2 y = r.top() + (r.height() - indicator_side) / 2 x = r.left() + indicator_border w = indicator_side h = indicator_side indicator_rect = QRect(x, y, w, h) return indicator_rect def draw_channel_state(self, painter, option, index, data_item): # Draw empty cell as the background self.paint_empty_background(painter, option) text_rect = option.rect if data_item['status'] == CHANNEL_STATE.LEGACY.value: painter.drawText(text_rect, Qt.AlignCenter, "Legacy") return True if 'type' in data_item and data_item['type'] != CHANNEL_TORRENT: return True if data_item['state'] == CHANNEL_STATE.COMPLETE.value: painter.drawText(text_rect, Qt.AlignCenter, "✔") return True if data_item['state'] == CHANNEL_STATE.PERSONAL.value: self.share_icon.paint(painter, self.get_indicator_rect(option.rect)) return True if data_item['state'] == CHANNEL_STATE.DOWNLOADING.value: painter.drawText(text_rect, Qt.AlignCenter, "⏳") return True if data_item['state'] == CHANNEL_STATE.METAINFO_LOOKUP.value: painter.drawText(text_rect, Qt.AlignCenter, "❓") return True if data_item['state'] == CHANNEL_STATE.UPDATING.value: progress = data_item.get('progress') if progress is not None: draw_progress_bar(painter, option.rect, float(progress)) return True return True
def initialize_market_page(self): if not self.initialized: self.window().market_back_button.setIcon( QIcon(get_image_path('page_back.png'))) self.window( ).core_manager.events_manager.received_market_ask.connect( self.on_ask) self.window( ).core_manager.events_manager.received_market_bid.connect( self.on_bid) self.window( ).core_manager.events_manager.expired_market_ask.connect( self.on_ask_timeout) self.window( ).core_manager.events_manager.expired_market_bid.connect( self.on_bid_timeout) self.window( ).core_manager.events_manager.market_payment_received.connect( self.on_payment) self.window( ).core_manager.events_manager.market_payment_sent.connect( self.on_payment) self.window( ).core_manager.events_manager.market_transaction_complete.connect( self.on_transaction_complete) self.window().create_ask_button.clicked.connect( self.on_create_ask_clicked) self.window().create_bid_button.clicked.connect( self.on_create_bid_clicked) self.window().market_currency_type_button.clicked.connect( self.on_asset_type_clicked) self.window().market_transactions_button.clicked.connect( self.on_transactions_button_clicked) self.window().market_wallets_button.clicked.connect( self.on_wallets_button_clicked) self.window().market_orders_button.clicked.connect( self.on_orders_button_clicked) self.window().market_create_wallet_button.clicked.connect( self.on_wallets_button_clicked) # Sort asks ascending and bids descending self.window().asks_list.sortItems(0, Qt.AscendingOrder) self.window().bids_list.sortItems(2, Qt.DescendingOrder) self.window().asks_list.itemSelectionChanged.connect( lambda: self.on_tick_item_clicked(self.window().asks_list)) self.window().bids_list.itemSelectionChanged.connect( lambda: self.on_tick_item_clicked(self.window().bids_list)) self.window().tick_detail_container.hide() self.window().market_create_wallet_button.hide() self.window().create_ask_button.hide() self.window().create_bid_button.hide() self.initialized = True self.load_wallets()
def __init__(self, parent): super().__init__(parent) self.setGeometry(0, 0, 100, 100) self.setAttribute(Qt.WA_TranslucentBackground) self.qm = QMovie(get_image_path("spinner.gif")) self.setMovie(self.qm)
def initialize_content_page(self, autocommit_enabled=False, hide_xxx=None): if self.initialized: return self.hide_xxx = hide_xxx self.initialized = True self.category_selector.addItems(CATEGORY_SELECTOR_ITEMS) connect(self.category_selector.currentIndexChanged, self.on_category_selector_changed) self.channel_back_button.setIcon(QIcon(get_image_path('page_back.png'))) connect(self.channel_back_button.clicked, self.go_back) connect(self.channel_name_label.linkActivated, self.on_breadcrumb_clicked) self.commit_control_bar.setHidden(True) self.controller = ContentTableViewController( self.content_table, filter_input=self.channel_torrents_filter_input ) # To reload the preview connect(self.channel_preview_button.clicked, self.preview_clicked) self.autocommit_enabled = autocommit_enabled if self.autocommit_enabled: self._enable_autocommit_timer() # New channel button connect(self.new_channel_button.clicked, self.create_new_channel) connect(self.content_table.channel_clicked, self.on_channel_clicked) connect(self.edit_channel_commit_button.clicked, self.commit_channels) self.subscription_widget.initialize(self) self.channel_options_menu = self.create_channel_options_menu() self.channel_options_button.setMenu(self.channel_options_menu)
def initialize_wallets_page(self): if not self.initialized: self.window().wallets_back_button.setIcon( QIcon(get_image_path('page_back.png'))) self.window().wallet_btc_overview_button.clicked.connect( lambda: self.initialize_wallet_info( 'BTC', self.window().wallet_btc_overview_button)) self.window().wallet_tbtc_overview_button.clicked.connect( lambda: self.initialize_wallet_info( 'TBTC', self.window().wallet_tbtc_overview_button)) self.window().wallet_mc_overview_button.clicked.connect( lambda: self.initialize_wallet_info( 'MB', self.window().wallet_mc_overview_button)) self.window().add_wallet_button.clicked.connect( self.on_add_wallet_clicked) self.window().wallet_mc_overview_button.hide() self.window().wallet_btc_overview_button.hide() self.window().wallet_tbtc_overview_button.hide() self.window().wallet_paypal_overview_button.hide() self.window().wallet_abn_overview_button.hide() self.window().wallet_rabo_overview_button.hide() self.window().wallet_info_tabs.hide() self.window().wallet_info_tabs.currentChanged.connect( self.tab_changed) self.initialized = True self.load_wallets()
class CommitStatusControl(QObject, CheckClickedMixin): # Column-level controls are stateless collections of methods for visualizing cell data and # triggering corresponding events. icon_border = 4 icon_size = 16 h = icon_size + 2 * icon_border w = h size = QSize(w, h) clicked = pyqtSignal(QModelIndex) new_icon = QIcon(get_image_path("plus.svg")) committed_icon = QIcon(get_image_path("check.svg")) todelete_icon = QIcon(get_image_path("minus.svg")) updated_icon = QIcon(get_image_path("update.svg")) restore_action_icon = QIcon(get_image_path("undo.svg")) def __init__(self, column_name, parent=None): QObject.__init__(self, parent=parent) self.column_name = column_name self.rect = QRect() self.last_index = QModelIndex() def paint(self, painter, rect, index, hover=False): data_item = index.model().data_items[index.row()] column_key = index.model().columns[index.model().column_position[ self.column_name]].dict_key if data_item.get(column_key, '') == '': return state = data_item[column_key] icon = QIcon() if state == COMMIT_STATUS_COMMITTED: icon = self.committed_icon elif state == COMMIT_STATUS_NEW: icon = self.new_icon elif state == COMMIT_STATUS_TODELETE: icon = self.todelete_icon elif state == COMMIT_STATUS_UPDATED: icon = self.updated_icon x = rect.left() + (rect.width() - self.w) / 2 y = rect.top() + (rect.height() - self.h) / 2 icon_rect = QRect(x, y, self.w, self.h) icon.paint(painter, icon_rect) self.rect = rect
def __init__(self, parent): super().__init__(QIcon(QPixmap(get_image_path('edit.png'))), "", parent) self.setGeometry(20, 20, 20, 20) self.setFlat(True) self.paddingRight = 5 self.paddingTop = 5
def load_gears_animation(): svg_container = QGraphicsScene() svg_item = QGraphicsSvgItem() svg = QSvgRenderer(get_image_path("loading_animation.svg")) svg.repaintNeeded.connect(svg_item.update) svg_item.setSharedRenderer(svg) svg_container.addItem(svg_item) return svg_container
def initialize_content_page( self, autocommit_enabled=False, hide_xxx=None, controller_class=ContentTableViewController, categories=CATEGORY_SELECTOR_FOR_SEARCH_ITEMS, ): if self.initialized: return self.hide_xxx = hide_xxx self.initialized = True self.categories = categories self.category_selector.addItems(self.categories) connect(self.category_selector.currentIndexChanged, self.on_category_selector_changed) self.channel_back_button.setIcon(QIcon( get_image_path('page_back.png'))) connect(self.channel_back_button.clicked, self.go_back) connect(self.channel_name_label.linkActivated, self.on_breadcrumb_clicked) self.commit_control_bar.setHidden(True) if LINUX: # On Linux, the default font sometimes does not contain the emoji characters. self.category_selector.setStyleSheet( "font-family: Noto Color Emoji") self.controller = controller_class( self.content_table, filter_input=self.channel_torrents_filter_input) # Hide channel description on scroll connect(self.controller.table_view.verticalScrollBar().valueChanged, self._on_table_scroll) self.autocommit_enabled = autocommit_enabled if self.autocommit_enabled: self._enable_autocommit_timer() # New channel button connect(self.new_channel_button.clicked, self.create_new_channel) connect(self.content_table.channel_clicked, self.on_channel_clicked) connect(self.edit_channel_commit_button.clicked, self.commit_channels) self.subscription_widget.initialize(self) self.channel_options_menu = self.create_channel_options_menu() self.channel_options_button.setMenu(self.channel_options_menu) connect(self.channel_description_container.became_hidden, self.run_brain_dead_refresh) connect(self.channel_description_container.description_changed, self._description_changed)
def initialize_discovering_page(self): svg_container = QGraphicsScene(self.window().discovering_svg_view) svg_item = QGraphicsSvgItem() svg = QSvgRenderer(get_image_path("loading_animation.svg")) connect(svg.repaintNeeded, svg_item.update) svg_item.setSharedRenderer(svg) svg_container.addItem(svg_item) self.window().discovering_svg_view.setScene(svg_container) connect(self.window().core_manager.events_manager.discovered_channel, self.on_discovered_channel)
def initialize_orders_page(self, wallets): if not self.initialized: self.window().orders_back_button.setIcon( QIcon(get_image_path('page_back.png'))) self.window().market_orders_list.sortItems(0, Qt.AscendingOrder) self.window( ).market_orders_list.customContextMenuRequested.connect( self.on_right_click_order) self.initialized = True self.wallets = wallets self.load_orders()
def initialize_transactions_page(self, wallets): if not self.initialized: self.window().core_manager.events_manager.market_payment_received.connect(self.on_payment) self.window().core_manager.events_manager.market_payment_sent.connect(self.on_payment) self.window().transactions_back_button.setIcon(QIcon(get_image_path('page_back.png'))) self.window().market_transactions_list.itemSelectionChanged.connect(self.on_transaction_item_clicked) self.window().market_transactions_list.sortItems(5, Qt.DescendingOrder) self.initialized = True self.window().market_payments_container.hide() self.wallets = wallets self.load_transactions()
class ChannelStateMixin(object): wait_png = QIcon(get_image_path("wait.png")) share_icon = QIcon(get_image_path("share.png")) @staticmethod def get_indicator_rect(rect): r = rect indicator_border = 1 indicator_side = (r.height() if r.width() > r.height() else r.width()) - indicator_border * 2 y = r.top() + (r.height() - indicator_side) / 2 x = r.left() + indicator_border w = indicator_side h = indicator_side indicator_rect = QRect(x, y, w, h) return indicator_rect def draw_channel_state(self, painter, option, index, data_item): # Draw empty cell as the background self.paint_empty_background(painter, option) if u'type' in data_item and data_item[u'type'] != CHANNEL_TORRENT: return True if data_item[u'status'] == 1000: # LEGACY ENTRIES! return True if data_item[u'state'] == u'Personal': self.share_icon.paint(painter, self.get_indicator_rect(option.rect)) return True if data_item[u'state'] in [u'Updating', u'Downloading']: rect = option.rect rect_side = option.rect.height() * 0.8 x = rect.left() + (rect.width() - rect_side) / 2 y = rect.top() + (rect.height() - rect_side) / 2 icon_rect = QRect(x, y, rect_side, rect_side) self.wait_png.paint(painter, icon_rect) return True return True
def __init__(self, parent=None): QListWidget.__init__(self, parent=parent) self.base_url = "channels" # Items set, used for checking changes self.items_set = frozenset() self.personal_channel_icon = QIcon(get_image_path("share.png")) empty_transparent_image = QPixmap(15, 15) empty_transparent_image.fill(QColor(0, 0, 0, 0)) self.empty_image = QIcon(empty_transparent_image) self.foreign_channel_menu = self.create_foreign_menu() self.personal_channel_menu = self.create_personal_menu() self.setSelectionMode(QAbstractItemView.NoSelection)
def initialize_loading_page(self): svg_container = QGraphicsScene(self.window().loading_svg_view) svg_item = QGraphicsSvgItem() svg = QSvgRenderer(get_image_path("loading_animation.svg")) svg.repaintNeeded.connect(svg_item.update) svg_item.setSharedRenderer(svg) svg_container.addItem(svg_item) self.window().loading_svg_view.setScene(svg_container) self.window().core_manager.events_manager.upgrader_tick.connect( self.on_upgrader_tick) self.window().core_manager.events_manager.upgrader_finished.connect( self.upgrader_finished) self.window().skip_conversion_btn.hide() # Hide the force shutdown button initially. Should be triggered by shutdown timer from main window. self.window().force_shutdown_btn.hide()
def initialize_content_page(self, autocommit_enabled=False, hide_xxx=None, controller_class=ContentTableViewController): if self.initialized: return self.hide_xxx = hide_xxx self.initialized = True self.category_selector.addItems(CATEGORY_SELECTOR_ITEMS) connect(self.category_selector.currentIndexChanged, self.on_category_selector_changed) self.channel_back_button.setIcon(QIcon( get_image_path('page_back.png'))) connect(self.channel_back_button.clicked, self.go_back) connect(self.channel_name_label.linkActivated, self.on_breadcrumb_clicked) self.commit_control_bar.setHidden(True) self.controller = controller_class( self.content_table, filter_input=self.channel_torrents_filter_input) # Hide channel description on scroll connect(self.controller.table_view.verticalScrollBar().valueChanged, self._on_table_scroll) self.autocommit_enabled = autocommit_enabled if self.autocommit_enabled: self._enable_autocommit_timer() # New channel button connect(self.new_channel_button.clicked, self.create_new_channel) connect(self.content_table.channel_clicked, self.on_channel_clicked) connect(self.edit_channel_commit_button.clicked, self.commit_channels) self.subscription_widget.initialize(self) self.channel_options_menu = self.create_channel_options_menu() self.channel_options_button.setMenu(self.channel_options_menu) connect(self.channel_description_container.became_hidden, self._run_brain_dead_refresh) connect(self.channel_description_container.description_changed, self._description_changed)
def initialize(self): self.window().create_torrent_name_field.setText('') self.window().create_torrent_description_field.setText('') self.window().create_torrent_files_list.clear() self.window().seed_after_adding_checkbox.setChecked(True) self.window().edit_channel_create_torrent_progress_label.hide() if not self.initialized: self.window().manage_channel_create_torrent_back.setIcon( QIcon(get_image_path('page_back.png'))) connect( self.window().create_torrent_files_list. customContextMenuRequested, self.on_right_click_file_item) connect(self.window().manage_channel_create_torrent_back.clicked, self.on_create_torrent_manage_back_clicked) connect(self.window().create_torrent_choose_files_button.clicked, self.on_choose_files_clicked) connect(self.window().create_torrent_choose_dir_button.clicked, self.on_choose_dir_clicked) connect(self.window().edit_channel_create_torrent_button.clicked, self.on_create_clicked) self.initialized = True
class PlayIconButton(IconButton): icon = QIcon(get_image_path("play.png")) def should_draw(self, index): return index.model().data_items[index.row()][u'category'] == u'Video'
class CommitStatusControl(QObject): # Column-level controls are stateless collections of methods for visualizing cell data and # triggering corresponding events. icon_border = 4 icon_size = 16 h = icon_size + 2 * icon_border w = h size = QSize(w, h) clicked = pyqtSignal(QModelIndex) new_icon = QIcon(get_image_path("plus.svg")) committed_icon = QIcon(get_image_path("check.svg")) todelete_icon = QIcon(get_image_path("minus.svg")) updated_icon = QIcon(get_image_path("update.svg")) delete_action_icon = QIcon(get_image_path("delete.png")) restore_action_icon = QIcon(get_image_path("undo.svg")) def __init__(self, column_name, parent=None): QObject.__init__(self, parent=parent) self.column_name = column_name self.rect = QRect() self.last_index = QModelIndex() def paint(self, painter, rect, index): data_item = index.model().data_items[index.row()] if self.column_name not in data_item or data_item[ self.column_name] == '': return state = data_item[self.column_name] icon = QIcon() if state == COMMIT_STATUS_COMMITTED: icon = self.committed_icon elif state == COMMIT_STATUS_NEW: icon = self.new_icon elif state == COMMIT_STATUS_TODELETE: icon = self.todelete_icon elif state == COMMIT_STATUS_UPDATED: icon = self.updated_icon x = rect.left() + (rect.width() - self.w) / 2 y = rect.top() + (rect.height() - self.h) / 2 icon_rect = QRect(x, y, self.w, self.h) icon.paint(painter, icon_rect) self.rect = rect def paint_hover(self, painter, rect, index): # FIXME: This should remain disabled until we implement the undo feature in the GUI. """ data_item = index.model().data_items[index.row()] if self.column_name not in data_item or data_item[self.column_name] == '': return state = data_item[self.column_name] icon = QIcon() if state == COMMIT_STATUS_COMMITTED: icon = self.delete_action_icon elif state == COMMIT_STATUS_NEW: icon = self.delete_action_icon elif state == COMMIT_STATUS_TODELETE: icon = self.restore_action_icon elif state == COMMIT_STATUS_UPDATED: icon = self.delete_action_icon x = rect.left() + (rect.width() - self.w) / 2 y = rect.top() + (rect.height() - self.h) / 2 icon_rect = QRect(x, y, self.w, self.h) icon.paint(painter, icon_rect) self.rect = rect """ # This line must be removed when the above code is uncommented return self.paint(painter, rect, index) def check_clicked(self, event, _, __, index): data_item = index.model().data_items[index.row()] if (event.type() == QEvent.MouseButtonRelease and index.model().column_position.get(self.column_name, -1) == index.column() and data_item[self.column_name] != ''): self.clicked.emit(index) return True return False def size_hint(self, _, __): return self.size def on_mouse_moved(self, _, index): if self.last_index != index: # Handle the case when the cursor leaves the table if not index.model(): self.last_index = index return True elif index.model().column_position.get(self.column_name, -1) == index.column(): self.last_index = index return True return False
class TagsMixin: edit_tags_icon = QIcon(get_image_path("edit_white.png")) edit_tags_icon_hover = QIcon(get_image_path("edit_orange.png")) def draw_title_and_tags(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex, data_item: Dict) -> None: painter.setRenderHint(QPainter.Antialiasing, True) title_text_pos = option.rect.topLeft() painter.setPen(Qt.white) painter.drawText( QRectF(title_text_pos.x() + 6, title_text_pos.y(), option.rect.width() - 6, 28), Qt.AlignVCenter, data_item["name"], ) cur_tag_x = option.rect.x() + 6 cur_tag_y = option.rect.y() + TAG_TOP_MARGIN tags_disabled = self.get_bool_gui_setting("disable_tags") if data_item["type"] != REGULAR_TORRENT or tags_disabled: return edit_tags_button_hovered = self.hovering_over_tag_edit_button and self.hover_index == index # If there are no tags (yet), ask the user to add some tags if len(data_item.get("tags", ())) == 0: no_tags_text = tr("Be the first to suggest tags!") painter.setPen( QColor(TRIBLER_ORANGE ) if edit_tags_button_hovered else QColor("#aaa")) text_width = painter.fontMetrics().horizontalAdvance(no_tags_text) edit_tags_rect = QRectF(title_text_pos.x() + 6, title_text_pos.y() + 34, text_width + 4, 28) index.model().edit_tags_rects[index] = edit_tags_rect painter.drawText(edit_tags_rect, no_tags_text) return for tag_text in data_item.get("tags", ())[:MAX_TAGS_TO_SHOW]: text_width = painter.fontMetrics().horizontalAdvance(tag_text) tag_box_width = text_width + 2 * TAG_TEXT_HORIZONTAL_PADDING # Check whether this tag is going to overflow to the next row if cur_tag_x + tag_box_width >= option.rect.x( ) + option.rect.width(): cur_tag_x = option.rect.x() + 6 cur_tag_y += TAG_HEIGHT + 10 # Draw tag painter.setPen(TAG_BORDER_COLOR) path = QPainterPath() rect = QRectF(cur_tag_x, cur_tag_y, tag_box_width, TAG_HEIGHT) path.addRoundedRect(rect, TAG_HEIGHT // 2, TAG_HEIGHT // 2) painter.fillPath(path, TAG_BACKGROUND_COLOR) painter.drawPath(path) painter.setPen(Qt.white) text_pos = rect.topLeft() + QPointF( TAG_TEXT_HORIZONTAL_PADDING, painter.fontMetrics().ascent() + ((rect.height() - painter.fontMetrics().height()) // 2) - 1, ) painter.setPen(TAG_TEXT_COLOR) painter.drawText(text_pos, tag_text) cur_tag_x += rect.width() + TAG_HORIZONTAL_MARGIN # Draw the 'edit tags' button if cur_tag_x + TAG_HEIGHT >= option.rect.x() + option.rect.width(): cur_tag_x = option.rect.x() + 6 cur_tag_y += TAG_HEIGHT + 10 edit_rect = QRect(int(cur_tag_x + 4), int(cur_tag_y), int(TAG_HEIGHT), int(TAG_HEIGHT)) index.model().edit_tags_rects[index] = edit_rect if edit_tags_button_hovered: self.edit_tags_icon_hover.paint(painter, edit_rect) else: self.edit_tags_icon.paint(painter, edit_rect)
class DeleteIconButton(IconButton): icon = QIcon(get_image_path("trash.svg")) def should_draw(self, index): return index.model().edit_enabled
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)
from tribler_common.sentry_reporter.sentry_mixin import AddBreadcrumbOnShowMixin from tribler_gui.dialogs.confirmationdialog import ConfirmationDialog from tribler_gui.i18n import tr from tribler_gui.tribler_request_manager import TriblerNetworkRequest from tribler_gui.utilities import connect, get_image_path, get_ui_file_path widget_form, widget_class = uic.loadUiType( get_ui_file_path('channel_description.ui')) EDIT_BUTTON = "edit_mode_button" PREVIEW_BUTTON = "preview_mode_button" EDIT_BUTTON_NUM = 0 PREVIEW_BUTTON_NUM = 1 DEFAULT_THUMBNAIL_PIXMAP = QPixmap(get_image_path('chan_thumb.png')) CREATE_THUMBNAIL_TEXT = tr( "Click this to add \n channel thumbnail \n (max. 1MB JPG/PNG)") PREVIEW_PAGE = 0 EDIT_PAGE = 1 class FloatingButtonWidget(QPushButton): # Solution inspired by https://gist.github.com/namuan/floating_button_widget.py def __init__(self, parent): super().__init__(QIcon(QPixmap(get_image_path('edit.png'))), "", parent) self.setGeometry(20, 20, 20, 20)
class DownloadIconButton(IconButton): icon = QIcon(get_image_path("downloads.png"))
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
seemingly random eliding of the root item, if the checkbox is added to the first column. 5. Without border-bottom set, checkbox images overlap the text of their column In other words, the only place where it works is *right before showing results*, p.s: putting *any* styling for ::indicator thing into the .ui file result in broken styling. """ TORRENT_FILES_TREE_STYLESHEET_NO_ITEM = """ TorrentFileTreeWidget::indicator { width: 18px; height: 18px;} TorrentFileTreeWidget::indicator:checked { image: url("%s"); } TorrentFileTreeWidget::indicator:unchecked { image: url("%s"); } TorrentFileTreeWidget::indicator:indeterminate { image: url("%s"); } TorrentFileTreeWidget { border: none; font-size: 13px; } TorrentFileTreeWidget::item:hover { background-color: #303030; } """ % ( get_image_path('toggle-checked.svg', convert_slashes_to_forward=True), get_image_path('toggle-unchecked.svg', convert_slashes_to_forward=True), get_image_path('toggle-undefined.svg', convert_slashes_to_forward=True), ) # Note the amount of padding is aligned to the size of progress bars to give both list variants # (with and without progress bars) a similiar look TORRENT_FILES_TREE_STYLESHEET = (TORRENT_FILES_TREE_STYLESHEET_NO_ITEM + """ TorrentFileTreeWidget::item { color: white; padding-top: 7px; padding-bottom: 7px; } """) class DownloadFileTreeWidgetItem(QTreeWidgetItem): def __init__(self, parent, file_size=None,
def initialize_player(self): vlc_available = True vlc = None try: from tribler_gui import vlc except OSError: vlc_available = False if vlc and vlc.plugin_path: os.environ['VLC_PLUGIN_PATH'] = vlc.plugin_path if not vlc_available: self.window().vlc_available = False self.window().left_menu_button_video_player.setHidden(True) return self.instance = vlc.Instance() if not self.instance: self.window().vlc_available = False self.window().left_menu_button_video_player.setHidden(True) return self.mediaplayer = self.instance.media_player_new() self.window().video_player_widget.should_hide_video_widgets.connect(self.hide_video_widgets) self.window().video_player_widget.should_show_video_widgets.connect(self.show_video_widgets) #self.window().video_player_position_slider.should_change_video_position.connect( # self.on_should_change_video_time #) self.window().video_player_volume_slider.valueChanged.connect(self.on_volume_change) self.window().video_player_volume_slider.setValue(self.mediaplayer.audio_get_volume()) self.window().video_player_volume_slider.setFixedWidth(0) self.window().video_player_play_pause_button.clicked.connect(self.on_play_pause_button_click) self.window().video_player_stop_button.clicked.connect(self.on_stop_button_click) self.window().video_player_volume_button.clicked.connect(self.on_volume_button_click) self.window().video_player_full_screen_button.clicked.connect(self.on_full_screen_button_click) # Create play/pause and volume button images self.play_icon = QIcon(QPixmap(get_image_path("play.png"))) self.pause_icon = QIcon(QPixmap(get_image_path("pause.png"))) self.stop_icon = QIcon(QPixmap(get_image_path("stop.png"))) self.volume_on_icon = QIcon(QPixmap(get_image_path("volume_on.png"))) self.volume_off_icon = QIcon(QPixmap(get_image_path("volume_off.png"))) self.window().video_player_play_pause_button.setIcon(self.play_icon) self.window().video_player_stop_button.setIcon(self.stop_icon) self.window().video_player_volume_button.setIcon(self.volume_on_icon) self.window().video_player_full_screen_button.setIcon(QIcon(QPixmap(get_image_path("full_screen.png")))) self.window().video_player_info_button.setIcon(QIcon(QPixmap(get_image_path("info.png")))) self.window().video_player_info_button.hide() if sys.platform.startswith('linux'): self.mediaplayer.set_xwindow(self.window().video_player_widget.winId()) elif sys.platform == "win32": self.mediaplayer.set_hwnd(self.window().video_player_widget.winId()) elif sys.platform == "darwin": self.mediaplayer.set_nsobject(int(self.window().video_player_widget.winId())) self.manager = self.mediaplayer.event_manager() self.manager.event_attach(vlc.EventType.MediaPlayerBuffering, self.on_vlc_player_buffering) self.manager.event_attach(vlc.EventType.MediaPlayerPlaying, self.on_vlc_player_playing) self.manager.event_attach(vlc.EventType.MediaPlayerPositionChanged, self.on_vlc_player_position_changed) self.update_timer = QTimer() self.update_timer.timeout.connect(self.on_update_timer_tick) self.update_timer.start(500) self.window().left_menu_playlist.playing_item_change.connect(self.change_playing_index) # now we have a buffering mechanism. so dont initiate the play without buffering # self.window().left_menu_playlist.item_should_play.connect(self.on_play_pause_button_click) self.window().left_menu_playlist.list_loaded.connect(self.on_files_list_loaded) self.window().video_player_play_pause_button.setEnabled(False) self.window().video_player_stop_button.setEnabled(False)