示例#1
0
    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; }"
        )
示例#2
0
    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()
示例#3
0
 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,
     )
示例#4
0
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
示例#5
0
    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()
示例#6
0
    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)
示例#8
0
    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()
示例#9
0
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
示例#10
0
    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
示例#11
0
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
示例#12
0
    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)
示例#13
0
    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)
示例#14
0
    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()
示例#15
0
    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()
示例#16
0
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)
示例#18
0
    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()
示例#19
0
    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)
示例#20
0
    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
示例#21
0
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'
示例#22
0
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
示例#23
0
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)
示例#24
0
class DeleteIconButton(IconButton):
    icon = QIcon(get_image_path("trash.svg"))

    def should_draw(self, index):
        return index.model().edit_enabled
示例#25
0
    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)
示例#26
0
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)
示例#27
0
class DownloadIconButton(IconButton):
    icon = QIcon(get_image_path("downloads.png"))
示例#28
0
    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
示例#29
0
     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,
示例#30
0
    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)