Merge lp:~system76-dev/ubiquity/trunk into lp:ubiquity

Proposed by Jeremy Soller
Status: Merged
Merged at revision: 6540
Proposed branch: lp:~system76-dev/ubiquity/trunk
Merge into: lp:ubiquity
Diff against target: 419 lines (+103/-110)
7 files modified
d-i/manifest (+5/-3)
debian/changelog (+6/-0)
debian/control (+1/-1)
tests/test_wireless.py (+1/-18)
ubiquity/frontend/gtk_components/nmwidgets.py (+83/-77)
ubiquity/frontend/kde_components/nmwidgets.py (+7/-1)
ubiquity/plugins/ubi-wireless.py (+0/-10)
To merge this branch: bzr merge lp:~system76-dev/ubiquity/trunk
Reviewer Review Type Date Requested Status
Mathieu Trudel-Lapierre Needs Information
Review via email: mp+319142@code.launchpad.net

Description of the change

- Add WPA-2 enterprise support using libnm-gtk
- Remove password box from GTK installer, using libnm-gtk for any secure connections

This patch to `libnm-gtk` must also be applied: https://bugs.launchpad.net/ubuntu/+source/network-manager-applet/+bug/1667129

To post a comment you must log in.
lp:~system76-dev/ubiquity/trunk updated
6525. By Jeremy Soller

Switch to using libnma

6526. By Jeremy Soller

Fixes for use of libnma

6527. By Jeremy Soller

Change RemoteConnection to SimpleConnection

Revision history for this message
Mathieu Trudel-Lapierre (cyphermox) wrote :

Looks fine to me code-wise; now I'll merge and review functionally.

Revision history for this message
Mathieu Trudel-Lapierre (cyphermox) wrote :

How did you test this? I've built this in my PPA, and installing it on a live session leads to ubiquity not starting the wireless panel at all (I expected it to still show a list of wireless networks).

review: Needs Information
lp:~system76-dev/ubiquity/trunk updated
6528. By Jeremy Soller

Merge

6529. By Jeremy Soller

Update changelog

Revision history for this message
Jeremy Soller (jackpot51) wrote :

cyphermox, the wireless network page is skipped if you are connected to a wired network.

lp:~system76-dev/ubiquity/trunk updated
6530. By Jeremy Soller

Merge

6531. By Jeremy Soller

Update changelog

6532. By Jeremy Soller

