Make most public strings in the GUI translatable
[wifi-radar.git] / wifiradar / gui / g2 / __init__.py
blob09d5f4e156918605d82d4b5cb410b9c7d5b0f094
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
4 # gui/g2/__init__.py - collection of classes for main UI with PyGTK
6 # Part of WiFi Radar: A utility for managing WiFi profiles on GNU/Linux.
8 # Copyright (C) 2004-2005 Ahmad Baitalmal <ahmad@baitalmal.com>
9 # Copyright (C) 2005 Nicolas Brouard <nicolas.brouard@mandrake.org>
10 # Copyright (C) 2005-2009 Brian Elliott Finley <brian@thefinleys.com>
11 # Copyright (C) 2006 David Decotigny <com.d2@free.fr>
12 # Copyright (C) 2006 Simon Gerber <gesimu@gmail.com>
13 # Copyright (C) 2006-2007 Joey Hurst <jhurst@lucubrate.org>
14 # Copyright (C) 2012 Anari Jalakas <anari.jalakas@gmail.com>
15 # Copyright (C) 2006, 2009 Ante Karamatic <ivoks@ubuntu.com>
16 # Copyright (C) 2009-2010,2014 Sean Robinson <seankrobinson@gmail.com>
17 # Copyright (C) 2010 Prokhor Shuchalov <p@shuchalov.ru>
19 # This program is free software; you can redistribute it and/or modify
20 # it under the terms of the GNU General Public License as published by
21 # the Free Software Foundation; version 2 of the License.
23 # This program is distributed in the hope that it will be useful,
24 # but WITHOUT ANY WARRANTY; without even the implied warranty of
25 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 # GNU General Public License in LICENSE.GPL for more details.
28 # You should have received a copy of the GNU General Public License
29 # along with this program; if not, write to the Free Software
30 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 import errno
35 import logging
36 import sys
38 import glib
39 import gtk
41 from wifiradar.config import make_section_name
42 import wifiradar.connections as connections
43 from wifiradar.misc import _, PipeError, get_new_profile
44 from wifiradar.pubsub import Message
45 from . import prefs
46 from . import profile as profile_ed
47 from . import transients
49 # create a logger
50 logger = logging.getLogger(__name__)
53 # Create a bunch of icons from files in the package.
54 known_profile_icon = gtk.gdk.pixbuf_new_from_file("pixmaps/known_profile.png")
55 unknown_profile_icon = gtk.gdk.pixbuf_new_from_file("pixmaps/unknown_profile.png")
56 signal_none_pb = gtk.gdk.pixbuf_new_from_file("pixmaps/signal_none.xpm")
57 signal_low_pb = gtk.gdk.pixbuf_new_from_file("pixmaps/signal_low.xpm")
58 signal_barely_pb = gtk.gdk.pixbuf_new_from_file("pixmaps/signal_barely.xpm")
59 signal_ok_pb = gtk.gdk.pixbuf_new_from_file("pixmaps/signal_ok.xpm")
60 signal_best_pb = gtk.gdk.pixbuf_new_from_file("pixmaps/signal_best.xpm")
62 def pixbuf_from_known(known):
63 """ Return a :class:`gtk.gdk.Pixbuf` icon to represent :data:`known`.
64 Any true :data:`known` value returns the icon showing previous
65 familiarity.
66 """
67 if known:
68 return known_profile_icon
69 return unknown_profile_icon
71 def pixbuf_from_signal(signal):
72 """ Return a :class:`gtk.gdk.Pixbuf` icon to indicate the :data:`signal`
73 level. :data:`signal` is as reported by iwlist (may be arbitrary
74 scale in 0-100 or -X dBm)
75 """
76 signal = int(signal)
77 # Shift signal up by 80 to convert dBm scale to arbitrary scale.
78 if signal < 0:
79 signal = signal + 80
80 # Find an icon...
81 if signal < 3:
82 return signal_none_pb
83 elif signal < 12:
84 return signal_low_pb
85 elif signal < 20:
86 return signal_barely_pb
87 elif signal < 35:
88 return signal_ok_pb
89 elif signal >= 35:
90 return signal_best_pb
92 def start(ui_pipe):
93 """ Function to boot-strap the UI. :data:`ui_pipe` is one half of a
94 :class:`multiprocessing.Pipe` which will be given to the main UI
95 element for intra-app communication.
96 """
97 gtk.gdk.threads_init()
98 ui = RadarWindow(ui_pipe)
99 ui.run()
100 with gtk.gdk.lock:
101 gtk.main()
104 class RadarWindow(gtk.Dialog, object):
105 def __init__(self, msg_pipe):
106 """ Create a new RadarWindow wanting to communicate through
107 :data:`msg_pipe`, a :class:`multiprocessing.Connection`.
109 gtk.Dialog.__init__(self, 'WiFi Radar', None, gtk.DIALOG_MODAL)
110 self.msg_pipe = msg_pipe
112 self.icon = gtk.gdk.pixbuf_new_from_file("pixmaps/wifi-radar.png")
114 self.set_icon(self.icon)
115 self.set_border_width(10)
116 self.set_size_request(550, 300)
117 self.connect('delete_event', self.delete_event)
118 # let's create all our widgets
119 self.current_network = gtk.Label()
120 self.current_network.set_property('justify', gtk.JUSTIFY_CENTER)
121 self.current_network.show()
122 self.close_button = gtk.Button(_('Close'), gtk.STOCK_CLOSE)
123 self.close_button.show()
124 self.close_button.connect('clicked', self.delete_event, None)
125 self.about_button = gtk.Button(_('About'), gtk.STOCK_ABOUT)
126 self.about_button.show()
127 self.about_button.connect('clicked', self.show_about_info, None)
128 self.preferences_button = gtk.Button(_('Preferences'), gtk.STOCK_PREFERENCES)
129 self.preferences_button.show()
130 self.preferences_button.connect('clicked', self.request_preferences_edit)
131 # essid bssid known_icon known available wep_icon signal_level mode protocol channel
132 self.pstore = gtk.ListStore(str, str, gtk.gdk.Pixbuf, bool, bool, str, gtk.gdk.Pixbuf, str, str, str)
133 self.plist = gtk.TreeView(self.pstore)
134 # The icons column, known and encryption
135 self.pix_cell = gtk.CellRendererPixbuf()
136 self.wep_cell = gtk.CellRendererPixbuf()
137 self.icons_cell = gtk.CellRendererText()
138 self.icons_col = gtk.TreeViewColumn()
139 self.icons_col.pack_start(self.pix_cell, False)
140 self.icons_col.pack_start(self.wep_cell, False)
141 self.icons_col.add_attribute(self.pix_cell, 'pixbuf', 2)
142 self.icons_col.add_attribute(self.wep_cell, 'stock-id', 5)
143 self.plist.append_column(self.icons_col)
144 # The AP column
145 self.ap_cell = gtk.CellRendererText()
146 self.ap_col = gtk.TreeViewColumn(_('Access Point'))
147 self.ap_col.pack_start(self.ap_cell, True)
148 self.ap_col.set_cell_data_func(self.ap_cell, self._set_ap_col_value)
149 self.plist.append_column(self.ap_col)
150 # The signal column
151 self.sig_cell = gtk.CellRendererPixbuf()
152 self.signal_col = gtk.TreeViewColumn(_('Signal'))
153 self.signal_col.pack_start(self.sig_cell, True)
154 self.signal_col.add_attribute(self.sig_cell, 'pixbuf', 6)
155 self.plist.append_column(self.signal_col)
156 # The mode column
157 self.mode_cell = gtk.CellRendererText()
158 self.mode_col = gtk.TreeViewColumn(_('Mode'))
159 self.mode_col.pack_start(self.mode_cell, True)
160 self.mode_col.add_attribute(self.mode_cell, 'text', 7)
161 self.plist.append_column(self.mode_col)
162 # The protocol column
163 self.prot_cell = gtk.CellRendererText()
164 self.protocol_col = gtk.TreeViewColumn("802.11")
165 self.protocol_col.pack_start(self.prot_cell, True)
166 self.protocol_col.add_attribute(self.prot_cell, 'text', 8)
167 self.plist.append_column(self.protocol_col)
168 # The channel column
169 self.channel_cell = gtk.CellRendererText()
170 self.channel_col = gtk.TreeViewColumn(_('Channel'))
171 self.channel_col.pack_start(self.channel_cell, True)
172 self.channel_col.add_attribute(self.channel_cell, 'text', 9)
173 self.plist.append_column(self.channel_col)
174 # DnD Ordering
175 self.plist.set_reorderable(True)
176 # detect d-n-d of AP in round-about way, since rows-reordered does not work as advertised
177 self.pstore.connect('row-deleted', self.update_auto_profile_order)
178 # enable/disable buttons based on the selected network
179 self.selected_network = self.plist.get_selection()
180 self.selected_network.connect('changed', self.on_network_selection, None)
181 # the list scroll bar
182 sb = gtk.VScrollbar(self.plist.get_vadjustment())
183 sb.show()
184 self.plist.show()
185 # Add New button
186 self.new_button = gtk.Button(_('_New'))
187 self.new_button.connect('clicked', self.create_new_profile)
188 self.new_button.show()
189 # Add Configure button
190 self.edit_button = gtk.Button(_('C_onfigure'))
191 self.edit_button.connect('clicked', self.request_profile_edit)
192 self.edit_button.show()
193 self.edit_button.set_sensitive(False)
194 # Add Delete button
195 self.delete_button = gtk.Button(_('_Delete'))
196 self.delete_button.connect('clicked', self.request_profile_delete)
197 self.delete_button.show()
198 self.delete_button.set_sensitive(False)
199 # Add Connect button
200 self.connect_button = gtk.Button(_('Co_nnect'))
201 self.connect_button.connect('clicked', self.connect_profile, None)
202 # Add Disconnect button
203 self.disconnect_button = gtk.Button(_('D_isconnect'))
204 self.disconnect_button.connect('clicked', self.disconnect_profile, None)
205 # lets add our widgets
206 rows = gtk.VBox(False, 3)
207 net_list = gtk.HBox(False, 0)
208 listcols = gtk.HBox(False, 0)
209 prows = gtk.VBox(False, 0)
210 # lets start packing
211 # the network list
212 net_list.pack_start(self.plist, True, True, 0)
213 net_list.pack_start(sb, False, False, 0)
214 # the rows level
215 rows.pack_start(net_list , True, True, 0)
216 rows.pack_start(self.current_network, False, True, 0)
217 # the list columns
218 listcols.pack_start(rows, True, True, 0)
219 listcols.pack_start(prows, False, False, 5)
220 # the list buttons
221 prows.pack_start(self.new_button, False, False, 2)
222 prows.pack_start(self.edit_button, False, False, 2)
223 prows.pack_start(self.delete_button, False, False, 2)
224 prows.pack_end(self.connect_button, False, False, 2)
225 prows.pack_end(self.disconnect_button, False, False, 2)
227 self.action_area.pack_start(self.about_button)
228 self.action_area.pack_start(self.preferences_button)
229 self.action_area.pack_start(self.close_button)
231 rows.show()
232 prows.show()
233 listcols.show()
234 self.vbox.add(listcols)
235 self.vbox.set_spacing(3)
236 self.show_all()
238 # Now, immediately hide these two. The proper one will be
239 # displayed later, based on interface state. -BEF-
240 self.disconnect_button.hide()
241 self.connect_button.hide()
242 self.connect_button.set_sensitive(False)
244 # set up status window for later use
245 self.status_window = transients.StatusWindow(self)
246 self.status_window.cancel_button.connect('clicked', self.disconnect_profile, "cancel")
248 self._running = True
249 # Check for incoming messages every 25 ms, a.k.a. 40 Hz.
250 glib.timeout_add(25, self.run)
252 def run(self):
253 """ Watch for incoming messages.
255 if self.msg_pipe.poll():
256 try:
257 msg = self.msg_pipe.recv()
258 except (EOFError, IOError) as e:
259 # This is bad, really bad.
260 logger.critical(_('read on closed Pipe ({FD}), '
261 'failing...').format(FD=rfd))
262 raise PipeError(e)
263 else:
264 self._check_message(msg)
265 # Update the UI before returning.
266 self.update_network_info()
267 self.update_connect_buttons()
268 return self._running
270 def _check_message(self, msg):
271 """ Process incoming messages.
273 if msg.topic == 'EXIT':
274 self.delete_event()
275 elif msg.topic == 'CONFIG-UPDATE':
276 # Replace configuration manager with the one in msg.details.
277 self.config = msg.details
278 elif msg.topic == 'PROFILE-EDIT':
279 with gtk.gdk.lock:
280 self.edit_profile(msg.details)
281 elif msg.topic == 'PROFILE-UPDATE':
282 with gtk.gdk.lock:
283 self.update_profile(msg.details)
284 elif msg.topic == 'PROFILE-UNLIST':
285 with gtk.gdk.lock:
286 self.delete_profile(msg.details)
287 elif msg.topic == 'PROFILE-MOVE':
288 new_position, profile = msg.details
289 with gtk.gdk.lock:
290 if profile['roaming']:
291 old_position = self.get_row_by_ap(profile['essid'])
292 else:
293 old_position = self.get_row_by_ap(profile['essid'],
294 profile['bssid'])
295 self.pstore.move_before(old_position, self.pstore[new_position].iter)
296 elif msg.topic == 'PREFS-EDIT':
297 with gtk.gdk.lock:
298 self.edit_preferences(msg.details)
299 elif msg.topic == 'ERROR':
300 with gtk.gdk.lock:
301 transients.ErrorDialog(self, msg.details)
302 else:
303 logger.warning(_('unrecognized Message: "{MSG}"').format(MSG=msg))
305 def destroy(self, widget=None):
306 """ Quit the Gtk event loop. :data:`widget` is the widget
307 sending the signal, but it is ignored.
309 if self.status_window:
310 self.status_window.destroy()
311 gtk.main_quit()
313 def delete_event(self, widget=None, data=None):
314 """ Shutdown the application. :data:`widget` is the widget sending
315 the signal and :data:`data` is a list of arbitrary arguments,
316 both are ignored. Always returns False to not propigate the
317 signal which called :func:`delete_event`.
319 self._running = False
320 self.msg_pipe.send(Message('EXIT', ''))
321 self.msg_pipe.close()
322 self.hide()
323 # process GTK events so that window hides more quickly
324 if sys.modules.has_key("gtk"):
325 while gtk.events_pending():
326 gtk.main_iteration(False)
327 self.destroy()
328 return False
330 def update_network_info(self, profile=None, ip=None):
331 """ Update the current ip and essid shown to the user.
333 if (profile is None) and (ip is None):
334 self.current_network.set_text(_('Not Connected.'))
335 else:
336 self.current_network.set_text(_('Connected to {PROFILE}\n'
337 'IP Address {IP}').format(PROFILE=profile, IP=ip))
339 def update_connect_buttons(self, connected=False):
340 """ Set the state of connect/disconnect buttons to reflect the
341 current connected state.
343 if connected:
344 self.connect_button.hide()
345 self.disconnect_button.show()
346 else:
347 self.disconnect_button.hide()
348 self.connect_button.show()
350 def _set_ap_col_value(self, column, cell, model, iter):
351 """ Set the text attribute of :data:`column` to the first two
352 :data:`model` values joined by a newline. This is for
353 displaying the :data:`essid` and :data:`bssid` in a single
354 cell column.
356 essid = model.get_value(iter, 0)
357 bssid = model.get_value(iter, 1)
358 cell.set_property('text', '\n'.join([essid, bssid]))
360 def get_row_by_ap(self, essid, bssid=_(' Multiple APs')):
361 """ Returns a :class:`gtk.TreeIter` for the row which holds
362 :data:`essid` and :data:`bssid`.
364 :data:`bssid` is optional. If not given, :func:`get_row_by_ap`
365 will try to match a roaming profile with the given :data:`essid`.
367 If no match is found, it returns None.
369 for row in self.pstore:
370 if (row[0] == essid) and (row[1] == bssid):
371 return row.iter
372 return None
374 def on_network_selection(self, widget=None, data=None):
375 """ Enable/disable buttons based on the selected network.
376 :data:`widget` is the widget sending the signal and :data:`data`
377 is a list of arbitrary arguments, both are ignored.
379 store, selected_iter = self.selected_network.get_selected()
380 if selected_iter is None:
381 # No row is selected, disable all buttons except New.
382 # This occurs after a drag-and-drop.
383 self.edit_button.set_sensitive(False)
384 self.delete_button.set_sensitive(False)
385 self.connect_button.set_sensitive(False)
386 else:
387 # One row is selected, so enable or disable buttons.
388 self.connect_button.set_sensitive(True)
389 if store.get_value(selected_iter, 3):
390 # Known profile.
391 self.edit_button.set_sensitive(True)
392 self.delete_button.set_sensitive(True)
393 else:
394 # Unknown profile.
395 self.edit_button.set_sensitive(True)
396 self.delete_button.set_sensitive(False)
398 def show_about_info(self, widget=None, data=None):
399 """ Handle the life-cycle of the About dialog. :data:`widget` is
400 the widget sending the signal and :data:`data` is a list of
401 arbitrary arguments, both are ignored.
403 about = transients.AboutDialog()
404 about.run()
405 about.destroy()
407 def request_preferences_edit(self, widget=None, data=None):
408 """ Respond to a request to edit the application preferences.
409 :data:`widget` is the widget sending the signal and :data:`data`
410 is a list of arbitrary arguments, both are ignored.
412 self.msg_pipe.send(Message('PREFS-EDIT-REQUEST', ''))
414 def edit_preferences(self, config):
415 """ Allow the user to edit :data:`config`.
417 # get raw strings from config file
418 config.raw = True
419 prefs_editor = prefs.PreferencesEditor(self, config)
420 response, config_copy = prefs_editor.run()
421 if response == gtk.RESPONSE_APPLY:
422 self.msg_pipe.send(Message('PREFS-UPDATE', config_copy))
423 prefs_editor.destroy()
425 def update_profile(self, profile):
426 """ Updates the display of :data:`profile`.
428 if profile['roaming']:
429 prow_iter = self.get_row_by_ap(profile['essid'])
430 else:
431 prow_iter = self.get_row_by_ap(profile['essid'], profile['bssid'])
433 if prow_iter is None:
434 # the AP is not in the list of APs on the screen
435 self._add_profile(profile)
436 else:
437 # the AP is in the list of APs on the screen
438 self._update_row(profile, prow_iter)
440 def _add_profile(self, profile):
441 """ Add :data:`profile` to the list of APs shown to the user.
443 if profile['roaming']:
444 profile['bssid'] = _(' Multiple APs')
446 wep = None
447 if profile['encrypted']:
448 wep = gtk.STOCK_DIALOG_AUTHENTICATION
450 self.pstore.append([profile['essid'], profile['bssid'],
451 known_profile_icon, profile['known'], profile['available'],
452 wep, signal_none_pb, profile['mode'], profile['protocol'],
453 profile['channel']])
455 def _update_row(self, profile, row_iter):
456 """ Change the values displayed in :data:`row_iter` (a
457 :class:`gtk.TreeIter`) using :data:`profile`.
459 wep = None
460 if profile['encrypted']:
461 wep = gtk.STOCK_DIALOG_AUTHENTICATION
462 # Update the Gtk objects.
463 self.pstore.set_value(row_iter, 2, pixbuf_from_known(profile['known']))
464 self.pstore.set_value(row_iter, 3, profile['known'])
465 self.pstore.set_value(row_iter, 4, profile['available'])
466 self.pstore.set_value(row_iter, 5, wep)
467 self.pstore.set_value(row_iter, 6, pixbuf_from_signal(profile['signal']))
468 self.pstore.set_value(row_iter, 7, profile['mode'])
469 self.pstore.set_value(row_iter, 8, profile['protocol'])
470 self.pstore.set_value(row_iter, 9, profile['channel'])
472 def create_new_profile(self, widget=None, profile=None, data=None):
473 """ Respond to a user request to create a new AP profile.
474 :data:`widget` is the widget sending the signal. :data:profile`
475 is an AP profile to use as the basis for the new profile. It
476 is likely empty or mostly empty. :data:`data` is a list of
477 arbitrary arguments. :data:`widget` and "data"`data` are both
478 ignored.
480 The order of parameters is important. Because when this method
481 is called from a signal handler, :data:`widget` is always the
482 first argument.
484 if profile is None:
485 profile = get_new_profile()
487 profile_editor = profile_ed.ProfileEditor(self, profile)
488 try:
489 edited_profile = profile_editor.run()
490 except ValueError:
491 self.msg_pipe.send(Message('ERROR', _('Cannot save empty ESSID')))
492 else:
493 if profile:
494 self.msg_pipe.send(Message('PROFILE-EDITED', (edited_profile, profile)))
495 finally:
496 profile_editor.destroy()
498 def request_profile_edit(self, widget=None, data=None):
499 """ Respond to a request to edit an AP profile. :data:`widget`
500 is the widget sending the signal and :data:`data` is a list
501 of arbitrary arguments, both are ignored.
503 store, selected_iter = self.plist.get_selection().get_selected()
504 if selected_iter is not None:
505 essid = self.pstore.get_value(selected_iter, 0)
506 bssid = self.pstore.get_value(selected_iter, 1)
507 if bssid == _(' Multiple APs'):
508 # AP list says this is a roaming profile
509 bssid = ''
510 self.msg_pipe.send(Message('PROFILE-EDIT-REQUEST', (essid, bssid)))
512 def edit_profile(self, profile):
513 """ Allow the user to edit :data:`profile`.
515 profile_editor = profile_ed.ProfileEditor(self, profile)
516 edited_profile = profile_editor.run()
517 profile_editor.destroy()
519 if edited_profile is not None:
520 # Replace old profile.
521 self.msg_pipe.send(Message('PROFILE-EDITED',
522 (edited_profile, profile)))
524 def request_profile_delete(self, widget=None, data=None):
525 """ Respond to a request to delete an AP profile (i.e. make the
526 profile unknown). Trying to delete an AP which is not configured
527 is a NOOP. Check with the user before deleting the profile.
528 :data:`widget` is the widget sending the signal and :data:`data`
529 is a list of arbitrary arguments, both are ignored.
531 store, selected_iter = self.plist.get_selection().get_selected()
532 if selected_iter is not None:
533 if store.get_value(selected_iter, 3):
534 # The selected AP is configured (a.k.a. 'known').
535 essid = self.pstore.get_value(selected_iter, 0)
536 bssid = self.pstore.get_value(selected_iter, 1)
537 if bssid == _(' Multiple APs'):
538 # AP list says this is a roaming profile
539 bssid = ''
540 profile_name = essid
541 else:
542 profile_name = '{ESSID} ({BSSID})'.format(ESSID=essid,
543 BSSID=bssid)
545 dialog = gtk.MessageDialog(self,
546 gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL,
547 gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO,
548 _('Are you sure you want to delete the '
549 '{NAME} profile?').format(NAME=profile_name))
551 result = dialog.run()
552 dialog.destroy()
553 del dialog
555 if result == gtk.RESPONSE_YES:
556 apname = make_section_name(essid, bssid)
557 self.msg_pipe.send(Message('PROFILE-REMOVE', apname))
559 def delete_profile(self, profile):
560 """ Remove :data:`profile` from the list of APs shown to the user.
562 if profile['roaming']:
563 prow_iter = self.get_row_by_ap(profile['essid'])
564 else:
565 prow_iter = self.get_row_by_ap(profile['essid'], profile['bssid'])
566 if prow_iter is not None:
567 self.pstore.remove(prow_iter)
569 def connect_profile(self, widget, profile, data=None):
570 """ Respond to a request to connect to an AP.
572 Parameters:
574 'widget' -- gtk.Widget - The widget sending the event.
576 'profile' -- dictionary - The AP profile to which to connect.
578 'data' -- tuple - list of arbitrary arguments (not used)
580 Returns:
582 nothing
584 store, selected_iter = self.plist.get_selection().get_selected()
585 if selected_iter is None:
586 return
587 essid = self.pstore.get_value(selected_iter, 0)
588 bssid = self.pstore.get_value(selected_iter, 1)
589 known = store.get_value(selected_iter, 3)
590 if not known:
591 dlg = gtk.MessageDialog(self,
592 gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL,
593 gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO,
594 _('This network does not have a profile configured.\n\n'
595 'Would you like to create one now?'))
596 res = dlg.run()
597 dlg.destroy()
598 del dlg
599 if res == gtk.RESPONSE_NO:
600 return
601 profile = get_new_profile()
602 profile['essid'] = essid
603 profile['bssid'] = bssid
604 if not self.create_new_profile(widget, profile, data):
605 return
606 else:
607 # Check for roaming profile.
608 ap_name = make_section_name(essid, '')
609 profile = self.config.get_profile(ap_name)
610 if not profile:
611 # Check for normal profile.
612 ap_name = make_section_name(essid, bssid)
613 profile = self.config.get_profile(ap_name)
614 if not profile:
615 # No configured profile
616 return
617 profile['bssid'] = self.access_points[ap_name]['bssid']
618 profile['channel'] = self.access_points[ap_name]['channel']
619 self.msg_pipe.send(Message('CONNECT', profile))
621 def disconnect_profile(self, widget=None, data=None):
622 """ Respond to a request to disconnect by sending a message to
623 ConnectionManager. :data:`widget` is the widget sending the
624 signal and :data:`data` is a list of arbitrary arguments, both
625 are ignored.
627 self.msg_pipe.send(Message('DISCONNECT', ''))
628 if data == "cancel":
629 self.status_window.update_message(_('Canceling connection...'))
630 if sys.modules.has_key("gtk"):
631 while gtk.events_pending():
632 gtk.main_iteration(False)
634 def profile_order_updater(self, model, path, iter, auto_profile_order):
637 if model.get_value(iter, 3) is True:
638 essid = self.pstore.get_value(iter, 0)
639 bssid = self.pstore.get_value(iter, 1)
640 if bssid == _(' Multiple APs'):
641 bssid = ''
642 apname = make_section_name(essid, bssid)
643 auto_profile_order.append(apname)
645 def update_auto_profile_order(self, widget=None, data=None, data2=None):
646 """ Update the config file auto profile order from the on-screen
647 order. :data:`widget` is the widget sending the signal and
648 :data:`data` and :data:`data2` is a list of arbitrary arguments,
649 all are ignored.
651 # recreate the auto_profile_order
652 auto_profile_order = []
653 self.pstore.foreach(self.profile_order_updater, auto_profile_order)
654 self.msg_pipe.send(Message('PROFILE-ORDER-UPDATE', auto_profile_order))
657 # Make so we can be imported
658 if __name__ == "__main__":
659 pass