class DialogMirror(QDialog):

  def __init__(self, parent, datadir, distro, custom_mirrors):
    """
    Initialize the dialog that allows to choose a custom or official mirror
    """
    QDialog.__init__(self, parent)
    uic.loadUi("%s/designer/dialog_mirror.ui" % datadir, self)
    self.parent = parent

    self.custom_mirrors = custom_mirrors

    self.country_info = CountryInformation()

    self.button_choose = self.buttonBox.button(QDialogButtonBox.Ok)
    self.button_choose.setEnabled(False)
    self.button_cancel = self.buttonBox.button(QDialogButtonBox.Cancel)
    self.distro = distro

    self.treeview.setColumnCount(1)
    self.treeview.setHeaderLabels([utf8(_("Mirror"))])

    translate_widget(self)
    # used to find the corresponding iter of a location
    map_loc = {}
    patriot = None
    """ no custom yet
    # at first add all custom mirrors and a separator
    if len(self.custom_mirrors) > 0:
        for mirror in self.custom_mirrors:

            model.append(None, [mirror, False, True, None])
            self.column_mirror.add_attribute(self.renderer_mirror, 
                                             "editable", 
                                             COLUMN_CUSTOM)
        model.append(None, [None, True, False, None])
    """
    self.mirror_map = {}
    # secondly add all official mirrors
    for hostname in self.distro.source_template.mirror_set.keys():
        mirror = self.distro.source_template.mirror_set[hostname]
        if map_loc.has_key(mirror.location):  # a mirror in a country
            QTreeWidgetItem(map_loc[mirror.location], [hostname])
            self.mirror_map[hostname] = mirror
        elif mirror.location != None:  # a country new to the list
            country = utf8(self.country_info.get_country_name(mirror.location))
            parent = QTreeWidgetItem([country])
            self.mirror_map[country] = None
            self.treeview.addTopLevelItem(parent)
            QTreeWidgetItem(parent, [hostname])
            self.mirror_map[hostname] = mirror
            if mirror.location == self.country_info.code and patriot == None:
                patriot = parent
            map_loc[mirror.location] = parent
        else:  # a mirror without country
            item = QTreeWidgetItem([hostname])
            self.treeview.addTopLevelItem(item)
    self.treeview.sortItems(0, Qt.AscendingOrder)
    # Scroll to the local mirror set
    if patriot != None:
        self.select_mirror(patriot.text(0))
    self.connect(self.treeview, SIGNAL("itemClicked(QTreeWidgetItem*, int)"), self.on_treeview_mirrors_cursor_changed)
    self.connect(self.button_find_server, SIGNAL("clicked()"), self.on_button_test_clicked)
    self.edit_buttons_frame.hide()  ##FIXME not yet implemented

  def on_treeview_mirrors_cursor_changed(self, item, column):
    """ Check if the currently selected row in the mirror list
        contains a mirror and or is editable """
    # Update the list of available protocolls
    hostname = unicode(self.treeview.currentItem().text(0))
    mirror = self.mirror_map[hostname]
    self.combobox.clear()
    if mirror != None:
        self.combobox.setEnabled(True)
        seen_protos = []
        self.protocol_paths = {}
        for repo in mirror.repositories:
            # Only add a repository for a protocoll once
            if repo.proto in seen_protos:
                continue
            seen_protos.append(repo.proto)
            self.protocol_paths[repo.get_info()[0]] = repo.get_info()[1]
            self.combobox.addItem(repo.get_info()[0])
        self.button_choose.setEnabled(True)
    else:
        self.button_choose.setEnabled(False)
    """
        # Allow to edit and remove custom mirrors
        self.button_remove.set_sensitive(model.get_value(iter, COLUMN_CUSTOM))
        self.button_edit.set_sensitive(model.get_value(iter, COLUMN_CUSTOM))
        self.button_choose.set_sensitive(self.is_valid_mirror(model.get_value(iter, COLUMN_URI)))
        self.combobox.set_sensitive(False)

    """

  def run(self):
    """ Run the chooser dialog and return the chosen mirror or None """
    res = self.exec_()

    # FIXME: we should also return the list of custom servers
    if res == QDialog.Accepted:
        hostname = unicode(self.treeview.currentItem().text(0))
        mirror = self.mirror_map[hostname]

        if mirror == None:
            # Return the URL of the selected custom mirror
            print "Error, unknown mirror"
            return None
            ##FIXME return model.get_value(iter, COLUMN_URI)
        else:
            # Return a URL created from the hostname and the selected
            # repository
            proto = unicode(self.combobox.currentText())

            directory = self.protocol_paths[proto]
            return "%s://%s/%s" % (proto, mirror.hostname, directory)
    else:
        return None

  def on_button_test_clicked(self):
    ''' Perform a test to find the best mirror and select it 
        afterwards in the treeview '''
    class MirrorTestKDE(MirrorTest):
        def __init__(self, mirrors, test_file, running, dialog, parent):
            MirrorTest.__init__(self, mirrors, test_file, running)
            self.dialog = dialog
            self.parent = parent

        def report_action(self, text):
            if self.running.isSet():
                self.parent.emit(SIGNAL("report_action(QString*)"), text)

        def report_progress(self, current, max, borders=(0,1), mod=(0,0)):
            if self.running.isSet():
                self.parent.emit(SIGNAL("report_progress(int, int, PyQt_PyObject, PyQt_PyObject)"),
                                   current, max, borders, mod)

        def run(self):
            self.parent.emit(SIGNAL("test_start()"))
            rocker = self.run_full_test()
            self.parent.emit(SIGNAL("test_end(QString*)"), rocker)

    self.dialog = QProgressDialog(utf8(_("Testing Mirrors")), utf8(_("Cancel")), 0, 100, self)
    self.dialog.setWindowTitle(utf8(_("Testing Mirrors")))
    self.dialog.setWindowModality(Qt.WindowModal)
    self.button_cancel_test = QPushButton(utf8(_("Cancel")), self.dialog)
    self.dialog.setCancelButton(self.button_cancel_test)
    self.connect(self.button_cancel_test, SIGNAL("clicked()"), self.on_button_cancel_test_clicked);
    # the following signals are connected across threads
    self.connect(self, SIGNAL("test_start()"), self.on_test_start, Qt.BlockingQueuedConnection)
    self.connect(self, SIGNAL("test_end(QString*)"), self.on_test_end, Qt.BlockingQueuedConnection)
    self.connect(self, SIGNAL("report_progress(int, int, PyQt_PyObject, PyQt_PyObject)"), self.on_report_progress, Qt.BlockingQueuedConnection)
    self.connect(self, SIGNAL("report_action(QString*)"), self.on_report_action, Qt.BlockingQueuedConnection)

    self.running = threading.Event()
    self.running.set()
    pipe = os.popen("dpkg --print-architecture")
    arch = pipe.read().strip()
    test_file = "dists/%s/%s/binary-%s/Packages.gz" % \
                 (self.distro.source_template.name,
                  self.distro.source_template.components[0].name,
                  arch)
    test = MirrorTestKDE(self.distro.source_template.mirror_set.values(),
                         test_file, self.running, self.dialog, self)
    test.start() # test starts in a separate thread

  def on_test_start(self):
      self.dialog.show()

  def on_test_end(self, mirror):
      self.dialog.hide()
      if not self.running.isSet():
          return # canceled by user
      if mirror != None:
          self.select_mirror(mirror)
      else:
          QMessageBox.warning(self.dialog, utf8(_("Testing Mirrors")),
                                  utf8(_("No suitable download server was found")) + "\n" +
                                  utf8(_("Please check your Internet connection.")))

  def on_report_action(self, text):
      self.dialog.setLabelText(str("<i>%s</i>" % text))

  def on_report_progress(self, current, max, borders=(0,1), mod=(0,0)):
      #self.dialog.setLabelText(utf8(_("Completed %s of %s tests")) % \
      #                       (current + mod[0], max + mod[1]))
      frac = borders[0] + (borders[1] - borders[0]) / max * current
      self.dialog.setValue(frac*100)

  def on_button_cancel_test_clicked(self):
    ''' Abort the mirror performance test '''
    self.running.clear()
    self.dialog.show()
    self.dialog.setLabelText("<i>%s</i>" % utf8(_("Canceling...")))
    self.button_cancel_test.setEnabled(False)
    self.dialog.setValue(100)

  def select_mirror(self, mirror):
    """Select and expand the path to a matching mirror in the list"""
    found = self.treeview.findItems(QString(mirror), Qt.MatchExactly|Qt.MatchRecursive)
    if found:
      found[0].setSelected(True)
      self.treeview.setCurrentItem(found[0])
      self.treeview.scrollToItem(found[0], QAbstractItemView.PositionAtCenter)
      self.on_treeview_mirrors_cursor_changed(found[0], 0)
      self.button_choose.setFocus()
      return True
  def __init__(self, parent, datadir, distro, custom_mirrors):
    """
    Initialize the dialog that allows to choose a custom or official mirror
    """
    QDialog.__init__(self, parent)
    uic.loadUi("%s/designer/dialog_mirror.ui" % datadir, self)
    self.parent = parent

    self.custom_mirrors = custom_mirrors

    self.country_info = CountryInformation()

    self.button_choose = self.buttonBox.button(QDialogButtonBox.Ok)
    self.button_choose.setEnabled(False)
    self.button_cancel = self.buttonBox.button(QDialogButtonBox.Cancel)
    self.distro = distro

    self.treeview.setColumnCount(1)
    self.treeview.setHeaderLabels([utf8(_("Mirror"))])

    translate_widget(self)
    # used to find the corresponding iter of a location
    map_loc = {}
    patriot = None
    """ no custom yet
    # at first add all custom mirrors and a separator
    if len(self.custom_mirrors) > 0:
        for mirror in self.custom_mirrors:

            model.append(None, [mirror, False, True, None])
            self.column_mirror.add_attribute(self.renderer_mirror, 
                                             "editable", 
                                             COLUMN_CUSTOM)
        model.append(None, [None, True, False, None])
    """
    self.mirror_map = {}
    # secondly add all official mirrors
    for hostname in self.distro.source_template.mirror_set.keys():
        mirror = self.distro.source_template.mirror_set[hostname]
        if map_loc.has_key(mirror.location):  # a mirror in a country
            QTreeWidgetItem(map_loc[mirror.location], [hostname])
            self.mirror_map[hostname] = mirror
        elif mirror.location != None:  # a country new to the list
            country = utf8(self.country_info.get_country_name(mirror.location))
            parent = QTreeWidgetItem([country])
            self.mirror_map[country] = None
            self.treeview.addTopLevelItem(parent)
            QTreeWidgetItem(parent, [hostname])
            self.mirror_map[hostname] = mirror
            if mirror.location == self.country_info.code and patriot == None:
                patriot = parent
            map_loc[mirror.location] = parent
        else:  # a mirror without country
            item = QTreeWidgetItem([hostname])
            self.treeview.addTopLevelItem(item)
    self.treeview.sortItems(0, Qt.AscendingOrder)
    # Scroll to the local mirror set
    if patriot != None:
        self.select_mirror(patriot.text(0))
    self.connect(self.treeview, SIGNAL("itemClicked(QTreeWidgetItem*, int)"), self.on_treeview_mirrors_cursor_changed)
    self.connect(self.button_find_server, SIGNAL("clicked()"), self.on_button_test_clicked)
    self.edit_buttons_frame.hide()  ##FIXME not yet implemented
class DialogMirror(QDialog):
    def __init__(self, parent, datadir, distro, custom_mirrors):
        """
    Initialize the dialog that allows to choose a custom or official mirror
    """
        QDialog.__init__(self, parent)
        uic.loadUi("%s/designer/dialog_mirror.ui" % datadir, self)
        self.parent = parent

        self.custom_mirrors = custom_mirrors

        self.country_info = CountryInformation()

        self.button_choose = self.buttonBox.button(QDialogButtonBox.Ok)
        self.button_choose.setEnabled(False)
        self.button_cancel = self.buttonBox.button(QDialogButtonBox.Cancel)
        self.distro = distro

        self.treeview.setColumnCount(1)
        self.treeview.setHeaderLabels([_("Mirror")])

        # used to find the corresponding iter of a location
        map_loc = {}
        patriot = None
        """ no custom yet
    # at first add all custom mirrors and a separator
    if len(self.custom_mirrors) > 0:
        for mirror in self.custom_mirrors:

            model.append(None, [mirror, False, True, None])
            self.column_mirror.add_attribute(self.renderer_mirror, 
                                             "editable", 
                                             COLUMN_CUSTOM)
        model.append(None, [None, True, False, None])
    """
        self.mirror_map = {}
        # secondly add all official mirrors
        for hostname in self.distro.source_template.mirror_set.keys():
            mirror = self.distro.source_template.mirror_set[hostname]
            if map_loc.has_key(mirror.location):  # a mirror in a country
                QTreeWidgetItem(map_loc[mirror.location], [hostname])
                self.mirror_map[hostname] = mirror
            elif mirror.location != None:  # a country new to the list
                country = self.country_info.get_country_name(mirror.location)
                parent = QTreeWidgetItem([unicode(country, 'utf-8')])
                self.mirror_map[country] = None
                self.treeview.addTopLevelItem(parent)
                QTreeWidgetItem(parent, [hostname])
                self.mirror_map[hostname] = mirror
                if mirror.location == self.country_info.code and patriot == None:
                    patriot = parent
                map_loc[mirror.location] = parent
            else:  # a mirror without country
                item = QTreeWidgetItem([hostname])
                self.treeview.addTopLevelItem(item)
        # Scroll to the local mirror set
        if patriot != None:
            self.treeview.scrollToItem(patriot)
        self.treeview.sortItems(0, Qt.AscendingOrder)
        self.connect(self.treeview,
                     SIGNAL("itemClicked(QTreeWidgetItem*, int)"),
                     self.on_treeview_mirrors_cursor_changed)
        self.connect(self.button_find_server, SIGNAL("clicked()"),
                     self.on_button_test_clicked)
        self.edit_buttons_frame.hide()  ##FIXME not yet implemented

    def on_treeview_mirrors_cursor_changed(self, item, column):
        """ Check if the currently selected row in the mirror list
        contains a mirror and or is editable """
        # Update the list of available protocolls
        hostname = unicode(self.treeview.currentItem().text(0))
        mirror = self.mirror_map[hostname]
        self.combobox.clear()
        if mirror != None:
            self.combobox.setEnabled(True)
            seen_protos = []
            self.protocol_paths = {}
            for repo in mirror.repositories:
                # Only add a repository for a protocoll once
                if repo.proto in seen_protos:
                    continue
                seen_protos.append(repo.proto)
                self.protocol_paths[repo.get_info()[0]] = repo.get_info()[1]
                self.combobox.addItem(repo.get_info()[0])
            self.button_choose.setEnabled(True)
        else:
            self.button_choose.setEnabled(False)
        """
        # Allow to edit and remove custom mirrors
        self.button_remove.set_sensitive(model.get_value(iter, COLUMN_CUSTOM))
        self.button_edit.set_sensitive(model.get_value(iter, COLUMN_CUSTOM))
        self.button_choose.set_sensitive(self.is_valid_mirror(model.get_value(iter, COLUMN_URI)))
        self.combobox.set_sensitive(False)

    """

    def run(self):
        """ Run the chooser dialog and return the chosen mirror or None """
        res = self.exec_()

        # FIXME: we should also return the list of custom servers
        if res == QDialog.Accepted:
            text = unicode(self.treeview.currentItem().text(0))
            mirror = self.mirror_map[text]

            if mirror == None:
                # Return the URL of the selected custom mirror
                print "Error, unknown mirror"
                return None
                ##FIXME return model.get_value(iter, COLUMN_URI)
            else:
                # Return a URL created from the hostname and the selected
                # repository
                proto = unicode(self.combobox.currentText())

                directory = self.protocol_paths[proto]
                return "%s://%s/%s" % (proto, mirror.hostname, directory)
        else:
            return None

    @threaded
    def on_button_test_clicked(self):
        ''' Perform a test to find the best mirror and select it 
        afterwards in the treeview '''
        class MirrorTestGtk(MirrorTest):
            def __init__(self, mirrors, test_file, running, dialogue, parent):
                MirrorTest.__init__(self, mirrors, test_file, running)
                self.dialogue = dialogue
                self.parent = parent

            def report_action(self, text):
                ##Qt doesn't like settings text in a thread
                #gtk.gdk.threads_enter()
                #self.label.set_label(str("<i>%s</i>" % text))
                #gtk.gdk.threads_leave()
                #self.dialogue.setLabelText(str("<i>%s</i>" % text))
                self.parent.process()
                pass

            def report_progress(self, current, max, borders=(0, 1),
                                mod=(0, 0)):
                ##Qt doesn't like settings text in a thread
                #gtk.gdk.threads_enter()
                #self.progress.set_text(_("Completed %s of %s tests") % \
                #                       (current + mod[0], max + mod[1]))
                #self.dialogue.setLabelText(_("Completed %s of %s tests") % \
                #                       (current + mod[0], max + mod[1]))
                frac = borders[0] + (borders[1] - borders[0]) / max * current
                #self.progress.set_fraction(frac)
                self.dialogue.setValue(frac * 100)
                self.parent.process()
                #gtk.gdk.threads_leave()
            def run_full_test(self):
                # Determinate the 5 top ping servers
                results_ping = self.run_ping_test(max=5,
                                                  borders=(0, 0.5),
                                                  mod=(0, 7))
                # Add two random mirrors to the download test
                results_ping.append(
                    [0, 0, self.mirrors[random.randint(1, len(self.mirrors))]])
                results_ping.append(
                    [0, 0, self.mirrors[random.randint(1, len(self.mirrors))]])
                results = self.run_download_test(map(lambda r: r[2],
                                                     results_ping),
                                                 borders=(0.5, 1),
                                                 mod=(MirrorTest.todo,
                                                      MirrorTest.todo))
                for (t, h) in results:
                    print h.hostname, t
                if len(results) == 0:
                    return None
                else:
                    return results[0][1].hostname

        self.dialogue = QProgressDialog(_("Testing Mirrors"), _("Cancel"), 0,
                                        100, self)
        self.dialogue.setWindowTitle(_("Testing Mirrors"))
        self.dialogue.setWindowModality(Qt.WindowModal)
        self.cancelButton = QPushButton(_("Cancel"), self.dialogue)
        self.dialogue.setCancelButton(self.cancelButton)
        self.connect(self.cancelButton, SIGNAL("clicked()"),
                     self.progressCancelled)
        self.cancelButton.setEnabled(
            False)  ##FIXME, cancel doesn't work (because it's in a thread?)
        self.dialogue.show()

        self.running = threading.Event()
        self.running.set()
        pipe = os.popen("dpkg --print-architecture")
        arch = pipe.read().strip()
        test_file = "dists/%s/%s/binary-%s/Packages.gz" % \
                     (self.distro.source_template.name,
                      self.distro.source_template.components[0].name,
                      arch)
        test = MirrorTestGtk(self.distro.source_template.mirror_set.values(),
                             test_file, self.running, self.dialogue, self)
        test.start()
        rocker = test.run_full_test()
        self.dialogue.hide()
        # Select the mirror in the list or show an error dialog
        if rocker != None:
            self.select_mirror(rocker)
        """
    else:
        dialogs.show_error_dialog(self.dialog, 
                                  _("No suitable download server was found"),
                                  _("Please check your Internet connection."))
    """

    def progressCancelled(self):
        pass

    def process(self):
        if self.dialogue.wasCanceled():
            self.running.clear()
        app = QApplication.instance()
        app.processEvents()

    def select_mirror(self, mirror):
        """Select and expand the path to a matching mirror in the list"""
        found = self.treeview.findItems(QString(mirror),
                                        Qt.MatchExactly | Qt.MatchRecursive)
        if len(found) > 0:
            found[0].setSelected(True)
            self.treeview.scrollToItem(found[0])
            return True
    def __init__(self, parent, datadir, distro, custom_mirrors):
        """
    Initialize the dialog that allows to choose a custom or official mirror
    """
        QDialog.__init__(self, parent)
        uic.loadUi("%s/designer/dialog_mirror.ui" % datadir, self)
        self.parent = parent

        self.custom_mirrors = custom_mirrors

        self.country_info = CountryInformation()

        self.button_choose = self.buttonBox.button(QDialogButtonBox.Ok)
        self.button_choose.setEnabled(False)
        self.button_cancel = self.buttonBox.button(QDialogButtonBox.Cancel)
        self.distro = distro

        self.treeview.setColumnCount(1)
        self.treeview.setHeaderLabels([_("Mirror")])

        # used to find the corresponding iter of a location
        map_loc = {}
        patriot = None
        """ no custom yet
    # at first add all custom mirrors and a separator
    if len(self.custom_mirrors) > 0:
        for mirror in self.custom_mirrors:

            model.append(None, [mirror, False, True, None])
            self.column_mirror.add_attribute(self.renderer_mirror, 
                                             "editable", 
                                             COLUMN_CUSTOM)
        model.append(None, [None, True, False, None])
    """
        self.mirror_map = {}
        # secondly add all official mirrors
        for hostname in self.distro.source_template.mirror_set.keys():
            mirror = self.distro.source_template.mirror_set[hostname]
            if map_loc.has_key(mirror.location):  # a mirror in a country
                QTreeWidgetItem(map_loc[mirror.location], [hostname])
                self.mirror_map[hostname] = mirror
            elif mirror.location != None:  # a country new to the list
                country = self.country_info.get_country_name(mirror.location)
                parent = QTreeWidgetItem([unicode(country, 'utf-8')])
                self.mirror_map[country] = None
                self.treeview.addTopLevelItem(parent)
                QTreeWidgetItem(parent, [hostname])
                self.mirror_map[hostname] = mirror
                if mirror.location == self.country_info.code and patriot == None:
                    patriot = parent
                map_loc[mirror.location] = parent
            else:  # a mirror without country
                item = QTreeWidgetItem([hostname])
                self.treeview.addTopLevelItem(item)
        # Scroll to the local mirror set
        if patriot != None:
            self.treeview.scrollToItem(patriot)
        self.treeview.sortItems(0, Qt.AscendingOrder)
        self.connect(self.treeview,
                     SIGNAL("itemClicked(QTreeWidgetItem*, int)"),
                     self.on_treeview_mirrors_cursor_changed)
        self.connect(self.button_find_server, SIGNAL("clicked()"),
                     self.on_button_test_clicked)
        self.edit_buttons_frame.hide()  ##FIXME not yet implemented
