コード例 #1
0
ファイル: editchannelpage.py プロジェクト: zippav/tribler
 def add_dir_to_channel(self, dirname, recursive=False):
     post_data = {"torrents_dir": dirname, "recursive": int(recursive)}
     request_mgr = TriblerRequestManager()
     request_mgr.perform_request("mychannel/torrents",
                                 self.on_torrent_to_channel_added,
                                 method='PUT',
                                 data=post_data)
コード例 #2
0
ファイル: tribler_window.py プロジェクト: unoffices/tribler
    def perform_start_download_request(self, uri, anon_download, safe_seeding, destination, selected_files,
                                       total_files=0, callback=None):
        selected_files_uri = ""
        if len(selected_files) != total_files:  # Not all files included
            selected_files_uri = u'&' + u''.join(u"selected_files[]=%s&" % file for file in selected_files)[:-1]

        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=%s&anon_hops=%d&safe_seeding=%d&destination=%s%s" % (uri, anon_hops, safe_seeding,
                                                                                   destination, selected_files_uri)
        post_data = post_data.encode('utf-8')  # We need to send bytes in the request, not unicode

        request_mgr = TriblerRequestManager()
        self.pending_requests[request_mgr.request_id] = request_mgr
        request_mgr.perform_request("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 []
        encoded_destination = destination.encode('hex')
        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))
コード例 #3
0
ファイル: editchannelpage.py プロジェクト: Tribler/tribler
 def add_torrent_to_channel(self, filename):
     with open(filename, "rb") as torrent_file:
         torrent_content = b64encode(torrent_file.read())
         request_mgr = TriblerRequestManager()
         request_mgr.perform_request("mychannel/torrents",
                                     self.on_torrent_to_channel_added, method='PUT',
                                     data={"torrent": torrent_content})
コード例 #4
0
ファイル: editchannelpage.py プロジェクト: Tribler/tribler
    def on_torrents_remove_all_action(self, action):
        if action == 0:
            request_mgr = TriblerRequestManager()
            request_mgr.perform_request("mychannel/torrents", self.on_all_torrents_removed_response, method='DELETE')

        self.dialog.close_dialog()
        self.dialog = None
コード例 #5
0
ファイル: editchannelpage.py プロジェクト: zippav/tribler
 def add_torrent_url_to_channel(self, url):
     post_data = {"uri": url}
     request_mgr = TriblerRequestManager()
     request_mgr.perform_request("mychannel/torrents",
                                 self.on_torrent_to_channel_added,
                                 method='PUT',
                                 data=post_data)
コード例 #6
0
    def perform_start_download_request(self,
                                       uri,
                                       anon_download,
                                       safe_seeding,
                                       destination,
                                       selected_files,
                                       total_files=0):
        selected_files_uri = ""
        if len(selected_files) != total_files:  # Not all files included
            selected_files_uri = '&' + ''.join(
                u"selected_files[]=%s&" % file
                for file in selected_files)[:-1].encode('utf-8')

        anon_hops = int(self.tribler_settings['Tribler']
                        ['default_number_hops']) if anon_download else 0
        safe_seeding = 1 if safe_seeding else 0
        post_data = str(
            "uri=%s&anon_hops=%d&safe_seeding=%d&destination=%s%s" %
            (uri, anon_hops, safe_seeding, destination, selected_files_uri))
        request_mgr = TriblerRequestManager()
        self.pending_requests[request_mgr.request_id] = request_mgr
        request_mgr.perform_request("downloads",
                                    self.on_download_added,
                                    method='PUT',
                                    data=post_data)
コード例 #7
0
ファイル: editchannelpage.py プロジェクト: synctext/tribler
 def add_torrent_to_channel(self, filename):
     with open(filename, "rb") as torrent_file:
         torrent_content = urllib.quote_plus(base64.b64encode(torrent_file.read()))
         editchannel_request_mgr = TriblerRequestManager()
         editchannel_request_mgr.perform_request("channels/discovered/%s/torrents" %
                                                      self.channel_overview['identifier'],
                                                      self.on_torrent_to_channel_added, method='PUT',
                                                      data='torrent=%s' % torrent_content)
コード例 #8
0
ファイル: editchannelpage.py プロジェクト: zippav/tribler
 def add_torrent_to_channel(self, filename):
     with open(filename, "rb") as torrent_file:
         torrent_content = b64encode(torrent_file.read())
         request_mgr = TriblerRequestManager()
         request_mgr.perform_request("mychannel/torrents",
                                     self.on_torrent_to_channel_added,
                                     method='PUT',
                                     data={"torrent": torrent_content})
コード例 #9
0
ファイル: editchannelpage.py プロジェクト: Tribler/tribler
 def add_dir_to_channel(self, dirname, recursive=False):
     post_data = {
         "torrents_dir": dirname,
         "recursive": int(recursive)
     }
     request_mgr = TriblerRequestManager()
     request_mgr.perform_request("mychannel/torrents",
                                 self.on_torrent_to_channel_added, method='PUT', data=post_data)
コード例 #10
0
ファイル: tribler_window.py プロジェクト: yws/tribler
    def perform_start_download_request(self,
                                       uri,
                                       anon_download,
                                       safe_seeding,
                                       destination,
                                       selected_files,
                                       total_files=0,
                                       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_uri = ""
        if len(selected_files) != total_files:  # Not all files included
            selected_files_uri = u'&' + u''.join(
                u"selected_files[]=%s&" % quote_plus_unicode(filename)
                for filename in selected_files)[:-1]

        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=%s&anon_hops=%d&safe_seeding=%d&destination=%s%s" % (
            quote_plus_unicode(uri), anon_hops, safe_seeding, destination,
            selected_files_uri)
        post_data = post_data.encode(
            'utf-8')  # We need to send bytes in the request, not unicode

        request_mgr = TriblerRequestManager()
        request_mgr.perform_request(
            "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, unicode):
            destination = destination.encode('utf-8')
        encoded_destination = destination.encode('hex')
        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))
コード例 #11
0
class SubscribedChannelsPage(QWidget):
    """
    This page shows all the channels that the user has subscribed to.
    """

    def __init__(self):
        QWidget.__init__(self)

        self.dialog = None
        self.request_mgr = None

    def initialize(self):
        self.window().add_subscription_button.clicked.connect(self.on_add_subscription_clicked)

    def load_subscribed_channels(self):
        self.window().subscribed_channels_list.set_data_items([(LoadingListItem, None)])

        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("channels/subscribed", self.received_subscribed_channels)

    def received_subscribed_channels(self, results):
        if not results:
            return
        self.window().subscribed_channels_list.set_data_items([])
        items = []

        if len(results['subscribed']) == 0:
            self.window().subscribed_channels_list.set_data_items(
                [(LoadingListItem, "You are not subscribed to any channel.")])
            return

        for result in results['subscribed']:
            items.append((ChannelListItem, result))
        self.window().subscribed_channels_list.set_data_items(items)

    def on_add_subscription_clicked(self):
        self.dialog = ConfirmationDialog(self, "Add subscribed channel",
                                         "Please enter the identifier of the channel you want to subscribe to below. "
                                         "It can take up to a minute before the channel is visible in your list of "
                                         "subscribed channels.",
                                         [('ADD', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)],
                                         show_input=True)
        self.dialog.dialog_widget.dialog_input.setPlaceholderText('Channel identifier')
        self.dialog.button_clicked.connect(self.on_subscription_added)
        self.dialog.show()

    def on_subscription_added(self, action):
        if action == 0:
            self.request_mgr = TriblerRequestManager()
            self.request_mgr.perform_request("channels/subscribed/%s" % self.dialog.dialog_widget.dialog_input.text(),
                                             self.on_channel_subscribed, method='PUT')

        self.dialog.close_dialog()
        self.dialog = None

    def on_channel_subscribed(self, _):
        pass
コード例 #12
0
ファイル: editchannelpage.py プロジェクト: zippav/tribler
    def on_torrents_remove_all_action(self, action):
        if action == 0:
            request_mgr = TriblerRequestManager()
            request_mgr.perform_request("mychannel/torrents",
                                        self.on_all_torrents_removed_response,
                                        method='DELETE')

        self.dialog.close_dialog()
        self.dialog = None
コード例 #13
0
    def perform_start_download_request(self,
                                       uri,
                                       anon_download,
                                       safe_seeding,
                                       destination,
                                       selected_files,
                                       total_files=0,
                                       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
        }
        request_mgr = TriblerRequestManager()
        request_mgr.perform_request(
            "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, six.text_type):
            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))
コード例 #14
0
ファイル: lazytableview.py プロジェクト: zippav/tribler
    def on_commit_control_clicked(self, index):
        infohash = index.model().data_items[index.row()][u'infohash']
        status = index.model().data_items[index.row()][u'status']

        new_status = COMMIT_STATUS_COMMITTED
        if status == COMMIT_STATUS_NEW or status == COMMIT_STATUS_COMMITTED:
            new_status = COMMIT_STATUS_TODELETE

        request_mgr = TriblerRequestManager()
        request_mgr.perform_request("mychannel/torrents/%s" % infohash,
                                    lambda response: self.on_torrent_status_updated(response, index),
                                    data={"status": new_status}, method='PATCH')
コード例 #15
0
ファイル: editchannelpage.py プロジェクト: ildella/tribler
    def on_torrents_remove_all_action(self, action):
        if action == 0:
            for torrent_ind in xrange(self.window().edit_channel_torrents_list.count()):
                torrent_data = self.window().edit_channel_torrents_list.item(torrent_ind).data(Qt.UserRole)
                request_mgr = TriblerRequestManager()
                request_mgr.perform_request("channels/discovered/%s/torrents/%s" %
                                            (self.channel_overview["identifier"], torrent_data['infohash']),
                                            None, method='DELETE')
                self.remove_torrent_requests.append(request_mgr)

            self.window().edit_channel_torrents_list.set_data_items([])

        self.dialog.close_dialog()
        self.dialog = None
コード例 #16
0
class DiscoveredPage(QWidget):
    """
    The DiscoveredPage shows an overview of all discovered channels in Tribler.
    """
    def __init__(self):
        QWidget.__init__(self)
        self.discovered_channels = []
        self.request_mgr = None
        self.initialized = False

    def initialize_discovered_page(self):
        if not self.initialized:
            self.window(
            ).core_manager.events_manager.discovered_channel.connect(
                self.on_discovered_channel)
            self.initialized = True

    def load_discovered_channels(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("channels/discovered",
                                         self.received_discovered_channels)

    def received_discovered_channels(self, results):
        if not results or 'channels' not in results:
            return

        self.discovered_channels = []
        self.window().discovered_channels_list.set_data_items([])
        items = []

        results['channels'].sort(key=lambda x: x['torrents'], reverse=True)

        for result in results['channels']:
            items.append((ChannelListItem, result))
            self.discovered_channels.append(result)
            self.update_num_label()
        self.window().discovered_channels_list.set_data_items(items)

    def on_discovered_channel(self, channel_info):
        channel_info['torrents'] = 0
        channel_info['subscribed'] = False
        channel_info['votes'] = 0
        self.window().discovered_channels_list.append_item(
            (ChannelListItem, channel_info))
        self.discovered_channels.append(channel_info)
        self.update_num_label()

    def update_num_label(self):
        self.window().num_discovered_channels_label.setText(
            "%d items" % len(self.discovered_channels))
コード例 #17
0
 def on_save_clicked(self):
     self.requests_done = 0
     self.pending_requests = []
     for torrent in self.torrents_to_create:
         request = TriblerRequestManager()
         request.perform_request("channels/discovered/%s/playlists/%s/%s" %
                                 (self.channel_info["identifier"], self.playlist_info['id'],
                                  torrent['infohash']), self.on_request_done, method="PUT")
         self.pending_requests.append(request)
     for torrent in self.torrents_to_remove:
         request = TriblerRequestManager()
         request.perform_request("channels/discovered/%s/playlists/%s/%s" %
                                 (self.channel_info["identifier"], self.playlist_info['id'], torrent['infohash']),
                                 self.on_request_done, method="DELETE")
         self.pending_requests.append(request)
コード例 #18
0
ファイル: lazytableview.py プロジェクト: zippav/tribler
 def on_subscribe_control_clicked(self, index):
     item = index.model().data_items[index.row()]
     # skip LEGACY entries, regular torrents and personal channel
     if (u'subscribed' not in item or
             item[u'status'] == 1000 or
             item[u'my_channel']):
         return
     status = int(item[u'subscribed'])
     public_key = item[u'public_key']
     request_mgr = TriblerRequestManager()
     request_mgr.perform_request("metadata/channels/%s" % public_key,
                                 (lambda _: self.on_unsubscribed_channel.emit(index)) if status else
                                 (lambda _: self.on_subscribed_channel.emit(index)),
                                 data={"subscribe": int(not status)}, method='POST')
     index.model().data_items[index.row()][u'subscribed'] = int(not status)
コード例 #19
0
ファイル: manageplaylistpage.py プロジェクト: brussee/tribler
 def on_save_clicked(self):
     self.requests_done = 0
     self.pending_requests = []
     for torrent in self.torrents_to_create:
         request = TriblerRequestManager()
         request.perform_request("channels/discovered/%s/playlists/%s/%s" %
                                 (self.channel_info["identifier"], self.playlist_info['id'],
                                  torrent['infohash']), self.on_request_done, method="PUT")
         self.pending_requests.append(request)
     for torrent in self.torrents_to_remove:
         request = TriblerRequestManager()
         request.perform_request("channels/discovered/%s/playlists/%s/%s" %
                                 (self.channel_info["identifier"], self.playlist_info['id'], torrent['infohash']),
                                 self.on_request_done, method="DELETE")
         self.pending_requests.append(request)
コード例 #20
0
ファイル: editchannelpage.py プロジェクト: synctext/tribler
    def on_torrents_remove_all_action(self, action):
        if action == 0:
            for torrent_ind in xrange(self.window().edit_channel_torrents_list.count()):
                torrent_data = self.window().edit_channel_torrents_list.item(torrent_ind).data(Qt.UserRole)
                request_mgr = TriblerRequestManager()
                request_mgr.perform_request("channels/discovered/%s/torrents/%s" %
                                            (self.channel_overview["identifier"], torrent_data['infohash']),
                                            None, method='DELETE')
                self.remove_torrent_requests.append(request_mgr)

            self.window().edit_channel_torrents_list.set_data_items([])
            if "chant" in self.channel_overview:
                self.load_channel_torrents()

        self.dialog.close_dialog()
        self.dialog = None
コード例 #21
0
ファイル: editchannelpage.py プロジェクト: Tribler/tribler
    def on_torrents_remove_selected_action(self, action, items):
        if action == 0:
            items = [str(item) for item in items]
            infohashes = ",".join(items)

            post_data = {
                "infohashes": infohashes,
                "status": COMMIT_STATUS_TODELETE
            }

            request_mgr = TriblerRequestManager()
            request_mgr.perform_request("mychannel/torrents",
                                        lambda response: self.on_torrents_removed_response(response, items),
                                        data=post_data, method='POST')
        if self.dialog:
            self.dialog.close_dialog()
            self.dialog = None
コード例 #22
0
ファイル: discoveredpage.py プロジェクト: synctext/tribler
class DiscoveredPage(QWidget):
    """
    The DiscoveredPage shows an overview of all discovered channels in Tribler.
    """

    def __init__(self):
        QWidget.__init__(self)
        self.discovered_channels = []
        self.request_mgr = None
        self.initialized = False

    def initialize_discovered_page(self):
        if not self.initialized:
            self.window().core_manager.events_manager.discovered_channel.connect(self.on_discovered_channel)
            self.initialized = True

    def load_discovered_channels(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("channels/discovered", self.received_discovered_channels)

    def received_discovered_channels(self, results):
        if not results or 'channels' not in results:
            return

        self.discovered_channels = []
        self.window().discovered_channels_list.set_data_items([])
        items = []

        results['channels'].sort(key=lambda x: x['torrents'], reverse=True)

        for result in results['channels']:
            items.append((ChannelListItem, result))
            self.discovered_channels.append(result)
            self.update_num_label()
        self.window().discovered_channels_list.set_data_items(items)

    def on_discovered_channel(self, channel_info):
        channel_info['torrents'] = 0
        channel_info['subscribed'] = False
        channel_info['votes'] = 0
        self.window().discovered_channels_list.append_item((ChannelListItem, channel_info))
        self.discovered_channels.append(channel_info)
        self.update_num_label()

    def update_num_label(self):
        self.window().num_discovered_channels_label.setText("%d items" % len(self.discovered_channels))
コード例 #23
0
ファイル: tribler_window.py プロジェクト: Tribler/tribler
    def perform_start_download_request(self, uri, anon_download, safe_seeding, destination, selected_files,
                                       total_files=0, 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
        }
        request_mgr = TriblerRequestManager()
        request_mgr.perform_request("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, six.text_type):
            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))
コード例 #24
0
ファイル: editchannelpage.py プロジェクト: zippav/tribler
    def on_torrents_remove_selected_action(self, action, items):
        if action == 0:
            items = [str(item) for item in items]
            infohashes = ",".join(items)

            post_data = {
                "infohashes": infohashes,
                "status": COMMIT_STATUS_TODELETE
            }

            request_mgr = TriblerRequestManager()
            request_mgr.perform_request(
                "mychannel/torrents",
                lambda response: self.on_torrents_removed_response(
                    response, items),
                data=post_data,
                method='POST')
        if self.dialog:
            self.dialog.close_dialog()
            self.dialog = None
コード例 #25
0
class MyTorrentsTableViewController(TorrentsTableViewController):
    """
    This class manages the list with the torrents in your own channel.
    """
    def __init__(self, *args, **kwargs):
        super(MyTorrentsTableViewController, self).__init__(*args, **kwargs)
        self.model.row_edited.connect(self._on_row_edited)

    def _on_row_edited(self, index, new_value):
        infohash = self.model.data_items[index.row()][u'infohash']
        attribute_name = self.model.columns[index.column()]
        attribute_name = u'tags' if attribute_name == u'category' else attribute_name
        attribute_name = u'title' if attribute_name == u'name' else attribute_name

        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("mychannel/torrents/%s" % infohash,
                                         self._on_row_update_results,
                                         method='PATCH',
                                         data={attribute_name: new_value})

    def _on_row_update_results(self, response):
        if response:
            self.table_view.window(
            ).edit_channel_page.channel_dirty = response['dirty']
            self.table_view.window(
            ).edit_channel_page.update_channel_commit_views()

    def perform_query(self, **kwargs):
        kwargs.update({
            "rest_endpoint_url": "mychannel/torrents",
            "exclude_deleted": self.model.exclude_deleted
        })
        super(MyTorrentsTableViewController, self).perform_query(**kwargs)

    def on_query_results(self, response):
        if super(MyTorrentsTableViewController,
                 self).on_query_results(response):
            self.table_view.window(
            ).edit_channel_page.channel_dirty = response['dirty']
            self.table_view.window(
            ).edit_channel_page.update_channel_commit_views()
コード例 #26
0
ファイル: tribler_window.py プロジェクト: synctext/tribler
    def perform_start_download_request(self, uri, anon_download, safe_seeding, destination, selected_files,
                                       total_files=0, 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_uri = ""
        if len(selected_files) != total_files:  # Not all files included
            selected_files_uri = u'&' + u''.join(u"selected_files[]=%s&" %
                                                 quote_plus_unicode(filename) for filename in selected_files)[:-1]

        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=%s&anon_hops=%d&safe_seeding=%d&destination=%s%s" % (quote_plus_unicode(uri), anon_hops,
                                                                              safe_seeding, destination,
                                                                              selected_files_uri)
        post_data = post_data.encode('utf-8')  # We need to send bytes in the request, not unicode

        request_mgr = TriblerRequestManager()
        request_mgr.perform_request("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, unicode):
            destination = destination.encode('utf-8')
        encoded_destination = destination.encode('hex')
        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))
コード例 #27
0
class MyTorrentsTableViewController(TorrentsTableViewController):
    """
    This class manages the list with the torrents in your own channel.
    """

    def __init__(self, *args, **kwargs):
        super(MyTorrentsTableViewController, self).__init__(*args, **kwargs)
        self.model.row_edited.connect(self._on_row_edited)

    def _on_row_edited(self, index, new_value):
        infohash = self.model.data_items[index.row()][u'infohash']
        attribute_name = self.model.columns[index.column()]
        attribute_name = u'tags' if attribute_name == u'category' else attribute_name
        attribute_name = u'title' if attribute_name == u'name' else attribute_name

        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request(
            "mychannel/torrents/%s" % infohash,
            self._on_row_update_results,
            method='PATCH',
            data={attribute_name: new_value})

    def _on_row_update_results(self, response):
        if response:
            self.table_view.window().edit_channel_page.channel_dirty = response['dirty']
            self.table_view.window().edit_channel_page.update_channel_commit_views()

    def perform_query(self, **kwargs):
        kwargs.update({
            "rest_endpoint_url": "mychannel/torrents",
            "exclude_deleted": self.model.exclude_deleted})
        super(MyTorrentsTableViewController, self).perform_query(**kwargs)

    def on_query_results(self, response):
        if super(MyTorrentsTableViewController, self).on_query_results(response):
            self.table_view.window().edit_channel_page.channel_dirty = response['dirty']
            self.table_view.window().edit_channel_page.update_channel_commit_views()
コード例 #28
0
ファイル: lazytableview.py プロジェクト: Tribler/tribler
 def on_delete_button_clicked(self, index):
     request_mgr = TriblerRequestManager()
     request_mgr.perform_request("mychannel/torrents/%s" % index.model().data_items[index.row()][u'infohash'],
                                 lambda response: self.on_torrent_status_updated(response, index),
                                 data={"status" : COMMIT_STATUS_TODELETE}, method='PATCH')
コード例 #29
0
class TorrentDetailsTabWidget(QTabWidget):
    """
    The TorrentDetailsTabWidget is the tab that provides details about a specific selected torrent. This information
    includes the generic info about the torrent, files and trackers.
    """

    def __init__(self, parent):
        QTabWidget.__init__(self, parent)
        self.torrent_info = None
        self._logger = logging.getLogger("TriberGUI")

        self.torrent_detail_name_label = None
        self.torrent_detail_category_label = None
        self.torrent_detail_size_label = None
        self.torrent_detail_health_label = None
        self.torrent_detail_files_list = None
        self.torrent_detail_trackers_list = None
        self.check_health_button = None
        self.request_mgr = None
        self.health_request_mgr = None
        self.is_health_checking = False
        self.last_health_check_ts = -1

    def initialize_details_widget(self):
        """
        Initialize the details widget. We need to manually assign these attributes since we're dynamically loading
        this view (using uic.loadUI).
        """
        self.torrent_detail_name_label = self.findChild(QLabel, "torrent_detail_name_label")
        self.torrent_detail_category_label = self.findChild(QLabel, "torrent_detail_category_label")
        self.torrent_detail_size_label = self.findChild(QLabel, "torrent_detail_size_label")
        self.torrent_detail_health_label = self.findChild(QLabel, "torrent_detail_health_label")
        self.torrent_detail_files_list = self.findChild(QTreeWidget, "torrent_detail_files_list")
        self.torrent_detail_trackers_list = self.findChild(QTreeWidget, "torrent_detail_trackers_list")
        self.setCurrentIndex(0)

        self.check_health_button = self.findChild(EllipseButton, "check_health_button")
        self.check_health_button.clicked.connect(lambda: self.on_check_health_clicked(timeout=15))

    def on_torrent_info(self, torrent_info):
        if not torrent_info:
            return
        self.setTabEnabled(1, True)
        self.setTabEnabled(2, True)

        self.torrent_detail_files_list.clear()
        self.torrent_detail_trackers_list.clear()

        for file_info in torrent_info["files"]:
            item = QTreeWidgetItem(self.torrent_detail_files_list)
            item.setText(0, file_info["path"])
            item.setText(1, format_size(float(file_info["size"])))

        for tracker in torrent_info["trackers"]:
            if tracker == 'DHT':
                continue
            item = QTreeWidgetItem(self.torrent_detail_trackers_list)
            item.setText(0, tracker)

        if torrent_info["num_seeders"] > 0:
            self.torrent_detail_health_label.setText("good health (S%d L%d)" % (torrent_info["num_seeders"],
                                                                                torrent_info["num_leechers"]))
        elif torrent_info["num_leechers"] > 0:
            self.torrent_detail_health_label.setText("unknown health (found peers)")
        else:
            self.torrent_detail_health_label.setText("no peers found")

    def update_with_torrent(self, torrent_info):
        self.torrent_info = torrent_info
        self.is_health_checking = False
        self.torrent_detail_name_label.setText(self.torrent_info["name"])
        if self.torrent_info["category"]:
            self.torrent_detail_category_label.setText(self.torrent_info["category"].lower())
        else:
            self.torrent_detail_category_label.setText("unknown")

        if self.torrent_info["size"] is None:
            self.torrent_detail_size_label.setText("Size: -")
        else:
            self.torrent_detail_size_label.setText("%s" % format_size(float(self.torrent_info["size"])))

        if self.torrent_info["num_seeders"] > 0:
            self.torrent_detail_health_label.setText("good health (S%d L%d)" % (self.torrent_info["num_seeders"],
                                                                                self.torrent_info["num_leechers"]))
        elif self.torrent_info["num_leechers"] > 0:
            self.torrent_detail_health_label.setText("unknown health (found peers)")
        else:
            self.torrent_detail_health_label.setText("no peers found")

        self.setCurrentIndex(0)
        self.setTabEnabled(1, False)
        self.setTabEnabled(2, False)

        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("torrents/%s" % self.torrent_info["infohash"], self.on_torrent_info)

    def on_check_health_clicked(self, timeout=15):
        if self.is_health_checking and (time.time() - self.last_health_check_ts < timeout):
            return

        self.is_health_checking = True
        self.torrent_detail_health_label.setText("Checking...")
        self.last_health_check_ts = time.time()
        self.health_request_mgr = TriblerRequestManager()
        self.health_request_mgr.perform_request("torrents/%s/health?timeout=%s&refresh=%d" %
                                                (self.torrent_info["infohash"], timeout, 1),
                                                self.on_health_response, capture_errors=False, priority="LOW",
                                                on_cancel=self.on_cancel_health_check)

    def on_health_response(self, response):
        if not response:
            return
        total_seeders = 0
        total_leechers = 0

        if not response or 'error' in response:
            self.update_health(0, 0)  # Just set the health to 0 seeders, 0 leechers
            return

        for _, status in response['health'].iteritems():
            if 'error' in status:
                continue  # Timeout or invalid status

            total_seeders += int(status['seeders'])
            total_leechers += int(status['leechers'])

        self.is_health_checking = False
        self.update_health(total_seeders, total_leechers)

    def update_health(self, seeders, leechers):
        try:
            if seeders > 0:
                self.torrent_detail_health_label.setText("good health (S%d L%d)" % (seeders, leechers))
            elif leechers > 0:
                self.torrent_detail_health_label.setText("unknown health (found peers)")
            else:
                self.torrent_detail_health_label.setText("no peers found")
        except RuntimeError:
            self._logger.error("The underlying GUI widget has already been removed.")

    def on_cancel_health_check(self):
        self.is_health_checking = False
コード例 #30
0
ファイル: editchannelpage.py プロジェクト: zippav/tribler
class EditChannelPage(QWidget):
    """
    This class is responsible for managing lists and data on your channel page
    """
    on_torrents_removed = pyqtSignal(list)
    on_all_torrents_removed = pyqtSignal()
    on_commit = pyqtSignal()

    def __init__(self):
        QWidget.__init__(self)

        self.channel_overview = None
        self.chosen_dir = None
        self.dialog = None
        self.editchannel_request_mgr = None
        self.model = None
        self.controller = None
        self.channel_dirty = False
        self.gui_settings = None
        self.commit_timer = None
        self.autocommit_enabled = None

    def initialize_edit_channel_page(self, gui_settings):
        self.gui_settings = gui_settings

        self.window().create_channel_intro_button.clicked.connect(
            self.on_create_channel_intro_button_clicked)

        self.window().create_channel_form.hide()
        self.update_channel_commit_views()

        self.window().edit_channel_stacked_widget.setCurrentIndex(1)
        self.window().edit_channel_details_stacked_widget.setCurrentIndex(
            PAGE_EDIT_CHANNEL_OVERVIEW)

        self.window().create_channel_button.clicked.connect(
            self.on_create_channel_button_pressed)
        self.window().edit_channel_save_button.clicked.connect(
            self.on_edit_channel_save_button_pressed)
        self.window().edit_channel_commit_button.clicked.connect(
            self.clicked_edit_channel_commit_button)

        # Tab bar buttons
        self.window().channel_settings_tab.initialize()
        self.window().channel_settings_tab.clicked_tab_button.connect(
            self.clicked_tab_button)

        self.window().export_channel_button.clicked.connect(
            self.on_export_mdblob)

        # TODO: re-enable remove_selected button
        self.window().remove_selected_button.setHidden(True)

        # Connect torrent addition/removal buttons
        self.window().remove_selected_button.clicked.connect(
            self.on_torrents_remove_selected_clicked)
        self.window().remove_all_button.clicked.connect(
            self.on_torrents_remove_all_clicked)
        self.window().add_button.clicked.connect(self.on_torrents_add_clicked)

        self.model = MyTorrentsContentModel()
        self.controller = MyTorrentsTableViewController(
            self.model,
            self.window().edit_channel_torrents_container.content_table,
            self.window().edit_channel_torrents_container.details_container,
            self.window().edit_channel_torrents_num_items_label,
            self.window().edit_channel_torrents_filter)
        self.window().edit_channel_torrents_container.details_container.hide()
        self.autocommit_enabled = get_gui_setting(
            self.gui_settings, "autocommit_enabled", True,
            is_bool=True) if self.gui_settings else True

        # Commit the channel just in case there are uncommitted changes left since the last time (e.g. Tribler crashed)
        # The timer thing here is a workaround for race condition with the core startup
        if self.autocommit_enabled:
            if not self.commit_timer:
                self.commit_timer = QTimer()
                self.commit_timer.setSingleShot(True)
                self.commit_timer.timeout.connect(self.autocommit_fired)

            self.controller.table_view.setColumnHidden(3, True)
            self.model.exclude_deleted = True
            self.commit_timer.stop()
            self.commit_timer.start(10000)
        else:
            self.controller.table_view.setColumnHidden(4, True)
            self.model.exclude_deleted = False

    def update_channel_commit_views(self, deleted_index=None):
        if self.channel_dirty and self.autocommit_enabled:
            self.commit_timer.stop()
            self.commit_timer.start(CHANNEL_COMMIT_DELAY)
            if deleted_index:
                # TODO: instead of reloading the whole table, just remove the deleted row and update start and end
                self.load_my_torrents()

        self.window().commit_control_bar.setHidden(not self.channel_dirty
                                                   or self.autocommit_enabled)

    def load_my_channel_overview(self):
        if not self.channel_overview:
            self.window().edit_channel_stacked_widget.setCurrentIndex(2)

        self.editchannel_request_mgr = TriblerRequestManager()
        self.editchannel_request_mgr.perform_request(
            "mychannel",
            self.initialize_with_channel_overview,
            capture_errors=False)

    def initialize_with_channel_overview(self, overview):
        if not overview:
            return
        if 'error' in overview:
            self.window().edit_channel_stacked_widget.setCurrentIndex(0)
            return

        self.channel_overview = overview["mychannel"]
        self.channel_dirty = self.channel_overview['dirty']
        self.update_channel_commit_views()

        self.window().export_channel_button.setHidden(False)
        self.window().edit_channel_name_label.setText("My channel")

        self.window().edit_channel_overview_name_label.setText(
            self.channel_overview["name"])
        self.window().edit_channel_description_label.setText(
            self.channel_overview["description"])
        self.window().edit_channel_identifier_label.setText(
            self.channel_overview["public_key"])

        self.window().edit_channel_name_edit.setText(
            self.channel_overview["name"])
        self.window().edit_channel_description_edit.setText(
            self.channel_overview["description"])

        self.window().edit_channel_stacked_widget.setCurrentIndex(1)

        self.model.channel_pk = self.channel_overview["public_key"]

    def on_create_channel_button_pressed(self):
        channel_name = self.window().new_channel_name_edit.text()
        channel_description = self.window(
        ).new_channel_description_edit.toPlainText()
        if len(channel_name) == 0:
            self.window().new_channel_name_label.setStyleSheet("color: red;")
            return

        post_data = {"name": channel_name, "description": channel_description}
        self.editchannel_request_mgr = TriblerRequestManager()
        self.editchannel_request_mgr.perform_request("mychannel",
                                                     self.on_channel_created,
                                                     data=post_data,
                                                     method='PUT')

    def on_channel_created(self, result):
        if not result:
            return
        if u'added' in result:
            self.window().create_channel_button.setEnabled(True)
            self.load_my_channel_overview()

    def on_edit_channel_save_button_pressed(self):
        channel_name = self.window().edit_channel_name_edit.text()
        channel_description = self.window(
        ).edit_channel_description_edit.toPlainText()
        post_data = {"name": channel_name, "description": channel_description}

        self.editchannel_request_mgr = TriblerRequestManager()
        self.editchannel_request_mgr.perform_request("mychannel",
                                                     self.on_channel_edited,
                                                     data=post_data,
                                                     method='POST')

    def on_channel_edited(self, result):
        if not result:
            return
        if 'modified' in result:
            self.window().edit_channel_name_label.setText(
                self.window().edit_channel_name_edit.text())
            self.window().edit_channel_description_label.setText(
                self.window().edit_channel_description_edit.toPlainText())

    def clicked_tab_button(self, tab_button_name):
        if tab_button_name == "edit_channel_overview_button":
            self.window().edit_channel_details_stacked_widget.setCurrentIndex(
                PAGE_EDIT_CHANNEL_OVERVIEW)
        elif tab_button_name == "edit_channel_settings_button":
            self.window().edit_channel_details_stacked_widget.setCurrentIndex(
                PAGE_EDIT_CHANNEL_SETTINGS)
        elif tab_button_name == "edit_channel_torrents_button":
            self.load_my_torrents()
            self.window().edit_channel_details_stacked_widget.setCurrentIndex(
                PAGE_EDIT_CHANNEL_TORRENTS)

    def load_my_torrents(self):
        self.controller.model.reset()
        self.controller.perform_query(first=1,
                                      last=50)  # Load the first 50 torrents

    def on_create_channel_intro_button_clicked(self):
        self.window().create_channel_form.show()
        self.window().create_channel_intro_button_container.hide()
        self.window().create_new_channel_intro_label.setText(
            "Please enter your channel details below.")

    def on_export_mdblob(self):
        export_dir = QFileDialog.getExistingDirectory(
            self, "Please select the destination directory", "",
            QFileDialog.ShowDirsOnly)

        if len(export_dir) == 0:
            return

        # Show confirmation dialog where we specify the name of the file
        mdblob_name = self.channel_overview["public_key"]
        dialog = ConfirmationDialog(
            self,
            "Export mdblob file",
            "Please enter the name of the channel metadata file:",
            [('SAVE', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)],
            show_input=True)

        def on_export_download_dialog_done(action):
            if action == 0:
                dest_path = os.path.join(
                    export_dir, dialog.dialog_widget.dialog_input.text())
                request_mgr = TriblerRequestManager()
                request_mgr.download_file(
                    "channels/discovered/%s/mdblob" % mdblob_name,
                    lambda data: on_export_download_request_done(
                        dest_path, data))

            dialog.close_dialog()

        def on_export_download_request_done(dest_path, data):
            try:
                torrent_file = open(dest_path, "wb")
                torrent_file.write(data)
                torrent_file.close()
            except IOError as exc:
                ConfirmationDialog.show_error(
                    self.window(), "Error when exporting file",
                    "An error occurred when exporting the torrent file: %s" %
                    str(exc))
            else:
                self.window().tray_show_message(
                    "Torrent file exported",
                    "Torrent file exported to %s" % dest_path)

        dialog.dialog_widget.dialog_input.setPlaceholderText(
            'Channel file name')
        dialog.dialog_widget.dialog_input.setText("%s.mdblob" % mdblob_name)
        dialog.dialog_widget.dialog_input.setFocus()
        dialog.button_clicked.connect(on_export_download_dialog_done)
        dialog.show()

    # Torrent removal-related methods
    def on_torrents_remove_selected_clicked(self):
        selected_items = self.controller.table_view.selectedIndexes()
        num_selected = len(selected_items)
        if num_selected == 0:
            return

        selected_infohashes = [
            self.model.data_items[row][u'infohash']
            for row in set([index.row() for index in selected_items])
        ]
        self.dialog = ConfirmationDialog(
            self, "Remove %s selected torrents" % len(selected_infohashes),
            "Are you sure that you want to remove %s selected torrents "
            "from your channel?" % len(selected_infohashes),
            [('CONFIRM', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)])
        self.dialog.button_clicked.connect(
            lambda action: self.on_torrents_remove_selected_action(
                action, selected_infohashes))
        self.dialog.show()

    def on_torrents_remove_selected_action(self, action, items):
        if action == 0:
            items = [str(item) for item in items]
            infohashes = ",".join(items)

            post_data = {
                "infohashes": infohashes,
                "status": COMMIT_STATUS_TODELETE
            }

            request_mgr = TriblerRequestManager()
            request_mgr.perform_request(
                "mychannel/torrents",
                lambda response: self.on_torrents_removed_response(
                    response, items),
                data=post_data,
                method='POST')
        if self.dialog:
            self.dialog.close_dialog()
            self.dialog = None

    def on_torrents_removed_response(self, json_result, infohashes):
        if not json_result:
            return

        if 'success' in json_result and json_result['success']:
            self.on_torrents_removed.emit(infohashes)
            self.load_my_torrents()

    def on_torrents_remove_all_clicked(self):
        self.dialog = ConfirmationDialog(
            self.window(), "Remove all torrents",
            "Are you sure that you want to remove all torrents from your channel?",
            [('CONFIRM', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)])
        self.dialog.button_clicked.connect(self.on_torrents_remove_all_action)
        self.dialog.show()

    def on_torrents_remove_all_action(self, action):
        if action == 0:
            request_mgr = TriblerRequestManager()
            request_mgr.perform_request("mychannel/torrents",
                                        self.on_all_torrents_removed_response,
                                        method='DELETE')

        self.dialog.close_dialog()
        self.dialog = None

    def on_all_torrents_removed_response(self, json_result):
        if not json_result:
            return

        if 'success' in json_result and json_result['success']:
            self.on_all_torrents_removed.emit()
            self.load_my_torrents()

    # Torrent addition-related methods
    def on_add_torrents_browse_dir(self):
        chosen_dir = QFileDialog.getExistingDirectory(
            self, "Please select the directory containing the .torrent files",
            QDir.homePath(), QFileDialog.ShowDirsOnly)
        if not chosen_dir:
            return

        self.chosen_dir = chosen_dir
        self.dialog = ConfirmationDialog(
            self,
            "Add torrents from directory",
            "Add all torrent files from the following directory "
            "to your Tribler channel:\n\n%s" % chosen_dir,
            [('ADD', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)],
            checkbox_text="Include subdirectories (recursive mode)")
        self.dialog.button_clicked.connect(
            self.on_confirm_add_directory_dialog)
        self.dialog.show()

    def on_confirm_add_directory_dialog(self, action):
        if action == 0:
            self.add_dir_to_channel(self.chosen_dir,
                                    recursive=self.dialog.checkbox.isChecked())

        if self.dialog:
            self.dialog.close_dialog()
            self.dialog = None
            self.chosen_dir = None

    def on_torrents_add_clicked(self):
        menu = TriblerActionMenu(self)

        browse_files_action = QAction('Import torrent from file', self)
        browse_dir_action = QAction('Import torrent(s) from dir', self)
        add_url_action = QAction('Add torrent from URL/magnet link', self)
        create_torrent_action = QAction('Create torrent from file(s)', self)

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

        menu.addAction(browse_files_action)
        menu.addAction(browse_dir_action)
        menu.addAction(add_url_action)
        menu.addAction(create_torrent_action)

        menu.exec_(QCursor.pos())

    def on_create_torrent_from_files(self):
        self.window().edit_channel_details_create_torrent.initialize()
        self.window().edit_channel_details_stacked_widget.setCurrentIndex(
            PAGE_EDIT_CHANNEL_CREATE_TORRENT)

    def on_add_torrent_browse_file(self):
        filenames = QFileDialog.getOpenFileNames(
            self, "Please select the .torrent file", "",
            "Torrent files (*.torrent)")
        if not filenames[0]:
            return

        for filename in filenames[0]:
            self.add_torrent_to_channel(filename)

    def on_add_torrent_from_url(self):
        self.dialog = ConfirmationDialog(
            self,
            "Add torrent from URL/magnet link",
            "Please enter the URL/magnet link in the field below:",
            [('ADD', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)],
            show_input=True)
        self.dialog.dialog_widget.dialog_input.setPlaceholderText(
            'URL/magnet link')
        self.dialog.button_clicked.connect(
            self.on_torrent_from_url_dialog_done)
        self.dialog.show()

    def on_torrent_from_url_dialog_done(self, action):
        if action == 0:
            self.add_torrent_url_to_channel(
                self.dialog.dialog_widget.dialog_input.text())
        self.dialog.close_dialog()
        self.dialog = None

    def autocommit_fired(self):
        def commit_channel(overview):
            try:
                if overview and overview['mychannel']['dirty']:
                    self.editchannel_request_mgr = TriblerRequestManager()
                    self.editchannel_request_mgr.perform_request(
                        "mychannel/commit",
                        lambda _: None,
                        method='POST',
                        capture_errors=False)
            except KeyError:
                return

        if self.channel_overview:
            self.clicked_edit_channel_commit_button()
        else:
            self.editchannel_request_mgr = TriblerRequestManager()
            self.editchannel_request_mgr.perform_request("mychannel",
                                                         commit_channel,
                                                         capture_errors=False)

    # Commit button-related methods
    def clicked_edit_channel_commit_button(self):
        request_mgr = TriblerRequestManager()
        request_mgr.perform_request("mychannel/commit",
                                    self.on_channel_committed,
                                    method='POST')

    def on_channel_committed(self, result):
        if not result:
            return
        if 'success' in result and result['success']:
            self.channel_dirty = False
            self.update_channel_commit_views()
            self.on_commit.emit()
            if not self.autocommit_enabled:
                self.load_my_torrents()

    def add_torrent_to_channel(self, filename):
        with open(filename, "rb") as torrent_file:
            torrent_content = b64encode(torrent_file.read())
            request_mgr = TriblerRequestManager()
            request_mgr.perform_request("mychannel/torrents",
                                        self.on_torrent_to_channel_added,
                                        method='PUT',
                                        data={"torrent": torrent_content})

    def add_dir_to_channel(self, dirname, recursive=False):
        post_data = {"torrents_dir": dirname, "recursive": int(recursive)}
        request_mgr = TriblerRequestManager()
        request_mgr.perform_request("mychannel/torrents",
                                    self.on_torrent_to_channel_added,
                                    method='PUT',
                                    data=post_data)

    def add_torrent_url_to_channel(self, url):
        post_data = {"uri": url}
        request_mgr = TriblerRequestManager()
        request_mgr.perform_request("mychannel/torrents",
                                    self.on_torrent_to_channel_added,
                                    method='PUT',
                                    data=post_data)

    def on_torrent_to_channel_added(self, result):
        if not result:
            return

        if 'added' in result:
            self.load_my_torrents()