Revert manifest to zesty versions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'd-i/manifest'
--- d-i/manifest 2017-04-07 14:17:15 +0000
+++ d-i/manifest 2017-06-22 16:34:36 +0000
@@ -1,15 +1,15 @@
1apt-setup 1:0.104ubuntu51apt-setup 1:0.104ubuntu5
2base-installer 1.158ubuntu42base-installer 1.158ubuntu4
3bterm-unifont 1.43bterm-unifont 1.4
4choose-mirror 2.78ubuntu14choose-mirror 2.75ubuntu1
5clock-setup 0.131ubuntu15clock-setup 0.131ubuntu1
6console-setup 1.142ubuntu56console-setup 1.142ubuntu5
7debian-installer-utils 1.113ubuntu17debian-installer-utils 1.113ubuntu1
8flash-kernel 3.0~rc.4ubuntu658flash-kernel 3.0~rc.4ubuntu65
9grub-installer 1.128ubuntu79grub-installer 1.128ubuntu7
10hw-detect 1.117ubuntu410hw-detect 1.117ubuntu3
11localechooser 2.65ubuntu411localechooser 2.65ubuntu4
12netcfg 1.138ubuntu512netcfg 1.138ubuntu4
13partconf 1.5013partconf 1.50
14partman-auto 134ubuntu614partman-auto 134ubuntu6
15partman-auto-crypto 22ubuntu115partman-auto-crypto 22ubuntu1
@@ -24,6 +24,7 @@
24partman-ext3 86ubuntu124partman-ext3 86ubuntu1
25partman-jfs 4725partman-jfs 47
26partman-lvm 11326partman-lvm 113
27partman-newworld 34
27partman-partitioning 114ubuntu228partman-partitioning 114ubuntu2
28partman-swapfile 129partman-swapfile 1
29partman-target 98ubuntu130partman-target 98ubuntu1
@@ -32,3 +33,4 @@
32preseed 1.71ubuntu433preseed 1.71ubuntu4
33tzsetup 1:0.81ubuntu134tzsetup 1:0.81ubuntu1
34user-setup 1.63ubuntu435user-setup 1.63ubuntu4
36yaboot-installer 1.1.36ubuntu1
3537
=== modified file 'debian/changelog'
--- debian/changelog 2017-04-10 02:36:04 +0000
+++ debian/changelog 2017-06-22 16:34:36 +0000
@@ -1,3 +1,9 @@
1ubiquity (17.04.10~system76~1) zesty; urgency=medium
2
3 * Fix for crashes when selecting a WPA 2 enterprise network
4
5 -- Jeremy Soller <jeremy@system76.com> Fri, 16 Jun 2017 09:55:28 -0600
6
1ubiquity (17.04.9) zesty; urgency=medium7ubiquity (17.04.9) zesty; urgency=medium
28
3 * tests/test_misc.py: Really fix test for the 'ta' keymap: check for9 * tests/test_misc.py: Really fix test for the 'ta' keymap: check for
410
=== modified file 'debian/control'
--- debian/control 2016-09-26 19:16:34 +0000
+++ debian/control 2017-06-22 16:34:36 +0000
@@ -45,7 +45,7 @@
45Package: ubiquity-frontend-gtk45Package: ubiquity-frontend-gtk
46Architecture: amd64 arm64 armhf i386 powerpc ppc64el46Architecture: amd64 arm64 armhf i386 powerpc ppc64el
47Pre-Depends: ${misc:Pre-Depends}47Pre-Depends: ${misc:Pre-Depends}
48Depends: ${shlibs:Depends}, ${misc:Depends}, ${python3:Depends}, ubiquity (= ${binary:Version}), python3-dbus, gir1.2-gtk-3.0 (>= 3.20), gir1.2-pango-1.0, gir1.2-soup-2.4, gir1.2-vte-2.91, gir1.2-webkit2-4.0, iso-codes, metacity | marco | xfwm4 | matchbox-window-manager | lubuntu-default-settings | openbox | gnome-shell, gir1.2-xkl-1.0, gir1.2-timezonemap-1.0, python3-gi, python3-cairo, python3-gi-cairo, gir1.2-appindicator3-0.1, busybox-static | busybox48Depends: ${shlibs:Depends}, ${misc:Depends}, ${python3:Depends}, ubiquity (= ${binary:Version}), python3-dbus, gir1.2-gtk-3.0 (>= 3.20), gir1.2-nma-1.0, gir1.2-pango-1.0, gir1.2-soup-2.4, gir1.2-vte-2.91, gir1.2-webkit2-4.0, iso-codes, metacity | marco | xfwm4 | matchbox-window-manager | lubuntu-default-settings | openbox | gnome-shell, gir1.2-xkl-1.0, gir1.2-timezonemap-1.0, python3-gi, python3-cairo, python3-gi-cairo, gir1.2-appindicator3-0.1, busybox-static | busybox
49Suggests: gnome-control-center | feh49Suggests: gnome-control-center | feh
50Conflicts: ubuntu-express-frontend-gtk, espresso-frontend-gtk, ubiquity (<< 2.4.3)50Conflicts: ubuntu-express-frontend-gtk, espresso-frontend-gtk, ubiquity (<< 2.4.3)
51Replaces: ubuntu-express-frontend-gtk, espresso-frontend-gtk, ubiquity (<< 2.4.3)51Replaces: ubuntu-express-frontend-gtk, espresso-frontend-gtk, ubiquity (<< 2.4.3)
5252
=== modified file 'tests/test_wireless.py'
--- tests/test_wireless.py 2012-07-16 14:29:13 +0000
+++ tests/test_wireless.py 2017-06-22 16:34:36 +0000
@@ -4,7 +4,7 @@
44
5import mock5import mock
66
7from ubiquity import gtkwidgets, nm, plugin_manager7from ubiquity import nm, plugin_manager
88
99
10class WirelessTests(unittest.TestCase):10class WirelessTests(unittest.TestCase):
@@ -22,20 +22,3 @@
22 self.manager = self.nmwidget.view.wifi_model22 self.manager = self.nmwidget.view.wifi_model
23 self.model = self.manager.model23 self.model = self.manager.model
24 self.manager.passphrases_cache = {}24 self.manager.passphrases_cache = {}
25
26 @mock.patch('ubiquity.nm.NetworkManager.is_connected')
27 def test_secure_ap_can_enter_password(self, is_connected):
28 is_connected.return_value = False
29 iterator = self.model.append(None, ['/foo', 'Intel', 'Wireless'])
30 iterator_insecure = self.model.append(iterator, ['Insecure', False, 0])
31 iterator_secure = self.model.append(iterator, ['Secure', True, 0])
32 gtkwidgets.refresh()
33 self.assertFalse(self.nmwidget.hbox.get_sensitive())
34 self.nmwidget.view.set_cursor(
35 self.model.get_path(iterator_secure), None, False)
36 gtkwidgets.refresh()
37 self.assertTrue(self.nmwidget.hbox.get_sensitive())
38 self.nmwidget.view.set_cursor(
39 self.model.get_path(iterator_insecure), None, False)
40 gtkwidgets.refresh()
41 self.assertFalse(self.nmwidget.hbox.get_sensitive())
4225
=== modified file 'ubiquity/frontend/gtk_components/nmwidgets.py'
--- ubiquity/frontend/gtk_components/nmwidgets.py 2016-12-01 14:00:11 +0000
+++ ubiquity/frontend/gtk_components/nmwidgets.py 2017-06-22 16:34:36 +0000
@@ -1,11 +1,10 @@
1import string
2
3from dbus.mainloop.glib import DBusGMainLoop1from dbus.mainloop.glib import DBusGMainLoop
4DBusGMainLoop(set_as_default=True)2DBusGMainLoop(set_as_default=True)
53
6from gi.repository import Gtk, GObject, GLib4from gi.repository import Gtk, GObject, GLib
5from gi.repository import NM, NMA
76
8from ubiquity.nm import QueuedCaller, NetworkStore, NetworkManager7from ubiquity.nm import decode_ssid, QueuedCaller, NetworkStore, NetworkManager
98
109
11class GLibQueuedCaller(QueuedCaller):10class GLibQueuedCaller(QueuedCaller):
@@ -92,9 +91,8 @@
92class NetworkManagerTreeView(Gtk.TreeView):91class NetworkManagerTreeView(Gtk.TreeView):
93 __gtype_name__ = 'NetworkManagerTreeView'92 __gtype_name__ = 'NetworkManagerTreeView'
9493
95 def __init__(self, password_entry=None, state_changed=None):94 def __init__(self, state_changed=None):
96 Gtk.TreeView.__init__(self)95 Gtk.TreeView.__init__(self)
97 self.password_entry = password_entry
98 self.configure_icons()96 self.configure_icons()
99 model = GtkNetworkStore()97 model = GtkNetworkStore()
100 model.set_sort_column_id(0, Gtk.SortType.ASCENDING)98 model.set_sort_column_id(0, Gtk.SortType.ASCENDING)
@@ -102,6 +100,10 @@
102 self.wifi_model = NetworkManager(model,100 self.wifi_model = NetworkManager(model,
103 GLibQueuedCaller,101 GLibQueuedCaller,
104 state_changed)102 state_changed)
103
104 self.nm_client = None
105 self.nm_connection = None
106
105 self.set_model(model)107 self.set_model(model)
106108
107 ssid_column = Gtk.TreeViewColumn('')109 ssid_column = Gtk.TreeViewColumn('')
@@ -157,17 +159,21 @@
157 self.expand_row(path, False)159 self.expand_row(path, False)
158 i = model.iter_next(i)160 i = model.iter_next(i)
159161
162 def row_activated(self, unused, path, column):
163 self.connect_to_selection()
164
160 def get_state(self):165 def get_state(self):
161 return self.wifi_model.get_state()166 return self.wifi_model.get_state()
162167
163 def disconnect_from_ap(self):168 def disconnect_from_ap(self):
164 self.wifi_model.disconnect_from_ap()169 if self.nm_connection:
170 if not self.nm_client:
171 self.nm_client = NM.Client.new()
165172
166 def row_activated(self, unused, path, column):173 self.nm_client.deactivate_connection(self.nm_connection)
167 passphrase = None174 self.nm_connection = None
168 if self.password_entry:175 else:
169 passphrase = self.password_entry.get_text()176 self.wifi_model.disconnect_from_ap()
170 self.connect_to_selection(passphrase)
171177
172 def configure_icons(self):178 def configure_icons(self):
173 it = Gtk.IconTheme()179 it = Gtk.IconTheme()
@@ -220,13 +226,6 @@
220 else:226 else:
221 cell.set_property('text', ssid)227 cell.set_property('text', ssid)
222228
223 def get_passphrase(self, ssid):
224 try:
225 cached = self.wifi_model.passphrases_cache[ssid]
226 except KeyError:
227 return ''
228 return cached
229
230 def is_row_an_ap(self):229 def is_row_an_ap(self):
231 model, iterator = self.get_selection().get_selected()230 model, iterator = self.get_selection().get_selected()
232 if iterator is None:231 if iterator is None:
@@ -244,12 +243,72 @@
244 else:243 else:
245 return False244 return False
246245
247 def connect_to_selection(self, passphrase):246 def find_ap(self, device, ssid):
247 for ap in device.get_access_points():
248 ap_ssid = ap.get_ssid()
249 if ap_ssid and decode_ssid(ap_ssid.get_data()) == ssid:
250 return ap
251 return None
252
253 def connect_cb(self, client, result, user_data):
254 self.nm_connection = client.add_and_activate_connection_finish(result)
255
256 def connect_dialog_cb(self, dialog, response):
257 if response == Gtk.ResponseType.OK:
258 connection, device, ap = dialog.get_connection()
259
260 if not self.nm_client:
261 self.nm_client = NM.Client.new()
262
263 self.nm_client.add_and_activate_connection_async(
264 connection, device, None, None, self.connect_cb, None
265 )
266 dialog.hide()
267
268 def connect_to_selection(self):
248 model, iterator = self.get_selection().get_selected()269 model, iterator = self.get_selection().get_selected()
249 ssid = model[iterator][0]270 if iterator is None:
271 return
250 parent = model.iter_parent(iterator)272 parent = model.iter_parent(iterator)
251 if parent:273 if parent:
252 self.wifi_model.connect_to_ap(model[parent][0], ssid, passphrase)274 try:
275 devid = model[parent][0]
276 ssid = model[iterator][0]
277 if model[iterator][1]:
278 if not self.nm_client:
279 self.nm_client = NM.Client.new()
280
281 device = self.nm_client.get_device_by_path(devid)
282 ap = self.find_ap(device, ssid)
283
284 connection = NM.SimpleConnection()
285 connection.add_setting(NM.SettingConnection(
286 uuid=NM.utils_uuid_generate()
287 ))
288 connection.add_setting(NM.SettingWireless(
289 ssid=ap.get_property("ssid")
290 ))
291
292 dialog = NMA.WifiDialog.new(
293 self.nm_client,
294 connection,
295 device,
296 ap,
297 False
298 )
299 dialog.connect("response", self.connect_dialog_cb)
300 dialog.run()
301 else:
302 self.wifi_model.connect_to_ap(devid, ssid)
303 except Exception as e:
304 dialog = Gtk.MessageDialog(
305 None, Gtk.DialogFlags.MODAL,
306 Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE,
307 "Failed to connect to wireless network"
308 )
309 dialog.format_secondary_text("{}".format(e))
310 dialog.run()
311 dialog.hide()
253312
254313
255GObject.type_register(NetworkManagerTreeView)314GObject.type_register(NetworkManagerTreeView)
@@ -262,44 +321,23 @@
262 GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE,321 GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE,
263 (GObject.TYPE_UINT,)),322 (GObject.TYPE_UINT,)),
264 'selection_changed': (323 'selection_changed': (
265 GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, ()),324 GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, ())}
266 'pw_validated': (
267 GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE,
268 (GObject.TYPE_BOOLEAN,))}
269325
270 def __init__(self):326 def __init__(self):
271 Gtk.Box.__init__(self)327 Gtk.Box.__init__(self)
272 self.set_orientation(Gtk.Orientation.VERTICAL)328 self.set_orientation(Gtk.Orientation.VERTICAL)
273 self.set_spacing(12)329 self.set_spacing(12)
274 self.password_entry = Gtk.Entry()330 self.view = NetworkManagerTreeView(self.state_changed)
275 self.view = NetworkManagerTreeView(self.password_entry,
276 self.state_changed)
277 scrolled_window = Gtk.ScrolledWindow()331 scrolled_window = Gtk.ScrolledWindow()
278 scrolled_window.set_policy(332 scrolled_window.set_policy(
279 Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)333 Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
280 scrolled_window.set_shadow_type(Gtk.ShadowType.IN)334 scrolled_window.set_shadow_type(Gtk.ShadowType.IN)
281 scrolled_window.add(self.view)335 scrolled_window.add(self.view)
282 self.pack_start(scrolled_window, True, True, 0)336 self.pack_start(scrolled_window, True, True, 0)
283 self.hbox = Gtk.Box(spacing=6)
284 self.pack_start(self.hbox, False, True, 0)
285 self.password_label = Gtk.Label(label='Password:')
286 self.password_entry.set_visibility(False)
287 self.password_entry.connect('activate', self.connect_to_ap)
288 self.password_entry.connect('changed', self.password_entry_changed)
289 self.display_password = Gtk.CheckButton(label='Display password')
290 self.display_password.connect('toggled', self.display_password_toggled)
291 self.hbox.pack_start(self.password_label, False, True, 0)
292 self.hbox.pack_start(self.password_entry, True, True, 0)
293 self.hbox.pack_start(self.display_password, False, True, 0)
294 self.hbox.set_sensitive(False)
295 self.selection = self.view.get_selection()337 self.selection = self.view.get_selection()
296 self.selection.connect('changed', self.changed)338 self.selection.connect('changed', self.changed)
297 self.show_all()339 self.show_all()
298340
299 def translate(self, password_label_text, display_password_text):
300 self.password_label.set_label(password_label_text)
301 self.display_password.set_label(display_password_text)
302
303 def get_state(self):341 def get_state(self):
304 return self.view.get_state()342 return self.view.get_state()
305343
@@ -315,48 +353,16 @@
315 def state_changed(self, state):353 def state_changed(self, state):
316 self.emit('connection', state)354 self.emit('connection', state)
317355
318 def password_is_valid(self):
319 passphrase = self.password_entry.get_text()
320 if len(passphrase) >= 8 and len(passphrase) < 64:
321 return True
322 if len(passphrase) == 64:
323 for c in passphrase:
324 if c not in string.hexdigits:
325 return False
326 return True
327 else:
328 return False
329
330 def connect_to_ap(self, *args):356 def connect_to_ap(self, *args):
331 if self.password_is_valid():357 self.view.connect_to_selection()
332 passphrase = self.password_entry.get_text()
333 self.view.connect_to_selection(passphrase)
334358
335 def disconnect_from_ap(self):359 def disconnect_from_ap(self):
336 self.view.disconnect_from_ap()360 self.view.disconnect_from_ap()
337361
338 def password_entry_changed(self, *args):
339 self.emit('pw_validated', self.password_is_valid())
340
341 def display_password_toggled(self, *args):
342 self.password_entry.set_visibility(self.display_password.get_active())
343
344 def changed(self, selection):362 def changed(self, selection):
345 iterator = selection.get_selected()[1]363 iterator = selection.get_selected()[1]
346 if not iterator:364 if not iterator:
347 return365 return
348 row = selection.get_tree_view().get_model()[iterator]
349 secure = row[1]
350 ssid = row[0]
351 if secure:
352 self.hbox.set_sensitive(True)
353 passphrase = self.view.get_passphrase(ssid)
354 self.password_entry.set_text(passphrase)
355 self.emit('pw_validated', False)
356 else:
357 self.hbox.set_sensitive(False)
358 self.password_entry.set_text('')
359 self.emit('pw_validated', True)
360 self.emit('selection_changed')366 self.emit('selection_changed')
361367
362368
363369
=== modified file 'ubiquity/frontend/kde_components/nmwidgets.py'
--- ubiquity/frontend/kde_components/nmwidgets.py 2016-10-06 14:29:28 +0000
+++ ubiquity/frontend/kde_components/nmwidgets.py 2017-06-22 16:34:36 +0000
@@ -272,7 +272,13 @@
272272
273 def connect_to_selection(self, passphrase):273 def connect_to_selection(self, passphrase):
274 devid, ssid = self._get_selected_row_ids()274 devid, ssid = self._get_selected_row_ids()
275 self.wifi_model.connect_to_ap(devid, ssid, passphrase)275 try:
276 self.wifi_model.connect_to_ap(devid, ssid, passphrase)
277 except Exception as e:
278 dialog = QtWidgets.QMessageBox()
279 dialog.setWindowTitle("Failed to connect to wireless network")
280 dialog.setText("{}".format(e))
281 dialog.exec_()
276282
277 def get_cached_passphrase(self):283 def get_cached_passphrase(self):
278 index = self.currentIndex()284 index = self.currentIndex()
279285
=== modified file 'ubiquity/plugins/ubi-wireless.py'
--- ubiquity/plugins/ubi-wireless.py 2016-10-06 03:27:02 +0000
+++ ubiquity/plugins/ubi-wireless.py 2017-06-22 16:34:36 +0000
@@ -84,7 +84,6 @@
84 self.nmwidget = builder.get_object('nmwidget')84 self.nmwidget = builder.get_object('nmwidget')
85 self.nmwidget.connect('connection', self.state_changed)85 self.nmwidget.connect('connection', self.state_changed)
86 self.nmwidget.connect('selection_changed', self.selection_changed)86 self.nmwidget.connect('selection_changed', self.selection_changed)
87 self.nmwidget.connect('pw_validated', self.pw_validated)
88 self.no_wireless = builder.get_object('no_wireless')87 self.no_wireless = builder.get_object('no_wireless')
89 self.use_wireless = builder.get_object('use_wireless')88 self.use_wireless = builder.get_object('use_wireless')
90 self.use_wireless.connect('toggled', self.wireless_toggled)89 self.use_wireless.connect('toggled', self.wireless_toggled)
@@ -99,10 +98,6 @@
9998
100 def plugin_translate(self, lang):99 def plugin_translate(self, lang):
101 get_s = self.controller.get_string100 get_s = self.controller.get_string
102 label_text = get_s('ubiquity/text/wireless_password_label')
103 display_text = get_s('ubiquity/text/wireless_display_password')
104 self.nmwidget.translate(label_text, display_text)
105
106 self.connect_text = get_s('ubiquity/text/connect', lang)101 self.connect_text = get_s('ubiquity/text/connect', lang)
107 self.stop_text = get_s('ubiquity/text/stop', lang)102 self.stop_text = get_s('ubiquity/text/stop', lang)
108 frontend = self.controller._wizard103 frontend = self.controller._wizard
@@ -141,7 +136,6 @@
141 frontend.connecting_spinner.stop()136 frontend.connecting_spinner.stop()
142 frontend.connecting_label.hide()137 frontend.connecting_label.hide()
143 frontend.translate_widget(frontend.next)138 frontend.translate_widget(frontend.next)
144 self.nmwidget.hbox.set_sensitive(False)
145 self.next_normal = True139 self.next_normal = True
146 self.controller.allow_go_forward(True)140 self.controller.allow_go_forward(True)
147141
@@ -179,7 +173,6 @@
179 frontend.connecting_spinner.hide()173 frontend.connecting_spinner.hide()
180 frontend.connecting_spinner.stop()174 frontend.connecting_spinner.stop()
181 frontend.connecting_label.hide()175 frontend.connecting_label.hide()
182 self.controller.allow_go_forward(True)
183176
184 frontend.translate_widget(frontend.back)177 frontend.translate_widget(frontend.back)
185 self.back_normal = True178 self.back_normal = True
@@ -196,9 +189,6 @@
196 frontend.back.set_sensitive(True)189 frontend.back.set_sensitive(True)
197 self.selection_changed(None)190 self.selection_changed(None)
198191
199 def pw_validated(self, unused, validated):
200 self.controller.allow_go_forward(validated)
201
202192
203class PageKde(WirelessPageBase):193class PageKde(WirelessPageBase):
204 plugin_breadcrumb = 'ubiquity/text/breadcrumb_wireless'194 plugin_breadcrumb = 'ubiquity/text/breadcrumb_wireless'

Subscribers

People subscribed via source and target branches

to status/vote changes: