diff --git a/curses/README b/curses/README index bf4aebd..3faa1c8 100644 --- a/curses/README +++ b/curses/README @@ -25,6 +25,7 @@ P : Display preferences dialog C : Display network configuration for selected network (only works for wireless at the moment) A : Display "About" dialog +I : Raise up the "Scan for hidden networks" dialog IN DIALOGS (Meta usually is "Alt"): ESC or Q: Quit dialog without saving information (if present) diff --git a/curses/TODO b/curses/TODO index 56eb346..6c81304 100644 --- a/curses/TODO +++ b/curses/TODO @@ -4,7 +4,6 @@ Things to do (in no particular order): * Implement a keyhandler function for the overall frame * Make keystrokes customizable * Make color schemes customizable -* Implement a "scan for hidden networks" dialog * Implement a "make an ad-hoc network" dialog * Implement a "help" dialog * Perform a mass code cleanup diff --git a/curses/curses_misc.py b/curses/curses_misc.py index dfbfd84..f26d4c6 100644 --- a/curses/curses_misc.py +++ b/curses/curses_misc.py @@ -350,73 +350,124 @@ class ComboBox(urwid.WidgetWrap): def set_sensitive(self,state): self.cbox.set_sensitive(state) -# Almost completely ripped from rbreu_filechooser.py: -# http://excess.org/urwid/browser/contrib/trunk/rbreu_menus.py -class Dialog(urwid.WidgetWrap): - """ - Creates a BoxWidget that displays a message +# This is a h4x3d copy of some of the code in Ian Ward's dialog.py example. +class DialogExit(Exception): + pass - Attributes: - - b_pressed -- Contains the label of the last button pressed or None if no - button has been pressed. - edit_text -- After a button is pressed, this contains the text the user - has entered in the edit field - """ +class Dialog2(urwid.WidgetWrap): + def __init__(self, text, height,width, body=None ): + self.width = int(width) + if width <= 0: + self.width = ('relative', 80) + self.height = int(height) + if height <= 0: + self.height = ('relative', 80) + + self.body = body + if body is None: + # fill space with nothing + body = urwid.Filler(urwid.Divider(),'top') - b_pressed = None - edit_text = None - - _blank = urwid.Text("") - _edit_widget = None - _mode = None - - def __init__(self, msg, buttons, attr, width, height, body, ): - """ - msg -- content of the message widget, one of: - plain string -- string is displayed - (attr, markup2) -- markup2 is given attribute attr - [markupA, markupB, ... ] -- list items joined together - buttons -- a list of strings with the button labels - attr -- a tuple (background, button, active_button) of attributes - width -- width of the message widget - height -- height of the message widget - body -- widget displayed beneath the message widget - """ - - # Text widget containing the message: - msg_widget = urwid.Padding(urwid.Text(msg), 'center', width - 4) - - # GridFlow widget containing all the buttons: - button_widgets = [] - - for button in buttons: - button_widgets.append(urwid.AttrWrap( - urwid.Button(button, self._action), attr[1], attr[2])) - - button_grid = urwid.GridFlow(button_widgets, 12, 2, 1, 'center') - - # Combine message widget and button widget: - widget_list = [msg_widget, self._blank, button_grid] - self._combined = urwid.AttrWrap(urwid.Filler( - urwid.Pile(widget_list, 2)), attr[0]) - - # This was the real thing I added to this class - self._linebox = urwid.LineBox(self._combined) - # Place the dialog widget on top of body: - # Width and height are increased to accomidate the linebox - overlay = urwid.Overlay(self._linebox, body, 'center', width+2, - 'middle', height+2) + self.frame = urwid.Frame( body, focus_part='footer') + if text is not None: + self.frame.header = urwid.Pile( [urwid.Text(text), + urwid.Divider()] ) + w = self.frame + self.view = w - urwid.WidgetWrap.__init__(self, overlay) + # pad area around listbox + #w = urwid.Padding(w, ('fixed left',2), ('fixed right',2)) + #w = urwid.Filler(w, ('fixed top',1), ('fixed bottom',1)) + #w = urwid.AttrWrap(w, 'body') + # buttons: tuple of name,exitcode + def add_buttons(self, buttons): + l = [] + for name, exitcode in buttons: + b = urwid.Button( name, self.button_press ) + b.exitcode = exitcode + b = urwid.AttrWrap( b, 'body','focus' ) + l.append( b ) + self.buttons = urwid.GridFlow(l, 10, 3, 1, 'center') + self.frame.footer = urwid.Pile( [ urwid.Divider(), + self.buttons ], focus_item = 1) + + def button_press(self, button): + raise DialogExit(button.exitcode) + + def run(self,ui,parent): + ui.set_mouse_tracking() + size = ui.get_cols_rows() + overlay = urwid.Overlay(urwid.LineBox(self.view), parent, 'center', self.width, + 'middle', self.height) + try: + while True: + canvas = overlay.render( size, focus=True ) + ui.draw_screen( size, canvas ) + keys = None + while not keys: + keys = ui.get_input() + for k in keys: + if urwid.is_mouse_event(k): + event, button, col, row = k + overlay.mouse_event( size, + event, button, col, row, + focus=True) + if k == 'window resize': + size = ui.get_cols_rows() + k = self.view.keypress( size, k ) + if k == 'esc': + raise DialogExit(-1) + if k: + self.unhandled_key( size, k) + except DialogExit, e: + return self.on_exit( e.args[0] ) + + def on_exit(self, exitcode): + return exitcode, "" + + def unhandled_key(self, size, key): + pass + +class TextDialog(Dialog2): + def __init__(self, text, height, width, header=None): + l = [] + # read the whole file (being slow, not lazy this time) + #for line in open(file).readlines(): + # l.append( urwid.Text( line.rstrip() )) + l = [urwid.Text(text)] + body = urwid.ListBox(l) + body = urwid.AttrWrap(body, 'body') + + Dialog2.__init__(self, header, height+2, width+2, body) + self.add_buttons([('OK',1)]) - def _action(self, button): - """ - Function called when a button is pressed. - Should not be called manually. - """ - - self.b_pressed = button.get_label() - if self._edit_widget: - self.edit_text = self._edit_widget.get_edit_text() + def unhandled_key(self, size, k): + if k in ('up','page up','down','page down'): + self.frame.set_focus('body') + self.view.keypress( size, k ) + self.frame.set_focus('footer') + +class InputDialog(Dialog2): + def __init__(self, text, height, width,ok_name='OK'): + self.edit = urwid.Edit(wrap='clip') + body = urwid.ListBox([self.edit]) + body = urwid.AttrWrap(body, 'editbx','editfc') + + Dialog2.__init__(self, text, height, width, body) + + self.frame.set_focus('body') + self.add_buttons([(ok_name,0),('Cancel',-1)]) + + def unhandled_key(self, size, k): + if k in ('up','page up'): + self.frame.set_focus('body') + if k in ('down','page down'): + self.frame.set_focus('footer') + if k == 'enter': + # pass enter to the "ok" button + self.frame.set_focus('footer') + self.view.keypress( size, k ) + + def on_exit(self, exitcode): + return exitcode, self.edit.get_edit_text() diff --git a/curses/netentry_curses.py b/curses/netentry_curses.py index 79f3703..09fa7f8 100644 --- a/curses/netentry_curses.py +++ b/curses/netentry_curses.py @@ -22,7 +22,7 @@ # MA 02110-1301, USA. import urwid -from curses_misc import Dialog,DynWrap,MaskingEdit,ComboBox +from curses_misc import TextDialog,DynWrap,MaskingEdit,ComboBox import wicd.misc as misc from wicd.misc import noneToString, stringToNone, noneToBlankString, to_bool @@ -31,23 +31,9 @@ def error(ui,parent,message): # /\ # /!!\ # /____\ - dialog = Dialog([('important','ERROR: '),message],['OK'],('body','body','focus'),40,6,parent) + dialog = TextDialog(message,40,6,('important',"ERROR")) + return dialog.run(ui,parent) - keys = True - dim = ui.get_cols_rows() - while True: - if keys: - ui.draw_screen(dim, dialog.render(dim, True)) - - keys = ui.get_input() - if "window resize" in keys: - dim = ui.get_cols_rows() - if "esc" in keys: - return False - for k in keys: - dialog.keypress(dim, k) - if dialog.b_pressed == 'OK': - return False language = misc.get_language_list_gui() @@ -310,13 +296,13 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): encrypt_methods[self.encryption_combo.get_focus()[1] ][1]) for x in encryption_info: if encryption_info[x].get_edit_text() == "": - error(self.ui, self, language['encrypt_info_missing']) + error(self.ui, self.overlay,language['encrypt_info_missing']) return False self.set_net_prop(x, noneToString(encryption_info[x]. get_edit_text())) elif not self.encryption_chkbox.get_state() and \ wireless.GetWirelessProperty(networkid, "encryption"): - error(self.ui, self, language['enable_encryption']) + error(self.ui, self.overlay, language['enable_encryption']) return False else: #print 'encryption is ' + str(wireless.GetWirelessProperty(networkid, @@ -372,27 +358,34 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): def run(self,ui,dim,display): self.ui = ui + self.parent = display width,height = ui.get_cols_rows() - overlay = urwid.Overlay(self, display, ('fixed left', 0),width + self.overlay = urwid.Overlay(self, display, ('fixed left', 0),width , ('fixed top',1), height-3) - self.encryption_combo.build_combobox(overlay,ui,14) + self.encryption_combo.build_combobox(self.overlay,ui,14) #self.change_encrypt_method() #self._w.body.body.append(self.pile_encrypt) keys = True while True: if keys: - ui.draw_screen(dim, overlay.render(dim, True)) + ui.draw_screen(dim, self.overlay.render(dim, True)) keys = ui.get_input() for k in keys: #Send key to underlying widget: - overlay.keypress(dim, k) + if urwid.is_mouse_event(k): + event, button, col, row = k + self.overlay.mouse_event( dim, + event, button, col, row, + focus=True) + self.overlay.keypress(dim, k) if "window resize" in keys: dim = ui.get_cols_rows() if "esc" in keys or 'Q' in keys: return False if "meta enter" in keys or self.OK_PRESSED: + self.OK_PRESSED = False if self.save_settings(self.networkID): return True if self.CANCEL_PRESSED: diff --git a/curses/prefs_curses.py b/curses/prefs_curses.py index 49737e0..b5d1ef9 100755 --- a/curses/prefs_curses.py +++ b/curses/prefs_curses.py @@ -425,6 +425,11 @@ class PrefsDialog(urwid.WidgetWrap): return False for k in keys: #Send key to underlying widget: + if urwid.is_mouse_event(k): + event, button, col, row = k + overlay.mouse_event( dim, + event, button, col, row, + focus=True) overlay.keypress(dim, k) # Check if buttons are pressed. if self.CANCEL_PRESSED: diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 10eaecf..637b34b 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -53,10 +53,10 @@ import sys from time import sleep # Curses UIs for other stuff -from curses_misc import SelText,ComboBox,Dialog +from curses_misc import SelText,ComboBox,TextDialog,InputDialog from prefs_curses import PrefsDialog import netentry_curses -from netentry_curses import WirelessSettingsDialog +from netentry_curses import WirelessSettingsDialog, error language = misc.get_language_list_gui() @@ -80,6 +80,19 @@ class wrap_exceptions: ui.stop() print "\nTerminated by user." raise + except DBusException: + gobject.source_remove(redraw_tag) + # Quit the loop + loop.quit() + # Zap the screen + ui.stop() + print "" + print "DBus failiure!" + print "This is most likely caused by the wicd daemon stopping" + print "while wicd-curses is running." + print "" + print "Please restart the daemon, and restart wicd-curses." + raise except : # If the UI isn't inactive (redraw_tag wouldn't normally be # set), then don't try to stop it, just gracefully die. @@ -212,23 +225,8 @@ def about_dialog(body): " ___|+|___ Dan O'Reilly (wicd)\n", " |---------| Andrew Psaltis (this ui)\n", "---------------------------------------------------"] - about = Dialog(theText,['OK'],('body','body','focus'),55,14,body) - - keys = True - dim = ui.get_cols_rows() - while True: - if keys: - ui.draw_screen(dim, about.render(dim, True)) - - keys = ui.get_input() - if "window resize" in keys: - dim = ui.get_cols_rows() - if "esc" in keys: - return False - for k in keys: - about.keypress(dim, k) - if about.b_pressed == 'OK': - return False + about = TextDialog(theText,55,14) + about.run(ui,body) ######################################## ##### URWID SUPPORT CLASSES @@ -335,6 +333,7 @@ class appGUI(): # for networks. :-) # Will need a translation sooner or later self.screen_locker = urwid.Filler(urwid.Text(('important',"Scanning networks... stand by..."), align='center')) + self.no_wlan = urwid.Filler(urwid.Text(('important',"No wireless networks found."), align='center')) self.TITLE = 'Wicd Curses Interface' #wrap1 = urwid.AttrWrap(txt, 'black') @@ -344,8 +343,10 @@ class appGUI(): self.wiredH=urwid.Filler(urwid.Text("Wired Network(s)")) self.wlessH=urwid.Filler(urwid.Text("Wireless Network(s)")) + #if wireless.GetNumberOfNetworks() == 0: + # wireless.Scan() wiredL,wlessL = gen_network_list() - self.wiredCB = urwid.Filler(ComboBox(list=wiredL)) + self.wiredCB = urwid.Filler(ComboBox(list=wiredL,use_enter=False)) self.wlessLB = urwid.ListBox(wlessL) # Stuff I used to simulate large lists #spam = SelText('spam') @@ -383,6 +384,8 @@ class appGUI(): self.screen_locked = False #self.always_show_wired = daemon.GetAlwaysShowWiredInterface() + self.focusloc = (1,0) + self.pref = None self.update_status() @@ -395,18 +398,46 @@ class appGUI(): self.screen_locked = True def unlock_screen(self): - self.update_netlist(force_check=True) self.frame.set_body(self.thePile) self.screen_locked = False # I'm hoping that this will get rid of Adam's problem with the ListBox not # redisplaying itself immediately upon completion. + self.update_netlist(force_check=True) self.update_ui() + def raise_hidden_network_dialog(self): + dialog = InputDialog(('header','Select Hidden Network ESSID'),7,30,'Scan') + exitcode,hidden = dialog.run(ui,self.frame) + if exitcode != -1: + # That dialog will sit there for a while if I don't get rid of it + self.update_ui() + wireless.SetHiddenNetworkESSID(misc.noneToString(hidden)) + wireless.Scan() + wireless.SetHiddenNetworkESSID("") + + def update_focusloc(self): + # Location of last known focus is remapped to current location. + # This might need to be cleaned up later. + + if self.thePile.get_focus() is self.wiredCB: + wlessorwired = 1 + else : + wlessorwired = 3 + if self.thePile.get_focus() == self.no_wlan: + where = 0 + elif self.thePile.get_focus() == self.wiredCB: + where = self.thePile.get_focus().get_body().get_focus()[1] + else: + where = self.thePile.get_focus().get_focus()[1] + + self.focusloc = (wlessorwired,where) + # Be clunky until I get to a later stage of development. # Update the list of networks. Usually called by DBus. # TODO: Preserve current focus when updating the list. @wrap_exceptions() def update_netlist(self,state=None, x=None, force_check=False): + self.update_focusloc() """ Updates the overall network list.""" if not state: state, x = daemon.GetConnectionStatus() @@ -416,17 +447,28 @@ class appGUI(): # use_enter=False)) self.wiredCB.get_body().set_list(wiredL) self.wiredCB.get_body().build_combobox(self.frame,ui,3) - self.wlessLB.body = urwid.SimpleListWalker(wlessL) - + if len(wlessL) != 0: + self.wlessLB.body = urwid.SimpleListWalker(wlessL) + else: + self.wlessLB.body = urwid.SimpleListWalker([self.no_wlan]) if daemon.GetAlwaysShowWiredInterface() or wired.CheckPluggedIn(): #if daemon.GetAlwaysShowWiredInterface(): self.thePile = urwid.Pile([('fixed',1,self.wiredH), ('fixed',1,self.wiredCB), ('fixed',1,self.wlessH), self.wlessLB] ) + #self.focusloc = (self.thePile.get_focus(), + # self.thePile.get_focus().get_focus()[1]) + self.thePile.set_focus(self.focusloc[0]) + if self.focusloc[0] == 1: + self.thePile.get_focus().get_body().set_focus(self.focusloc[1]) + else: + self.thePile.get_focus().set_focus(self.focusloc[1]) else: self.thePile = urwid.Pile([('fixed',1,self.wlessH),self.wlessLB] ) self.frame.body = self.thePile + if self.focusloc[0] == self.wlessLB: + self.wlessLB.set_focus(self.focusloc[1]) #self.always_show_wired = not self.always_show_wired self.prev_state = state @@ -512,19 +554,20 @@ class appGUI(): # Yeah, I'm copying code. Anything wrong with that? #@wrap_exceptions() def dbus_scan_finished(self): - # I'm pretty sure that I'll need this later. - #if not self.connecting: - #self.refresh_networks(fresh=False) - self.unlock_screen() - # I'm hoping that this will resolve Adam's problem with the screen lock - # remaining onscreen until a key is pressed. It goes away perfectly well - # here. - self.update_ui() + # I'm pretty sure that I'll need this later. + #if not self.connecting: + # gobject.idle_add(self.refresh_networks, None, False, None) + self.unlock_screen() + # I'm hoping that this will resolve Adam's problem with the screen lock + # remaining onscreen until a key is pressed. It goes away perfectly well + # here. + self.update_ui() # Same, same, same, same, same, same #@wrap_exceptions() def dbus_scan_started(self): self.lock_screen() + self.update_ui() # Redraw the screen @wrap_exceptions() @@ -554,7 +597,7 @@ class appGUI(): # references to self.frame lying around. ^_^ if "enter" in keys: focus = self.thePile.get_focus() - if focus == self.wiredCB: + if focus is self.wiredCB: self.connect("wired",0) else: # wless list only other option @@ -586,8 +629,15 @@ class appGUI(): WirelessSettingsDialog(pos).run(ui,self.size,self.frame) #self.netentry = NetEntryBase(dbusmanager.get_dbus_ifaces()) #self.netentry.run(ui,self.size,self.frame) + if "I" in keys: + self.raise_hidden_network_dialog() for k in keys: + if urwid.is_mouse_event(k): + event, button, col, row = k + self.frame.mouse_event( self.size, + event, button, col, row, + focus=True) if k == "window resize": self.size = ui.get_cols_rows() continue @@ -597,7 +647,7 @@ class appGUI(): focus = self.thePile.get_focus() if focus == self.wiredCB: #self.set_status('space pressed on wiredCB!') - wid,pos = self.wiredCB.get_body().get_selected() + wid,pos = self.wiredCB.get_body().get_focus() text,attr = wid.get_text() wired.ReadWiredNetworkProfile(text) # Make sure our internal reference to the combobox matches the @@ -629,14 +679,14 @@ def main(): misc.RenameProcess('wicd-curses') ui = urwid.curses_display.Screen() - # Color scheme. + # Default Color scheme. # Other potential color schemes can be found at: # http://excess.org/urwid/wiki/RecommendedPalette # Note: the current palette below is optimized for the linux console. # For example, this looks particularly bad on a default-colored XTerm. # NB: To find current terminal background use variable COLORFGBG ui.register_palette([ - ('body','light gray','default'), + ('body','default','default'), ('focus','dark magenta','light gray'), ('header','light blue','default'), ('important','light red','default'), @@ -658,6 +708,7 @@ def main(): def run(): global loop,redraw_tag + ui.set_mouse_tracking() redraw_tag = -1 app = appGUI() diff --git a/in/man=wicd-curses.8.in b/in/man=wicd-curses.8.in index 5913828..7d81ba9 100644 --- a/in/man=wicd-curses.8.in +++ b/in/man=wicd-curses.8.in @@ -33,6 +33,9 @@ Refresh the network list .TP .BR P Bring up the preferences controller +.TP +.BR I +Bring up hidden network scanning dialog .PP The following is a work in progress and might not be fully functional as of yet. .TP @@ -44,9 +47,6 @@ The following are not implemented yet: .BR S Bring up the script selector for the selected network (requires superuser privileges) .TP -.BR I -Bring up hidden network scanning dialog -.TP .BR R Bring up script selector "dialog." .TP diff --git a/man/wicd-client.1 b/man/wicd-client.1 index 99d5a7c..115217c 100644 --- a/man/wicd-client.1 +++ b/man/wicd-client.1 @@ -4,7 +4,7 @@ wicd-client \- manual page for wicd-client .SH DESCRIPTION wireless (and wired) connection daemon front\-end. -If wicd-curses(8) is instaled, and you attempt to run wicd-client without an active X server on the current terminal, wicd-client will attempt to run wicd-curses(8). It will warn you the first time this happens. +If wicd-curses(8) is instaled, and you attempt to run wicd-client without an active X server on the current terminal, wicd-client will attempt to run wicd-curses(8) instead. It will warn you the first time this happens. .SS "Arguments:" .TP \fB\-n\fR \fB\-\-no\-tray\fR