コード例 #31
0
class ManagePlaylistPage(QWidget):
    """
    On this page, users can add or remove torrents from/to a playlist.
    """

    playlist_saved = pyqtSignal()

    def __init__(self):
        QWidget.__init__(self)

        self.channel_info = None
        self.playlist_info = None
        self.request_mgr = None

        self.torrents_in_playlist = []
        self.torrents_in_channel = []

        self.torrents_to_create = []
        self.torrents_to_remove = []

        self.pending_requests = []
        self.requests_done = 0

    def initialize(self, channel_info, playlist_info):
        self.channel_info = channel_info
        self.playlist_info = playlist_info
        self.window().edit_channel_details_manage_playlist_header.setText(
            "Manage torrents in playlist '%s'" % playlist_info['name'])
        self.window().manage_channel_playlist_torrents_back.setIcon(
            QIcon(get_image_path('page_back.png')))

        self.window().playlist_manage_add_to_playlist.clicked.connect(
            self.on_add_clicked)
        self.window().playlist_manage_remove_from_playlist.clicked.connect(
            self.on_remove_clicked)
        self.window().edit_channel_manage_playlist_save_button.clicked.connect(
            self.on_save_clicked)
        self.window().manage_channel_playlist_torrents_back.clicked.connect(
            self.on_playlist_manage_back_clicked)

        # Load torrents in your channel
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request(
            "channels/discovered/%s/torrents?disable_filter=1" %
            channel_info["identifier"], self.on_received_channel_torrents)

        self.torrents_in_playlist = []
        self.torrents_in_channel = []

        self.torrents_to_create = []
        self.torrents_to_remove = []

        self.pending_requests = []
        self.requests_done = 0

    def on_playlist_manage_back_clicked(self):
        self.window().edit_channel_details_stacked_widget.setCurrentIndex(
            PAGE_EDIT_CHANNEL_PLAYLIST_TORRENTS)

    def update_lists(self):
        self.window().playlist_manage_in_channel_list.clear()
        self.window().playlist_manage_in_playlist_list.clear()

        for torrent in self.torrents_in_channel:
            item = QListWidgetItem(
                torrent["name"],
                self.window().playlist_manage_in_channel_list)
            item.setData(Qt.UserRole, torrent)
            self.window().playlist_manage_in_channel_list.addItem(item)

        for torrent in self.torrents_in_playlist:
            item = QListWidgetItem(
                torrent["name"],
                self.window().playlist_manage_in_playlist_list)
            item.setData(Qt.UserRole, torrent)
            self.window().playlist_manage_in_playlist_list.addItem(item)

    @staticmethod
    def remove_torrent_from_list(torrent, remove_from_list):
        index = -1
        for torrent_index in xrange(len(remove_from_list)):
            if remove_from_list[torrent_index]['infohash'] == torrent[
                    'infohash']:
                index = torrent_index
                break

        if index != -1:
            del remove_from_list[index]

    def on_received_channel_torrents(self, result):
        self.torrents_in_playlist = self.playlist_info['torrents']

        self.torrents_in_channel = []
        for torrent in result['torrents']:
            if not ManagePlaylistPage.list_contains_torrent(
                    self.torrents_in_playlist, torrent):
                self.torrents_in_channel.append(torrent)

        self.update_lists()

    @staticmethod
    def list_contains_torrent(torrent_list, torrent):
        for playlist_torrent in torrent_list:
            if torrent['infohash'] == playlist_torrent['infohash']:
                return True
        return False

    def on_add_clicked(self):
        for item in self.window(
        ).playlist_manage_in_channel_list.selectedItems():
            torrent = item.data(Qt.UserRole)
            ManagePlaylistPage.remove_torrent_from_list(
                torrent, self.torrents_in_channel)
            self.torrents_in_playlist.append(torrent)

            if ManagePlaylistPage.list_contains_torrent(
                    self.torrents_to_remove, torrent):
                ManagePlaylistPage.remove_torrent_from_list(
                    torrent, self.torrents_to_remove)
            self.torrents_to_create.append(torrent)

        self.update_lists()

    def on_remove_clicked(self):
        for item in self.window(
        ).playlist_manage_in_playlist_list.selectedItems():
            torrent = item.data(Qt.UserRole)
            ManagePlaylistPage.remove_torrent_from_list(
                torrent, self.torrents_in_playlist)
            self.torrents_in_channel.append(torrent)

            if ManagePlaylistPage.list_contains_torrent(
                    self.torrents_to_create, torrent):
                ManagePlaylistPage.remove_torrent_from_list(
                    torrent, self.torrents_to_create)
            self.torrents_to_remove.append(torrent)

        self.update_lists()

    def on_save_clicked(self):
        self.requests_done = 0
        self.pending_requests = []
        for torrent in self.torrents_to_create:
            request = TriblerRequestManager()
            request.perform_request(
                "channels/discovered/%s/playlists/%s/%s" %
                (self.channel_info["identifier"], self.playlist_info['id'],
                 torrent['infohash']),
                self.on_request_done,
                method="PUT")
            self.pending_requests.append(request)
        for torrent in self.torrents_to_remove:
            request = TriblerRequestManager()
            request.perform_request(
                "channels/discovered/%s/playlists/%s/%s" %
                (self.channel_info["identifier"], self.playlist_info['id'],
                 torrent['infohash']),
                self.on_request_done,
                method="DELETE")
            self.pending_requests.append(request)

    def on_request_done(self, _):
        self.requests_done += 1
        if self.requests_done == len(self.pending_requests):
            self.on_requests_done()

    def on_requests_done(self):
        self.window().edit_channel_details_stacked_widget.setCurrentIndex(
            PAGE_EDIT_CHANNEL_PLAYLIST_TORRENTS)
        self.playlist_saved.emit()
