1
# Qt 4 based frontend to software-properties
3
# Copyright (c) 2007 Canonical Ltd.
5
# Author: Jonathan Riddell <jriddell@ubuntu.com>
7
# This program is free software; you can redistribute it and/or
8
# modify it under the terms of the GNU General Public License as
9
# published by the Free Software Foundation; either version 2 of the
10
# License, or (at your option) any later version.
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
17
# You should have received a copy of the GNU General Public License
18
# along with this program; if not, write to the Free Software
19
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22
from __future__ import absolute_import, print_function
24
from gettext import gettext as _
28
from softwareproperties.MirrorTest import MirrorTest
29
from .I18nHelper import *
31
from PyQt5.QtCore import *
32
from PyQt5.QtGui import *
35
from softwareproperties.CountryInformation import CountryInformation
37
class DialogMirror(QDialog):
40
test_start = pyqtSignal()
41
test_end = pyqtSignal('QString')
42
report_progress = pyqtSignal(int, int, tuple, tuple)
43
report_action = pyqtSignal('QString')
45
def __init__(self, parent, datadir, distro, custom_mirrors):
47
Initialize the dialog that allows to choose a custom or official mirror
49
QDialog.__init__(self, parent)
50
uic.loadUi("%s/designer/dialog_mirror.ui" % datadir, self)
53
self.custom_mirrors = custom_mirrors
55
self.country_info = CountryInformation()
57
self.button_choose = self.buttonBox.button(QDialogButtonBox.Ok)
58
self.button_choose.setEnabled(False)
59
self.button_cancel = self.buttonBox.button(QDialogButtonBox.Cancel)
62
self.treeview.setColumnCount(1)
63
self.treeview.setHeaderLabels([_("Mirror")])
65
translate_widget(self)
66
# used to find the corresponding iter of a location
70
# at first add all custom mirrors and a separator
71
if len(self.custom_mirrors) > 0:
72
for mirror in self.custom_mirrors:
74
model.append(None, [mirror, False, True, None])
75
self.column_mirror.add_attribute(self.renderer_mirror,
78
model.append(None, [None, True, False, None])
81
# secondly add all official mirrors
82
for hostname in self.distro.source_template.mirror_set.keys():
83
mirror = self.distro.source_template.mirror_set[hostname]
84
if mirror.location in map_loc: # a mirror in a country
85
QTreeWidgetItem(map_loc[mirror.location], [hostname])
86
self.mirror_map[hostname] = mirror
87
elif mirror.location != None: # a country new to the list
88
country = self.country_info.get_country_name(mirror.location)
89
parent = QTreeWidgetItem([country])
90
self.mirror_map[country] = None
91
self.treeview.addTopLevelItem(parent)
92
QTreeWidgetItem(parent, [hostname])
93
self.mirror_map[hostname] = mirror
94
if mirror.location == self.country_info.code and patriot == None:
96
map_loc[mirror.location] = parent
97
else: # a mirror without country
98
item = QTreeWidgetItem([hostname])
99
self.treeview.addTopLevelItem(item)
100
self.treeview.sortItems(0, Qt.AscendingOrder)
101
# Scroll to the local mirror set
103
self.select_mirror(patriot.text(0))
104
self.treeview.itemClicked.connect(self.on_treeview_mirrors_cursor_changed)
105
self.button_find_server.clicked.connect(self.on_button_test_clicked)
106
self.edit_buttons_frame.hide() ##FIXME not yet implemented
108
def on_treeview_mirrors_cursor_changed(self, item, column):
109
""" Check if the currently selected row in the mirror list
110
contains a mirror and or is editable """
111
# Update the list of available protocolls
112
hostname = self.treeview.currentItem().text(0)
113
mirror = self.mirror_map[hostname]
114
self.combobox.clear()
116
self.combobox.setEnabled(True)
118
self.protocol_paths = {}
119
for repo in mirror.repositories:
120
# Only add a repository for a protocoll once
121
if repo.proto in seen_protos:
123
seen_protos.append(repo.proto)
124
self.protocol_paths[repo.get_info()[0]] = repo.get_info()[1]
125
self.combobox.addItem(repo.get_info()[0])
126
self.button_choose.setEnabled(True)
128
self.button_choose.setEnabled(False)
130
# Allow to edit and remove custom mirrors
131
self.button_remove.set_sensitive(model.get_value(iter, COLUMN_CUSTOM))
132
self.button_edit.set_sensitive(model.get_value(iter, COLUMN_CUSTOM))
133
self.button_choose.set_sensitive(self.is_valid_mirror(model.get_value(iter, COLUMN_URI)))
134
self.combobox.set_sensitive(False)
139
""" Run the chooser dialog and return the chosen mirror or None """
142
# FIXME: we should also return the list of custom servers
143
if res == QDialog.Accepted:
144
hostname = self.treeview.currentItem().text(0)
145
mirror = self.mirror_map[hostname]
148
# Return the URL of the selected custom mirror
149
print("Error, unknown mirror")
151
##FIXME return model.get_value(iter, COLUMN_URI)
153
# Return a URL created from the hostname and the selected
155
proto = self.combobox.currentText()
157
directory = self.protocol_paths[proto]
158
return "%s://%s/%s" % (proto, mirror.hostname, directory)
162
def on_button_test_clicked(self):
163
''' Perform a test to find the best mirror and select it
164
afterwards in the treeview '''
165
class MirrorTestQt(MirrorTest):
166
def __init__(self, mirrors, test_file, running, dialog, parent):
167
MirrorTest.__init__(self, mirrors, test_file, None, running)
171
def report_action(self, text):
172
if self.running.isSet():
173
self.parent.report_action.emit(text)
175
def report_progress(self, current, max, borders=(0,1), mod=(0,0)):
176
if self.running.isSet():
177
self.parent.report_progress.emit(current, max, borders, mod)
180
self.parent.test_start.emit()
181
rocker = self.run_full_test()
182
self.parent.test_end.emit(rocker)
184
self.dialog = QProgressDialog(_("Testing Mirrors"), _("Cancel"), 0, 100, self)
185
self.dialog.setWindowTitle(_("Testing Mirrors"))
186
self.dialog.setWindowModality(Qt.WindowModal)
187
self.button_cancel_test = QPushButton(_("Cancel"), self.dialog)
188
self.dialog.setCancelButton(self.button_cancel_test)
189
self.button_cancel_test.clicked.connect(self.on_button_cancel_test_clicked);
190
# the following signals are connected across threads
191
self.test_start.connect(self.on_test_start, Qt.BlockingQueuedConnection)
192
self.test_end.connect(self.on_test_end, Qt.BlockingQueuedConnection)
193
self.report_progress.connect(self.on_report_progress, Qt.BlockingQueuedConnection)
194
self.report_action.connect(self.on_report_action, Qt.BlockingQueuedConnection)
196
self.running = threading.Event()
198
pipe = os.popen("dpkg --print-architecture")
199
arch = pipe.read().strip()
200
test_file = "dists/%s/%s/binary-%s/Packages.gz" % \
201
(self.distro.source_template.name,
202
self.distro.source_template.components[0].name,
204
test = MirrorTestQt(list(self.distro.source_template.mirror_set.values()),
205
test_file, self.running, self.dialog, self)
206
test.start() # test starts in a separate thread
208
def on_test_start(self):
211
def on_test_end(self, mirror):
213
if not self.running.isSet():
214
return # canceled by user
216
self.select_mirror(mirror)
218
QMessageBox.warning(self.dialog, _("Testing Mirrors"),
219
_("No suitable download server was found") + "\n" +
220
_("Please check your Internet connection."))
222
def on_report_action(self, text):
223
self.dialog.setLabelText(str("<i>%s</i>" % text))
225
def on_report_progress(self, current, max, borders=(0,1), mod=(0,0)):
226
#self.dialog.setLabelText(_("Completed %s of %s tests") % \
227
# (current + mod[0], max + mod[1]))
228
frac = borders[0] + (borders[1] - borders[0]) / max * current
229
self.dialog.setValue(frac*100)
231
def on_button_cancel_test_clicked(self):
232
''' Abort the mirror performance test '''
235
self.dialog.setLabelText("<i>%s</i>" % _("Canceling..."))
236
self.button_cancel_test.setEnabled(False)
237
self.dialog.setValue(100)
239
def select_mirror(self, mirror):
240
"""Select and expand the path to a matching mirror in the list"""
241
found = self.treeview.findItems(mirror, Qt.MatchExactly|Qt.MatchRecursive)
243
found[0].setSelected(True)
244
self.treeview.setCurrentItem(found[0])
245
self.treeview.scrollToItem(found[0], QAbstractItemView.PositionAtCenter)
246
self.on_treeview_mirrors_cursor_changed(found[0], 0)
247
self.button_choose.setFocus()