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