コード例 #32
0
class TriblerWindow(QMainWindow):
    resize_event = pyqtSignal()
    escape_pressed = pyqtSignal()
    received_search_completions = pyqtSignal(object)

    def on_exception(self, *exc_info):
        if self.exception_handler_called:
            # We only show one feedback dialog, even when there are two consecutive exceptions.
            return

        self.exception_handler_called = True

        if self.tray_icon:
            try:
                self.tray_icon.deleteLater()
            except RuntimeError:
                # The tray icon might have already been removed when unloading Qt.
                # This is due to the C code actually being asynchronous.
                logging.debug("Tray icon already removed, no further deletion necessary.")
            self.tray_icon = None

        # Stop the download loop
        self.downloads_page.stop_loading_downloads()

        # Add info about whether we are stopping Tribler or not
        os.environ['TRIBLER_SHUTTING_DOWN'] = str(self.core_manager.shutting_down)

        if not self.core_manager.shutting_down:
            self.core_manager.stop(stop_app_on_shutdown=False)

        self.setHidden(True)

        if self.debug_window:
            self.debug_window.setHidden(True)

        exception_text = "".join(traceback.format_exception(*exc_info))
        logging.error(exception_text)

        dialog = FeedbackDialog(self, exception_text, self.core_manager.events_manager.tribler_version,
                                self.start_time)
        dialog.show()

    def __init__(self, core_args=None, core_env=None, api_port=None):
        QMainWindow.__init__(self)

        QCoreApplication.setOrganizationDomain("nl")
        QCoreApplication.setOrganizationName("TUDelft")
        QCoreApplication.setApplicationName("Tribler")
        QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)

        self.gui_settings = QSettings()
        api_port = api_port or int(get_gui_setting(self.gui_settings, "api_port", DEFAULT_API_PORT))
        dispatcher.update_worker_settings(port=api_port)

        self.navigation_stack = []
        self.tribler_started = False
        self.tribler_settings = None
        self.debug_window = None
        self.core_manager = CoreManager(api_port)
        self.pending_requests = {}
        self.pending_uri_requests = []
        self.download_uri = None
        self.dialog = None
        self.new_version_dialog = None
        self.start_download_dialog_active = False
        self.request_mgr = None
        self.search_request_mgr = None
        self.search_suggestion_mgr = None
        self.selected_torrent_files = []
        self.vlc_available = True
        self.has_search_results = False
        self.last_search_query = None
        self.last_search_time = None
        self.start_time = time.time()
        self.exception_handler_called = False
        self.token_refresh_timer = None

        sys.excepthook = self.on_exception

        uic.loadUi(get_ui_file_path('mainwindow.ui'), self)
        TriblerRequestManager.window = self
        self.tribler_status_bar.hide()

        # Load dynamic widgets
        uic.loadUi(get_ui_file_path('torrent_channel_list_container.ui'), self.channel_page_container)
        self.channel_torrents_list = self.channel_page_container.items_list
        self.channel_torrents_detail_widget = self.channel_page_container.details_tab_widget
        self.channel_torrents_detail_widget.initialize_details_widget()
        self.channel_torrents_list.itemSelectionChanged.connect(self.channel_page.clicked_item)

        uic.loadUi(get_ui_file_path('torrent_channel_list_container.ui'), self.search_page_container)
        self.search_results_list = self.search_page_container.items_list
        self.search_torrents_detail_widget = self.search_page_container.details_tab_widget
        self.search_torrents_detail_widget.initialize_details_widget()
        self.search_results_list.itemClicked.connect(self.on_channel_item_click)
        self.search_results_list.itemSelectionChanged.connect(self.search_results_page.clicked_item)
        self.token_balance_widget.mouseReleaseEvent = self.on_token_balance_click

        def on_state_update(new_state):
            self.loading_text_label.setText(new_state)

        self.core_manager.core_state_update.connect(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)
        self.debug_pane_shortcut.activated.connect(self.clicked_menu_button_debug)

        # 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_home, self.left_menu_button_search, self.left_menu_button_my_channel,
                             self.left_menu_button_subscriptions, self.left_menu_button_video_player,
                             self.left_menu_button_downloads, self.left_menu_button_discovered]

        self.video_player_page.initialize_player()
        self.search_results_page.initialize_search_results_page()
        self.settings_page.initialize_settings_page()
        self.subscribed_channels_page.initialize()
        self.edit_channel_page.initialize_edit_channel_page()
        self.downloads_page.initialize_downloads_page()
        self.home_page.initialize_home_page()
        self.loading_page.initialize_loading_page()
        self.discovering_page.initialize_discovering_page()
        self.discovered_page.initialize_discovered_page()
        self.trust_page.initialize_trust_page()

        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)
            show_downloads_action.triggered.connect(self.clicked_menu_button_downloads)
            token_balance_action = QAction('Show token balance', self)
            token_balance_action.triggered.connect(lambda: self.on_token_balance_click(None))
            quit_action = QAction('Quit Tribler', self)
            quit_action.triggered.connect(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.hide_left_menu_playlist()
        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)

        self.core_manager.events_manager.received_search_result_channel.connect(
            self.search_results_page.received_search_result_channel)
        self.core_manager.events_manager.received_search_result_torrent.connect(
            self.search_results_page.received_search_result_torrent)
        self.core_manager.events_manager.torrent_finished.connect(self.on_torrent_finished)
        self.core_manager.events_manager.new_version_available.connect(self.on_new_version_available)
        self.core_manager.events_manager.tribler_started.connect(self.on_tribler_started)
        self.core_manager.events_manager.events_started.connect(self.on_events_started)
        self.core_manager.events_manager.low_storage_signal.connect(self.on_low_storage)

        # Install signal handler for ctrl+c events
        def sigint_handler(*_):
            self.close_tribler()

        signal.signal(signal.SIGINT, sigint_handler)

        self.installEventFilter(self.video_player_page)

        # 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()

    def update_tray_icon(self, use_monochrome_icon):
        if not QSystemTrayIcon.isSystemTrayAvailable():
            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 on_low_storage(self):
        """
        Dealing with low storage space available. First stop the downloads and the core manager and ask user to user to
        make free space.
        :return:
        """
        self.downloads_page.stop_loading_downloads()
        self.core_manager.stop(False)
        close_dialog = ConfirmationDialog(self.window(), "<b>CRITICAL ERROR</b>",
                                          "You are running low on disk space (<100MB). Please make sure to have "
                                          "sufficient free space available and restart Tribler again.",
                                          [("Close Tribler", BUTTON_TYPE_NORMAL)])
        close_dialog.button_clicked.connect(lambda _: self.close_tribler())
        close_dialog.show()

    def on_torrent_finished(self, torrent_info):
        if self.tray_icon:
            self.window().tray_icon.showMessage("Download finished",
                                                "Download of %s has finished." % torrent_info["name"])

    def show_loading_screen(self):
        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)
        self.stackedWidget.setCurrentIndex(PAGE_LOADING)

    def on_tribler_started(self):
        self.tribler_started = True

        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)

        # fetch the settings, needed for the video player port
        self.request_mgr = TriblerRequestManager()
        self.fetch_settings()

        self.downloads_page.start_loading_downloads()
        self.home_page.load_popular_torrents()
        if not self.gui_settings.value("first_discover", False) and not self.core_manager.use_existing_core:
            self.window().gui_settings.setValue("first_discover", True)
            self.discovering_page.is_discovering = True
            self.stackedWidget.setCurrentIndex(PAGE_DISCOVERING)
        else:
            self.clicked_menu_button_home()

        self.setAcceptDrops(True)

    def on_events_started(self, json_dict):
        self.setWindowTitle("Tribler %s" % json_dict["version"])

    def show_status_bar(self, message):
        self.tribler_status_bar_label.setText(message)
        self.tribler_status_bar.show()

    def hide_status_bar(self):
        self.tribler_status_bar.hide()

    def process_uri_request(self):
        """
        Process a URI request if we have one in the queue.
        """
        if len(self.pending_uri_requests) == 0:
            return

        uri = self.pending_uri_requests.pop()
        if uri.startswith('file') or uri.startswith('magnet'):
            self.start_download_from_uri(uri)

    def perform_start_download_request(self, uri, anon_download, safe_seeding, destination, selected_files,
                                       total_files=0, callback=None):
        # Check if destination directory is writable
        if not is_dir_writable(destination):
            ConfirmationDialog.show_message(self.window(), "Download error <i>%s</i>" % uri,
                                            "Insufficient write permissions to <i>%s</i> directory. "
                                            "Please add proper write permissions on the directory and "
                                            "add the torrent again." % destination, "OK")
            return

        selected_files_uri = ""
        if len(selected_files) != total_files:  # Not all files included
            selected_files_uri = u'&' + u''.join(u"selected_files[]=%s&" %
                                                 quote_plus_unicode(filename) for filename in selected_files)[:-1]

        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=%s&anon_hops=%d&safe_seeding=%d&destination=%s%s" % (quote_plus_unicode(uri), anon_hops,
                                                                              safe_seeding, destination,
                                                                              selected_files_uri)
        post_data = post_data.encode('utf-8')  # We need to send bytes in the request, not unicode

        request_mgr = TriblerRequestManager()
        request_mgr.perform_request("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, unicode):
            destination = destination.encode('utf-8')
        encoded_destination = destination.encode('hex')
        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 on_new_version_available(self, version):
        if version == str(self.gui_settings.value('last_reported_version')):
            return

        self.new_version_dialog = ConfirmationDialog(self, "New version available",
                                                     "Version %s of Tribler is available.Do you want to visit the "
                                                     "website to download the newest version?" % version,
                                                     [('IGNORE', BUTTON_TYPE_NORMAL), ('LATER', BUTTON_TYPE_NORMAL),
                                                      ('OK', BUTTON_TYPE_NORMAL)])
        self.new_version_dialog.button_clicked.connect(lambda action: self.on_new_version_dialog_done(version, action))
        self.new_version_dialog.show()

    def on_new_version_dialog_done(self, version, action):
        if action == 0:  # ignore
            self.gui_settings.setValue("last_reported_version", version)
        elif action == 2:  # ok
            import webbrowser
            webbrowser.open("https://tribler.org")

        self.new_version_dialog.close_dialog()
        self.new_version_dialog = None

    def on_search_text_change(self, text):
        self.search_suggestion_mgr = TriblerRequestManager()
        self.search_suggestion_mgr.perform_request(
            "search/completions?q=%s" % text, self.on_received_search_completions)

    def on_received_search_completions(self, completions):
        if completions is None:
            return
        self.received_search_completions.emit(completions)
        self.search_completion_model.setStringList(completions["completions"])

    def fetch_settings(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("settings", self.received_settings, capture_errors=False)

    def received_settings(self, settings):
        if not settings:
            return
        # If we cannot receive the settings, stop Tribler with an option to send the crash report.
        if 'error' in settings:
            raise RuntimeError(TriblerRequestManager.get_message_from_error(settings))

        self.tribler_settings = settings['settings']

        # Set the video server port
        self.video_player_page.video_player_port = settings["ports"]["video_server~port"]

        # Disable various components based on the settings
        if not self.tribler_settings['search_community']['enabled']:
            self.window().top_search_bar.setHidden(True)
        if not self.tribler_settings['video_server']['enabled']:
            self.left_menu_button_video_player.setHidden(True)
        self.downloads_creditmining_button.setHidden(not self.tribler_settings["credit_mining"]["enabled"])
        self.downloads_all_button.click()

        # process pending file requests (i.e. someone clicked a torrent file when Tribler was closed)
        # We do this after receiving the settings so we have the default download location.
        self.process_uri_request()

        # Set token balance refresh timer and load the token balance
        self.token_refresh_timer = QTimer()
        self.token_refresh_timer.timeout.connect(self.load_token_balance)
        self.token_refresh_timer.start(60000)

        self.load_token_balance()

    def on_top_search_button_click(self):
        current_ts = time.time()
        current_search_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

        self.left_menu_button_search.setChecked(True)
        self.has_search_results = True
        self.clicked_menu_button_search()
        self.search_results_page.perform_search(current_search_query)
        self.search_request_mgr = TriblerRequestManager()
        self.search_request_mgr.perform_request("search?q=%s" % current_search_query, None)
        self.last_search_query = current_search_query
        self.last_search_time = current_ts

    def on_settings_button_click(self):
        self.deselect_all_menu_buttons()
        self.stackedWidget.setCurrentIndex(PAGE_SETTINGS)
        self.settings_page.load_settings()
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def on_token_balance_click(self, _):
        self.raise_window()
        self.deselect_all_menu_buttons()
        self.stackedWidget.setCurrentIndex(PAGE_TRUST)
        self.trust_page.load_trust_statistics()
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def load_token_balance(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("trustchain/statistics", self.received_token_balance, capture_errors=False)

    def received_token_balance(self, statistics):
        if not statistics or "statistics" not in statistics:
            return

        statistics = statistics["statistics"]
        if 'latest_block' in statistics:
            balance = (statistics["latest_block"]["transaction"]["total_up"] -
                       statistics["latest_block"]["transaction"]["total_down"])
            self.set_token_balance(balance)
        else:
            self.token_balance_label.setText("0 MB")

    def set_token_balance(self, balance):
        if abs(balance) > 1024 ** 4:    # Balance is over a TB
            balance /= 1024.0 ** 4
            self.token_balance_label.setText("%.1f TB" % balance)
        elif abs(balance) > 1024 ** 3:  # Balance is over a GB
            balance /= 1024.0 ** 3
            self.token_balance_label.setText("%.1f GB" % balance)
        else:
            balance /= 1024.0 ** 2
            self.token_balance_label.setText("%d MB" % balance)

    def raise_window(self):
        self.setWindowState(self.windowState() & ~Qt.WindowMinimized | Qt.WindowActive)
        self.raise_()
        self.activateWindow()

    def create_add_torrent_menu(self):
        """
        Create a menu to add new torrents. Shows when users click on the tray icon or the big plus button.
        """
        menu = TriblerActionMenu(self)

        browse_files_action = QAction('Import torrent from file', self)
        browse_directory_action = QAction('Import torrent(s) from directory', self)
        add_url_action = QAction('Import torrent from magnet/URL', self)

        browse_files_action.triggered.connect(self.on_add_torrent_browse_file)
        browse_directory_action.triggered.connect(self.on_add_torrent_browse_dir)
        add_url_action.triggered.connect(self.on_add_torrent_from_url)

        menu.addAction(browse_files_action)
        menu.addAction(browse_directory_action)
        menu.addAction(add_url_action)

        return menu

    def on_add_torrent_button_click(self, pos):
        self.create_add_torrent_menu().exec_(self.mapToGlobal(self.add_torrent_button.pos()))

    def on_add_torrent_browse_file(self):
        filenames = QFileDialog.getOpenFileNames(self,
                                                 "Please select the .torrent file",
                                                 QDir.homePath(),
                                                 "Torrent files (*.torrent)")
        if len(filenames[0]) > 0:
            [self.pending_uri_requests.append(u"file:%s" % filename) for filename in filenames[0]]
            self.process_uri_request()

    def start_download_from_uri(self, uri):
        self.download_uri = uri

        if get_gui_setting(self.gui_settings, "ask_download_settings", True, is_bool=True):
            # If tribler settings is not available, fetch the settings and inform the user to try again.
            if not self.tribler_settings:
                self.fetch_settings()
                ConfirmationDialog.show_error(self, "Download Error", "Tribler settings is not available yet. "
                                                                      "Fetching it now. Please try again later.")
                return
            # Clear any previous dialog if exists
            if self.dialog:
                self.dialog.close_dialog()
                self.dialog = None

            self.dialog = StartDownloadDialog(self, self.download_uri)
            self.dialog.button_clicked.connect(self.on_start_download_action)
            self.dialog.show()
            self.start_download_dialog_active = True
        else:
            # 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'], [], 0)
            self.process_uri_request()

    def on_start_download_action(self, action):
        if action == 1:
            if self.dialog and self.dialog.dialog_widget:
                self.window().perform_start_download_request(
                    self.download_uri, self.dialog.dialog_widget.anon_download_checkbox.isChecked(),
                    self.dialog.dialog_widget.safe_seed_checkbox.isChecked(),
                    self.dialog.dialog_widget.destination_input.currentText(),
                    self.dialog.get_selected_files(),
                    self.dialog.dialog_widget.files_list_view.topLevelItemCount())
            else:
                ConfirmationDialog.show_error(self, "Tribler UI Error", "Something went wrong. Please try again.")
                logging.exception("Error while trying to download. Either dialog or dialog.dialog_widget is None")

        self.dialog.request_mgr.cancel_request()  # To abort the torrent info request
        self.dialog.close_dialog()
        self.dialog = None
        self.start_download_dialog_active = False

        if action == 0:  # We do this after removing the dialog since process_uri_request is blocking
            self.process_uri_request()

    def on_add_torrent_browse_dir(self):
        chosen_dir = QFileDialog.getExistingDirectory(self,
                                                      "Please select the directory containing the .torrent files",
                                                      QDir.homePath(),
                                                      QFileDialog.ShowDirsOnly)

        if len(chosen_dir) != 0:
            self.selected_torrent_files = [torrent_file for torrent_file in glob.glob(chosen_dir + "/*.torrent")]
            self.dialog = ConfirmationDialog(self, "Add torrents from directory",
                                             "Are you sure you want to add %d torrents to Tribler?" %
                                             len(self.selected_torrent_files),
                                             [('ADD', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)])
            self.dialog.button_clicked.connect(self.on_confirm_add_directory_dialog)
            self.dialog.show()

    def on_confirm_add_directory_dialog(self, action):
        if action == 0:
            for torrent_file in self.selected_torrent_files:
                escaped_uri = u"file:%s" % pathname2url(torrent_file)
                self.perform_start_download_request(escaped_uri,
                                                    self.window().tribler_settings['download_defaults'][
                                                         'anonymity_enabled'],
                                                    self.window().tribler_settings['download_defaults'][
                                                         'safeseeding_enabled'],
                                                    self.tribler_settings['download_defaults']['saveas'], [], 0)

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

    def on_add_torrent_from_url(self):
        # Make sure that the window is visible (this action might be triggered from the tray icon)
        self.raise_window()

        if self.video_player_page.isVisible():
            # If we're adding a torrent from the video player page, go to the home page.
            # This is necessary since VLC takes the screen and the popup becomes invisible.
            self.clicked_menu_button_home()

        self.dialog = ConfirmationDialog(self, "Add torrent from URL/magnet link",
                                         "Please enter the URL/magnet link in the field below:",
                                         [('ADD', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)],
                                         show_input=True)
        self.dialog.dialog_widget.dialog_input.setPlaceholderText('URL/magnet link')
        self.dialog.dialog_widget.dialog_input.setFocus()
        self.dialog.button_clicked.connect(self.on_torrent_from_url_dialog_done)
        self.dialog.show()

    def on_torrent_from_url_dialog_done(self, action):
        if self.dialog and self.dialog.dialog_widget:
            uri = self.dialog.dialog_widget.dialog_input.text()

            # Remove first dialog
            self.dialog.close_dialog()
            self.dialog = None

            if action == 0:
                self.start_download_from_uri(uri)

    def on_download_added(self, result):
        if not result:
            return
        if len(self.pending_uri_requests) == 0:  # Otherwise, we first process the remaining requests.
            self.window().left_menu_button_downloads.click()
        else:
            self.process_uri_request()

    def on_top_menu_button_click(self):
        if self.left_menu.isHidden():
            self.left_menu.show()
        else:
            self.left_menu.hide()

    def deselect_all_menu_buttons(self, except_select=None):
        for button in self.menu_buttons:
            if button == except_select:
                button.setEnabled(False)
                continue
            button.setEnabled(True)

            if button == self.left_menu_button_search and not self.has_search_results:
                button.setEnabled(False)

            button.setChecked(False)

    def clicked_menu_button_home(self):
        self.deselect_all_menu_buttons(self.left_menu_button_home)
        self.stackedWidget.setCurrentIndex(PAGE_HOME)
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def clicked_menu_button_search(self):
        self.deselect_all_menu_buttons(self.left_menu_button_search)
        self.stackedWidget.setCurrentIndex(PAGE_SEARCH_RESULTS)
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def clicked_menu_button_discovered(self):
        self.deselect_all_menu_buttons(self.left_menu_button_discovered)
        self.stackedWidget.setCurrentIndex(PAGE_DISCOVERED)
        self.discovered_page.load_discovered_channels()
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def clicked_menu_button_my_channel(self):
        self.deselect_all_menu_buttons(self.left_menu_button_my_channel)
        self.stackedWidget.setCurrentIndex(PAGE_EDIT_CHANNEL)
        self.edit_channel_page.load_my_channel_overview()
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def clicked_menu_button_video_player(self):
        self.deselect_all_menu_buttons(self.left_menu_button_video_player)
        self.stackedWidget.setCurrentIndex(PAGE_VIDEO_PLAYER)
        self.navigation_stack = []
        self.show_left_menu_playlist()

    def clicked_menu_button_downloads(self):
        self.raise_window()
        self.left_menu_button_downloads.setChecked(True)
        self.deselect_all_menu_buttons(self.left_menu_button_downloads)
        self.stackedWidget.setCurrentIndex(PAGE_DOWNLOADS)
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def clicked_menu_button_debug(self):
        if not self.debug_window:
            self.debug_window = DebugWindow(self.tribler_settings, self.core_manager.events_manager.tribler_version)
        self.debug_window.show()

    def clicked_menu_button_subscriptions(self):
        self.deselect_all_menu_buttons(self.left_menu_button_subscriptions)
        self.subscribed_channels_page.load_subscribed_channels()
        self.stackedWidget.setCurrentIndex(PAGE_SUBSCRIBED_CHANNELS)
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def hide_left_menu_playlist(self):
        self.left_menu_seperator.setHidden(True)
        self.left_menu_playlist_label.setHidden(True)
        self.left_menu_playlist.setHidden(True)

    def show_left_menu_playlist(self):
        self.left_menu_seperator.setHidden(False)
        self.left_menu_playlist_label.setHidden(False)
        self.left_menu_playlist.setHidden(False)

    def on_channel_item_click(self, channel_list_item):
        list_widget = channel_list_item.listWidget()
        from TriblerGUI.widgets.channel_list_item import ChannelListItem
        if isinstance(list_widget.itemWidget(channel_list_item), ChannelListItem):
            channel_info = channel_list_item.data(Qt.UserRole)
            self.channel_page.initialize_with_channel(channel_info)
            self.navigation_stack.append(self.stackedWidget.currentIndex())
            self.stackedWidget.setCurrentIndex(PAGE_CHANNEL_DETAILS)

    def on_playlist_item_click(self, playlist_list_item):
        list_widget = playlist_list_item.listWidget()
        from TriblerGUI.widgets.playlist_list_item import PlaylistListItem
        if isinstance(list_widget.itemWidget(playlist_list_item), PlaylistListItem):
            playlist_info = playlist_list_item.data(Qt.UserRole)
            self.playlist_page.initialize_with_playlist(playlist_info)
            self.navigation_stack.append(self.stackedWidget.currentIndex())
            self.stackedWidget.setCurrentIndex(PAGE_PLAYLIST_DETAILS)

    def on_page_back_clicked(self):
        try:
            prev_page = self.navigation_stack.pop()
            self.stackedWidget.setCurrentIndex(prev_page)
            if prev_page == PAGE_SEARCH_RESULTS:
                self.stackedWidget.widget(prev_page).load_search_results_in_list()
            if prev_page == PAGE_SUBSCRIBED_CHANNELS:
                self.stackedWidget.widget(prev_page).load_subscribed_channels()
            if prev_page == PAGE_DISCOVERED:
                self.stackedWidget.widget(prev_page).load_discovered_channels()
        except IndexError:
            logging.exception("Unknown page found in stack")

    def on_edit_channel_clicked(self):
        self.stackedWidget.setCurrentIndex(PAGE_EDIT_CHANNEL)
        self.navigation_stack = []
        self.channel_page.on_edit_channel_clicked()

    def resizeEvent(self, _):
        # Resize home page cells
        cell_width = self.home_page_table_view.width() / 3 - 3  # We have some padding to the right
        cell_height = cell_width / 2 + 60

        for i in range(0, 3):
            self.home_page_table_view.setColumnWidth(i, cell_width)
            self.home_page_table_view.setRowHeight(i, cell_height)
        self.resize_event.emit()

    def exit_full_screen(self):
        self.top_bar.show()
        self.left_menu.show()
        self.video_player_page.is_full_screen = False
        self.showNormal()

    def close_tribler(self):
        if not self.core_manager.shutting_down:
            def show_force_shutdown():
                self.loading_text_label.setText("Tribler is taking longer than expected to shut down. You can force "
                                                "Tribler to shutdown by pressing the button below. This might lead "
                                                "to data loss.")
                self.window().force_shutdown_btn.show()

            if self.tray_icon:
                self.tray_icon.deleteLater()
            self.show_loading_screen()
            self.hide_status_bar()
            self.loading_text_label.setText("Shutting down...")

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

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

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

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

            # Stop the token balance timer
            if self.token_refresh_timer:
                self.token_refresh_timer.stop()

    def closeEvent(self, close_event):
        self.close_tribler()
        close_event.ignore()

    def keyReleaseEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.escape_pressed.emit()
            if self.isFullScreen():
                self.exit_full_screen()

    def dragEnterEvent(self, e):
        file_urls = [_qurl_to_path(url) for url in e.mimeData().urls()] if e.mimeData().hasUrls() else []

        if any(os.path.isfile(filename) for filename in file_urls):
            e.accept()
        else:
            e.ignore()

    def dropEvent(self, e):
        file_urls = ([(_qurl_to_path(url), url.toString()) for url in e.mimeData().urls()]
                     if e.mimeData().hasUrls() else [])

        for filename, fileurl in file_urls:
            if os.path.isfile(filename):
                self.start_download_from_uri(fileurl)

        e.accept()

    def clicked_force_shutdown(self):
        process_checker = ProcessChecker()
        if process_checker.already_running:
            core_pid = process_checker.get_pid_from_lock_file()
            os.kill(int(core_pid), 9)
        # Stop the Qt application
        QApplication.quit()
コード例 #33
0
ファイル: channelpage.py プロジェクト: synctext/tribler
class ChannelPage(QWidget):
    """
    The ChannelPage is the page with an overview of each channel and displays the list of torrents/playlist available.
    """

    def __init__(self):
        QWidget.__init__(self)

        self.playlists = []
        self.torrents = []
        self.loaded_channels = False
        self.loaded_playlists = False
        self.channel_info = None

        self.get_torents_in_channel_manager = None
        self.get_playlists_in_channel_manager = None

    def initialize_with_channel(self, channel_info):
        self.playlists = []
        self.torrents = []
        self.loaded_channels = False
        self.loaded_playlists = False

        self.get_torents_in_channel_manager = None
        self.get_playlists_in_channel_manager = None

        self.channel_info = channel_info

        self.window().channel_torrents_list.set_data_items([(LoadingListItem, None)])
        self.window().channel_torrents_detail_widget.hide()

        self.window().channel_preview_label.setHidden(channel_info['subscribed'])
        self.window().channel_back_button.setIcon(QIcon(get_image_path('page_back.png')))

        self.get_torents_in_channel_manager = TriblerRequestManager()
        self.get_torents_in_channel_manager.perform_request("channels/discovered/%s/torrents" %
                                                            channel_info['dispersy_cid'],
                                                            self.received_torrents_in_channel)

        if len(channel_info['dispersy_cid']) == 148: # Check-hack for Channel2.0 style address
            self.loaded_playlists = True
        else:
            self.get_playlists_in_channel_manager = TriblerRequestManager()
            self.get_playlists_in_channel_manager.perform_request("channels/discovered/%s/playlists" %
                                                                  channel_info['dispersy_cid'],
                                                                  self.received_playlists_in_channel)

        # initialize the page about a channel
        self.window().channel_name_label.setText(channel_info['name'])
        self.window().num_subs_label.setText(str(channel_info['votes']))
        self.window().subscription_widget.initialize_with_channel(channel_info)

    def clicked_item(self):
        if len(self.window().channel_torrents_list.selectedItems()) != 1:
            self.window().channel_torrents_detail_widget.hide()
        else:
            item = self.window().channel_torrents_list.selectedItems()[0]
            list_widget = item.listWidget()
            list_item = list_widget.itemWidget(item)
            if isinstance(list_item, ChannelTorrentListItem):
                self.window().channel_torrents_detail_widget.update_with_torrent(list_item.torrent_info)
                self.window().channel_torrents_detail_widget.show()
            else:
                self.window().channel_torrents_detail_widget.hide()

    def update_result_list(self):
        if self.loaded_channels and self.loaded_playlists:
            self.window().channel_torrents_list.set_data_items(self.playlists + self.torrents)

    def received_torrents_in_channel(self, results):
        if not results:
            return
        def sort_key(torrent):
            """ Scoring algorithm for sorting the torrent to show liveness. The score is basically the sum of number
                of seeders and leechers. If swarm info is unknown, we give unknown seeder and leecher as 0.5 & 0.4 so
                that the sum is less than 1 and higher than zero. This means unknown torrents will have higher score
                than dead torrent with no seeders and leechers and lower score than any barely alive torrent with a
                single seeder or leecher.
            """
            seeder_score = torrent['num_seeders'] if torrent['num_seeders'] or torrent['last_tracker_check'] > 0\
                else 0.5
            leecher_score = torrent['num_leechers'] if torrent['num_leechers'] or torrent['last_tracker_check'] > 0\
                else 0.5
            return seeder_score + .5 * leecher_score

        for result in sorted(results['torrents'], key=sort_key, reverse=True):
            self.torrents.append((ChannelTorrentListItem, result))

        if not self.channel_info['subscribed']:
            self.torrents.append((TextListItem, "You're looking at a preview of this channel.\n"
                                                "Subscribe to this channel to see the full content."))

        self.loaded_channels = True
        self.update_result_list()

    def received_playlists_in_channel(self, results):
        if not results:
            return
        for result in results['playlists']:
            self.playlists.append((PlaylistListItem, result))
        self.loaded_playlists = True
        self.update_result_list()
コード例 #34
0
ファイル: downloadspage.py プロジェクト: synctext/tribler
class DownloadsPage(QWidget):
    """
    This class is responsible for managing all items on the downloads page.
    The downloads page shows all downloads and specific details about a download.
    """
    received_downloads = pyqtSignal(object)

    def __init__(self):
        QWidget.__init__(self)
        self.export_dir = None
        self.filter = DOWNLOADS_FILTER_ALL
        self.download_widgets = {}  # key: infohash, value: QTreeWidgetItem
        self.downloads = None
        self.downloads_timer = QTimer()
        self.downloads_timeout_timer = QTimer()
        self.downloads_last_update = 0
        self.selected_items = None
        self.dialog = None
        self.downloads_request_mgr = TriblerRequestManager()
        self.request_mgr = None
        self.loading_message_widget = None

    def showEvent(self, QShowEvent):
        """
        When the downloads tab is clicked, we want to update the downloads list immediately.
        """
        super(DownloadsPage, self).showEvent(QShowEvent)
        self.stop_loading_downloads()
        self.schedule_downloads_timer(True)

    def initialize_downloads_page(self):
        self.window().downloads_tab.initialize()
        self.window().downloads_tab.clicked_tab_button.connect(self.on_downloads_tab_button_clicked)

        self.window().start_download_button.clicked.connect(self.on_start_download_clicked)
        self.window().stop_download_button.clicked.connect(self.on_stop_download_clicked)
        self.window().remove_download_button.clicked.connect(self.on_remove_download_clicked)
        self.window().play_download_button.clicked.connect(self.on_play_download_clicked)

        self.window().downloads_list.itemSelectionChanged.connect(self.on_download_item_clicked)

        self.window().downloads_list.customContextMenuRequested.connect(self.on_right_click_item)

        self.window().download_details_widget.initialize_details_widget()
        self.window().download_details_widget.hide()

        self.window().downloads_filter_input.textChanged.connect(self.on_filter_text_changed)

        self.window().downloads_list.header().resizeSection(12, 146)

        if not self.window().vlc_available:
            self.window().play_download_button.setHidden(True)

    def on_filter_text_changed(self, text):
        self.window().downloads_list.clearSelection()
        self.window().download_details_widget.hide()
        self.update_download_visibility()

    def start_loading_downloads(self):
        self.window().downloads_list.setSelectionMode(QAbstractItemView.NoSelection)
        self.loading_message_widget = QTreeWidgetItem()
        self.window().downloads_list.addTopLevelItem(self.loading_message_widget)
        self.window().downloads_list.setItemWidget(self.loading_message_widget, 2,
                                                   LoadingListItem(self.window().downloads_list))
        self.schedule_downloads_timer(now=True)

    def schedule_downloads_timer(self, now=False):
        self.downloads_timer = QTimer()
        self.downloads_timer.setSingleShot(True)
        self.downloads_timer.timeout.connect(self.load_downloads)
        self.downloads_timer.start(0 if now else 1000)

        self.downloads_timeout_timer = QTimer()
        self.downloads_timeout_timer.setSingleShot(True)
        self.downloads_timeout_timer.timeout.connect(self.on_downloads_request_timeout)
        self.downloads_timeout_timer.start(16000)

    def on_downloads_request_timeout(self):
        self.downloads_request_mgr.cancel_request()
        self.schedule_downloads_timer()

    def stop_loading_downloads(self):
        self.downloads_timer.stop()
        self.downloads_timeout_timer.stop()

    def load_downloads(self):
        url = "downloads?get_pieces=1"
        if self.window().download_details_widget.currentIndex() == 3:
            url += "&get_peers=1"
        elif self.window().download_details_widget.currentIndex() == 1:
            url += "&get_files=1"

        if not self.isHidden() or (time.time() - self.downloads_last_update > 30):
            # Update if the downloads page is visible or if we haven't updated for longer than 30 seconds
            self.downloads_last_update = time.time()
            priority = "LOW" if self.isHidden() else "HIGH"
            self.downloads_request_mgr.cancel_request()
            self.downloads_request_mgr = TriblerRequestManager()
            self.downloads_request_mgr.perform_request(url, self.on_received_downloads, priority=priority)

    def on_received_downloads(self, downloads):
        if not downloads:
            return  # This might happen when closing Tribler
        loading_widget_index = self.window().downloads_list.indexOfTopLevelItem(self.loading_message_widget)
        if loading_widget_index > -1:
            self.window().downloads_list.takeTopLevelItem(loading_widget_index)
            self.window().downloads_list.setSelectionMode(QAbstractItemView.ExtendedSelection)

        self.downloads = downloads

        self.total_download = 0
        self.total_upload = 0

        download_infohashes = set()

        items = []
        for download in downloads["downloads"]:
            if download["infohash"] in self.download_widgets:
                item = self.download_widgets[download["infohash"]]
            else:
                item = DownloadWidgetItem()
                self.download_widgets[download["infohash"]] = item
                items.append(item)

            item.update_with_download(download)

            # Update video player with download info
            video_infohash = self.window().video_player_page.active_infohash
            if video_infohash != "" and download["infohash"] == video_infohash:
                self.window().video_player_page.update_with_download_info(download)

            self.total_download += download["speed_down"]
            self.total_upload += download["speed_up"]

            download_infohashes.add(download["infohash"])

            if self.window().download_details_widget.current_download is not None and \
                    self.window().download_details_widget.current_download["infohash"] == download["infohash"]:
                self.window().download_details_widget.current_download = download
                self.window().download_details_widget.update_pages()

        self.window().downloads_list.addTopLevelItems(items)
        for item in items:
            self.window().downloads_list.setItemWidget(item, 2, item.bar_container)

        # Check whether there are download that should be removed
        for infohash, item in self.download_widgets.items():
            if infohash not in download_infohashes:
                index = self.window().downloads_list.indexOfTopLevelItem(item)
                self.window().downloads_list.takeTopLevelItem(index)
                del self.download_widgets[infohash]

        self.window().tray_set_tooltip("Down: %s, Up: %s" % (format_speed(self.total_download), format_speed(self.total_upload)))
        self.update_download_visibility()
        self.schedule_downloads_timer()

        # Update the top download management button if we have a row selected
        if len(self.window().downloads_list.selectedItems()) > 0:
            self.on_download_item_clicked()

        self.update_credit_mining_disk_usage()

        self.received_downloads.emit(downloads)

    def update_download_visibility(self):
        for i in range(self.window().downloads_list.topLevelItemCount()):
            item = self.window().downloads_list.topLevelItem(i)
            if not isinstance(item, DownloadWidgetItem):
                continue

            filter_match = self.window().downloads_filter_input.text().lower() in item.download_info["name"].lower()
            is_creditmining = item.download_info["credit_mining"]
            if self.filter == DOWNLOADS_FILTER_CREDITMINING:
                item.setHidden(not is_creditmining or not filter_match)
            else:
                item.setHidden(not item.get_raw_download_status() in DOWNLOADS_FILTER_DEFINITION[self.filter] or \
                               not filter_match or is_creditmining)

    def on_downloads_tab_button_clicked(self, button_name):
        if button_name == "downloads_all_button":
            self.filter = DOWNLOADS_FILTER_ALL
        elif button_name == "downloads_downloading_button":
            self.filter = DOWNLOADS_FILTER_DOWNLOADING
        elif button_name == "downloads_completed_button":
            self.filter = DOWNLOADS_FILTER_COMPLETED
        elif button_name == "downloads_active_button":
            self.filter = DOWNLOADS_FILTER_ACTIVE
        elif button_name == "downloads_inactive_button":
            self.filter = DOWNLOADS_FILTER_INACTIVE
        elif button_name == "downloads_creditmining_button":
            self.filter = DOWNLOADS_FILTER_CREDITMINING

        self.window().downloads_list.clearSelection()
        self.window().download_details_widget.hide()
        self.update_download_visibility()
        self.update_credit_mining_disk_usage()

    def update_credit_mining_disk_usage(self):
        on_credit_mining_tab = self.filter == DOWNLOADS_FILTER_CREDITMINING
        self.window().diskspace_usage.setVisible(on_credit_mining_tab)

        if not on_credit_mining_tab or not self.window().tribler_settings or not self.downloads:
            return

        bytes_max = self.window().tribler_settings["credit_mining"]["max_disk_space"]
        bytes_used = 0
        for download in self.downloads["downloads"]:
            if download["credit_mining"] and \
               download["status"] in ("DLSTATUS_DOWNLOADING", "DLSTATUS_SEEDING",
                                      "DLSTATUS_STOPPED", "DLSTATUS_STOPPED_ON_ERROR"):
                bytes_used += download["progress"] * download["size"]
        self.window().diskspace_usage.setText("Current disk space usage %s / %s" % (format_size(float(bytes_used)),
                                                                                    format_size(float(bytes_max))))

    @staticmethod
    def start_download_enabled(download_widgets):
        return any([download_widget.get_raw_download_status() == DLSTATUS_STOPPED
                    for download_widget in download_widgets])

    @staticmethod
    def stop_download_enabled(download_widgets):
        return any([download_widget.get_raw_download_status() not in [DLSTATUS_STOPPED, DLSTATUS_STOPPED_ON_ERROR]
                    for download_widget in download_widgets])

    @staticmethod
    def force_recheck_download_enabled(download_widgets):
        return any([download_widget.get_raw_download_status() not in
                    [DLSTATUS_METADATA, DLSTATUS_HASHCHECKING, DLSTATUS_WAITING4HASHCHECK]
                    for download_widget in download_widgets])

    def on_download_item_clicked(self):
        selected_count = len(self.window().downloads_list.selectedItems())
        if selected_count == 0:
            self.window().play_download_button.setEnabled(False)
            self.window().remove_download_button.setEnabled(False)
            self.window().start_download_button.setEnabled(False)
            self.window().stop_download_button.setEnabled(False)
            self.window().download_details_widget.hide()
        elif selected_count == 1:
            self.selected_items = self.window().downloads_list.selectedItems()
            self.window().play_download_button.setEnabled(True)
            self.window().remove_download_button.setEnabled(True)
            self.window().start_download_button.setEnabled(DownloadsPage.start_download_enabled(self.selected_items))
            self.window().stop_download_button.setEnabled(DownloadsPage.stop_download_enabled(self.selected_items))

            self.window().download_details_widget.update_with_download(self.selected_items[0].download_info)
            self.window().download_details_widget.show()
        else:
            self.selected_items = self.window().downloads_list.selectedItems()
            self.window().play_download_button.setEnabled(False)
            self.window().remove_download_button.setEnabled(True)
            self.window().start_download_button.setEnabled(DownloadsPage.start_download_enabled(self.selected_items))
            self.window().stop_download_button.setEnabled(DownloadsPage.stop_download_enabled(self.selected_items))
            self.window().download_details_widget.hide()

    def on_start_download_clicked(self):
        for selected_item in self.selected_items:
            infohash = selected_item.download_info["infohash"]
            self.request_mgr = TriblerRequestManager()
            self.request_mgr.perform_request("downloads/%s" % infohash, self.on_download_resumed,
                                             method='PATCH', data="state=resume")

    def on_download_resumed(self, json_result):
        if json_result and 'modified' in json_result:
            for selected_item in self.selected_items:
                if selected_item.download_info["infohash"] == json_result["infohash"]:
                    selected_item.download_info['status'] = "DLSTATUS_DOWNLOADING"
                    selected_item.update_item()
                    self.on_download_item_clicked()

    def on_stop_download_clicked(self):
        for selected_item in self.selected_items:
            infohash = selected_item.download_info["infohash"]
            self.request_mgr = TriblerRequestManager()
            self.request_mgr.perform_request("downloads/%s" % infohash, self.on_download_stopped,
                                             method='PATCH', data="state=stop")

    def on_play_download_clicked(self):
        self.window().left_menu_button_video_player.click()
        selected_item = self.selected_items[:1]
        if selected_item and \
           self.window().video_player_page.active_infohash != selected_item[0].download_info["infohash"]:
            self.window().video_player_page.play_media_item(selected_item[0].download_info["infohash"], -1)

    def on_download_stopped(self, json_result):
        if json_result and "modified" in json_result:
            for selected_item in self.selected_items:
                if selected_item.download_info["infohash"] == json_result["infohash"]:
                    selected_item.download_info['status'] = "DLSTATUS_STOPPED"
                    selected_item.update_item()
                    self.on_download_item_clicked()

    def on_remove_download_clicked(self):
        self.dialog = ConfirmationDialog(self, "Remove download", "Are you sure you want to remove this download?",
                                         [('remove download', BUTTON_TYPE_NORMAL),
                                          ('remove download + data', BUTTON_TYPE_NORMAL),
                                          ('cancel', BUTTON_TYPE_CONFIRM)])
        self.dialog.button_clicked.connect(self.on_remove_download_dialog)
        self.dialog.show()

    def on_remove_download_dialog(self, action):
        if action != 2:
            for selected_item in self.selected_items:
                infohash = selected_item.download_info["infohash"]

                # Reset video player if necessary before doing the actual request
                if self.window().video_player_page.active_infohash == infohash:
                    self.window().video_player_page.reset_player()

                self.request_mgr = TriblerRequestManager()
                self.request_mgr.perform_request("downloads/%s" % infohash, self.on_download_removed,
                                                 method='DELETE', data="remove_data=%d" % action)

        self.dialog.close_dialog()
        self.dialog = None

    def on_download_removed(self, json_result):
        if json_result and "removed" in json_result:
            self.load_downloads()
            self.window().download_details_widget.hide()

    def on_force_recheck_download(self):
        for selected_item in self.selected_items:
            infohash = selected_item.download_info["infohash"]
            self.request_mgr = TriblerRequestManager()
            self.request_mgr.perform_request("downloads/%s" % infohash, self.on_forced_recheck,
                                             method='PATCH', data='state=recheck')

    def on_forced_recheck(self, result):
        if result and "modified" in result:
            for selected_item in self.selected_items:
                if selected_item.download_info["infohash"] == result["infohash"]:
                    selected_item.download_info['status'] = "DLSTATUS_HASHCHECKING"
                    selected_item.update_item()
                    self.on_download_item_clicked()

    def change_anonymity(self, hops):
        for selected_item in self.selected_items:
            infohash = selected_item.download_info["infohash"]
            self.request_mgr = TriblerRequestManager()
            self.request_mgr.perform_request("downloads/%s" % infohash, lambda _: None,
                                             method='PATCH', data='anon_hops=%d' % hops)

    def on_explore_files(self):
        for selected_item in self.selected_items:
            path = os.path.normpath(os.path.join(self.window().tribler_settings['download_defaults']['saveas'],
                                                 selected_item.download_info["destination"]))
            QDesktopServices.openUrl(QUrl.fromLocalFile(path))

    def on_export_download(self):
        self.export_dir = QFileDialog.getExistingDirectory(self, "Please select the destination directory", "",
                                                           QFileDialog.ShowDirsOnly)

        selected_item = self.selected_items[:1]
        if len(self.export_dir) > 0 and selected_item:
            # Show confirmation dialog where we specify the name of the file
            torrent_name = selected_item[0].download_info['name']
            self.dialog = ConfirmationDialog(self, "Export torrent file",
                                             "Please enter the name of the torrent file:",
                                             [('SAVE', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)],
                                             show_input=True)
            self.dialog.dialog_widget.dialog_input.setPlaceholderText('Torrent file name')
            self.dialog.dialog_widget.dialog_input.setText("%s.torrent" % torrent_name)
            self.dialog.dialog_widget.dialog_input.setFocus()
            self.dialog.button_clicked.connect(self.on_export_download_dialog_done)
            self.dialog.show()

    def on_export_download_dialog_done(self, action):
        selected_item = self.selected_items[:1]
        if action == 0 and selected_item:
            filename = self.dialog.dialog_widget.dialog_input.text()
            self.request_mgr = TriblerRequestManager()
            self.request_mgr.download_file("downloads/%s/torrent" % selected_item[0].download_info['infohash'],
                                           lambda data: self.on_export_download_request_done(filename, data))

        self.dialog.close_dialog()
        self.dialog = None

    def on_export_download_request_done(self, filename, data):
        dest_path = os.path.join(self.export_dir, filename)
        try:
            torrent_file = open(dest_path, "wb")
            torrent_file.write(data)
            torrent_file.close()
        except IOError as exc:
            ConfirmationDialog.show_error(self.window(),
                                          "Error when exporting file",
                                          "An error occurred when exporting the torrent file: %s" % str(exc))
        else:
            self.window().tray_show_message("Torrent file exported", "Torrent file exported to %s" % dest_path)

    def on_right_click_item(self, pos):
        item_clicked = self.window().downloads_list.itemAt(pos)
        if not item_clicked or self.selected_items is None:
            return

        if item_clicked not in self.selected_items:
            self.selected_items.append(item_clicked)

        menu = TriblerActionMenu(self)

        start_action = QAction('Start', self)
        stop_action = QAction('Stop', self)
        remove_download_action = QAction('Remove download', self)
        force_recheck_action = QAction('Force recheck', self)
        export_download_action = QAction('Export .torrent file', self)
        explore_files_action = QAction('Explore files', self)

        no_anon_action = QAction('No anonymity', self)
        one_hop_anon_action = QAction('One hop', self)
        two_hop_anon_action = QAction('Two hops', self)
        three_hop_anon_action = QAction('Three hops', self)

        start_action.triggered.connect(self.on_start_download_clicked)
        start_action.setEnabled(DownloadsPage.start_download_enabled(self.selected_items))
        stop_action.triggered.connect(self.on_stop_download_clicked)
        stop_action.setEnabled(DownloadsPage.stop_download_enabled(self.selected_items))
        remove_download_action.triggered.connect(self.on_remove_download_clicked)
        force_recheck_action.triggered.connect(self.on_force_recheck_download)
        force_recheck_action.setEnabled(DownloadsPage.force_recheck_download_enabled(self.selected_items))
        export_download_action.triggered.connect(self.on_export_download)
        explore_files_action.triggered.connect(self.on_explore_files)

        no_anon_action.triggered.connect(lambda: self.change_anonymity(0))
        one_hop_anon_action.triggered.connect(lambda: self.change_anonymity(1))
        two_hop_anon_action.triggered.connect(lambda: self.change_anonymity(2))
        three_hop_anon_action.triggered.connect(lambda: self.change_anonymity(3))

        menu.addAction(start_action)
        menu.addAction(stop_action)

        if self.window().vlc_available and len(self.selected_items) == 1:
            play_action = QAction('Play', self)
            play_action.triggered.connect(self.on_play_download_clicked)
            menu.addAction(play_action)
        menu.addSeparator()
        menu.addAction(remove_download_action)
        menu.addSeparator()
        menu.addAction(force_recheck_action)
        menu.addSeparator()

        exclude_states = [DLSTATUS_METADATA, DLSTATUS_CIRCUITS, DLSTATUS_HASHCHECKING, DLSTATUS_WAITING4HASHCHECK]
        if len(self.selected_items) == 1 and self.selected_items[0].get_raw_download_status() not in exclude_states:
            menu.addAction(export_download_action)
            menu.addSeparator()
        menu_anon_level = menu.addMenu("Change anonymity")
        menu_anon_level.addAction(no_anon_action)
        menu_anon_level.addAction(one_hop_anon_action)
        menu_anon_level.addAction(two_hop_anon_action)
        menu_anon_level.addAction(three_hop_anon_action)
        menu.addAction(explore_files_action)

        menu.exec_(self.window().downloads_list.mapToGlobal(pos))
コード例 #35
0
ファイル: marketorderspage.py プロジェクト: synctext/tribler
class MarketOrdersPage(QWidget):
    """
    This page displays orders in the decentralized market in Tribler.
    """

    def __init__(self):
        QWidget.__init__(self)
        self.request_mgr = None
        self.initialized = False
        self.selected_item = None
        self.dialog = None
        self.wallets = {}

    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 load_orders(self):
        self.window().market_orders_list.clear()

        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("market/orders", self.on_received_orders)

    def on_received_orders(self, orders):
        if not orders:
            return
        for order in orders["orders"]:
            if self.wallets:
                asset1_prec = self.wallets[order["assets"]["first"]["type"]]["precision"]
                asset2_prec = self.wallets[order["assets"]["second"]["type"]]["precision"]
                item = OrderWidgetItem(self.window().market_orders_list, order, asset1_prec, asset2_prec)
                self.window().market_orders_list.addTopLevelItem(item)

    def on_right_click_order(self, pos):
        item_clicked = self.window().market_orders_list.itemAt(pos)
        if not item_clicked:
            return

        self.selected_item = item_clicked

        if self.selected_item.order['status'] == 'open':  # We can only cancel an open order
            menu = TriblerActionMenu(self)
            cancel_action = QAction('Cancel order', self)
            cancel_action.triggered.connect(self.on_cancel_order_clicked)
            menu.addAction(cancel_action)
            menu.exec_(self.window().market_orders_list.mapToGlobal(pos))

    def on_cancel_order_clicked(self):
        self.dialog = ConfirmationDialog(self, "Cancel order",
                                         "Are you sure you want to cancel the order with id %s?" %
                                         self.selected_item.order['order_number'],
                                         [('NO', BUTTON_TYPE_NORMAL), ('YES', BUTTON_TYPE_CONFIRM)])
        self.dialog.button_clicked.connect(self.on_confirm_cancel_order)
        self.dialog.show()

    def on_confirm_cancel_order(self, action):
        if action == 1:
            self.request_mgr = TriblerRequestManager()
            self.request_mgr.perform_request("market/orders/%s/cancel" % self.selected_item.order['order_number'],
                                             self.on_order_cancelled, method='POST')

        self.dialog.close_dialog()
        self.dialog = None

    def on_order_cancelled(self, response):
        if not response:
            return
        self.load_orders()
コード例 #36
0
class StartDownloadDialog(DialogContainer):

    button_clicked = pyqtSignal(int)
    received_metainfo = pyqtSignal(dict)

    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

        uic.loadUi(get_ui_file_path('startdownloaddialog.ui'), self.dialog_widget)

        self.dialog_widget.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)

        self.dialog_widget.browse_dir_button.clicked.connect(self.on_browse_dir_clicked)
        self.dialog_widget.cancel_button.clicked.connect(lambda: self.button_clicked.emit(0))
        self.dialog_widget.download_button.clicked.connect(self.on_download_clicked)
        self.dialog_widget.select_all_files_button.clicked.connect(self.on_all_files_selected_clicked)
        self.dialog_widget.deselect_all_files_button.clicked.connect(self.on_all_files_deselected_clicked)

        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'))

        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 = [url.decode('hex').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)

        self.dialog_widget.anon_download_checkbox.stateChanged.connect(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.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()

    def get_selected_files(self):
        included_files = []
        for ind in xrange(self.dialog_widget.files_list_view.topLevelItemCount()):
            item = self.dialog_widget.files_list_view.topLevelItem(ind)
            if item.checkState(2) == Qt.Checked:
                included_files.append(u'/'.join(item.data(0, Qt.UserRole)['path']))

        return included_files

    def perform_files_request(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("torrentinfo?uri=%s" % quote_plus_unicode(self.download_uri),
                                         self.on_received_metainfo, capture_errors=False)

    def on_received_metainfo(self, metainfo):
        if not metainfo:
            return

        if 'error' in metainfo:
            if metainfo['error'] == 'timeout':
                self.dialog_widget.loading_files_label.setText("Timeout when trying to fetch files.")
            elif 'code' in metainfo['error'] and metainfo['error']['code'] == 'IOError':
                self.dialog_widget.loading_files_label.setText("Unable to read torrent file data")
            else:
                self.dialog_widget.loading_files_label.setText("Error: %s" % metainfo['error'])
            return

        metainfo = metainfo['metainfo']
        if 'files' in metainfo['info']:  # Multi-file torrent
            files = metainfo['info']['files']
        else:
            files = [{'path': [metainfo['info']['name']], 'length': metainfo['info']['length']}]

        # Show if the torrent already exists in the downloads
        if 'download_exists' in metainfo and metainfo['download_exists']:
            self.dialog_widget.existing_download_info_label.setText("Note: this torrent already exists in the Downloads")
        else:
            self.dialog_widget.existing_download_info_label.setText("")

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

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

        self.received_metainfo.emit(metainfo)

    def on_browse_dir_clicked(self):
        chosen_dir = QFileDialog.getExistingDirectory(self.window(), "Please select the destination directory of your "
                                                                     "download", "", QFileDialog.ShowDirsOnly)

        if len(chosen_dir) != 0:
            self.dialog_widget.destination_input.setCurrentText(chosen_dir)

        is_writable, error = is_dir_writable(chosen_dir)
        if not is_writable:
            gui_error_message = "Tribler cannot download to <i>%s</i> directory. Please add proper write " \
                                "permissions to the directory or choose another download directory. [%s]" \
                                % (chosen_dir, error)
            ConfirmationDialog.show_message(self.dialog_widget, "Insufficient Permissions", gui_error_message, "OK")

    def on_anon_download_state_changed(self, _):
        if self.dialog_widget.anon_download_checkbox.isChecked():
            self.dialog_widget.safe_seed_checkbox.setChecked(True)
        self.dialog_widget.safe_seed_checkbox.setEnabled(not self.dialog_widget.anon_download_checkbox.isChecked())

    def on_download_clicked(self):
        if self.has_metainfo and len(self.get_selected_files()) == 0:  # User deselected all torrents
            ConfirmationDialog.show_error(self.window(), "No files selected",
                                          "Please select at least one file to download.")
        else:
            download_dir = self.dialog_widget.destination_input.currentText()
            is_writable, error = is_dir_writable(download_dir)
            if not is_writable:
                gui_error_message = "Tribler cannot download to <i>%s</i> directory. Please add proper write " \
                                    "permissions to the directory or choose another download directory and try " \
                                    "to download again. [%s]" % (download_dir, error)
                ConfirmationDialog.show_message(self.dialog_widget, "Insufficient Permissions", gui_error_message, "OK")
            else:
                self.button_clicked.emit(1)

    def on_all_files_selected_clicked(self):
        for ind in xrange(self.dialog_widget.files_list_view.topLevelItemCount()):
            item = self.dialog_widget.files_list_view.topLevelItem(ind)
            item.setCheckState(2, Qt.Checked)

    def on_all_files_deselected_clicked(self):
        for ind in xrange(self.dialog_widget.files_list_view.topLevelItemCount()):
            item = self.dialog_widget.files_list_view.topLevelItem(ind)
            item.setCheckState(2, Qt.Unchecked)
コード例 #37
0
ファイル: createtorrentpage.py プロジェクト: Tribler/tribler
class CreateTorrentPage(QWidget):
    """
    The CreateTorrentPage is the page where users can create torrent files so they can be added to their channel.
    """

    def __init__(self):
        QWidget.__init__(self)

        self.channel_identifier = None
        self.request_mgr = None
        self.dialog = None
        self.selected_item_index = -1
        self.initialized = False

    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')))

            self.window().create_torrent_files_list.customContextMenuRequested.connect(self.on_right_click_file_item)
            self.window().manage_channel_create_torrent_back.clicked.connect(self.on_create_torrent_manage_back_clicked)
            self.window().create_torrent_choose_files_button.clicked.connect(self.on_choose_files_clicked)
            self.window().create_torrent_choose_dir_button.clicked.connect(self.on_choose_dir_clicked)
            self.window().edit_channel_create_torrent_button.clicked.connect(self.on_create_clicked)

            self.initialized = True

    def on_create_torrent_manage_back_clicked(self):
        self.window().edit_channel_details_stacked_widget.setCurrentIndex(PAGE_EDIT_CHANNEL_TORRENTS)

    def on_choose_files_clicked(self):
        filenames, _ = QFileDialog.getOpenFileNames(self.window(), "Please select the files", QDir.homePath())

        for filename in filenames:
            self.window().create_torrent_files_list.addItem(filename)

    def on_choose_dir_clicked(self):
        chosen_dir = QFileDialog.getExistingDirectory(self.window(), "Please select the directory containing the files",
                                                      "", QFileDialog.ShowDirsOnly)

        if len(chosen_dir) == 0:
            return

        files = []
        for path, _, dir_files in os.walk(chosen_dir):
            for filename in dir_files:
                files.append(os.path.join(path, filename))

        self.window().create_torrent_files_list.clear()
        for filename in files:
            self.window().create_torrent_files_list.addItem(filename)

    def on_create_clicked(self):
        if self.window().create_torrent_files_list.count() == 0:
            self.dialog = ConfirmationDialog(self, "Notice", "You should add at least one file to your torrent.",
                                             [('CLOSE', BUTTON_TYPE_NORMAL)])
            self.dialog.button_clicked.connect(self.on_dialog_ok_clicked)
            self.dialog.show()
            return

        self.window().edit_channel_create_torrent_button.setEnabled(False)

        files_list = []
        for ind in xrange(self.window().create_torrent_files_list.count()):
            file_str = self.window().create_torrent_files_list.item(ind).text()
            files_list.append(file_str)

        name = self.window().create_torrent_name_field.text()
        description = self.window().create_torrent_description_field.toPlainText()
        post_data = {
            "name": name,
            "description": description,
            "files": files_list
        }
        url = "createtorrent?download=1" if self.window().seed_after_adding_checkbox.isChecked() else "createtorrent"
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request(url, self.on_torrent_created, data=post_data, method='POST')
        # Show creating torrent text
        self.window().edit_channel_create_torrent_progress_label.show()

    def on_dialog_ok_clicked(self, _):
        self.dialog.close_dialog()
        self.dialog = None

    def on_torrent_created(self, result):
        if not result:
            return
        self.window().edit_channel_create_torrent_button.setEnabled(True)
        if 'torrent' in result:
            self.add_torrent_to_channel(result['torrent'])

    def add_torrent_to_channel(self, torrent):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("mychannel/torrents", self.on_torrent_to_channel_added,
                                         data={"torrent": torrent}, method='PUT')

    def on_torrent_to_channel_added(self, result):
        if not result:
            return
        self.window().edit_channel_create_torrent_progress_label.hide()
        if 'added' in result:
            self.window().edit_channel_details_stacked_widget.setCurrentIndex(PAGE_EDIT_CHANNEL_TORRENTS)
            self.window().edit_channel_page.load_my_torrents()

    def on_remove_entry(self):
        self.window().create_torrent_files_list.takeItem(self.selected_item_index)

    def on_right_click_file_item(self, pos):
        item_clicked = self.window().create_torrent_files_list.itemAt(pos)
        if not item_clicked:
            return

        self.selected_item_index = self.window().create_torrent_files_list.row(item_clicked)

        menu = TriblerActionMenu(self)

        remove_action = QAction('Remove file', self)
        remove_action.triggered.connect(self.on_remove_entry)
        menu.addAction(remove_action)
        menu.exec_(self.window().create_torrent_files_list.mapToGlobal(pos))
コード例 #38
0
class ManagePlaylistPage(QWidget):
    """
    On this page, users can add or remove torrents from/to a playlist.
    """

    playlist_saved = pyqtSignal()

    def __init__(self):
        QWidget.__init__(self)

        self.channel_info = None
        self.playlist_info = None
        self.request_mgr = None

        self.torrents_in_playlist = []
        self.torrents_in_channel = []

        self.torrents_to_create = []
        self.torrents_to_remove = []

        self.pending_requests = []
        self.requests_done = 0

    def initialize(self, channel_info, playlist_info):
        self.channel_info = channel_info
        self.playlist_info = playlist_info
        self.window().edit_channel_details_manage_playlist_header.setText("Manage torrents in playlist '%s'" %
                                                                          playlist_info['name'])
        self.window().manage_channel_playlist_torrents_back.setIcon(QIcon(get_image_path('page_back.png')))

        self.window().playlist_manage_add_to_playlist.clicked.connect(self.on_add_clicked)
        self.window().playlist_manage_remove_from_playlist.clicked.connect(self.on_remove_clicked)
        self.window().edit_channel_manage_playlist_save_button.clicked.connect(self.on_save_clicked)
        self.window().manage_channel_playlist_torrents_back.clicked.connect(self.on_playlist_manage_back_clicked)

        # Load torrents in your channel
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("channels/discovered/%s/torrents?disable_filter=1" %
                                         channel_info["identifier"], self.on_received_channel_torrents)

        self.torrents_in_playlist = []
        self.torrents_in_channel = []

        self.torrents_to_create = []
        self.torrents_to_remove = []

        self.pending_requests = []
        self.requests_done = 0

    def on_playlist_manage_back_clicked(self):
        self.window().edit_channel_details_stacked_widget.setCurrentIndex(PAGE_EDIT_CHANNEL_PLAYLIST_TORRENTS)

    def update_lists(self):
        self.window().playlist_manage_in_channel_list.clear()
        self.window().playlist_manage_in_playlist_list.clear()

        for torrent in self.torrents_in_channel:
            item = QListWidgetItem(torrent["name"], self.window().playlist_manage_in_channel_list)
            item.setData(Qt.UserRole, torrent)
            self.window().playlist_manage_in_channel_list.addItem(item)

        for torrent in self.torrents_in_playlist:
            item = QListWidgetItem(torrent["name"], self.window().playlist_manage_in_playlist_list)
            item.setData(Qt.UserRole, torrent)
            self.window().playlist_manage_in_playlist_list.addItem(item)

    @staticmethod
    def remove_torrent_from_list(torrent, remove_from_list):
        index = -1
        for torrent_index in xrange(len(remove_from_list)):
            if remove_from_list[torrent_index]['infohash'] == torrent['infohash']:
                index = torrent_index
                break

        if index != -1:
            del remove_from_list[index]

    def on_received_channel_torrents(self, result):
        if not result:
            return
        self.torrents_in_playlist = self.playlist_info['torrents']

        self.torrents_in_channel = []
        for torrent in result['torrents']:
            if not ManagePlaylistPage.list_contains_torrent(self.torrents_in_playlist, torrent):
                self.torrents_in_channel.append(torrent)

        self.update_lists()

    @staticmethod
    def list_contains_torrent(torrent_list, torrent):
        for playlist_torrent in torrent_list:
            if torrent['infohash'] == playlist_torrent['infohash']:
                return True
        return False

    def on_add_clicked(self):
        for item in self.window().playlist_manage_in_channel_list.selectedItems():
            torrent = item.data(Qt.UserRole)
            ManagePlaylistPage.remove_torrent_from_list(torrent, self.torrents_in_channel)
            self.torrents_in_playlist.append(torrent)

            if ManagePlaylistPage.list_contains_torrent(self.torrents_to_remove, torrent):
                ManagePlaylistPage.remove_torrent_from_list(torrent, self.torrents_to_remove)
            self.torrents_to_create.append(torrent)

        self.update_lists()

    def on_remove_clicked(self):
        for item in self.window().playlist_manage_in_playlist_list.selectedItems():
            torrent = item.data(Qt.UserRole)
            ManagePlaylistPage.remove_torrent_from_list(torrent, self.torrents_in_playlist)
            self.torrents_in_channel.append(torrent)

            if ManagePlaylistPage.list_contains_torrent(self.torrents_to_create, torrent):
                ManagePlaylistPage.remove_torrent_from_list(torrent, self.torrents_to_create)
            self.torrents_to_remove.append(torrent)

        self.update_lists()

    def on_save_clicked(self):
        self.requests_done = 0
        self.pending_requests = []
        for torrent in self.torrents_to_create:
            request = TriblerRequestManager()
            request.perform_request("channels/discovered/%s/playlists/%s/%s" %
                                    (self.channel_info["identifier"], self.playlist_info['id'],
                                     torrent['infohash']), self.on_request_done, method="PUT")
            self.pending_requests.append(request)
        for torrent in self.torrents_to_remove:
            request = TriblerRequestManager()
            request.perform_request("channels/discovered/%s/playlists/%s/%s" %
                                    (self.channel_info["identifier"], self.playlist_info['id'], torrent['infohash']),
                                    self.on_request_done, method="DELETE")
            self.pending_requests.append(request)

    def on_request_done(self, result):
        if not result:
            return
        self.requests_done += 1
        if self.requests_done == len(self.pending_requests):
            self.on_requests_done()

    def on_requests_done(self):
        self.window().edit_channel_details_stacked_widget.setCurrentIndex(PAGE_EDIT_CHANNEL_PLAYLIST_TORRENTS)
        self.playlist_saved.emit()
コード例 #39
0
class DebugWindow(QMainWindow):
    """
    The debug window shows various statistics about Tribler such as performed requests, Dispersy statistics and
    community information.
    """

    def __init__(self, settings):
        QMainWindow.__init__(self)

        self.request_mgr = None

        uic.loadUi(get_ui_file_path('debugwindow.ui'), self)
        self.setWindowTitle("Tribler debug pane")

        self.window().debug_tab_widget.setCurrentIndex(0)
        self.window().dispersy_tab_widget.setCurrentIndex(0)
        self.window().debug_tab_widget.currentChanged.connect(self.tab_changed)
        self.window().dispersy_tab_widget.currentChanged.connect(self.dispersy_tab_changed)
        self.window().events_tree_widget.itemClicked.connect(self.on_event_clicked)
        self.load_general_tab()

        if not settings['trustchain']['enabled']:
            self.window().debug_tab_widget.setTabEnabled(2, False)

    def tab_changed(self, index):
        if index == 0:
            self.load_general_tab()
        elif index == 1:
            self.load_requests_tab()
        elif index == 2:
            self.load_trustchain_tab()
        elif index == 3:
            self.dispersy_tab_changed(self.window().dispersy_tab_widget.currentIndex())
        elif index == 4:
            self.load_events_tab()

    def dispersy_tab_changed(self, index):
        if index == 0:
            self.load_dispersy_general_tab()
        elif index == 1:
            self.load_dispersy_communities_tab()

    def create_and_add_widget_item(self, key, value, widget):
        item = QTreeWidgetItem(widget)
        item.setText(0, key)
        item.setText(1, "%s" % value)
        widget.addTopLevelItem(item)

    def load_general_tab(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("statistics/tribler", self.on_tribler_statistics)

    def on_tribler_statistics(self, data):
        data = data["tribler_statistics"]
        self.window().general_tree_widget.clear()
        self.create_and_add_widget_item("Number of channels", data["num_channels"], self.window().general_tree_widget)
        self.create_and_add_widget_item("Database size", format_size(data["database_size"]),
                                        self.window().general_tree_widget)
        self.create_and_add_widget_item("Number of collected torrents", data["torrents"]["num_collected"],
                                        self.window().general_tree_widget)
        self.create_and_add_widget_item("Number of torrent files", data["torrents"]["num_files"],
                                        self.window().general_tree_widget)
        self.create_and_add_widget_item("Total size of torrent files", format_size(data["torrents"]["total_size"]),
                                        self.window().general_tree_widget)

    def load_requests_tab(self):
        self.window().requests_tree_widget.clear()
        for endpoint, method, data, timestamp, status_code in sorted(tribler_performed_requests.values(),
                                                                     key=lambda x: x[3]):
            item = QTreeWidgetItem(self.window().requests_tree_widget)
            item.setText(0, "%s %s %s" % (method, endpoint, data))
            item.setText(1, ("%d" % status_code) if status_code else "unknown")
            item.setText(2, "%s" % strftime("%H:%M:%S", localtime(timestamp)))
            self.window().requests_tree_widget.addTopLevelItem(item)

    def load_trustchain_tab(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("trustchain/statistics", self.on_trustchain_statistics)

    def on_trustchain_statistics(self, data):
        self.window().trustchain_tree_widget.clear()
        for key, value in data["statistics"].iteritems():
            self.create_and_add_widget_item(key, value, self.window().trustchain_tree_widget)

    def load_dispersy_general_tab(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("statistics/dispersy", self.on_dispersy_general_stats)

    def on_dispersy_general_stats(self, data):
        self.window().dispersy_general_tree_widget.clear()
        for key, value in data["dispersy_statistics"].iteritems():
            self.create_and_add_widget_item(key, value, self.window().dispersy_general_tree_widget)

    def load_dispersy_communities_tab(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("statistics/communities", self.on_dispersy_community_stats)

    def on_dispersy_community_stats(self, data):
        self.window().communities_tree_widget.clear()
        for community in data["community_statistics"]:
            item = QTreeWidgetItem(self.window().communities_tree_widget)
            item.setText(0, community["classification"])
            item.setText(1, community["identifier"][:6])
            item.setText(2, community["member"][:6])
            item.setText(3, "%s" % community["candidates"])
            self.window().communities_tree_widget.addTopLevelItem(item)

    def on_event_clicked(self, item):
        event_dict = item.data(0, Qt.UserRole)
        self.window().event_text_box.setPlainText(json.dumps(event_dict))

    def load_events_tab(self):
        self.window().events_tree_widget.clear()
        for event_dict, timestamp in tribler_received_events:
            item = QTreeWidgetItem(self.window().events_tree_widget)
            item.setData(0, Qt.UserRole, event_dict)
            item.setText(0, "%s" % event_dict['type'])
            item.setText(1, "%s" % strftime("%H:%M:%S", localtime(timestamp)))
            self.window().events_tree_widget.addTopLevelItem(item)
コード例 #40
0
class EditChannelPage(QWidget):
    """
    This class is responsible for managing lists and data on the your channel page, including torrents, playlists
    and rss feeds.
    """
    playlists_loaded = pyqtSignal(object)

    def __init__(self):
        QWidget.__init__(self)

        self.remove_torrent_requests = []
        self.channel_overview = None
        self.playlists = None
        self.editing_playlist = None
        self.viewing_playlist = None
        self.editing_own_channel = False
        self.dialog = None
        self.editchannel_request_mgr = None

    def initialize_edit_channel_page(self):
        self.window().create_channel_intro_button.clicked.connect(
            self.on_create_channel_intro_button_clicked)

        self.window().create_channel_form.hide()

        self.window().edit_channel_stacked_widget.setCurrentIndex(1)
        self.window().edit_channel_details_stacked_widget.setCurrentIndex(
            PAGE_EDIT_CHANNEL_OVERVIEW)

        self.window().create_channel_button.clicked.connect(
            self.on_create_channel_button_pressed)
        self.window().edit_channel_save_button.clicked.connect(
            self.on_edit_channel_save_button_pressed)

        self.window(
        ).edit_channel_torrents_remove_selected_button.clicked.connect(
            self.on_torrents_remove_selected_clicked)
        self.window().edit_channel_torrents_remove_all_button.clicked.connect(
            self.on_torrents_remove_all_clicked)
        self.window().edit_channel_torrents_add_button.clicked.connect(
            self.on_torrents_add_clicked)

        self.window(
        ).edit_channel_details_playlist_manage.playlist_saved.connect(
            self.load_channel_playlists)

        self.window().edit_channel_playlist_torrents_back.clicked.connect(
            self.on_playlist_torrents_back_clicked)
        self.window().edit_channel_playlists_list.itemClicked.connect(
            self.on_playlist_item_clicked)
        self.window(
        ).edit_channel_playlist_manage_torrents_button.clicked.connect(
            self.on_playlist_manage_clicked)
        self.window().edit_channel_create_playlist_button.clicked.connect(
            self.on_playlist_created_clicked)

        self.window().playlist_edit_save_button.clicked.connect(
            self.on_playlist_edit_save_clicked)
        self.window().playlist_edit_cancel_button.clicked.connect(
            self.on_playlist_edit_cancel_clicked)

        self.window(
        ).edit_channel_details_rss_feeds_remove_selected_button.clicked.connect(
            self.on_rss_feeds_remove_selected_clicked)
        self.window().edit_channel_details_rss_add_button.clicked.connect(
            self.on_rss_feed_add_clicked)
        self.window().edit_channel_details_rss_refresh_button.clicked.connect(
            self.on_rss_feeds_refresh_clicked)

        # Tab bar buttons
        self.window().channel_settings_tab.initialize()
        self.window().channel_settings_tab.clicked_tab_button.connect(
            self.clicked_tab_button)

    def load_my_channel_overview(self):
        if not self.channel_overview:
            self.window().edit_channel_stacked_widget.setCurrentIndex(2)

        self.editchannel_request_mgr = TriblerRequestManager()
        self.editchannel_request_mgr.perform_request(
            "mychannel",
            self.initialize_with_channel_overview,
            capture_errors=False)

    def initialize_with_channel_overview(self, overview):
        if 'error' in overview:
            self.window().edit_channel_stacked_widget.setCurrentIndex(0)
        else:
            if "mychannel" in overview:
                self.channel_overview = overview["mychannel"]
                self.set_editing_own_channel(True)
                self.window().edit_channel_name_label.setText("My channel")
            else:
                self.channel_overview = overview["channel"]
                self.set_editing_own_channel(False)
                self.window().edit_channel_name_label.setText(
                    self.channel_overview["name"])

            self.window().edit_channel_overview_name_label.setText(
                self.channel_overview["name"])
            self.window().edit_channel_description_label.setText(
                self.channel_overview["description"])
            self.window().edit_channel_identifier_label.setText(
                self.channel_overview["identifier"])

            self.window().edit_channel_name_edit.setText(
                self.channel_overview["name"])
            self.window().edit_channel_description_edit.setText(
                self.channel_overview["description"])

            self.window().edit_channel_stacked_widget.setCurrentIndex(1)

    def set_editing_own_channel(self, edit_own):
        self.editing_own_channel = edit_own

        self.window().edit_channel_settings_button.setHidden(not edit_own)
        self.window().edit_channel_rss_feeds_button.setHidden(not edit_own)
        self.window().edit_channel_playlists_button.setHidden(not edit_own)

        self.window().edit_channel_torrents_remove_all_button.setHidden(
            not edit_own)
        self.window().edit_channel_torrents_remove_selected_button.setHidden(
            not edit_own)

    def load_channel_torrents(self):
        self.window().edit_channel_torrents_list.set_data_items([
            (LoadingListItem, None)
        ])
        self.editchannel_request_mgr = TriblerRequestManager()
        self.editchannel_request_mgr.perform_request(
            "channels/discovered/%s/torrents?disable_filter=1" %
            self.channel_overview["identifier"], self.initialize_with_torrents)

    def initialize_with_torrents(self, torrents):
        self.window().edit_channel_torrents_list.set_data_items([])

        items = []
        for result in torrents['torrents']:
            items.append((ChannelTorrentListItem, result, {
                "show_controls": True,
                "on_remove_clicked": self.on_torrent_remove_clicked
            }))
        self.window().edit_channel_torrents_list.set_data_items(items)

    def load_channel_playlists(self):
        self.window().edit_channel_playlists_list.set_data_items([
            (LoadingListItem, None)
        ])
        self.editchannel_request_mgr = TriblerRequestManager()
        self.editchannel_request_mgr.perform_request(
            "channels/discovered/%s/playlists?disable_filter=1" %
            self.channel_overview["identifier"],
            self.initialize_with_playlists)

    def initialize_with_playlists(self, playlists):
        self.playlists_loaded.emit(playlists)
        self.playlists = playlists
        self.window().edit_channel_playlists_list.set_data_items([])

        self.update_playlist_list()

        viewing_playlist_index = self.get_index_of_viewing_playlist()
        if viewing_playlist_index != -1:
            self.viewing_playlist = self.playlists['playlists'][
                viewing_playlist_index]
            self.update_playlist_torrent_list()

    def load_channel_rss_feeds(self):
        self.editchannel_request_mgr = TriblerRequestManager()
        self.editchannel_request_mgr.perform_request(
            "channels/discovered/%s/rssfeeds" %
            self.channel_overview["identifier"],
            self.initialize_with_rss_feeds)

    def initialize_with_rss_feeds(self, rss_feeds):
        self.window().edit_channel_rss_feeds_list.clear()
        for feed in rss_feeds["rssfeeds"]:
            item = QTreeWidgetItem(self.window().edit_channel_rss_feeds_list)
            item.setText(0, feed["url"])

            self.window().edit_channel_rss_feeds_list.addTopLevelItem(item)

    def on_torrent_remove_clicked(self, item):
        self.dialog = ConfirmationDialog(
            self, "Remove selected torrent",
            "Are you sure that you want to remove the selected torrent from this channel?",
            [('CONFIRM', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)])
        self.dialog.button_clicked.connect(
            lambda action: self.on_torrents_remove_selected_action(
                action, item))
        self.dialog.show()

    def on_create_channel_button_pressed(self):
        channel_name = self.window().new_channel_name_edit.text()
        channel_description = self.window(
        ).new_channel_description_edit.toPlainText()
        if len(channel_name) == 0:
            self.window().new_channel_name_label.setStyleSheet("color: red;")
            return

        self.window().create_channel_button.setEnabled(False)
        self.editchannel_request_mgr = TriblerRequestManager()
        self.editchannel_request_mgr.perform_request(
            "channels/discovered",
            self.on_channel_created,
            data=unicode('name=%s&description=%s' %
                         (channel_name, channel_description)).encode('utf-8'),
            method='PUT')

    def on_channel_created(self, result):
        if u'added' in result:
            self.window().create_channel_button.setEnabled(True)
            self.load_my_channel_overview()

    def on_edit_channel_save_button_pressed(self):
        channel_name = self.window().edit_channel_name_edit.text()
        channel_description = self.window(
        ).edit_channel_description_edit.toPlainText()

        self.editchannel_request_mgr = TriblerRequestManager()
        self.editchannel_request_mgr.perform_request(
            "mychannel",
            self.on_channel_edited,
            data=unicode('name=%s&description=%s' %
                         (channel_name, channel_description)).encode('utf-8'),
            method='POST')

    def on_channel_edited(self, result):
        if 'modified' in result:
            self.window().edit_channel_name_label.setText(
                self.window().edit_channel_name_edit.text())
            self.window().edit_channel_description_label.setText(
                self.window().edit_channel_description_edit.toPlainText())

    def on_torrents_remove_selected_clicked(self):
        num_selected = len(
            self.window().edit_channel_torrents_list.selectedItems())
        if num_selected == 0:
            return

        selected_torrent_items = [
            self.window().edit_channel_torrents_list.itemWidget(
                list_widget_item) for list_widget_item in
            self.window().edit_channel_torrents_list.selectedItems()
        ]

        self.dialog = ConfirmationDialog(
            self, "Remove %s selected torrents" % num_selected,
            "Are you sure that you want to remove %s selected torrents "
            "from your channel?" % num_selected,
            [('CONFIRM', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)])
        self.dialog.button_clicked.connect(
            lambda action: self.on_torrents_remove_selected_action(
                action, selected_torrent_items))
        self.dialog.show()

    def on_torrents_remove_all_clicked(self):
        self.dialog = ConfirmationDialog(
            self.window(), "Remove all torrents",
            "Are you sure that you want to remove all torrents from your channel? "
            "You cannot undo this action.", [('CONFIRM', BUTTON_TYPE_NORMAL),
                                             ('CANCEL', BUTTON_TYPE_CONFIRM)])
        self.dialog.button_clicked.connect(self.on_torrents_remove_all_action)
        self.dialog.show()

    def on_torrents_add_clicked(self):
        menu = TriblerActionMenu(self)

        browse_files_action = QAction('Import torrent from file', self)
        add_url_action = QAction('Add URL', self)
        create_torrent_action = QAction('Create torrent from file(s)', self)

        browse_files_action.triggered.connect(self.on_add_torrent_browse_file)
        add_url_action.triggered.connect(self.on_add_torrent_from_url)
        create_torrent_action.triggered.connect(
            self.on_create_torrent_from_files)

        menu.addAction(browse_files_action)
        menu.addAction(add_url_action)
        menu.addAction(create_torrent_action)

        menu.exec_(QCursor.pos())

    def on_add_torrent_browse_file(self):
        filename = QFileDialog.getOpenFileName(
            self, "Please select the .torrent file", "",
            "Torrent files (*.torrent)")

        if len(filename[0]) == 0:
            return

        with open(filename[0], "rb") as torrent_file:
            torrent_content = urllib.quote_plus(
                base64.b64encode(torrent_file.read()))
            self.editchannel_request_mgr = TriblerRequestManager()
            self.editchannel_request_mgr.perform_request(
                "channels/discovered/%s/torrents" %
                self.channel_overview['identifier'],
                self.on_torrent_to_channel_added,
                method='PUT',
                data='torrent=%s' % torrent_content)

    def on_add_torrent_from_url(self):
        self.dialog = ConfirmationDialog(
            self,
            "Add torrent from URL/magnet link",
            "Please enter the URL/magnet link in the field below:",
            [('ADD', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)],
            show_input=True)
        self.dialog.dialog_widget.dialog_input.setPlaceholderText(
            'URL/magnet link')
        self.dialog.button_clicked.connect(
            self.on_torrent_from_url_dialog_done)
        self.dialog.show()

    def on_torrent_from_url_dialog_done(self, action):
        if action == 0:
            url = urllib.quote_plus(
                self.dialog.dialog_widget.dialog_input.text())
            self.editchannel_request_mgr = TriblerRequestManager()
            self.editchannel_request_mgr.perform_request(
                "channels/discovered/%s/torrents/%s" %
                (self.channel_overview['identifier'], url),
                self.on_torrent_to_channel_added,
                method='PUT')

        self.dialog.setParent(None)
        self.dialog = None

    def on_torrent_to_channel_added(self, result):
        if 'added' in result:
            self.load_channel_torrents()

    def on_create_torrent_from_files(self):
        self.window().edit_channel_details_create_torrent.initialize(
            self.channel_overview['identifier'])
        self.window().edit_channel_details_stacked_widget.setCurrentIndex(
            PAGE_EDIT_CHANNEL_CREATE_TORRENT)

    def on_playlist_torrents_back_clicked(self):
        self.window().edit_channel_details_stacked_widget.setCurrentIndex(
            PAGE_EDIT_CHANNEL_PLAYLISTS)

    def on_playlist_item_clicked(self, item):
        playlist_info = item.data(Qt.UserRole)
        self.window().edit_channel_playlist_torrents_list.set_data_items([])
        self.window().edit_channel_details_playlist_torrents_header.setText(
            "Torrents in '%s'" % playlist_info['name'])
        self.window().edit_channel_playlist_torrents_back.setIcon(
            QIcon(get_image_path('page_back.png')))

        self.viewing_playlist = playlist_info
        self.update_playlist_torrent_list()

        self.window().edit_channel_details_stacked_widget.setCurrentIndex(
            PAGE_EDIT_CHANNEL_PLAYLIST_TORRENTS)

    def update_playlist_list(self):
        self.playlists['playlists'].sort(
            key=lambda torrent: len(torrent['torrents']), reverse=True)

        items = []
        for result in self.playlists['playlists']:
            items.append((PlaylistListItem, result, {
                "show_controls": True,
                "on_remove_clicked": self.on_playlist_remove_clicked,
                "on_edit_clicked": self.on_playlist_edit_clicked
            }))
        self.window().edit_channel_playlists_list.set_data_items(items)

    def update_playlist_torrent_list(self):
        items = []
        for torrent in self.viewing_playlist["torrents"]:
            items.append((ChannelTorrentListItem, torrent, {
                "show_controls":
                True,
                "on_remove_clicked":
                self.on_playlist_torrent_remove_clicked
            }))
        self.window().edit_channel_playlist_torrents_list.set_data_items(items)

    def on_playlist_manage_clicked(self):
        self.window().edit_channel_details_playlist_manage.initialize(
            self.channel_overview, self.viewing_playlist)
        self.window().edit_channel_details_stacked_widget.setCurrentIndex(
            PAGE_EDIT_CHANNEL_PLAYLIST_MANAGE)

    def on_playlist_torrent_remove_clicked(self, item):
        self.dialog = ConfirmationDialog(
            self, "Remove selected torrent from playlist",
            "Are you sure that you want to remove the selected torrent "
            "from this playlist?", [('CONFIRM', BUTTON_TYPE_NORMAL),
                                    ('CANCEL', BUTTON_TYPE_CONFIRM)])
        self.dialog.button_clicked.connect(
            lambda action: self.on_playlist_torrent_remove_selected_action(
                item, action))
        self.dialog.show()

    def on_playlist_torrent_remove_selected_action(self, item, action):
        if action == 0:
            self.editchannel_request_mgr = TriblerRequestManager()
            self.editchannel_request_mgr.perform_request(
                "channels/discovered/%s/playlists/%s/%s" %
                (self.channel_overview["identifier"],
                 self.viewing_playlist['id'], item.torrent_info['infohash']),
                lambda result: self.on_playlist_torrent_removed(
                    result, item.torrent_info),
                method='DELETE')

        self.dialog.setParent(None)
        self.dialog = None

    def on_playlist_torrent_removed(self, result, torrent):
        self.remove_torrent_from_playlist(torrent)

    def get_index_of_viewing_playlist(self):
        if self.viewing_playlist is None:
            return -1

        for index in xrange(len(self.playlists['playlists'])):
            if self.playlists['playlists'][index][
                    'id'] == self.viewing_playlist['id']:
                return index

        return -1

    def remove_torrent_from_playlist(self, torrent):
        playlist_index = self.get_index_of_viewing_playlist()

        torrent_index = -1
        for index in xrange(len(self.viewing_playlist['torrents'])):
            if self.viewing_playlist['torrents'][index]['infohash'] == torrent[
                    'infohash']:
                torrent_index = index
                break

        if torrent_index != -1:
            del self.playlists['playlists'][playlist_index]['torrents'][
                torrent_index]
            self.viewing_playlist = self.playlists['playlists'][playlist_index]
            self.update_playlist_list()
            self.update_playlist_torrent_list()

    def on_playlist_edit_save_clicked(self):
        if len(self.window().playlist_edit_name.text()) == 0:
            return

        name = self.window().playlist_edit_name.text()
        description = self.window().playlist_edit_description.toPlainText()

        self.editchannel_request_mgr = TriblerRequestManager()
        if self.editing_playlist is None:
            self.editchannel_request_mgr.perform_request(
                "channels/discovered/%s/playlists" %
                self.channel_overview["identifier"],
                self.on_playlist_created,
                data=unicode('name=%s&description=%s' %
                             (name, description)).encode('utf-8'),
                method='PUT')
        else:
            self.editchannel_request_mgr.perform_request(
                "channels/discovered/%s/playlists/%s" %
                (self.channel_overview["identifier"],
                 self.editing_playlist["id"]),
                self.on_playlist_edited,
                data=unicode('name=%s&description=%s' %
                             (name, description)).encode('utf-8'),
                method='POST')

    def on_playlist_created(self, json_result):
        if 'created' in json_result and json_result['created']:
            self.on_playlist_edited_done()

    def on_playlist_edited(self, json_result):
        if 'modified' in json_result and json_result['modified']:
            self.on_playlist_edited_done()

    def on_playlist_edited_done(self):
        self.window().playlist_edit_name.setText('')
        self.window().playlist_edit_description.setText('')
        self.load_channel_playlists()
        self.window().edit_channel_details_stacked_widget.setCurrentIndex(
            PAGE_EDIT_CHANNEL_PLAYLISTS)

    def on_playlist_edit_cancel_clicked(self):
        self.window().edit_channel_details_stacked_widget.setCurrentIndex(
            PAGE_EDIT_CHANNEL_PLAYLISTS)

    def on_playlist_created_clicked(self):
        self.editing_playlist = None
        self.window().playlist_edit_save_button.setText("CREATE")
        self.window().edit_channel_details_stacked_widget.setCurrentIndex(
            PAGE_EDIT_CHANNEL_PLAYLIST_EDIT)

    def on_playlist_remove_clicked(self, item):
        self.dialog = ConfirmationDialog(
            self, "Remove selected playlist",
            "Are you sure that you want to remove the selected playlist "
            "from your channel?", [('CONFIRM', BUTTON_TYPE_NORMAL),
                                   ('CANCEL', BUTTON_TYPE_CONFIRM)])
        self.dialog.button_clicked.connect(
            lambda action: self.on_playlist_remove_selected_action(
                item, action))
        self.dialog.show()

    def on_playlist_remove_selected_action(self, item, action):
        if action == 0:
            self.editchannel_request_mgr = TriblerRequestManager()
            self.editchannel_request_mgr.perform_request(
                "channels/discovered/%s/playlists/%s" %
                (self.channel_overview["identifier"],
                 item.playlist_info['id']),
                self.on_playlist_removed,
                method='DELETE')

        self.dialog.setParent(None)
        self.dialog = None

    def on_playlist_removed(self, json_result):
        if 'removed' in json_result and json_result['removed']:
            self.load_channel_playlists()

    def on_playlist_edit_clicked(self, item):
        self.editing_playlist = item.playlist_info
        self.window().playlist_edit_save_button.setText("CREATE")
        self.window().playlist_edit_name.setText(item.playlist_info["name"])
        self.window().playlist_edit_description.setText(
            item.playlist_info["description"])
        self.window().edit_channel_details_stacked_widget.setCurrentIndex(
            PAGE_EDIT_CHANNEL_PLAYLIST_EDIT)

    def on_torrents_remove_selected_action(self, action, items):
        if action == 0:

            if isinstance(items, list):
                infohash = ",".join([
                    torrent_item.torrent_info['infohash']
                    for torrent_item in items
                ])
            else:
                infohash = items.torrent_info['infohash']
            self.editchannel_request_mgr = TriblerRequestManager()
            self.editchannel_request_mgr.perform_request(
                "channels/discovered/%s/torrents/%s" %
                (self.channel_overview["identifier"], infohash),
                self.on_torrent_removed,
                method='DELETE')

        self.dialog.setParent(None)
        self.dialog = None

    def on_torrent_removed(self, json_result):
        if 'removed' in json_result and json_result['removed']:
            self.load_channel_torrents()

    def on_torrents_remove_all_action(self, action):
        if action == 0:
            for torrent_ind in xrange(
                    self.window().edit_channel_torrents_list.count()):
                torrent_data = self.window().edit_channel_torrents_list.item(
                    torrent_ind).data(Qt.UserRole)
                request_mgr = TriblerRequestManager()
                request_mgr.perform_request(
                    "channels/discovered/%s/torrents/%s" %
                    (self.channel_overview["identifier"],
                     torrent_data['infohash']),
                    None,
                    method='DELETE')
                self.remove_torrent_requests.append(request_mgr)

            self.window().edit_channel_torrents_list.set_data_items([])

        self.dialog.setParent(None)
        self.dialog = None

    def clicked_tab_button(self, tab_button_name):
        if tab_button_name == "edit_channel_overview_button":
            self.window().edit_channel_details_stacked_widget.setCurrentIndex(
                PAGE_EDIT_CHANNEL_OVERVIEW)
        elif tab_button_name == "edit_channel_settings_button":
            self.window().edit_channel_details_stacked_widget.setCurrentIndex(
                PAGE_EDIT_CHANNEL_SETTINGS)
        elif tab_button_name == "edit_channel_torrents_button":
            self.window().edit_channel_details_stacked_widget.setCurrentIndex(
                PAGE_EDIT_CHANNEL_TORRENTS)
            self.load_channel_torrents()
        elif tab_button_name == "edit_channel_playlists_button":
            self.window().edit_channel_details_stacked_widget.setCurrentIndex(
                PAGE_EDIT_CHANNEL_PLAYLISTS)
            self.load_channel_playlists()
        elif tab_button_name == "edit_channel_rss_feeds_button":
            self.window().edit_channel_details_stacked_widget.setCurrentIndex(
                PAGE_EDIT_CHANNEL_RSS_FEEDS)
            self.load_channel_rss_feeds()

    def on_create_channel_intro_button_clicked(self):
        self.window().create_channel_form.show()
        self.window().create_channel_intro_button_container.hide()
        self.window().create_new_channel_intro_label.setText(
            "Please enter your channel details below.")

    def on_rss_feed_add_clicked(self):
        self.dialog = ConfirmationDialog(
            self,
            "Add RSS feed",
            "Please enter the RSS feed URL in the field below:",
            [('ADD', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)],
            show_input=True)
        self.dialog.dialog_widget.dialog_input.setPlaceholderText(
            'RSS feed URL')
        self.dialog.button_clicked.connect(self.on_rss_feed_dialog_added)
        self.dialog.show()

    def on_rss_feed_dialog_added(self, action):
        if action == 0:
            url = urllib.quote_plus(
                self.dialog.dialog_widget.dialog_input.text())
            self.editchannel_request_mgr = TriblerRequestManager()
            self.editchannel_request_mgr.perform_request(
                "channels/discovered/%s/rssfeeds/%s" %
                (self.channel_overview["identifier"], url),
                self.on_rss_feed_added,
                method='PUT')

        self.dialog.setParent(None)
        self.dialog = None

    def on_rss_feed_added(self, json_result):
        if json_result['added']:
            self.load_channel_rss_feeds()

    def on_rss_feeds_remove_selected_clicked(self):
        if len(self.window().edit_channel_rss_feeds_list.selectedItems()) == 0:
            ConfirmationDialog.show_message(
                self, "Remove RSS Feeds",
                "Selection is empty. Please select the feeds to remove.", "OK")
            return
        self.dialog = ConfirmationDialog(
            self, "Remove RSS feed",
            "Are you sure you want to remove the selected RSS feed?",
            [('REMOVE', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)])
        self.dialog.button_clicked.connect(self.on_rss_feed_dialog_removed)
        self.dialog.show()

    def on_rss_feed_dialog_removed(self, action):
        if action == 0:
            url = urllib.quote_plus(
                self.window().edit_channel_rss_feeds_list.selectedItems()
                [0].text(0))
            self.editchannel_request_mgr = TriblerRequestManager()
            self.editchannel_request_mgr.perform_request(
                "channels/discovered/%s/rssfeeds/%s" %
                (self.channel_overview["identifier"], url),
                self.on_rss_feed_removed,
                method='DELETE')

        self.dialog.setParent(None)
        self.dialog = None

    def on_rss_feed_removed(self, json_result):
        if json_result['removed']:
            self.load_channel_rss_feeds()

    def on_rss_feeds_refresh_clicked(self):
        self.window().edit_channel_details_rss_refresh_button.setEnabled(False)
        self.editchannel_request_mgr = TriblerRequestManager()
        self.editchannel_request_mgr.perform_request('channels/discovered/%s/recheckfeeds' %
                                                     self.channel_overview["identifier"], self.on_rss_feeds_refreshed,\
                                                     method='POST')

    def on_rss_feeds_refreshed(self, json_result):
        if json_result["rechecked"]:
            self.window().edit_channel_details_rss_refresh_button.setEnabled(
                True)
コード例 #41
0
ファイル: settingspage.py プロジェクト: Tribler/tribler
class SettingsPage(QWidget):
    """
    This class is responsible for displaying and adjusting the settings present in Tribler.
    """

    def __init__(self):
        QWidget.__init__(self)
        self.settings = None
        self.settings_request_mgr = None
        self.trustchain_request_mgr = None
        self.saved_dialog = None
        self.empty_tokens_barcode_dialog = None
        self.empty_partial_tokens_dialog = None
        self.confirm_empty_tokens_dialog = None

    def initialize_settings_page(self):
        self.window().settings_tab.initialize()
        self.window().settings_tab.clicked_tab_button.connect(self.clicked_tab_button)
        self.window().settings_save_button.clicked.connect(self.save_settings)

        self.window().download_location_chooser_button.clicked.connect(self.on_choose_download_dir_clicked)
        self.window().watch_folder_chooser_button.clicked.connect(self.on_choose_watch_dir_clicked)

        self.window().channel_autocommit_checkbox.stateChanged.connect(self.on_channel_autocommit_checkbox_changed)
        self.window().family_filter_checkbox.stateChanged.connect(self.on_family_filter_checkbox_changed)
        self.window().developer_mode_enabled_checkbox.stateChanged.connect(self.on_developer_mode_checkbox_changed)
        self.window().use_monochrome_icon_checkbox.stateChanged.connect(self.on_use_monochrome_icon_checkbox_changed)
        self.window().download_settings_anon_checkbox.stateChanged.connect(self.on_anon_download_state_changed)
        self.window().fully_empty_tokens_button.clicked.connect(self.confirm_fully_empty_tokens)
        self.window().partially_empty_tokens_button.clicked.connect(self.partially_empty_tokens)
        self.window().log_location_chooser_button.clicked.connect(self.on_choose_log_dir_clicked)

        self.update_stacked_widget_height()

    def confirm_fully_empty_tokens(self):
        self.confirm_empty_tokens_dialog = ConfirmationDialog(self, "Empty tokens into another account",
                                                              "Are you sure you want to empty ALL bandwidth tokens "
                                                              "into another account? "
                                                              "Warning: one-way action that cannot be revered",
                                                              [
                                                                  ('EMPTY', BUTTON_TYPE_CONFIRM),
                                                                  ('CANCEL', BUTTON_TYPE_NORMAL)
                                                              ])
        self.confirm_empty_tokens_dialog.button_clicked.connect(self.on_confirm_fully_empty_tokens)
        self.confirm_empty_tokens_dialog.show()

    def on_confirm_fully_empty_tokens(self, action):
        self.confirm_empty_tokens_dialog.close_dialog()
        self.confirm_empty_tokens_dialog = None

        if action == 0:
            self.trustchain_request_mgr = TriblerRequestManager()
            self.trustchain_request_mgr.perform_request("trustchain/bootstrap", self.on_emptying_tokens)

    def partially_empty_tokens(self):
        self.empty_partial_tokens_dialog = ConfirmationDialog(self, "Empty tokens into another account",
                                                              "Specify the amount of bandwidth tokens to empty into "
                                                              "another account below:",
                                                              [
                                                                  ('EMPTY', BUTTON_TYPE_CONFIRM),
                                                                  ('CANCEL', BUTTON_TYPE_NORMAL)
                                                              ], show_input=True)
        self.empty_partial_tokens_dialog.dialog_widget.dialog_input.setPlaceholderText(
            'Please enter the amount of tokens in MB')
        self.empty_partial_tokens_dialog.dialog_widget.dialog_input.setFocus()
        self.empty_partial_tokens_dialog.button_clicked.connect(self.confirm_partially_empty_tokens)
        self.empty_partial_tokens_dialog.show()

    def confirm_partially_empty_tokens(self, action):
        tokens = self.empty_partial_tokens_dialog.dialog_widget.dialog_input.text()
        self.empty_partial_tokens_dialog.close_dialog()
        self.empty_partial_tokens_dialog = None

        if action == 0:
            try:
                tokens = int(float(tokens))
            except ValueError:
                ConfirmationDialog.show_error(self.window(), "Wrong input", "The provided amount is not a number")
                return

            self.confirm_empty_tokens_dialog = ConfirmationDialog(self, "Empty tokens into another account",
                                                                  "Are you sure you want to empty %d bandwidth tokens "
                                                                  "into another account? "
                                                                  "Warning: one-way action that cannot be revered" %
                                                                  tokens,
                                                                  [
                                                                      ('EMPTY', BUTTON_TYPE_NORMAL),
                                                                      ('CANCEL', BUTTON_TYPE_CONFIRM)
                                                                  ])
            self.confirm_empty_tokens_dialog.button_clicked.connect(
                lambda action2: self.on_confirm_partially_empty_tokens(action2, tokens))
            self.confirm_empty_tokens_dialog.show()

    def on_confirm_partially_empty_tokens(self, action, tokens):
        self.confirm_empty_tokens_dialog.close_dialog()
        self.confirm_empty_tokens_dialog = None
        if action == 0:
            self.trustchain_request_mgr = TriblerRequestManager()
            self.trustchain_request_mgr.perform_request("trustchain/bootstrap?amount=%d" % (tokens * MEBIBYTE),
                                                        self.on_emptying_tokens)

    def on_emptying_tokens(self, data):
        if not data:
            return
        json_data = json.dumps(data)

        if has_qr:
            self.empty_tokens_barcode_dialog = QWidget()
            self.empty_tokens_barcode_dialog.setWindowTitle("Please scan the following QR code")
            self.empty_tokens_barcode_dialog.setGeometry(10, 10, 500, 500)
            qr = qrcode.QRCode(
                version=1,
                error_correction=qrcode.constants.ERROR_CORRECT_M,
                box_size=10,
                border=5,
            )
            qr.add_data(json_data)
            qr.make(fit=True)

            img = qr.make_image()  # PIL format

            qim = ImageQt(img)
            pixmap = QtGui.QPixmap.fromImage(qim).scaled(600, 600, QtCore.Qt.KeepAspectRatio)
            label = QLabel(self.empty_tokens_barcode_dialog)
            label.setPixmap(pixmap)
            self.empty_tokens_barcode_dialog.resize(pixmap.width(), pixmap.height())
            self.empty_tokens_barcode_dialog.show()
        else:
            ConfirmationDialog.show_error(self.window(), DEPENDENCY_ERROR_TITLE, DEPENDENCY_ERROR_MESSAGE)

    def on_channel_autocommit_checkbox_changed(self, _):
        self.window().gui_settings.setValue("autocommit_enabled", self.window().channel_autocommit_checkbox.isChecked())

    def on_family_filter_checkbox_changed(self, _):
        self.window().gui_settings.setValue("family_filter", self.window().family_filter_checkbox.isChecked())

    def on_developer_mode_checkbox_changed(self, _):
        self.window().gui_settings.setValue("debug", self.window().developer_mode_enabled_checkbox.isChecked())
        self.window().left_menu_button_debug.setHidden(not self.window().developer_mode_enabled_checkbox.isChecked())

    def on_use_monochrome_icon_checkbox_changed(self, _):
        use_monochrome_icon = self.window().use_monochrome_icon_checkbox.isChecked()
        self.window().gui_settings.setValue("use_monochrome_icon", use_monochrome_icon)
        self.window().update_tray_icon(use_monochrome_icon)

    def on_anon_download_state_changed(self, _):
        if self.window().download_settings_anon_checkbox.isChecked():
            self.window().download_settings_anon_seeding_checkbox.setChecked(True)
        self.window().download_settings_anon_seeding_checkbox.setEnabled(
            not self.window().download_settings_anon_checkbox.isChecked())

    def on_choose_download_dir_clicked(self):
        previous_download_path = self.window().download_location_input.text() or ""
        download_dir = QFileDialog.getExistingDirectory(self.window(), "Please select the download location",
                                                        previous_download_path, QFileDialog.ShowDirsOnly)

        if not download_dir:
            return

        self.window().download_location_input.setText(download_dir)

    def on_choose_watch_dir_clicked(self):
        if self.window().watchfolder_enabled_checkbox.isChecked():
            previous_watch_dir = self.window().watchfolder_location_input.text() or ""
            watch_dir = QFileDialog.getExistingDirectory(self.window(), "Please select the watch folder",
                                                         previous_watch_dir, QFileDialog.ShowDirsOnly)

            if not watch_dir:
                return

            self.window().watchfolder_location_input.setText(watch_dir)

    def on_choose_log_dir_clicked(self):
        previous_log_dir = self.window().log_location_input.text() or ""
        log_dir = QFileDialog.getExistingDirectory(self.window(), "Please select the log directory",
                                                   previous_log_dir, QFileDialog.ShowDirsOnly)

        if not log_dir or log_dir == previous_log_dir:
            return

        is_writable, error = is_dir_writable(log_dir)
        if not is_writable:
            gui_error_message = "<i>%s</i> is not writable. [%s]" % (log_dir, error)
            ConfirmationDialog.show_message(self.window(), "Insufficient Permissions", gui_error_message, "OK")
        else:
            self.window().log_location_input.setText(log_dir)

    def initialize_with_settings(self, settings):
        if not settings:
            return
        self.settings = settings
        settings = settings["settings"]
        gui_settings = self.window().gui_settings

        # 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().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("%s" % 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']))
        self.window().number_hops_slider.valueChanged.connect(self.update_anonymity_cost_label)
        self.update_anonymity_cost_label(int(settings['download_defaults']['number_hops']))
        self.window().credit_mining_enabled_checkbox.setChecked(settings['credit_mining']['enabled'])
        self.window().max_disk_space_input.setText(str(settings['credit_mining']['max_disk_space']))

        # 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("Current Priority = %s" % cpu_priority)
        self.window().slider_cpu_level.valueChanged.connect(self.show_updated_cpu_priority)
        self.window().checkbox_enable_network_statistics.setChecked(settings['ipv8']['statistics'])

    def update_anonymity_cost_label(self, value):
        html_text = """<html><head/><body><p>Download with <b>%d</b> hop(s) of anonymity. 
        When you download a file of 200 Megabyte, you will pay roughly <b>%d</b>
        Megabyte of bandwidth tokens.</p></body></html>
        """ % (value, 400 * (value - 1) + 200)
        self.window().anonymity_costs_label.setText(html_text)

    def show_updated_cpu_priority(self, value):
        self.window().cpu_priority_value.setText("Current Priority = %s" % value)

    def load_settings(self):
        self.settings_request_mgr = TriblerRequestManager()
        self.settings_request_mgr.perform_request("settings", self.initialize_with_settings)

    def clicked_tab_button(self, tab_button_name):
        if tab_button_name == "settings_general_button":
            self.window().settings_stacked_widget.setCurrentIndex(PAGE_SETTINGS_GENERAL)
        elif tab_button_name == "settings_connection_button":
            self.window().settings_stacked_widget.setCurrentIndex(PAGE_SETTINGS_CONNECTION)
        elif tab_button_name == "settings_bandwidth_button":
            self.window().settings_stacked_widget.setCurrentIndex(PAGE_SETTINGS_BANDWIDTH)
        elif tab_button_name == "settings_seeding_button":
            self.window().settings_stacked_widget.setCurrentIndex(PAGE_SETTINGS_SEEDING)
        elif tab_button_name == "settings_anonymity_button":
            self.window().settings_stacked_widget.setCurrentIndex(PAGE_SETTINGS_ANONYMITY)
        elif tab_button_name == "settings_debug_button":
            self.window().settings_stacked_widget.setCurrentIndex(PAGE_SETTINGS_DEBUG)

        self.update_stacked_widget_height()

    def update_stacked_widget_height(self):
        """
        Update the height of the settings tab. This is required since the height of a QStackedWidget is by default
        the height of the largest page. This messes up the scroll bar.
        """
        for index in range(self.window().settings_stacked_widget.count()):
            if index == self.window().settings_stacked_widget.currentIndex():
                self.window().settings_stacked_widget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
            else:
                self.window().settings_stacked_widget.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)

        self.window().settings_stacked_widget.adjustSize()

    def save_settings(self):
        # Create a dictionary with all available settings
        settings_data = {'general': {}, 'Tribler': {}, 'download_defaults': {}, 'libtorrent': {}, 'watch_folder': {},
                         'tunnel_community': {}, 'trustchain': {}, 'credit_mining': {}, 'resource_monitor': {},
                         'ipv8': {}, 'chant': {}}
        settings_data['download_defaults']['saveas'] = self.window().download_location_input.text().encode('utf-8')
        settings_data['general']['log_dir'] = self.window().log_location_input.text()

        settings_data['watch_folder']['enabled'] = self.window().watchfolder_enabled_checkbox.isChecked()
        if settings_data['watch_folder']['enabled']:
            settings_data['watch_folder']['directory'] = self.window().watchfolder_location_input.text()

        settings_data['libtorrent']['proxy_type'] = self.window().lt_proxy_type_combobox.currentIndex()

        if self.window().lt_proxy_server_input.text() and len(self.window().lt_proxy_server_input.text()) > 0 and len(
                self.window().lt_proxy_port_input.text()) > 0:
            try:
                settings_data['libtorrent']['proxy_server'] = "%s:%s" % (self.window().lt_proxy_server_input.text(),
                                                                         int(self.window().lt_proxy_port_input.text()))
            except ValueError:
                ConfirmationDialog.show_error(self.window(), "Invalid proxy port number",
                                              "You've entered an invalid format for the proxy port number. "
                                              "Please enter a whole number.")
                return
        else:
            settings_data['libtorrent']['proxy_server'] = ":"

        if self.window().lt_proxy_username_input.text() and self.window().lt_proxy_password_input.text():
            settings_data['libtorrent']['proxy_auth'] = "%s:%s" % (self.window().lt_proxy_username_input.text(),
                                                                   self.window().lt_proxy_password_input.text())
        else:
            settings_data['libtorrent']['proxy_auth'] = ":"

        settings_data['libtorrent']['utp'] = self.window().lt_utp_checkbox.isChecked()

        try:
            max_conn_download = int(self.window().max_connections_download_input.text())
        except ValueError:
            ConfirmationDialog.show_error(self.window(), "Invalid number of connections",
                                          "You've entered an invalid format for the maximum number of connections. "
                                          "Please enter a whole number.")
            return
        if max_conn_download == 0:
            max_conn_download = -1
        settings_data['libtorrent']['max_connections_download'] = max_conn_download

        try:
            if self.window().upload_rate_limit_input.text():
                user_upload_rate_limit = int(self.window().upload_rate_limit_input.text()) * 1024
                if user_upload_rate_limit < sys.maxsize:
                    settings_data['libtorrent']['max_upload_rate'] = user_upload_rate_limit
                else:
                    raise ValueError
            if self.window().download_rate_limit_input.text():
                user_download_rate_limit = int(self.window().download_rate_limit_input.text()) * 1024
                if user_download_rate_limit < sys.maxsize:
                    settings_data['libtorrent']['max_download_rate'] = user_download_rate_limit
                else:
                    raise ValueError
        except ValueError:
            ConfirmationDialog.show_error(self.window(), "Invalid value for bandwidth limit",
                                          "You've entered an invalid value for the maximum upload/download rate. "
                                          "Please enter a whole number (max: %d)" % (sys.maxsize / 1000))
            return

        try:
            if self.window().api_port_input.text():
                api_port = int(self.window().api_port_input.text())
                if api_port <= 0 or api_port >= 65536:
                    raise ValueError()
                self.window().gui_settings.setValue("api_port", api_port)
        except ValueError:
            ConfirmationDialog.show_error(self.window(), "Invalid value for api port",
                                          "Please enter a valid port for the api (between 0 and 65536)")
            return

        seeding_modes = ['forever', 'time', 'never', 'ratio']
        selected_mode = 'forever'
        for seeding_mode in seeding_modes:
            if getattr(self.window(), "seeding_" + seeding_mode + "_radio").isChecked():
                selected_mode = seeding_mode
                break
        settings_data['download_defaults']['seeding_mode'] = selected_mode
        settings_data['download_defaults']['seeding_ratio'] = self.window().seeding_ratio_combobox.currentText()

        try:
            settings_data['download_defaults']['seeding_time'] = string_to_seconds(
                self.window().seeding_time_input.text())
        except ValueError:
            ConfirmationDialog.show_error(self.window(), "Invalid seeding time",
                                          "You've entered an invalid format for the seeding time (expected HH:MM)")
            return

        settings_data['credit_mining']['enabled'] = self.window().credit_mining_enabled_checkbox.isChecked()
        try:
            settings_data['credit_mining']['max_disk_space'] = int(self.window().max_disk_space_input.text())
        except ValueError:
            ConfirmationDialog.show_error(self.window(), "Invalid number",
                                          "You've entered an invalid number for max disk space value")
            return

        settings_data['tunnel_community']['exitnode_enabled'] = self.window().allow_exit_node_checkbox.isChecked()
        settings_data['download_defaults']['number_hops'] = self.window().number_hops_slider.value()
        settings_data['download_defaults']['anonymity_enabled'] = \
            self.window().download_settings_anon_checkbox.isChecked()
        settings_data['download_defaults']['safeseeding_enabled'] = \
            self.window().download_settings_anon_seeding_checkbox.isChecked()

        settings_data['resource_monitor']['enabled'] = self.window().checkbox_enable_resource_log.isChecked()
        settings_data['resource_monitor']['cpu_priority'] = int(self.window().slider_cpu_level.value())

        # network statistics
        settings_data['ipv8']['statistics'] = self.window().checkbox_enable_network_statistics.isChecked()

        self.window().settings_save_button.setEnabled(False)

        self.settings_request_mgr = TriblerRequestManager()
        self.settings_request_mgr.perform_request("settings", self.on_settings_saved,
                                                  method='POST', raw_data=json.dumps(settings_data))

    def on_settings_saved(self, data):
        if not data:
            return
        # Now save the GUI settings
        self.window().gui_settings.setValue("family_filter",
                                            self.window().family_filter_checkbox.isChecked())
        self.window().gui_settings.setValue("autocommit_enabled",
                                            self.window().channel_autocommit_checkbox.isChecked())
        self.window().gui_settings.setValue("ask_download_settings",
                                            self.window().always_ask_location_checkbox.isChecked())
        self.window().gui_settings.setValue("use_monochrome_icon",
                                            self.window().use_monochrome_icon_checkbox.isChecked())

        self.saved_dialog = ConfirmationDialog(TriblerRequestManager.window, "Settings saved",
                                               "Your settings have been saved.", [('CLOSE', BUTTON_TYPE_NORMAL)])
        self.saved_dialog.button_clicked.connect(self.on_dialog_cancel_clicked)
        self.saved_dialog.show()
        self.window().fetch_settings()

    def on_dialog_cancel_clicked(self, _):
        self.window().settings_save_button.setEnabled(True)
        self.saved_dialog.close_dialog()
        self.saved_dialog = None
コード例 #42
0
ファイル: leftmenuplaylist.py プロジェクト: Tribler/tribler
class LeftMenuPlaylist(QListWidget):
    """
    This class represents the menu with video files that is visible in the left menu.
    Only shows when a video is playing.
    """

    playing_item_change = pyqtSignal(int)  # file index
    list_loaded = pyqtSignal()
    item_should_play = pyqtSignal()  # no info required, a double click always follow a click event

    def __init__(self, parent):
        QListWidget.__init__(self, parent)

        self.files_data = []
        self.loaded_list = False
        self.loading_list = False
        self.active_index = -1
        self.infohash = None
        self.itemClicked.connect(self.on_item_clicked)
        self.itemDoubleClicked.connect(self.on_item_double_clicked)

        self.files_request_mgr = None
        self.files_request_timer = None

    def set_loading(self):
        self.clear()
        self.addItem("Loading...")
        self.loaded_list = False
        self.loading_list = True

    def load_list(self, infohash):
        self.infohash = infohash
        self.set_loading()

        if self.files_request_timer:
            self.files_request_timer.stop()

        self.files_request_timer = QTimer()
        self.files_request_timer.timeout.connect(self.perform_get_files_request)
        self.files_request_timer.start(1000)

    def perform_get_files_request(self):
        self.files_request_mgr = TriblerRequestManager()
        self.files_request_mgr.perform_request("downloads/%s/files" % self.infohash, self.on_received_files,
                                               capture_errors=False)

    def on_received_files(self, files):
        if not files:
            return
        if "files" not in files or not files["files"]:
            return

        if self.files_request_timer:
            self.files_request_timer.stop()
            self.files_request_timer = None

        self.set_files(files["files"])
        self.loaded_list = True
        self.loading_list = False
        self.list_loaded.emit()

    def get_largest_file(self):
        largest_file = None
        largest_index = None
        for index, file_info in enumerate(self.files_data):
            if is_video_file(file_info["name"]) and \
                    (largest_file is None or file_info["size"] > largest_file["size"]):
                largest_file = file_info
                largest_index = index
        return largest_index, largest_file

    def set_files(self, files):
        self.clear()
        self.files_data = []

        for file_info in files:
            if is_video_file(file_info['name']):
                self.addItem(file_info['name'])
                self.files_data.append(file_info)

    def set_active_index(self, file_index):
        cur_ind = 0
        for ind, file_info in enumerate(self.files_data):
            if ind == file_index:
                self.item(cur_ind).setSelected(True)
                self.setFocus()
                break
            cur_ind += 1

    def get_file_info(self, menu_index):
        """
        Get the file info, based on the menu index
        """
        return self.files_data[menu_index] if menu_index < len(self.files_data) else None

    def on_item_clicked(self, item):
        item_ind = self.row(item)
        if self.loaded_list:
            self.playing_item_change.emit(item_ind)

    def on_item_double_clicked(self, item):
        self.item_should_play.emit()
コード例 #43
0
class DownloadsDetailsTabWidget(QTabWidget):
    """
    The DownloadDetailsTab is the tab that provides details about a specific selected download. This information
    includes the connected peers, tracker status and file information.
    """

    def __init__(self, parent):
        QTabWidget.__init__(self, parent)
        self.current_download = None
        self.request_mgr = None
        self.files_widgets = {}    # dict of file name -> widget

    def initialize_details_widget(self):
        self.window().download_files_list.customContextMenuRequested.connect(self.on_right_click_file_item)
        self.window().download_files_list.header().resizeSection(0, 220)
        self.setCurrentIndex(0)

    def update_with_download(self, download):
        did_change = self.current_download != download
        self.current_download = download
        self.update_pages(new_download=did_change)

    @staticmethod
    def update_file_row(item, file_info):
        item.file_info = file_info
        item.update_item()

    @staticmethod
    def update_tracker_row(item, tracker):
        item.setText(0, tracker["url"])
        item.setText(1, tracker["status"])
        item.setText(2, str(tracker["peers"]))

    @staticmethod
    def update_peer_row(item, peer):
        peer_name = "%s:%s" % (peer["ip"], peer["port"])
        if peer['connection_type'] == 1:
            peer_name += ' [WebSeed]'
        elif peer['connection_type'] == 2:
            peer_name += ' [HTTP Seed]'
        elif peer['connection_type'] == 3:
            peer_name += ' [uTP]'

        state = ""
        if peer['optimistic']:
            state += "O,"
        if peer['uinterested']:
            state += "UI,"
        if peer['uchoked']:
            state += "UC,"
        if peer['uhasqueries']:
            state += "UQ,"
        if not peer['uflushed']:
            state += "UBL,"
        if peer['dinterested']:
            state += "DI,"
        if peer['dchoked']:
            state += "DC,"
        if peer['snubbed']:
            state += "S,"
        state += peer['direction']

        item.setText(0, peer_name)
        item.setText(1, '%d%%' % (peer['completed'] * 100.0))
        item.setText(2, format_speed(peer['downrate']))
        item.setText(3, format_speed(peer['uprate']))
        item.setText(4, state)
        item.setText(5, peer['extended_version'])

    def update_pages(self, new_download=False):
        if self.current_download is None:
            return

        if "files" not in self.current_download:
            self.current_download["files"] = []

        self.window().download_progress_bar.update_with_download(self.current_download)
        self.window().download_detail_name_label.setText(self.current_download['name'])

        if self.current_download["vod_mode"]:
            self.window().download_detail_status_label.setText('Streaming')
        else:
            status_string = DLSTATUS_STRINGS[eval(self.current_download["status"])]
            if eval(self.current_download["status"]) == DLSTATUS_STOPPED_ON_ERROR:
                status_string += " (error: %s)" % self.current_download["error"]
            self.window().download_detail_status_label.setText(status_string)

        self.window().download_detail_filesize_label.setText("%s in %d files" %
                                                             (format_size(float(self.current_download["size"])),
                                                              len(self.current_download["files"])))
        self.window().download_detail_health_label.setText("%d seeders, %d leechers" %
                                                           (self.current_download["num_seeds"],
                                                            self.current_download["num_peers"]))
        self.window().download_detail_infohash_label.setText(self.current_download['infohash'])
        self.window().download_detail_destination_label.setText(self.current_download["destination"])
        self.window().download_detail_ratio_label.setText(
            "%.3f, up: %s, down: %s" % (
                self.current_download["ratio"],
                format_size(self.current_download["total_up"]),
                format_size(self.current_download["total_down"])))
        self.window().download_detail_availability_label.setText("%.2f" % self.current_download['availability'])

        if new_download or len(self.current_download["files"]) != len(self.files_widgets.keys()):

            # (re)populate the files list
            self.window().download_files_list.clear()
            self.files_widgets = {}
            for dfile in self.current_download["files"]:
                item = DownloadFileWidgetItem(self.window().download_files_list, dfile)
                DownloadsDetailsTabWidget.update_file_row(item, dfile)
                self.files_widgets[dfile["name"]] = item

        else:  # No new download, just update data in the lists
            for dfile in self.current_download["files"]:
                DownloadsDetailsTabWidget.update_file_row(self.files_widgets[dfile["name"]], dfile)

        # Populate the trackers list
        self.window().download_trackers_list.clear()
        for tracker in self.current_download["trackers"]:
            item = QTreeWidgetItem(self.window().download_trackers_list)
            DownloadsDetailsTabWidget.update_tracker_row(item, tracker)

        # Populate the peers list if the peer information is available
        self.window().download_peers_list.clear()
        if "peers" in self.current_download:
            for peer in self.current_download["peers"]:
                item = QTreeWidgetItem(self.window().download_peers_list)
                DownloadsDetailsTabWidget.update_peer_row(item, peer)

    def on_right_click_file_item(self, pos):
        num_selected = len(self.window().download_files_list.selectedItems())
        if num_selected == 0:
            return

        item_infos = []  # Array of (item, included, is_selected)
        selected_files_info = []

        for i in range(self.window().download_files_list.topLevelItemCount()):
            item = self.window().download_files_list.topLevelItem(i)
            is_selected = item in self.window().download_files_list.selectedItems()
            item_infos.append((item, item.file_info["included"], is_selected))

            if is_selected:
                selected_files_info.append(item.file_info)

        item_clicked = self.window().download_files_list.itemAt(pos)
        if not item_clicked or not item_clicked in self.window().download_files_list.selectedItems():
            return

        # Check whether we should enable the 'exclude' button
        num_excludes = 0
        num_includes_selected = 0
        for item_info in item_infos:
            if item_info[1] and item_info[0] in self.window().download_files_list.selectedItems():
                num_includes_selected += 1
            if not item_info[1]:
                num_excludes += 1

        menu = TriblerActionMenu(self)

        include_action = QAction('Include file' + ('(s)' if num_selected > 1 else ''), self)
        exclude_action = QAction('Exclude file' + ('(s)' if num_selected > 1 else ''), self)

        include_action.triggered.connect(lambda: self.on_files_included(selected_files_info))
        include_action.setEnabled(True)
        exclude_action.triggered.connect(lambda: self.on_files_excluded(selected_files_info))
        exclude_action.setEnabled(not (num_excludes + num_includes_selected == len(item_infos)))

        menu.addAction(include_action)
        menu.addAction(exclude_action)

        if len(selected_files_info) == 1 and is_video_file(selected_files_info[0]['name'])\
                and self.window().vlc_available:
            play_action = QAction('Play', self)
            play_action.triggered.connect(lambda: self.on_play_file(selected_files_info[0]))
            menu.addAction(play_action)

        menu.exec_(self.window().download_files_list.mapToGlobal(pos))

    def get_video_file_index(self, file_index):
        video_index = 0
        for index in xrange(file_index):
            if is_video_file(self.current_download["files"][index]['name']):
                video_index += 1
        return video_index

    def get_included_file_list(self):
        return [file_info["index"] for file_info in self.current_download["files"] if file_info["included"]]

    def on_files_included(self, files_data):
        included_list = self.get_included_file_list()
        for file_data in files_data:
            if not file_data["index"] in included_list:
                included_list.append(file_data["index"])

        self.set_included_files(included_list)

    def on_files_excluded(self, files_data):
        included_list = self.get_included_file_list()
        for file_data in files_data:
            if file_data["index"] in included_list:
                included_list.remove(file_data["index"])

        self.set_included_files(included_list)

    def on_play_file(self, file_info):
        self.window().left_menu_button_video_player.click()
        self.window().video_player_page.play_media_item(self.current_download["infohash"],
                                                        self.get_video_file_index(file_info["index"]))

    def set_included_files(self, files):
        data_str = ''.join("selected_files[]=%s&" % ind for ind in files)[:-1]
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("downloads/%s" % self.current_download['infohash'], lambda _: None,
                                         method='PATCH', data=data_str)
コード例 #44
0
class DownloadsPage(QWidget):
    """
    This class is responsible for managing all items on the downloads page.
    The downloads page shows all downloads and specific details about a download.
    """
    received_downloads = pyqtSignal(object)

    def __init__(self):
        QWidget.__init__(self)
        self.export_dir = None
        self.filter = DOWNLOADS_FILTER_ALL
        self.download_widgets = {}  # key: infohash, value: QTreeWidgetItem
        self.downloads = None
        self.downloads_timer = QTimer()
        self.downloads_timeout_timer = QTimer()
        self.selected_item = None
        self.dialog = None
        self.downloads_request_mgr = TriblerRequestManager()
        self.request_mgr = None

    def initialize_downloads_page(self):
        self.window().downloads_tab.initialize()
        self.window().downloads_tab.clicked_tab_button.connect(self.on_downloads_tab_button_clicked)

        self.window().start_download_button.clicked.connect(self.on_start_download_clicked)
        self.window().stop_download_button.clicked.connect(self.on_stop_download_clicked)
        self.window().remove_download_button.clicked.connect(self.on_remove_download_clicked)
        self.window().play_download_button.clicked.connect(self.on_play_download_clicked)

        self.window().downloads_list.itemSelectionChanged.connect(self.on_download_item_clicked)

        self.window().downloads_list.customContextMenuRequested.connect(self.on_right_click_item)

        self.window().download_details_widget.initialize_details_widget()
        self.window().download_details_widget.hide()

        self.window().downloads_filter_input.textChanged.connect(self.on_filter_text_changed)

        self.window().downloads_list.header().resizeSection(12, 146)

        if not self.window().vlc_available:
            self.window().play_download_button.setHidden(True)

    def on_filter_text_changed(self, text):
        self.window().downloads_list.clearSelection()
        self.window().download_details_widget.hide()
        self.update_download_visibility()

    def start_loading_downloads(self):
        self.schedule_downloads_timer(now=True)

    def schedule_downloads_timer(self, now=False):
        self.downloads_timer = QTimer()
        self.downloads_timer.setSingleShot(True)
        self.downloads_timer.timeout.connect(self.load_downloads)
        self.downloads_timer.start(0 if now else 1000)

        self.downloads_timeout_timer = QTimer()
        self.downloads_timeout_timer.setSingleShot(True)
        self.downloads_timeout_timer.timeout.connect(self.on_downloads_request_timeout)
        self.downloads_timeout_timer.start(16000)

    def on_downloads_request_timeout(self):
        self.downloads_request_mgr.cancel_request()
        self.schedule_downloads_timer()

    def stop_loading_downloads(self):
        self.downloads_timer.stop()
        self.downloads_timeout_timer.stop()

    def load_downloads(self):
        url = "downloads?get_pieces=1"
        if self.window().download_details_widget.currentIndex() == 3:
            url = "downloads?get_peers=1&get_pieces=1"

        self.downloads_request_mgr.generate_request_id()
        self.downloads_request_mgr.perform_request(url, self.on_received_downloads)

    def on_received_downloads(self, downloads):
        if not downloads:
            return  # This might happen when closing Tribler

        total_download = 0
        total_upload = 0
        self.received_downloads.emit(downloads)
        self.downloads = downloads

        download_infohashes = set()
        for download in downloads["downloads"]:
            if download["infohash"] in self.download_widgets:
                item = self.download_widgets[download["infohash"]]
            else:
                item = DownloadWidgetItem(self.window().downloads_list)
                self.download_widgets[download["infohash"]] = item

            item.update_with_download(download)

            # Update video player with download info
            video_infohash = self.window().video_player_page.active_infohash
            if video_infohash != "" and download["infohash"] == video_infohash:
                self.window().video_player_page.update_with_download_info(download)

            total_download += download["speed_down"]
            total_upload += download["speed_up"]

            download_infohashes.add(download["infohash"])

            if self.window().download_details_widget.current_download is not None and \
                    self.window().download_details_widget.current_download["infohash"] == download["infohash"]:
                self.window().download_details_widget.current_download = download
                self.window().download_details_widget.update_pages()

        # Check whether there are download that should be removed
        toremove = set()
        for infohash, item in self.download_widgets.iteritems():
            if infohash not in download_infohashes:
                index = self.window().downloads_list.indexOfTopLevelItem(item)
                toremove.add((infohash, index))

        for infohash, index in toremove:
            self.window().downloads_list.takeTopLevelItem(index)
            del self.download_widgets[infohash]

        if self.window().tray_icon:
            self.window().tray_icon.setToolTip(
                "Down: %s, Up: %s" % (format_speed(total_download), format_speed(total_upload)))
        self.update_download_visibility()
        self.schedule_downloads_timer()

        # Update the top download management button if we have a row selected
        if len(self.window().downloads_list.selectedItems()) > 0:
            self.on_download_item_clicked()

    def update_download_visibility(self):
        for i in range(self.window().downloads_list.topLevelItemCount()):
            item = self.window().downloads_list.topLevelItem(i)
            filter_match = self.window().downloads_filter_input.text().lower() in item.download_info["name"].lower()
            item.setHidden(
                not item.get_raw_download_status() in DOWNLOADS_FILTER_DEFINITION[self.filter] or not filter_match)

    def on_downloads_tab_button_clicked(self, button_name):
        if button_name == "downloads_all_button":
            self.filter = DOWNLOADS_FILTER_ALL
        elif button_name == "downloads_downloading_button":
            self.filter = DOWNLOADS_FILTER_DOWNLOADING
        elif button_name == "downloads_completed_button":
            self.filter = DOWNLOADS_FILTER_COMPLETED
        elif button_name == "downloads_active_button":
            self.filter = DOWNLOADS_FILTER_ACTIVE
        elif button_name == "downloads_inactive_button":
            self.filter = DOWNLOADS_FILTER_INACTIVE

        self.window().downloads_list.clearSelection()
        self.window().download_details_widget.hide()
        self.update_download_visibility()

    @staticmethod
    def start_download_enabled(download_widget):
        return download_widget.get_raw_download_status() == DLSTATUS_STOPPED

    @staticmethod
    def stop_download_enabled(download_widget):
        status = download_widget.get_raw_download_status()
        return status != DLSTATUS_STOPPED and status != DLSTATUS_STOPPED_ON_ERROR

    @staticmethod
    def force_recheck_download_enabled(download_widget):
        status = download_widget.get_raw_download_status()
        return status != DLSTATUS_METADATA and status != DLSTATUS_HASHCHECKING and status != DLSTATUS_WAITING4HASHCHECK

    def on_download_item_clicked(self):
        self.window().download_details_widget.show()
        if len(self.window().downloads_list.selectedItems()) == 0:
            self.window().play_download_button.setEnabled(False)
            self.window().remove_download_button.setEnabled(False)
            self.window().start_download_button.setEnabled(False)
            self.window().stop_download_button.setEnabled(False)
            return

        self.selected_item = self.window().downloads_list.selectedItems()[0]
        self.window().play_download_button.setEnabled(True)
        self.window().remove_download_button.setEnabled(True)
        self.window().start_download_button.setEnabled(DownloadsPage.start_download_enabled(self.selected_item))
        self.window().stop_download_button.setEnabled(DownloadsPage.stop_download_enabled(self.selected_item))

        self.window().download_details_widget.update_with_download(self.selected_item.download_info)

    def on_start_download_clicked(self):
        infohash = self.selected_item.download_info["infohash"]
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("downloads/%s" % infohash, self.on_download_resumed,
                                         method='PATCH', data="state=resume")

    def on_download_resumed(self, json_result):
        if json_result["modified"]:
            self.selected_item.download_info['status'] = "DLSTATUS_DOWNLOADING"
            self.selected_item.update_item()
            self.on_download_item_clicked()

    def on_stop_download_clicked(self):
        infohash = self.selected_item.download_info["infohash"]
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("downloads/%s" % infohash, self.on_download_stopped,
                                         method='PATCH', data="state=stop")

    def on_play_download_clicked(self):
        self.window().left_menu_button_video_player.click()
        self.window().video_player_page.set_torrent_infohash(self.selected_item.download_info["infohash"])
        self.window().left_menu_playlist.set_loading()

    def on_download_stopped(self, json_result):
        if json_result["modified"]:
            self.selected_item.download_info['status'] = "DLSTATUS_STOPPED"
            self.selected_item.update_item()
            self.on_download_item_clicked()

    def on_remove_download_clicked(self):
        self.dialog = ConfirmationDialog(self, "Remove download", "Are you sure you want to remove this download?",
                                         [('remove download', BUTTON_TYPE_NORMAL),
                                          ('remove download + data', BUTTON_TYPE_NORMAL),
                                          ('cancel', BUTTON_TYPE_CONFIRM)])
        self.dialog.button_clicked.connect(self.on_remove_download_dialog)
        self.dialog.show()

    def on_remove_download_dialog(self, action):
        if action != 2:
            infohash = self.selected_item.download_info["infohash"]

            # Reset video player if necessary before doing the actual request
            if self.window().video_player_page.active_infohash == infohash:
                self.window().video_player_page.reset_player()

            self.request_mgr = TriblerRequestManager()
            self.request_mgr.perform_request("downloads/%s" % infohash, self.on_download_removed,
                                             method='DELETE', data="remove_data=%d" % action)

        self.dialog.setParent(None)
        self.dialog = None

    def on_download_removed(self, json_result):
        if json_result["removed"]:
            infohash = self.selected_item.download_info["infohash"]
            index = self.window().downloads_list.indexOfTopLevelItem(self.selected_item)
            self.window().downloads_list.takeTopLevelItem(index)
            if infohash in self.download_widgets:  # Could have been removed already through API
                del self.download_widgets[infohash]
            self.window().download_details_widget.hide()

    def on_force_recheck_download(self):
        infohash = self.selected_item.download_info["infohash"]
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("downloads/%s" % infohash, self.on_forced_recheck,
                                         method='PATCH', data='state=recheck')

    def on_forced_recheck(self, result):
        if result['modified']:
            self.selected_item.download_info['status'] = "DLSTATUS_HASHCHECKING"
            self.selected_item.update_item()
            self.on_download_item_clicked()

    def change_anonymity(self, hops):
        infohash = self.selected_item.download_info["infohash"]
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("downloads/%s" % infohash, lambda _: None,
                                         method='PATCH', data='anon_hops=%d' % hops)

    def on_explore_files(self):
        QDesktopServices.openUrl(QUrl.fromLocalFile(self.selected_item.download_info["destination"]))

    def on_export_download(self):
        self.export_dir = QFileDialog.getExistingDirectory(self, "Please select the destination directory", "",
                                                           QFileDialog.ShowDirsOnly)

        if len(self.export_dir) > 0:
            # Show confirmation dialog where we specify the name of the file
            torrent_name = self.selected_item.download_info['name']
            self.dialog = ConfirmationDialog(self, "Export torrent file",
                                             "Please enter the name of the torrent file:",
                                             [('SAVE', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)],
                                             show_input=True)
            self.dialog.dialog_widget.dialog_input.setPlaceholderText('Torrent file name')
            self.dialog.dialog_widget.dialog_input.setText("%s.torrent" % torrent_name)
            self.dialog.dialog_widget.dialog_input.setFocus()
            self.dialog.button_clicked.connect(self.on_export_download_dialog_done)
            self.dialog.show()

    def on_export_download_dialog_done(self, action):
        if action == 0:
            filename = self.dialog.dialog_widget.dialog_input.text()
            self.request_mgr = TriblerRequestManager()
            self.request_mgr.download_file("downloads/%s/torrent" % self.selected_item.download_info['infohash'],
                                           lambda data: self.on_export_download_request_done(filename, data))

        self.dialog.setParent(None)
        self.dialog = None

    def on_export_download_request_done(self, filename, data):
        dest_path = os.path.join(self.export_dir, filename)
        try:
            torrent_file = open(dest_path, "wb")
            torrent_file.write(data)
            torrent_file.close()
        except IOError as exc:
            ConfirmationDialog.show_error(self.window(),
                                          "Error when exporting file",
                                          "An error occurred when exporting the torrent file: %s" % str(exc))
        else:
            if self.window().tray_icon:
                self.window().tray_icon.showMessage("Torrent file exported", "Torrent file exported to %s" % dest_path)

    def on_right_click_item(self, pos):
        item_clicked = self.window().downloads_list.itemAt(pos)
        if not item_clicked:
            return

        self.selected_item = item_clicked

        menu = TriblerActionMenu(self)

        start_action = QAction('Start', self)
        stop_action = QAction('Stop', self)
        remove_download_action = QAction('Remove download', self)
        force_recheck_action = QAction('Force recheck', self)
        export_download_action = QAction('Export .torrent file', self)
        explore_files_action = QAction('Explore files', self)

        no_anon_action = QAction('No anonymity', self)
        one_hop_anon_action = QAction('One hop', self)
        two_hop_anon_action = QAction('Two hops', self)
        three_hop_anon_action = QAction('Three hops', self)

        start_action.triggered.connect(self.on_start_download_clicked)
        start_action.setEnabled(DownloadsPage.start_download_enabled(self.selected_item))
        stop_action.triggered.connect(self.on_stop_download_clicked)
        stop_action.setEnabled(DownloadsPage.stop_download_enabled(self.selected_item))
        remove_download_action.triggered.connect(self.on_remove_download_clicked)
        force_recheck_action.triggered.connect(self.on_force_recheck_download)
        force_recheck_action.setEnabled(DownloadsPage.force_recheck_download_enabled(self.selected_item))
        export_download_action.triggered.connect(self.on_export_download)
        explore_files_action.triggered.connect(self.on_explore_files)

        no_anon_action.triggered.connect(lambda: self.change_anonymity(0))
        one_hop_anon_action.triggered.connect(lambda: self.change_anonymity(1))
        two_hop_anon_action.triggered.connect(lambda: self.change_anonymity(2))
        three_hop_anon_action.triggered.connect(lambda: self.change_anonymity(3))

        menu.addAction(start_action)
        menu.addAction(stop_action)

        if self.window().vlc_available:
            play_action = QAction('Play', self)
            play_action.triggered.connect(self.on_play_download_clicked)
            menu.addAction(play_action)
        menu.addSeparator()
        menu.addAction(remove_download_action)
        menu.addSeparator()
        menu.addAction(force_recheck_action)
        menu.addSeparator()
        menu.addAction(export_download_action)
        menu.addSeparator()
        menu_anon_level = menu.addMenu("Change anonymity")
        menu_anon_level.addAction(no_anon_action)
        menu_anon_level.addAction(one_hop_anon_action)
        menu_anon_level.addAction(two_hop_anon_action)
        menu_anon_level.addAction(three_hop_anon_action)
        menu.addAction(explore_files_action)

        menu.exec_(self.window().downloads_list.mapToGlobal(pos))
コード例 #45
0
ファイル: debug_window.py プロジェクト: bluefalcon26/tribler
class DebugWindow(QMainWindow):
    """
    The debug window shows various statistics about Tribler such as performed requests, Dispersy statistics and
    community information.
    """
    def __init__(self, settings, tribler_version):
        QMainWindow.__init__(self)

        self.request_mgr = None
        self.cpu_plot = None
        self.memory_plot = None
        self.initialized_cpu_plot = False
        self.initialized_memory_plot = False
        self.cpu_plot_timer = None
        self.memory_plot_timer = None
        self.tribler_version = tribler_version
        self.profiler_enabled = False
        self.toggling_profiler = False

        uic.loadUi(get_ui_file_path('debugwindow.ui'), self)
        self.setWindowTitle("Tribler debug pane")

        self.window().dump_memory_core_button.clicked.connect(
            lambda: self.on_memory_dump_button_clicked(True))
        self.window().dump_memory_gui_button.clicked.connect(
            lambda: self.on_memory_dump_button_clicked(False))
        self.window().toggle_profiler_button.clicked.connect(
            self.on_toggle_profiler_button_clicked)

        self.window().debug_tab_widget.setCurrentIndex(0)
        self.window().dispersy_tab_widget.setCurrentIndex(0)
        self.window().system_tab_widget.setCurrentIndex(0)
        self.window().debug_tab_widget.currentChanged.connect(self.tab_changed)
        self.window().dispersy_tab_widget.currentChanged.connect(
            self.dispersy_tab_changed)
        self.window().events_tree_widget.itemClicked.connect(
            self.on_event_clicked)
        self.window().system_tab_widget.currentChanged.connect(
            self.system_tab_changed)
        self.load_general_tab()

        self.window().open_files_tree_widget.header().setSectionResizeMode(
            0, QHeaderView.Stretch)

        # Enable/disable tabs, based on settings
        self.window().debug_tab_widget.setTabEnabled(
            2, settings and settings['trustchain']['enabled'])
        self.window().debug_tab_widget.setTabEnabled(
            3, settings and settings['dispersy']['enabled'])
        self.window().system_tab_widget.setTabEnabled(
            3, settings and settings['resource_monitor']['enabled'])
        self.window().system_tab_widget.setTabEnabled(
            4, settings and settings['resource_monitor']['enabled'])

        # Refresh logs
        self.window().log_refresh_button.clicked.connect(
            lambda: self.load_logs_tab())
        self.window().log_tab_widget.currentChanged.connect(
            lambda index: self.load_logs_tab())

        # Position to center
        frame_geometry = self.frameGeometry()
        screen = QDesktopWidget().screenNumber(QDesktopWidget().cursor().pos())
        center_point = QDesktopWidget().screenGeometry(screen).center()
        frame_geometry.moveCenter(center_point)
        self.move(frame_geometry.topLeft())

    def tab_changed(self, index):
        if index == 0:
            self.load_general_tab()
        elif index == 1:
            self.load_requests_tab()
        elif index == 2:
            self.load_trustchain_tab()
        elif index == 3:
            self.dispersy_tab_changed(
                self.window().dispersy_tab_widget.currentIndex())
        elif index == 4:
            self.load_events_tab()
        elif index == 5:
            self.system_tab_changed(
                self.window().system_tab_widget.currentIndex())
        elif index == 6:
            self.load_logs_tab()

    def dispersy_tab_changed(self, index):
        if index == 0:
            self.load_dispersy_general_tab()
        elif index == 1:
            self.load_dispersy_communities_tab()

    def system_tab_changed(self, index):
        if index == 0:
            self.load_open_files_tab()
        elif index == 1:
            self.load_open_sockets_tab()
        elif index == 2:
            self.load_threads_tab()
        elif index == 3:
            self.load_cpu_tab()
        elif index == 4:
            self.load_memory_tab()
        elif index == 5:
            self.load_profiler_tab()

    def create_and_add_widget_item(self, key, value, widget):
        item = QTreeWidgetItem(widget)
        item.setText(0, key)
        item.setText(1, "%s" % value)
        widget.addTopLevelItem(item)

    def load_general_tab(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("statistics/tribler",
                                         self.on_tribler_statistics)

    def on_tribler_statistics(self, data):
        if not data:
            return
        data = data["tribler_statistics"]
        self.window().general_tree_widget.clear()
        self.create_and_add_widget_item("Tribler version",
                                        self.tribler_version,
                                        self.window().general_tree_widget)
        self.create_and_add_widget_item("Number of channels",
                                        data["num_channels"],
                                        self.window().general_tree_widget)
        self.create_and_add_widget_item("Database size",
                                        format_size(data["database_size"]),
                                        self.window().general_tree_widget)
        self.create_and_add_widget_item("Number of collected torrents",
                                        data["torrents"]["num_collected"],
                                        self.window().general_tree_widget)
        self.create_and_add_widget_item("Number of torrent files",
                                        data["torrents"]["num_files"],
                                        self.window().general_tree_widget)
        self.create_and_add_widget_item(
            "Total size of torrent files",
            format_size(data["torrents"]["total_size"]),
            self.window().general_tree_widget)
        self.create_and_add_widget_item("", "",
                                        self.window().general_tree_widget)

        disk_usage = psutil.disk_usage('/')
        self.create_and_add_widget_item("Total disk space",
                                        format_size(disk_usage.total),
                                        self.window().general_tree_widget)
        self.create_and_add_widget_item("Used disk space",
                                        format_size(disk_usage.used),
                                        self.window().general_tree_widget)
        self.create_and_add_widget_item("Free disk space",
                                        format_size(disk_usage.free),
                                        self.window().general_tree_widget)

    def load_requests_tab(self):
        self.window().requests_tree_widget.clear()
        for endpoint, method, data, timestamp, status_code in sorted(
                tribler_performed_requests, key=lambda x: x[3]):
            item = QTreeWidgetItem(self.window().requests_tree_widget)
            item.setText(0, "%s %s %s" % (method, endpoint, data))
            item.setText(1, ("%d" % status_code) if status_code else "unknown")
            item.setText(2, "%s" % strftime("%H:%M:%S", localtime(timestamp)))
            self.window().requests_tree_widget.addTopLevelItem(item)

    def load_trustchain_tab(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("trustchain/statistics",
                                         self.on_trustchain_statistics)

    def on_trustchain_statistics(self, data):
        if not data:
            return
        self.window().trustchain_tree_widget.clear()
        for key, value in data["statistics"].iteritems():
            self.create_and_add_widget_item(
                key, value,
                self.window().trustchain_tree_widget)

    def load_dispersy_general_tab(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("statistics/dispersy",
                                         self.on_dispersy_general_stats)

    def on_dispersy_general_stats(self, data):
        if not data:
            return
        self.window().dispersy_general_tree_widget.clear()
        for key, value in data["dispersy_statistics"].iteritems():
            self.create_and_add_widget_item(
                key, value,
                self.window().dispersy_general_tree_widget)

    def load_dispersy_communities_tab(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("statistics/communities",
                                         self.on_dispersy_community_stats)

    def on_dispersy_community_stats(self, data):
        if not data:
            return
        self.window().communities_tree_widget.clear()
        for community in data["dispersy_community_statistics"]:
            item = QTreeWidgetItem(self.window().communities_tree_widget)
            item.setText(0, community["classification"])
            item.setText(1, community["identifier"][:6])
            item.setText(2, community["member"][:6])
            item.setText(3, "%s" % community["candidates"])
            self.window().communities_tree_widget.addTopLevelItem(item)

    def on_event_clicked(self, item):
        event_dict = item.data(0, Qt.UserRole)
        self.window().event_text_box.setPlainText(json.dumps(event_dict))

    def load_events_tab(self):
        self.window().events_tree_widget.clear()
        for event_dict, timestamp in tribler_received_events:
            item = QTreeWidgetItem(self.window().events_tree_widget)
            item.setData(0, Qt.UserRole, event_dict)
            item.setText(0, "%s" % event_dict['type'])
            item.setText(1, "%s" % strftime("%H:%M:%S", localtime(timestamp)))
            self.window().events_tree_widget.addTopLevelItem(item)

    def load_open_files_tab(self):
        # Fill the open files (GUI) tree widget
        my_process = psutil.Process()
        self.window().open_files_tree_widget.clear()
        gui_item = QTreeWidgetItem(self.window().open_files_tree_widget)

        try:
            open_files = my_process.open_files()
            gui_item.setText(0, "GUI (%d)" % len(open_files))
            self.window().open_files_tree_widget.addTopLevelItem(gui_item)

            for open_file in open_files:
                item = QTreeWidgetItem()
                item.setText(0, open_file.path)
                item.setText(1, "%d" % open_file.fd)
                gui_item.addChild(item)
        except psutil.AccessDenied as exc:
            gui_item.setText(0, "Unable to get open files for GUI (%s)" % exc)

        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("debug/open_files",
                                         self.on_core_open_files)

    def on_core_open_files(self, data):
        if not data:
            return
        core_item = QTreeWidgetItem(self.window().open_files_tree_widget)
        core_item.setText(0, "Core (%d)" % len(data["open_files"]))
        self.window().open_files_tree_widget.addTopLevelItem(core_item)

        for open_file in data["open_files"]:
            item = QTreeWidgetItem()
            item.setText(0, open_file["path"])
            item.setText(1, "%d" % open_file["fd"])
            core_item.addChild(item)

    def load_open_sockets_tab(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("debug/open_sockets",
                                         self.on_core_open_sockets)

    def on_core_open_sockets(self, data):
        if not data:
            return
        self.window().open_sockets_tree_widget.clear()
        self.window().open_sockets_label.setText(
            "Sockets opened by core (%d):" % len(data["open_sockets"]))
        for open_socket in data["open_sockets"]:
            if open_socket["family"] == socket.AF_INET:
                family = "AF_INET"
            elif open_socket["family"] == socket.AF_INET6:
                family = "AF_INET6"
            elif open_socket["family"] == socket.AF_UNIX:
                family = "AF_UNIX"
            else:
                family = "-"

            item = QTreeWidgetItem(self.window().open_sockets_tree_widget)
            item.setText(0, open_socket["laddr"])
            item.setText(1, open_socket["raddr"])
            item.setText(2, family)
            item.setText(
                3, "SOCK_STREAM"
                if open_socket["type"] == socket.SOCK_STREAM else "SOCK_DGRAM")
            item.setText(4, open_socket["status"])
            self.window().open_sockets_tree_widget.addTopLevelItem(item)

    def load_threads_tab(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("debug/threads", self.on_core_threads)

    def on_core_threads(self, data):
        if not data:
            return
        self.window().threads_tree_widget.clear()
        for thread_info in data["threads"]:
            thread_item = QTreeWidgetItem(self.window().threads_tree_widget)
            thread_item.setText(0, "%d" % thread_info["thread_id"])
            thread_item.setText(1, thread_info["thread_name"])
            self.window().threads_tree_widget.addTopLevelItem(thread_item)

            for frame in thread_info["frames"]:
                frame_item = QTreeWidgetItem()
                frame_item.setText(2, frame)
                thread_item.addChild(frame_item)

    def load_cpu_tab(self):
        if not self.initialized_cpu_plot:
            vlayout = self.window().cpu_plot_widget.layout()
            self.cpu_plot = CPUPlotMplCanvas(self.window().cpu_plot_widget,
                                             dpi=100)
            vlayout.addWidget(self.cpu_plot)
            self.initialized_cpu_plot = True

        self.refresh_cpu_plot()

        # Start timer
        self.cpu_plot_timer = QTimer()
        self.cpu_plot_timer.timeout.connect(self.load_cpu_tab)
        self.cpu_plot_timer.start(5000)

    def refresh_cpu_plot(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("debug/cpu/history",
                                         self.on_core_cpu_history)

    def on_core_cpu_history(self, data):
        if not data:
            return
        plot_data = [[], []]
        for cpu_info in data["cpu_history"]:
            if cpu_info["cpu"] == 0.0:
                continue  # Ignore the initial measurement, is always zero
            plot_data[0].append(
                datetime.datetime.fromtimestamp(cpu_info["time"]))
            plot_data[1].append(cpu_info["cpu"])

        if len(plot_data[0]) == 0:
            plot_data = [[datetime.datetime.now()], [0]]

        self.cpu_plot.plot_data = plot_data
        self.cpu_plot.compute_initial_figure()

    def load_memory_tab(self):
        if not self.initialized_memory_plot:
            vlayout = self.window().memory_plot_widget.layout()
            self.memory_plot = MemoryPlotMplCanvas(
                self.window().memory_plot_widget, dpi=100)
            vlayout.addWidget(self.memory_plot)
            self.initialized_memory_plot = True

        self.refresh_memory_plot()

        # Start timer
        self.memory_plot_timer = QTimer()
        self.memory_plot_timer.timeout.connect(self.load_memory_tab)
        self.memory_plot_timer.start(5000)

    def load_profiler_tab(self):
        self.window().toggle_profiler_button.setEnabled(False)
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("debug/profiler",
                                         self.on_profiler_info)

    def on_profiler_info(self, data):
        self.profiler_enabled = (data["state"] == "STARTED")
        self.window().toggle_profiler_button.setEnabled(True)
        self.window().toggle_profiler_button.setText(
            "%s profiler" % ("Stop" if self.profiler_enabled else "Start"))

    def on_toggle_profiler_button_clicked(self):
        if self.toggling_profiler:
            return

        self.toggling_profiler = True
        self.window().toggle_profiler_button.setEnabled(False)
        self.request_mgr = TriblerRequestManager()
        method = "DELETE" if self.profiler_enabled else "PUT"
        self.request_mgr.perform_request("debug/profiler",
                                         self.on_profiler_state_changed,
                                         method=method)

    def on_profiler_state_changed(self, data):
        self.toggling_profiler = False
        self.window().toggle_profiler_button.setEnabled(True)
        self.load_profiler_tab()

        if 'profiler_file' in data:
            QMessageBox.about(
                self, "Profiler statistics saved",
                "The profiler data has been saved to %s." %
                data['profiler_file'])

    def refresh_memory_plot(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("debug/memory/history",
                                         self.on_core_memory_history)

    def on_core_memory_history(self, data):
        if not data:
            return
        plot_data = [[], []]
        for mem_info in data["memory_history"]:
            plot_data[0].append(
                datetime.datetime.fromtimestamp(mem_info["time"]))
            plot_data[1].append(mem_info["mem"] / 1024 / 1024)

        if len(plot_data[0]) == 0:
            plot_data = [[datetime.datetime.now()], [0]]

        self.memory_plot.plot_data = plot_data
        self.memory_plot.compute_initial_figure()

    def on_memory_dump_button_clicked(self, dump_core):
        self.export_dir = QFileDialog.getExistingDirectory(
            self, "Please select the destination directory", "",
            QFileDialog.ShowDirsOnly)

        if len(self.export_dir) > 0:
            filename = "tribler_mem_dump_%s_%s.json" % \
                       ('core' if dump_core else 'gui', datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"))
            if dump_core:
                self.request_mgr = TriblerRequestManager()
                self.request_mgr.download_file(
                    "debug/memory/dump",
                    lambda data: self.on_memory_dump_data_available(
                        filename, data))
            else:
                scanner.dump_all_objects(
                    os.path.join(self.export_dir, filename))

    def on_memory_dump_data_available(self, filename, data):
        if not data:
            return
        dest_path = os.path.join(self.export_dir, filename)
        try:
            memory_dump_file = open(dest_path, "wb")
            memory_dump_file.write(data)
            memory_dump_file.close()
        except IOError as exc:
            ConfirmationDialog.show_error(
                self.window(), "Error when exporting file",
                "An error occurred when exporting the torrent file: %s" %
                str(exc))

    def closeEvent(self, close_event):
        if self.cpu_plot_timer:
            self.cpu_plot_timer.stop()

        if self.memory_plot_timer:
            self.memory_plot_timer.stop()

    def load_logs_tab(self):
        # Max lines from GUI
        max_log_lines = self.window().max_lines_value.text()

        tab_index = self.window().log_tab_widget.currentIndex()
        tab_name = "core" if tab_index == 0 else "gui"

        self.request_mgr = TriblerRequestManager()
        request_query = "process=%s&max_lines=%s" % (tab_name, max_log_lines)
        self.request_mgr.perform_request("debug/log?%s" % request_query,
                                         self.display_logs)

    def display_logs(self, data):
        tab_index = self.window().log_tab_widget.currentIndex()
        log_display_widget = self.window().core_log_display_area if tab_index == 0 \
            else self.window().gui_log_display_area

        log_display_widget.moveCursor(QTextCursor.End)

        key_content = u'content'
        key_max_lines = u'max_lines'

        if not key_content in data or not data[key_content]:
            log_display_widget.setPlainText('No logs found')
        else:
            log_display_widget.setPlainText(data[key_content])

        if not key_max_lines in data or not data[key_max_lines]:
            self.window().max_lines_value.setText('')
        else:
            self.window().max_lines_value.setText(str(data[key_max_lines]))

        sb = log_display_widget.verticalScrollBar()
        sb.setValue(sb.maximum())

    def show(self):
        super(DebugWindow, self).show()

        # this will remove minimized status
        # and restore window with keeping maximized/normal state
        self.window().setWindowState(self.window().windowState()
                                     & ~Qt.WindowMinimized | Qt.WindowActive)
        self.window().activateWindow()
コード例 #46
0
ファイル: debug_window.py プロジェクト: Tribler/tribler
class DebugWindow(QMainWindow):
    """
    The debug window shows various statistics about Tribler such as performed requests, IPv8 statistics and
    community information.
    """
    resize_event = pyqtSignal()

    def __init__(self, settings, tribler_version):
        self._logger = logging.getLogger(self.__class__.__name__)
        QMainWindow.__init__(self)

        self.request_mgr = None
        self.cpu_plot = None
        self.memory_plot = None
        self.initialized_cpu_plot = False
        self.initialized_memory_plot = False
        self.cpu_plot_timer = None
        self.memory_plot_timer = None
        self.tribler_version = tribler_version
        self.profiler_enabled = False
        self.toggling_profiler = False

        uic.loadUi(get_ui_file_path('debugwindow.ui'), self)
        self.setWindowTitle("Tribler debug pane")

        self.window().dump_memory_core_button.clicked.connect(lambda: self.on_memory_dump_button_clicked(True))
        self.window().dump_memory_gui_button.clicked.connect(lambda: self.on_memory_dump_button_clicked(False))
        self.window().toggle_profiler_button.clicked.connect(self.on_toggle_profiler_button_clicked)

        self.window().debug_tab_widget.setCurrentIndex(0)
        self.window().ipv8_tab_widget.setCurrentIndex(0)
        self.window().tunnel_tab_widget.setCurrentIndex(0)
        self.window().system_tab_widget.setCurrentIndex(0)
        self.window().debug_tab_widget.currentChanged.connect(self.tab_changed)
        self.window().ipv8_tab_widget.currentChanged.connect(self.ipv8_tab_changed)
        self.window().tunnel_tab_widget.currentChanged.connect(self.tunnel_tab_changed)
        self.window().events_tree_widget.itemClicked.connect(self.on_event_clicked)
        self.window().system_tab_widget.currentChanged.connect(self.system_tab_changed)
        self.load_general_tab()

        self.window().open_files_tree_widget.header().setSectionResizeMode(0, QHeaderView.Stretch)

        # Enable/disable tabs, based on settings
        self.window().debug_tab_widget.setTabEnabled(2, settings and settings['trustchain']['enabled'])
        self.window().debug_tab_widget.setTabEnabled(3, settings and settings['ipv8']['enabled'])
        self.window().system_tab_widget.setTabEnabled(3, settings and settings['resource_monitor']['enabled'])
        self.window().system_tab_widget.setTabEnabled(4, settings and settings['resource_monitor']['enabled'])

        # Refresh logs
        self.window().log_refresh_button.clicked.connect(lambda: self.load_logs_tab())
        self.window().log_tab_widget.currentChanged.connect(lambda index: self.load_logs_tab())

        # IPv8 statistics enabled?
        self.ipv8_statistics_enabled = settings['ipv8']['statistics']

        # Libtorrent tab
        self.init_libtorrent_tab()

        # Position to center
        frame_geometry = self.frameGeometry()
        screen = QDesktopWidget().screenNumber(QDesktopWidget().cursor().pos())
        center_point = QDesktopWidget().screenGeometry(screen).center()
        frame_geometry.moveCenter(center_point)
        self.move(frame_geometry.topLeft())

        # Refresh timer
        self.refresh_timer = None

    def hideEvent(self, hide_event):
        self.stop_timer()

    def run_with_timer(self, call_fn, timeout=DEBUG_PANE_REFRESH_TIMEOUT):
        call_fn()
        self.stop_timer()
        self.refresh_timer = QTimer()
        self.refresh_timer.setSingleShot(True)
        self.refresh_timer.timeout.connect(lambda _call_fn=call_fn, _timeout=timeout:
                                           self.run_with_timer(_call_fn, timeout=_timeout))
        self.refresh_timer.start(timeout)

    def stop_timer(self):
        if self.refresh_timer:
            try:
                self.refresh_timer.stop()
                self.refresh_timer.deleteLater()
            except RuntimeError:
                self._logger.error("Failed to stop refresh timer in Debug pane")

    def init_libtorrent_tab(self):
        self.window().libtorrent_tab_widget.setCurrentIndex(0)
        self.window().libtorrent_tab_widget.currentChanged.connect(lambda _: self.load_libtorrent_data(export=False))

        self.window().lt_zero_hop_btn.clicked.connect(lambda _: self.load_libtorrent_data(export=False))
        self.window().lt_one_hop_btn.clicked.connect(lambda _: self.load_libtorrent_data(export=False))
        self.window().lt_two_hop_btn.clicked.connect(lambda _: self.load_libtorrent_data(export=False))
        self.window().lt_three_hop_btn.clicked.connect(lambda _: self.load_libtorrent_data(export=False))
        self.window().lt_export_btn.clicked.connect(lambda _: self.load_libtorrent_data(export=True))

        self.window().lt_zero_hop_btn.setChecked(True)

    def tab_changed(self, index):
        if index == 0:
            self.load_general_tab()
        elif index == 1:
            self.load_requests_tab()
        elif index == 2:
            self.run_with_timer(self.load_trustchain_tab)
        elif index == 3:
            self.ipv8_tab_changed(self.window().ipv8_tab_widget.currentIndex())
        elif index == 4:
            self.tunnel_tab_changed(self.window().tunnel_tab_widget.currentIndex())
        elif index == 5:
            self.run_with_timer(self.load_dht_tab)
        elif index == 6:
            self.run_with_timer(self.load_events_tab)
        elif index == 7:
            self.system_tab_changed(self.window().system_tab_widget.currentIndex())
        elif index == 8:
            self.load_libtorrent_data()
        elif index == 9:
            self.load_logs_tab()

    def ipv8_tab_changed(self, index):
        if index == 0:
            self.run_with_timer(self.load_ipv8_general_tab)
        elif index == 1:
            self.run_with_timer(self.load_ipv8_communities_tab)
        elif index == 2:
            self.run_with_timer(self.load_ipv8_community_details_tab)

    def tunnel_tab_changed(self, index):
        if index == 0:
            self.run_with_timer(self.load_tunnel_circuits_tab)
        elif index == 1:
            self.run_with_timer(self.load_tunnel_relays_tab)
        elif index == 2:
            self.run_with_timer(self.load_tunnel_exits_tab)

    def system_tab_changed(self, index):
        if index == 0:
            self.load_open_files_tab()
        elif index == 1:
            self.load_open_sockets_tab()
        elif index == 2:
            self.load_threads_tab()
        elif index == 3:
            self.load_cpu_tab()
        elif index == 4:
            self.load_memory_tab()
        elif index == 5:
            self.load_profiler_tab()

    def create_and_add_widget_item(self, key, value, widget):
        item = QTreeWidgetItem(widget)
        item.setText(0, key)
        item.setText(1, "%s" % value)
        widget.addTopLevelItem(item)

    def load_general_tab(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("statistics/tribler", self.on_tribler_statistics)

    def on_tribler_statistics(self, data):
        if not data:
            return
        data = data["tribler_statistics"]
        self.window().general_tree_widget.clear()
        self.create_and_add_widget_item("Tribler version", self.tribler_version, self.window().general_tree_widget)
        self.create_and_add_widget_item("Number of channels", data["num_channels"], self.window().general_tree_widget)
        self.create_and_add_widget_item("Database size", format_size(data["db_size"]),
                                        self.window().general_tree_widget)
        self.create_and_add_widget_item("Number of known torrents", data["num_torrents"],
                                        self.window().general_tree_widget)
        self.create_and_add_widget_item("", "", self.window().general_tree_widget)

        disk_usage = psutil.disk_usage('/')
        self.create_and_add_widget_item("Total disk space", format_size(disk_usage.total),
                                        self.window().general_tree_widget)
        self.create_and_add_widget_item("Used disk space", format_size(disk_usage.used),
                                        self.window().general_tree_widget)
        self.create_and_add_widget_item("Free disk space", format_size(disk_usage.free),
                                        self.window().general_tree_widget)

    def load_requests_tab(self):
        self.window().requests_tree_widget.clear()
        for endpoint, method, data, timestamp, status_code in sorted(tribler_performed_requests,
                                                                     key=lambda x: x[3]):
            item = QTreeWidgetItem(self.window().requests_tree_widget)
            item.setText(0, "%s %s %s" % (method, endpoint, data))
            item.setText(1, ("%d" % status_code) if status_code else "unknown")
            item.setText(2, "%s" % strftime("%H:%M:%S", localtime(timestamp)))
            self.window().requests_tree_widget.addTopLevelItem(item)

    def load_trustchain_tab(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("trustchain/statistics", self.on_trustchain_statistics)

    def on_trustchain_statistics(self, data):
        if not data:
            return
        self.window().trustchain_tree_widget.clear()
        for key, value in data["statistics"].items():
            self.create_and_add_widget_item(key, value, self.window().trustchain_tree_widget)

    def load_ipv8_general_tab(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("statistics/ipv8", self.on_ipv8_general_stats)

    def on_ipv8_general_stats(self, data):
        if not data:
            return
        self.window().ipv8_general_tree_widget.clear()
        for key, value in data["ipv8_statistics"].items():
            if key in ('total_up', 'total_down'):
                value = "%.2f MB" % (value / (1024.0 * 1024.0))
            elif key == 'session_uptime':
                value = "%s" % str(datetime.timedelta(seconds=int(value)))
            self.create_and_add_widget_item(key, value, self.window().ipv8_general_tree_widget)

    def load_ipv8_communities_tab(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("ipv8/overlays", self.on_ipv8_community_stats)

    def _colored_peer_count(self, peer_count, overlay_count, master_peer):
        is_discovery = (master_peer == "3081a7301006072a8648ce3d020106052b81040027038192000403b3ab059ced9b20646ab5e01"
                                       "762b3595c5e8855227ae1e424cff38a1e4edee73734ff2e2e829eb4f39bab20d7578284fcba72"
                                       "51acd74e7daf96f21d01ea17077faf4d27a655837d072baeb671287a88554e1191d8904b0dc57"
                                       "2d09ff95f10ff092c8a5e2a01cd500624376aec875a6e3028aab784cfaf0bac6527245db8d939"
                                       "00d904ac2a922a02716ccef5a22f7968")
        limits = [20, overlay_count * 30 + 1] if is_discovery else [20, 31]
        color = 0xF4D03F if peer_count < limits[0] else (0x56F129 if peer_count < limits[1] else 0xF12929)
        return QBrush(QColor(color))

    def on_ipv8_community_stats(self, data):
        if not data:
            return
        self.window().communities_tree_widget.clear()
        for overlay in data["overlays"]:
            item = QTreeWidgetItem(self.window().communities_tree_widget)
            item.setText(0, overlay["overlay_name"])
            item.setText(1, overlay["master_peer"][-12:])
            item.setText(2, overlay["my_peer"][-12:])
            peer_count = len(overlay["peers"])
            item.setText(3, "%s" % peer_count)
            item.setForeground(3, self._colored_peer_count(peer_count, len(data["overlays"]),
                                                           overlay["master_peer"]))

            if "statistics" in overlay and overlay["statistics"]:
                statistics = overlay["statistics"]
                item.setText(4, "%.3f" % (statistics["bytes_up"]/(1024.0 * 1024.0)))
                item.setText(5, "%.3f" % (statistics["bytes_down"]/(1024.0 * 1024.0)))
                item.setText(6, "%s" % statistics["num_up"])
                item.setText(7, "%s" % statistics["num_down"])
                item.setText(8, "%.3f" % statistics["diff_time"])
            else:
                item.setText(4, "N/A")
                item.setText(5, "N/A")
                item.setText(6, "N/A")
                item.setText(7, "N/A")
                item.setText(8, "N/A")

            self.window().communities_tree_widget.addTopLevelItem(item)
            map(self.window().communities_tree_widget.resizeColumnToContents, xrange(10))

    def load_ipv8_community_details_tab(self):
        if self.ipv8_statistics_enabled:
            self.window().ipv8_statistics_error_label.setHidden(True)
            self.request_mgr = TriblerRequestManager()
            self.request_mgr.perform_request("ipv8/overlays/statistics", self.on_ipv8_community_detail_stats)
        else:
            self.window().ipv8_statistics_error_label.setHidden(False)
            self.window().ipv8_communities_details_widget.setHidden(True)

    def on_ipv8_community_detail_stats(self, data):
        if not data:
            return

        self.window().ipv8_communities_details_widget.setHidden(False)
        self.window().ipv8_communities_details_widget.clear()
        for overlay in data["statistics"]:
            self.window().ipv8_communities_details_widget.setColumnWidth(0, 250)

            for key, stats in overlay.items():
                header_item = QTreeWidgetItem(self.window().ipv8_communities_details_widget)
                header_item.setFirstColumnSpanned(True)
                header_item.setBackground(0, QtGui.QColor('#CCCCCC'))
                header_item.setText(0, key)
                self.window().ipv8_communities_details_widget.addTopLevelItem(header_item)

                for request_id, stat in stats.items():
                    stat_item = QTreeWidgetItem(self.window().ipv8_communities_details_widget)
                    stat_item.setText(0, request_id)
                    stat_item.setText(1, "%.3f" % (stat["bytes_up"] / (1024.0 * 1024.0)))
                    stat_item.setText(2, "%.3f" % (stat["bytes_down"] / (1024.0 * 1024.0)))
                    stat_item.setText(3, "%s" % stat["num_up"])
                    stat_item.setText(4, "%s" % stat["num_down"])
                    self.window().ipv8_communities_details_widget.addTopLevelItem(stat_item)

    def add_items_to_tree(self, tree, items, keys):
        tree.clear()
        for item in items:
            widget_item = QTreeWidgetItem(tree)
            for index, key in enumerate(keys):
                value = format_size(item[key]) if key in ["bytes_up", "bytes_down"] else str(item[key])
                widget_item.setText(index, value)
            tree.addTopLevelItem(widget_item)

    def load_tunnel_circuits_tab(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("ipv8/tunnel/circuits", self.on_tunnel_circuits)

    def on_tunnel_circuits(self, data):
        if data:
            self.add_items_to_tree(self.window().circuits_tree_widget, data.get("circuits"),
                                   ["circuit_id", "goal_hops", "actual_hops", "unverified_hop",
                                    "type", "state", "bytes_up", "bytes_down"])

    def load_tunnel_relays_tab(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("ipv8/tunnel/relays", self.on_tunnel_relays)

    def on_tunnel_relays(self, data):
        if data:
            self.add_items_to_tree(self.window().relays_tree_widget, data["relays"],
                                   ["circuit_from", "circuit_to", "is_rendezvous", "bytes_up", "bytes_down"])

    def load_tunnel_exits_tab(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("ipv8/tunnel/exits", self.on_tunnel_exits)

    def on_tunnel_exits(self, data):
        if data:
            self.add_items_to_tree(self.window().exits_tree_widget, data["exits"],
                                   ["circuit_from", "enabled", "bytes_up", "bytes_down"])

    def load_dht_tab(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("ipv8/dht/statistics", self.on_dht_statistics)

    def on_dht_statistics(self, data):
        if not data:
            return
        self.window().dht_tree_widget.clear()
        for key, value in data["statistics"].items():
            self.create_and_add_widget_item(key, value, self.window().dht_tree_widget)

    def on_event_clicked(self, item):
        event_dict = item.data(0, Qt.UserRole)
        self.window().event_text_box.setPlainText(json.dumps(event_dict))

    def load_events_tab(self):
        self.window().events_tree_widget.clear()
        for event_dict, timestamp in tribler_received_events:
            item = QTreeWidgetItem(self.window().events_tree_widget)
            item.setData(0, Qt.UserRole, event_dict)
            item.setText(0, "%s" % event_dict['type'])
            item.setText(1, "%s" % strftime("%H:%M:%S", localtime(timestamp)))
            self.window().events_tree_widget.addTopLevelItem(item)

    def load_open_files_tab(self):
        # Fill the open files (GUI) tree widget
        my_process = psutil.Process()
        self.window().open_files_tree_widget.clear()
        gui_item = QTreeWidgetItem(self.window().open_files_tree_widget)

        try:
            open_files = my_process.open_files()
            gui_item.setText(0, "GUI (%d)" % len(open_files))
            self.window().open_files_tree_widget.addTopLevelItem(gui_item)

            for open_file in open_files:
                item = QTreeWidgetItem()
                item.setText(0, open_file.path)
                item.setText(1, "%d" % open_file.fd)
                gui_item.addChild(item)
        except psutil.AccessDenied as exc:
            gui_item.setText(0, "Unable to get open files for GUI (%s)" % exc)

        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("debug/open_files", self.on_core_open_files)

    def on_core_open_files(self, data):
        if not data:
            return
        core_item = QTreeWidgetItem(self.window().open_files_tree_widget)
        core_item.setText(0, "Core (%d)" % len(data["open_files"]))
        self.window().open_files_tree_widget.addTopLevelItem(core_item)

        for open_file in data["open_files"]:
            item = QTreeWidgetItem()
            item.setText(0, open_file["path"])
            item.setText(1, "%d" % open_file["fd"])
            core_item.addChild(item)

    def load_open_sockets_tab(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("debug/open_sockets", self.on_core_open_sockets)

    def on_core_open_sockets(self, data):
        if not data:
            return
        self.window().open_sockets_tree_widget.clear()
        self.window().open_sockets_label.setText("Sockets opened by core (%d):" % len(data["open_sockets"]))
        for open_socket in data["open_sockets"]:
            if open_socket["family"] == socket.AF_INET:
                family = "AF_INET"
            elif open_socket["family"] == socket.AF_INET6:
                family = "AF_INET6"
            elif open_socket["family"] == socket.AF_UNIX:
                family = "AF_UNIX"
            else:
                family = "-"

            item = QTreeWidgetItem(self.window().open_sockets_tree_widget)
            item.setText(0, open_socket["laddr"])
            item.setText(1, open_socket["raddr"])
            item.setText(2, family)
            item.setText(3, "SOCK_STREAM" if open_socket["type"] == socket.SOCK_STREAM else "SOCK_DGRAM")
            item.setText(4, open_socket["status"])
            self.window().open_sockets_tree_widget.addTopLevelItem(item)

    def load_threads_tab(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("debug/threads", self.on_core_threads)

    def on_core_threads(self, data):
        if not data:
            return
        self.window().threads_tree_widget.clear()
        for thread_info in data["threads"]:
            thread_item = QTreeWidgetItem(self.window().threads_tree_widget)
            thread_item.setText(0, "%d" % thread_info["thread_id"])
            thread_item.setText(1, thread_info["thread_name"])
            self.window().threads_tree_widget.addTopLevelItem(thread_item)

            for frame in thread_info["frames"]:
                frame_item = QTreeWidgetItem()
                frame_item.setText(2, frame)
                thread_item.addChild(frame_item)

    def load_cpu_tab(self):
        if not self.initialized_cpu_plot:
            vlayout = self.window().cpu_plot_widget.layout()
            self.cpu_plot = CPUPlotMplCanvas(self.window().cpu_plot_widget, dpi=100)
            vlayout.addWidget(self.cpu_plot)
            self.initialized_cpu_plot = True

        self.refresh_cpu_plot()

        # Start timer
        self.cpu_plot_timer = QTimer()
        self.cpu_plot_timer.timeout.connect(self.load_cpu_tab)
        self.cpu_plot_timer.start(5000)

    def refresh_cpu_plot(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("debug/cpu/history", self.on_core_cpu_history)

    def on_core_cpu_history(self, data):
        if not data:
            return
        plot_data = [[], []]
        for cpu_info in data["cpu_history"]:
            if cpu_info["cpu"] == 0.0:
                continue  # Ignore the initial measurement, is always zero
            plot_data[0].append(datetime.datetime.fromtimestamp(cpu_info["time"]))
            plot_data[1].append(cpu_info["cpu"])

        if len(plot_data[0]) == 0:
            plot_data = [[datetime.datetime.now()], [0]]

        self.cpu_plot.plot_data = plot_data
        self.cpu_plot.compute_initial_figure()

    def load_memory_tab(self):
        if not self.initialized_memory_plot:
            vlayout = self.window().memory_plot_widget.layout()
            self.memory_plot = MemoryPlotMplCanvas(self.window().memory_plot_widget, dpi=100)
            vlayout.addWidget(self.memory_plot)
            self.initialized_memory_plot = True

        self.refresh_memory_plot()

        # Start timer
        self.memory_plot_timer = QTimer()
        self.memory_plot_timer.timeout.connect(self.load_memory_tab)
        self.memory_plot_timer.start(5000)

    def load_profiler_tab(self):
        self.window().toggle_profiler_button.setEnabled(False)
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("debug/profiler", self.on_profiler_info)

    def on_profiler_info(self, data):
        if not data:
            return
        self.profiler_enabled = (data["state"] == "STARTED")
        self.window().toggle_profiler_button.setEnabled(True)
        self.window().toggle_profiler_button.setText("%s profiler" %
                                                     ("Stop" if self.profiler_enabled else "Start"))

    def on_toggle_profiler_button_clicked(self):
        if self.toggling_profiler:
            return

        self.toggling_profiler = True
        self.window().toggle_profiler_button.setEnabled(False)
        self.request_mgr = TriblerRequestManager()
        method = "DELETE" if self.profiler_enabled else "PUT"
        self.request_mgr.perform_request("debug/profiler", self.on_profiler_state_changed, method=method)

    def on_profiler_state_changed(self, data):
        if not data:
            return
        self.toggling_profiler = False
        self.window().toggle_profiler_button.setEnabled(True)
        self.load_profiler_tab()

        if 'profiler_file' in data:
            QMessageBox.about(self,
                              "Profiler statistics saved",
                              "The profiler data has been saved to %s." % data['profiler_file'])

    def refresh_memory_plot(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("debug/memory/history", self.on_core_memory_history)

    def on_core_memory_history(self, data):
        if not data:
            return
        plot_data = [[], []]
        for mem_info in data["memory_history"]:
            plot_data[0].append(datetime.datetime.fromtimestamp(mem_info["time"]))
            plot_data[1].append(mem_info["mem"] / 1024 / 1024)

        if len(plot_data[0]) == 0:
            plot_data = [[datetime.datetime.now()], [0]]

        self.memory_plot.plot_data = plot_data
        self.memory_plot.compute_initial_figure()

    def on_memory_dump_button_clicked(self, dump_core):
        self.export_dir = QFileDialog.getExistingDirectory(self, "Please select the destination directory", "",
                                                           QFileDialog.ShowDirsOnly)

        if len(self.export_dir) > 0:
            filename = "tribler_mem_dump_%s_%s.json" % \
                       ('core' if dump_core else 'gui', datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"))
            if dump_core:
                self.request_mgr = TriblerRequestManager()
                self.request_mgr.download_file("debug/memory/dump",
                                               lambda data: self.on_memory_dump_data_available(filename, data))
            elif scanner:
                scanner.dump_all_objects(os.path.join(self.export_dir, filename))
            else:
                ConfirmationDialog.show_error(self.window(),
                                              "Error when performing a memory dump",
                                              "meliae memory dumper is not compatible with Python 3")

    def on_memory_dump_data_available(self, filename, data):
        if not data:
            return
        dest_path = os.path.join(self.export_dir, filename)
        try:
            memory_dump_file = open(dest_path, "wb")
            memory_dump_file.write(data)
            memory_dump_file.close()
        except IOError as exc:
            ConfirmationDialog.show_error(self.window(),
                                          "Error when exporting file",
                                          "An error occurred when exporting the torrent file: %s" % str(exc))

    def closeEvent(self, close_event):
        self.request_mgr.cancel_request()
        if self.cpu_plot_timer:
            self.cpu_plot_timer.stop()

        if self.memory_plot_timer:
            self.memory_plot_timer.stop()

    def load_logs_tab(self):
        # Max lines from GUI
        max_log_lines = self.window().max_lines_value.text()

        tab_index = self.window().log_tab_widget.currentIndex()
        tab_name = "core" if tab_index == 0 else "gui"

        self.request_mgr = TriblerRequestManager()
        request_query = "process=%s&max_lines=%s" % (tab_name, max_log_lines)
        self.request_mgr.perform_request("debug/log?%s" % request_query, self.display_logs)

    def display_logs(self, data):
        if not data:
            return
        tab_index = self.window().log_tab_widget.currentIndex()
        log_display_widget = self.window().core_log_display_area if tab_index == 0 \
            else self.window().gui_log_display_area

        log_display_widget.moveCursor(QTextCursor.End)

        key_content = u'content'
        key_max_lines = u'max_lines'

        if not key_content in data or not data[key_content]:
            log_display_widget.setPlainText('No logs found')
        else:
            log_display_widget.setPlainText(data[key_content])

        if not key_max_lines in data or not data[key_max_lines]:
            self.window().max_lines_value.setText('')
        else:
            self.window().max_lines_value.setText(str(data[key_max_lines]))

        sb = log_display_widget.verticalScrollBar()
        sb.setValue(sb.maximum())

    def show(self):
        super(DebugWindow, self).show()

        # this will remove minimized status
        # and restore window with keeping maximized/normal state
        self.window().setWindowState(self.window().windowState() & ~Qt.WindowMinimized | Qt.WindowActive)
        self.window().activateWindow()

    def load_libtorrent_data(self, export=False):
        tab = self.window().libtorrent_tab_widget.currentIndex()
        hop = 0 if self.window().lt_zero_hop_btn.isChecked() \
            else 1 if self.window().lt_one_hop_btn.isChecked() \
            else 2 if self.window().lt_two_hop_btn.isChecked() \
            else 3
        if tab == 0:
            self.load_libtorrent_settings_tab(hop, export=export)
        elif tab == 1:
            self.load_libtorrent_sessions_tab(hop, export=export)

    def load_libtorrent_settings_tab(self, hop, export=False):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("libtorrent/settings?hop=%d" % hop,
                                         lambda data: self.on_libtorrent_settings_received(data, export=export))
        self.window().libtorrent_settings_tree_widget.clear()

    def on_libtorrent_settings_received(self, data, export=False):
        if not data:
            return
        for key, value in data["settings"].items():
            item = QTreeWidgetItem(self.window().libtorrent_settings_tree_widget)
            item.setText(0, key)
            item.setText(1, str(value))
            self.window().libtorrent_settings_tree_widget.addTopLevelItem(item)
        if export:
            self.save_to_file("libtorrent_settings.json", data)

    def load_libtorrent_sessions_tab(self, hop, export=False):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("libtorrent/session?hop=%d" % hop,
                                         lambda data: self.on_libtorrent_session_received(data, export=export))
        self.window().libtorrent_session_tree_widget.clear()

    def on_libtorrent_session_received(self, data, export=False):
        if not data:
            return
        for key, value in data["session"].items():
            item = QTreeWidgetItem(self.window().libtorrent_session_tree_widget)
            item.setText(0, key)
            item.setText(1, str(value))
            self.window().libtorrent_session_tree_widget.addTopLevelItem(item)
        if export:
            self.save_to_file("libtorrent_session.json", data)

    def save_to_file(self, filename, data):
        base_dir = QFileDialog.getExistingDirectory(self, "Select an export directory", "", QFileDialog.ShowDirsOnly)
        if len(base_dir) > 0:
            dest_path = os.path.join(base_dir, filename)
            try:
                torrent_file = open(dest_path, "wb")
                torrent_file.write(json.dumps(data))
                torrent_file.close()
            except IOError as exc:
                ConfirmationDialog.show_error(self.window(), "Error exporting file", str(exc))
コード例 #47
0
ファイル: trustpage.py プロジェクト: synctext/tribler
class TrustPage(QWidget):
    """
    This page shows various trust statistics.
    """

    def __init__(self):
        QWidget.__init__(self)
        self.trust_plot = None
        self.public_key = None
        self.request_mgr = None
        self.blocks = None
        self.byte_scale = 1024 * 1024
        self.dialog = None

        # Timer for garbage collection
        self.gc_timer = 0

    def initialize_trust_page(self):
        vlayout = self.window().plot_widget.layout()
        self.trust_plot = TrustPlotMplCanvas(self.window().plot_widget, dpi=100)
        vlayout.addWidget(self.trust_plot)

        self.window().trade_button.clicked.connect(self.on_trade_button_clicked)
        self.window().trust_explain_button.clicked.connect(self.on_info_button_clicked)

    def on_trade_button_clicked(self):
        self.window().market_page.initialize_market_page()
        self.window().navigation_stack.append(self.window().stackedWidget.currentIndex())
        self.window().stackedWidget.setCurrentIndex(PAGE_MARKET)

    def on_info_button_clicked(self):
        self.dialog = TrustExplanationDialog(self.window())
        self.dialog.show()

    def load_blocks(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("ipv8/trustchain/users/%s/blocks" % self.public_key,
                                         self.received_trustchain_blocks)

    def received_trustchain_statistics(self, statistics):
        if not statistics:
            return
        statistics = statistics["statistics"]
        self.public_key = statistics["id"]
        total_up = 0
        total_down = 0
        if 'latest_block' in statistics:
            total_up = statistics["latest_block"]["transaction"]["total_up"]
            total_down = statistics["latest_block"]["transaction"]["total_down"]

        self.window().trust_contribution_amount_label.setText("%s MBytes" % (total_up / self.byte_scale))
        self.window().trust_consumption_amount_label.setText("%s MBytes" % (total_down / self.byte_scale))

        self.window().trust_people_helped_label.setText("%d" % statistics["peers_that_pk_helped"])
        self.window().trust_people_helped_you_label.setText("%d" % statistics["peers_that_helped_pk"])

    def received_trustchain_blocks(self, blocks):
        if blocks:
            self.blocks = blocks["blocks"]
            self.plot_absolute_values()
            # Matplotlib is leaking memory on re-plotting. Refer: https://github.com/matplotlib/matplotlib/issues/8528
            # Note that gc is called every 10 minutes.
            if self.gc_timer == GC_TIMEOUT:
                gc.collect()
                self.gc_timer = 0
            else:
                self.gc_timer += 1

    def plot_absolute_values(self):
        """
        Plot two lines of the absolute amounts of contributed and consumed bytes.
        """
        plot_data = [[[], []], []]

        # Convert all dates to a datetime object
        num_bandwidth_blocks = 0
        for block in self.blocks:
            if block["type"] != "tribler_bandwidth":
                continue

            plot_data[1].append(datetime.datetime.strptime(block["insert_time"], "%Y-%m-%d %H:%M:%S"))

            plot_data[0][0].append(block["transaction"]["total_up"] / self.byte_scale)
            plot_data[0][1].append(block["transaction"]["total_down"] / self.byte_scale)
            num_bandwidth_blocks += 1

        if num_bandwidth_blocks == 0:
            # Create on single data point with 0mb up and 0mb down
            plot_data = [[[0], [0]], [datetime.datetime.now()]]

        self.trust_plot.plot_data = plot_data
        self.trust_plot.compute_initial_figure()
コード例 #48
0
ファイル: editchannelpage.py プロジェクト: zippav/tribler
 def clicked_edit_channel_commit_button(self):
     request_mgr = TriblerRequestManager()
     request_mgr.perform_request("mychannel/commit",
                                 self.on_channel_committed,
                                 method='POST')
コード例 #49
0
ファイル: feedbackdialog.py プロジェクト: xiaomuweb/tribler
class FeedbackDialog(QDialog):

    def __init__(self, parent, exception_text, tribler_version, start_time):
        QDialog.__init__(self, parent)

        uic.loadUi(get_ui_file_path('feedback_dialog.ui'), self)

        self.setWindowTitle("Unexpected error")
        self.selected_item_index = 0
        self.tribler_version = tribler_version
        self.request_mgr = None

        # Qt 5.2 does not have the setPlaceholderText property
        if hasattr(self.comments_text_edit, "setPlaceholderText"):
            self.comments_text_edit.setPlaceholderText("Comments (optional)")

        def add_item_to_info_widget(key, value):
            item = QTreeWidgetItem(self.env_variables_list)
            item.setText(0, key)
            item.setText(1, value)

        self.error_text_edit.setPlainText(exception_text.rstrip())

        self.cancel_button.clicked.connect(self.on_cancel_clicked)
        self.send_report_button.clicked.connect(self.on_send_clicked)

        # Add machine information to the tree widget
        add_item_to_info_widget('os.getcwd', '%s' % os.getcwd())
        add_item_to_info_widget('sys.executable', '%s' % sys.executable)

        add_item_to_info_widget('os', os.name)
        add_item_to_info_widget('platform', sys.platform)
        add_item_to_info_widget('platform.details', platform.platform())
        add_item_to_info_widget('platform.machine', platform.machine())
        add_item_to_info_widget('python.version', sys.version)
        add_item_to_info_widget('indebug', str(__debug__))
        add_item_to_info_widget('tribler_uptime', "%s" % (time.time() - start_time))

        for argv in sys.argv:
            add_item_to_info_widget('sys.argv', '%s' % argv)

        for path in sys.path:
            add_item_to_info_widget('sys.path', '%s' % path)

        for key in os.environ.keys():
            add_item_to_info_widget('os.environ', '%s: %s' % (key, os.environ[key]))

        # Add recent requests to feedback dialog
        request_ind = 1
        for endpoint, method, data, timestamp, status_code in sorted(tribler_performed_requests,
                                                                     key=lambda x: x[3])[-30:]:
            add_item_to_info_widget('request_%d' % request_ind, '%s %s %s (time: %s, code: %s)' %
                                    (endpoint, method, data, timestamp, status_code))
            request_ind += 1

        # Add recent events to feedback dialog
        events_ind = 1
        for event, event_time in received_events[:30][::-1]:
            add_item_to_info_widget('event_%d' % events_ind, '%s (time: %s)' % (json.dumps(event), event_time))
            events_ind += 1

        # Users can remove specific lines in the report
        self.env_variables_list.customContextMenuRequested.connect(self.on_right_click_item)

    def on_remove_entry(self):
        self.env_variables_list.takeTopLevelItem(self.selected_item_index)

    def on_right_click_item(self, pos):
        item_clicked = self.env_variables_list.itemAt(pos)
        if not item_clicked:
            return

        self.selected_item_index = self.env_variables_list.indexOfTopLevelItem(item_clicked)

        menu = TriblerActionMenu(self)

        remove_action = QAction('Remove entry', self)
        remove_action.triggered.connect(self.on_remove_entry)
        menu.addAction(remove_action)
        menu.exec_(self.env_variables_list.mapToGlobal(pos))

    def on_cancel_clicked(self):
        QApplication.quit()

    def on_report_sent(self, response):
        if not response:
            return
        sent = response[u'sent']

        success_text = "Successfully sent the report! Thanks for your contribution."
        error_text = "Could not send the report! Please post this issue on GitHub."

        box = QMessageBox(self.window())
        box.setWindowTitle("Report Sent" if sent else "ERROR: Report Sending Failed")
        box.setText(success_text if sent else error_text)
        box.setStyleSheet("QPushButton { color: white; }")
        box.exec_()

        QApplication.quit()

    def on_send_clicked(self):
        self.send_report_button.setEnabled(False)
        self.send_report_button.setText("SENDING...")

        self.request_mgr = TriblerRequestManager()
        endpoint = 'http://reporter.tribler.org/report'

        sys_info = ""
        for ind in xrange(self.env_variables_list.topLevelItemCount()):
            item = self.env_variables_list.topLevelItem(ind)
            sys_info += "%s\t%s\n" % (quote_plus(item.text(0)), quote_plus(item.text(1)))

        comments = self.comments_text_edit.toPlainText()
        if len(comments) == 0:
            comments = "Not provided"
        comments = quote_plus(comments)

        stack = quote_plus(self.error_text_edit.toPlainText())

        post_data = "version=%s&machine=%s&os=%s&timestamp=%s&sysinfo=%s&comments=%s&stack=%s" % \
                    (self.tribler_version, platform.machine(), platform.platform(),
                     int(time.time()), sys_info, comments, stack)

        self.request_mgr.perform_request(endpoint, self.on_report_sent, data=str(post_data), method='POST')

    def closeEvent(self, close_event):
        QApplication.quit()
        close_event.ignore()
コード例 #50
0
class SettingsPage(QWidget):
    """
    This class is responsible for displaying and adjusting the settings present in Tribler.
    """
    def __init__(self):
        QWidget.__init__(self)
        self.settings = None
        self.settings_request_mgr = None
        self.saved_dialog = None

    def initialize_settings_page(self):
        self.window().settings_tab.initialize()
        self.window().settings_tab.clicked_tab_button.connect(
            self.clicked_tab_button)
        self.window().settings_save_button.clicked.connect(self.save_settings)

        self.window().developer_mode_enabled_checkbox.stateChanged.connect(
            self.on_developer_mode_checkbox_changed)
        self.window().download_settings_anon_checkbox.stateChanged.connect(
            self.on_anon_download_state_changed)

    def on_developer_mode_checkbox_changed(self, _):
        self.window().gui_settings.setValue(
            "debug",
            self.window().developer_mode_enabled_checkbox.isChecked())
        self.window().left_menu_button_debug.setHidden(
            not self.window().developer_mode_enabled_checkbox.isChecked())

    def on_anon_download_state_changed(self, _):
        if self.window().download_settings_anon_checkbox.isChecked():
            self.window().download_settings_anon_seeding_checkbox.setChecked(
                True)
        self.window().download_settings_anon_seeding_checkbox.setEnabled(
            not self.window().download_settings_anon_checkbox.isChecked())

    def initialize_with_settings(self, settings):
        self.settings = settings
        settings = settings["settings"]
        gui_settings = self.window().gui_settings

        # General settings
        self.window().developer_mode_enabled_checkbox.setChecked(
            get_gui_setting(gui_settings, "debug", False, is_bool=True))
        self.window().family_filter_checkbox.setChecked(
            settings['general']['family_filter'])
        self.window().download_location_input.setText(
            settings['downloadconfig']['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(
            get_gui_setting(gui_settings,
                            "default_anonymity_enabled",
                            True,
                            is_bool=True))
        self.window().download_settings_anon_seeding_checkbox.setChecked(
            get_gui_setting(gui_settings,
                            "default_safeseeding_enabled",
                            True,
                            is_bool=True))
        self.window().watchfolder_enabled_checkbox.setChecked(
            settings['watch_folder']['enabled'])
        self.window().watchfolder_location_input.setText(
            settings['watch_folder']['watch_folder_dir'])

        # Connection settings
        self.window().firewall_current_port_input.setText(
            str(settings['general']['minport']))
        self.window().lt_proxy_type_combobox.setCurrentIndex(
            settings['libtorrent']['lt_proxytype'])
        if settings['libtorrent']['lt_proxyserver']:
            self.window().lt_proxy_server_input.setText(
                settings['libtorrent']['lt_proxyserver'][0])
            self.window().lt_proxy_port_input.setText(
                settings['libtorrent']['lt_proxyserver'][1])
        if settings['libtorrent']['lt_proxyauth']:
            self.window().lt_proxy_username_input.setText(
                settings['libtorrent']['lt_proxyauth'][0])
            self.window().lt_proxy_password_input.setText(
                settings['libtorrent']['lt_proxyauth'][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))

        # Bandwidth settings
        self.window().upload_rate_limit_input.setText(
            str(settings['Tribler']['maxuploadrate']))
        self.window().download_rate_limit_input.setText(
            str(settings['Tribler']['maxdownloadrate']))

        # Seeding settings
        getattr(
            self.window(),
            "seeding_" + settings['downloadconfig']['seeding_mode'] +
            "_radio").setChecked(True)
        self.window().seeding_time_input.setText(
            seconds_to_string(settings['downloadconfig']['seeding_time']))
        ind = self.window().seeding_ratio_combobox.findText(
            str(settings['downloadconfig']['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['Tribler']['default_number_hops']) - 1)
        self.window().multichain_enabled_checkbox.setChecked(
            settings['multichain']['enabled'])

    def load_settings(self):
        self.settings_request_mgr = TriblerRequestManager()
        self.settings_request_mgr.perform_request(
            "settings", self.initialize_with_settings)

    def clicked_tab_button(self, tab_button_name):
        if tab_button_name == "settings_general_button":
            self.window().settings_stacked_widget.setCurrentIndex(
                PAGE_SETTINGS_GENERAL)
        elif tab_button_name == "settings_connection_button":
            self.window().settings_stacked_widget.setCurrentIndex(
                PAGE_SETTINGS_CONNECTION)
        elif tab_button_name == "settings_bandwidth_button":
            self.window().settings_stacked_widget.setCurrentIndex(
                PAGE_SETTINGS_BANDWIDTH)
        elif tab_button_name == "settings_seeding_button":
            self.window().settings_stacked_widget.setCurrentIndex(
                PAGE_SETTINGS_SEEDING)
        elif tab_button_name == "settings_anonymity_button":
            self.window().settings_stacked_widget.setCurrentIndex(
                PAGE_SETTINGS_ANONYMITY)

    def save_settings(self):
        # Create a dictionary with all available settings
        settings_data = {
            'general': {},
            'Tribler': {},
            'downloadconfig': {},
            'libtorrent': {},
            'watch_folder': {},
            'tunnel_community': {},
            'multichain': {}
        }
        settings_data['general']['family_filter'] = self.window(
        ).family_filter_checkbox.isChecked()
        settings_data['downloadconfig']['saveas'] = self.window(
        ).download_location_input.text()

        settings_data['watch_folder']['enabled'] = self.window(
        ).watchfolder_enabled_checkbox.isChecked()
        if settings_data['watch_folder']['enabled']:
            settings_data['watch_folder']['watch_folder_dir'] = self.window(
            ).watchfolder_location_input.text()

        settings_data['general']['minport'] = self.window(
        ).firewall_current_port_input.text()
        settings_data['libtorrent']['lt_proxytype'] = self.window(
        ).lt_proxy_type_combobox.currentIndex()

        if len(self.window().lt_proxy_server_input.text()) > 0 and len(
                self.window().lt_proxy_port_input.text()) > 0:
            settings_data['libtorrent']['lt_proxyserver'] = [None, None]
            settings_data['libtorrent']['lt_proxyserver'][0] = self.window(
            ).lt_proxy_server_input.text()
            settings_data['libtorrent']['lt_proxyserver'][1] = self.window(
            ).lt_proxy_port_input.text()

        if len(self.window().lt_proxy_username_input.text()) > 0 and \
                        len(self.window().lt_proxy_password_input.text()) > 0:
            settings_data['libtorrent']['lt_proxyauth'] = [None, None]
            settings_data['libtorrent']['lt_proxyauth'][0] = self.window(
            ).lt_proxy_username_input.text()
            settings_data['libtorrent']['lt_proxyauth'][1] = self.window(
            ).lt_proxy_password_input.text()
        settings_data['libtorrent']['utp'] = self.window(
        ).lt_utp_checkbox.isChecked()

        try:
            max_conn_download = int(
                self.window().max_connections_download_input.text())
        except ValueError:
            ConfirmationDialog.show_error(
                self.window(), "Invalid number of connections",
                "You've entered an invalid format for the maximum number of connections."
            )
            return
        if max_conn_download == 0:
            max_conn_download = -1
        settings_data['libtorrent'][
            'max_connections_download'] = max_conn_download

        if self.window().upload_rate_limit_input.text():
            settings_data['Tribler']['maxuploadrate'] = self.window(
            ).upload_rate_limit_input.text()
        if self.window().download_rate_limit_input.text():
            settings_data['Tribler']['maxdownloadrate'] = self.window(
            ).download_rate_limit_input.text()

        seeding_modes = ['forever', 'time', 'never', 'ratio']
        selected_mode = 'forever'
        for seeding_mode in seeding_modes:
            if getattr(self.window(),
                       "seeding_" + seeding_mode + "_radio").isChecked():
                selected_mode = seeding_mode
                break
        settings_data['downloadconfig']['seeding_mode'] = selected_mode
        settings_data['downloadconfig']['seeding_ratio'] = self.window(
        ).seeding_ratio_combobox.currentText()

        try:
            settings_data['downloadconfig'][
                'seeding_time'] = string_to_minutes(
                    self.window().seeding_time_input.text())
        except ValueError:
            ConfirmationDialog.show_error(
                self.window(), "Invalid seeding time",
                "You've entered an invalid format for the seeding time (expected HH:MM)"
            )
            return

        settings_data['tunnel_community']['exitnode_enabled'] = self.window(
        ).allow_exit_node_checkbox.isChecked()
        settings_data['Tribler']['default_number_hops'] = self.window(
        ).number_hops_slider.value() + 1
        settings_data['multichain']['enabled'] = self.window(
        ).multichain_enabled_checkbox.isChecked()

        self.settings_request_mgr = TriblerRequestManager()
        self.settings_request_mgr.perform_request(
            "settings",
            self.on_settings_saved,
            method='POST',
            data=json.dumps(settings_data))

    def on_settings_saved(self, _):
        # Now save the GUI settings
        self.window().gui_settings.setValue(
            "ask_download_settings",
            self.window().always_ask_location_checkbox.isChecked())
        self.window().gui_settings.setValue(
            "default_anonymity_enabled",
            self.window().download_settings_anon_checkbox.isChecked())
        self.window().gui_settings.setValue(
            "default_safeseeding_enabled",
            self.window().download_settings_anon_seeding_checkbox.isChecked())

        self.saved_dialog = ConfirmationDialog(
            TriblerRequestManager.window, "Settings saved",
            "Your settings have been saved.", [('close', BUTTON_TYPE_NORMAL)])
        self.saved_dialog.button_clicked.connect(self.on_dialog_cancel_clicked)
        self.saved_dialog.show()
        self.window().fetch_settings()

    def on_dialog_cancel_clicked(self, _):
        self.saved_dialog.setParent(None)
        self.saved_dialog = None
コード例 #51
0
class SubscriptionsWidget(QWidget):
    """
    This widget shows a favorite button and the number of subscriptions that a specific channel has.
    """

    unsubscribed_channel = pyqtSignal(object)
    subscribed_channel = pyqtSignal(object)

    def __init__(self, parent):
        QWidget.__init__(self, parent)

        self.subscribe_button = None
        self.channel_info = None
        self.num_subs_label = None
        self.credit_mining_button = None
        self.request_mgr = None
        self.initialized = False

    def initialize_with_channel(self, channel):
        self.channel_info = channel
        if not self.initialized:
            self.subscribe_button = self.findChild(QWidget, "subscribe_button")
            self.num_subs_label = self.findChild(QWidget, "num_subs_label")
            self.credit_mining_button = self.findChild(QWidget, "credit_mining_button")

            self.subscribe_button.clicked.connect(self.on_subscribe_button_click)
            self.credit_mining_button.clicked.connect(self.on_credit_mining_button_click)
            self.initialized = True

        self.update_subscribe_button()

    def update_subscribe_button(self, remote_response=None):
        if remote_response and 'subscribed' in remote_response:
            self.channel_info["subscribed"] = remote_response['subscribed']

        if remote_response and 'votes' in remote_response:
            self.channel_info["votes"] = remote_response['votes']

        if self.channel_info["subscribed"]:
            self.subscribe_button.setIcon(QIcon(QPixmap(get_image_path('subscribed_yes.png'))))
        else:
            self.subscribe_button.setIcon(QIcon(QPixmap(get_image_path('subscribed_not.png'))))

        self.num_subs_label.setText(str(self.channel_info["votes"]))

        if self.window().tribler_settings:  # It could be that the settings are not loaded yet
            self.credit_mining_button.setHidden(not self.window().tribler_settings["credit_mining"]["enabled"])
            if self.channel_info["dispersy_cid"] in self.window().tribler_settings["credit_mining"]["sources"]:
                self.credit_mining_button.setIcon(QIcon(QPixmap(get_image_path('credit_mining_yes.png'))))
            else:
                self.credit_mining_button.setIcon(QIcon(QPixmap(get_image_path('credit_mining_not.png'))))
        else:
            self.credit_mining_button.hide()

    def on_subscribe_button_click(self):
        self.request_mgr = TriblerRequestManager()
        if self.channel_info["subscribed"]:
            self.request_mgr.perform_request("channels/subscribed/%s" %
                                             self.channel_info['dispersy_cid'],
                                             self.on_channel_unsubscribed, method='DELETE')
        else:
            self.request_mgr.perform_request("channels/subscribed/%s" %
                                             self.channel_info['dispersy_cid'],
                                             self.on_channel_subscribed, method='PUT')

    def on_channel_unsubscribed(self, json_result):
        if not json_result:
            return
        if json_result["unsubscribed"]:
            self.unsubscribed_channel.emit(self.channel_info)
            self.channel_info["subscribed"] = False
            self.channel_info["votes"] -= 1
            self.update_subscribe_button()

    def on_channel_subscribed(self, json_result):
        if not json_result:
            return
        if json_result["subscribed"]:
            self.subscribed_channel.emit(self.channel_info)
            self.channel_info["subscribed"] = True
            self.channel_info["votes"] += 1
            self.update_subscribe_button()

    def on_credit_mining_button_click(self):
        old_sources = self.window().tribler_settings["credit_mining"]["sources"]
        new_sources = [] if self.channel_info["dispersy_cid"] in old_sources else [self.channel_info["dispersy_cid"]]
        settings = {"credit_mining": {"sources": new_sources}}

        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("settings", self.on_credit_mining_sources,
                                         method='POST', data=json.dumps(settings))

    def on_credit_mining_sources(self, json_result):
        if not json_result:
            return
        if json_result["modified"]:
            old_source = next(iter(self.window().tribler_settings["credit_mining"]["sources"]), None)

            new_sources = [self.channel_info["dispersy_cid"]] if self.channel_info["dispersy_cid"] != old_source else []
            self.window().tribler_settings["credit_mining"]["sources"] = new_sources

            self.update_subscribe_button()

            channels_list = self.window().discovered_channels_list
            for index, data_item in enumerate(channels_list.data_items):
                if data_item[1]['dispersy_cid'] == old_source:
                    channel_item = channels_list.itemWidget(channels_list.item(index))
                    if channel_item:
                        channel_item.subscriptions_widget.update_subscribe_button()
                    break
コード例 #52
0
class StartDownloadDialog(DialogContainer):

    button_clicked = pyqtSignal(int)
    received_metainfo = pyqtSignal(dict)

    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
        gui_settings = self.window().gui_settings

        uic.loadUi(get_ui_file_path('startdownloaddialog.ui'),
                   self.dialog_widget)

        self.dialog_widget.setSizePolicy(QSizePolicy.Fixed,
                                         QSizePolicy.Expanding)

        self.dialog_widget.browse_dir_button.clicked.connect(
            self.on_browse_dir_clicked)
        self.dialog_widget.cancel_button.clicked.connect(
            lambda: self.button_clicked.emit(0))
        self.dialog_widget.download_button.clicked.connect(
            self.on_download_clicked)
        self.dialog_widget.select_all_files_button.clicked.connect(
            self.on_all_files_selected_clicked)
        self.dialog_widget.deselect_all_files_button.clicked.connect(
            self.on_all_files_deselected_clicked)

        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'))

        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 = [
                    url.decode('hex') 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)

        self.dialog_widget.anon_download_checkbox.stateChanged.connect(
            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.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()

    def get_selected_files(self):
        included_files = []
        for ind in xrange(
                self.dialog_widget.files_list_view.topLevelItemCount()):
            item = self.dialog_widget.files_list_view.topLevelItem(ind)
            if item.checkState(2) == Qt.Checked:
                included_files.append(u'/'.join(
                    item.data(0, Qt.UserRole)['path']))

        return included_files

    def perform_files_request(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("torrentinfo?uri=%s" %
                                         quote_plus_unicode(self.download_uri),
                                         self.on_received_metainfo,
                                         capture_errors=False)

    def on_received_metainfo(self, metainfo):
        if not metainfo:
            return

        if 'error' in metainfo:
            if metainfo['error'] == 'timeout':
                self.dialog_widget.loading_files_label.setText(
                    "Timeout when trying to fetch files.")
            elif 'code' in metainfo['error'] and metainfo['error'][
                    'code'] == 'IOError':
                self.dialog_widget.loading_files_label.setText(
                    "Unable to read torrent file data")
            else:
                self.dialog_widget.loading_files_label.setText(
                    "Error: %s" % metainfo['error'])
            return

        metainfo = metainfo['metainfo']
        if 'files' in metainfo['info']:  # Multi-file torrent
            files = metainfo['info']['files']
        else:
            files = [{
                'path': [metainfo['info']['name']],
                'length': metainfo['info']['length']
            }]

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

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

        self.received_metainfo.emit(metainfo)

    def on_browse_dir_clicked(self):
        chosen_dir = QFileDialog.getExistingDirectory(
            self.window(), "Please select the destination directory of your "
            "download", "", QFileDialog.ShowDirsOnly)

        if len(chosen_dir) != 0:
            self.dialog_widget.destination_input.setCurrentText(chosen_dir)

        if not is_dir_writable(chosen_dir):
            ConfirmationDialog.show_message(
                self.dialog_widget, "Insufficient Permissions",
                "Tribler cannot download to <i>%s</i> directory. "
                "Please add proper write permissions to the directory "
                "or choose another download directory." % chosen_dir, "OK")

    def on_anon_download_state_changed(self, _):
        if self.dialog_widget.anon_download_checkbox.isChecked():
            self.dialog_widget.safe_seed_checkbox.setChecked(True)
        self.dialog_widget.safe_seed_checkbox.setEnabled(
            not self.dialog_widget.anon_download_checkbox.isChecked())

    def on_download_clicked(self):
        if self.has_metainfo and len(self.get_selected_files()
                                     ) == 0:  # User deselected all torrents
            ConfirmationDialog.show_error(
                self.window(), "No files selected",
                "Please select at least one file to download.")
        else:
            download_dir = self.dialog_widget.destination_input.currentText()
            if not is_dir_writable(download_dir):
                ConfirmationDialog.show_message(
                    self.dialog_widget, "Insufficient Permissions",
                    "Tribler cannot download to <i>%s</i> directory. "
                    "Please add proper write permissions to the directory "
                    "or choose another download directory and try to download again."
                    % download_dir, "OK")
            else:
                self.button_clicked.emit(1)

    def on_all_files_selected_clicked(self):
        for ind in xrange(
                self.dialog_widget.files_list_view.topLevelItemCount()):
            item = self.dialog_widget.files_list_view.topLevelItem(ind)
            item.setCheckState(2, Qt.Checked)

    def on_all_files_deselected_clicked(self):
        for ind in xrange(
                self.dialog_widget.files_list_view.topLevelItemCount()):
            item = self.dialog_widget.files_list_view.topLevelItem(ind)
            item.setCheckState(2, Qt.Unchecked)
コード例 #53
0
ファイル: marketpage.py プロジェクト: yanheven/tribler
class MarketPage(QWidget):
    """
    This page displays the decentralized market in Tribler.
    """
    def __init__(self):
        QWidget.__init__(self)
        self.request_mgr = None
        self.asks_request_mgr = None
        self.bids_request_mgr = None
        self.dialog = None
        self.initialized = False
        self.wallets = []
        self.chosen_wallets = None
        self.wallet_widgets = {}

        self.bids = []
        self.asks = []

    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(
            ).core_manager.events_manager.market_iom_input_required.connect(
                self.on_iom_input_required)

            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_currency_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(2, 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.initialized = True

        self.load_wallets()

    def load_wallets(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("wallets", self.on_wallets)

    def on_wallets(self, wallets):
        wallets = wallets["wallets"]

        currency_wallets = ['BTC']
        total_currency_wallets = 0
        for wallet_id in wallets.keys():
            if wallet_id in currency_wallets:
                total_currency_wallets += 1

        if currency_wallets == 0:
            self.window().market_create_wallet_button.show()
            self.window().create_ask_button.hide()
            self.window().create_bid_button.hide()

        self.wallets = []
        for wallet_id in wallets.keys():
            self.wallets.append(wallet_id)

        if self.chosen_wallets is None and len(self.wallets) >= 2:
            self.chosen_wallets = (self.wallets[0], self.wallets[1])
            self.update_button_texts()

        for wallet_id, wallet in wallets.iteritems():
            if not wallet['created'] or not wallet['unlocked']:
                continue

            if wallet_id not in self.wallet_widgets:
                wallet_widget = MarketCurrencyBox(
                    self.window().market_header_widget,
                    wallets[wallet_id]['name'])
                self.window().market_header_widget.layout().insertWidget(
                    4, wallet_widget)
                wallet_widget.setFixedWidth(100)
                wallet_widget.setFixedHeight(34)
                wallet_widget.show()
                self.wallet_widgets[wallet_id] = wallet_widget

                spacer = QSpacerItem(10, 20, QSizePolicy.Fixed,
                                     QSizePolicy.Fixed)
                self.window().market_header_widget.layout().insertSpacerItem(
                    5, spacer)

            # The total balance keys might be different between wallet
            balance_amount = wallet['balance']['available']
            balance_currency = None

            if wallet_id == 'PP' or wallet_id == 'ABNA' or wallet_id == 'RABO':
                balance_currency = wallet['balance']['currency']

            self.wallet_widgets[wallet_id].update_with_amount(
                balance_amount, balance_currency)

        self.load_asks()
        self.load_bids()

    def update_button_texts(self):
        self.window().market_currency_type_button.setText(
            "%s / %s" % (self.chosen_wallets[0], self.chosen_wallets[1]))
        self.window().create_ask_button.setText(
            "Sell %s for %s" %
            (self.chosen_wallets[0], self.chosen_wallets[1]))
        self.window().create_bid_button.setText(
            "Buy %s for %s" % (self.chosen_wallets[0], self.chosen_wallets[1]))

    def create_widget_item_from_tick(self, tick_list, tick, is_ask=True):
        tick["type"] = "ask" if is_ask else "bid"
        item = TickWidgetItem(tick_list, tick)
        item.setText(0, "%s %s" % (tick["quantity"], tick["quantity_type"]))
        item.setText(1, "%s %s" % (tick["price"], tick["price_type"]))
        return item

    def load_asks(self):
        self.asks_request_mgr = TriblerRequestManager()
        self.asks_request_mgr.perform_request("market/asks",
                                              self.on_received_asks)

    def on_received_asks(self, asks):
        self.asks = asks["asks"]
        self.update_filter_asks_list()

    def update_filter_asks_list(self):
        self.window().asks_list.clear()

        ticks = None
        for price_level_info in self.asks:
            if (price_level_info['quantity_type'],
                    price_level_info['price_type']) == self.chosen_wallets:
                ticks = price_level_info["ticks"]
                break

        if ticks:
            for ask in ticks:
                self.window().asks_list.addTopLevelItem(
                    self.create_widget_item_from_tick(self.window().asks_list,
                                                      ask,
                                                      is_ask=True))

    def load_bids(self):
        self.bids_request_mgr = TriblerRequestManager()
        self.bids_request_mgr.perform_request("market/bids",
                                              self.on_received_bids)

    def on_received_bids(self, bids):
        self.bids = bids["bids"]
        self.update_filter_bids_list()

    def update_filter_bids_list(self):
        self.window().bids_list.clear()

        ticks = None
        for price_level_info in self.bids:
            if (price_level_info['quantity_type'],
                    price_level_info['price_type']) == self.chosen_wallets:
                ticks = price_level_info["ticks"]
                break

        if ticks:
            for bid in ticks:
                self.window().bids_list.addTopLevelItem(
                    self.create_widget_item_from_tick(self.window().bids_list,
                                                      bid,
                                                      is_ask=False))

    def on_ask(self, ask):
        has_level = False
        for price_level_info in self.asks:
            if price_level_info['quantity_type'] == ask['quantity_type'] \
                    and price_level_info['price_type'] == ask['price_type']:
                price_level_info['ticks'].append(ask)
                has_level = True

        if not has_level:
            self.asks.append({
                'price_type': ask['price_type'],
                'quantity_type': ask['quantity_type'],
                'ticks': [ask]
            })

        self.update_filter_asks_list()

    def on_bid(self, bid):
        has_level = False
        for price_level_info in self.bids:
            if price_level_info['quantity_type'] == bid['quantity_type'] \
                    and price_level_info['price_type'] == bid['price_type']:
                price_level_info['ticks'].append(bid)

        if not has_level:
            self.bids.append({
                'price_type': bid['price_type'],
                'quantity_type': bid['quantity_type'],
                'ticks': [bid]
            })

        self.update_filter_bids_list()

    def on_transaction_complete(self, transaction):
        if transaction["mine"]:
            transaction = transaction["tx"]
            main_text = "Transaction with price %f %s and quantity %f %s completed." \
                        % (transaction["price"], transaction["price_type"],
                           transaction["quantity"], transaction["quantity_type"])
            self.window().tray_icon.showMessage("Transaction completed",
                                                main_text)
            self.window().hide_status_bar()

            # Reload wallets
            self.load_wallets()

            # Reload transactions
            self.window().market_transactions_page.load_transactions()
        else:
            self.load_asks()
            self.load_bids()

    def on_iom_input_required(self, event_dict):
        self.dialog = IomInputDialog(self.window().stackedWidget,
                                     event_dict['bank_name'],
                                     event_dict['input'])
        self.dialog.button_clicked.connect(self.on_iom_input)
        self.dialog.show()

    def on_iom_input(self, action):
        if action == 1:
            post_data = {'input_name': self.dialog.required_input['name']}
            for input_name, input_widget in self.dialog.input_widgets.iteritems(
            ):
                post_data[input_name] = input_widget.text()

            self.request_mgr = TriblerRequestManager()
            self.request_mgr.perform_request("iominput",
                                             None,
                                             data=urlencode(post_data),
                                             method='POST')

        self.dialog.setParent(None)
        self.dialog = None

    def create_order(self, is_ask, price, price_type, quantity, quantity_type):
        post_data = str("price=%f&price_type=%s&quantity=%f&quantity_type=%s" %
                        (price, price_type, quantity, quantity_type))
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request(
            "market/%s" % ('asks' if is_ask else 'bids'),
            lambda response: self.on_order_created(response, is_ask),
            data=post_data,
            method='PUT')

    def on_transactions_button_clicked(self):
        self.window().market_transactions_page.initialize_transactions_page()
        self.window().navigation_stack.append(
            self.window().stackedWidget.currentIndex())
        self.window().stackedWidget.setCurrentIndex(PAGE_MARKET_TRANSACTIONS)

    def on_wallets_button_clicked(self):
        self.window().market_wallets_page.initialize_wallets_page()
        self.window().navigation_stack.append(
            self.window().stackedWidget.currentIndex())
        self.window().stackedWidget.setCurrentIndex(PAGE_MARKET_WALLETS)

    def on_orders_button_clicked(self):
        self.window().market_orders_page.initialize_orders_page()
        self.window().navigation_stack.append(
            self.window().stackedWidget.currentIndex())
        self.window().stackedWidget.setCurrentIndex(PAGE_MARKET_ORDERS)

    def on_order_created(self, response, is_ask):
        if is_ask:
            self.load_asks()
        else:
            self.load_bids()

    def on_tick_item_clicked(self, tick_list):
        if len(tick_list.selectedItems()) == 0:
            return
        tick = tick_list.selectedItems()[0].tick

        if tick_list == self.window().asks_list:
            self.window().bids_list.clearSelection()
        else:
            self.window().asks_list.clearSelection()

        tick_time = datetime.datetime.fromtimestamp(int(
            tick["timestamp"])).strftime('%Y-%m-%d %H:%M:%S')
        self.window().market_detail_trader_id_label.setText(tick["trader_id"])
        self.window().market_detail_order_number_label.setText(
            "%s" % tick["order_number"])
        self.window().market_detail_quantity_label.setText(
            "%s %s" % (tick["quantity"], tick["quantity_type"]))
        self.window().market_detail_price_label.setText(
            "%s %s" % (tick["price"], tick["price_type"]))
        self.window().market_detail_time_created_label.setText(tick_time)

        self.window().tick_detail_container.show()

    def on_create_ask_clicked(self):
        self.show_new_order_dialog(True)

    def on_create_bid_clicked(self):
        self.show_new_order_dialog(False)

    def on_currency_type_clicked(self):
        menu = TriblerActionMenu(self)

        for first_wallet_id in self.wallets:
            sub_menu = menu.addMenu(first_wallet_id)

            for second_wallet_id in self.wallets:
                if first_wallet_id == second_wallet_id:
                    continue

                wallet_action = QAction(
                    '%s / %s' % (first_wallet_id, second_wallet_id), self)
                wallet_action.triggered.connect(
                    lambda _, id1=first_wallet_id, id2=second_wallet_id: self.
                    on_currency_type_changed(id1, id2))
                sub_menu.addAction(wallet_action)
        menu.exec_(QCursor.pos())

    def on_currency_type_changed(self, currency1, currency2):
        self.chosen_wallets = (currency1, currency2)
        self.update_button_texts()
        self.update_filter_asks_list()
        self.update_filter_bids_list()

    def show_new_order_dialog(self, is_ask):
        self.dialog = NewMarketOrderDialog(self.window().stackedWidget, is_ask,
                                           self.chosen_wallets[1],
                                           self.chosen_wallets[0])
        self.dialog.button_clicked.connect(self.on_new_order_action)
        self.dialog.show()

    def on_new_order_action(self, action):
        if action == 1:
            self.create_order(self.dialog.is_ask, self.dialog.price,
                              self.dialog.price_type, self.dialog.quantity,
                              self.dialog.quantity_type)

        self.dialog.setParent(None)
        self.dialog = None

    def on_ask_timeout(self, ask):
        self.remove_tick_with_msg_id(self.window().asks_list,
                                     ask["message_id"])

    def on_bid_timeout(self, bid):
        self.remove_tick_with_msg_id(self.window().bids_list,
                                     bid["message_id"])

    def remove_tick_with_msg_id(self, tick_list, msg_id):
        index_to_remove = -1
        for ind in xrange(tick_list.topLevelItemCount()):
            item = tick_list.topLevelItem(ind)
            if item.tick["message_id"] == msg_id:
                index_to_remove = ind
                break

        if index_to_remove != -1:
            tick_list.takeTopLevelItem(index_to_remove)

    def on_payment(self, payment):
        if not payment["success"]:
            # Error occurred during payment
            main_text = "Transaction with id %s failed." % payment[
                "transaction_number"]
            self.window().tray_icon.showMessage("Transaction failed",
                                                main_text)
            ConfirmationDialog.show_error(self.window(), "Transaction failed",
                                          main_text)
            self.window().hide_status_bar()
        else:
            self.window().show_status_bar(
                "Transaction in process, please don't close Tribler.")
コード例 #54
0
class TrustPage(QWidget):
    """
    This page shows various trust statistics.
    """
    def __init__(self):
        QWidget.__init__(self)
        self.trust_plot = None
        self.public_key = None
        self.request_mgr = None
        self.blocks = None
        self.byte_scale = 1024 * 1024
        self.dialog = None

        # Timer for garbage collection
        self.gc_timer = 0

    def initialize_trust_page(self):
        vlayout = self.window().plot_widget.layout()
        if vlayout.isEmpty():
            self.trust_plot = TrustPlotMplCanvas(self.window().plot_widget,
                                                 dpi=100)
            vlayout.addWidget(self.trust_plot)

        self.window().trade_button.clicked.connect(
            self.on_trade_button_clicked)
        self.window().mine_button.clicked.connect(self.on_mine_button_clicked)
        self.window().trust_explain_button.clicked.connect(
            self.on_info_button_clicked)

    def on_trade_button_clicked(self):
        self.window().market_page.initialize_market_page()
        self.window().navigation_stack.append(
            self.window().stackedWidget.currentIndex())
        self.window().stackedWidget.setCurrentIndex(PAGE_MARKET)

    def on_info_button_clicked(self):
        self.dialog = TrustExplanationDialog(self.window())
        self.dialog.show()

    def on_mine_button_clicked(self):
        self.window().token_mining_page.initialize_token_mining_page()
        self.window().navigation_stack.append(
            self.window().stackedWidget.currentIndex())
        self.window().stackedWidget.setCurrentIndex(PAGE_TOKEN_MINING_PAGE)

    def load_blocks(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request(
            "ipv8/trustchain/users/%s/blocks" % self.public_key,
            self.received_trustchain_blocks)

    def received_trustchain_statistics(self, statistics):
        if not statistics:
            return
        statistics = statistics["statistics"]
        self.public_key = statistics["id"]
        total_up = 0
        total_down = 0
        if 'latest_block' in statistics:
            total_up = statistics["latest_block"]["transaction"]["total_up"]
            total_down = statistics["latest_block"]["transaction"][
                "total_down"]

        self.window().trust_contribution_amount_label.setText(
            "%s MBytes" % (total_up / self.byte_scale))
        self.window().trust_consumption_amount_label.setText(
            "%s MBytes" % (total_down / self.byte_scale))

        self.window().trust_people_helped_label.setText(
            "%d" % statistics["peers_that_pk_helped"])
        self.window().trust_people_helped_you_label.setText(
            "%d" % statistics["peers_that_helped_pk"])

    def received_trustchain_blocks(self, blocks):
        if blocks:
            self.blocks = blocks["blocks"]
            self.plot_absolute_values()
            # Matplotlib is leaking memory on re-plotting. Refer: https://github.com/matplotlib/matplotlib/issues/8528
            # Note that gc is called every 10 minutes.
            if self.gc_timer == GC_TIMEOUT:
                gc.collect()
                self.gc_timer = 0
            else:
                self.gc_timer += 1

    def plot_absolute_values(self):
        """
        Plot two lines of the absolute amounts of contributed and consumed bytes.
        """
        plot_data = [[[], []], []]

        # Convert all dates to a datetime object
        num_bandwidth_blocks = 0
        for block in self.blocks:
            if block["type"] != "tribler_bandwidth":
                continue

            plot_data[1].append(
                datetime.datetime.strptime(block["insert_time"],
                                           "%Y-%m-%d %H:%M:%S"))

            plot_data[0][0].append(block["transaction"]["total_up"] /
                                   self.byte_scale)
            plot_data[0][1].append(block["transaction"]["total_down"] /
                                   self.byte_scale)
            num_bandwidth_blocks += 1

        if num_bandwidth_blocks == 0:
            # Create on single data point with 0mb up and 0mb down
            plot_data = [[[0], [0]], [datetime.datetime.now()]]

        self.trust_plot.plot_data = plot_data
        self.trust_plot.compute_initial_figure()
コード例 #55
0
ファイル: marketwalletspage.py プロジェクト: xemasiv/tribler
class MarketWalletsPage(QWidget):
    """
    This page displays information about wallets.
    """
    def __init__(self):
        QWidget.__init__(self)
        self.request_mgr = None
        self.initialized = False
        self.wallets_to_create = []
        self.wallets = None
        self.active_wallet = None
        self.dialog = None

    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().wallet_paypal_overview_button.clicked.connect(
                lambda: self.initialize_wallet_info(
                    'PP',
                    self.window().wallet_paypal_overview_button))
            self.window().wallet_abn_overview_button.clicked.connect(
                lambda: self.initialize_wallet_info(
                    'ABNA',
                    self.window().wallet_abn_overview_button))
            self.window().wallet_rabo_overview_button.clicked.connect(
                lambda: self.initialize_wallet_info(
                    'RABO',
                    self.window().wallet_rabo_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()

    def load_wallets(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("wallets", self.on_wallets)

    def on_wallets(self, wallets):
        self.wallets = wallets["wallets"]

        if 'MB' in self.wallets and self.wallets["MB"]["created"]:
            self.window().wallet_mc_overview_button.show()

        if 'BTC' in self.wallets and self.wallets["BTC"]["created"]:
            self.window().wallet_btc_overview_button.show()

        if 'TBTC' in self.wallets and self.wallets["TBTC"]["created"]:
            self.window().wallet_tbtc_overview_button.show()

        if 'PP' in self.wallets and self.wallets["PP"]["created"]:
            self.window().wallet_paypal_overview_button.show()

        if 'ABNA' in self.wallets and self.wallets["ABNA"]["created"]:
            self.window().wallet_abn_overview_button.show()

        if 'RABO' in self.wallets and self.wallets["RABO"]["created"]:
            self.window().wallet_rabo_overview_button.show()

        # Find out which wallets we still can create
        self.wallets_to_create = []
        for identifier, wallet in self.wallets.iteritems():
            if not wallet["created"]:
                self.wallets_to_create.append(identifier)

        if len(self.wallets_to_create) > 0:
            self.window().add_wallet_button.setEnabled(True)
        else:
            self.window().add_wallet_button.hide()

    def tab_changed(self, index):
        if index == 1 and self.active_wallet:
            self.load_transactions(self.active_wallet)

    def initialize_wallet_info(self, wallet_id, pressed_button):
        # Show the tab again
        self.window().wallet_info_tabs.show()
        self.window().wallet_management_placeholder_widget.hide()

        # Clear the selection of all other buttons, except the pressed button
        for button in self.window().wallet_buttons_container.findChildren(
                QPushButton):
            if button != pressed_button:
                button.setChecked(False)

        self.active_wallet = wallet_id
        self.window().wallet_info_tabs.setCurrentIndex(0)
        self.window().wallet_address_label.setText(
            self.wallets[wallet_id]['address'])

        # Create a QR code of the wallet address
        try:
            import qrcode
            qr = qrcode.QRCode(
                version=1,
                error_correction=qrcode.constants.ERROR_CORRECT_M,
                box_size=10,
                border=5,
            )
            qr.add_data(self.wallets[wallet_id]['address'])
            qr.make(fit=True)

            img = qr.make_image()  # PIL format

            qim = ImageQt(img)
            pixmap = QtGui.QPixmap.fromImage(qim).scaled(
                300, 300, QtCore.Qt.KeepAspectRatio)
            self.window().wallet_address_qr_label.setPixmap(pixmap)
        except ImportError:
            self.window().wallet_address_qr_label.setText(
                "QR Code functionality not available!")

    def load_transactions(self, wallet_id):
        self.window().wallet_transactions_list.clear()
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("wallets/%s/transactions" % wallet_id,
                                         self.on_transactions)

    def on_transactions(self, transactions):
        for transaction in transactions["transactions"]:
            item = QTreeWidgetItem(self.window().wallet_transactions_list)
            item.setText(0, "Sent" if transaction["outgoing"] else "Received")
            item.setText(1, transaction["from"])
            item.setText(2, transaction["to"])
            item.setText(
                3, "%g %s" % (transaction["amount"], transaction["currency"]))
            item.setText(
                4,
                "%g %s" % (transaction["fee_amount"], transaction["currency"]))
            item.setText(5, transaction["id"])
            timestamp = timestamp_to_time(
                float(transaction["timestamp"]
                      )) if transaction["timestamp"] != "False" else "-"
            item.setText(6, timestamp)
            self.window().wallet_transactions_list.addTopLevelItem(item)

    def on_add_wallet_clicked(self):
        menu = TriblerActionMenu(self)

        for wallet_id in self.wallets_to_create:
            wallet_action = QAction(self.wallets[wallet_id]['name'], self)
            wallet_action.triggered.connect(
                lambda _, wid=wallet_id: self.should_create_wallet(wid))
            menu.addAction(wallet_action)

        menu.exec_(QCursor.pos())

    def should_create_wallet(self, wallet_id):
        if wallet_id == 'BTC' or wallet_id == 'TBTC':
            self.dialog = ConfirmationDialog(
                self,
                "Create Bitcoin wallet",
                "Please enter the password of your Bitcoin wallet below:",
                [('CREATE', BUTTON_TYPE_NORMAL),
                 ('CANCEL', BUTTON_TYPE_CONFIRM)],
                show_input=True)
            self.dialog.dialog_widget.dialog_input.setPlaceholderText(
                'Wallet password')
            self.dialog.button_clicked.connect(
                lambda action: self.on_create_btc_wallet_dialog_done(
                    action, wallet_id))
            self.dialog.show()
        else:
            self.request_mgr = TriblerRequestManager()
            self.request_mgr.perform_request("wallets/%s" % wallet_id,
                                             self.on_wallet_created,
                                             method='PUT',
                                             data='')

    def on_create_btc_wallet_dialog_done(self, action, wallet_id):
        password = self.dialog.dialog_widget.dialog_input.text()

        if action == 1:  # Remove the dialog right now
            self.dialog.close_dialog()
            self.dialog = None
        elif action == 0:
            self.dialog.buttons[0].setEnabled(False)
            self.dialog.buttons[1].setEnabled(False)
            self.dialog.buttons[0].setText("CREATING...")
            self.request_mgr = TriblerRequestManager()
            post_data = str("password=%s" % password)
            self.request_mgr.perform_request("wallets/%s" % wallet_id,
                                             self.on_wallet_created,
                                             method='PUT',
                                             data=post_data)

    def on_wallet_created(self, response):
        if self.dialog:
            self.dialog.close_dialog()
            self.dialog = None
        self.load_wallets()
コード例 #56
0
class TriblerWindow(QMainWindow):

    resize_event = pyqtSignal()
    escape_pressed = pyqtSignal()
    received_search_completions = pyqtSignal(object)

    def on_exception(self, *exc_info):
        # Stop the download loop
        self.downloads_page.stop_loading_downloads()

        # Add info about whether we are stopping Tribler or not
        os.environ['TRIBLER_SHUTTING_DOWN'] = str(
            self.core_manager.shutting_down)

        if not self.core_manager.shutting_down:
            self.core_manager.stop(stop_app_on_shutdown=False)

        self.setHidden(True)

        if self.debug_window:
            self.debug_window.setHidden(True)

        exception_text = "".join(traceback.format_exception(*exc_info))
        logging.error(exception_text)

        if not self.feedback_dialog_is_open:
            dialog = FeedbackDialog(
                self, exception_text,
                self.core_manager.events_manager.tribler_version,
                self.start_time)
            self.feedback_dialog_is_open = True
            _ = dialog.exec_()

    def __init__(self):
        QMainWindow.__init__(self)

        self.navigation_stack = []
        self.feedback_dialog_is_open = False
        self.tribler_started = False
        self.tribler_settings = None
        self.debug_window = None
        self.core_manager = CoreManager()
        self.pending_requests = {}
        self.pending_uri_requests = []
        self.download_uri = None
        self.dialog = None
        self.start_download_dialog_active = False
        self.request_mgr = None
        self.search_request_mgr = None
        self.search_suggestion_mgr = None
        self.selected_torrent_files = []
        self.vlc_available = True
        self.has_search_results = False
        self.start_time = time.time()

        sys.excepthook = self.on_exception

        uic.loadUi(get_ui_file_path('mainwindow.ui'), self)
        TriblerRequestManager.window = self
        self.tribler_status_bar.hide()

        self.magnet_handler = MagnetHandler(self.window)
        QDesktopServices.setUrlHandler("magnet", self.magnet_handler,
                                       "on_open_magnet_link")

        QCoreApplication.setOrganizationDomain("nl")
        QCoreApplication.setOrganizationName("TUDelft")
        QCoreApplication.setApplicationName("Tribler")
        QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)

        self.read_settings()

        # 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_home, self.left_menu_button_search,
            self.left_menu_button_my_channel,
            self.left_menu_button_subscriptions,
            self.left_menu_button_video_player,
            self.left_menu_button_downloads, self.left_menu_button_discovered
        ]

        self.video_player_page.initialize_player()
        self.search_results_page.initialize_search_results_page()
        self.settings_page.initialize_settings_page()
        self.subscribed_channels_page.initialize()
        self.edit_channel_page.initialize_edit_channel_page()
        self.downloads_page.initialize_downloads_page()
        self.home_page.initialize_home_page()
        self.loading_page.initialize_loading_page()
        self.discovering_page.initialize_discovering_page()
        self.discovered_page.initialize_discovered_page()
        self.trust_page.initialize_trust_page()

        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)

        self.hide_left_menu_playlist()
        self.left_menu_button_debug.setHidden(True)
        self.top_menu_button.setHidden(True)
        self.left_menu.setHidden(True)
        self.trust_button.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))

        self.core_manager.start()

        self.core_manager.events_manager.received_search_result_channel.connect(
            self.search_results_page.received_search_result_channel)
        self.core_manager.events_manager.received_search_result_torrent.connect(
            self.search_results_page.received_search_result_torrent)
        self.core_manager.events_manager.torrent_finished.connect(
            self.on_torrent_finished)
        self.core_manager.events_manager.new_version_available.connect(
            self.on_new_version_available)
        self.core_manager.events_manager.tribler_started.connect(
            self.on_tribler_started)

        # Install signal handler for ctrl+c events
        def sigint_handler(*_):
            self.close_tribler()

        signal.signal(signal.SIGINT, sigint_handler)

        self.installEventFilter(self.video_player_page)

        self.show()

    def update_tray_icon(self, use_monochrome_icon):
        if not QSystemTrayIcon.isSystemTrayAvailable():
            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 on_torrent_finished(self, torrent_info):
        if QSystemTrayIcon.isSystemTrayAvailable():
            self.window().tray_icon.showMessage(
                "Download finished",
                "Download of %s has finished." % torrent_info["name"])

    def show_loading_screen(self):
        self.top_menu_button.setHidden(True)
        self.left_menu.setHidden(True)
        self.trust_button.setHidden(True)
        self.settings_button.setHidden(True)
        self.add_torrent_button.setHidden(True)
        self.top_search_bar.setHidden(True)
        self.stackedWidget.setCurrentIndex(PAGE_LOADING)

    def on_tribler_started(self):
        self.tribler_started = True

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

        # fetch the settings, needed for the video player port
        self.request_mgr = TriblerRequestManager()
        self.fetch_settings()

        self.downloads_page.start_loading_downloads()
        self.home_page.load_popular_torrents()
        if not self.gui_settings.value(
                "first_discover",
                False) and not self.core_manager.use_existing_core:
            self.window().gui_settings.setValue("first_discover", True)
            self.discovering_page.is_discovering = True
            self.stackedWidget.setCurrentIndex(PAGE_DISCOVERING)
        else:
            self.clicked_menu_button_home()

    def show_status_bar(self, message):
        self.tribler_status_bar_label.setText(message)
        self.tribler_status_bar.show()

    def hide_status_bar(self):
        self.tribler_status_bar.hide()

    def process_uri_request(self):
        """
        Process a URI request if we have one in the queue.
        """
        if len(self.pending_uri_requests) == 0:
            return

        uri = self.pending_uri_requests.pop()
        if uri.startswith('file') or uri.startswith('magnet'):
            self.start_download_from_uri(uri)

    def perform_start_download_request(self,
                                       uri,
                                       anon_download,
                                       safe_seeding,
                                       destination,
                                       selected_files,
                                       total_files=0,
                                       callback=None):
        selected_files_uri = ""
        if len(selected_files) != total_files:  # Not all files included
            selected_files_uri = u'&' + u''.join(
                u"selected_files[]=%s&" % file for file in selected_files)[:-1]

        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=%s&anon_hops=%d&safe_seeding=%d&destination=%s%s" % (
            uri, anon_hops, safe_seeding, destination, selected_files_uri)
        post_data = post_data.encode(
            'utf-8')  # We need to send bytes in the request, not unicode

        request_mgr = TriblerRequestManager()
        self.pending_requests[request_mgr.request_id] = request_mgr
        request_mgr.perform_request(
            "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 []
        encoded_destination = destination.encode('hex')
        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 on_new_version_available(self, version):
        if version == str(self.gui_settings.value('last_reported_version')):
            return

        self.dialog = ConfirmationDialog(
            self, "New version available",
            "Version %s of Tribler is available.Do you want to visit the website to "
            "download the newest version?" % version,
            [('IGNORE', BUTTON_TYPE_NORMAL), ('LATER', BUTTON_TYPE_NORMAL),
             ('OK', BUTTON_TYPE_NORMAL)])
        self.dialog.button_clicked.connect(
            lambda action: self.on_new_version_dialog_done(version, action))
        self.dialog.show()

    def on_new_version_dialog_done(self, version, action):
        if action == 0:  # ignore
            self.gui_settings.setValue("last_reported_version", version)
        elif action == 2:  # ok
            import webbrowser
            webbrowser.open("https://tribler.org")

        self.dialog.setParent(None)
        self.dialog = None

    def read_settings(self):
        self.gui_settings = QSettings()
        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)

    def on_search_text_change(self, text):
        self.search_suggestion_mgr = TriblerRequestManager()
        self.search_suggestion_mgr.perform_request(
            "search/completions?q=%s" % text,
            self.on_received_search_completions)

    def on_received_search_completions(self, completions):
        self.received_search_completions.emit(completions)
        self.search_completion_model.setStringList(completions["completions"])

    def fetch_settings(self):
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request("settings",
                                         self.received_settings,
                                         capture_errors=False)

    def received_settings(self, settings):
        # If we cannot receive the settings, stop Tribler with an option to send the crash report.
        if 'error' in settings:
            raise RuntimeError(
                TriblerRequestManager.get_message_from_error(settings))
        else:
            self.tribler_settings = settings['settings']

        # Disable various components based on the settings
        if not self.tribler_settings['search_community']['enabled']:
            self.window().top_search_bar.setHidden(True)
        if not self.tribler_settings['video_server']['enabled']:
            self.left_menu_button_video_player.setHidden(True)

        # Set the video server port
        self.video_player_page.video_player_port = self.tribler_settings[
            "video_server"]["port"]

        # process pending file requests (i.e. someone clicked a torrent file when Tribler was closed)
        # We do this after receiving the settings so we have the default download location.
        self.process_uri_request()

    def on_top_search_button_click(self):
        self.left_menu_button_search.setChecked(True)
        self.has_search_results = True
        self.clicked_menu_button_search()
        self.search_results_page.perform_search(self.top_search_bar.text())
        self.search_request_mgr = TriblerRequestManager()
        self.search_request_mgr.perform_request(
            "search?q=%s" % self.top_search_bar.text(), None)

    def on_settings_button_click(self):
        self.deselect_all_menu_buttons()
        self.stackedWidget.setCurrentIndex(PAGE_SETTINGS)
        self.settings_page.load_settings()
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def on_trust_button_click(self):
        self.deselect_all_menu_buttons()
        self.stackedWidget.setCurrentIndex(PAGE_TRUST)
        self.trust_page.load_trust_statistics()
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def on_add_torrent_button_click(self, pos):
        menu = TriblerActionMenu(self)

        browse_files_action = QAction('Import torrent from file', self)
        browse_directory_action = QAction('Import torrents from directory',
                                          self)
        add_url_action = QAction('Import torrent from magnet/URL', self)

        browse_files_action.triggered.connect(self.on_add_torrent_browse_file)
        browse_directory_action.triggered.connect(
            self.on_add_torrent_browse_dir)
        add_url_action.triggered.connect(self.on_add_torrent_from_url)

        menu.addAction(browse_files_action)
        menu.addAction(browse_directory_action)
        menu.addAction(add_url_action)

        menu.exec_(self.mapToGlobal(self.add_torrent_button.pos()))

    def on_add_torrent_browse_file(self):
        filenames = QFileDialog.getOpenFileNames(
            self, "Please select the .torrent file", "",
            "Torrent files (*.torrent)")
        if len(filenames[0]) > 0:
            [
                self.pending_uri_requests.append(u"file:%s" % filename)
                for filename in filenames[0]
            ]
            self.process_uri_request()

    def start_download_from_uri(self, uri):
        self.download_uri = uri

        if get_gui_setting(self.gui_settings,
                           "ask_download_settings",
                           True,
                           is_bool=True):
            self.dialog = StartDownloadDialog(self.window().stackedWidget,
                                              self.download_uri)
            self.dialog.button_clicked.connect(self.on_start_download_action)
            self.dialog.show()
            self.start_download_dialog_active = True
        else:
            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'], [], 0)
            self.process_uri_request()

    def on_start_download_action(self, action):
        if action == 1:
            self.window().perform_start_download_request(
                self.download_uri,
                self.dialog.dialog_widget.anon_download_checkbox.isChecked(),
                self.dialog.dialog_widget.safe_seed_checkbox.isChecked(),
                self.dialog.dialog_widget.destination_input.currentText(),
                self.dialog.get_selected_files(),
                self.dialog.dialog_widget.files_list_view.topLevelItemCount())

        self.dialog.request_mgr.cancel_request(
        )  # To abort the torrent info request
        self.dialog.setParent(None)
        self.dialog = None
        self.start_download_dialog_active = False

        if action == 0:  # We do this after removing the dialog since process_uri_request is blocking
            self.process_uri_request()

    def on_add_torrent_browse_dir(self):
        chosen_dir = QFileDialog.getExistingDirectory(
            self, "Please select the directory containing the .torrent files",
            "", QFileDialog.ShowDirsOnly)

        if len(chosen_dir) != 0:
            self.selected_torrent_files = [
                torrent_file
                for torrent_file in glob.glob(chosen_dir + "/*.torrent")
            ]
            self.dialog = ConfirmationDialog(
                self, "Add torrents from directory",
                "Are you sure you want to add %d torrents to Tribler?" %
                len(self.selected_torrent_files),
                [('ADD', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)])
            self.dialog.button_clicked.connect(
                self.on_confirm_add_directory_dialog)
            self.dialog.show()

    def on_confirm_add_directory_dialog(self, action):
        if action == 0:
            for torrent_file in self.selected_torrent_files:
                escaped_uri = quote_plus(
                    (u"file:%s" % torrent_file).encode('utf-8'))
                self.perform_start_download_request(
                    escaped_uri,
                    self.window().tribler_settings['download_defaults']
                    ['anonymity_enabled'],
                    self.window().tribler_settings['download_defaults']
                    ['safeseeding_enabled'],
                    self.tribler_settings['download_defaults']['saveas'], [],
                    0)

        self.dialog.setParent(None)
        self.dialog = None

    def on_add_torrent_from_url(self):
        self.dialog = ConfirmationDialog(
            self,
            "Add torrent from URL/magnet link",
            "Please enter the URL/magnet link in the field below:",
            [('ADD', BUTTON_TYPE_NORMAL), ('CANCEL', BUTTON_TYPE_CONFIRM)],
            show_input=True)
        self.dialog.dialog_widget.dialog_input.setPlaceholderText(
            'URL/magnet link')
        self.dialog.dialog_widget.dialog_input.setFocus()
        self.dialog.button_clicked.connect(
            self.on_torrent_from_url_dialog_done)
        self.dialog.show()

    def on_torrent_from_url_dialog_done(self, action):
        uri = self.dialog.dialog_widget.dialog_input.text()

        # Remove first dialog
        self.dialog.setParent(None)
        self.dialog = None

        if action == 0:
            self.start_download_from_uri(uri)

    def on_download_added(self, result):
        if len(self.pending_uri_requests
               ) == 0:  # Otherwise, we first process the remaining requests.
            self.window().left_menu_button_downloads.click()
        else:
            self.process_uri_request()

    def on_top_menu_button_click(self):
        if self.left_menu.isHidden():
            self.left_menu.show()
        else:
            self.left_menu.hide()

    def deselect_all_menu_buttons(self, except_select=None):
        for button in self.menu_buttons:
            if button == except_select:
                button.setEnabled(False)
                continue
            button.setEnabled(True)

            if button == self.left_menu_button_search and not self.has_search_results:
                button.setEnabled(False)

            button.setChecked(False)

    def clicked_menu_button_home(self):
        self.deselect_all_menu_buttons(self.left_menu_button_home)
        self.stackedWidget.setCurrentIndex(PAGE_HOME)
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def clicked_menu_button_search(self):
        self.deselect_all_menu_buttons(self.left_menu_button_search)
        self.stackedWidget.setCurrentIndex(PAGE_SEARCH_RESULTS)
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def clicked_menu_button_discovered(self):
        self.deselect_all_menu_buttons(self.left_menu_button_discovered)
        self.stackedWidget.setCurrentIndex(PAGE_DISCOVERED)
        self.discovered_page.load_discovered_channels()
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def clicked_menu_button_my_channel(self):
        self.deselect_all_menu_buttons(self.left_menu_button_my_channel)
        self.stackedWidget.setCurrentIndex(PAGE_EDIT_CHANNEL)
        self.edit_channel_page.load_my_channel_overview()
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def clicked_menu_button_video_player(self):
        self.deselect_all_menu_buttons(self.left_menu_button_video_player)
        self.stackedWidget.setCurrentIndex(PAGE_VIDEO_PLAYER)
        self.navigation_stack = []
        self.show_left_menu_playlist()

    def clicked_menu_button_downloads(self):
        self.deselect_all_menu_buttons(self.left_menu_button_downloads)
        self.stackedWidget.setCurrentIndex(PAGE_DOWNLOADS)
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def clicked_menu_button_debug(self):
        self.debug_window = DebugWindow(self.tribler_settings)
        self.debug_window.show()

    def clicked_menu_button_subscriptions(self):
        self.deselect_all_menu_buttons(self.left_menu_button_subscriptions)
        self.subscribed_channels_page.load_subscribed_channels()
        self.stackedWidget.setCurrentIndex(PAGE_SUBSCRIBED_CHANNELS)
        self.navigation_stack = []
        self.hide_left_menu_playlist()

    def hide_left_menu_playlist(self):
        self.left_menu_seperator.setHidden(True)
        self.left_menu_playlist_label.setHidden(True)
        self.left_menu_playlist.setHidden(True)

    def show_left_menu_playlist(self):
        self.left_menu_seperator.setHidden(False)
        self.left_menu_playlist_label.setHidden(False)
        self.left_menu_playlist.setHidden(False)

    def on_channel_item_click(self, channel_list_item):
        list_widget = channel_list_item.listWidget()
        from TriblerGUI.widgets.channel_list_item import ChannelListItem
        if isinstance(list_widget.itemWidget(channel_list_item),
                      ChannelListItem):
            channel_info = channel_list_item.data(Qt.UserRole)
            self.channel_page.initialize_with_channel(channel_info)
            self.navigation_stack.append(self.stackedWidget.currentIndex())
            self.stackedWidget.setCurrentIndex(PAGE_CHANNEL_DETAILS)

    def on_playlist_item_click(self, playlist_list_item):
        list_widget = playlist_list_item.listWidget()
        from TriblerGUI.widgets.playlist_list_item import PlaylistListItem
        if isinstance(list_widget.itemWidget(playlist_list_item),
                      PlaylistListItem):
            playlist_info = playlist_list_item.data(Qt.UserRole)
            self.playlist_page.initialize_with_playlist(playlist_info)
            self.navigation_stack.append(self.stackedWidget.currentIndex())
            self.stackedWidget.setCurrentIndex(PAGE_PLAYLIST_DETAILS)

    def on_page_back_clicked(self):
        prev_page = self.navigation_stack.pop()
        self.stackedWidget.setCurrentIndex(prev_page)

    def on_edit_channel_clicked(self):
        self.stackedWidget.setCurrentIndex(PAGE_EDIT_CHANNEL)
        self.navigation_stack = []
        self.channel_page.on_edit_channel_clicked()

    def resizeEvent(self, _):
        # Resize home page cells
        cell_width = self.home_page_table_view.width(
        ) / 3 - 3  # We have some padding to the right
        cell_height = cell_width / 2 + 60

        for i in range(0, 3):
            self.home_page_table_view.setColumnWidth(i, cell_width)
            self.home_page_table_view.setRowHeight(i, cell_height)
        self.resize_event.emit()

    def exit_full_screen(self):
        self.top_bar.show()
        self.left_menu.show()
        self.video_player_page.is_full_screen = False
        self.showNormal()

    def close_tribler(self):
        if not self.core_manager.shutting_down:
            self.show_loading_screen()

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

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

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

    def closeEvent(self, close_event):
        self.close_tribler()
        close_event.ignore()

    def keyReleaseEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.escape_pressed.emit()
            if self.isFullScreen():
                self.exit_full_screen()
コード例 #57
0
class TriblerTableViewController(object):
    """
    Base controller for a table view that displays some data.
    """

    def __init__(self, model, table_view):
        self.model = model
        self.model.on_sort.connect(self._on_view_sort)
        self.table_view = table_view
        self.table_view.setModel(self.model)
        self.table_view.verticalScrollBar().valueChanged.connect(self._on_list_scroll)
        self.query_text = ''
        self.num_results_label = None
        self.request_mgr = None
        self.query_uuid = None

    def _on_view_sort(self, column, ascending):
        self.model.reset()
        self.perform_query(first=1, last=50)

    def _on_list_scroll(self, event):
        if self.table_view.verticalScrollBar().value() == self.table_view.verticalScrollBar().maximum() and \
                self.model.data_items:  # workaround for duplicate calls to _on_list_scroll on view creation
            self.perform_query()

    def _get_sort_parameters(self):
        """
        Return a tuple (column_name, sort_asc) that indicates the sorting column/order of the table view.
        """
        sort_by = self.model.columns[self.table_view.horizontalHeader().sortIndicatorSection()]
        sort_asc = self.table_view.horizontalHeader().sortIndicatorOrder()
        return sort_by, sort_asc

    def perform_query(self, **kwargs):
        """
        Fetch results for a given query.
        """
        if 'first' not in kwargs or 'last' not in kwargs:
            kwargs["first"], kwargs[
                'last'] = self.model.rowCount() + 1, self.model.rowCount() + self.model.item_load_batch

        # Create a new uuid for each new search
        if kwargs['first'] == 1 or not self.query_uuid:
            self.query_uuid = uuid.uuid4().hex

        sort_by, sort_asc = self._get_sort_parameters()
        kwargs.update({
            "uuid": self.query_uuid,
            "filter": to_fts_query(self.query_text),
            "sort_by": sort_by,
            "sort_asc": sort_asc,
            "hide_xxx": self.model.hide_xxx})

        rest_endpoint_url = kwargs.pop("rest_endpoint_url")
        self.request_mgr = TriblerRequestManager()
        self.request_mgr.perform_request(rest_endpoint_url,
                                         self.on_query_results,
                                         url_params=kwargs)

    def on_query_results(self, response, remote=False):
        """
        Updates the table with the response.
        :param response: List of the items to be added to the model
        :param remote: True if response is from a remote peer. Default: False
        :return: None
        """
        if not response:
            return False
        if self.is_new_result(response):
            self.model.add_items(response['results'], remote=remote)
        self.model.total_items = len(self.model.data_items)
        if self.num_results_label:
            self.num_results_label.setText("%d results" % self.model.total_items)
        return True

    def is_new_result(self, response):
        """
        Returns True if the response is a new fresh response else False.
        - If UUID of the response and the last query does not match, then it is a stale response.
        - If the response has info about pagination, here 'first' field, if the value of the first field is less than
        the number of results already present, then the response is stale.
        :param response: List of items
        :return: True for fresh response else False
        """
        if 'uuid' in response and response['uuid'] != self.query_uuid:
            return False
        if 'first' in response and response['first'] < self.model.rowCount():
            return False
        return True