diff --git a/curses/README b/curses/README index d443845..3faa1c8 100644 --- a/curses/README +++ b/curses/README @@ -2,30 +2,34 @@ This is a curses-based client for wicd. It is designed to imitate wicd-client as much as can be done with a console-based interface. It is written using the Urwid (http://excess.org/urwid) toolkit, and thus requires it. -That's all there is to it, really. It installs unless you disable when you -call setup.py +That's all there is to it, really. It installs unless you disable it when you +call setup.py. Right now, it lists current available networks, and whether you are connected -to anything or not, all of which is updated in real time. It will actually -connect you to networks now. Global preferences are now configurable from the -console. Per-network settings is a work in progress. +to anything or not, all of which is updated in real time. Other features +include the ability to connect to networks, global preferences controls, and +per-network settings for wireless networks. + +All features that I plan on implementing (that are not mentioned above) are +listed the TODO file in this same directory. If you want any other features, +ask me. I try to be on the #wicd Freenode IRC channel most of the time. Controls: F5 : refresh wireless networks F8 or Q: quit -D : disconnect from active network +D : disconnect from all active networks ESC : if connecting to a network, stop doing so ENTER : Attempt connection to selected network P : Display preferences dialog -C : Display network configuration for selected network +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: +IN DIALOGS (Meta usually is "Alt"): ESC or Q: Quit dialog without saving information (if present) -Meta+Left/Right: Change tabs Left/Right +Meta+Left/Right: Change tabs Left/Right (if tabs present) Meta+Enter : Quit dialog and save information - - ~NaCl diff --git a/curses/TODO b/curses/TODO index 1c80fde..6c81304 100644 --- a/curses/TODO +++ b/curses/TODO @@ -1,17 +1,9 @@ Things to do (in no particular order): -* Make a network config dialog for both wireless and wired interfaces -* Make an about dialog +* Make a network config dialog for wired interfaces * Implement a keyhandler function for the overall frame * Make keystrokes customizable * Make color schemes customizable -* Integrate this with the my local copy of the experimental branch -* Give some indication of activity during the connection process -* Make a man page for the UI. - -Oh, and most importantly: - -* Tell people how they can quit the app in the app (F8 or Q, until I do all of - that stuff) :-) - -Anything else? That's all I can think of now. +* 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 06bfb77..f26d4c6 100644 --- a/curses/curses_misc.py +++ b/curses/curses_misc.py @@ -261,7 +261,7 @@ class ComboBox(urwid.WidgetWrap): #def get_size(self): - def __init__(self,label='',list=[],attrs=('body','editnfc'),focus_attr='focus',use_enter=True,show_first=0): + def __init__(self,label='',list=[],attrs=('body','editnfc'),focus_attr='focus',use_enter=True,focus=0,callback=None,user_args=None): """ label : bit of text that preceeds the combobox. If it is "", then ignore it @@ -269,13 +269,16 @@ class ComboBox(urwid.WidgetWrap): body : parent widget ui : the screen row : where this object is to be found onscreen - show_first: index of the element in the list to pick first + focus : index of the element in the list to pick first + callback : function that takes (combobox,sel_index,user_args=None) + user_args : user_args in the callback """ self.label = urwid.Text(label) self.attrs = attrs self.focus_attr = focus_attr self.list = list + str,trash = self.label.get_text() self.overlay = None @@ -290,26 +293,27 @@ class ComboBox(urwid.WidgetWrap): # We need this to pick our keypresses self.use_enter = use_enter - - # Set the focus at the beginning to 0 - self.show_first = show_first - + # The Focus + self.focus = focus + # The callback and friends + self.callback = callback + self.user_args = user_args def set_list(self,list): self.list = list - def set_show_first(self,show_first): - self.show_first = show_first + def set_focus(self,index): + self.focus = index def build_combobox(self,body,ui,row): str,trash = self.label.get_text() - self.cbox = DynWrap(SelText([self.list[self.show_first]+' vvv']),attrs=self.attrs,focus_attr=self.focus_attr) + self.cbox = DynWrap(SelText([self.list[self.focus]+' vvv']),attrs=self.attrs,focus_attr=self.focus_attr) if str != '': w = urwid.Columns([('fixed',len(str),self.label),self.cbox],dividechars=1) - self.overlay = self.ComboSpace(self.list,body,ui,self.show_first, + self.overlay = self.ComboSpace(self.list,body,ui,self.focus, pos=(len(str)+1,row)) else: w = urwid.Columns([self.cbox]) - self.overlay = self.ComboSpace(self.list,body,ui,self.show_first, + self.overlay = self.ComboSpace(self.list,body,ui,self.focus, pos=(0,row)) self.set_w(w) @@ -328,89 +332,142 @@ class ComboBox(urwid.WidgetWrap): retval = self.overlay.show(self.ui,self.body) if retval != None: self.cbox.set_w(SelText(retval+' vvv')) + if self.callback != None: + self.callback(self,self.overlay._listbox.get_focus()[1],self.user_args) return self._w.keypress(size,key) - # Most obvious thing ever. :-) def selectable(self): return self.cbox.selectable() - # Return the index of the selected element - def get_selected(self): - wid,pos = self.overlay._listbox.get_focus() - return (wid,pos) + def get_focus(self): + if self.overlay: + return self.overlay._listbox.get_focus() + else: + return None,self.focus def get_sensitive(self): return self.cbox.get_sensitive() 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 71f0d18..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(message,[OK],('body','body','focus'),40,6) + 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, 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: - dialog.keypress(dim, k) - if dialog.b_pressed == 'OK': - return False language = misc.get_language_list_gui() @@ -61,10 +47,13 @@ def dbus_init(dbus_ifaces): wired = dbus_ifaces['wired'] wireless = dbus_ifaces['wireless'] -# Both the wired and the wireless NetEntries some of the same fields. -# This will be used to produce the individual network settings -class NetEntryBase(urwid.WidgetWrap): +# Both the wired and the wireless settings preferences dialogs use some of the +# same fields. +# This will be used to produce the individual network settings dialogs way far below +class AdvancedSettingsDialog(urwid.WidgetWrap): def __init__(self): + self.ui=None + static_ip_t = language['use_static_ip'] ip_t = ('editcp',language['ip']+': ') netmask_t = ('editcp',language['netmask']+':') @@ -78,7 +67,7 @@ class NetEntryBase(urwid.WidgetWrap): dns2_t = ('editcp',language['dns']+ ' ' + language['2']+':'+' '*8) dns3_t = ('editcp',language['dns']+ ' ' + language['3']+':'+' '*8) - cancel_t = 'cancel' + cancel_t = 'Cancel' ok_t = 'OK' self.static_ip_cb = urwid.CheckBox(static_ip_t, @@ -102,6 +91,12 @@ class NetEntryBase(urwid.WidgetWrap): _blank = urwid.Text('') + # Buttons. These need to be added to the list in superclasses. + self.OK_PRESSED= False + self.CANCEL_PRESSED = False + self.ok_button = urwid.AttrWrap(urwid.Button('OK',self.ok_callback),'body','focus') + self.cancel_button = urwid.AttrWrap(urwid.Button('Cancel',self.cancel_callback),'body','focus') + self.button_cols = urwid.Columns([self.ok_button,self.cancel_button]) walker = urwid.SimpleListWalker([self.static_ip_cb, self.ip_edit, @@ -113,11 +108,20 @@ class NetEntryBase(urwid.WidgetWrap): self.dns1,self.dns2,self.dns3 ]) + + self._listbox = urwid.ListBox(walker) #self._frame = urwid.Frame(self._listbox) self._frame = urwid.Frame(self._listbox) self.__super.__init__(self._frame) + + # Button callbacks + def ok_callback(self,button_object,user_data=None): + self.OK_PRESSED = True + def cancel_callback(self,button_object,user_data=None): + self.CANCEL_PRESSED = True + def static_ip_set_state(self,checkb,new_state,user_data=None): for w in [ self.ip_edit,self.netmask_edit,self.gateway_edit ]: w.set_sensitive(new_state) @@ -139,7 +143,7 @@ class NetEntryBase(urwid.WidgetWrap): # Code totally yanked from netentry.py def save_settings(self): """ Save settings common to wired and wireless settings dialogs. """ - if self.chkbox_static_ip.get_active(): + if self.static_ip_cb.get_state(): self.set_net_prop("ip", noneToString(self.ip_edit.get_edit_text())) self.set_net_prop("netmask", noneToString(self.netmask_edit.get_edit_text())) self.set_net_prop("gateway", noneToString(self.gateway_edit.get_edit_text())) @@ -148,17 +152,17 @@ class NetEntryBase(urwid.WidgetWrap): self.set_net_prop("netmask", '') self.set_net_prop("gateway", '') - if self.chkbox_static_dns.get_active() and \ - not self.chkbox_global_dns.get_active(): + if self.static_dns_cb.get_state() and \ + not self.global_dns_cb.get_state(): self.set_net_prop('use_static_dns', True) self.set_net_prop('use_global_dns', False) - self.set_net_prop('dns_domain', noneToString(self.txt_domain.get_text())) - self.set_net_prop("search_domain", noneToString(self.txt_search_dom.get_text())) - self.set_net_prop("dns1", noneToString(self.dns_1.get_text())) - self.set_net_prop("dns2", noneToString(self.dns_2.get_text())) - self.set_net_prop("dns3", noneToString(self.dns_3.get_text())) - elif self.chkbox_static_dns.get_active() and \ - self.chkbox_global_dns.get_active(): + self.set_net_prop('dns_domain', noneToString(self.dns_dom_edit.get_text())) + self.set_net_prop("search_domain", noneToString(self.search_dom_edit.get_text())) + self.set_net_prop("dns1", noneToString(self.dns1.get_text())) + self.set_net_prop("dns2", noneToString(self.dns2.get_text())) + self.set_net_prop("dns3", noneToString(self.dns3.get_text())) + elif self.static_dns_cb.get_state() and \ + self.global_dns_cb.get_state(): self.set_net_prop('use_static_dns', True) self.set_net_prop('use_global_dns', True) else: @@ -198,24 +202,35 @@ class NetEntryBase(urwid.WidgetWrap): ######################################## -class WirelessNetEntry(NetEntryBase): +class WirelessSettingsDialog(AdvancedSettingsDialog): def __init__(self,networkID): - NetEntryBase.__init__(self) + global wireless, daemon + AdvancedSettingsDialog.__init__(self) self.networkID = networkID global_settings_t = language['global_settings'] encryption_t = language['use_encryption'] self.global_settings_chkbox = urwid.CheckBox(global_settings_t) self.encryption_chkbox = urwid.CheckBox(encryption_t,on_state_change=self.encryption_toggle) - self.encryption_combo = ComboBox() + self.encryption_combo = ComboBox(callback=self.combo_on_change) + self.pile_encrypt = None + # _w is a Frame, _w.body is a ListBox, _w.body.body is the ListWalker :-) self._w.body.body.append(self.global_settings_chkbox) self._w.body.body.append(self.encryption_chkbox) self._w.body.body.append(self.encryption_combo) + self._w.body.body.append(self.button_cols) self.encrypt_types = misc.LoadEncryptionMethods() self.set_values() + + # Set the frame title so that people will always know what we're dealing with. + self._w.header = urwid.Text(('header',">Configuring preferences for wireless network \"%s\"" % wireless.GetWirelessProperty(networkID,'essid')),align='right' ) def encryption_toggle(self,chkbox,new_state,user_data=None): self.encryption_combo.set_sensitive(new_state) + self.pile_encrypt.set_sensitive(new_state) + + def combo_on_change(self,combobox,new_index,user_data=None): + self.change_encrypt_method() def set_values(self): """ Set the various network settings to the right values. """ @@ -238,9 +253,9 @@ class WirelessNetEntry(NetEntryBase): #self.reset_static_checkboxes() self.encryption_chkbox.set_state(bool(wireless.GetWirelessProperty(networkID, - 'encryption'))) - self.global_settings_chkbox.set_state(bool(wireless.GetWirelessProperty(networkID, - 'use_settings_globally'))) + 'encryption')),do_callback=False) + self.global_settings_chkbox.set_state(bool(wireless.GetWirelessProperty(networkID + ,'use_settings_globally'))) activeID = -1 # Set the menu to this item when we are done user_enctype = wireless.GetWirelessProperty(networkID, "enctype") @@ -248,14 +263,19 @@ class WirelessNetEntry(NetEntryBase): if enc_type[1] == user_enctype: activeID = x - #self.combo_encryption.set_active(activeID) - #if activeID != -1: - # self.chkbox_encryption.set_active(True) - # self.combo_encryption.set_sensitive(True) - # self.vbox_encrypt_info.set_sensitive(True) - #else: - # self.combo_encryption.set_active(0) - #self.change_encrypt_method() + self.encryption_combo.set_focus(activeID) + if activeID != -1: + self.encryption_chkbox.set_state(True,do_callback=False) + self.encryption_combo.set_sensitive(True) + #self.lbox_encrypt_info.set_sensitive(True) + else: + self.encryption_combo.set_focus(0) + # Throw the encryption stuff into a list + list = [] + for x, enc_type in enumerate(self.encrypt_types): + list.append(enc_type[0]) + self.encryption_combo.set_list(list) + self.change_encrypt_method() def set_net_prop(self, option, value): """ Sets the given option to the given value for this network. """ @@ -265,31 +285,108 @@ class WirelessNetEntry(NetEntryBase): """ Helper method for fetching/formatting wireless properties. """ return noneToBlankString(wireless.GetWirelessProperty(networkid, label)) + # Ripped from netentry.py + def save_settings(self, networkid): + # Check encryption info + if self.encryption_chkbox.get_state(): + #print "setting encryption info..." + encryption_info = self.encryption_info + encrypt_methods = misc.LoadEncryptionMethods() + self.set_net_prop("enctype", + 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.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.overlay, language['enable_encryption']) + return False + else: + #print 'encryption is ' + str(wireless.GetWirelessProperty(networkid, + # "encryption")) + #print "no encryption specified..." + self.set_net_prop("enctype", "None") + AdvancedSettingsDialog.save_settings(self) + + if self.global_settings_chkbox.get_state(): + self.set_net_prop('use_settings_globally', True) + else: + self.set_net_prop('use_settings_globally', False) + wireless.RemoveGlobalEssidEntry(networkid) + + wireless.SaveWirelessNetworkProfile(networkid) + return True + + # More or less ripped from netentry.py + def change_encrypt_method(self): + #self.lbox_encrypt = urwid.ListBox() + wid,ID = self.encryption_combo.get_focus() + methods = misc.LoadEncryptionMethods() + self.encryption_info = {} + + if self._w.body.body.__contains__(self.pile_encrypt): + self._w.body.body.pop(self._w.body.body.__len__()-2) + + # If nothing is selected, select the first entry. + if ID == -1: + self.encryption_combo.set_active(0) + ID = 0 + + opts = methods[ID][2] + theList = [] + for x in opts: + edit = None + if language.has_key(opts[x][0]): + edit = MaskingEdit(('editcp',language[opts[x][0].lower().replace(' ','_')]+': '),mask_mode='on_focus') + else: + edit = MaskingEdit(('editcp',opts[x][0].replace('_',' ')+': '),mask_mode='on_focus') + theList.append(edit) + # Add the data to any array, so that the information + # can be easily accessed by giving the name of the wanted + # data. + self.encryption_info[opts[x][1]] = edit + + edit.set_edit_text(noneToBlankString( + wireless.GetWirelessProperty(self.networkID, opts[x][1]))) + + self.pile_encrypt = DynWrap(urwid.Pile(theList),attrs=('editbx','editnfc')) + self._w.body.body.insert(self._w.body.body.__len__()-1,self.pile_encrypt) + #self._w.body.body.append(self.pile_encrypt) + def run(self,ui,dim,display): + self.ui = ui + self.parent = display width,height = ui.get_cols_rows() - list = [] - for x, enc_type in enumerate(self.encrypt_types): - list.append(enc_type[0]) - self.encryption_combo.set_list(list) - 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: + 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 - for k in keys: - #Send key to underlying widget: - overlay.keypress(dim, k) - # Check if buttons are pressed. - #if self.CANCEL_PRESSED: - # return False - #if self.OK_PRESSED or 'meta enter' in keys: - # return True + 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: + return False diff --git a/curses/prefs_curses.py b/curses/prefs_curses.py index 4f19361..b5d1ef9 100755 --- a/curses/prefs_curses.py +++ b/curses/prefs_curses.py @@ -109,6 +109,7 @@ class PrefsDialog(urwid.WidgetWrap): backend_cat_t = ('header',language['backend']) backend_t = language['backend']+':' backend_list = ['spam','double spam','triple spam','quadruple spam'] + backend_warn_t = ('important','Changes to the backend (probably) requires a daemon restart') debug_cat_t = ('header','Debugging') debug_mode_t = language['use_debug_mode'] @@ -207,6 +208,7 @@ class PrefsDialog(urwid.WidgetWrap): self.backend_cat = urwid.Text(backend_cat_t) self.backend_cbox = ComboBox(backend_t) + self.backend_warn = urwid.Text(backend_warn_t) self.debug_cat = urwid.Text(debug_cat_t) self.debug_mode_checkb = urwid.CheckBox(debug_mode_t) @@ -218,7 +220,7 @@ class PrefsDialog(urwid.WidgetWrap): advancedLB = urwid.ListBox([self.wpa_cat, self.wpa_cbox,self.wpa_warn,_blank, self.backend_cat, - self.backend_cbox,_blank, + self.backend_cbox,self.backend_warn,_blank, self.debug_cat, self.debug_mode_checkb, _blank, self.wless_cat, @@ -315,7 +317,7 @@ class PrefsDialog(urwid.WidgetWrap): # Pick where to begin first: def_driver = daemon.GetWPADriver() try: - self.wpa_cbox.set_show_first(self.wpadrivers.index(def_driver)) + self.wpa_cbox.set_focus(self.wpadrivers.index(def_driver)) except ValueError: pass # It defaults to 0 anyway @@ -326,9 +328,9 @@ class PrefsDialog(urwid.WidgetWrap): self.backend_cbox.set_list(self.thebackends) cur_backend = daemon.GetSavedBackend() try: - self.backend_cbox.set_show_first(self.thebackends.index(cur_backend)) + self.backend_cbox.set_focus(self.thebackends.index(cur_backend)) except ValueError: - self.backend_cbox.set_show_first(0) + self.backend_cbox.set_focus(0) # Two last checkboxes self.debug_mode_checkb.set_state(daemon.GetDebugMode()) @@ -343,7 +345,7 @@ class PrefsDialog(urwid.WidgetWrap): self.search_dom.get_edit_text()) daemon.SetWirelessInterface(self.wless_edit.get_edit_text()) daemon.SetWiredInterface(self.wired_edit.get_edit_text()) - daemon.SetWPADriver(self.wpadrivers[self.wpa_cbox.get_selected()[1]]) + daemon.SetWPADriver(self.wpadrivers[self.wpa_cbox.get_focus()[1]]) daemon.SetAlwaysShowWiredInterface(self.always_show_wired_checkb.get_state()) daemon.SetAutoReconnect(self.auto_reconn_checkb.get_state()) daemon.SetDebugMode(self.debug_mode_checkb.get_state()) @@ -355,7 +357,7 @@ class PrefsDialog(urwid.WidgetWrap): else: daemon.SetWiredAutoConnectMethod(1) - daemon.SetBackend(self.backends[self.backend_cbox.get_selected()[1]]) + daemon.SetBackend(self.backends[self.backend_cbox.get_focus()[1]]) # External Programs Tab if self.dhcp0.get_state(): @@ -423,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 fc483aa..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 WirelessNetEntry +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 @@ -303,7 +301,7 @@ class WiredComboBox(ComboBox): wiredL.append(theString) id+=1 self.__super.__init__(list=wiredL,use_enter=False) - self.set_show_first(theList.index(wired.GetDefaultWiredProfile())) + self.set_focus(theList.index(wired.GetDefaultWiredProfile())) def keypress(self,size,key): self.__super.keypress(size,key) @@ -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 @@ -503,27 +545,29 @@ class appGUI(): def idle_incr(self): theText = "" if self.connecting: - theText = "-- Connecting -- Press ESC to cancel" - self.footer1 = urwid.Text(str(self.incr) + ' '+theText) + theText = "-- Connecting -- Press ESC to cancel " + quit_note = "-- Press F8 or Q to quit." + self.footer1 = urwid.Text(str(self.incr) + ' '+theText+quit_note) self.incr+=1 return True # 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() @@ -553,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 @@ -575,30 +619,35 @@ class appGUI(): self.update_ui() if "A" in keys: about_dialog(self.frame) + if "C" in keys: + focus = self.thePile.get_focus() + if focus == self.wiredCB: + pass + else: + # wireless list only other option + wid,pos = self.thePile.get_focus().get_focus() + 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 self.frame.keypress( self.size, k ) - if "C" in keys: - focus = self.thePile.get_focus() - if focus == self.wiredCB: - pass - #self.connect("wired",0) - else: - # wless list only other option - wid,pos = self.thePile.get_focus().get_focus() - WirelessNetEntry(pos).run(ui,self.size,self.frame) - #self.connect("wireless",pos) - #self.netentry = NetEntryBase(dbusmanager.get_dbus_ifaces()) - #self.netentry.run(ui,self.size,self.frame) - if " " in keys: 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 @@ -630,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'), @@ -659,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 670b37d..7d81ba9 100644 --- a/in/man=wicd-curses.8.in +++ b/in/man=wicd-curses.8.in @@ -33,17 +33,25 @@ 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 .BR C Bring up network configuration controller for the selected network .PP -The following is not implemented yet: +The following are not implemented yet: .TP .BR S Bring up the script selector for the selected network (requires superuser privileges) - +.TP +.BR R +Bring up script selector "dialog." +.TP +.BR H +Bring up a rather simplistic help dialog. Of course, it mentions this man page first. :-) .SH "FILES" These are not used yet. .TP diff --git a/in/other=WHEREAREMYFILES.in b/in/other=WHEREAREMYFILES.in new file mode 100644 index 0000000..61363e9 --- /dev/null +++ b/in/other=WHEREAREMYFILES.in @@ -0,0 +1,14 @@ +If you are reading this, you are probably wondering why your Wicd configuration +files are not here. What follows is a summary of the folders that wicd uses. + +For a more detailed (and complete) description what is in each directory, consult the +man pages for wicd(8) and wicd-curses(8). + +~/.wicd + User-dependent configuration files, only used by wicd-curses + +%ETC% + Global configuration files + +%NETWORKS% + Individual network configurations diff --git a/in/scripts=wicd-client.in b/in/scripts=wicd-client.in index d79a061..f535254 100755 --- a/in/scripts=wicd-client.in +++ b/in/scripts=wicd-client.in @@ -1,2 +1,47 @@ #!/bin/bash +BOLD=`tput bold` +BLUE=`tput setaf 4` +NC=`tput sgr0` +# check_firstrun() +if [ ! -d ~/.wicd ]; then + mkdir ~/.wicd +fi +# Make sure the user knows WHEREAREMYFILES ;-) +if [ -e %DOCDIR%WHEREAREMYFILES ] && [ ! -L ~/.wicd/WHEREAREMYFILES ]; then + ln -s %DOCDIR%WHEREAREMYFILES ~/.wicd/WHEREAREMYFILES +fi +if [ "$DISPLAY" = "" ] && [ -x "%BIN%wicd-curses" ]; then + if [ ! -f ~/.wicd/CLIENT_CURSES_WARNING ]; then + echo "NOTICE: We see that you don't have an X server active on this console." + echo "We will now be starting ${BOLD}${BLUE}wicd-curses${NC}. If you desire" + echo "more information about what is happening here, please read:" + echo + echo "man wicd-client" + echo "-or-" + echo "man wicd-curses" + echo + echo "We apologize for any inconvenience. This message will not be displayed again." + echo "Please press enter to continue..." + + read junk + cat >>~/.wicd/CLIENT_CURSES_WARNING<