class DialogMirror:
  def __init__(self, parent, datadir, distro, custom_mirrors):
    """
    Initialize the dialog that allows to choose a custom or official mirror
    """
    def is_separator(model, iter, data=None):
        return model.get_value(iter, COLUMN_SEPARATOR)

    self.custom_mirrors = custom_mirrors
    self.country_info = CountryInformation()

    setup_ui(self, os.path.join(datadir, "gtkbuilder", "dialog-mirror.ui"), domain="software-properties")
    
    self.dialog = self.dialog_mirror
    self.dialog.set_transient_for(parent)
    
    self.dialog_test = self.dialog_mirror_test
    self.dialog_test.set_transient_for(self.dialog)
    self.distro = distro
    self.treeview = self.treeview_mirrors
    self.button_edit = self.button_mirror_edit
    self.button_remove = self.button_mirror_remove
    self.button_choose = self.button_mirror_choose
    self.button_cancel = self.button_test_cancel
    self.label_test = self.label_test_mirror
    self.progressbar_test = self.progressbar_test_mirror
    self.combobox = self.combobox_mirror_proto
    self.progress = self.progressbar_test_mirror
    self.label_action = self.label_test_mirror

    # store each proto and its dir
    model_proto = gtk.ListStore(gobject.TYPE_STRING,
                                gobject.TYPE_STRING)
    self.combobox.set_model(model_proto)
    cr = gtk.CellRendererText()
    self.combobox.pack_start(cr)
    self.combobox.add_attribute(cr, "markup", 0)

    self.model = gtk.TreeStore(gobject.TYPE_STRING,  # COLUMN_URI
                               gobject.TYPE_BOOLEAN, # COLUMN_SEPARATOR
                               gobject.TYPE_BOOLEAN, # COLUMN_CUSTOM
                               gobject.TYPE_PYOBJECT)# COLUMN_MIRROR
    self.treeview.set_row_separator_func(is_separator)
    self.model_sort = gtk.TreeModelSort(self.model)
    self.model_sort.set_default_sort_func(sort_mirrors)

    self.distro = distro

    self.treeview.set_model(self.model_sort)
    # the cell renderer for the mirror uri
    self.renderer_mirror = gtk.CellRendererText()
    self.renderer_mirror.connect('edited', 
                                 self.on_edited_custom_mirror, 
                                 self.model)
    # the visible column that holds the mirror uris
    self.column_mirror = gtk.TreeViewColumn("URI", 
                                            self.renderer_mirror, 
                                            text=COLUMN_URI)
    self.treeview.append_column(self.column_mirror)

    # used to find the corresponding iter of a location
    map_loc = {}
    patriot = None
    model = self.treeview.get_model().get_model()
    # at first add all custom mirrors and a separator
    if len(self.custom_mirrors) > 0:
        for mirror in self.custom_mirrors:
            model.append(None, [mirror, False, True, None])
            self.column_mirror.add_attribute(self.renderer_mirror, 
                                             "editable", 
                                             COLUMN_CUSTOM)
        model.append(None, [None, True, False, None])
    # secondly add all official mirrors
    for hostname in self.distro.source_template.mirror_set.keys():
        mirror = self.distro.source_template.mirror_set[hostname]
        if map_loc.has_key(mirror.location):
            model.append(map_loc[mirror.location],
                         [hostname, False, False, mirror])
        elif mirror.location != None:
            parent = model.append(None, 
                                  [self.country_info.get_country_name(mirror.location), False, False, None])
            if mirror.location == self.country_info.code and patriot == None:
                patriot = parent
            model.append(parent, [hostname, False, False, mirror]),
            map_loc[mirror.location] = parent
        else:
            model.append(None, [hostname, False, False, mirror])
    # Scroll to the local mirror set
    if patriot != None:
        path_sort = self.model_sort.get_path(self.model_sort.convert_child_iter_to_iter(None, patriot))
        self.treeview.expand_row(path_sort, False)
        self.treeview.set_cursor(path_sort)
        self.treeview.scroll_to_cell(path_sort, use_align=True, row_align=0.5)

  def on_edited_custom_mirror(self, cell, path, new_text, model):
    ''' Check if the new mirror uri is faild, if yes change it, if not
        remove the mirror from the list '''
    iter = model.get_iter(path)
    iter_next = model.iter_next(iter)
    if new_text != "":
        model.set_value(iter, COLUMN_URI, new_text)
        # Add a separator if the next mirror is a not a separator or 
        # a custom one
        if iter_next != None and not \
           (model.get_value(iter_next, COLUMN_SEPARATOR) or \
            model.get_value(iter_next, COLUMN_CUSTOM)):
            model.insert(1, [None, True, False])
        self.button_choose.set_sensitive(self.is_valid_mirror(new_text))
    else:
        model.remove(iter)
        # Remove the separator if this was the last custom mirror
        if model.get_value(model.get_iter_first(), COLUMN_SEPARATOR):
            model.remove(model.get_iter_first())
        self.treeview.set_cursor((0,))
    return

  def is_valid_mirror(self, uri):
    ''' Check if a given uri is a vaild one '''
    if uri == None:
        return False
    elif re.match("^((ftp)|(http)|(file)|(rsync)|(https))://([a-z]|[A-Z]|[0-9]|:|/|\.|~)+$", uri) == None:
        return False
    else:
        return True

  def on_treeview_mirrors_cursor_changed(self, treeview, data=None):
    ''' Check if the currently selected row in the mirror list
        contains a mirror and or is editable '''
    (row, column) = treeview.get_cursor()
    if row == None:
        self.button_remove.set_sensitive(False)
        self.button_edit.set_sensitive(False)
        self.button_choose.set_sensitive(False)
        return
    model = treeview.get_model()
    iter = model.get_iter(row)
    # Update the list of available protocolls
    mirror = model.get_value(iter, COLUMN_MIRROR)
    model_protos = self.combobox.get_model()
    model_protos.clear()
    if mirror != None:
        self.combobox.set_sensitive(True)
        seen_protos = []
        for repo in mirror.repositories:
            # Only add a repository for a protocoll once
            if repo.proto in seen_protos:
                continue
            seen_protos.append(repo.proto)
            model_protos.append(repo.get_info())
        self.combobox.set_active(0)
        self.button_choose.set_sensitive(True)
    else:
        # Allow to edit and remove custom mirrors
        self.button_remove.set_sensitive(model.get_value(iter, COLUMN_CUSTOM))
        self.button_edit.set_sensitive(model.get_value(iter, COLUMN_CUSTOM))
        self.button_choose.set_sensitive(self.is_valid_mirror(model.get_value(iter, COLUMN_URI)))
        self.combobox.set_sensitive(False)

  def on_button_mirror_remove_clicked(self, button, data=None):
    ''' Remove the currently selected mirror '''
    path, column = self.treeview.get_cursor()
    iter = self.treeview.get_model().get_iter(path)
    model = self.treeview.get_model().get_model()
    model.remove(iter)
    # Remove the separator if this was the last custom mirror
    if model.get_value(model.get_iter_first(), COLUMN_SEPARATOR):
        model.remove(model.get_iter_first())
    self.treeview.set_cursor((0,))

  def on_button_mirror_add_clicked(self, button, data=None):
    ''' Add a new mirror at the beginning of the list and start
        editing '''
    model = self.treeview.get_model().get_model()
    model.append(None, [_("New mirror"), False, True, None])
    self.treeview.grab_focus()
    self.treeview.set_cursor((0,),
                             focus_column=self.column_mirror, 
                             start_editing=True)

  def on_button_mirror_edit_clicked(self, button, data=None):
    ''' Grab the focus and start editing the currently selected mirror '''
    path, column = self.treeview.get_cursor()
    self.treeview.grab_focus()
    self.treeview.set_cursor(path, focus_column=column, start_editing=True)

  def on_dialog_mirror_test_delete_event(self, dialog, event, data=None):
    ''' If anybody wants to close the dialog, stop the test before '''
    self.on_button_cancel_test_clicked(None)
    return True

  def run(self):
    ''' Run the chooser dialog and return the chosen mirror or None '''
    res = self.dialog.run()
    self.dialog.hide()

    (row, column) = self.treeview.get_cursor()
    model = self.treeview.get_model()
    iter = model.get_iter(row)
    mirror = model.get_value(iter, COLUMN_MIRROR)

    # FIXME: we should also return the list of custom servers
    if res == gtk.RESPONSE_OK:
        if mirror == None:
            # Return the URL of the selected custom mirror
            return model.get_value(iter, COLUMN_URI)
        else:
            # Return an URL created from the hostname and the selected
            # repository
            model_proto = self.combobox.get_model()
            iter_proto = model_proto.get_iter(self.combobox.get_active())
            proto = model_proto.get_value(iter_proto, COLUMN_PROTO)
            dir = model_proto.get_value(iter_proto, COLUMN_DIR)
            return "%s://%s/%s" % (proto, mirror.hostname, dir)
    else:
        return None

  @threaded
  def on_button_test_clicked(self, button, data=None):
    ''' Perform a test to find the best mirror and select it 
        afterwards in the treeview '''
    class MirrorTestGtk(MirrorTest):
        def __init__(self, mirrors, test_file, running, progressbar, label):
            MirrorTest.__init__(self, mirrors, test_file, running)
            self.progress = progressbar
            self.label = label
        def report_action(self, text):
            gtk.gdk.threads_enter()
            self.label.set_label(str("<i>%s</i>" % text))
            gtk.gdk.threads_leave()
        def report_progress(self, current, max, borders=(0,1), mod=(0,0)):
            gtk.gdk.threads_enter()
            self.progress.set_text(_("Completed %s of %s tests") % \
                                   (current + mod[0], max + mod[1]))
            frac = borders[0] + (borders[1] - borders[0]) / max * current
            self.progress.set_fraction(frac)
            gtk.gdk.threads_leave()

    gtk.gdk.threads_enter()
    self.button_cancel.set_sensitive(True)
    self.dialog_test.show()
    gtk.gdk.threads_leave()
    self.running = threading.Event()
    self.running.set()
    pipe = os.popen("dpkg --print-architecture")
    arch = pipe.read().strip()
    test_file = "dists/%s/%s/binary-%s/Packages.gz" % \
                 (self.distro.source_template.name,
                  self.distro.source_template.components[0].name,
                  arch)
    test = MirrorTestGtk(self.distro.source_template.mirror_set.values(), 
                         test_file,
                         self.running,
                         self.progress,
                         self.label_action)
    test.start()
    rocker = test.run_full_test()
    gtk.gdk.threads_enter()
    testing.clear()
    self.dialog_test.hide()
    # Select the mirror in the list or show an error dialog
    if rocker != None:
        self.model_sort.foreach(self.select_mirror, rocker)
    else:
        dialogs.show_error_dialog(self.dialog, 
                                  _("No suitable download server was found"),
                                  _("Please check your Internet connection."))
    gtk.gdk.threads_leave()

  def select_mirror(self, model, path, iter, mirror):
    """Select and expand the path to a matching mirror in the list"""
    if model.get_value(iter, COLUMN_URI) == mirror:
        self.treeview.expand_to_path(path)
        self.treeview.set_cursor(path)
        self.treeview.scroll_to_cell(path, use_align=True, row_align=0.5)
        self.treeview.grab_focus()
        # breaks foreach
        return True

  def on_button_cancel_test_clicked(self, button):
    ''' Abort the mirror performance test '''
    self.running.clear()
    self.label_test.set_label("<i>%s</i>" % _("Canceling..."))
    self.button_cancel.set_sensitive(False)
    self.progressbar_test.set_fraction(1)
  def __init__(self, parent, datadir, distro, custom_mirrors):
    """
    Initialize the dialog that allows to choose a custom or official mirror
    """
    def is_separator(model, iter, data=None):
        return model.get_value(iter, COLUMN_SEPARATOR)

    self.custom_mirrors = custom_mirrors
    self.country_info = CountryInformation()

    setup_ui(self, os.path.join(datadir, "gtkbuilder", "dialog-mirror.ui"), domain="software-properties")
    
    self.dialog = self.dialog_mirror
    self.dialog.set_transient_for(parent)
    
    self.dialog_test = self.dialog_mirror_test
    self.dialog_test.set_transient_for(self.dialog)
    self.distro = distro
    self.treeview = self.treeview_mirrors
    self.button_edit = self.button_mirror_edit
    self.button_remove = self.button_mirror_remove
    self.button_choose = self.button_mirror_choose
    self.button_cancel = self.button_test_cancel
    self.label_test = self.label_test_mirror
    self.progressbar_test = self.progressbar_test_mirror
    self.combobox = self.combobox_mirror_proto
    self.progress = self.progressbar_test_mirror
    self.label_action = self.label_test_mirror

    # store each proto and its dir
    model_proto = gtk.ListStore(gobject.TYPE_STRING,
                                gobject.TYPE_STRING)
    self.combobox.set_model(model_proto)
    cr = gtk.CellRendererText()
    self.combobox.pack_start(cr)
    self.combobox.add_attribute(cr, "markup", 0)

    self.model = gtk.TreeStore(gobject.TYPE_STRING,  # COLUMN_URI
                               gobject.TYPE_BOOLEAN, # COLUMN_SEPARATOR
                               gobject.TYPE_BOOLEAN, # COLUMN_CUSTOM
                               gobject.TYPE_PYOBJECT)# COLUMN_MIRROR
    self.treeview.set_row_separator_func(is_separator)
    self.model_sort = gtk.TreeModelSort(self.model)
    self.model_sort.set_default_sort_func(sort_mirrors)

    self.distro = distro

    self.treeview.set_model(self.model_sort)
    # the cell renderer for the mirror uri
    self.renderer_mirror = gtk.CellRendererText()
    self.renderer_mirror.connect('edited', 
                                 self.on_edited_custom_mirror, 
                                 self.model)
    # the visible column that holds the mirror uris
    self.column_mirror = gtk.TreeViewColumn("URI", 
                                            self.renderer_mirror, 
                                            text=COLUMN_URI)
    self.treeview.append_column(self.column_mirror)

    # used to find the corresponding iter of a location
    map_loc = {}
    patriot = None
    model = self.treeview.get_model().get_model()
    # at first add all custom mirrors and a separator
    if len(self.custom_mirrors) > 0:
        for mirror in self.custom_mirrors:
            model.append(None, [mirror, False, True, None])
            self.column_mirror.add_attribute(self.renderer_mirror, 
                                             "editable", 
                                             COLUMN_CUSTOM)
        model.append(None, [None, True, False, None])
    # secondly add all official mirrors
    for hostname in self.distro.source_template.mirror_set.keys():
        mirror = self.distro.source_template.mirror_set[hostname]
        if map_loc.has_key(mirror.location):
            model.append(map_loc[mirror.location],
                         [hostname, False, False, mirror])
        elif mirror.location != None:
            parent = model.append(None, 
                                  [self.country_info.get_country_name(mirror.location), False, False, None])
            if mirror.location == self.country_info.code and patriot == None:
                patriot = parent
            model.append(parent, [hostname, False, False, mirror]),
            map_loc[mirror.location] = parent
        else:
            model.append(None, [hostname, False, False, mirror])
    # Scroll to the local mirror set
    if patriot != None:
        path_sort = self.model_sort.get_path(self.model_sort.convert_child_iter_to_iter(None, patriot))
        self.treeview.expand_row(path_sort, False)
        self.treeview.set_cursor(path_sort)
        self.treeview.scroll_to_cell(path_sort, use_align=True, row_align=0.5)
Beispiel #7
0
  def __init__(self, parent, datadir, distro, custom_mirrors):
    """
    Initialize the dialog that allows to choose a custom or official mirror
    """
    def is_separator(model, iter, data=None):
        return model.get_value(iter, COLUMN_SEPARATOR)

    self.custom_mirrors = custom_mirrors
    self.country_info = CountryInformation()

    setup_ui(self, os.path.join(datadir, "gtkbuilder", "dialog-mirror.ui"), domain="software-properties")
    
    self.dialog = self.dialog_mirror
    self.dialog.set_transient_for(parent)
    
    self.dialog_test = self.dialog_mirror_test
    self.dialog_test.set_transient_for(self.dialog)
    self.distro = distro
    self.treeview = self.treeview_mirrors
    self.button_edit = self.button_mirror_edit
    self.button_remove = self.button_mirror_remove
    self.button_choose = self.button_mirror_choose
    self.button_cancel = self.button_test_cancel
    self.label_test = self.label_test_mirror
    self.progressbar_test = self.progressbar_test_mirror
    self.combobox = self.combobox_mirror_proto
    self.progress = self.progressbar_test_mirror
    self.label_action = self.label_test_mirror

    # store each proto and its dir
    model_proto = Gtk.ListStore(GObject.TYPE_STRING,
                                GObject.TYPE_STRING)
    self.combobox.set_model(model_proto)
    cr = Gtk.CellRendererText()
    self.combobox.pack_start(cr, True)
    self.combobox.add_attribute(cr, "markup", 0)

    self.model = Gtk.TreeStore(GObject.TYPE_STRING,  # COLUMN_URI
                               GObject.TYPE_BOOLEAN, # COLUMN_SEPARATOR
                               GObject.TYPE_BOOLEAN, # COLUMN_CUSTOM
                               GObject.TYPE_PYOBJECT)# COLUMN_MIRROR
    self.treeview.set_row_separator_func(is_separator, None)
    self.model_sort = Gtk.TreeModelSort(model=self.model)

    self.distro = distro

    self.treeview.set_model(self.model_sort)
    # the cell renderer for the mirror uri
    self.renderer_mirror = Gtk.CellRendererText()
    self.renderer_mirror.connect('edited', 
                                 self.on_edited_custom_mirror, 
                                 self.model)
    # the visible column that holds the mirror uris
    self.column_mirror = Gtk.TreeViewColumn("URI", 
                                            self.renderer_mirror, 
                                            text=COLUMN_URI)
    self.treeview.append_column(self.column_mirror)

    # used to find the corresponding iter of a location
    map_loc = {}
    patriot = None
    model = self.treeview.get_model().get_model()
    # at first add all custom mirrors and a separator
    if len(self.custom_mirrors) > 0:
        for mirror in self.custom_mirrors:
            model.append(None, [mirror, False, True, None])
            self.column_mirror.add_attribute(self.renderer_mirror, 
                                             "editable", 
                                             COLUMN_CUSTOM)
        model.append(None, [None, True, False, None])
    # secondly add all official mirrors
    for hostname in self.distro.source_template.mirror_set.keys():
        mirror = self.distro.source_template.mirror_set[hostname]
        if mirror.location in map_loc:
            model.append(map_loc[mirror.location],
                         [hostname, False, False, mirror])
        elif mirror.location != None:
            parent = model.append(None, 
                                  [self.country_info.get_country_name(mirror.location), False, False, None])
            if mirror.location == self.country_info.code and patriot == None:
                patriot = parent
            model.append(parent, [hostname, False, False, mirror]),
            map_loc[mirror.location] = parent
        else:
            model.append(None, [hostname, False, False, mirror])
    # Scroll to the local mirror set
    if patriot != None:
        path_sort = self.model_sort.get_path(self.model_sort.convert_child_iter_to_iter(patriot)[1])
        self.treeview.expand_row(path_sort, False)
        self.treeview.set_cursor(path_sort, None, False)
        self.treeview.scroll_to_cell(path_sort, use_align=True, row_align=0.5)
    # set the sort function, this will also trigger a sort
    self.model_sort.set_default_sort_func(sort_mirrors, None)
Beispiel #8
0
class DialogMirror:

  def __init__(self, parent, datadir, distro, custom_mirrors):
    """
    Initialize the dialog that allows to choose a custom or official mirror
    """
    def is_separator(model, iter, data=None):
        return model.get_value(iter, COLUMN_SEPARATOR)

    self.custom_mirrors = custom_mirrors
    self.country_info = CountryInformation()

    setup_ui(self, os.path.join(datadir, "gtkbuilder", "dialog-mirror.ui"), domain="software-properties")
    
    self.dialog = self.dialog_mirror
    self.dialog.set_transient_for(parent)
    
    self.dialog_test = self.dialog_mirror_test
    self.dialog_test.set_transient_for(self.dialog)
    self.distro = distro
    self.treeview = self.treeview_mirrors
    self.button_edit = self.button_mirror_edit
    self.button_remove = self.button_mirror_remove
    self.button_choose = self.button_mirror_choose
    self.button_cancel = self.button_test_cancel
    self.label_test = self.label_test_mirror
    self.progressbar_test = self.progressbar_test_mirror
    self.combobox = self.combobox_mirror_proto
    self.progress = self.progressbar_test_mirror
    self.label_action = self.label_test_mirror

    # store each proto and its dir
    model_proto = Gtk.ListStore(GObject.TYPE_STRING,
                                GObject.TYPE_STRING)
    self.combobox.set_model(model_proto)
    cr = Gtk.CellRendererText()
    self.combobox.pack_start(cr, True)
    self.combobox.add_attribute(cr, "markup", 0)

    self.model = Gtk.TreeStore(GObject.TYPE_STRING,  # COLUMN_URI
                               GObject.TYPE_BOOLEAN, # COLUMN_SEPARATOR
                               GObject.TYPE_BOOLEAN, # COLUMN_CUSTOM
                               GObject.TYPE_PYOBJECT)# COLUMN_MIRROR
    self.treeview.set_row_separator_func(is_separator, None)
    self.model_sort = Gtk.TreeModelSort(model=self.model)

    self.distro = distro

    self.treeview.set_model(self.model_sort)
    # the cell renderer for the mirror uri
    self.renderer_mirror = Gtk.CellRendererText()
    self.renderer_mirror.connect('edited', 
                                 self.on_edited_custom_mirror, 
                                 self.model)
    # the visible column that holds the mirror uris
    self.column_mirror = Gtk.TreeViewColumn("URI", 
                                            self.renderer_mirror, 
                                            text=COLUMN_URI)
    self.treeview.append_column(self.column_mirror)

    # used to find the corresponding iter of a location
    map_loc = {}
    patriot = None
    model = self.treeview.get_model().get_model()
    # at first add all custom mirrors and a separator
    if len(self.custom_mirrors) > 0:
        for mirror in self.custom_mirrors:
            model.append(None, [mirror, False, True, None])
            self.column_mirror.add_attribute(self.renderer_mirror, 
                                             "editable", 
                                             COLUMN_CUSTOM)
        model.append(None, [None, True, False, None])
    # secondly add all official mirrors
    for hostname in self.distro.source_template.mirror_set.keys():
        mirror = self.distro.source_template.mirror_set[hostname]
        if mirror.location in map_loc:
            model.append(map_loc[mirror.location],
                         [hostname, False, False, mirror])
        elif mirror.location != None:
            parent = model.append(None, 
                                  [self.country_info.get_country_name(mirror.location), False, False, None])
            if mirror.location == self.country_info.code and patriot == None:
                patriot = parent
            model.append(parent, [hostname, False, False, mirror]),
            map_loc[mirror.location] = parent
        else:
            model.append(None, [hostname, False, False, mirror])
    # Scroll to the local mirror set
    if patriot != None:
        path_sort = self.model_sort.get_path(self.model_sort.convert_child_iter_to_iter(patriot)[1])
        self.treeview.expand_row(path_sort, False)
        self.treeview.set_cursor(path_sort, None, False)
        self.treeview.scroll_to_cell(path_sort, use_align=True, row_align=0.5)
    # set the sort function, this will also trigger a sort
    self.model_sort.set_default_sort_func(sort_mirrors, None)

  def on_edited_custom_mirror(self, cell, path, new_text, model):
    ''' Check if the new mirror uri is faild, if yes change it, if not
        remove the mirror from the list '''
    iter = model.get_iter(path)
    iter_next = model.iter_next(iter)
    if new_text != "":
        model.set_value(iter, COLUMN_URI, new_text)
        # Add a separator if the next mirror is a not a separator or 
        # a custom one
        if iter_next != None and not \
           (model.get_value(iter_next, COLUMN_SEPARATOR) or \
            model.get_value(iter_next, COLUMN_CUSTOM)):
            model.insert(1, [None, True, False])
        self.button_choose.set_sensitive(self.is_valid_mirror(new_text))
    else:
        model.remove(iter)
        # Remove the separator if this was the last custom mirror
        if model.get_value(model.get_iter_first(), COLUMN_SEPARATOR):
            model.remove(model.get_iter_first())
        self.treeview.set_cursor((0,))
    return

  def is_valid_mirror(self, uri):
    ''' Check if a given uri is a vaild one '''
    if uri == None:
        return False
    elif re.match("^((ftp)|(http)|(file)|(rsync)|(https))://([a-z]|[A-Z]|[0-9]|:|/|\.|~)+$", uri) == None:
        return False
    else:
        return True

  def on_treeview_mirrors_cursor_changed(self, treeview, data=None):
    ''' Check if the currently selected row in the mirror list
        contains a mirror and or is editable '''
    (row, column) = treeview.get_cursor()
    if row == None:
        self.button_remove.set_sensitive(False)
        self.button_edit.set_sensitive(False)
        self.button_choose.set_sensitive(False)
        return
    model = treeview.get_model()
    iter = model.get_iter(row)
    # Update the list of available protocolls
    mirror = model.get_value(iter, COLUMN_MIRROR)
    model_protos = self.combobox.get_model()
    model_protos.clear()
    if mirror != None:
        self.combobox.set_sensitive(True)
        seen_protos = []
        for repo in mirror.repositories:
            # Only add a repository for a protocoll once
            if repo.proto in seen_protos:
                continue
            seen_protos.append(repo.proto)
            model_protos.append(repo.get_info())
        self.combobox.set_active(0)
        self.button_choose.set_sensitive(True)
    else:
        # Allow to edit and remove custom mirrors
        self.button_remove.set_sensitive(model.get_value(iter, COLUMN_CUSTOM))
        self.button_edit.set_sensitive(model.get_value(iter, COLUMN_CUSTOM))
        self.button_choose.set_sensitive(self.is_valid_mirror(model.get_value(iter, COLUMN_URI)))
        self.combobox.set_sensitive(False)

  def on_button_mirror_remove_clicked(self, button, data=None):
    ''' Remove the currently selected mirror '''
    path, column = self.treeview.get_cursor()
    iter = self.treeview.get_model().get_iter(path)
    model = self.treeview.get_model().get_model()
    model.remove(iter)
    # Remove the separator if this was the last custom mirror
    if model.get_value(model.get_iter_first(), COLUMN_SEPARATOR):
        model.remove(model.get_iter_first())
    self.treeview.set_cursor((0,))

  def on_button_mirror_add_clicked(self, button, data=None):
    ''' Add a new mirror at the beginning of the list and start
        editing '''
    model = self.treeview.get_model().get_model()
    model.append(None, [_("New mirror"), False, True, None])
    self.treeview.grab_focus()
    self.treeview.set_cursor((0,),
                             focus_column=self.column_mirror, 
                             start_editing=True)

  def on_button_mirror_edit_clicked(self, button, data=None):
    ''' Grab the focus and start editing the currently selected mirror '''
    path, column = self.treeview.get_cursor()
    self.treeview.grab_focus()
    self.treeview.set_cursor(path, focus_column=column, start_editing=True)

  def on_dialog_mirror_test_delete_event(self, dialog, event, data=None):
    ''' If anybody wants to close the dialog, stop the test before '''
    self.on_button_cancel_test_clicked(None)
    return True

  def run(self):
    ''' Run the chooser dialog and return the chosen mirror or None '''
    res = self.dialog.run()
    self.dialog.hide()

    (row, column) = self.treeview.get_cursor()
    if not row:
        return None

    model = self.treeview.get_model()
    iter = model.get_iter(row)
    mirror = model.get_value(iter, COLUMN_MIRROR)

    # FIXME: we should also return the list of custom servers
    if res == Gtk.ResponseType.OK:
        if mirror == None:
            # Return the URL of the selected custom mirror
            return model.get_value(iter, COLUMN_URI)
        else:
            # Return an URL created from the hostname and the selected
            # repository
            model_proto = self.combobox.get_model()
            iter_proto = model_proto.get_iter(self.combobox.get_active())
            proto = model_proto.get_value(iter_proto, COLUMN_PROTO)
            dir = model_proto.get_value(iter_proto, COLUMN_DIR)
            return "%s://%s/%s" % (proto, mirror.hostname, dir)
    else:
        return None

  def on_button_test_clicked(self, button, data=None):
    ''' Perform a test to find the best mirror and select it 
        afterwards in the treeview '''
    self.button_cancel.set_sensitive(True)
    self.dialog_test.show()
    self.running = threading.Event()
    self.running.set()
    progress_update = threading.Event()
    pipe = os.popen("dpkg --print-architecture")
    arch = pipe.read().strip()
    test_file = "dists/%s/%s/binary-%s/Packages.gz" % \
                 (self.distro.source_template.name,
                  self.distro.source_template.components[0].name,
                  arch)
    test = MirrorTest(list(self.distro.source_template.mirror_set.values()),
                         test_file,
                         progress_update,
                         self.running)
    test.start()

    # now run the tests in a background thread, and update the UI on each event
    while self.running.is_set():
        while Gtk.events_pending():
            Gtk.main_iteration_do(False)

        # don't spin the CPU until there's something to update; but update the
        # UI at least every 100 ms
        progress_update.wait(0.1)

        if progress_update.is_set():
            self.progress.set_text(_("Completed %s of %s tests") % \
                                   (test.progress[0], test.progress[1]))
            self.progress.set_fraction(test.progress[2])
            progress_update.clear()
    self.dialog_test.hide()
    self.label_test.set_label("")
    # Select the mirror in the list or show an error dialog
    if test.best != None:
        self.model_sort.foreach(self.select_mirror, test.best)
    else:
        dialogs.show_error_dialog(self.dialog, 
                                  _("No suitable download server was found"),
                                  _("Please check your Internet connection."))

  def select_mirror(self, model, path, iter, mirror):
    """Select and expand the path to a matching mirror in the list"""
    if model.get_value(iter, COLUMN_URI) == mirror:
        self.treeview.expand_to_path(path)
        self.treeview.set_cursor(path, None, False)
        self.treeview.scroll_to_cell(path, use_align=True, row_align=0.5)
        self.treeview.grab_focus()
        # breaks foreach
        return True

  def on_button_cancel_test_clicked(self, button):
    ''' Abort the mirror performance test '''
    self.running.clear()
    self.label_test.set_label("<i>%s</i>" % _("Canceling..."))
    self.button_cancel.set_sensitive(False)
    self.progressbar_test.set_fraction(1)
Beispiel #9
0
class DialogMirror(QDialog):

    # Signals
    test_start = pyqtSignal()
    test_end = pyqtSignal('QString')
    report_progress = pyqtSignal(int, int, tuple, tuple)
    report_action = pyqtSignal('QString')

    def __init__(self, parent, datadir, distro, custom_mirrors):
        """
    Initialize the dialog that allows to choose a custom or official mirror
    """
        QDialog.__init__(self, parent)
        uic.loadUi("%s/designer/dialog_mirror.ui" % datadir, self)
        self.parent = parent

        self.custom_mirrors = custom_mirrors

        self.country_info = CountryInformation()

        self.button_choose = self.buttonBox.button(QDialogButtonBox.Ok)
        self.button_choose.setEnabled(False)
        self.button_cancel = self.buttonBox.button(QDialogButtonBox.Cancel)
        self.distro = distro

        self.treeview.setColumnCount(1)
        self.treeview.setHeaderLabels([_("Mirror")])

        translate_widget(self)
        # used to find the corresponding iter of a location
        map_loc = {}
        patriot = None
        """ no custom yet
    # at first add all custom mirrors and a separator
    if len(self.custom_mirrors) > 0:
        for mirror in self.custom_mirrors:

            model.append(None, [mirror, False, True, None])
            self.column_mirror.add_attribute(self.renderer_mirror, 
                                             "editable", 
                                             COLUMN_CUSTOM)
        model.append(None, [None, True, False, None])
    """
        self.mirror_map = {}
        # secondly add all official mirrors
        for hostname in self.distro.source_template.mirror_set.keys():
            mirror = self.distro.source_template.mirror_set[hostname]
            if mirror.location in map_loc:  # a mirror in a country
                QTreeWidgetItem(map_loc[mirror.location], [hostname])
                self.mirror_map[hostname] = mirror
            elif mirror.location != None:  # a country new to the list
                country = self.country_info.get_country_name(mirror.location)
                parent = QTreeWidgetItem([country])
                self.mirror_map[country] = None
                self.treeview.addTopLevelItem(parent)
                QTreeWidgetItem(parent, [hostname])
                self.mirror_map[hostname] = mirror
                if mirror.location == self.country_info.code and patriot == None:
                    patriot = parent
                map_loc[mirror.location] = parent
            else:  # a mirror without country
                item = QTreeWidgetItem([hostname])
                self.treeview.addTopLevelItem(item)
        self.treeview.sortItems(0, Qt.AscendingOrder)
        # Scroll to the local mirror set
        if patriot != None:
            self.select_mirror(patriot.text(0))
        self.treeview.itemClicked.connect(
            self.on_treeview_mirrors_cursor_changed)
        self.button_find_server.clicked.connect(self.on_button_test_clicked)
        self.edit_buttons_frame.hide()  ##FIXME not yet implemented

    def on_treeview_mirrors_cursor_changed(self, item, column):
        """ Check if the currently selected row in the mirror list
        contains a mirror and or is editable """
        # Update the list of available protocolls
        hostname = self.treeview.currentItem().text(0)
        mirror = self.mirror_map[hostname]
        self.combobox.clear()
        if mirror != None:
            self.combobox.setEnabled(True)
            seen_protos = []
            self.protocol_paths = {}
            for repo in mirror.repositories:
                # Only add a repository for a protocoll once
                if repo.proto in seen_protos:
                    continue
                seen_protos.append(repo.proto)
                self.protocol_paths[repo.get_info()[0]] = repo.get_info()[1]
                self.combobox.addItem(repo.get_info()[0])
            self.button_choose.setEnabled(True)
        else:
            self.button_choose.setEnabled(False)
        """
        # Allow to edit and remove custom mirrors
        self.button_remove.set_sensitive(model.get_value(iter, COLUMN_CUSTOM))
        self.button_edit.set_sensitive(model.get_value(iter, COLUMN_CUSTOM))
        self.button_choose.set_sensitive(self.is_valid_mirror(model.get_value(iter, COLUMN_URI)))
        self.combobox.set_sensitive(False)

    """

    def run(self):
        """ Run the chooser dialog and return the chosen mirror or None """
        res = self.exec_()

        # FIXME: we should also return the list of custom servers
        if res == QDialog.Accepted:
            hostname = self.treeview.currentItem().text(0)
            mirror = self.mirror_map[hostname]

            if mirror == None:
                # Return the URL of the selected custom mirror
                print("Error, unknown mirror")
                return None
                ##FIXME return model.get_value(iter, COLUMN_URI)
            else:
                # Return a URL created from the hostname and the selected
                # repository
                proto = self.combobox.currentText()

                directory = self.protocol_paths[proto]
                return "%s://%s/%s" % (proto, mirror.hostname, directory)
        else:
            return None

    def on_button_test_clicked(self):
        ''' Perform a test to find the best mirror and select it 
        afterwards in the treeview '''
        class MirrorTestKDE(MirrorTest):
            def __init__(self, mirrors, test_file, running, dialog, parent):
                MirrorTest.__init__(self, mirrors, test_file, None, running)
                self.dialog = dialog
                self.parent = parent

            def report_action(self, text):
                if self.running.isSet():
                    self.parent.report_action.emit(text)

            def report_progress(self, current, max, borders=(0, 1),
                                mod=(0, 0)):
                if self.running.isSet():
                    self.parent.report_progress.emit(current, max, borders,
                                                     mod)

            def run(self):
                self.parent.test_start.emit()
                rocker = self.run_full_test()
                self.parent.test_end.emit(rocker)

        self.dialog = QProgressDialog(_("Testing Mirrors"), _("Cancel"), 0,
                                      100, self)
        self.dialog.setWindowTitle(_("Testing Mirrors"))
        self.dialog.setWindowModality(Qt.WindowModal)
        self.button_cancel_test = QPushButton(_("Cancel"), self.dialog)
        self.dialog.setCancelButton(self.button_cancel_test)
        self.button_cancel_test.clicked.connect(
            self.on_button_cancel_test_clicked)
        # the following signals are connected across threads
        self.test_start.connect(self.on_test_start,
                                Qt.BlockingQueuedConnection)
        self.test_end.connect(self.on_test_end, Qt.BlockingQueuedConnection)
        self.report_progress.connect(self.on_report_progress,
                                     Qt.BlockingQueuedConnection)
        self.report_action.connect(self.on_report_action,
                                   Qt.BlockingQueuedConnection)

        self.running = threading.Event()
        self.running.set()
        pipe = os.popen("dpkg --print-architecture")
        arch = pipe.read().strip()
        test_file = "dists/%s/%s/binary-%s/Packages.gz" % \
                     (self.distro.source_template.name,
                      self.distro.source_template.components[0].name,
                      arch)
        test = MirrorTestKDE(
            list(self.distro.source_template.mirror_set.values()), test_file,
            self.running, self.dialog, self)
        test.start()  # test starts in a separate thread

    def on_test_start(self):
        self.dialog.show()

    def on_test_end(self, mirror):
        self.dialog.hide()
        if not self.running.isSet():
            return  # canceled by user
        if mirror != None:
            self.select_mirror(mirror)
        else:
            QMessageBox.warning(
                self.dialog, _("Testing Mirrors"),
                _("No suitable download server was found") + "\n" +
                _("Please check your Internet connection."))

    def on_report_action(self, text):
        self.dialog.setLabelText(str("<i>%s</i>" % text))

    def on_report_progress(self, current, max, borders=(0, 1), mod=(0, 0)):
        #self.dialog.setLabelText(_("Completed %s of %s tests") % \
        #                       (current + mod[0], max + mod[1]))
        frac = borders[0] + (borders[1] - borders[0]) / max * current
        self.dialog.setValue(frac * 100)

    def on_button_cancel_test_clicked(self):
        ''' Abort the mirror performance test '''
        self.running.clear()
        self.dialog.show()
        self.dialog.setLabelText("<i>%s</i>" % _("Canceling..."))
        self.button_cancel_test.setEnabled(False)
        self.dialog.setValue(100)

    def select_mirror(self, mirror):
        """Select and expand the path to a matching mirror in the list"""
        found = self.treeview.findItems(mirror,
                                        Qt.MatchExactly | Qt.MatchRecursive)
        if found:
            found[0].setSelected(True)
            self.treeview.setCurrentItem(found[0])
            self.treeview.scrollToItem(found[0],
                                       QAbstractItemView.PositionAtCenter)
            self.on_treeview_mirrors_cursor_changed(found[0], 0)
            self.button_choose.setFocus()
            return True
Beispiel #10
0
    def __init__(self, parent, datadir, distro, custom_mirrors):
        """
    Initialize the dialog that allows to choose a custom or official mirror
    """
        def is_separator(model, iter, data=None):
            return model.get_value(iter, COLUMN_SEPARATOR)

        self.custom_mirrors = custom_mirrors

        self.country_info = CountryInformation()

        self.gladexml = gtk.glade.XML("%s/glade/dialogs.glade" %\
                                      datadir)
        self.gladexml.signal_autoconnect(self)
        self.dialog = self.gladexml.get_widget("dialog_mirror")
        self.dialog.set_transient_for(parent)
        self.dialog_test = self.gladexml.get_widget("dialog_mirror_test")
        self.dialog_test.set_transient_for(self.dialog)
        self.distro = distro
        self.treeview = self.gladexml.get_widget("treeview_mirrors")
        self.button_edit = self.gladexml.get_widget("button_mirror_edit")
        self.button_remove = self.gladexml.get_widget("button_mirror_remove")
        self.button_choose = self.gladexml.get_widget("button_mirror_choose")
        self.button_cancel = self.gladexml.get_widget("button_test_cancel")
        self.label_test = self.gladexml.get_widget("label_test_mirror")
        self.progressbar_test = self.gladexml.get_widget(
            "progressbar_test_mirror")
        self.combobox = self.gladexml.get_widget("combobox_mirror_proto")
        self.progress = self.gladexml.get_widget("progressbar_test_mirror")
        self.label_action = self.gladexml.get_widget("label_test_mirror")

        # store each proto and its dir
        model_proto = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
        self.combobox.set_model(model_proto)

        self.model = gtk.TreeStore(
            gobject.TYPE_STRING,  # COLUMN_URI
            gobject.TYPE_BOOLEAN,  # COLUMN_SEPARATOR
            gobject.TYPE_BOOLEAN,  # COLUMN_CUSTOM
            gobject.TYPE_PYOBJECT)  # COLUMN_MIRROR
        self.treeview.set_row_separator_func(is_separator)
        self.model_sort = gtk.TreeModelSort(self.model)
        self.model_sort.set_default_sort_func(sort_mirrors)

        self.distro = distro

        self.treeview.set_model(self.model_sort)
        # the cell renderer for the mirror uri
        self.renderer_mirror = gtk.CellRendererText()
        self.renderer_mirror.connect('edited', self.on_edited_custom_mirror,
                                     self.model)
        # the visible column that holds the mirror uris
        self.column_mirror = gtk.TreeViewColumn("URI",
                                                self.renderer_mirror,
                                                text=COLUMN_URI)
        self.treeview.append_column(self.column_mirror)

        # used to find the corresponding iter of a location
        map_loc = {}
        patriot = None
        model = self.treeview.get_model().get_model()
        # at first add all custom mirrors and a separator
        if len(self.custom_mirrors) > 0:
            for mirror in self.custom_mirrors:
                model.append(None, [mirror, False, True, None])
                self.column_mirror.add_attribute(self.renderer_mirror,
                                                 "editable", COLUMN_CUSTOM)
            model.append(None, [None, True, False, None])
        # secondly add all official mirrors
        for hostname in self.distro.source_template.mirror_set.keys():
            mirror = self.distro.source_template.mirror_set[hostname]
            if map_loc.has_key(mirror.location):
                model.append(map_loc[mirror.location],
                             [hostname, False, False, mirror])
            elif mirror.location != None:
                parent = model.append(None, [
                    self.country_info.get_country_name(mirror.location), False,
                    False, None
                ])
                if mirror.location == self.country_info.code and patriot == None:
                    patriot = parent
                model.append(parent, [hostname, False, False, mirror]),
                map_loc[mirror.location] = parent
            else:
                model.append(None, [hostname, False, False, mirror])
        # Scroll to the local mirror set
        if patriot != None:
            path_sort = self.model_sort.get_path(
                self.model_sort.convert_child_iter_to_iter(None, patriot))
            self.treeview.expand_row(path_sort, False)
            self.treeview.set_cursor(path_sort)
            self.treeview.scroll_to_cell(path_sort,
                                         use_align=True,
                                         row_align=0.5)
Beispiel #11
0
class DialogMirror:
    def __init__(self, parent, datadir, distro, custom_mirrors):
        """
    Initialize the dialog that allows to choose a custom or official mirror
    """
        def is_separator(model, iter, data=None):
            return model.get_value(iter, COLUMN_SEPARATOR)

        self.custom_mirrors = custom_mirrors

        self.country_info = CountryInformation()

        self.gladexml = gtk.glade.XML("%s/glade/dialogs.glade" %\
                                      datadir)
        self.gladexml.signal_autoconnect(self)
        self.dialog = self.gladexml.get_widget("dialog_mirror")
        self.dialog.set_transient_for(parent)
        self.dialog_test = self.gladexml.get_widget("dialog_mirror_test")
        self.dialog_test.set_transient_for(self.dialog)
        self.distro = distro
        self.treeview = self.gladexml.get_widget("treeview_mirrors")
        self.button_edit = self.gladexml.get_widget("button_mirror_edit")
        self.button_remove = self.gladexml.get_widget("button_mirror_remove")
        self.button_choose = self.gladexml.get_widget("button_mirror_choose")
        self.button_cancel = self.gladexml.get_widget("button_test_cancel")
        self.label_test = self.gladexml.get_widget("label_test_mirror")
        self.progressbar_test = self.gladexml.get_widget(
            "progressbar_test_mirror")
        self.combobox = self.gladexml.get_widget("combobox_mirror_proto")
        self.progress = self.gladexml.get_widget("progressbar_test_mirror")
        self.label_action = self.gladexml.get_widget("label_test_mirror")

        # store each proto and its dir
        model_proto = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
        self.combobox.set_model(model_proto)

        self.model = gtk.TreeStore(
            gobject.TYPE_STRING,  # COLUMN_URI
            gobject.TYPE_BOOLEAN,  # COLUMN_SEPARATOR
            gobject.TYPE_BOOLEAN,  # COLUMN_CUSTOM
            gobject.TYPE_PYOBJECT)  # COLUMN_MIRROR
        self.treeview.set_row_separator_func(is_separator)
        self.model_sort = gtk.TreeModelSort(self.model)
        self.model_sort.set_default_sort_func(sort_mirrors)

        self.distro = distro

        self.treeview.set_model(self.model_sort)
        # the cell renderer for the mirror uri
        self.renderer_mirror = gtk.CellRendererText()
        self.renderer_mirror.connect('edited', self.on_edited_custom_mirror,
                                     self.model)
        # the visible column that holds the mirror uris
        self.column_mirror = gtk.TreeViewColumn("URI",
                                                self.renderer_mirror,
                                                text=COLUMN_URI)
        self.treeview.append_column(self.column_mirror)

        # used to find the corresponding iter of a location
        map_loc = {}
        patriot = None
        model = self.treeview.get_model().get_model()
        # at first add all custom mirrors and a separator
        if len(self.custom_mirrors) > 0:
            for mirror in self.custom_mirrors:
                model.append(None, [mirror, False, True, None])
                self.column_mirror.add_attribute(self.renderer_mirror,
                                                 "editable", COLUMN_CUSTOM)
            model.append(None, [None, True, False, None])
        # secondly add all official mirrors
        for hostname in self.distro.source_template.mirror_set.keys():
            mirror = self.distro.source_template.mirror_set[hostname]
            if map_loc.has_key(mirror.location):
                model.append(map_loc[mirror.location],
                             [hostname, False, False, mirror])
            elif mirror.location != None:
                parent = model.append(None, [
                    self.country_info.get_country_name(mirror.location), False,
                    False, None
                ])
                if mirror.location == self.country_info.code and patriot == None:
                    patriot = parent
                model.append(parent, [hostname, False, False, mirror]),
                map_loc[mirror.location] = parent
            else:
                model.append(None, [hostname, False, False, mirror])
        # Scroll to the local mirror set
        if patriot != None:
            path_sort = self.model_sort.get_path(
                self.model_sort.convert_child_iter_to_iter(None, patriot))
            self.treeview.expand_row(path_sort, False)
            self.treeview.set_cursor(path_sort)
            self.treeview.scroll_to_cell(path_sort,
                                         use_align=True,
                                         row_align=0.5)

    def on_edited_custom_mirror(self, cell, path, new_text, model):
        ''' Check if the new mirror uri is faild, if yes change it, if not
        remove the mirror from the list '''
        iter = model.get_iter(path)
        iter_next = model.iter_next(iter)
        if new_text != "":
            model.set_value(iter, COLUMN_URI, new_text)
            # Add a separator if the next mirror is a not a separator or
            # a custom one
            if iter_next != None and not \
               (model.get_value(iter_next, COLUMN_SEPARATOR) or \
                model.get_value(iter_next, COLUMN_CUSTOM)):
                model.insert(1, [None, True, False])
            self.button_choose.set_sensitive(self.is_valid_mirror(new_text))
        else:
            model.remove(iter)
            # Remove the separator if this was the last custom mirror
            if model.get_value(model.get_iter_first(), COLUMN_SEPARATOR):
                model.remove(model.get_iter_first())
            self.treeview.set_cursor((0, ))
        return

    def is_valid_mirror(self, uri):
        ''' Check if a given uri is a vaild one '''
        if uri == None:
            return False
        elif re.match(
                "^((ftp)|(http)|(file)|(rsync)|(https))://([a-z]|[A-Z]|[0-9]|:|/|\.|~)+$",
                uri) == None:
            return False
        else:
            return True

    def on_treeview_mirrors_cursor_changed(self, treeview, data=None):
        ''' Check if the currently selected row in the mirror list
        contains a mirror and or is editable '''
        (row, column) = treeview.get_cursor()
        if row == None:
            self.button_remove.set_sensitive(False)
            self.button_edit.set_sensitive(False)
            self.button_choose.set_sensitive(False)
            return
        model = treeview.get_model()
        iter = model.get_iter(row)
        # Update the list of available protocolls
        mirror = model.get_value(iter, COLUMN_MIRROR)
        model_protos = self.combobox.get_model()
        model_protos.clear()
        if mirror != None:
            self.combobox.set_sensitive(True)
            seen_protos = []
            for repo in mirror.repositories:
                # Only add a repository for a protocoll once
                if repo.proto in seen_protos:
                    continue
                seen_protos.append(repo.proto)
                model_protos.append(repo.get_info())
            self.combobox.set_active(0)
            self.button_choose.set_sensitive(True)
        else:
            # Allow to edit and remove custom mirrors
            self.button_remove.set_sensitive(
                model.get_value(iter, COLUMN_CUSTOM))
            self.button_edit.set_sensitive(model.get_value(
                iter, COLUMN_CUSTOM))
            self.button_choose.set_sensitive(
                self.is_valid_mirror(model.get_value(iter, COLUMN_URI)))
            self.combobox.set_sensitive(False)

    def on_button_mirror_remove_clicked(self, button, data=None):
        ''' Remove the currently selected mirror '''
        path, column = self.treeview.get_cursor()
        iter = self.treeview.get_model().get_iter(path)
        model = self.treeview.get_model().get_model()
        model.remove(iter)
        # Remove the separator if this was the last custom mirror
        if model.get_value(model.get_iter_first(), COLUMN_SEPARATOR):
            model.remove(model.get_iter_first())
        self.treeview.set_cursor((0, ))

    def on_button_mirror_add_clicked(self, button, data=None):
        ''' Add a new mirror at the beginning of the list and start
        editing '''
        model = self.treeview.get_model().get_model()
        model.append(None, [_("New mirror"), False, True, None])
        self.treeview.grab_focus()
        self.treeview.set_cursor((0, ),
                                 focus_column=self.column_mirror,
                                 start_editing=True)

    def on_button_mirror_edit_clicked(self, button, data=None):
        ''' Grab the focus and start editing the currently selected mirror '''
        path, column = self.treeview.get_cursor()
        self.treeview.grab_focus()
        self.treeview.set_cursor(path, focus_column=column, start_editing=True)

    def on_dialog_mirror_test_delete_event(self, dialog, event, data=None):
        ''' If anybody wants to close the dialog, stop the test before '''
        self.on_button_cancel_test_clicked(None)
        return True

    def run(self):
        ''' Run the chooser dialog and return the chosen mirror or None '''
        res = self.dialog.run()
        self.dialog.hide()

        (row, column) = self.treeview.get_cursor()
        model = self.treeview.get_model()
        iter = model.get_iter(row)
        mirror = model.get_value(iter, COLUMN_MIRROR)

        # FIXME: we should also return the list of custom servers
        if res == gtk.RESPONSE_OK:
            if mirror == None:
                # Return the URL of the selected custom mirror
                return model.get_value(iter, COLUMN_URI)
            else:
                # Return an URL created from the hostname and the selected
                # repository
                model_proto = self.combobox.get_model()
                iter_proto = model_proto.get_iter(self.combobox.get_active())
                proto = model_proto.get_value(iter_proto, COLUMN_PROTO)
                dir = model_proto.get_value(iter_proto, COLUMN_DIR)
                return "%s://%s/%s" % (proto, mirror.hostname, dir)
        else:
            return None

    @threaded
    def on_button_test_clicked(self, button, data=None):
        ''' Perform a test to find the best mirror and select it 
        afterwards in the treeview '''
        class MirrorTestGtk(MirrorTest):
            def __init__(self, mirrors, test_file, running, progressbar,
                         label):
                MirrorTest.__init__(self, mirrors, test_file, running)
                self.progress = progressbar
                self.label = label

            def report_action(self, text):
                gtk.gdk.threads_enter()
                self.label.set_label(str("<i>%s</i>" % text))
                gtk.gdk.threads_leave()

            def report_progress(self, current, max, borders=(0, 1),
                                mod=(0, 0)):
                gtk.gdk.threads_enter()
                self.progress.set_text(_("Completed %s of %s tests") % \
                                       (current + mod[0], max + mod[1]))
                frac = borders[0] + (borders[1] - borders[0]) / max * current
                self.progress.set_fraction(frac)
                gtk.gdk.threads_leave()

            def run_full_test(self):
                # Determinate the 5 top ping servers
                results_ping = self.run_ping_test(max=5,
                                                  borders=(0, 0.5),
                                                  mod=(0, 7))
                # Add two random mirrors to the download test
                results_ping.append(
                    [0, 0, self.mirrors[random.randint(1, len(self.mirrors))]])
                results_ping.append(
                    [0, 0, self.mirrors[random.randint(1, len(self.mirrors))]])
                results = self.run_download_test(map(lambda r: r[2],
                                                     results_ping),
                                                 borders=(0.5, 1),
                                                 mod=(MirrorTest.todo,
                                                      MirrorTest.todo))
                for (t, h) in results:
                    print "mirror: %s - time: %s" % (h.hostname, t)
                if len(results) == 0:
                    return None
                else:
                    return results[0][1].hostname

        gtk.gdk.threads_enter()
        self.button_cancel.set_sensitive(True)
        self.dialog_test.show()
        gtk.gdk.threads_leave()
        self.running = threading.Event()
        self.running.set()
        pipe = os.popen("dpkg --print-architecture")
        arch = pipe.read().strip()
        test_file = "dists/%s/%s/binary-%s/Packages.gz" % \
                     (self.distro.source_template.name,
                      self.distro.source_template.components[0].name,
                      arch)
        test = MirrorTestGtk(self.distro.source_template.mirror_set.values(),
                             test_file, self.running, self.progress,
                             self.label_action)
        test.start()
        rocker = test.run_full_test()
        gtk.gdk.threads_enter()
        testing.clear()
        self.dialog_test.hide()
        # Select the mirror in the list or show an error dialog
        if rocker != None:
            self.model_sort.foreach(self.select_mirror, rocker)
        else:
            dialogs.show_error_dialog(
                self.dialog, _("No suitable download server was found"),
                _("Please check your Internet connection."))
        gtk.gdk.threads_leave()

    def select_mirror(self, model, path, iter, mirror):
        """Select and expand the path to a matching mirror in the list"""
        if model.get_value(iter, COLUMN_URI) == mirror:
            self.treeview.expand_to_path(path)
            self.treeview.set_cursor(path)
            self.treeview.scroll_to_cell(path, use_align=True, row_align=0.5)
            self.treeview.grab_focus()
            # breaks foreach
            return True

    def on_button_cancel_test_clicked(self, button):
        ''' Abort the mirror performance test '''
        self.running.clear()
        self.label_test.set_label("<i>%s</i>" % _("Canceling..."))
        self.button_cancel.set_sensitive(False)
        self.progressbar_test.set_fraction(1)