From 23297b3f7ed52a326c06e9d5ae3fabcc36b3696f Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Sat, 13 Dec 2008 13:29:07 -0500 Subject: [PATCH 01/50] Let there be light! curses/wicd-curses.py: ADDED (new (very incomplete) curses UI) curses/README: ADDED (Simple README. Hope it says enough for the moment) curses/TODO: ADDED (Simple, incomplete, TODO list) --- curses/README | 13 ++ curses/TODO | 15 ++ curses/wicd-curses.py | 339 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 367 insertions(+) create mode 100644 curses/README create mode 100644 curses/TODO create mode 100644 curses/wicd-curses.py diff --git a/curses/README b/curses/README new file mode 100644 index 0000000..fae294b --- /dev/null +++ b/curses/README @@ -0,0 +1,13 @@ +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's not going to install itself until I +work on it more and figure out how to use distutils. + +Right now, it only lists current available networks, and whether you are +connected to anything or not, and that is updated in real time. It does not +actually connect you to anything yet. I'll get on that when I have more free +time than I do now (which will be soon). + +~ ampsaltis diff --git a/curses/TODO b/curses/TODO new file mode 100644 index 0000000..0f9fd37 --- /dev/null +++ b/curses/TODO @@ -0,0 +1,15 @@ +Things to do (in no particular order): + +* Integrate a glib mainloop into the UI so that it can be aware of whether + we're connecting or not by some means. +* Implement the ability to connect/disconnect to/from stuff. + Yeah, I know that it's important... +* Make a settings dialog + * Implement something that resembles a combo box in urwid +* Make a network config dialog + +Oh, and most importantly: + +* Tell people how they can quit the app (F8, until I do all of that stuff) :-) + +Anything else? That's all I can think of now. diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py new file mode 100644 index 0000000..f35d4cf --- /dev/null +++ b/curses/wicd-curses.py @@ -0,0 +1,339 @@ +#!/usr/bin/env python + +""" wicd-curses -- a (cursed-based) console interface to wicd + +Provides the a console UI for wicd, so that people with broken X servers can +at least get a network connection. Or for those who don't like using X. :-) + +""" + +# Copyright (C) 2008 Andrew Psaltis + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +""" + This contains/will contain A LOT of code from the other parts of wicd. + + This is probably due to the fact that I did not really know what I was doing + when I started writing this. It works, so I guess that's all that matters. + + Comments, criticisms, patches all welcome! +""" + +# UI stuff +#import urwid.raw_display +import urwid.curses_display +import urwid + +# DBus communication stuff +import dbus +import dbus.service +# It took me a while to figure out that I have to use this. +import gobject + +# Other stuff +import wicd.misc as misc +#import sys + +# Both of these are not currently used, until I can best resolve how to use them +#import functions +#from functions import language #,Functions + +# Translations for the text that people will see... as of yet. This code is +# already found in the gui.py file +# Stick into own ui_common file? +_ = misc.get_gettext() +language = {} +language['connected_to_wireless'] = _('Connected to $A at $B (IP: $C)') +language['connected_to_wired'] = _('Connected to wired network (IP: $A)') +language['not_connected'] = _('Not connected') + +# I might not need this... but I'm not sure so much yet. +if getattr(dbus, 'version', (0, 0, 0)) < (0, 80, 0): + import dbus.glib +else: + from dbus.mainloop.glib import DBusGMainLoop + DBusGMainLoop(set_as_default=True) + +# Look familiar? These two functions are clones of functions found in wicd's +# gui.py file, except that now set_status is a function passed to them. +def check_for_wired(wired_ip,set_status): + """ Determine if wired is active, and if yes, set the status. """ + if wired_ip and wired.CheckPluggedIn(): + set_status(language['connected_to_wired'].replace('$A',wired_ip)) + return True + else: + return False + +def check_for_wireless(iwconfig, wireless_ip, set_status): + """ Determine if wireless is active, and if yes, set the status. """ + if not wireless_ip: + return False + + network = wireless.GetCurrentNetwork(iwconfig) + if not network: + return False + + network = str(network) + if daemon.GetSignalDisplayType() == 0: + strength = wireless.GetCurrentSignalStrength(iwconfig) + else: + strength = wireless.GetCurrentDBMStrength(iwconfig) + + if strength is None: + return False + strength = str(strength) + ip = str(wireless_ip) + set_status(language['connected_to_wireless'].replace + ('$A', network).replace + ('$B', daemon.FormatSignalForPrinting(strength)).replace + ('$C', wireless_ip)) + return True + + +# Self explanitory, and not used until I can get some list sort function +# working... +def gen_list_header(): + return '%3s %4s %s %19s %s ' % ('NUM','STR','BSSID','CHANNEL','ESSID') + +# Generate the list of networks. +# Mostly borrowed/stolen from wpa_cli, since I had no clue what all of those +# DBUS interfaces do. ^_^ +def gen_network_list(): + #theList = [urwid.Text(gen_list_header())] + theList = [] + + id = 0 + for profile in config.GetWiredProfileList(): + if id == 0: + #theList.append(urwid.Text("Wired Network(s):")) + theList.append(ListElem("Wired Network(s):")) + theList.append(NetElem('%3s%*s' % (id, 33+len(profile),profile))) + ++id + for network_id in range(0, wireless.GetNumberOfNetworks()): + if network_id == 0: + theList.append(ListElem("Wireless Network(s):")) + elem = '%3s %3s%% %17s %3s %s' % ( network_id, + wireless.GetWirelessProperty(network_id, 'quality'), + wireless.GetWirelessProperty(network_id, 'bssid'), + wireless.GetWirelessProperty(network_id, 'channel'), + wireless.GetWirelessProperty(network_id, 'essid')) + theList.append(NetElem(elem)) + return theList + +# Widget representing an individual network element +# This will be more complicated later, once I know the rest of it works +class NetElem(urwid.WidgetWrap): + """Defines a selectable element, either a wireless or wired network profile, + in a NetList + """ + def __init__(self, theText): + self.label = urwid.AttrWrap(urwid.Text(theText),None) + w = self.label + self.__super.__init__(w) + self.selected = False + self.update_w() + + # Make the thing selectable. + def selectable(self): + return True + + # Update the widget. + # Called by NetList below pretty often + def update_w(self): + if self.selected: + self._w.attr = 'selected' + self._w.focus_attr = 'selected' + else: + self._w.attr = 'body' + self._w.focus_attr = 'body' + + # Don't handle any keys... yet + def keypress(self, size, key): + return key + +# Hackish. Designed to make my problems go away until I get around to cleaning +# this thing up. NetElem should be a subclass of ListElem. It'll make more +# sense later, once I start cleaning up some of the code... +class ListElem(NetElem): + """ Defines a non-selectable element that happens to be hanging out in a + NetList + """ + def selectable(self): + return False + +# Class representing the list of networks that appears in the middle. +# Just a listbox with some special features +class NetList(urwid.WidgetWrap): + """ The list of elements that sits in the middle of the screen most of the + time. + """ + def __init__(self, elems): + self.lbox = urwid.AttrWrap(urwid.ListBox(elems),'body') + w = self.lbox + self.__super.__init__(w) + #self.selected = False + # The first element in the list is to be selected first, since that one + # is a header + elems[1].selected = True + elems[1].update_w() + #widget.update_w() + + # Pick the selected-ness of the app + def update_selected(self,is_selected): + (elem, num) = self.w.get_focus() + elem.selected = is_selected + elem.update_w() + + # Updates the selected element, moves the focused element, and then selects + # that one, then updates its selection status + def keypress(self, size, key): + self.update_selected(False) + self.w.keypress(size,key) + (widget, num) = self.lbox.get_focus() + widget.selected = True + self.update_selected(True) + +# The Whole Shebang +class appGUI(): + """The UI itself, all glory belongs to it!""" + def __init__(self): + # Happy screen saying that you can't do anything because we're scanning + # for networks. :-) + # And I can't use it yet b/c of that blasted glib mainloop + self.screen_locker = urwid.Filler(urwid.Text(('important',"Scanning networks... stand by..."), align='center')) + + txt = urwid.Text("Wicd Curses Interface",align='right') + #wrap1 = urwid.AttrWrap(txt, 'black') + #fill = urwid.Filler(txt) + + header = urwid.AttrWrap(txt, 'header') + self.update_netlist() + #walker = urwid.SimpleListWalker(gen_network_list()) + + #thePile = urwid.Pile(walker) + footer = urwid.AttrWrap(urwid.Text("Something will go here... eventually!"),'important') + # Pop takes a number! + #walker.pop(1) + #self.listbox = urwid.AttrWrap(urwid.ListBox(netList),'body','selected') + self.frame = urwid.Frame(self.netList, header=header,footer=footer) + #self.frame = urwid.Frame(self.screen_locker, header=header,footer=footer) + self.update_status() + + # Does what it says it does + def lock_screen(self): + self.frame.set_body(self.screen_locker) + + def unlock_screen(self): + self.update_netlist() + self.frame.set_body(self.netList) + + # Be clunky until I get to a later stage of development. + def update_netlist(self): + netElems = gen_network_list() + self.netList = NetList(netElems) + + def update_status(self): + if check_for_wired(wired.GetWiredIP(),self.set_status): + return True + elif check_for_wireless(wireless.GetIwconfig(), + wireless.GetWirelessIP(), self.set_status): + return True + else: + self.set_status(language['not_connected']) + return True + + def set_status(self,text): + self.frame.set_footer(urwid.AttrWrap(urwid.Text(text),'important')) + + # Yeah, I'm copying code. Anything wrong with that? + #def dbus_scan_finished(self): + # #if not self.connecting: + # #self.refresh_networks(fresh=False) + # self.unlock_screen() + + # Same, same, same, same, same, same + #def dbus_scan_started(self): + # self.lock_screen() + + # Run the bleeding thing. + # Calls the main loop. This is how the thing should be started, at least + # until I decide to change it, whenever that is. + def main(self): + misc.RenameProcess('urwicd') + self.ui = urwid.curses_display.Screen() + self.ui.register_palette([ + ('body','light gray','black'), + ('selected','dark blue','light gray'), + ('header','light blue','black'), + ('important','light red','black')]) + self.ui.run_wrapper(self.run) + + # Main program loop + def run(self): + size = self.ui.get_cols_rows() + + # This doesn't do what I need it to do! + # What I will have to do is... (unless I totally misunderstand glib) + # 1. Stick all this loop into another function (probably update_ui) + # 2. Make a glib MainLoop object somewhere in this file + # 3. Connect the DBus Main Loop to that main loop + # 4. Throw update_ui into gobject.timeout() + # 5. Pray. :-) + while True: + self.update_status() + canvas = self.frame.render( (size) ) + self.ui.draw_screen((size),canvas) + keys = self.ui.get_input() + if "f8" in keys: + break + for k in keys: + if k == "window resize": + size = self.ui.get_cols_rows() + continue + self.frame.keypress( size, k ) + +# Mostly borrowed from gui.py, but also with the standard "need daemon first" +# check +def setup_dbus(): + global proxy_obj, daemon, wireless, wired, config, dbus_ifaces + try: + proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon') + except dbus.DBusException: + print 'Error: Could not connect to the daemon. Please make sure it is running.' + sys.exit(3) + daemon = dbus.Interface(proxy_obj, 'org.wicd.daemon') + wireless = dbus.Interface(proxy_obj, 'org.wicd.daemon.wireless') + wired = dbus.Interface(proxy_obj, 'org.wicd.daemon.wired') + config = dbus.Interface(proxy_obj, 'org.wicd.daemon.config') + + dbus_ifaces = {"daemon" : daemon, "wireless" : wireless, "wired" : wired, + "config" : config} + +bus = dbus.SystemBus() +setup_dbus() +# Main entry point +if __name__ == '__main__': + app = appGUI() + + # This stuff doesn't work yet. I have to stick a gobject mainloop in to get + # it to work... It'll be done soon enough + #bus.add_signal_receiver(app.dbus_scan_finished, 'SendEndScanSignal', + # 'org.wicd.daemon') + #bus.add_signal_receiver(app.dbus_scan_started, 'SendStartScanSignal', + # 'org.wicd.daemon') + + app.main() From 64fd3940d62a612d29e46dd5cb68c8ec8154bf40 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Sat, 13 Dec 2008 16:06:11 -0500 Subject: [PATCH 02/50] curses/wicd-curses.py: Add gobject.MainLoop support, and enable the D-Bus function connections (It works!). Various comments/code cleanup done. curses/README: f5 refreshes the netlist now curses/TODO: Added a bunch of features to implement, and removed one of them. --- curses/README | 10 +++- curses/TODO | 6 ++- curses/wicd-curses.py | 103 ++++++++++++++++++++++++------------------ 3 files changed, 72 insertions(+), 47 deletions(-) diff --git a/curses/README b/curses/README index fae294b..4b6bdce 100644 --- a/curses/README +++ b/curses/README @@ -1,4 +1,4 @@ -This is a CURSES-based client for wicd. It is designed to imitate wicd-client +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. @@ -10,4 +10,10 @@ connected to anything or not, and that is updated in real time. It does not actually connect you to anything yet. I'll get on that when I have more free time than I do now (which will be soon). -~ ampsaltis +Other important things: + +F5: refresh wireless networks +F8: quit + + +~nacl diff --git a/curses/TODO b/curses/TODO index 0f9fd37..579bfb6 100644 --- a/curses/TODO +++ b/curses/TODO @@ -1,12 +1,14 @@ Things to do (in no particular order): -* Integrate a glib mainloop into the UI so that it can be aware of whether - we're connecting or not by some means. * Implement the ability to connect/disconnect to/from stuff. Yeah, I know that it's important... * Make a settings dialog * Implement something that resembles a combo box in urwid * Make a network config dialog +* Make an about dialog +* Implement a keyhandler function for the overall frame + * Make keystrokes customizable +* Make color schemes customizable Oh, and most importantly: diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index f35d4cf..c7ba294 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -""" wicd-curses -- a (cursed-based) console interface to wicd +""" wicd-curses -- a (curses-based) console interface to wicd Provides the a console UI for wicd, so that people with broken X servers can at least get a network connection. Or for those who don't like using X. :-) @@ -44,14 +44,10 @@ import dbus.service # It took me a while to figure out that I have to use this. import gobject -# Other stuff +# Other important wicd-related stuff import wicd.misc as misc #import sys -# Both of these are not currently used, until I can best resolve how to use them -#import functions -#from functions import language #,Functions - # Translations for the text that people will see... as of yet. This code is # already found in the gui.py file # Stick into own ui_common file? @@ -216,6 +212,8 @@ class appGUI(): # And I can't use it yet b/c of that blasted glib mainloop self.screen_locker = urwid.Filler(urwid.Text(('important',"Scanning networks... stand by..."), align='center')) + #self.update_ct = 0 + txt = urwid.Text("Wicd Curses Interface",align='right') #wrap1 = urwid.AttrWrap(txt, 'black') #fill = urwid.Filler(txt) @@ -224,7 +222,6 @@ class appGUI(): self.update_netlist() #walker = urwid.SimpleListWalker(gen_network_list()) - #thePile = urwid.Pile(walker) footer = urwid.AttrWrap(urwid.Text("Something will go here... eventually!"),'important') # Pop takes a number! #walker.pop(1) @@ -246,7 +243,9 @@ class appGUI(): netElems = gen_network_list() self.netList = NetList(netElems) + # Update the footer/status bar def update_status(self): + #self.update_ct += 1 if check_for_wired(wired.GetWiredIP(),self.set_status): return True elif check_for_wireless(wireless.GetIwconfig(), @@ -256,58 +255,77 @@ class appGUI(): self.set_status(language['not_connected']) return True + # Set the status text, called by the update_status method def set_status(self,text): self.frame.set_footer(urwid.AttrWrap(urwid.Text(text),'important')) # Yeah, I'm copying code. Anything wrong with that? - #def dbus_scan_finished(self): - # #if not self.connecting: - # #self.refresh_networks(fresh=False) - # self.unlock_screen() + 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() # Same, same, same, same, same, same - #def dbus_scan_started(self): - # self.lock_screen() + def dbus_scan_started(self): + self.lock_screen() # Run the bleeding thing. # Calls the main loop. This is how the thing should be started, at least # until I decide to change it, whenever that is. def main(self): - misc.RenameProcess('urwicd') + misc.RenameProcess('wicd-curses') self.ui = urwid.curses_display.Screen() + # Color scheme + # Other potential color schemes can be found at: + # http://excess.org/urwid/wiki/RecommendedPalette self.ui.register_palette([ ('body','light gray','black'), - ('selected','dark blue','light gray'), + ('selected','dark magenta','light gray'), ('header','light blue','black'), ('important','light red','black')]) + # This is a wrapper around a function that calls another a function that is a + # wrapper around a infinite loop. Fun. self.ui.run_wrapper(self.run) # Main program loop def run(self): - size = self.ui.get_cols_rows() + self.size = self.ui.get_cols_rows() - # This doesn't do what I need it to do! - # What I will have to do is... (unless I totally misunderstand glib) - # 1. Stick all this loop into another function (probably update_ui) - # 2. Make a glib MainLoop object somewhere in this file - # 3. Connect the DBus Main Loop to that main loop - # 4. Throw update_ui into gobject.timeout() - # 5. Pray. :-) - while True: - self.update_status() - canvas = self.frame.render( (size) ) - self.ui.draw_screen((size),canvas) - keys = self.ui.get_input() - if "f8" in keys: - break - for k in keys: - if k == "window resize": - size = self.ui.get_cols_rows() - continue - self.frame.keypress( size, k ) + # This actually makes some things easier to do, amusingly enough + self.loop = gobject.MainLoop() + # Update what the interface looks like every 0.5 ms + gobject.timeout_add(0.5,self.update_ui) + # Update the connection status on the bottom every 0.5 s + gobject.timeout_add(500,self.update_status) + # Terminate the loop if the UI is terminated. + gobject.idle_add(self.stop_loop) + self.loop.run() -# Mostly borrowed from gui.py, but also with the standard "need daemon first" -# check + # Redraw the screen + def update_ui(self): + #self.update_status() + canvas = self.frame.render( (self.size) ) + self.ui.draw_screen((self.size),canvas) + keys = self.ui.get_input() + # Should make a keyhandler method, but this will do until I get around to + # that stage + if "f8" in keys: + return False + if "f5" in keys: + wireless.Scan() + for k in keys: + if k == "window resize": + self.size = self.ui.get_cols_rows() + continue + self.frame.keypress( self.size, k ) + return True + + # Terminate the loop, used as the glib mainloop's idle function + def stop_loop(self): + self.loop.quit() + +# Mostly borrowed from gui.py, but also with the "need daemon first" check def setup_dbus(): global proxy_obj, daemon, wireless, wired, config, dbus_ifaces try: @@ -329,11 +347,10 @@ setup_dbus() if __name__ == '__main__': app = appGUI() - # This stuff doesn't work yet. I have to stick a gobject mainloop in to get - # it to work... It'll be done soon enough - #bus.add_signal_receiver(app.dbus_scan_finished, 'SendEndScanSignal', - # 'org.wicd.daemon') - #bus.add_signal_receiver(app.dbus_scan_started, 'SendStartScanSignal', - # 'org.wicd.daemon') + # Connect signals and whatnot to UI screen control functions + bus.add_signal_receiver(app.dbus_scan_finished, 'SendEndScanSignal', + 'org.wicd.daemon') + bus.add_signal_receiver(app.dbus_scan_started, 'SendStartScanSignal', + 'org.wicd.daemon') app.main() From d8ae040ae664dc0f6ad2087d3d321ac13792fd2e Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Sun, 14 Dec 2008 01:04:23 -0500 Subject: [PATCH 03/50] curses/wicd-curses.py: Cleaned up code for the Net/ListElements. Added '>' to mark to currently selected network. Set gen_network_list() to output signal quality in units specified in the config. --- curses/TODO | 1 + curses/wicd-curses.py | 80 +++++++++++++++++++++++++++++-------------- 2 files changed, 56 insertions(+), 25 deletions(-) diff --git a/curses/TODO b/curses/TODO index 579bfb6..710ee79 100644 --- a/curses/TODO +++ b/curses/TODO @@ -9,6 +9,7 @@ Things to do (in no particular order): * Implement a keyhandler function for the overall frame * Make keystrokes customizable * Make color schemes customizable +* Add code to restore the screen if _anything_ bad happens Oh, and most importantly: diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index c7ba294..dbb527f 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -57,7 +57,6 @@ language['connected_to_wireless'] = _('Connected to $A at $B (IP: $C)') language['connected_to_wired'] = _('Connected to wired network (IP: $A)') language['not_connected'] = _('Not connected') -# I might not need this... but I'm not sure so much yet. if getattr(dbus, 'version', (0, 0, 0)) < (0, 80, 0): import dbus.glib else: @@ -112,35 +111,72 @@ def gen_network_list(): #theList = [urwid.Text(gen_list_header())] theList = [] + # Pick which strength measure to use based on what the daemon says + if daemon.GetSignalDisplayType() == 0: + strenstr = 'quality' + gap = 3 + else: + strenstr = 'strength' + gap = 5 + id = 0 for profile in config.GetWiredProfileList(): if id == 0: #theList.append(urwid.Text("Wired Network(s):")) theList.append(ListElem("Wired Network(s):")) - theList.append(NetElem('%3s%*s' % (id, 33+len(profile),profile))) - ++id + theString = '%4s%*s' % (id, 32+len(profile),profile) + #### THIS IS wired.blah() in experimental + #print config.GetLastUsedWiredNetwork() + # Tag if no wireless IP present, and wired one is + if wireless.GetWirelessIP() == None and wired.GetWiredIP() != None: + theString = '>'+theString[1:] + + theList.append(NetElem(theString,id )) + id+=1 for network_id in range(0, wireless.GetNumberOfNetworks()): if network_id == 0: theList.append(ListElem("Wireless Network(s):")) - elem = '%3s %3s%% %17s %3s %s' % ( network_id, - wireless.GetWirelessProperty(network_id, 'quality'), + + theString = '%4s %*s %17s %3s %s' % ( network_id, + gap,daemon.FormatSignalForPrinting( + str(wireless.GetWirelessProperty(network_id, strenstr))), wireless.GetWirelessProperty(network_id, 'bssid'), wireless.GetWirelessProperty(network_id, 'channel'), wireless.GetWirelessProperty(network_id, 'essid')) - theList.append(NetElem(elem)) + # This returns -1 if no ID is found, so we I could put this outside of this + # loop. I'll do that soon. + if wireless.GetCurrentNetworkID( wireless.GetIwconfig() ) == network_id: + theString = '>'+theString[1:] + theList.append(NetElem(theString,network_id)) return theList -# Widget representing an individual network element -# This will be more complicated later, once I know the rest of it works -class NetElem(urwid.WidgetWrap): - """Defines a selectable element, either a wireless or wired network profile, - in a NetList - """ +class ListElem(urwid.WidgetWrap): + """ Defines a (generic) non-selectable element that hangs out in a NetList""" def __init__(self, theText): self.label = urwid.AttrWrap(urwid.Text(theText),None) w = self.label self.__super.__init__(w) + #self.update_w() + def selectable(self): + return False + + def update_w(self): + pass + + # Don't handle any keys in the superclass + def keypress(self, size, key): + return key + +# Widget representing an individual network +# This will be more complicated later, once I know the rest of it works +class NetElem(ListElem): + """Defines a selectable element, either a wireless or wired network profile, + in a NetList + """ + def __init__(self, theText,theId): self.selected = False + self.id = theId + self.__super.__init__(theText) self.update_w() # Make the thing selectable. @@ -161,15 +197,6 @@ class NetElem(urwid.WidgetWrap): def keypress(self, size, key): return key -# Hackish. Designed to make my problems go away until I get around to cleaning -# this thing up. NetElem should be a subclass of ListElem. It'll make more -# sense later, once I start cleaning up some of the code... -class ListElem(NetElem): - """ Defines a non-selectable element that happens to be hanging out in a - NetList - """ - def selectable(self): - return False # Class representing the list of networks that appears in the middle. # Just a listbox with some special features @@ -182,7 +209,7 @@ class NetList(urwid.WidgetWrap): w = self.lbox self.__super.__init__(w) #self.selected = False - # The first element in the list is to be selected first, since that one + # The 1th element in the list is to be selected first, since that one # is a header elems[1].selected = True elems[1].update_w() @@ -190,15 +217,18 @@ class NetList(urwid.WidgetWrap): # Pick the selected-ness of the app def update_selected(self,is_selected): - (elem, num) = self.w.get_focus() + (elem, num) = self._w.get_focus() elem.selected = is_selected elem.update_w() # Updates the selected element, moves the focused element, and then selects - # that one, then updates its selection status + # that one, then updates its selection status. + # TODO: Pressing "Enter" would disconnect you from your current network, and + # connect you to the selected one def keypress(self, size, key): + #if key == 'down' or key == 'up': self.update_selected(False) - self.w.keypress(size,key) + self._w.keypress(size,key) (widget, num) = self.lbox.get_focus() widget.selected = True self.update_selected(True) From d23af8337122144a6f3e21cdd818f23aa4616096 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Mon, 15 Dec 2008 17:50:00 -0500 Subject: [PATCH 04/50] curses/wicd-curses.py: Colorized the network we're currently connected to. That network is now updated every time that wicd tells us that the "status" has changed. Network connection status is now updated every 2 seconds, instead of every 0.5. --- curses/README | 1 - curses/TODO | 3 +- curses/wicd-curses.py | 106 ++++++++++++++++++++++++++++-------------- 3 files changed, 74 insertions(+), 36 deletions(-) diff --git a/curses/README b/curses/README index 4b6bdce..1db3021 100644 --- a/curses/README +++ b/curses/README @@ -15,5 +15,4 @@ Other important things: F5: refresh wireless networks F8: quit - ~nacl diff --git a/curses/TODO b/curses/TODO index 710ee79..d659e6b 100644 --- a/curses/TODO +++ b/curses/TODO @@ -9,7 +9,8 @@ Things to do (in no particular order): * Implement a keyhandler function for the overall frame * Make keystrokes customizable * Make color schemes customizable -* Add code to restore the screen if _anything_ bad happens +* Add code to restore the terminal if _anything_ bad happens. I have an idea about + how to do it. Ask me about it if you know some Python. Oh, and most importantly: diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index dbb527f..6baa552 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -3,7 +3,7 @@ """ wicd-curses -- a (curses-based) console interface to wicd Provides the a console UI for wicd, so that people with broken X servers can -at least get a network connection. Or for those who don't like using X. :-) +at least get a network connection. Or those who don't like using X. :-) """ @@ -30,7 +30,7 @@ at least get a network connection. Or for those who don't like using X. :-) This is probably due to the fact that I did not really know what I was doing when I started writing this. It works, so I guess that's all that matters. - Comments, criticisms, patches all welcome! + Comments, criticisms, patches, bug reports all welcome! """ # UI stuff @@ -128,10 +128,11 @@ def gen_network_list(): #### THIS IS wired.blah() in experimental #print config.GetLastUsedWiredNetwork() # Tag if no wireless IP present, and wired one is - if wireless.GetWirelessIP() == None and wired.GetWiredIP() != None: + is_active = wireless.GetWirelessIP() == None and wired.GetWiredIP() != None + if is_active: theString = '>'+theString[1:] - theList.append(NetElem(theString,id )) + theList.append(NetElem(theString,id,is_active)) id+=1 for network_id in range(0, wireless.GetNumberOfNetworks()): if network_id == 0: @@ -145,9 +146,10 @@ def gen_network_list(): wireless.GetWirelessProperty(network_id, 'essid')) # This returns -1 if no ID is found, so we I could put this outside of this # loop. I'll do that soon. - if wireless.GetCurrentNetworkID( wireless.GetIwconfig() ) == network_id: + is_active = wireless.GetPrintableSignalStrength("") != 0 and wireless.GetCurrentNetworkID(wireless.GetIwconfig())==network_id + if is_active: theString = '>'+theString[1:] - theList.append(NetElem(theString,network_id)) + theList.append(NetElem(theString,network_id,is_active)) return theList class ListElem(urwid.WidgetWrap): @@ -173,10 +175,18 @@ class NetElem(ListElem): """Defines a selectable element, either a wireless or wired network profile, in a NetList """ - def __init__(self, theText,theId): - self.selected = False + def __init__(self, theText,theId,is_active): + self.is_selected = False self.id = theId self.__super.__init__(theText) + + # Color the text differently if we are connected to that network + self.body = 'body' + self.selected = 'selected' + if is_active: + self.body = 'connected' + self.selected = 'connected_sel' + self.update_w() # Make the thing selectable. @@ -186,12 +196,12 @@ class NetElem(ListElem): # Update the widget. # Called by NetList below pretty often def update_w(self): - if self.selected: - self._w.attr = 'selected' - self._w.focus_attr = 'selected' + if self.is_selected: + self._w.attr = self.selected + self._w.focus_attr = self.selected else: - self._w.attr = 'body' - self._w.focus_attr = 'body' + self._w.attr = self.body + self._w.focus_attr = self.body # Don't handle any keys... yet def keypress(self, size, key): @@ -211,14 +221,14 @@ class NetList(urwid.WidgetWrap): #self.selected = False # The 1th element in the list is to be selected first, since that one # is a header - elems[1].selected = True + elems[1].is_selected = True elems[1].update_w() #widget.update_w() # Pick the selected-ness of the app def update_selected(self,is_selected): (elem, num) = self._w.get_focus() - elem.selected = is_selected + elem.is_selected = is_selected elem.update_w() # Updates the selected element, moves the focused element, and then selects @@ -229,8 +239,8 @@ class NetList(urwid.WidgetWrap): #if key == 'down' or key == 'up': self.update_selected(False) self._w.keypress(size,key) - (widget, num) = self.lbox.get_focus() - widget.selected = True + #(widget, num) = self.lbox.get_focus() + #widget.is_selected = True self.update_selected(True) # The Whole Shebang @@ -239,17 +249,17 @@ class appGUI(): def __init__(self): # Happy screen saying that you can't do anything because we're scanning # for networks. :-) - # And I can't use it yet b/c of that blasted glib mainloop self.screen_locker = urwid.Filler(urwid.Text(('important',"Scanning networks... stand by..."), align='center')) - #self.update_ct = 0 - + #self.update_ct = 0 txt = urwid.Text("Wicd Curses Interface",align='right') #wrap1 = urwid.AttrWrap(txt, 'black') #fill = urwid.Filler(txt) header = urwid.AttrWrap(txt, 'header') - self.update_netlist() + #self.update_netlist() + netElems = gen_network_list() + self.netList = NetList(netElems) #walker = urwid.SimpleListWalker(gen_network_list()) footer = urwid.AttrWrap(urwid.Text("Something will go here... eventually!"),'important') @@ -258,6 +268,7 @@ class appGUI(): #self.listbox = urwid.AttrWrap(urwid.ListBox(netList),'body','selected') self.frame = urwid.Frame(self.netList, header=header,footer=footer) #self.frame = urwid.Frame(self.screen_locker, header=header,footer=footer) + self.prev_state = False self.update_status() # Does what it says it does @@ -265,13 +276,22 @@ class appGUI(): self.frame.set_body(self.screen_locker) def unlock_screen(self): - self.update_netlist() + self.update_netlist(force_check=True) self.frame.set_body(self.netList) # Be clunky until I get to a later stage of development. - def update_netlist(self): - netElems = gen_network_list() - self.netList = NetList(netElems) + # Update the list of networks. Usually called by DBus. + # TODO: Preserve current focus when updating the list. + def update_netlist(self,state=None, x=None, force_check=False): + """ Updates the overall network list.""" + if not state: + state, x = daemon.GetConnectionStatus() + if self.prev_state != state or force_check: + netElems = gen_network_list() + self.netList = NetList(netElems) + self.frame.set_body(self.netList) + + self.prev_state = state # Update the footer/status bar def update_status(self): @@ -291,10 +311,14 @@ class appGUI(): # Yeah, I'm copying code. Anything wrong with that? 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 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() # Same, same, same, same, same, same def dbus_scan_started(self): @@ -306,14 +330,16 @@ class appGUI(): def main(self): misc.RenameProcess('wicd-curses') self.ui = urwid.curses_display.Screen() - # Color scheme + # Color scheme. # Other potential color schemes can be found at: # http://excess.org/urwid/wiki/RecommendedPalette self.ui.register_palette([ ('body','light gray','black'), ('selected','dark magenta','light gray'), ('header','light blue','black'), - ('important','light red','black')]) + ('important','light red','black'), + ('connected','dark green','black'), + ('connected_sel','black','dark green')]) # This is a wrapper around a function that calls another a function that is a # wrapper around a infinite loop. Fun. self.ui.run_wrapper(self.run) @@ -325,14 +351,25 @@ class appGUI(): # This actually makes some things easier to do, amusingly enough self.loop = gobject.MainLoop() # Update what the interface looks like every 0.5 ms + # Apparently this is deprecated. May have to change this. gobject.timeout_add(0.5,self.update_ui) - # Update the connection status on the bottom every 0.5 s - gobject.timeout_add(500,self.update_status) + # Update the connection status on the bottom every 2 s + gobject.timeout_add(2000,self.update_status) # Terminate the loop if the UI is terminated. gobject.idle_add(self.stop_loop) self.loop.run() # Redraw the screen + # There exists a problem with this where any exceptions that occur (especially of + # the DBus variety) will get spread out on the top of the screen, or not displayed + # at all. Urwid and the glib main loop don't mix all too well. I may need to + # consult the Urwid maintainer about this. + # + # I believe that I have a fix for this. It just involves wrapping every single + # function that might throw an exception with a try-except block, using a function + # wrapper. I have tested it, and it seems to work, but I'll save it until I can + # evaluate what I need to wrap. Probably a vast majority of stuff, until I am sure + # that this is stable. def update_ui(self): #self.update_status() canvas = self.frame.render( (self.size) ) @@ -382,5 +419,6 @@ if __name__ == '__main__': 'org.wicd.daemon') bus.add_signal_receiver(app.dbus_scan_started, 'SendStartScanSignal', 'org.wicd.daemon') - + bus.add_signal_receiver(app.update_netlist, 'StatusChanged', + 'org.wicd.daemon') app.main() From 868469ef90159c39a7018023a0d43f3a9e48fa5a Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Wed, 17 Dec 2008 11:27:09 -0500 Subject: [PATCH 05/50] curses/wicd-curses.py: Added code to restore the console on all errors, and then print them, including KeyboardInterrupts. curses/TODO: Removed the above from TODO --- curses/TODO | 2 - curses/wicd-curses.py | 85 +++++++++++++++++++++++++++++++++---------- 2 files changed, 66 insertions(+), 21 deletions(-) diff --git a/curses/TODO b/curses/TODO index d659e6b..579bfb6 100644 --- a/curses/TODO +++ b/curses/TODO @@ -9,8 +9,6 @@ Things to do (in no particular order): * Implement a keyhandler function for the overall frame * Make keystrokes customizable * Make color schemes customizable -* Add code to restore the terminal if _anything_ bad happens. I have an idea about - how to do it. Ask me about it if you know some Python. Oh, and most importantly: diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 6baa552..639d931 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -46,11 +46,13 @@ import gobject # Other important wicd-related stuff import wicd.misc as misc -#import sys + +# Internal Python stuff +import sys # Translations for the text that people will see... as of yet. This code is # already found in the gui.py file -# Stick into own ui_common file? +# IN EXPERIMENTAL, THIS IS ALL IN wicd.misc _ = misc.get_gettext() language = {} language['connected_to_wireless'] = _('Connected to $A at $B (IP: $C)') @@ -63,8 +65,42 @@ else: from dbus.mainloop.glib import DBusGMainLoop DBusGMainLoop(set_as_default=True) +# A hack to get any errors that pop out of the program to appear ***AFTER*** the +# program exits. +# I also may have been a bit overkill about using this too, I guess I'll find that out +# soon enough. +class wrap_exceptions: + def __call__(self, f): + def wrap_exceptions(*args, **kargs): + try: + return f(*args, **kargs) + except KeyboardInterrupt: + gobject.source_remove(redraw_tag) + loop.quit() + ui.stop() + print "Terminated by user." + raise + except : + # Remove update_ui from the event queue + gobject.source_remove(redraw_tag) + # Quit the loop + loop.quit() + # Zap the screen + ui.stop() + # Print out standard notification: + print "EXCEPTION!" + print "Please report this to the maintainer and/or file a bug report with the backtrace below:" + # Flush the buffer so that the notification is always above the + # backtrace + sys.stdout.flush() + # Raise the exception + raise + + return wrap_exceptions + # Look familiar? These two functions are clones of functions found in wicd's # gui.py file, except that now set_status is a function passed to them. +@wrap_exceptions() def check_for_wired(wired_ip,set_status): """ Determine if wired is active, and if yes, set the status. """ if wired_ip and wired.CheckPluggedIn(): @@ -73,6 +109,7 @@ def check_for_wired(wired_ip,set_status): else: return False +@wrap_exceptions() def check_for_wireless(iwconfig, wireless_ip, set_status): """ Determine if wireless is active, and if yes, set the status. """ if not wireless_ip: @@ -107,6 +144,7 @@ def gen_list_header(): # Generate the list of networks. # Mostly borrowed/stolen from wpa_cli, since I had no clue what all of those # DBUS interfaces do. ^_^ +@wrap_exceptions() def gen_network_list(): #theList = [urwid.Text(gen_list_header())] theList = [] @@ -235,6 +273,7 @@ class NetList(urwid.WidgetWrap): # that one, then updates its selection status. # TODO: Pressing "Enter" would disconnect you from your current network, and # connect you to the selected one + #@wrap_exceptions() def keypress(self, size, key): #if key == 'down' or key == 'up': self.update_selected(False) @@ -249,6 +288,7 @@ class appGUI(): def __init__(self): # Happy screen saying that you can't do anything because we're scanning # for networks. :-) + # Will need a translation sooner or later self.screen_locker = urwid.Filler(urwid.Text(('important',"Scanning networks... stand by..."), align='center')) #self.update_ct = 0 @@ -278,10 +318,14 @@ class appGUI(): def unlock_screen(self): self.update_netlist(force_check=True) self.frame.set_body(self.netList) + # I'm hoping that this will get rid of Adam's problem with the NetList not + # redisplaying itself immediately upon completion. + update_ui() # 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): """ Updates the overall network list.""" if not state: @@ -294,6 +338,7 @@ class appGUI(): self.prev_state = state # Update the footer/status bar + @wrap_exceptions() def update_status(self): #self.update_ct += 1 if check_for_wired(wired.GetWiredIP(),self.set_status): @@ -310,6 +355,7 @@ class appGUI(): self.frame.set_footer(urwid.AttrWrap(urwid.Text(text),'important')) # 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: @@ -321,6 +367,7 @@ class appGUI(): self.update_ui() # Same, same, same, same, same, same + @wrap_exceptions() def dbus_scan_started(self): self.lock_screen() @@ -328,12 +375,13 @@ class appGUI(): # Calls the main loop. This is how the thing should be started, at least # until I decide to change it, whenever that is. def main(self): + global ui misc.RenameProcess('wicd-curses') - self.ui = urwid.curses_display.Screen() + ui = urwid.curses_display.Screen() # Color scheme. # Other potential color schemes can be found at: # http://excess.org/urwid/wiki/RecommendedPalette - self.ui.register_palette([ + ui.register_palette([ ('body','light gray','black'), ('selected','dark magenta','light gray'), ('header','light blue','black'), @@ -342,22 +390,24 @@ class appGUI(): ('connected_sel','black','dark green')]) # This is a wrapper around a function that calls another a function that is a # wrapper around a infinite loop. Fun. - self.ui.run_wrapper(self.run) + ui.run_wrapper(self.run) # Main program loop def run(self): - self.size = self.ui.get_cols_rows() + global loop,redraw_tag + self.size = ui.get_cols_rows() # This actually makes some things easier to do, amusingly enough - self.loop = gobject.MainLoop() + loop = gobject.MainLoop() # Update what the interface looks like every 0.5 ms - # Apparently this is deprecated. May have to change this. - gobject.timeout_add(0.5,self.update_ui) + # Apparently this is use (with fractional seconds) is deprecated. May have to + # change this. + redraw_tag = gobject.timeout_add(0.5,self.update_ui) # Update the connection status on the bottom every 2 s gobject.timeout_add(2000,self.update_status) # Terminate the loop if the UI is terminated. gobject.idle_add(self.stop_loop) - self.loop.run() + loop.run() # Redraw the screen # There exists a problem with this where any exceptions that occur (especially of @@ -365,16 +415,13 @@ class appGUI(): # at all. Urwid and the glib main loop don't mix all too well. I may need to # consult the Urwid maintainer about this. # - # I believe that I have a fix for this. It just involves wrapping every single - # function that might throw an exception with a try-except block, using a function - # wrapper. I have tested it, and it seems to work, but I'll save it until I can - # evaluate what I need to wrap. Probably a vast majority of stuff, until I am sure - # that this is stable. + # The implementation of this solution + @wrap_exceptions() def update_ui(self): #self.update_status() canvas = self.frame.render( (self.size) ) - self.ui.draw_screen((self.size),canvas) - keys = self.ui.get_input() + ui.draw_screen((self.size),canvas) + keys = ui.get_input() # Should make a keyhandler method, but this will do until I get around to # that stage if "f8" in keys: @@ -383,14 +430,14 @@ class appGUI(): wireless.Scan() for k in keys: if k == "window resize": - self.size = self.ui.get_cols_rows() + self.size = ui.get_cols_rows() continue self.frame.keypress( self.size, k ) return True # Terminate the loop, used as the glib mainloop's idle function def stop_loop(self): - self.loop.quit() + loop.quit() # Mostly borrowed from gui.py, but also with the "need daemon first" check def setup_dbus(): From a72b99ad592e2f42db0b70e0edf95d967a298f8f Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Thu, 18 Dec 2008 00:07:00 -0500 Subject: [PATCH 06/50] curses/wicd-curses.py: fixed a bug (missing 'self.') in dbus_scan_finished --- curses/wicd-curses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 639d931..8b4fa9d 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -320,7 +320,7 @@ class appGUI(): self.frame.set_body(self.netList) # I'm hoping that this will get rid of Adam's problem with the NetList not # redisplaying itself immediately upon completion. - update_ui() + self.update_ui() # Be clunky until I get to a later stage of development. # Update the list of networks. Usually called by DBus. From 76fcc3e7c62635329540b770a28544e63cc2fd89 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Thu, 18 Dec 2008 16:39:24 -0500 Subject: [PATCH 07/50] curses/wicd-curses.py: Removed a lot of redundant code related to focus on the main ListBox widget. Set focus=True in the frame's rendering function made everything so much easier. --- curses/wicd-curses.py | 163 ++++++++++++++---------------------------- 1 file changed, 54 insertions(+), 109 deletions(-) diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 8b4fa9d..5a776a8 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -69,6 +69,8 @@ else: # program exits. # I also may have been a bit overkill about using this too, I guess I'll find that out # soon enough. +# I learned about this from this example: +# http://blog.lutzky.net/2007/09/16/exception-handling-decorators-and-python/ class wrap_exceptions: def __call__(self, f): def wrap_exceptions(*args, **kargs): @@ -98,6 +100,28 @@ class wrap_exceptions: return wrap_exceptions +# My savior. :-) +# Although I could have made this myself pretty easily, just want to give credit where +# its due. +# http://excess.org/urwid/browser/contrib/trunk/rbreu_filechooser.py +class SelText(urwid.Text): + """ + A selectable text widget. See urwid.Text. + """ + + def selectable(self): + """ + Make widget selectable. + """ + return True + + + def keypress(self, size, key): + """ + Don't handle any keys. + """ + return key + # Look familiar? These two functions are clones of functions found in wicd's # gui.py file, except that now set_status is a function passed to them. @wrap_exceptions() @@ -161,7 +185,7 @@ def gen_network_list(): for profile in config.GetWiredProfileList(): if id == 0: #theList.append(urwid.Text("Wired Network(s):")) - theList.append(ListElem("Wired Network(s):")) + theList.append(urwid.Text(('body',"Wired Network(s):") ) ) theString = '%4s%*s' % (id, 32+len(profile),profile) #### THIS IS wired.blah() in experimental #print config.GetLastUsedWiredNetwork() @@ -169,12 +193,13 @@ def gen_network_list(): is_active = wireless.GetWirelessIP() == None and wired.GetWiredIP() != None if is_active: theString = '>'+theString[1:] - - theList.append(NetElem(theString,id,is_active)) + theList.append(urwid.AttrWrap(SelText(theString),'connected','connected focus')) + else: + theList.append(urwid.AttrWrap(SelText(theString),'body','focus')) id+=1 for network_id in range(0, wireless.GetNumberOfNetworks()): if network_id == 0: - theList.append(ListElem("Wireless Network(s):")) + theList.append(urwid.Text(('body', "Wireless Network(s):")) ) theString = '%4s %*s %17s %3s %s' % ( network_id, gap,daemon.FormatSignalForPrinting( @@ -187,100 +212,11 @@ def gen_network_list(): is_active = wireless.GetPrintableSignalStrength("") != 0 and wireless.GetCurrentNetworkID(wireless.GetIwconfig())==network_id if is_active: theString = '>'+theString[1:] - theList.append(NetElem(theString,network_id,is_active)) - return theList - -class ListElem(urwid.WidgetWrap): - """ Defines a (generic) non-selectable element that hangs out in a NetList""" - def __init__(self, theText): - self.label = urwid.AttrWrap(urwid.Text(theText),None) - w = self.label - self.__super.__init__(w) - #self.update_w() - def selectable(self): - return False - - def update_w(self): - pass - - # Don't handle any keys in the superclass - def keypress(self, size, key): - return key - -# Widget representing an individual network -# This will be more complicated later, once I know the rest of it works -class NetElem(ListElem): - """Defines a selectable element, either a wireless or wired network profile, - in a NetList - """ - def __init__(self, theText,theId,is_active): - self.is_selected = False - self.id = theId - self.__super.__init__(theText) - - # Color the text differently if we are connected to that network - self.body = 'body' - self.selected = 'selected' - if is_active: - self.body = 'connected' - self.selected = 'connected_sel' - - self.update_w() - - # Make the thing selectable. - def selectable(self): - return True - - # Update the widget. - # Called by NetList below pretty often - def update_w(self): - if self.is_selected: - self._w.attr = self.selected - self._w.focus_attr = self.selected + theList.append(urwid.AttrWrap(SelText(theString),'connected','connected focus')) else: - self._w.attr = self.body - self._w.focus_attr = self.body - - # Don't handle any keys... yet - def keypress(self, size, key): - return key - - -# Class representing the list of networks that appears in the middle. -# Just a listbox with some special features -class NetList(urwid.WidgetWrap): - """ The list of elements that sits in the middle of the screen most of the - time. - """ - def __init__(self, elems): - self.lbox = urwid.AttrWrap(urwid.ListBox(elems),'body') - w = self.lbox - self.__super.__init__(w) - #self.selected = False - # The 1th element in the list is to be selected first, since that one - # is a header - elems[1].is_selected = True - elems[1].update_w() - #widget.update_w() - - # Pick the selected-ness of the app - def update_selected(self,is_selected): - (elem, num) = self._w.get_focus() - elem.is_selected = is_selected - elem.update_w() - - # Updates the selected element, moves the focused element, and then selects - # that one, then updates its selection status. - # TODO: Pressing "Enter" would disconnect you from your current network, and - # connect you to the selected one - #@wrap_exceptions() - def keypress(self, size, key): - #if key == 'down' or key == 'up': - self.update_selected(False) - self._w.keypress(size,key) - #(widget, num) = self.lbox.get_focus() - #widget.is_selected = True - self.update_selected(True) + theList.append(urwid.AttrWrap(SelText(theString),'body','focus')) + #theList.append(SelText(theString)) + return theList # The Whole Shebang class appGUI(): @@ -299,15 +235,17 @@ class appGUI(): header = urwid.AttrWrap(txt, 'header') #self.update_netlist() netElems = gen_network_list() - self.netList = NetList(netElems) + #self.netList = urwi/RecommendedPalette + netList = urwid.ListBox(netElems) #walker = urwid.SimpleListWalker(gen_network_list()) - + self.netList = urwid.ListBox(gen_network_list()) footer = urwid.AttrWrap(urwid.Text("Something will go here... eventually!"),'important') # Pop takes a number! #walker.pop(1) - #self.listbox = urwid.AttrWrap(urwid.ListBox(netList),'body','selected') + #self.listbox = urwid.AttrWrap(urwid.ListBox(netList),'body','focus') self.frame = urwid.Frame(self.netList, header=header,footer=footer) #self.frame = urwid.Frame(self.screen_locker, header=header,footer=footer) + self.frame.set_focus('body') self.prev_state = False self.update_status() @@ -318,7 +256,7 @@ class appGUI(): def unlock_screen(self): self.update_netlist(force_check=True) self.frame.set_body(self.netList) - # I'm hoping that this will get rid of Adam's problem with the NetList not + # I'm hoping that this will get rid of Adam's problem with the ListBox not # redisplaying itself immediately upon completion. self.update_ui() @@ -332,7 +270,7 @@ class appGUI(): state, x = daemon.GetConnectionStatus() if self.prev_state != state or force_check: netElems = gen_network_list() - self.netList = NetList(netElems) + self.netList = urwid.ListBox(netElems) self.frame.set_body(self.netList) self.prev_state = state @@ -352,6 +290,8 @@ class appGUI(): # Set the status text, called by the update_status method def set_status(self,text): + #wid,pos = self.frame.body.get_focus() + #text = text +' '+ str(pos) self.frame.set_footer(urwid.AttrWrap(urwid.Text(text),'important')) # Yeah, I'm copying code. Anything wrong with that? @@ -375,19 +315,21 @@ class appGUI(): # Calls the main loop. This is how the thing should be started, at least # until I decide to change it, whenever that is. def main(self): - global ui + # We are _not_ python. misc.RenameProcess('wicd-curses') + + global ui ui = urwid.curses_display.Screen() # Color scheme. # Other potential color schemes can be found at: # http://excess.org/urwid/wiki/RecommendedPalette ui.register_palette([ ('body','light gray','black'), - ('selected','dark magenta','light gray'), + ('focus','dark magenta','light gray'), ('header','light blue','black'), ('important','light red','black'), ('connected','dark green','black'), - ('connected_sel','black','dark green')]) + ('connected focus','black','dark green')]) # This is a wrapper around a function that calls another a function that is a # wrapper around a infinite loop. Fun. ui.run_wrapper(self.run) @@ -402,7 +344,7 @@ class appGUI(): # Update what the interface looks like every 0.5 ms # Apparently this is use (with fractional seconds) is deprecated. May have to # change this. - redraw_tag = gobject.timeout_add(0.5,self.update_ui) + redraw_tag = gobject.timeout_add(1,self.update_ui) # Update the connection status on the bottom every 2 s gobject.timeout_add(2000,self.update_status) # Terminate the loop if the UI is terminated. @@ -415,11 +357,13 @@ class appGUI(): # at all. Urwid and the glib main loop don't mix all too well. I may need to # consult the Urwid maintainer about this. # - # The implementation of this solution + # The implementation of this solution is active in this program, and it appears to + # be functioning well. @wrap_exceptions() def update_ui(self): #self.update_status() - canvas = self.frame.render( (self.size) ) + canvas = self.frame.render( (self.size),True ) + ### GRRRRRRRRRRRRRRRRRRRRR ^^^^ ui.draw_screen((self.size),canvas) keys = ui.get_input() # Should make a keyhandler method, but this will do until I get around to @@ -457,8 +401,9 @@ def setup_dbus(): bus = dbus.SystemBus() setup_dbus() -# Main entry point +# Main entry point. Probably going to be moved soon. if __name__ == '__main__': + app = appGUI() # Connect signals and whatnot to UI screen control functions From c7e63acbfd22d28e269d7d51895216115827f1e0 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Thu, 18 Dec 2008 22:55:20 -0500 Subject: [PATCH 08/50] curses/wicd-curses.py: Moved the primary entry point to outside of the appGUI class, added some comments to improve code readability --- curses/wicd-curses.py | 144 ++++++++++++++++++++++-------------------- 1 file changed, 74 insertions(+), 70 deletions(-) diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 5a776a8..b38f141 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -65,10 +65,13 @@ else: from dbus.mainloop.glib import DBusGMainLoop DBusGMainLoop(set_as_default=True) +######################################## +##### SUPPORT CLASSES +######################################## # A hack to get any errors that pop out of the program to appear ***AFTER*** the # program exits. -# I also may have been a bit overkill about using this too, I guess I'll find that out -# soon enough. +# I also may have been a bit overkill about using this too, I guess I'll find that +# out soon enough. # I learned about this from this example: # http://blog.lutzky.net/2007/09/16/exception-handling-decorators-and-python/ class wrap_exceptions: @@ -105,23 +108,20 @@ class wrap_exceptions: # its due. # http://excess.org/urwid/browser/contrib/trunk/rbreu_filechooser.py class SelText(urwid.Text): - """ - A selectable text widget. See urwid.Text. - """ - + """A selectable text widget. See urwid.Text.""" def selectable(self): - """ - Make widget selectable. - """ + """Make widget selectable.""" return True def keypress(self, size, key): - """ - Don't handle any keys. - """ + """Don't handle any keys.""" return key +######################################## +##### SUPPORT FUNCTIONS +######################################## + # Look familiar? These two functions are clones of functions found in wicd's # gui.py file, except that now set_status is a function passed to them. @wrap_exceptions() @@ -168,7 +168,7 @@ def gen_list_header(): # Generate the list of networks. # Mostly borrowed/stolen from wpa_cli, since I had no clue what all of those # DBUS interfaces do. ^_^ -@wrap_exceptions() +# Whatever calls this needs to be exception-wrapped def gen_network_list(): #theList = [urwid.Text(gen_list_header())] theList = [] @@ -218,25 +218,27 @@ def gen_network_list(): #theList.append(SelText(theString)) return theList +######################################## +##### APPLICATION INTERFACE CLASS +######################################## # The Whole Shebang class appGUI(): """The UI itself, all glory belongs to it!""" def __init__(self): + self.size = ui.get_cols_rows() # Happy screen saying that you can't do anything because we're scanning # for networks. :-) # Will need a translation sooner or later self.screen_locker = urwid.Filler(urwid.Text(('important',"Scanning networks... stand by..."), align='center')) #self.update_ct = 0 - txt = urwid.Text("Wicd Curses Interface",align='right') + self.TITLE = 'Wicd Curses Interface' #wrap1 = urwid.AttrWrap(txt, 'black') #fill = urwid.Filler(txt) - header = urwid.AttrWrap(txt, 'header') + header = urwid.AttrWrap(urwid.Text(self.TITLE,align='right'), 'header') #self.update_netlist() - netElems = gen_network_list() #self.netList = urwi/RecommendedPalette - netList = urwid.ListBox(netElems) #walker = urwid.SimpleListWalker(gen_network_list()) self.netList = urwid.ListBox(gen_network_list()) footer = urwid.AttrWrap(urwid.Text("Something will go here... eventually!"),'important') @@ -311,46 +313,6 @@ class appGUI(): def dbus_scan_started(self): self.lock_screen() - # Run the bleeding thing. - # Calls the main loop. This is how the thing should be started, at least - # until I decide to change it, whenever that is. - def main(self): - # We are _not_ python. - misc.RenameProcess('wicd-curses') - - global ui - ui = urwid.curses_display.Screen() - # Color scheme. - # Other potential color schemes can be found at: - # http://excess.org/urwid/wiki/RecommendedPalette - ui.register_palette([ - ('body','light gray','black'), - ('focus','dark magenta','light gray'), - ('header','light blue','black'), - ('important','light red','black'), - ('connected','dark green','black'), - ('connected focus','black','dark green')]) - # This is a wrapper around a function that calls another a function that is a - # wrapper around a infinite loop. Fun. - ui.run_wrapper(self.run) - - # Main program loop - def run(self): - global loop,redraw_tag - self.size = ui.get_cols_rows() - - # This actually makes some things easier to do, amusingly enough - loop = gobject.MainLoop() - # Update what the interface looks like every 0.5 ms - # Apparently this is use (with fractional seconds) is deprecated. May have to - # change this. - redraw_tag = gobject.timeout_add(1,self.update_ui) - # Update the connection status on the bottom every 2 s - gobject.timeout_add(2000,self.update_status) - # Terminate the loop if the UI is terminated. - gobject.idle_add(self.stop_loop) - loop.run() - # Redraw the screen # There exists a problem with this where any exceptions that occur (especially of # the DBus variety) will get spread out on the top of the screen, or not displayed @@ -363,7 +325,7 @@ class appGUI(): def update_ui(self): #self.update_status() canvas = self.frame.render( (self.size),True ) - ### GRRRRRRRRRRRRRRRRRRRRR ^^^^ + ### GRRRRRRRRRRRRRRRRRRRRR ->^^^^ ui.draw_screen((self.size),canvas) keys = ui.get_input() # Should make a keyhandler method, but this will do until I get around to @@ -383,6 +345,55 @@ class appGUI(): def stop_loop(self): loop.quit() +######################################## +##### INITIALIZATION FUNCTIONS +######################################## + +def main(): + global ui + + # We are _not_ python. + misc.RenameProcess('wicd-curses') + + ui = urwid.curses_display.Screen() + # Color scheme. + # Other potential color schemes can be found at: + # http://excess.org/urwid/wiki/RecommendedPalette + ui.register_palette([ + ('body','light gray','black'), + ('focus','dark magenta','light gray'), + ('header','light blue','black'), + ('important','light red','black'), + ('connected','dark green','black'), + ('connected focus','black','dark green')]) + # This is a wrapper around a function that calls another a function that is a + # wrapper around a infinite loop. Fun. + ui.run_wrapper(run) + +def run(): + global loop,redraw_tag + + app = appGUI() + + # Connect signals and whatnot to UI screen control functions + bus.add_signal_receiver(app.dbus_scan_finished, 'SendEndScanSignal', + 'org.wicd.daemon') + bus.add_signal_receiver(app.dbus_scan_started, 'SendStartScanSignal', + 'org.wicd.daemon') + #bus.add_signal_receiver(app.update_netlist, 'StatusChanged', + # 'org.wicd.daemon') + loop = gobject.MainLoop() + # Update what the interface looks like every 0.5 ms + # Apparently this is use (with fractional seconds) is deprecated. May have to + # change this. + redraw_tag = gobject.timeout_add(1,app.update_ui) + # Update the connection status on the bottom every 2 s + gobject.timeout_add(2000,app.update_status) + # Terminate the loop if the UI is terminated. + gobject.idle_add(app.stop_loop) + loop.run() + + # Mostly borrowed from gui.py, but also with the "need daemon first" check def setup_dbus(): global proxy_obj, daemon, wireless, wired, config, dbus_ifaces @@ -401,16 +412,9 @@ def setup_dbus(): bus = dbus.SystemBus() setup_dbus() -# Main entry point. Probably going to be moved soon. -if __name__ == '__main__': - - app = appGUI() - # Connect signals and whatnot to UI screen control functions - bus.add_signal_receiver(app.dbus_scan_finished, 'SendEndScanSignal', - 'org.wicd.daemon') - bus.add_signal_receiver(app.dbus_scan_started, 'SendStartScanSignal', - 'org.wicd.daemon') - bus.add_signal_receiver(app.update_netlist, 'StatusChanged', - 'org.wicd.daemon') - app.main() +######################################## +##### MAIN ENTRY POINT +######################################## +if __name__ == '__main__': + main() From f80c04c98de37879645b0786edeec7d7c821abc5 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Fri, 19 Dec 2008 12:34:03 -0500 Subject: [PATCH 09/50] curses/wicd-curses.py: Redesigned the internal list so that the wired network information is always at the top, no matter the number of wireless networks present. --- curses/wicd-curses.py | 65 ++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index b38f141..36c2bdc 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -70,8 +70,8 @@ else: ######################################## # A hack to get any errors that pop out of the program to appear ***AFTER*** the # program exits. -# I also may have been a bit overkill about using this too, I guess I'll find that -# out soon enough. +# I also may have been a bit overkill about using this too, I guess I'll find +# that out soon enough. # I learned about this from this example: # http://blog.lutzky.net/2007/09/16/exception-handling-decorators-and-python/ class wrap_exceptions: @@ -109,6 +109,7 @@ class wrap_exceptions: # http://excess.org/urwid/browser/contrib/trunk/rbreu_filechooser.py class SelText(urwid.Text): """A selectable text widget. See urwid.Text.""" + def selectable(self): """Make widget selectable.""" return True @@ -168,10 +169,10 @@ def gen_list_header(): # Generate the list of networks. # Mostly borrowed/stolen from wpa_cli, since I had no clue what all of those # DBUS interfaces do. ^_^ -# Whatever calls this needs to be exception-wrapped +# Whatever calls this must be exception-wrapped if it is run if the UI is up def gen_network_list(): #theList = [urwid.Text(gen_list_header())] - theList = [] + #theList = [] # Pick which strength measure to use based on what the daemon says if daemon.GetSignalDisplayType() == 0: @@ -182,10 +183,11 @@ def gen_network_list(): gap = 5 id = 0 + wiredL = [] for profile in config.GetWiredProfileList(): - if id == 0: + #if id == 0: #theList.append(urwid.Text("Wired Network(s):")) - theList.append(urwid.Text(('body',"Wired Network(s):") ) ) + #wired.append(urwid.Text(('body',"Wired Network(s):") ) ) theString = '%4s%*s' % (id, 32+len(profile),profile) #### THIS IS wired.blah() in experimental #print config.GetLastUsedWiredNetwork() @@ -193,13 +195,15 @@ def gen_network_list(): is_active = wireless.GetWirelessIP() == None and wired.GetWiredIP() != None if is_active: theString = '>'+theString[1:] - theList.append(urwid.AttrWrap(SelText(theString),'connected','connected focus')) + wiredL.append(urwid.AttrWrap(SelText(theString),'connected','connected focus')) else: - theList.append(urwid.AttrWrap(SelText(theString),'body','focus')) + wiredL.append(urwid.AttrWrap(SelText(theString),'body','focus')) id+=1 + + wlessL = [] for network_id in range(0, wireless.GetNumberOfNetworks()): - if network_id == 0: - theList.append(urwid.Text(('body', "Wireless Network(s):")) ) + #if network_id == 0: + #wireless.append(urwid.Text(('body', "Wireless Network(s):")) ) theString = '%4s %*s %17s %3s %s' % ( network_id, gap,daemon.FormatSignalForPrinting( @@ -212,11 +216,12 @@ def gen_network_list(): is_active = wireless.GetPrintableSignalStrength("") != 0 and wireless.GetCurrentNetworkID(wireless.GetIwconfig())==network_id if is_active: theString = '>'+theString[1:] - theList.append(urwid.AttrWrap(SelText(theString),'connected','connected focus')) + wlessL.append(urwid.AttrWrap(SelText(theString),'connected','connected focus')) else: - theList.append(urwid.AttrWrap(SelText(theString),'body','focus')) + wlessL.append(urwid.AttrWrap(SelText(theString),'body','focus')) #theList.append(SelText(theString)) - return theList + return (wiredL,wlessL) + ######################################## ##### APPLICATION INTERFACE CLASS @@ -230,22 +235,32 @@ 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.TITLE = 'Wicd Curses Interface' #self.update_ct = 0 - self.TITLE = 'Wicd Curses Interface' #wrap1 = urwid.AttrWrap(txt, 'black') #fill = urwid.Filler(txt) header = urwid.AttrWrap(urwid.Text(self.TITLE,align='right'), 'header') - #self.update_netlist() - #self.netList = urwi/RecommendedPalette + self.wiredH=urwid.Filler(urwid.Text("Wired Networks")) + self.wlessH=urwid.Filler(urwid.Text("Wireless Networks")) + + wiredL,wlessL = gen_network_list() + self.wiredLB = urwid.ListBox(wiredL) + self.wlessLB = urwid.ListBox(wlessL) + #spam = SelText('spam') + #spamL = [ urwid.AttrWrap( w, None, 'focus' ) for w in [spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam] ] + self.thePile = urwid.Pile([('fixed',1,self.wiredH), + ('fixed',1,self.wiredLB), + ('fixed',1,self.wlessH), + self.wlessLB] ) + #self.netList = urwid.ListBox(wlessL) #walker = urwid.SimpleListWalker(gen_network_list()) - self.netList = urwid.ListBox(gen_network_list()) - footer = urwid.AttrWrap(urwid.Text("Something will go here... eventually!"),'important') + footer = urwid.AttrWrap(urwid.Text("If you are seeing this, then something has gone wrong!"),'important') # Pop takes a number! #walker.pop(1) #self.listbox = urwid.AttrWrap(urwid.ListBox(netList),'body','focus') - self.frame = urwid.Frame(self.netList, header=header,footer=footer) + self.frame = urwid.Frame(self.thePile, header=header,footer=footer) #self.frame = urwid.Frame(self.screen_locker, header=header,footer=footer) self.frame.set_focus('body') self.prev_state = False @@ -257,7 +272,7 @@ class appGUI(): def unlock_screen(self): self.update_netlist(force_check=True) - self.frame.set_body(self.netList) + self.frame.set_body(self.thePile) # I'm hoping that this will get rid of Adam's problem with the ListBox not # redisplaying itself immediately upon completion. self.update_ui() @@ -271,10 +286,10 @@ class appGUI(): if not state: state, x = daemon.GetConnectionStatus() if self.prev_state != state or force_check: - netElems = gen_network_list() - self.netList = urwid.ListBox(netElems) - self.frame.set_body(self.netList) - + wiredL,wlessL = gen_network_list() + self.wiredLB.body = urwid.SimpleListWalker(wiredL) + self.wlessLB.body = urwid.SimpleListWalker(wlessL) + self.prev_state = state # Update the footer/status bar @@ -386,7 +401,7 @@ def run(): # Update what the interface looks like every 0.5 ms # Apparently this is use (with fractional seconds) is deprecated. May have to # change this. - redraw_tag = gobject.timeout_add(1,app.update_ui) + redraw_tag = gobject.timeout_add(0.5,app.update_ui) # Update the connection status on the bottom every 2 s gobject.timeout_add(2000,app.update_status) # Terminate the loop if the UI is terminated. From b1475ce12c0b990f7b6a595934f0c2377bb8c973 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Sat, 20 Dec 2008 16:32:19 -0500 Subject: [PATCH 10/50] Big one this time. Hopefully I got everything. curses/wicd.curses.py: Added the full language component from wicd.misc into the file. Added support for connecting to networks :-). Added statusbar-updating support during connections. Fixed a problem where an exception found before the UI is on-screen will cause another exception in wrap_exceptions. Turned the footer into a ListBox, so that I can add more than more stuff to it more easily. Rearranged the order of strings in the wireless connection part of the UI. Added a bunch of keymappings to support all of the new functionality. Made the UI updating function into an idle function, to better support the new functionality (and it eats up less CPU, too). Some minor code cleanup throughout. curses/README: Updated to correspond with new features curses/TODO: Removed connection support from the TODO, added a few other things. --- curses/README | 16 +- curses/TODO | 7 +- curses/wicd-curses.py | 355 ++++++++++++++++++++++++++++++++++-------- 3 files changed, 307 insertions(+), 71 deletions(-) diff --git a/curses/README b/curses/README index 1db3021..4e3e9be 100644 --- a/curses/README +++ b/curses/README @@ -5,14 +5,16 @@ Urwid (http://excess.org/urwid) toolkit, and thus requires it. That's all there is to it, really. It's not going to install itself until I work on it more and figure out how to use distutils. -Right now, it only lists current available networks, and whether you are -connected to anything or not, and that is updated in real time. It does not -actually connect you to anything yet. I'll get on that when I have more free -time than I do now (which will be soon). +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. Configuring them is something soon to come soon. -Other important things: +Controls: -F5: refresh wireless networks -F8: quit +F5: refresh wireless networks +F8 or Q: quit +D : disconnect from active network +ESC : if connecting to a network, stop doing so +ENTER : Attempt connection to selected network ~nacl diff --git a/curses/TODO b/curses/TODO index 579bfb6..b306e15 100644 --- a/curses/TODO +++ b/curses/TODO @@ -1,7 +1,5 @@ Things to do (in no particular order): -* Implement the ability to connect/disconnect to/from stuff. - Yeah, I know that it's important... * Make a settings dialog * Implement something that resembles a combo box in urwid * Make a network config dialog @@ -9,9 +7,12 @@ Things to do (in no particular order): * 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 Oh, and most importantly: -* Tell people how they can quit the app (F8, until I do all of that stuff) :-) +* 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. diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 36c2bdc..6af93dc 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -33,6 +33,10 @@ at least get a network connection. Or those who don't like using X. :-) Comments, criticisms, patches, bug reports all welcome! """ +##### NOTICE: THIS DOES NOT WORK WITH THE EXPERIMENTAL BRANCH, DESPITE THE FACT +##### THAT THIS FILE COMES WITH A FULL COPY OF THE EXPERIMENTAL BRANCH! +##### I WILL PROBABLY BE REMEDYING THIS SOMETIME IN JANUARY. + # UI stuff #import urwid.raw_display import urwid.curses_display @@ -50,21 +54,131 @@ import wicd.misc as misc # Internal Python stuff import sys -# Translations for the text that people will see... as of yet. This code is -# already found in the gui.py file -# IN EXPERIMENTAL, THIS IS ALL IN wicd.misc -_ = misc.get_gettext() -language = {} -language['connected_to_wireless'] = _('Connected to $A at $B (IP: $C)') -language['connected_to_wired'] = _('Connected to wired network (IP: $A)') -language['not_connected'] = _('Not connected') - if getattr(dbus, 'version', (0, 0, 0)) < (0, 80, 0): import dbus.glib else: from dbus.mainloop.glib import DBusGMainLoop DBusGMainLoop(set_as_default=True) +# Translations for the text that people will see. This code is +# already found in the gui.py file +# IN EXPERIMENTAL, THIS IS ALL IN wicd.misc +# (Yeah... um... all 102 of them ^_^) +_ = misc.get_gettext() +language = {} +language['connect'] = _("Connect") +language['ip'] = _("IP") +language['netmask'] = _("Netmask") +language['gateway'] = _('Gateway') +language['dns'] = _('DNS') +language['use_static_ip'] = _('Use Static IPs') +language['use_static_dns'] = _('Use Static DNS') +language['use_encryption'] = _('Use Encryption') +language['advanced_settings'] = _('Advanced Settings') +language['wired_network'] = _('Wired Network') +language['wired_network_instructions'] = _('To connect to a wired network,' +' you must create a network profile. To create a network profile, type a' +' name that describes this network, and press Add.') +language['automatic_connect'] = _('Automatically connect to this network') +language['secured'] = _('Secured') +language['unsecured'] = _('Unsecured') +language['channel'] = _('Channel') +language['preferences'] = _('Preferences') +language['wpa_supplicant_driver'] = _('WPA Supplicant Driver') +language['wireless_interface'] = _('Wireless Interface') +language['wired_interface'] = _('Wired Interface') +language['hidden_network'] = _('Hidden Network') +language['hidden_network_essid'] = _('Hidden Network ESSID') +language['connected_to_wireless'] = _('Connected to $A at $B (IP: $C)') +language['connected_to_wired'] = _('Connected to wired network (IP: $A)') +language['not_connected'] = _('Not connected') +language['no_wireless_networks_found'] = _('No wireless networks found.') +language['killswitch_enabled'] = _('Wireless Kill Switch Enabled') +language['key'] = _('Key') +language['username'] = _('Username') +language['password'] = _('Password') +language['anonymous_identity'] = _('Anonymous Identity') +language['identity'] = _('Identity') +language['authentication'] = _('Authentication') +language['path_to_pac_file'] = _('Path to PAC File') +language['select_a_network'] = _('Choose from the networks below:') +language['connecting'] = _('Connecting...') +language['wired_always_on'] = _('Always show wired interface') +language['auto_reconnect'] = _('Automatically reconnect on connection loss') +language['create_adhoc_network'] = _('Create an Ad-Hoc Network') +language['essid'] = _('ESSID') +language['use_wep_encryption'] = _('Use Encryption (WEP only)') +language['before_script'] = _('Run script before connect') +language['after_script'] = _('Run script after connect') +language['disconnect_script'] = _('Run disconnect script') +language['script_settings'] = _('Scripts') +language['use_ics'] = _('Activate Internet Connection Sharing') +language['madwifi_for_adhoc'] = _('Check if using madwifi/atheros drivers') +language['default_wired'] = _('Use as default profile (overwrites any previous default)') +language['use_debug_mode'] = _('Enable debug mode') +language['use_global_dns'] = _('Use global DNS servers') +language['use_default_profile'] = _('Use default profile on wired autoconnect') +language['show_wired_list'] = _('Prompt for profile on wired autoconnect') +language['use_last_used_profile'] = _('Use last used profile on wired autoconnect') +language['choose_wired_profile'] = _('Select or create a wired profile to connect with') +language['wired_network_found'] = _('Wired connection detected') +language['stop_showing_chooser'] = _('Stop Showing Autoconnect pop-up temporarily') +language['display_type_dialog'] = _('Use dBm to measure signal strength') +language['scripts'] = _('Scripts') +language['invalid_address'] = _('Invalid address in $A entry.') +language['global_settings'] = _('Use these settings for all networks sharing this essid') +language['encrypt_info_missing'] = _('Required encryption information is missing.') +language['enable_encryption'] = _('This network requires encryption to be enabled.') +language['wicd_auto_config'] = _('Automatic (recommended)') +language["gen_settings"] = _("General Settings") +language["ext_programs"] = _("External Programs") +language["dhcp_client"] = _("DHCP Client") +language["wired_detect"] = _("Wired Link Detection") +language["route_flush"] = _("Route Table Flushing") +language["backend"] = _("Backend") +language["backend_alert"] = _("Changes to your backend won't occur until the daemon is restarted.") +language['search_domain'] = _("Search Domain") +language['scripts_need_pass'] = _('You must enter your password to configure scripts') +language['no_sudo_prog'] = _("Could not find a graphical sudo program. The script editor could not be launched." + + "You'll have to edit scripts directly your configuration file.") + +language['0'] = _('0') +language['1'] = _('1') +language['2'] = _('2') +language['3'] = _('3') +language['4'] = _('4') +language['5'] = _('5') +language['6'] = _('6') +language['7'] = _('7') +language['8'] = _('8') +language['9'] = _('9') + +language['interface_down'] = _('Putting interface down...') +language['resetting_ip_address'] = _('Resetting IP address...') +language['interface_up'] = _('Putting interface up...') +language['setting_encryption_info'] = _('Setting encryption info') +language['removing_old_connection'] = _('Removing old connection...') +language['generating_psk'] = _('Generating PSK...') +language['generating_wpa_config'] = _('Generating WPA configuration file...') +language['flushing_routing_table'] = _('Flushing the routing table...') +language['configuring_interface'] = _('Configuring wireless interface...') +language['validating_authentication'] = _('Validating authentication...') +language['setting_broadcast_address'] = _('Setting broadcast address...') +language['setting_static_dns'] = _('Setting static DNS servers...') +language['setting_static_ip'] = _('Setting static IP addresses...') +language['running_dhcp'] = _('Obtaining IP address...') +language['dhcp_failed'] = _('Connection Failed: Unable to Get IP Address') +language['aborted'] = _('Connection Cancelled') +language['bad_pass'] = _('Connection Failed: Bad password') +language['done'] = _('Done connecting...') +language['scanning'] = _('Scanning') +language['cannot_start_daemon'] = _("Unable to connect to wicd daemon DBus interface." + \ + "This typically means there was a problem starting the daemon." + \ + "Check the wicd log for more info") +language['lost_dbus'] = _("The wicd daemon has shut down, the UI will not function properly until it is restarted.") + +# Whew. Now on to more interesting stuff: + ######################################## ##### SUPPORT CLASSES ######################################## @@ -86,18 +200,22 @@ class wrap_exceptions: print "Terminated by user." raise except : - # Remove update_ui from the event queue - gobject.source_remove(redraw_tag) - # Quit the loop - loop.quit() - # Zap the screen - ui.stop() - # Print out standard notification: - print "EXCEPTION!" - print "Please report this to the maintainer and/or file a bug report with the backtrace below:" - # Flush the buffer so that the notification is always above the - # backtrace - sys.stdout.flush() + # If the UI isn't inactive (redraw_tag wouldn't normally be + # set), then don't try to stop it, just gracefully die. + if redraw_tag != -1: + # Remove update_ui from the event queue + gobject.source_remove(redraw_tag) + # Quit the loop + loop.quit() + # Zap the screen + ui.stop() + # Print out standard notification: + print "EXCEPTION!" + print "Please report this to the maintainer and/or file a bug report with the backtrace below:" + print redraw_tag + # Flush the buffer so that the notification is always above the + # backtrace + sys.stdout.flush() # Raise the exception raise @@ -163,6 +281,8 @@ def check_for_wireless(iwconfig, wireless_ip, set_status): # Self explanitory, and not used until I can get some list sort function # working... +# Also defunct. +# Current list header is STR,ESSID,ENCRYPT,BSSID,TYPE,CHANNEL def gen_list_header(): return '%3s %4s %s %19s %s ' % ('NUM','STR','BSSID','CHANNEL','ESSID') @@ -188,14 +308,15 @@ def gen_network_list(): #if id == 0: #theList.append(urwid.Text("Wired Network(s):")) #wired.append(urwid.Text(('body',"Wired Network(s):") ) ) - theString = '%4s%*s' % (id, 32+len(profile),profile) + theString = '%4s %25s' % (id, profile) #### THIS IS wired.blah() in experimental #print config.GetLastUsedWiredNetwork() # Tag if no wireless IP present, and wired one is is_active = wireless.GetWirelessIP() == None and wired.GetWiredIP() != None if is_active: theString = '>'+theString[1:] - wiredL.append(urwid.AttrWrap(SelText(theString),'connected','connected focus')) + wiredL.append(urwid.AttrWrap(SelText(theString),'connected', + 'connected focus')) else: wiredL.append(urwid.AttrWrap(SelText(theString),'body','focus')) id+=1 @@ -204,15 +325,19 @@ def gen_network_list(): for network_id in range(0, wireless.GetNumberOfNetworks()): #if network_id == 0: #wireless.append(urwid.Text(('body', "Wireless Network(s):")) ) - - theString = '%4s %*s %17s %3s %s' % ( network_id, - gap,daemon.FormatSignalForPrinting( + + # ?: in python + encryption = wireless.GetWirelessProperty(network_id, 'encryption_method') if wireless.GetWirelessProperty(network_id, 'encryption') else 'Unsecured' + theString = ' %*s %25s %9s %17s %6s: %s' % ( gap, + daemon.FormatSignalForPrinting( str(wireless.GetWirelessProperty(network_id, strenstr))), + wireless.GetWirelessProperty(network_id, 'essid'), + #wireless.GetWirelessProperty(network_id, 'encryption_method'), + encryption, wireless.GetWirelessProperty(network_id, 'bssid'), - wireless.GetWirelessProperty(network_id, 'channel'), - wireless.GetWirelessProperty(network_id, 'essid')) - # This returns -1 if no ID is found, so we I could put this outside of this - # loop. I'll do that soon. + wireless.GetWirelessProperty(network_id, 'mode'), # Master, Ad-Hoc + wireless.GetWirelessProperty(network_id, 'channel') + ) is_active = wireless.GetPrintableSignalStrength("") != 0 and wireless.GetCurrentNetworkID(wireless.GetIwconfig())==network_id if is_active: theString = '>'+theString[1:] @@ -237,42 +362,59 @@ class appGUI(): self.screen_locker = urwid.Filler(urwid.Text(('important',"Scanning networks... stand by..."), align='center')) self.TITLE = 'Wicd Curses Interface' - #self.update_ct = 0 #wrap1 = urwid.AttrWrap(txt, 'black') #fill = urwid.Filler(txt) header = urwid.AttrWrap(urwid.Text(self.TITLE,align='right'), 'header') - self.wiredH=urwid.Filler(urwid.Text("Wired Networks")) - self.wlessH=urwid.Filler(urwid.Text("Wireless Networks")) + self.wiredH=urwid.Filler(urwid.Text("Wired Network(s)")) + self.wlessH=urwid.Filler(urwid.Text("Wireless Network(s)")) wiredL,wlessL = gen_network_list() self.wiredLB = urwid.ListBox(wiredL) self.wlessLB = urwid.ListBox(wlessL) + # Stuff I used to simulate large lists #spam = SelText('spam') - #spamL = [ urwid.AttrWrap( w, None, 'focus' ) for w in [spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam] ] + #spamL = [ urwid.AttrWrap( w, None, 'focus' ) for w in [spam,spam,spam, + # spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam, + # spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam, + # spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam, + # spam,spam,spam,spam] ] + #self.spamLB = urwid.ListBox(spamL) self.thePile = urwid.Pile([('fixed',1,self.wiredH), ('fixed',1,self.wiredLB), ('fixed',1,self.wlessH), self.wlessLB] ) #self.netList = urwid.ListBox(wlessL) #walker = urwid.SimpleListWalker(gen_network_list()) - footer = urwid.AttrWrap(urwid.Text("If you are seeing this, then something has gone wrong!"),'important') + self.footer1 = urwid.AttrWrap(urwid.Text("Something important will eventually go here."),'body') + self.footer2 = urwid.AttrWrap(urwid.Text("If you are seeing this, then something has gone wrong!"),'important') + self.footerList = urwid.ListBox([self.footer1,self.footer2]) # Pop takes a number! #walker.pop(1) #self.listbox = urwid.AttrWrap(urwid.ListBox(netList),'body','focus') - self.frame = urwid.Frame(self.thePile, header=header,footer=footer) + self.frame = urwid.Frame(self.thePile, + header=header, + footer=urwid.BoxAdapter(self.footerList,2)) #self.frame = urwid.Frame(self.screen_locker, header=header,footer=footer) self.frame.set_focus('body') - self.prev_state = False + # Booleans gallore! + self.prev_state = False + self.connecting = False + self.screen_locked = False + self.connecting = False + self.update_status() + # Does what it says it does def lock_screen(self): self.frame.set_body(self.screen_locker) + 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_ui() @@ -295,24 +437,70 @@ class appGUI(): # Update the footer/status bar @wrap_exceptions() def update_status(self): - #self.update_ct += 1 - if check_for_wired(wired.GetWiredIP(),self.set_status): - return True - elif check_for_wireless(wireless.GetIwconfig(), - wireless.GetWirelessIP(), self.set_status): + wired_connecting = wired.CheckIfWiredConnecting() + wireless_connecting = wireless.CheckIfWirelessConnecting() + self.connecting = wired_connecting or wireless_connecting + + # IN EXPERIMENTAL + #fast = not daemon.NeedsExternalCalls() + if self.connecting: + #self.lock_screen() + #if self.statusID: + # gobject.idle_add(self.status_bar.remove, 1, self.statusID) + if wireless_connecting: + #if not fast: + iwconfig = wireless.GetIwconfig() + #else: + # iwconfig = '' + # set_status is rigged to return false when it is not + # connecting to anything, so this should work. + gobject.idle_add(self.set_status, wireless.GetCurrentNetwork(iwconfig) + + ': ' + + language[str(wireless.CheckWirelessConnectingMessage())], + True ) + if wired_connecting: + gobject.idle_add(self.set_status, language['wired_network'] + + ': ' + + language[str(wired.CheckWiredConnectingMessage())], + True) return True else: - self.set_status(language['not_connected']) - return True + if check_for_wired(wired.GetWiredIP(),self.set_status): + return True + elif check_for_wireless(wireless.GetIwconfig(), + wireless.GetWirelessIP(), self.set_status): + return True + else: + self.set_status(language['not_connected']) + return True # Set the status text, called by the update_status method - def set_status(self,text): - #wid,pos = self.frame.body.get_focus() - #text = text +' '+ str(pos) - self.frame.set_footer(urwid.AttrWrap(urwid.Text(text),'important')) + # from_idle : a check to see if we are being called directly from the + # mainloop + def set_status(self,text,from_idle=False): + # If we are being called as the result of trying to connect to + # something return False immediately. + if from_idle and not self.connecting: + return False + self.footer2 = urwid.AttrWrap(urwid.Text(text),'important') + self.frame.set_footer(urwid.BoxAdapter( + urwid.ListBox([self.footer1,self.footer2]),2)) + return True + + # Make sure the screen is still working by providing a pretty counter. + # Not necessary in the end, but I will be using footer1 for stuff in + # the long run. + incr = 0 + def idle_incr(self): + theText = "" + if self.connecting: + theText = "-- Connecting -- Press ESC to cancel" + self.footer1 = urwid.Text(str(self.incr) + ' '+theText) + self.incr+=1 + return True # Yeah, I'm copying code. Anything wrong with that? - @wrap_exceptions() + #@wrap_exceptions() def dbus_scan_finished(self): # I'm pretty sure that I'll need this later. #if not self.connecting: @@ -324,7 +512,7 @@ class appGUI(): self.update_ui() # Same, same, same, same, same, same - @wrap_exceptions() + #@wrap_exceptions() def dbus_scan_started(self): self.lock_screen() @@ -345,10 +533,25 @@ class appGUI(): keys = ui.get_input() # Should make a keyhandler method, but this will do until I get around to # that stage - if "f8" in keys: + if "f8" in keys or 'Q' in keys: + loop.quit() return False if "f5" in keys: wireless.Scan() + if "enter" in keys: + # Should be a function of the labels, I think. + self.call_connect() + if "D" in keys: + # Disconnect from all networks. + daemon.Disconnect() + self.update_netlist() + if "esc" in keys: + # Force disconnect here if connection in progress + if self.connecting: + daemon.CancelConnect() + # Prevents automatic reconnecting if that option is enabled + daemon.SetForcedDisconnect(True) + pass for k in keys: if k == "window resize": self.size = ui.get_cols_rows() @@ -360,6 +563,35 @@ class appGUI(): def stop_loop(self): loop.quit() + # Bring back memories, anyone? + def call_connect(self): + wid = self.thePile.get_focus() + if wid is self.wiredLB: + wid2,pos = self.wiredLB.get_focus() + self.connect(self,'wired',pos) + #return "Wired network %i" % pos + if wid is self.wlessLB: + #self.footer1 = urwid.Text("Wireless!") + wid2,pos = self.wlessLB.get_focus() + self.connect(self,'wireless',pos) + else: + return "Failure!" + + def connect(self, event, nettype, networkid): + """ Initiates the connection process in the daemon. """ + if nettype == "wireless": + # I need to do something that is similar to this in this UI, but + # I don't have an "advanced settings" dialog yet. + #if not self.check_encryption_valid(networkid, + # networkentry.advanced_dialog): + # self.edit_advanced(None, None, nettype, networkid, networkentry) + # return False + wireless.ConnectWireless(networkid) + elif nettype == "wired": + wired.ConnectWired() + self.update_status() + + ######################################## ##### INITIALIZATION FUNCTIONS ######################################## @@ -388,6 +620,7 @@ def main(): def run(): global loop,redraw_tag + redraw_tag = -1 app = appGUI() # Connect signals and whatnot to UI screen control functions @@ -395,17 +628,17 @@ def run(): 'org.wicd.daemon') bus.add_signal_receiver(app.dbus_scan_started, 'SendStartScanSignal', 'org.wicd.daemon') - #bus.add_signal_receiver(app.update_netlist, 'StatusChanged', - # 'org.wicd.daemon') + # I've left this commented out many times. + bus.add_signal_receiver(app.update_netlist, 'StatusChanged', + 'org.wicd.daemon') loop = gobject.MainLoop() - # Update what the interface looks like every 0.5 ms - # Apparently this is use (with fractional seconds) is deprecated. May have to - # change this. - redraw_tag = gobject.timeout_add(0.5,app.update_ui) - # Update the connection status on the bottom every 2 s - gobject.timeout_add(2000,app.update_status) - # Terminate the loop if the UI is terminated. - gobject.idle_add(app.stop_loop) + # Update what the interface looks like as an idle function + redraw_tag = gobject.idle_add(app.update_ui) + # Update the connection status on the bottom every 1.5 s. + gobject.timeout_add(1500,app.update_status) + gobject.idle_add(app.idle_incr) + # DEFUNCT: Terminate the loop if the UI is terminated. + #gobject.idle_add(app.stop_loop) loop.run() From 780a05cef3fc1cf387d5d87d5d380c2fcbcd4db4 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Fri, 26 Dec 2008 13:48:26 -0500 Subject: [PATCH 11/50] curses/prefs_curses.py: ADDED. A basic global preferences dialog. Has a tabbed interface. It is missing things such as buttons, external program controls, advanced settings, and the ability to save information. :-) curses/wicd-curses.py: Some code cleanup, replaced the language mess with the GUI list in misc, and added support for running the Preferences dialog with 'P'. curses/README: Added the keybindings to bring up the preferences dialog. --- curses/README | 8 +- curses/prefs_curses.py | 249 +++++++++++++++++++++++++++++++++++++++++ curses/wicd-curses.py | 133 +++------------------- 3 files changed, 271 insertions(+), 119 deletions(-) create mode 100644 curses/prefs_curses.py diff --git a/curses/README b/curses/README index 4e3e9be..d4d1444 100644 --- a/curses/README +++ b/curses/README @@ -11,10 +11,16 @@ connect you to networks now. Configuring them is something soon to come soon. Controls: -F5: refresh wireless networks +F5 : refresh wireless networks F8 or Q: quit D : disconnect from active network ESC : if connecting to a network, stop doing so ENTER : Attempt connection to selected network +P : Display preferences dialog + +IN DIALOGS: +ESC or Q: Quit dialog without saving information (if present) + + ~nacl diff --git a/curses/prefs_curses.py b/curses/prefs_curses.py new file mode 100644 index 0000000..a995c29 --- /dev/null +++ b/curses/prefs_curses.py @@ -0,0 +1,249 @@ +#!/usr/bin/env python +import urwid + +from wicd import misc + +# Will work for now, I guess. +language = misc.get_language_list_gui() + +class SelText(urwid.Text): + """A selectable text widget. See urwid.Text.""" + + def selectable(self): + """Make widget selectable.""" + return True + + + def keypress(self, size, key): + """Don't handle any keys.""" + return key + +class ToggleEdit(urwid.WidgetWrap): + """A edit that can be rendered unselectable by somethhing like a checkbox""" + def __init__(self, caption='', state=True,attr=('editbx','editfc'),attrnfoc='body'): + edit = urwid.Edit(caption) + curattr = attr[0] if state == True else attrnfoc + w = urwid.AttrWrap(edit,curattr,attr[1]) + self.sensitive=state + self.__super.__init__(w) + def set_sensitive(self,state): + self.sensitive=state + if state: + self._w.set_attr('editbx') + else: + self._w.set_attr('body') + def selectable(self): + return self.sensitive + def keypress(self,size,key): + return self._w.keypress(size,key) + +# Would seem to complicate things a little bit... +class TabColumns(urwid.WidgetWrap): + def __init__(self): + pass + def selectable(self): + return True + def keypress(self,size,key): + pass + +# A "combo box" of SelTexts +class ComboText(urwid.WidgetWrap): + class ComboSpace(urwid.WidgetWrap): + def init(self,body,list,show_first=0,pos=(0,0)): + + #Calculate width and height of the menu widget: + height = len(list) + width = 0 + for entry in list: + if len(entry) > width: + width = len(entry) + self._listbox = urwid.ListBox(list) + + overlay = urwid.Overlay(self._listbox, body, ('fixed left', pos[0]), + width + 2, ('fixed top', pos[1]), height) + + def init(self,list,show_first=0): + pass + +class PrefOverlay(urwid.WidgetWrap): + def __init__(self,body,pos): + # We are on a VT100, I presume. + width = 80 + height = 20 + # Stuff that goes at the top + header0_t = language["gen_settings"] + header1_t = language["ext_programs"] + header2_t = language["advanced_settings"] + self.header0 = urwid.AttrWrap(SelText(header0_t),'body','focus') + self.header1 = urwid.AttrWrap(SelText(header1_t),'body','focus') + self.header2 = urwid.AttrWrap(SelText(header2_t),'body','focus') + title = language['preferences'] + + # Blank line + self._blank = urwid.Text('') + + #### + #### Text in the widgets + #### + + # General Settings + wired_t=('editcp',language['wired_interface']+':') + wless_t=('editcp',language['wireless_interface']+':') + global_dns_t=(language['use_global_dns']) + search_dom_t= ('editcp','Search domain:') + dns1_t = ('editcp','DNS server 1:') + dns2_t = ('editcp','DNS server 2:') + dns3_t = ('editcp','DNS server 3:') + + always_show_wired_t = 'wired always on' #language['wired always on'] + auto_reconnect_t = language['auto_reconnect'] + + #wired_autoconnect_header = 'Wired Autoconnect Setting' + wired_auto_1_t = language['use_default_profile'] + wired_auto_2_t = language['show_wired_list'] + wired_auto_3_t = language['use_last_used_profile'] + + #### External Programs + automatic_t = language['wicd_auto_config'] + + dhcp_header = language["dhcp_client"] + # Automatic + dhcp1_t = 'dhclient' + dhcp2_t = 'dhcpcd' + dhcp3_t = 'pump' + + wired_detect_header = language["wired_detect"] + wired1_t = 'ethtool' + wired2_t = 'mii-tool' + + route_table_header = language["route_flush"] + route1_t = 'ip' + route2_t = 'route' + + # Advanced Settings + wpa_t=('editcp',language['wpa_supplicant_driver']+':') + debug_mode_t = language['use_debug_mode'] + use_dbm_t = language['display_type_dialog'] + # backend_sel_t = + + #### + #### UI Widgets + #### + + # General Settings + self.wpa_edit = urwid.AttrWrap(urwid.Edit(wpa_t),'editbx','editfc') + self.wired_iface = urwid.AttrWrap(urwid.Edit(wired_t),'editbx','editfc') + self.wless_iface = urwid.AttrWrap(urwid.Edit(wless_t),'editbx','editfc') + global_dns_state = False + self.global_dns = urwid.CheckBox(global_dns_t,global_dns_state, + on_state_change=self.global_dns_trigger) + self.search_dom = ToggleEdit(search_dom_t,global_dns_state) + self.dns1 = ToggleEdit(dns1_t,global_dns_state) + self.dns2 = ToggleEdit(dns2_t,global_dns_state) + self.dns3 = ToggleEdit(dns3_t,global_dns_state) + + self.always_show_wired = urwid.CheckBox(always_show_wired_t) + self.auto_reconnect = urwid.CheckBox(auto_reconnect_t) + self.debug_mode = urwid.CheckBox(debug_mode_t) + self.use_dbm = urwid.CheckBox(use_dbm_t) + + wired_auto_l = [] + self.wired_auto_1_r = urwid.RadioButton(wired_auto_l,wired_auto_1_t) + self.wired_auto_2_r = urwid.RadioButton(wired_auto_l,wired_auto_2_t) + self.wired_auto_3_r = urwid.RadioButton(wired_auto_l,wired_auto_3_t) + generalPile = urwid.Pile([ + self.wired_iface,#self._blank, + self.wless_iface,self._blank, + self.global_dns,#self._blank, + self.search_dom, + self.dns1,self.dns2,self.dns3,self._blank, + self.always_show_wired, + self.auto_reconnect, + self.debug_mode, + self.use_dbm,self._blank, + self.wired_auto_1_r, + self.wired_auto_2_r, + self.wired_auto_3_r + ]) + + #externalPile = urwid.Pile() + + + + # Advanced Settings + # WPA Supplicant: Combo Box + # Backend: Combo box + # Debugging + # Enable debug mode + # Wireless Interface + # Use DBM to measure signal strength + + advancedPile = urwid.Pile([self.wpa_edit,self._blank]) + + self.columns = urwid.Columns([('fixed',len(header0_t),self.header0),('fixed',len(header1_t),self.header1),urwid.Text(('header',title),align='right')],dividechars=1) + + self.tab_map = {self.header0 : generalPile, + self.header1 : advancedPile, + self.header2 : advancedPile} + + content = [self.columns,generalPile] + #self._label = urwid.AttrWrap(SelText(titles),attr[0],attr[1]) + self.walker = urwid.SimpleListWalker(content) + self._listbox = urwid.ListBox(self.walker) + self._boxadap = urwid.BoxAdapter + #self._linebox = urwid.LineBox(self._listbox) + overlay = urwid.Overlay(self._listbox, body, ('fixed left', pos[0]), + width + 2, ('fixed top', pos[1]), height) + self.__super.__init__(overlay) + + def global_dns_trigger(self,check_box,new_state,user_data=None): + for w in self.search_dom,self.dns1,self.dns2,self.dns3: + w.set_sensitive(new_state) + # Normal keypress, but if we are at the top, then be "tabbish" instead + def keypress(self,size,ui): + self._w.keypress(size,ui) + (wid,pos) = self._listbox.get_focus() + if wid is self.columns: + lw = self._listbox.body + lw.pop(1) + lw.append(self.tab_map[self.columns.get_focus()]) + self._listbox.body = lw + +#@wrap_exceptions() + def run(self,ui, dim, display): + + global app + #dialog = TabbedOverlay(["Foo", "Bar", "Quit"], + # ('body', 'focus'), (1, 1), display) + + #dialog = PrefOverlay(display,(0,1)) + keys = True + while True: + if keys: + ui.draw_screen(dim, self.render(dim, True)) + keys = ui.get_input() + + if "window resize" in keys: + dim = ui.get_cols_rows() + if "esc" in keys or 'Q' in keys: + return + + for k in keys: + #Send key to underlying widget: + self.keypress(dim, k) + + #if program_menu.selected == "Quit": + # return + + #if program_menu.selected == "Foo": + #Do something + # return + + #if program_menu.selected == "Bar": + #Do something + #return + +#@wrap_exceptions() +#def run_dialog(ui,dim,display,dialog): +# pass + #Event loop: diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index c754a58..e07e9bb 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -54,129 +54,17 @@ from wicd import dbusmanager # Internal Python stuff import sys +# Curses UIs for other stuff +import prefs_curses +from prefs_curses import PrefOverlay + if getattr(dbus, 'version', (0, 0, 0)) < (0, 80, 0): import dbus.glib else: from dbus.mainloop.glib import DBusGMainLoop DBusGMainLoop(set_as_default=True) -# Translations for the text that people will see. This code is -# already found in the gui.py file -# IN EXPERIMENTAL, THIS IS ALL IN wicd.misc -# (Yeah... um... all 102 of them ^_^) -_ = misc.get_gettext() -language = {} -language['connect'] = _("Connect") -language['ip'] = _("IP") -language['netmask'] = _("Netmask") -language['gateway'] = _('Gateway') -language['dns'] = _('DNS') -language['use_static_ip'] = _('Use Static IPs') -language['use_static_dns'] = _('Use Static DNS') -language['use_encryption'] = _('Use Encryption') -language['advanced_settings'] = _('Advanced Settings') -language['wired_network'] = _('Wired Network') -language['wired_network_instructions'] = _('To connect to a wired network,' -' you must create a network profile. To create a network profile, type a' -' name that describes this network, and press Add.') -language['automatic_connect'] = _('Automatically connect to this network') -language['secured'] = _('Secured') -language['unsecured'] = _('Unsecured') -language['channel'] = _('Channel') -language['preferences'] = _('Preferences') -language['wpa_supplicant_driver'] = _('WPA Supplicant Driver') -language['wireless_interface'] = _('Wireless Interface') -language['wired_interface'] = _('Wired Interface') -language['hidden_network'] = _('Hidden Network') -language['hidden_network_essid'] = _('Hidden Network ESSID') -language['connected_to_wireless'] = _('Connected to $A at $B (IP: $C)') -language['connected_to_wired'] = _('Connected to wired network (IP: $A)') -language['not_connected'] = _('Not connected') -language['no_wireless_networks_found'] = _('No wireless networks found.') -language['killswitch_enabled'] = _('Wireless Kill Switch Enabled') -language['key'] = _('Key') -language['username'] = _('Username') -language['password'] = _('Password') -language['anonymous_identity'] = _('Anonymous Identity') -language['identity'] = _('Identity') -language['authentication'] = _('Authentication') -language['path_to_pac_file'] = _('Path to PAC File') -language['select_a_network'] = _('Choose from the networks below:') -language['connecting'] = _('Connecting...') -language['wired_always_on'] = _('Always show wired interface') -language['auto_reconnect'] = _('Automatically reconnect on connection loss') -language['create_adhoc_network'] = _('Create an Ad-Hoc Network') -language['essid'] = _('ESSID') -language['use_wep_encryption'] = _('Use Encryption (WEP only)') -language['before_script'] = _('Run script before connect') -language['after_script'] = _('Run script after connect') -language['disconnect_script'] = _('Run disconnect script') -language['script_settings'] = _('Scripts') -language['use_ics'] = _('Activate Internet Connection Sharing') -language['madwifi_for_adhoc'] = _('Check if using madwifi/atheros drivers') -language['default_wired'] = _('Use as default profile (overwrites any previous default)') -language['use_debug_mode'] = _('Enable debug mode') -language['use_global_dns'] = _('Use global DNS servers') -language['use_default_profile'] = _('Use default profile on wired autoconnect') -language['show_wired_list'] = _('Prompt for profile on wired autoconnect') -language['use_last_used_profile'] = _('Use last used profile on wired autoconnect') -language['choose_wired_profile'] = _('Select or create a wired profile to connect with') -language['wired_network_found'] = _('Wired connection detected') -language['stop_showing_chooser'] = _('Stop Showing Autoconnect pop-up temporarily') -language['display_type_dialog'] = _('Use dBm to measure signal strength') -language['scripts'] = _('Scripts') -language['invalid_address'] = _('Invalid address in $A entry.') -language['global_settings'] = _('Use these settings for all networks sharing this essid') -language['encrypt_info_missing'] = _('Required encryption information is missing.') -language['enable_encryption'] = _('This network requires encryption to be enabled.') -language['wicd_auto_config'] = _('Automatic (recommended)') -language["gen_settings"] = _("General Settings") -language["ext_programs"] = _("External Programs") -language["dhcp_client"] = _("DHCP Client") -language["wired_detect"] = _("Wired Link Detection") -language["route_flush"] = _("Route Table Flushing") -language["backend"] = _("Backend") -language["backend_alert"] = _("Changes to your backend won't occur until the daemon is restarted.") -language['search_domain'] = _("Search Domain") -language['scripts_need_pass'] = _('You must enter your password to configure scripts') -language['no_sudo_prog'] = _("Could not find a graphical sudo program. The script editor could not be launched." + - "You'll have to edit scripts directly your configuration file.") - -language['0'] = _('0') -language['1'] = _('1') -language['2'] = _('2') -language['3'] = _('3') -language['4'] = _('4') -language['5'] = _('5') -language['6'] = _('6') -language['7'] = _('7') -language['8'] = _('8') -language['9'] = _('9') - -language['interface_down'] = _('Putting interface down...') -language['resetting_ip_address'] = _('Resetting IP address...') -language['interface_up'] = _('Putting interface up...') -language['setting_encryption_info'] = _('Setting encryption info') -language['removing_old_connection'] = _('Removing old connection...') -language['generating_psk'] = _('Generating PSK...') -language['generating_wpa_config'] = _('Generating WPA configuration file...') -language['flushing_routing_table'] = _('Flushing the routing table...') -language['configuring_interface'] = _('Configuring wireless interface...') -language['validating_authentication'] = _('Validating authentication...') -language['setting_broadcast_address'] = _('Setting broadcast address...') -language['setting_static_dns'] = _('Setting static DNS servers...') -language['setting_static_ip'] = _('Setting static IP addresses...') -language['running_dhcp'] = _('Obtaining IP address...') -language['dhcp_failed'] = _('Connection Failed: Unable to Get IP Address') -language['aborted'] = _('Connection Cancelled') -language['bad_pass'] = _('Connection Failed: Bad password') -language['done'] = _('Done connecting...') -language['scanning'] = _('Scanning') -language['cannot_start_daemon'] = _("Unable to connect to wicd daemon DBus interface." + \ - "This typically means there was a problem starting the daemon." + \ - "Check the wicd log for more info") -language['lost_dbus'] = _("The wicd daemon has shut down, the UI will not function properly until it is restarted.") - +language = misc.get_language_list_gui() # Whew. Now on to more interesting stuff: ######################################## @@ -392,6 +280,8 @@ class appGUI(): self.update_status() + #self.dialog = PrefOverlay(self.frame,self.size) + # Does what it says it does def lock_screen(self): @@ -512,6 +402,11 @@ class appGUI(): #self.update_status() canvas = self.frame.render( (self.size),True ) ### GRRRRRRRRRRRRRRRRRRRRR ->^^^^ + # It looks like if I wanted to get the statusbar to update itself + # continuously, I would have to use overlay the canvasses and redirect + # the input. I'll try to get that working at a later time, if people + # want that "feature". + #canvaso = urwid.CanvasOverlay(self.dialog.render( (80,20),True),canvas,0,1) ui.draw_screen((self.size),canvas) keys = ui.get_input() # Should make a keyhandler method, but this will do until I get around to @@ -534,6 +429,9 @@ class appGUI(): daemon.CancelConnect() # Prevents automatic reconnecting if that option is enabled daemon.SetForcedDisconnect(True) + if "P" in keys: + dialog = PrefOverlay(self.frame,(0,1)) + dialog.run(ui,self.size,self.frame) for k in keys: if k == "window resize": self.size = ui.get_cols_rows() @@ -648,7 +546,6 @@ def setup_dbus(force=True): return True -bus = dbus.SystemBus() setup_dbus() ######################################## From 5d11be8eae180c49fb7ebfde6a157f16c6e5b1d3 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Fri, 26 Dec 2008 14:18:40 -0500 Subject: [PATCH 12/50] curses/prefs_curses.py: Forgot the license. ^_^ --- curses/prefs_curses.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/curses/prefs_curses.py b/curses/prefs_curses.py index a995c29..a7cc9db 100644 --- a/curses/prefs_curses.py +++ b/curses/prefs_curses.py @@ -1,4 +1,21 @@ #!/usr/bin/env python +# Copyright (C) 2008 Andrew Psaltis + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + import urwid from wicd import misc From 0d4811b1291f22971a1d7915acb74f0dec62e0c2 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Sat, 27 Dec 2008 00:18:03 -0500 Subject: [PATCH 13/50] curses/curses_misc.py: ADDED. Various urwid classes that I use throughout the program. curses/prefs_curses.py: Frontend is complete. However, it is still missing buttons and the ability to save information. Removed code that is now in curses_misc.py. curses/wicd-curses.py: Removed code that is now in curses_misc.py. Tweaked the visuals a little bit. curses/README: Preferences configuration is a WIP now. curses/TODO: A combo box has been implemented in curses_misc.py, so that part has been removed. Also added a part about making a man page. --- curses/README | 4 +- curses/TODO | 5 +- curses/curses_misc.py | 176 ++++++++++++++++++++++++++++++ curses/prefs_curses.py | 237 ++++++++++++++++++++++------------------- curses/wicd-curses.py | 38 +++---- 5 files changed, 321 insertions(+), 139 deletions(-) create mode 100644 curses/curses_misc.py diff --git a/curses/README b/curses/README index d4d1444..8ee7f80 100644 --- a/curses/README +++ b/curses/README @@ -7,7 +7,7 @@ work on it more and figure out how to use distutils. 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. Configuring them is something soon to come soon. +connect you to networks now. Configuring them is a work in progress. Controls: @@ -23,4 +23,4 @@ ESC or Q: Quit dialog without saving information (if present) -~nacl +~NaCl diff --git a/curses/TODO b/curses/TODO index b306e15..6b3e9fb 100644 --- a/curses/TODO +++ b/curses/TODO @@ -1,7 +1,7 @@ Things to do (in no particular order): -* Make a settings dialog - * Implement something that resembles a combo box in urwid +* Make a settings dialog -- Finish the backend. The frontend is pretty much + done. * Make a network config dialog * Make an about dialog * Implement a keyhandler function for the overall frame @@ -9,6 +9,7 @@ Things to do (in no particular order): * 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: diff --git a/curses/curses_misc.py b/curses/curses_misc.py new file mode 100644 index 0000000..d34fedb --- /dev/null +++ b/curses/curses_misc.py @@ -0,0 +1,176 @@ +#!/usr/bin/env python +# -* coding: utf-8 -*- + +""" curses_misc.py: Module for various widgets that are used throughout +wicd-curses. +""" + +# Copyright (C) 2008 Andrew Psaltis + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import urwid + +# My savior. :-) +# Although I could have made this myself pretty easily, just want to give credit where +# its due. +# http://excess.org/urwid/browser/contrib/trunk/rbreu_filechooser.py +class SelText(urwid.Text): + """A selectable text widget. See urwid.Text.""" + + def selectable(self): + """Make widget selectable.""" + return True + + + def keypress(self, size, key): + """Don't handle any keys.""" + return key + +class ToggleEdit(urwid.WidgetWrap): + """A edit that can be rendered unselectable by somethhing like a checkbox""" + def __init__(self, caption='', state=True, + attr=('editbx','editfc'),attrnsens='body'): + """ + caption : the Edit's caption + state : the Edit's current sensitivity + attr : tuple of (attr_no_focus, attr_focus) + attrnsens: attr to use when not sensitive + """ + edit = urwid.Edit(caption) + curattr = attr[0] if state == True else attrnsens + w = urwid.AttrWrap(edit,curattr,attr[1]) + self.sensitive=state + self.__super.__init__(w) + + # Kinda like the thing in PyGTK + def set_sensitive(self,state): + self.sensitive=state + if state: + self._w.set_attr('editbx') + else: + self._w.set_attr('body') + + # If we aren't sensitive, don't be selectab;e + def selectable(self): + return self.sensitive + + # Do what an edit does with keys + def keypress(self,size,key): + return self._w.keypress(size,key) + +# Would seem to complicate things a little bit, but could be very useful. ^_^ +# Not used yet. Will be used very shortly, as a superclass of some future +# overlays +class TabColumns(urwid.WidgetWrap): + def __init__(self): + pass + def selectable(self): + return True + def keypress(self,size,key): + pass + +# A "combo box" of SelTexts +# I based this off of the code found here: +# http://excess.org/urwid/browser/contrib/trunk/rbreu_menus.py +class ComboText(urwid.WidgetWrap): + """A ComboBox of text objects""" + class ComboSpace(urwid.WidgetWrap): + """The actual menu-like space that comes down from the ComboText""" + def __init__(self,list,body,ui,show_first=0,pos=(0,0),attr=('body','focus')): + """ + body : parent widget + list : stuff to include in the combobox + ui : the screen + show_first: index of the element in the list to pick first + pos : a tuple of (row,col) where to put the list + attr : a tuple of (attr_no_focus,attr_focus) + """ + + #Calculate width and height of the menu widget: + height = len(list) + width = 0 + for entry in list: + if len(entry) > width: + width = len(entry) + content = [urwid.AttrWrap(SelText(" " + w), attr[0], attr[1]) + for w in list] + self._listbox = urwid.ListBox(content) + + overlay = urwid.Overlay(self._listbox, body, ('fixed left', pos[0]), + width + 2, ('fixed top', pos[1]), height) + self.__super.__init__(overlay) + + def show(self,ui,display): + + dim = ui.get_cols_rows() + keys = True + + #Event loop: + while True: + if keys: + ui.draw_screen(dim, self.render(dim, True)) + + keys = ui.get_input() + + if "window resize" in keys: + dim = ui.get_cols_rows() + if "esc" in keys: + return None + if "enter" in keys: + (wid,pos) = self._listbox.get_focus() + (text,attr) = wid.get_text() + return text + + for k in keys: + #Send key to underlying widget: + self._w.keypress(dim, k) + + #def get_size(self): + + def __init__(self,label,list,body,ui,row = 0,show_first=0,attr=('body','focus')): + """ + label : bit of text that preceeds the combobox + list : stuff to include in the combobox + 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 + """ + + self.label = urwid.Text(label) + str,trash = self.label.get_text() + + self.cbox = urwid.AttrWrap(SelText(list[show_first]),attr[0],attr[1]) + self.overlay = self.ComboSpace(list,body,ui,show_first,pos=(len(str)+1,row)) + # Unicode will kill me sooner or later. ^_^ + w = urwid.Columns([('fixed',len(str),self.label),self.cbox,('fixed',3,urwid.Text("vvv"))],dividechars=1) + self.__super.__init__(w) + + # We need this to control the keypress + self.body = body + self.ui = ui + # If we press space or enter, be a combo box! + def keypress(self,size,key): + if key == ' ' or key == 'enter': + retval = self.overlay.show(self.ui,self.body) + if retval != None: + self.cbox.set_w(SelText(retval)) + return self._w.keypress(size,key) + + # Most obvious thing ever. :-) + def selectable(self): + return True diff --git a/curses/prefs_curses.py b/curses/prefs_curses.py index a7cc9db..1fb36be 100644 --- a/curses/prefs_curses.py +++ b/curses/prefs_curses.py @@ -1,4 +1,5 @@ #!/usr/bin/env python + # Copyright (C) 2008 Andrew Psaltis # This program is free software; you can redistribute it and/or modify @@ -19,71 +20,14 @@ import urwid from wicd import misc +from curses_misc import SelText,ToggleEdit,ComboText # Will work for now, I guess. language = misc.get_language_list_gui() -class SelText(urwid.Text): - """A selectable text widget. See urwid.Text.""" - - def selectable(self): - """Make widget selectable.""" - return True - - - def keypress(self, size, key): - """Don't handle any keys.""" - return key - -class ToggleEdit(urwid.WidgetWrap): - """A edit that can be rendered unselectable by somethhing like a checkbox""" - def __init__(self, caption='', state=True,attr=('editbx','editfc'),attrnfoc='body'): - edit = urwid.Edit(caption) - curattr = attr[0] if state == True else attrnfoc - w = urwid.AttrWrap(edit,curattr,attr[1]) - self.sensitive=state - self.__super.__init__(w) - def set_sensitive(self,state): - self.sensitive=state - if state: - self._w.set_attr('editbx') - else: - self._w.set_attr('body') - def selectable(self): - return self.sensitive - def keypress(self,size,key): - return self._w.keypress(size,key) - -# Would seem to complicate things a little bit... -class TabColumns(urwid.WidgetWrap): - def __init__(self): - pass - def selectable(self): - return True - def keypress(self,size,key): - pass - -# A "combo box" of SelTexts -class ComboText(urwid.WidgetWrap): - class ComboSpace(urwid.WidgetWrap): - def init(self,body,list,show_first=0,pos=(0,0)): - - #Calculate width and height of the menu widget: - height = len(list) - width = 0 - for entry in list: - if len(entry) > width: - width = len(entry) - self._listbox = urwid.ListBox(list) - - overlay = urwid.Overlay(self._listbox, body, ('fixed left', pos[0]), - width + 2, ('fixed top', pos[1]), height) - - def init(self,list,show_first=0): - pass - class PrefOverlay(urwid.WidgetWrap): - def __init__(self,body,pos): + def __init__(self,body,pos,ui): + self.ui = ui # We are on a VT100, I presume. width = 80 height = 20 @@ -91,7 +35,7 @@ class PrefOverlay(urwid.WidgetWrap): header0_t = language["gen_settings"] header1_t = language["ext_programs"] header2_t = language["advanced_settings"] - self.header0 = urwid.AttrWrap(SelText(header0_t),'body','focus') + self.header0 = urwid.AttrWrap(SelText(header0_t),'tab active','focus') self.header1 = urwid.AttrWrap(SelText(header1_t),'body','focus') self.header2 = urwid.AttrWrap(SelText(header2_t),'body','focus') title = language['preferences'] @@ -104,18 +48,20 @@ class PrefOverlay(urwid.WidgetWrap): #### # General Settings - wired_t=('editcp',language['wired_interface']+':') - wless_t=('editcp',language['wireless_interface']+':') - global_dns_t=(language['use_global_dns']) - search_dom_t= ('editcp','Search domain:') - dns1_t = ('editcp','DNS server 1:') - dns2_t = ('editcp','DNS server 2:') - dns3_t = ('editcp','DNS server 3:') + net_cat_t = ('header','Network Interfaces') + wired_t = ('editcp',language['wired_interface']+': ') + wless_t = ('editcp',language['wireless_interface']+':') + always_show_wired_t = 'Always show wired interface' - always_show_wired_t = 'wired always on' #language['wired always on'] - auto_reconnect_t = language['auto_reconnect'] + global_dns_cat_t = ('header','Global DNS Servers') + global_dns_t = ('editcp',language['use_global_dns']) + search_dom_t = ('editcp',' Search domain:') + dns1_t = ('editcp',' DNS server 1: ') + dns2_t = ('editcp',' DNS server 2: ') + dns3_t = ('editcp',' DNS server 3: ') - #wired_autoconnect_header = 'Wired Autoconnect Setting' + + wired_auto_cat_t= ('header','Wired Autoconnect Settings') wired_auto_1_t = language['use_default_profile'] wired_auto_2_t = language['show_wired_list'] wired_auto_3_t = language['use_last_used_profile'] @@ -123,34 +69,51 @@ class PrefOverlay(urwid.WidgetWrap): #### External Programs automatic_t = language['wicd_auto_config'] - dhcp_header = language["dhcp_client"] + dhcp_header_t = ('header',language["dhcp_client"]) # Automatic dhcp1_t = 'dhclient' dhcp2_t = 'dhcpcd' dhcp3_t = 'pump' - wired_detect_header = language["wired_detect"] - wired1_t = 'ethtool' - wired2_t = 'mii-tool' + wired_detect_header_t = ('header',language["wired_detect"]) + wired1_t = 'ethtool' + wired2_t = 'mii-tool' - route_table_header = language["route_flush"] + route_table_header_t = ('header',language["route_flush"]) route1_t = 'ip' route2_t = 'route' - # Advanced Settings - wpa_t=('editcp',language['wpa_supplicant_driver']+':') + #### Advanced Settings + #wpa_t=('editcp',language['wpa_supplicant_driver']+':') + wpa_cat_t=('header','WPA_Supplicant') + wpa_t=('editcp','Driver:') + wpa_list = ['spam','double spam','triple spam','quadruple spam'] + wpa_warn_t = ('important','You should almost always use wext as the WPA Supplicant Driver') + + backend_cat_t = ('header',language['backend']) + backend_t = language['backend']+':' + backend_list = ['spam','double spam','triple spam','quadruple spam'] + + debug_cat_t = ('header','Debugging') debug_mode_t = language['use_debug_mode'] + + wless_cat_t = ('header','Wireless Interface') use_dbm_t = language['display_type_dialog'] - # backend_sel_t = + + auto_reconn_cat_t = ('header','Automatic Reconnect') + auto_reconn_t = 'Automatically reconnect on connection loss' + #### #### UI Widgets #### # General Settings - self.wpa_edit = urwid.AttrWrap(urwid.Edit(wpa_t),'editbx','editfc') + self.net_cat = urwid.Text(net_cat_t) self.wired_iface = urwid.AttrWrap(urwid.Edit(wired_t),'editbx','editfc') self.wless_iface = urwid.AttrWrap(urwid.Edit(wless_t),'editbx','editfc') + + self.global_dns_cat = urwid.Text(global_dns_cat_t) global_dns_state = False self.global_dns = urwid.CheckBox(global_dns_t,global_dns_state, on_state_change=self.global_dns_trigger) @@ -160,58 +123,109 @@ class PrefOverlay(urwid.WidgetWrap): self.dns3 = ToggleEdit(dns3_t,global_dns_state) self.always_show_wired = urwid.CheckBox(always_show_wired_t) - self.auto_reconnect = urwid.CheckBox(auto_reconnect_t) - self.debug_mode = urwid.CheckBox(debug_mode_t) - self.use_dbm = urwid.CheckBox(use_dbm_t) wired_auto_l = [] - self.wired_auto_1_r = urwid.RadioButton(wired_auto_l,wired_auto_1_t) - self.wired_auto_2_r = urwid.RadioButton(wired_auto_l,wired_auto_2_t) - self.wired_auto_3_r = urwid.RadioButton(wired_auto_l,wired_auto_3_t) - generalPile = urwid.Pile([ - self.wired_iface,#self._blank, - self.wless_iface,self._blank, + self.wired_auto_cat = urwid.Text(wired_auto_cat_t) + self.wired_auto_1 = urwid.RadioButton(wired_auto_l,wired_auto_1_t) + self.wired_auto_2 = urwid.RadioButton(wired_auto_l,wired_auto_2_t) + self.wired_auto_3 = urwid.RadioButton(wired_auto_l,wired_auto_3_t) + generalPile = urwid.Pile([self.net_cat, + self.wless_iface,#self._blank, + self.wired_iface, + self.always_show_wired,self._blank, + self.global_dns_cat, self.global_dns,#self._blank, self.search_dom, self.dns1,self.dns2,self.dns3,self._blank, - self.always_show_wired, - self.auto_reconnect, - self.debug_mode, - self.use_dbm,self._blank, - self.wired_auto_1_r, - self.wired_auto_2_r, - self.wired_auto_3_r + self.wired_auto_cat, + self.wired_auto_1, + self.wired_auto_2, + self.wired_auto_3 ]) - #externalPile = urwid.Pile() + #### External Programs tab + automatic_t = language['wicd_auto_config'] + + self.dhcp_header = urwid.Text(dhcp_header_t) + dhcp_l = [] + # Automatic + self.dhcp0 = urwid.RadioButton(dhcp_l,automatic_t) + self.dhcp1 = urwid.RadioButton(dhcp_l,dhcp1_t) + self.dhcp2 = urwid.RadioButton(dhcp_l,dhcp2_t) + self.dhcp3 = urwid.RadioButton(dhcp_l,dhcp3_t) + + wired_l = [] + self.wired_detect_header = urwid.Text(wired_detect_header_t) + self.wired0 = urwid.RadioButton(wired_l,automatic_t) + self.wired1 = urwid.RadioButton(wired_l,wired1_t) + self.wired2 = urwid.RadioButton(wired_l,wired2_t) + + route_l = [] + self.route_table_header = urwid.Text(route_table_header_t) + self.route0 = urwid.RadioButton(route_l,automatic_t) + self.route1 = urwid.RadioButton(route_l,route1_t) + self.route2 = urwid.RadioButton(route_l,route2_t) + + externalPile = urwid.Pile([self.dhcp_header, + self.dhcp0,self.dhcp1,self.dhcp2,self.dhcp3, + self._blank, + self.wired_detect_header, + self.wired0,self.wired1,self.wired2, + self._blank, + self.route_table_header, + self.route0,self.route1,self.route2 + ]) - - # Advanced Settings - # WPA Supplicant: Combo Box - # Backend: Combo box - # Debugging - # Enable debug mode - # Wireless Interface - # Use DBM to measure signal strength + #### Advanced settings + self.wpa_cat = urwid.Text(wpa_cat_t) + self.wpa_cbox = ComboText(wpa_t,wpa_list,self,ui,4) + self.wpa_warn = urwid.Text(wpa_warn_t) - advancedPile = urwid.Pile([self.wpa_edit,self._blank]) - - self.columns = urwid.Columns([('fixed',len(header0_t),self.header0),('fixed',len(header1_t),self.header1),urwid.Text(('header',title),align='right')],dividechars=1) + self.backend_cat = urwid.Text(backend_cat_t) + self.backend_cbox = ComboText(backend_t,backend_list,self,ui,8) + self.debug_cat = urwid.Text(debug_cat_t) + self.debug_mode = urwid.CheckBox(debug_mode_t) + + self.wless_cat = urwid.Text(wless_cat_t) + self.use_dbm = urwid.CheckBox(use_dbm_t) + + self.auto_reconn_cat = urwid.Text(auto_reconn_cat_t) + self.auto_reconn = urwid.CheckBox(auto_reconn_t) + + advancedPile = urwid.Pile([self.wpa_cat, + self.wpa_cbox,self.wpa_warn,self._blank, + self.backend_cat, + self.backend_cbox,self._blank, + self.debug_cat, + self.debug_mode, self._blank, + self.wless_cat, + self.use_dbm, self._blank, + self.auto_reconn_cat, + self.auto_reconn]) + self.tab_map = {self.header0 : generalPile, - self.header1 : advancedPile, + self.header1 : externalPile, self.header2 : advancedPile} + self.active_tab = self.header0 + self.columns = urwid.Columns([('fixed',len(header0_t),self.header0), + ('fixed',len(header1_t),self.header1), + ('fixed',len(header2_t),self.header2), + urwid.Text(('header',title),align='right')], + dividechars=1) + content = [self.columns,generalPile] #self._label = urwid.AttrWrap(SelText(titles),attr[0],attr[1]) self.walker = urwid.SimpleListWalker(content) self._listbox = urwid.ListBox(self.walker) - self._boxadap = urwid.BoxAdapter #self._linebox = urwid.LineBox(self._listbox) overlay = urwid.Overlay(self._listbox, body, ('fixed left', pos[0]), width + 2, ('fixed top', pos[1]), height) self.__super.__init__(overlay) + + def global_dns_trigger(self,check_box,new_state,user_data=None): for w in self.search_dom,self.dns1,self.dns2,self.dns3: @@ -223,6 +237,9 @@ class PrefOverlay(urwid.WidgetWrap): if wid is self.columns: lw = self._listbox.body lw.pop(1) + self.active_tab.set_attr('body') + self.columns.get_focus().set_attr('tab active') + self.active_tab = self.columns.get_focus() lw.append(self.tab_map[self.columns.get_focus()]) self._listbox.body = lw diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index e07e9bb..b605256 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -55,6 +55,7 @@ from wicd import dbusmanager import sys # Curses UIs for other stuff +from curses_misc import SelText import prefs_curses from prefs_curses import PrefOverlay @@ -109,22 +110,6 @@ class wrap_exceptions: return wrap_exceptions -# My savior. :-) -# Although I could have made this myself pretty easily, just want to give credit where -# its due. -# http://excess.org/urwid/browser/contrib/trunk/rbreu_filechooser.py -class SelText(urwid.Text): - """A selectable text widget. See urwid.Text.""" - - def selectable(self): - """Make widget selectable.""" - return True - - - def keypress(self, size, key): - """Don't handle any keys.""" - return key - ######################################## ##### SUPPORT FUNCTIONS ######################################## @@ -430,7 +415,7 @@ class appGUI(): # Prevents automatic reconnecting if that option is enabled daemon.SetForcedDisconnect(True) if "P" in keys: - dialog = PrefOverlay(self.frame,(0,1)) + dialog = PrefOverlay(self.frame,(0,1),ui) dialog.run(ui,self.size,self.frame) for k in keys: if k == "window resize": @@ -486,17 +471,20 @@ def main(): # 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 will look like crap on a default-colored XTerm. + # NB: To find current terminal background use variable COLORFGBG ui.register_palette([ - ('body','light gray','black'), + ('body','light gray','default'), ('focus','dark magenta','light gray'), - ('header','light blue','black'), - ('important','light red','black'), - ('connected','dark green','black'), - ('connected focus','black','dark green'), - # I'll be needing these soon, so I'll leave them here for now. - ('editcp', 'light gray', 'black', 'standout'), + ('header','light blue','default'), + ('important','light red','default'), + ('connected','dark green','default'), + ('connected focus','default','dark green'), + ('editcp', 'default', 'default', 'standout'), ('editbx', 'light gray', 'dark blue'), - ('editfc', 'white','dark blue', 'bold') ]) + ('editfc', 'white','dark blue', 'bold'), + ('tab active','dark green','light gray')]) # This is a wrapper around a function that calls another a function that is a # wrapper around a infinite loop. Fun. ui.run_wrapper(run) From 689d31b098de0a159c9c634aac665028c5c8a977 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Sat, 27 Dec 2008 22:35:58 -0500 Subject: [PATCH 14/50] curses/curses_misc.py: Added a tabbed interface widget for use in the preferences dialog. curses/prefs_curses.py: Converted the code to use the tabbed interface found in curses_misc.py. The dialog now fills up the terminal, but it still does nothing. curses/wicd-curses.py: Turned the "list" wired section of the interface to a combo box. --- curses/curses_misc.py | 68 +++++++++++++++++++++++++++++-------- curses/prefs_curses.py | 65 ++++++++++++++++++++---------------- curses/wicd-curses.py | 76 +++++++++++++++++++++++++----------------- 3 files changed, 135 insertions(+), 74 deletions(-) diff --git a/curses/curses_misc.py b/curses/curses_misc.py index d34fedb..0ee8e96 100644 --- a/curses/curses_misc.py +++ b/curses/curses_misc.py @@ -72,16 +72,42 @@ class ToggleEdit(urwid.WidgetWrap): def keypress(self,size,key): return self._w.keypress(size,key) -# Would seem to complicate things a little bit, but could be very useful. ^_^ -# Not used yet. Will be used very shortly, as a superclass of some future -# overlays +# Tabbed interface class TabColumns(urwid.WidgetWrap): - def __init__(self): - pass + """ + titles_dict = dictionary of tab_contents (a SelText) : tab_widget (box) + attr = normal attributes + attrsel = attribute when active + """ + def __init__(self,tab_str,tab_wid,title,attr=('body','focus'),attrsel='tab active', + attrtitle='header'): + #title_wid = urwid.Text((attrtitle,title),align='right') + column_list = [] + for w in tab_str: + text,trash = w.get_text() + column_list.append(('fixed',len(text),w)) + column_list.append(urwid.Text((attrtitle,title),align='right')) + + self.tab_map = dict(zip(tab_str,tab_wid)) + self.active_tab = tab_str[0] + self.columns = urwid.Columns(column_list,dividechars=1) + walker = urwid.SimpleListWalker([self.columns,tab_wid[0]]) + self.listbox = urwid.ListBox(walker) + self.__super.__init__(self.listbox) + def selectable(self): return True def keypress(self,size,key): - pass + self._w.keypress(size,key) + (wid,pos) = self.listbox.get_focus() + if wid is self.columns: + lw = self.listbox.body + lw.pop(1) + self.active_tab.set_attr('body') + self.columns.get_focus().set_attr('tab active') + self.active_tab = self.columns.get_focus() + lw.append(self.tab_map[self.columns.get_focus()]) + self.listbox.body = lw # A "combo box" of SelTexts # I based this off of the code found here: @@ -106,7 +132,7 @@ class ComboText(urwid.WidgetWrap): for entry in list: if len(entry) > width: width = len(entry) - content = [urwid.AttrWrap(SelText(" " + w), attr[0], attr[1]) + content = [urwid.AttrWrap(SelText(w), attr[0], attr[1]) for w in list] self._listbox = urwid.ListBox(content) @@ -141,9 +167,11 @@ class ComboText(urwid.WidgetWrap): #def get_size(self): - def __init__(self,label,list,body,ui,row = 0,show_first=0,attr=('body','focus')): + def __init__(self,label,list,body,ui,row = 0,show_first=0,attr=('body','focus'), + use_enter=True): """ - label : bit of text that preceeds the combobox + label : bit of text that preceeds the combobox. If it is "", then + ignore it list : stuff to include in the combobox body : parent widget ui : the screen @@ -154,23 +182,35 @@ class ComboText(urwid.WidgetWrap): self.label = urwid.Text(label) str,trash = self.label.get_text() - self.cbox = urwid.AttrWrap(SelText(list[show_first]),attr[0],attr[1]) - self.overlay = self.ComboSpace(list,body,ui,show_first,pos=(len(str)+1,row)) + self.cbox = urwid.AttrWrap(SelText([list[show_first]+' vvv']),attr[0],attr[1]) # Unicode will kill me sooner or later. ^_^ - w = urwid.Columns([('fixed',len(str),self.label),self.cbox,('fixed',3,urwid.Text("vvv"))],dividechars=1) + if label != '': + w = urwid.Columns([('fixed',len(str),self.label),self.cbox],dividechars=1) + self.overlay = self.ComboSpace(list,body,ui,show_first,pos=(len(str)+1,row)) + else: + w = urwid.Columns([self.cbox]) + self.overlay = self.ComboSpace(list,body,ui,show_first,pos=(0,row)) self.__super.__init__(w) # We need this to control the keypress self.body = body self.ui = ui + self.use_enter = use_enter # If we press space or enter, be a combo box! def keypress(self,size,key): - if key == ' ' or key == 'enter': + activate = key == ' ' + if self.use_enter: + activate = activate or key == 'enter' + if activate: retval = self.overlay.show(self.ui,self.body) if retval != None: - self.cbox.set_w(SelText(retval)) + self.cbox.set_w(SelText(retval+' vvv')) return self._w.keypress(size,key) # Most obvious thing ever. :-) def selectable(self): return True + + # Return a tuple of (widget,position) + def get_selected(self): + return self.overlay._listbox.get_focus() diff --git a/curses/prefs_curses.py b/curses/prefs_curses.py index 1fb36be..e360b9c 100644 --- a/curses/prefs_curses.py +++ b/curses/prefs_curses.py @@ -20,7 +20,7 @@ import urwid from wicd import misc -from curses_misc import SelText,ToggleEdit,ComboText +from curses_misc import SelText,ToggleEdit,ComboText,TabColumns # Will work for now, I guess. language = misc.get_language_list_gui() @@ -28,9 +28,11 @@ language = misc.get_language_list_gui() class PrefOverlay(urwid.WidgetWrap): def __init__(self,body,pos,ui): self.ui = ui - # We are on a VT100, I presume. - width = 80 - height = 20 + + width,height = ui.get_cols_rows() + height -= 3 + #width = 80 + #height = 20 # Stuff that goes at the top header0_t = language["gen_settings"] header1_t = language["ext_programs"] @@ -205,48 +207,53 @@ class PrefOverlay(urwid.WidgetWrap): self.auto_reconn_cat, self.auto_reconn]) + + headerList = [self.header0,self.header1,self.header2] + pileList = [generalPile,externalPile,advancedPile] self.tab_map = {self.header0 : generalPile, self.header1 : externalPile, self.header2 : advancedPile} - self.active_tab = self.header0 + #self.active_tab = self.header0 - self.columns = urwid.Columns([('fixed',len(header0_t),self.header0), - ('fixed',len(header1_t),self.header1), - ('fixed',len(header2_t),self.header2), - urwid.Text(('header',title),align='right')], - dividechars=1) + #self.columns = urwid.Columns([('fixed',len(header0_t),self.header0), + # ('fixed',len(header1_t),self.header1), + # ('fixed',len(header2_t),self.header2), + # urwid.Text(('header',title),align='right')], + # dividechars=1) - content = [self.columns,generalPile] + #content = [self.columns,generalPile] #self._label = urwid.AttrWrap(SelText(titles),attr[0],attr[1]) - self.walker = urwid.SimpleListWalker(content) - self._listbox = urwid.ListBox(self.walker) + #self.walker = urwid.SimpleListWalker(content) + #self.listbox = urwid.ListBox(self.walker) #self._linebox = urwid.LineBox(self._listbox) - overlay = urwid.Overlay(self._listbox, body, ('fixed left', pos[0]), + self.tabs = TabColumns(headerList,pileList,'Preferences') + overlay = urwid.Overlay(self.tabs, body, ('fixed left', pos[0]), width + 2, ('fixed top', pos[1]), height) self.__super.__init__(overlay) - - def global_dns_trigger(self,check_box,new_state,user_data=None): for w in self.search_dom,self.dns1,self.dns2,self.dns3: w.set_sensitive(new_state) # Normal keypress, but if we are at the top, then be "tabbish" instead - def keypress(self,size,ui): - self._w.keypress(size,ui) - (wid,pos) = self._listbox.get_focus() - if wid is self.columns: - lw = self._listbox.body - lw.pop(1) - self.active_tab.set_attr('body') - self.columns.get_focus().set_attr('tab active') - self.active_tab = self.columns.get_focus() - lw.append(self.tab_map[self.columns.get_focus()]) - self._listbox.body = lw + #def keypress(self,size,ui): + # self._w.keypress(size,ui) + # (wid,pos) = self._listbox.get_focus() + # if wid is self.columns: + # lw = self.listbox.body + # lw.pop(1) + # self.active_tab.set_attr('body') + # self.columns.get_focus().set_attr('tab active') + # self.active_tab = self.columns.get_focus() + # lw.append(self.tab_map[self.columns.get_focus()]) + # self.listbox.body = lw #@wrap_exceptions() + # Put the widget into an overlay, and run! def run(self,ui, dim, display): - - global app + # If we are small, "tabbify" the interface + + # Else, pile it together + #dialog = TabbedOverlay(["Foo", "Bar", "Quit"], # ('body', 'focus'), (1, 1), display) diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index b605256..d24f1d5 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -53,9 +53,10 @@ from wicd import dbusmanager # Internal Python stuff import sys +from time import sleep # Curses UIs for other stuff -from curses_misc import SelText +from curses_misc import SelText,ComboText import prefs_curses from prefs_curses import PrefOverlay @@ -106,6 +107,7 @@ class wrap_exceptions: # backtrace sys.stdout.flush() # Raise the exception + #sleep(2) raise return wrap_exceptions @@ -182,10 +184,12 @@ def gen_network_list(): is_active = wireless.GetWirelessIP('') == None and wired.GetWiredIP('') != None if is_active: theString = '>'+theString[1:] - wiredL.append(urwid.AttrWrap(SelText(theString),'connected', - 'connected focus')) - else: - wiredL.append(urwid.AttrWrap(SelText(theString),'body','focus')) + + #wiredL.append(urwid.AttrWrap(SelText(theString),'connected', + # 'connected focus')) + #else: + # wiredL.append(urwid.AttrWrap(SelText(theString),'body','focus')) + wiredL.append(theString) id+=1 wlessL = [] @@ -232,8 +236,21 @@ class appGUI(): self.wiredH=urwid.Filler(urwid.Text("Wired Network(s)")) self.wlessH=urwid.Filler(urwid.Text("Wireless Network(s)")) + self.footer1 = urwid.AttrWrap(urwid.Text("Something important will eventually go here."),'body') + self.footer2 = urwid.AttrWrap(urwid.Text("If you are seeing this, then something has gone wrong!"),'important') + self.footerList = urwid.ListBox([self.footer1,self.footer2]) + # Pop takes a number! + #walker.pop(1) + nothingness = urwid.Filler(urwid.Text('Hello, world!')) + self.frame = urwid.Frame(nothingness, + header=header, + footer=urwid.BoxAdapter(self.footerList,2)) + self.frame.set_focus('body') + + # Miiiiiiiiiiight be changing this back to something like how it was + # originally wiredL,wlessL = gen_network_list() - self.wiredLB = urwid.ListBox(wiredL) + self.wiredCB = urwid.Filler(ComboText('',wiredL,self.frame,ui,3,use_enter=False)) self.wlessLB = urwid.ListBox(wlessL) # Stuff I used to simulate large lists #spam = SelText('spam') @@ -244,19 +261,11 @@ class appGUI(): # spam,spam,spam,spam] ] #self.spamLB = urwid.ListBox(spamL) self.thePile = urwid.Pile([('fixed',1,self.wiredH), - ('fixed',1,self.wiredLB), + ('fixed',1,self.wiredCB), ('fixed',1,self.wlessH), self.wlessLB] ) - self.footer1 = urwid.AttrWrap(urwid.Text("Something important will eventually go here."),'body') - self.footer2 = urwid.AttrWrap(urwid.Text("If you are seeing this, then something has gone wrong!"),'important') - self.footerList = urwid.ListBox([self.footer1,self.footer2]) - # Pop takes a number! - #walker.pop(1) - self.frame = urwid.Frame(self.thePile, - header=header, - footer=urwid.BoxAdapter(self.footerList,2)) - self.frame.set_focus('body') + self.frame.set_body(self.thePile) # Booleans gallore! self.prev_state = False self.connecting = False @@ -290,9 +299,10 @@ class appGUI(): if not state: state, x = daemon.GetConnectionStatus() if self.prev_state != state or force_check: - wiredL,wlessL = gen_network_list() - self.wiredLB.body = urwid.SimpleListWalker(wiredL) - self.wlessLB.body = urwid.SimpleListWalker(wlessL) + wiredL,wlessL = gen_network_list() + self.wiredCB = urwid.Filler(ComboText('',wiredL,self.frame,ui,3, + use_enter=False)) + self.wlessLB.body = urwid.SimpleListWalker(wlessL) self.prev_state = state @@ -410,10 +420,9 @@ class appGUI(): self.update_netlist() if "esc" in keys: # Force disconnect here if connection in progress - if self.connecting: - daemon.CancelConnect() - # Prevents automatic reconnecting if that option is enabled - daemon.SetForcedDisconnect(True) + daemon.CancelConnect() + # Prevents automatic reconnecting if that option is enabled + daemon.SetForcedDisconnect(True) if "P" in keys: dialog = PrefOverlay(self.frame,(0,1),ui) dialog.run(ui,self.size,self.frame) @@ -422,18 +431,23 @@ class appGUI(): self.size = ui.get_cols_rows() continue self.frame.keypress( self.size, k ) - return True - # Terminate the loop, used as the glib mainloop's idle function - def stop_loop(self): - loop.quit() + if " " in keys: + # I can't really tell if this works ^_^. + if self.thePile.get_focus() == self.wiredCB: + wid,pos = self.wiredCB.get_body().get_selected() + text,attr = wid.get_text() + wired.ReadWiredNetworkProfile(text) + + return True # Bring back memories, anyone? def call_connect(self): wid = self.thePile.get_focus() - if wid is self.wiredLB: - wid2,pos = self.wiredLB.get_focus() - self.connect(self,'wired',pos) + if wid is self.wiredCB: + #wid2,pos = self.wiredCB.get_focus() + # Apparently, connect() doesn't care about the networkid + self.connect(self,'wired',0) #return "Wired network %i" % pos if wid is self.wlessLB: #self.footer1 = urwid.Text("Wireless!") @@ -472,7 +486,7 @@ def main(): # 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 will look like crap on a default-colored XTerm. + # 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'), From 98a1a74c493a023886a50d68d5a7fdfe7651f65a Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Sun, 28 Dec 2008 11:36:41 -0500 Subject: [PATCH 15/50] curses/wicd-curses.py: Fixed a problem where any use of the wired network combo box would prevent connecting to wired networks. Added some semblance of a "working" indicator while connecting, a simple |,/,-,\,|,/,... --- curses/wicd-curses.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index d24f1d5..82504b5 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -349,15 +349,25 @@ class appGUI(): self.set_status(language['not_connected']) return True - # Set the status text, called by the update_status method - # from_idle : a check to see if we are being called directly from the - # mainloop + + # Cheap little indicator stating that we are actually connecting + twirl = ['|','/','-','\\'] def set_status(self,text,from_idle=False): + # Set the status text, usually called by the update_status method + # from_idle : a check to see if we are being called directly from the + # mainloop # If we are being called as the result of trying to connect to - # something, return False immediately. + # something, and we aren't connecting to something, return False + # immediately. if from_idle and not self.connecting: return False - self.footer2 = urwid.AttrWrap(urwid.Text(text),'important') + toAppend = '' + # If we are connecting and being called from the idle function, spin + # the wheel. + if from_idle and self.connecting: + # This is probably the wrong way to do this, but ir works for now. + toAppend=self.twirl[self.incr % 4] + self.footer2 = urwid.AttrWrap(urwid.Text(text+' '+toAppend),'important') self.frame.set_footer(urwid.BoxAdapter( urwid.ListBox([self.footer1,self.footer2]),2)) return True @@ -433,11 +443,13 @@ class appGUI(): self.frame.keypress( self.size, k ) if " " in keys: - # I can't really tell if this works ^_^. - if self.thePile.get_focus() == self.wiredCB: + self.set_status('space pressed on wiredCB!') wid,pos = self.wiredCB.get_body().get_selected() text,attr = wid.get_text() wired.ReadWiredNetworkProfile(text) + # Make sure our internal reference to the combobox matches the + # one found in the pile. + self.wiredCB = self.thePile.get_focus() return True @@ -449,12 +461,13 @@ class appGUI(): # Apparently, connect() doesn't care about the networkid self.connect(self,'wired',0) #return "Wired network %i" % pos - if wid is self.wlessLB: + elif wid is self.wlessLB: #self.footer1 = urwid.Text("Wireless!") wid2,pos = self.wlessLB.get_focus() self.connect(self,'wireless',pos) else: - return "Failure!" + self.set_status("call_connect() failed! This is definitely a bug!") + #return "Failure!" def connect(self, event, nettype, networkid): """ Initiates the connection process in the daemon. """ From 2db3b3e60dc8a2a403160d8e08556041a9b36f92 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Mon, 29 Dec 2008 22:04:40 -0500 Subject: [PATCH 16/50] Checkpoint in getting the Preferences dialog functional. There's still some tweaking left to do. curses/curses_misc.py: Changed the internal layout of the widgets to allow me to stick buttons on the bottom. curses/prefs_curses.py: Added rudimentary Dbus support to the dialog. Started getting the config settings to save to wicd. Added buttons (which don't do anything yet). The PrefOverlay has been renamed to PrefsDialog. The PrefsDialog widget is wrapped around a TabColumns widget. Added a main entry point into the file to allow for somewhat easier testing. It can now be called indepentently of wicd-curses, if needed. curses/wicd-curses.py: Undid a change that caused the ESC key to disconnect from the current network, in addition to its current function. --- curses/curses_misc.py | 41 ++++++--- curses/prefs_curses.py | 188 +++++++++++++++++++++++++++-------------- curses/wicd-curses.py | 23 +++-- 3 files changed, 163 insertions(+), 89 deletions(-) diff --git a/curses/curses_misc.py b/curses/curses_misc.py index 0ee8e96..64de914 100644 --- a/curses/curses_misc.py +++ b/curses/curses_misc.py @@ -79,8 +79,9 @@ class TabColumns(urwid.WidgetWrap): attr = normal attributes attrsel = attribute when active """ - def __init__(self,tab_str,tab_wid,title,attr=('body','focus'),attrsel='tab active', - attrtitle='header'): + def __init__(self,tab_str,tab_wid,title,bottom_part,attr=('body','focus'), + attrsel='tab active', attrtitle='header'): + self.bottom_part = bottom_part #title_wid = urwid.Text((attrtitle,title),align='right') column_list = [] for w in tab_str: @@ -91,23 +92,38 @@ class TabColumns(urwid.WidgetWrap): self.tab_map = dict(zip(tab_str,tab_wid)) self.active_tab = tab_str[0] self.columns = urwid.Columns(column_list,dividechars=1) - walker = urwid.SimpleListWalker([self.columns,tab_wid[0]]) - self.listbox = urwid.ListBox(walker) - self.__super.__init__(self.listbox) + #walker = urwid.SimpleListWalker([self.columns,tab_wid[0]]) + #self.listbox = urwid.ListBox(walker) + self.gen_pile(tab_wid[0],True) + self.frame = urwid.Frame(self.pile) + self.__super.__init__(self.frame) + # Make the pile in the middle + def gen_pile(self,lbox,firstrun=False): + self.pile = urwid.Pile([ + ('fixed',1,urwid.Filler(self.columns,'top')), + urwid.Filler(lbox,'top',height=('relative',99)), + ('fixed',1,urwid.Filler(self.bottom_part,'bottom')) + ]) + if not firstrun: + self.frame.set_body(self.pile) + self.set_w(self.frame) + def selectable(self): return True + def keypress(self,size,key): self._w.keypress(size,key) - (wid,pos) = self.listbox.get_focus() - if wid is self.columns: - lw = self.listbox.body - lw.pop(1) + wid = self.pile.get_focus().get_body() + if wid == self.columns: + # lw = self.listbox.body + # lw.pop(1) self.active_tab.set_attr('body') self.columns.get_focus().set_attr('tab active') self.active_tab = self.columns.get_focus() - lw.append(self.tab_map[self.columns.get_focus()]) - self.listbox.body = lw + self.gen_pile(self.tab_map[self.active_tab]) + return key + # self.listbox.body = lw # A "combo box" of SelTexts # I based this off of the code found here: @@ -182,7 +198,8 @@ class ComboText(urwid.WidgetWrap): self.label = urwid.Text(label) str,trash = self.label.get_text() - self.cbox = urwid.AttrWrap(SelText([list[show_first]+' vvv']),attr[0],attr[1]) + self.cbox = urwid.AttrWrap(SelText([list[show_first]+' vvv']), + attr[0],attr[1]) # Unicode will kill me sooner or later. ^_^ if label != '': w = urwid.Columns([('fixed',len(str),self.label),self.cbox],dividechars=1) diff --git a/curses/prefs_curses.py b/curses/prefs_curses.py index e360b9c..67ae0bd 100644 --- a/curses/prefs_curses.py +++ b/curses/prefs_curses.py @@ -18,17 +18,27 @@ # MA 02110-1301, USA. import urwid +import urwid.curses_display from wicd import misc +from wicd import dbusmanager from curses_misc import SelText,ToggleEdit,ComboText,TabColumns +daemon = None +wireless = None +wired = None # Will work for now, I guess. language = misc.get_language_list_gui() -class PrefOverlay(urwid.WidgetWrap): - def __init__(self,body,pos,ui): +class PrefsDialog(urwid.WidgetWrap): + def __init__(self,body,pos,ui,dbus=None): + global daemon, wireless, wired self.ui = ui + daemon = dbus['daemon'] + wireless = dbus['wireless'] + wired = dbus['wired'] + width,height = ui.get_cols_rows() height -= 3 #width = 80 @@ -117,32 +127,32 @@ class PrefOverlay(urwid.WidgetWrap): self.global_dns_cat = urwid.Text(global_dns_cat_t) global_dns_state = False - self.global_dns = urwid.CheckBox(global_dns_t,global_dns_state, + self.global_dns_checkb = urwid.CheckBox(global_dns_t,global_dns_state, on_state_change=self.global_dns_trigger) self.search_dom = ToggleEdit(search_dom_t,global_dns_state) self.dns1 = ToggleEdit(dns1_t,global_dns_state) self.dns2 = ToggleEdit(dns2_t,global_dns_state) self.dns3 = ToggleEdit(dns3_t,global_dns_state) - self.always_show_wired = urwid.CheckBox(always_show_wired_t) + self.always_show_wired_checkb = urwid.CheckBox(always_show_wired_t) wired_auto_l = [] self.wired_auto_cat = urwid.Text(wired_auto_cat_t) self.wired_auto_1 = urwid.RadioButton(wired_auto_l,wired_auto_1_t) self.wired_auto_2 = urwid.RadioButton(wired_auto_l,wired_auto_2_t) self.wired_auto_3 = urwid.RadioButton(wired_auto_l,wired_auto_3_t) - generalPile = urwid.Pile([self.net_cat, - self.wless_iface,#self._blank, - self.wired_iface, - self.always_show_wired,self._blank, - self.global_dns_cat, - self.global_dns,#self._blank, - self.search_dom, - self.dns1,self.dns2,self.dns3,self._blank, - self.wired_auto_cat, - self.wired_auto_1, - self.wired_auto_2, - self.wired_auto_3 + generalLB = urwid.ListBox([self.net_cat, + self.wless_iface,#self._blank, + self.wired_iface, + self.always_show_wired_checkb,self._blank, + self.global_dns_cat, + self.global_dns_checkb,#self._blank, + self.search_dom, + self.dns1,self.dns2,self.dns3,self._blank, + self.wired_auto_cat, + self.wired_auto_1, + self.wired_auto_2, + self.wired_auto_3 ]) #### External Programs tab @@ -168,15 +178,15 @@ class PrefOverlay(urwid.WidgetWrap): self.route1 = urwid.RadioButton(route_l,route1_t) self.route2 = urwid.RadioButton(route_l,route2_t) - externalPile = urwid.Pile([self.dhcp_header, - self.dhcp0,self.dhcp1,self.dhcp2,self.dhcp3, - self._blank, - self.wired_detect_header, - self.wired0,self.wired1,self.wired2, - self._blank, - self.route_table_header, - self.route0,self.route1,self.route2 - ]) + externalLB = urwid.ListBox([self.dhcp_header, + self.dhcp0,self.dhcp1,self.dhcp2,self.dhcp3, + self._blank, + self.wired_detect_header, + self.wired0,self.wired1,self.wired2, + self._blank, + self.route_table_header, + self.route0,self.route1,self.route2 + ]) #### Advanced settings @@ -187,32 +197,44 @@ class PrefOverlay(urwid.WidgetWrap): self.backend_cat = urwid.Text(backend_cat_t) self.backend_cbox = ComboText(backend_t,backend_list,self,ui,8) - self.debug_cat = urwid.Text(debug_cat_t) - self.debug_mode = urwid.CheckBox(debug_mode_t) + self.debug_cat = urwid.Text(debug_cat_t) + self.debug_mode_checkb = urwid.CheckBox(debug_mode_t) - self.wless_cat = urwid.Text(wless_cat_t) - self.use_dbm = urwid.CheckBox(use_dbm_t) + self.wless_cat = urwid.Text(wless_cat_t) + self.use_dbm_checkb = urwid.CheckBox(use_dbm_t) - self.auto_reconn_cat = urwid.Text(auto_reconn_cat_t) - self.auto_reconn = urwid.CheckBox(auto_reconn_t) + self.auto_reconn_cat = urwid.Text(auto_reconn_cat_t) + self.auto_reconn_checkb = urwid.CheckBox(auto_reconn_t) - advancedPile = urwid.Pile([self.wpa_cat, - self.wpa_cbox,self.wpa_warn,self._blank, - self.backend_cat, - self.backend_cbox,self._blank, - self.debug_cat, - self.debug_mode, self._blank, - self.wless_cat, - self.use_dbm, self._blank, - self.auto_reconn_cat, - self.auto_reconn]) + advancedLB = urwid.ListBox([self.wpa_cat, + self.wpa_cbox,self.wpa_warn,self._blank, + self.backend_cat, + self.backend_cbox,self._blank, + self.debug_cat, + self.debug_mode_checkb, self._blank, + self.wless_cat, + self.use_dbm_checkb, self._blank, + self.auto_reconn_cat, + self.auto_reconn_checkb]) headerList = [self.header0,self.header1,self.header2] - pileList = [generalPile,externalPile,advancedPile] - self.tab_map = {self.header0 : generalPile, - self.header1 : externalPile, - self.header2 : advancedPile} + lbList = [generalLB,externalLB,advancedLB] + self.tab_map = {self.header0 : generalLB, + self.header1 : externalLB, + self.header2 : advancedLB} + self.load_settings() + + # Now for the buttons: + + ok_t = 'OK' + cancel_t = 'Cancel' + + ok_button = urwid.AttrWrap(urwid.Button('OK'),'body','focus') + cancel_button = urwid.AttrWrap(urwid.Button('Cancel'),'body','focus') + + + self.button_cols = urwid.Columns([ok_button,cancel_button]) #self.active_tab = self.header0 #self.columns = urwid.Columns([('fixed',len(header0_t),self.header0), @@ -226,11 +248,21 @@ class PrefOverlay(urwid.WidgetWrap): #self.walker = urwid.SimpleListWalker(content) #self.listbox = urwid.ListBox(self.walker) #self._linebox = urwid.LineBox(self._listbox) - self.tabs = TabColumns(headerList,pileList,'Preferences') - overlay = urwid.Overlay(self.tabs, body, ('fixed left', pos[0]), - width + 2, ('fixed top', pos[1]), height) - self.__super.__init__(overlay) + self.tabs = TabColumns(headerList,lbList,'Preferences',self.button_cols) + #overlay = urwid.Overlay(self.tabs, body, ('fixed left', pos[0]), + # width, ('fixed top', pos[1]), height) + self.__super.__init__(self.tabs) + def load_settings(self): + self.always_show_wired_checkb.set_state( + daemon.GetAlwaysShowWiredInterface()) + self.auto_reconn_checkb.set_state(daemon.GetAutoReconnect()) + self.debug_mode_checkb.set_state(daemon.GetDebugMode()) + self.use_dbm_checkb.set_state(daemon.GetSignalDisplayType()) + + def store_results(self): + daemon.SetAlwaysShowWiredInterface(self.always_show_wired_checkb.get_state()) + def global_dns_trigger(self,check_box,new_state,user_data=None): for w in self.search_dom,self.dns1,self.dns2,self.dns3: w.set_sensitive(new_state) @@ -250,9 +282,12 @@ class PrefOverlay(urwid.WidgetWrap): #@wrap_exceptions() # Put the widget into an overlay, and run! def run(self,ui, dim, display): + width,height = ui.get_cols_rows() # If we are small, "tabbify" the interface # Else, pile it together + overlay = urwid.Overlay(self.tabs, display, ('fixed left', 0),width + , ('fixed top',1), height-3) #dialog = TabbedOverlay(["Foo", "Bar", "Quit"], # ('body', 'focus'), (1, 1), display) @@ -261,7 +296,7 @@ class PrefOverlay(urwid.WidgetWrap): keys = True while True: if keys: - ui.draw_screen(dim, self.render(dim, True)) + ui.draw_screen(dim, overlay.render(dim, True)) keys = ui.get_input() if "window resize" in keys: @@ -271,20 +306,45 @@ class PrefOverlay(urwid.WidgetWrap): for k in keys: #Send key to underlying widget: - self.keypress(dim, k) + overlay.keypress(dim, k) - #if program_menu.selected == "Quit": - # return - - #if program_menu.selected == "Foo": - #Do something - # return +def run(): + dialog = PrefsDialog(None,(0,0),ui,dbusmanager.get_dbus_ifaces()) + keys = True + dim = ui.get_cols_rows() + while True: + if keys: + ui.draw_screen(dim, dialog.render(dim, True)) + keys = ui.get_input() - #if program_menu.selected == "Bar": - #Do something - #return + if "window resize" in keys: + dim = ui.get_cols_rows() + if "esc" in keys or 'Q' in keys: + return -#@wrap_exceptions() -#def run_dialog(ui,dim,display,dialog): -# pass - #Event loop: + for k in keys: + #Send key to underlying widget: + dialog.keypress(dim, k) + +if __name__=='__main__': + try: + dbusmanager.connect_to_dbus() + except DBusException: + # I may need to be a little more verbose here. + # Suggestions as to what should go here + print "Can't connect to the daemon. Are you sure it is running?" + print "Please check the wicd log for error messages." + raise + ui = urwid.curses_display.Screen() + ui.register_palette([ + ('body','light gray','default'), + ('focus','dark magenta','light gray'), + ('header','light blue','default'), + ('important','light red','default'), + ('connected','dark green','default'), + ('connected focus','default','dark green'), + ('editcp', 'default', 'default', 'standout'), + ('editbx', 'light gray', 'dark blue'), + ('editfc', 'white','dark blue', 'bold'), + ('tab active','dark green','light gray')]) + ui.run_wrapper(run) diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 82504b5..06f5d04 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -42,8 +42,8 @@ import urwid.curses_display import urwid # DBus communication stuff -import dbus -import dbus.service +from dbus import DBusException +from dbus import version as dbus_version # It took me a while to figure out that I have to use this. import gobject @@ -58,13 +58,7 @@ from time import sleep # Curses UIs for other stuff from curses_misc import SelText,ComboText import prefs_curses -from prefs_curses import PrefOverlay - -if getattr(dbus, 'version', (0, 0, 0)) < (0, 80, 0): - import dbus.glib -else: - from dbus.mainloop.glib import DBusGMainLoop - DBusGMainLoop(set_as_default=True) +from prefs_curses import PrefsDialog language = misc.get_language_list_gui() # Whew. Now on to more interesting stuff: @@ -430,12 +424,15 @@ class appGUI(): self.update_netlist() if "esc" in keys: # Force disconnect here if connection in progress - daemon.CancelConnect() - # Prevents automatic reconnecting if that option is enabled - daemon.SetForcedDisconnect(True) + if self.connecting: + daemon.CancelConnect() + # Prevents automatic reconnecting if that option is enabled + daemon.SetForcedDisconnect(True) if "P" in keys: - dialog = PrefOverlay(self.frame,(0,1),ui) + dialog = PrefsDialog(self.frame,(0,1),ui, + dbusmanager.get_dbus_ifaces()) dialog.run(ui,self.size,self.frame) + dialog.store_results() for k in keys: if k == "window resize": self.size = ui.get_cols_rows() From 5fd6cca50b786562ffefbbe884cd65b37f3c42f5 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Tue, 30 Dec 2008 21:27:41 -0500 Subject: [PATCH 17/50] Yet another checkpoint in building the Preferences Dialog up to completion. Some of the code isn't used yet, but this should all be done relatively soon. curses/curses_misc.py: Added a function in the ToggleEdit to set its text to something Changed the name of ComboText to ComboBox Provided the ability to generate the initial parts of a ComboBox w/o needing the screen. Added ComboBoxException, a simple derived exception for the ComboBox. Used it to die of the user never called build_combobox() curses/prefs_curses.py: Changed the names of some of the widgets. Adjusted the code to use the modified ComboBox widget curses/wicd-curses.py: Adjusted the code to use the modified ComboBox widget --- curses/curses_misc.py | 59 +++++++++++++++++++++++++------ curses/prefs_curses.py | 79 +++++++++++++++++++++++------------------- curses/wicd-curses.py | 37 ++++++++++---------- 3 files changed, 110 insertions(+), 65 deletions(-) diff --git a/curses/curses_misc.py b/curses/curses_misc.py index 64de914..898cd89 100644 --- a/curses/curses_misc.py +++ b/curses/curses_misc.py @@ -63,8 +63,11 @@ class ToggleEdit(urwid.WidgetWrap): self._w.set_attr('editbx') else: self._w.set_attr('body') + + def set_edit_text(self,text): + self._w.set_edit_text(text) - # If we aren't sensitive, don't be selectab;e + # If we aren't sensitive, don't be selectable def selectable(self): return self.sensitive @@ -125,10 +128,16 @@ class TabColumns(urwid.WidgetWrap): return key # self.listbox.body = lw + +### Combo box code begins here + +class ComboBoxException(Exception): + pass + # A "combo box" of SelTexts # I based this off of the code found here: # http://excess.org/urwid/browser/contrib/trunk/rbreu_menus.py -class ComboText(urwid.WidgetWrap): +class ComboBox(urwid.WidgetWrap): """A ComboBox of text objects""" class ComboSpace(urwid.WidgetWrap): """The actual menu-like space that comes down from the ComboText""" @@ -183,8 +192,7 @@ class ComboText(urwid.WidgetWrap): #def get_size(self): - def __init__(self,label,list,body,ui,row = 0,show_first=0,attr=('body','focus'), - use_enter=True): + def __init__(self,label='',list=[],attr=('body','focus'),use_enter=True,show_first=0): """ label : bit of text that preceeds the combobox. If it is "", then ignore it @@ -194,31 +202,60 @@ class ComboText(urwid.WidgetWrap): row : where this object is to be found onscreen show_first: index of the element in the list to pick first """ - + self.label = urwid.Text(label) + self.attr = attr + self.list = list str,trash = self.label.get_text() - self.cbox = urwid.AttrWrap(SelText([list[show_first]+' vvv']), - attr[0],attr[1]) + self.overlay = None + + self.cbox = urwid.AttrWrap(SelText(' vvv'),attr[0],attr[1]) # Unicode will kill me sooner or later. ^_^ if label != '': w = urwid.Columns([('fixed',len(str),self.label),self.cbox],dividechars=1) - self.overlay = self.ComboSpace(list,body,ui,show_first,pos=(len(str)+1,row)) else: w = urwid.Columns([self.cbox]) - self.overlay = self.ComboSpace(list,body,ui,show_first,pos=(0,row)) self.__super.__init__(w) - # We need this to control the keypress + # 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 + + def set_list(self,list): + self.list = list + + def set_show_first(self,show_first): + self.show_first = show_first + + def build_combobox(self,body,ui,row,show_first=0): + str,trash = self.label.get_text() + self.cbox = urwid.AttrWrap(SelText([self.list[show_first]+' vvv']), + self.attr[0],self.attr[1]) + 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, + pos=(len(str)+1,row)) + else: + w = urwid.Columns([self.cbox]) + self.overlay = self.ComboSpace(self.list,body,ui,self.show_first, + pos=(0,row)) + + self.set_w(w) self.body = body self.ui = ui - self.use_enter = use_enter + # If we press space or enter, be a combo box! def keypress(self,size,key): activate = key == ' ' if self.use_enter: activate = activate or key == 'enter' if activate: + # Die if the user didn't prepare the combobox overlay + if self.overlay == None: + raise ComboBoxException('ComboBox must be built before use!') retval = self.overlay.show(self.ui,self.body) if retval != None: self.cbox.set_w(SelText(retval+' vvv')) diff --git a/curses/prefs_curses.py b/curses/prefs_curses.py index 67ae0bd..3d1eee9 100644 --- a/curses/prefs_curses.py +++ b/curses/prefs_curses.py @@ -22,7 +22,7 @@ import urwid.curses_display from wicd import misc from wicd import dbusmanager -from curses_misc import SelText,ToggleEdit,ComboText,TabColumns +from curses_misc import SelText,ToggleEdit,ComboBox,TabColumns daemon = None wireless = None @@ -33,7 +33,6 @@ language = misc.get_language_list_gui() class PrefsDialog(urwid.WidgetWrap): def __init__(self,body,pos,ui,dbus=None): global daemon, wireless, wired - self.ui = ui daemon = dbus['daemon'] wireless = dbus['wireless'] @@ -91,9 +90,9 @@ class PrefsDialog(urwid.WidgetWrap): wired1_t = 'ethtool' wired2_t = 'mii-tool' - route_table_header_t = ('header',language["route_flush"]) - route1_t = 'ip' - route2_t = 'route' + flush_header_t = ('header',language["route_flush"]) + flush1_t = 'ip' + flush2_t = 'route' #### Advanced Settings #wpa_t=('editcp',language['wpa_supplicant_driver']+':') @@ -122,10 +121,12 @@ class PrefsDialog(urwid.WidgetWrap): # General Settings self.net_cat = urwid.Text(net_cat_t) - self.wired_iface = urwid.AttrWrap(urwid.Edit(wired_t),'editbx','editfc') - self.wless_iface = urwid.AttrWrap(urwid.Edit(wless_t),'editbx','editfc') + self.wired_edit = urwid.AttrWrap(urwid.Edit(wired_t),'editbx','editfc') + self.wless_edit = urwid.AttrWrap(urwid.Edit(wless_t),'editbx','editfc') self.global_dns_cat = urwid.Text(global_dns_cat_t) + # Default the global DNS settings to off. They will be reenabled later + # if so required. global_dns_state = False self.global_dns_checkb = urwid.CheckBox(global_dns_t,global_dns_state, on_state_change=self.global_dns_trigger) @@ -142,8 +143,8 @@ class PrefsDialog(urwid.WidgetWrap): self.wired_auto_2 = urwid.RadioButton(wired_auto_l,wired_auto_2_t) self.wired_auto_3 = urwid.RadioButton(wired_auto_l,wired_auto_3_t) generalLB = urwid.ListBox([self.net_cat, - self.wless_iface,#self._blank, - self.wired_iface, + self.wless_edit,#self._blank, + self.wired_edit, self.always_show_wired_checkb,self._blank, self.global_dns_cat, self.global_dns_checkb,#self._blank, @@ -159,24 +160,24 @@ class PrefsDialog(urwid.WidgetWrap): automatic_t = language['wicd_auto_config'] self.dhcp_header = urwid.Text(dhcp_header_t) - dhcp_l = [] + self.dhcp_l = [] # Automatic - self.dhcp0 = urwid.RadioButton(dhcp_l,automatic_t) - self.dhcp1 = urwid.RadioButton(dhcp_l,dhcp1_t) - self.dhcp2 = urwid.RadioButton(dhcp_l,dhcp2_t) - self.dhcp3 = urwid.RadioButton(dhcp_l,dhcp3_t) + self.dhcp0 = urwid.RadioButton(self.dhcp_l,automatic_t) + self.dhcp1 = urwid.RadioButton(self.dhcp_l,dhcp1_t) + self.dhcp2 = urwid.RadioButton(self.dhcp_l,dhcp2_t) + self.dhcp3 = urwid.RadioButton(self.dhcp_l,dhcp3_t) - wired_l = [] + self.wired_l = [] self.wired_detect_header = urwid.Text(wired_detect_header_t) - self.wired0 = urwid.RadioButton(wired_l,automatic_t) - self.wired1 = urwid.RadioButton(wired_l,wired1_t) - self.wired2 = urwid.RadioButton(wired_l,wired2_t) + self.wired0 = urwid.RadioButton(self.wired_l,automatic_t) + self.wired1 = urwid.RadioButton(self.wired_l,wired1_t) + self.wired2 = urwid.RadioButton(self.wired_l,wired2_t) - route_l = [] - self.route_table_header = urwid.Text(route_table_header_t) - self.route0 = urwid.RadioButton(route_l,automatic_t) - self.route1 = urwid.RadioButton(route_l,route1_t) - self.route2 = urwid.RadioButton(route_l,route2_t) + self.flush_l = [] + self.flush_header = urwid.Text(flush_header_t) + self.flush0 = urwid.RadioButton(self.flush_l,automatic_t) + self.flush1 = urwid.RadioButton(self.flush_l,flush1_t) + self.flush2 = urwid.RadioButton(self.flush_l,flush2_t) externalLB = urwid.ListBox([self.dhcp_header, self.dhcp0,self.dhcp1,self.dhcp2,self.dhcp3, @@ -184,18 +185,18 @@ class PrefsDialog(urwid.WidgetWrap): self.wired_detect_header, self.wired0,self.wired1,self.wired2, self._blank, - self.route_table_header, - self.route0,self.route1,self.route2 + self.flush_header, + self.flush0,self.flush1,self.flush2 ]) #### Advanced settings self.wpa_cat = urwid.Text(wpa_cat_t) - self.wpa_cbox = ComboText(wpa_t,wpa_list,self,ui,4) + self.wpa_cbox = ComboBox(wpa_t) self.wpa_warn = urwid.Text(wpa_warn_t) self.backend_cat = urwid.Text(backend_cat_t) - self.backend_cbox = ComboText(backend_t,backend_list,self,ui,8) + self.backend_cbox = ComboBox(backend_t) self.debug_cat = urwid.Text(debug_cat_t) self.debug_mode_checkb = urwid.CheckBox(debug_mode_t) @@ -223,7 +224,7 @@ class PrefsDialog(urwid.WidgetWrap): self.tab_map = {self.header0 : generalLB, self.header1 : externalLB, self.header2 : advancedLB} - self.load_settings() + #self.load_settings() # Now for the buttons: @@ -266,6 +267,11 @@ class PrefsDialog(urwid.WidgetWrap): def global_dns_trigger(self,check_box,new_state,user_data=None): for w in self.search_dom,self.dns1,self.dns2,self.dns3: w.set_sensitive(new_state) + + def ready_comboboxes(self,ui,body): + self.wpa_cbox.build_combobox(body,ui,4) + self.backend_cbox.build_combobox(body,ui,8) + # Normal keypress, but if we are at the top, then be "tabbish" instead #def keypress(self,size,ui): # self._w.keypress(size,ui) @@ -283,16 +289,16 @@ class PrefsDialog(urwid.WidgetWrap): # Put the widget into an overlay, and run! def run(self,ui, dim, display): width,height = ui.get_cols_rows() + self.load_settings() + # TODO: The below, if things go 'well' # If we are small, "tabbify" the interface - # Else, pile it together + overlay = urwid.Overlay(self.tabs, display, ('fixed left', 0),width , ('fixed top',1), height-3) + # Will need once we actually get the comboboxes filled with stuff + #self.ready_comboboxes(ui,overlay) - #dialog = TabbedOverlay(["Foo", "Bar", "Quit"], - # ('body', 'focus'), (1, 1), display) - - #dialog = PrefOverlay(display,(0,1)) keys = True while True: if keys: @@ -308,10 +314,13 @@ class PrefsDialog(urwid.WidgetWrap): #Send key to underlying widget: overlay.keypress(dim, k) -def run(): +def run_it(): dialog = PrefsDialog(None,(0,0),ui,dbusmanager.get_dbus_ifaces()) keys = True dim = ui.get_cols_rows() + dialog.load_settings() + # Will need once we actually get the comboboxes filled with stuff + #self.ready_comboboxes(ui,overlay) while True: if keys: ui.draw_screen(dim, dialog.render(dim, True)) @@ -347,4 +356,4 @@ if __name__=='__main__': ('editbx', 'light gray', 'dark blue'), ('editfc', 'white','dark blue', 'bold'), ('tab active','dark green','light gray')]) - ui.run_wrapper(run) + ui.run_wrapper(run_it) diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 06f5d04..dd19dde 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -56,7 +56,7 @@ import sys from time import sleep # Curses UIs for other stuff -from curses_misc import SelText,ComboText +from curses_misc import SelText,ComboBox import prefs_curses from prefs_curses import PrefsDialog @@ -230,21 +230,8 @@ class appGUI(): self.wiredH=urwid.Filler(urwid.Text("Wired Network(s)")) self.wlessH=urwid.Filler(urwid.Text("Wireless Network(s)")) - self.footer1 = urwid.AttrWrap(urwid.Text("Something important will eventually go here."),'body') - self.footer2 = urwid.AttrWrap(urwid.Text("If you are seeing this, then something has gone wrong!"),'important') - self.footerList = urwid.ListBox([self.footer1,self.footer2]) - # Pop takes a number! - #walker.pop(1) - nothingness = urwid.Filler(urwid.Text('Hello, world!')) - self.frame = urwid.Frame(nothingness, - header=header, - footer=urwid.BoxAdapter(self.footerList,2)) - self.frame.set_focus('body') - - # Miiiiiiiiiiight be changing this back to something like how it was - # originally wiredL,wlessL = gen_network_list() - self.wiredCB = urwid.Filler(ComboText('',wiredL,self.frame,ui,3,use_enter=False)) + 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') @@ -259,6 +246,17 @@ class appGUI(): ('fixed',1,self.wlessH), self.wlessLB] ) + self.footer1 = urwid.AttrWrap(urwid.Text("Something important will eventually go here."),'body') + self.footer2 = urwid.AttrWrap(urwid.Text("If you are seeing this, then something has gone wrong!"),'important') + self.footerList = urwid.ListBox([self.footer1,self.footer2]) + # Pop takes a number! + #walker.pop(1) + nothingness = urwid.Filler(urwid.Text('Hello, world!')) + self.frame = urwid.Frame(self.thePile, + header=header, + footer=urwid.BoxAdapter(self.footerList,2)) + self.wiredCB.get_body().build_combobox(self.frame,ui,3) + self.frame.set_body(self.thePile) # Booleans gallore! self.prev_state = False @@ -270,7 +268,6 @@ class appGUI(): #self.dialog = PrefOverlay(self.frame,self.size) - # Does what it says it does def lock_screen(self): self.frame.set_body(self.screen_locker) @@ -294,8 +291,10 @@ class appGUI(): state, x = daemon.GetConnectionStatus() if self.prev_state != state or force_check: wiredL,wlessL = gen_network_list() - self.wiredCB = urwid.Filler(ComboText('',wiredL,self.frame,ui,3, - use_enter=False)) + #self.wiredCB = urwid.Filler(ComboBox(wiredL,self.frame,ui,3, + # 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) self.prev_state = state @@ -440,7 +439,7 @@ class appGUI(): self.frame.keypress( self.size, k ) if " " in keys: - self.set_status('space pressed on wiredCB!') + #self.set_status('space pressed on wiredCB!') wid,pos = self.wiredCB.get_body().get_selected() text,attr = wid.get_text() wired.ReadWiredNetworkProfile(text) From 64741b032a122c900549b38f8004ca3c11aa1327 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Tue, 30 Dec 2008 23:10:18 -0500 Subject: [PATCH 18/50] curses/curses_misc.py: Added a get_edit_text function to ToggleEdit. Changed the get_selected function in ComboBox to return the index only. curses/prefs_curses.py: Completed the load+save functions of the UI Buttons are now functional. Only selecting the OK button will save the data for now. curses/wicd-curses.py: Added support for the "Always Show Wired Interface" config option Completed support for the preferences dialog curses/TODO,README: Preferences dialog is done. :-) --- curses/TODO | 4 +- curses/curses_misc.py | 10 ++- curses/prefs_curses.py | 192 +++++++++++++++++++++++++++++++---------- curses/wicd-curses.py | 33 +++++-- 4 files changed, 181 insertions(+), 58 deletions(-) diff --git a/curses/TODO b/curses/TODO index 6b3e9fb..1c80fde 100644 --- a/curses/TODO +++ b/curses/TODO @@ -1,8 +1,6 @@ Things to do (in no particular order): -* Make a settings dialog -- Finish the backend. The frontend is pretty much - done. -* Make a network config dialog +* Make a network config dialog for both wireless and wired interfaces * Make an about dialog * Implement a keyhandler function for the overall frame * Make keystrokes customizable diff --git a/curses/curses_misc.py b/curses/curses_misc.py index 898cd89..9469cfd 100644 --- a/curses/curses_misc.py +++ b/curses/curses_misc.py @@ -67,6 +67,9 @@ class ToggleEdit(urwid.WidgetWrap): def set_edit_text(self,text): self._w.set_edit_text(text) + def get_edit_text(self): + return self._w.get_edit_text() + # If we aren't sensitive, don't be selectable def selectable(self): return self.sensitive @@ -75,7 +78,7 @@ class ToggleEdit(urwid.WidgetWrap): def keypress(self,size,key): return self._w.keypress(size,key) -# Tabbed interface +# Tabbed interface, mostly for use in the Preferences Dialog class TabColumns(urwid.WidgetWrap): """ titles_dict = dictionary of tab_contents (a SelText) : tab_widget (box) @@ -265,6 +268,7 @@ class ComboBox(urwid.WidgetWrap): def selectable(self): return True - # Return a tuple of (widget,position) + # Return the index of the selected element def get_selected(self): - return self.overlay._listbox.get_focus() + wid,pos = self.overlay._listbox.get_focus() + return pos diff --git a/curses/prefs_curses.py b/curses/prefs_curses.py index 3d1eee9..d12d82e 100644 --- a/curses/prefs_curses.py +++ b/curses/prefs_curses.py @@ -43,6 +43,7 @@ class PrefsDialog(urwid.WidgetWrap): #width = 80 #height = 20 # Stuff that goes at the top + header0_t = language["gen_settings"] header1_t = language["ext_programs"] header2_t = language["advanced_settings"] @@ -52,7 +53,7 @@ class PrefsDialog(urwid.WidgetWrap): title = language['preferences'] # Blank line - self._blank = urwid.Text('') + _blank = urwid.Text('') #### #### Text in the widgets @@ -137,19 +138,19 @@ class PrefsDialog(urwid.WidgetWrap): self.always_show_wired_checkb = urwid.CheckBox(always_show_wired_t) - wired_auto_l = [] + self.wired_auto_l = [] self.wired_auto_cat = urwid.Text(wired_auto_cat_t) - self.wired_auto_1 = urwid.RadioButton(wired_auto_l,wired_auto_1_t) - self.wired_auto_2 = urwid.RadioButton(wired_auto_l,wired_auto_2_t) - self.wired_auto_3 = urwid.RadioButton(wired_auto_l,wired_auto_3_t) + self.wired_auto_1 = urwid.RadioButton(self.wired_auto_l,wired_auto_1_t) + self.wired_auto_2 = urwid.RadioButton(self.wired_auto_l,wired_auto_2_t) + self.wired_auto_3 = urwid.RadioButton(self.wired_auto_l,wired_auto_3_t) generalLB = urwid.ListBox([self.net_cat, - self.wless_edit,#self._blank, + self.wless_edit,#_blank, self.wired_edit, - self.always_show_wired_checkb,self._blank, + self.always_show_wired_checkb,_blank, self.global_dns_cat, - self.global_dns_checkb,#self._blank, + self.global_dns_checkb,#_blank, self.search_dom, - self.dns1,self.dns2,self.dns3,self._blank, + self.dns1,self.dns2,self.dns3,_blank, self.wired_auto_cat, self.wired_auto_1, self.wired_auto_2, @@ -181,10 +182,10 @@ class PrefsDialog(urwid.WidgetWrap): externalLB = urwid.ListBox([self.dhcp_header, self.dhcp0,self.dhcp1,self.dhcp2,self.dhcp3, - self._blank, + _blank, self.wired_detect_header, self.wired0,self.wired1,self.wired2, - self._blank, + _blank, self.flush_header, self.flush0,self.flush1,self.flush2 ]) @@ -208,13 +209,13 @@ class PrefsDialog(urwid.WidgetWrap): self.auto_reconn_checkb = urwid.CheckBox(auto_reconn_t) advancedLB = urwid.ListBox([self.wpa_cat, - self.wpa_cbox,self.wpa_warn,self._blank, + self.wpa_cbox,self.wpa_warn,_blank, self.backend_cat, - self.backend_cbox,self._blank, + self.backend_cbox,_blank, self.debug_cat, - self.debug_mode_checkb, self._blank, + self.debug_mode_checkb, _blank, self.wless_cat, - self.use_dbm_checkb, self._blank, + self.use_dbm_checkb, _blank, self.auto_reconn_cat, self.auto_reconn_checkb]) @@ -227,15 +228,17 @@ class PrefsDialog(urwid.WidgetWrap): #self.load_settings() # Now for the buttons: - ok_t = 'OK' cancel_t = 'Cancel' - ok_button = urwid.AttrWrap(urwid.Button('OK'),'body','focus') - cancel_button = urwid.AttrWrap(urwid.Button('Cancel'),'body','focus') + ok_button = urwid.AttrWrap(urwid.Button('OK',self.ok_callback),'body','focus') + cancel_button = urwid.AttrWrap(urwid.Button('Cancel',self.cancel_callback),'body','focus') + # Variables set by the buttons' callback functions + self.CANCEL_PRESSED = False + self.OK_PRESSED = False - self.button_cols = urwid.Columns([ok_button,cancel_button]) + self.button_cols = urwid.Columns([ok_button,cancel_button],dividechars=1) #self.active_tab = self.header0 #self.columns = urwid.Columns([('fixed',len(header0_t),self.header0), @@ -255,37 +258,130 @@ class PrefsDialog(urwid.WidgetWrap): self.__super.__init__(self.tabs) def load_settings(self): + ### General Settings + # Urwid does not like dbus.Strings as text markups + wless_iface = unicode(daemon.GetWirelessInterface()) + wired_iface = unicode(daemon.GetWiredInterface()) + self.wless_edit.set_edit_text(wless_iface) + self.wired_edit.set_edit_text(wired_iface) + self.always_show_wired_checkb.set_state( daemon.GetAlwaysShowWiredInterface()) - self.auto_reconn_checkb.set_state(daemon.GetAutoReconnect()) + + # DNS + self.global_dns_checkb.set_state(daemon.GetUseGlobalDNS()) + theDNS = daemon.GetGlobalDNSAddresses() + + i = 0 + for w in self.dns1,self.dns2,self.dns3,self.search_dom : + w.set_edit_text(misc.noneToBlankString(theDNS[i])) + i+=1 + + # Wired Automatic Connection + self.wired_auto_l[daemon.GetWiredAutoConnectMethod()-1] + + ### External Programs + dhcp_method = daemon.GetDHCPClient() + self.dhcp_l[dhcp_method].set_state(True) + + wired_link_method = daemon.GetLinkDetectionTool() + self.wired_l[wired_link_method].set_state(True) + + flush_method = daemon.GetFlushTool() + self.flush_l[flush_method].set_state(True) + + ### Advanced settings + # wpa_supplicant janx + self.wpadrivers = ["wext", "hostap", "madwifi", "atmel", + "ndiswrapper", "ipw"] + self.wpadrivers = wireless.GetWpaSupplicantDrivers(self.wpadrivers) + self.wpadrivers.append("ralink_legacy") + # Same as above with the dbus.String + self.thedrivers = [unicode(w) for w in self.wpadrivers] + self.wpa_cbox.set_list(self.thedrivers) + + # Pick where to begin first: + def_driver = daemon.GetWPADriver() + try: + self.wpa_cbox.set_show_first(self.wpadrivers.index(def_driver)) + except ValueError: + pass # It defaults to 0 anyway + + self.backends = daemon.GetBackendList() + # Remove the blank string b/c of some dbus mess + self.backends.remove('') + self.thebackends= [unicode(w) for w in self.backends] + self.backend_cbox.set_list(self.thebackends) + + # Three last checkboxes self.debug_mode_checkb.set_state(daemon.GetDebugMode()) self.use_dbm_checkb.set_state(daemon.GetSignalDisplayType()) + self.auto_reconn_checkb.set_state(daemon.GetAutoReconnect()) - def store_results(self): + def save_results(self): + """ Pushes the selected settings to the daemon. + This exact order is found in prefs.py""" + daemon.SetUseGlobalDNS(self.global_dns_checkb.get_state()) + daemon.SetGlobalDNS(self.dns1.get_edit_text(), self.dns2.get_edit_text(), + self.dns3.get_edit_text(), 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()]) 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()) + daemon.SetSignalDisplayType(int(self.use_dbm_checkb.get_state())) + if self.wired_auto_2.get_state(): + daemon.SetWiredAutoConnectMethod(2) + elif self.wired_auto_3.get_state(): + daemon.SetWiredAutoConnectMethod(3) + else: + daemon.SetWiredAutoConnectMethod(1) + daemon.SetBackend(self.backends[self.backend_cbox.get_selected()]) + + # External Programs Tab + if self.dhcp0.get_state(): + dhcp_client = misc.AUTO + elif self.dhcp1.get_state(): + dhcp_client = misc.DHCLIENT + elif self.dhcp2.get_state(): + dhcp_client = misc.DHCPCD + else: + dhcp_client = misc.PUMP + daemon.SetDHCPClient(dhcp_client) + + if self.wired0.get_state(): + link_tool = misc.AUTO + elif self.wired1.get_state(): + link_tool = misc.ETHTOOL + else: + link_tool = misc.MIITOOL + daemon.SetLinkDetectionTool(link_tool) + + if self.flush0.get_state(): + flush_tool = misc.AUTO + elif self.flush1.get_state(): + flush_tool = misc.IP + else: + flush_tool = misc.ROUTE + daemon.SetFlushTool(flush_tool) + + # DNS CheckBox callback def global_dns_trigger(self,check_box,new_state,user_data=None): for w in self.search_dom,self.dns1,self.dns2,self.dns3: w.set_sensitive(new_state) + # 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 ready_comboboxes(self,ui,body): self.wpa_cbox.build_combobox(body,ui,4) self.backend_cbox.build_combobox(body,ui,8) - # Normal keypress, but if we are at the top, then be "tabbish" instead - #def keypress(self,size,ui): - # self._w.keypress(size,ui) - # (wid,pos) = self._listbox.get_focus() - # if wid is self.columns: - # lw = self.listbox.body - # lw.pop(1) - # self.active_tab.set_attr('body') - # self.columns.get_focus().set_attr('tab active') - # self.active_tab = self.columns.get_focus() - # lw.append(self.tab_map[self.columns.get_focus()]) - # self.listbox.body = lw - -#@wrap_exceptions() # Put the widget into an overlay, and run! def run(self,ui, dim, display): width,height = ui.get_cols_rows() @@ -296,8 +392,7 @@ class PrefsDialog(urwid.WidgetWrap): overlay = urwid.Overlay(self.tabs, display, ('fixed left', 0),width , ('fixed top',1), height-3) - # Will need once we actually get the comboboxes filled with stuff - #self.ready_comboboxes(ui,overlay) + self.ready_comboboxes(ui,overlay) keys = True while True: @@ -308,19 +403,25 @@ class PrefsDialog(urwid.WidgetWrap): if "window resize" in keys: dim = ui.get_cols_rows() if "esc" in keys or 'Q' in keys: - return - + return False for k in keys: #Send key to underlying widget: overlay.keypress(dim, k) + if self.CANCEL_PRESSED: + return False + if self.OK_PRESSED: + return True + +### +### EXTERNAL ENTRY POINT STUFF +### def run_it(): dialog = PrefsDialog(None,(0,0),ui,dbusmanager.get_dbus_ifaces()) keys = True dim = ui.get_cols_rows() dialog.load_settings() - # Will need once we actually get the comboboxes filled with stuff - #self.ready_comboboxes(ui,overlay) + dialog.ready_comboboxes(ui,dialog) while True: if keys: ui.draw_screen(dim, dialog.render(dim, True)) @@ -329,11 +430,14 @@ def run_it(): if "window resize" in keys: dim = ui.get_cols_rows() if "esc" in keys or 'Q' in keys: - return - + return False for k in keys: - #Send key to underlying widget: dialog.keypress(dim, k) + if dialog.CANCEL_PRESSED: + return False + if dialog.OK_PRESSED: + dialog.save_results() + return True if __name__=='__main__': try: diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index dd19dde..a32b242 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -241,11 +241,15 @@ class appGUI(): # spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam,spam, # spam,spam,spam,spam] ] #self.spamLB = urwid.ListBox(spamL) - self.thePile = urwid.Pile([('fixed',1,self.wiredH), - ('fixed',1,self.wiredCB), - ('fixed',1,self.wlessH), - self.wlessLB] ) + # Choose whether to show the wired part of the interface. + if daemon.GetAlwaysShowWiredInterface(): + self.thePile = urwid.Pile([('fixed',1,self.wiredH), + ('fixed',1,self.wiredCB), + ('fixed',1,self.wlessH), + self.wlessLB] ) + else: + self.thePile = urwid.Pile([('fixed',1,self.wlessH),self.wlessLB] ) self.footer1 = urwid.AttrWrap(urwid.Text("Something important will eventually go here."),'body') self.footer2 = urwid.AttrWrap(urwid.Text("If you are seeing this, then something has gone wrong!"),'important') self.footerList = urwid.ListBox([self.footer1,self.footer2]) @@ -263,7 +267,7 @@ class appGUI(): self.connecting = False self.screen_locked = False self.connecting = False - + self.always_show_wired = daemon.GetAlwaysShowWiredInterface() self.update_status() #self.dialog = PrefOverlay(self.frame,self.size) @@ -296,7 +300,18 @@ class appGUI(): self.wiredCB.get_body().set_list(wiredL) self.wiredCB.get_body().build_combobox(self.frame,ui,3) self.wlessLB.body = urwid.SimpleListWalker(wlessL) - + # If the "Always Show Wired" part of the interface changes, change + # along with it. + if daemon.GetAlwaysShowWiredInterface() != self.always_show_wired: + if daemon.GetAlwaysShowWiredInterface(): + self.thePile = urwid.Pile([('fixed',1,self.wiredH), + ('fixed',1,self.wiredCB), + ('fixed',1,self.wlessH), + self.wlessLB] ) + else: + self.thePile = urwid.Pile([('fixed',1,self.wlessH),self.wlessLB] ) + self.frame.body = self.thePile + self.always_show_wired = not self.always_show_wired self.prev_state = state # Update the footer/status bar @@ -430,8 +445,10 @@ class appGUI(): if "P" in keys: dialog = PrefsDialog(self.frame,(0,1),ui, dbusmanager.get_dbus_ifaces()) - dialog.run(ui,self.size,self.frame) - dialog.store_results() + # There is some lag in using the buttons. Not my fault. + if dialog.run(ui,self.size,self.frame): + dialog.save_results() + self.update_ui() for k in keys: if k == "window resize": self.size = ui.get_cols_rows() From f0466be6b8cf2d6517b1a9a68cd109acda70f06f Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Thu, 1 Jan 2009 00:30:53 -0500 Subject: [PATCH 19/50] curses/curses_misc.py: Added a Dialog class, mostly borrowed from a urwid example curses/prefs_curses.py: Added the DNS domain to the dialog, as was done in the GTK UI curses/wicd-curses.py: Added a semi-pretty about dialog. curses/README: Activating about dialog is done by "A" --- curses/README | 1 + curses/curses_misc.py | 72 ++++++++++++++++++++++++++++++++++++++++++ curses/prefs_curses.py | 13 +++++--- curses/wicd-curses.py | 49 +++++++++++++++++++++++++--- 4 files changed, 125 insertions(+), 10 deletions(-) diff --git a/curses/README b/curses/README index f3832a6..7586196 100644 --- a/curses/README +++ b/curses/README @@ -18,6 +18,7 @@ D : disconnect from active network ESC : if connecting to a network, stop doing so ENTER : Attempt connection to selected network P : Display preferences dialog +A : Display "About" dialog IN DIALOGS: ESC or Q: Quit dialog without saving information (if present) diff --git a/curses/curses_misc.py b/curses/curses_misc.py index 9469cfd..45e3a46 100644 --- a/curses/curses_misc.py +++ b/curses/curses_misc.py @@ -272,3 +272,75 @@ class ComboBox(urwid.WidgetWrap): def get_selected(self): wid,pos = self.overlay._listbox.get_focus() return pos + + +# 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 + + 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 + """ + + 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) + + urwid.WidgetWrap.__init__(self, overlay) + + + 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() diff --git a/curses/prefs_curses.py b/curses/prefs_curses.py index d12d82e..f6a8dfb 100644 --- a/curses/prefs_curses.py +++ b/curses/prefs_curses.py @@ -67,6 +67,7 @@ class PrefsDialog(urwid.WidgetWrap): global_dns_cat_t = ('header','Global DNS Servers') global_dns_t = ('editcp',language['use_global_dns']) + dns_dom_t = ('editcp',' DNS Domain: ') search_dom_t = ('editcp',' Search domain:') dns1_t = ('editcp',' DNS server 1: ') dns2_t = ('editcp',' DNS server 2: ') @@ -132,6 +133,7 @@ class PrefsDialog(urwid.WidgetWrap): self.global_dns_checkb = urwid.CheckBox(global_dns_t,global_dns_state, on_state_change=self.global_dns_trigger) self.search_dom = ToggleEdit(search_dom_t,global_dns_state) + self.dns_dom = ToggleEdit(dns_dom_t,global_dns_state) self.dns1 = ToggleEdit(dns1_t,global_dns_state) self.dns2 = ToggleEdit(dns2_t,global_dns_state) self.dns3 = ToggleEdit(dns3_t,global_dns_state) @@ -149,7 +151,7 @@ class PrefsDialog(urwid.WidgetWrap): self.always_show_wired_checkb,_blank, self.global_dns_cat, self.global_dns_checkb,#_blank, - self.search_dom, + self.search_dom,self.dns_dom, self.dns1,self.dns2,self.dns3,_blank, self.wired_auto_cat, self.wired_auto_1, @@ -273,7 +275,7 @@ class PrefsDialog(urwid.WidgetWrap): theDNS = daemon.GetGlobalDNSAddresses() i = 0 - for w in self.dns1,self.dns2,self.dns3,self.search_dom : + for w in self.dns1,self.dns2,self.dns3,self.dns_dom,self.search_dom : w.set_edit_text(misc.noneToBlankString(theDNS[i])) i+=1 @@ -323,7 +325,8 @@ class PrefsDialog(urwid.WidgetWrap): This exact order is found in prefs.py""" daemon.SetUseGlobalDNS(self.global_dns_checkb.get_state()) daemon.SetGlobalDNS(self.dns1.get_edit_text(), self.dns2.get_edit_text(), - self.dns3.get_edit_text(), self.search_dom.get_edit_text()) + self.dns3.get_edit_text(), self.dns_dom.get_edit_text(), + 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()]) @@ -369,7 +372,7 @@ class PrefsDialog(urwid.WidgetWrap): # DNS CheckBox callback def global_dns_trigger(self,check_box,new_state,user_data=None): - for w in self.search_dom,self.dns1,self.dns2,self.dns3: + for w in self.dns1,self.dns2,self.dns3,self.dns_dom,self.search_dom: w.set_sensitive(new_state) # Button callbacks @@ -409,7 +412,7 @@ class PrefsDialog(urwid.WidgetWrap): overlay.keypress(dim, k) if self.CANCEL_PRESSED: return False - if self.OK_PRESSED: + if self.OK_PRESSED in keys: return True diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index a32b242..2582371 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -33,9 +33,6 @@ at least get a network connection. Or those who don't like using X. :-) Comments, criticisms, patches, bug reports all welcome! """ -##### NOTICE: THIS ONLY WORKS WITH THE SOURCE IN WICD 1.6 AS FOUND IN THE BZR -##### REPOSITORIES! - # UI stuff #import urwid.raw_display import urwid.curses_display @@ -56,7 +53,7 @@ import sys from time import sleep # Curses UIs for other stuff -from curses_misc import SelText,ComboBox +from curses_misc import SelText,ComboBox,Dialog import prefs_curses from prefs_curses import PrefsDialog @@ -208,6 +205,42 @@ def gen_network_list(): wlessL.append(urwid.AttrWrap(SelText(theString),'body','focus')) return (wiredL,wlessL) +def about_dialog(body): + # This looks A LOT better when it is actually displayed. I promise :-). + # The ASCII Art "Wicd" was made from the "smslant" font on one of those + # online ASCII big text generators. + theText = [ +('green'," /// \\\\\\")," _ ___ __\n", +('green'," /// \\\\\\")," | | /| / (_)______/ /\n", +('green'," /// \\\\\\")," | |/ |/ / / __/ _ / \n", +('green',"/|| // \\\\ ||\\")," |__/|__/_/\__/\_,_/ \n", +('green',"||| ||"),"(|^|)",('green',"|| |||"), +" ($VERSION) \n".replace("$VERSION",daemon.Hello()), + +('green',"\\|| \\\\")," |+| ",('green',"// ||/ \n"), +('green'," \\\\\\")," |+| ",('green',"///")," http://wicd.net \n", +('green'," \\\\\\")," |+| ",('green',"///")," Brought to you by:\n", +('green'," \\\\\\")," |+| "('green',"///")," Adam Blackburn (wicd)\n", +" ___|+|___ 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 ######################################## ##### APPLICATION INTERFACE CLASS @@ -449,6 +482,8 @@ class appGUI(): if dialog.run(ui,self.size,self.frame): dialog.save_results() self.update_ui() + if "A" in keys: + about_dialog(self.frame) for k in keys: if k == "window resize": self.size = ui.get_cols_rows() @@ -524,7 +559,11 @@ def main(): ('editcp', 'default', 'default', 'standout'), ('editbx', 'light gray', 'dark blue'), ('editfc', 'white','dark blue', 'bold'), - ('tab active','dark green','light gray')]) + ('tab active','dark green','light gray'), + # Simple colors around text + ('green','dark green','default'), + ('blue','dark blue','default'), + ('red','dark red','default')]) # This is a wrapper around a function that calls another a function that is a # wrapper around a infinite loop. Fun. ui.run_wrapper(run) From 8ed394abf3ac5c5ea70819cdb2801f6ed6a9b749 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Thu, 1 Jan 2009 00:36:08 -0500 Subject: [PATCH 20/50] curses/*.py: updated copyrights to include 2009 curses/wicd-curses.py: Fixed missing comma in the About Dialog text --- curses/curses_misc.py | 2 +- curses/prefs_curses.py | 2 +- curses/wicd-curses.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/curses/curses_misc.py b/curses/curses_misc.py index 45e3a46..91d9c2a 100644 --- a/curses/curses_misc.py +++ b/curses/curses_misc.py @@ -5,7 +5,7 @@ wicd-curses. """ -# Copyright (C) 2008 Andrew Psaltis +# Copyright (C) 2008-9 Andrew Psaltis # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/curses/prefs_curses.py b/curses/prefs_curses.py index f6a8dfb..3dd275a 100644 --- a/curses/prefs_curses.py +++ b/curses/prefs_curses.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (C) 2008 Andrew Psaltis +# Copyright (C) 2008-9 Andrew Psaltis # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 2582371..aa5ac35 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -7,7 +7,7 @@ at least get a network connection. Or those who don't like using X. :-) """ -# Copyright (C) 2008 Andrew Psaltis +# Copyright (C) 2008-9 Andrew Psaltis # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -220,7 +220,7 @@ def about_dialog(body): ('green',"\\|| \\\\")," |+| ",('green',"// ||/ \n"), ('green'," \\\\\\")," |+| ",('green',"///")," http://wicd.net \n", ('green'," \\\\\\")," |+| ",('green',"///")," Brought to you by:\n", -('green'," \\\\\\")," |+| "('green',"///")," Adam Blackburn (wicd)\n", +('green'," \\\\\\")," |+| ",('green',"///")," Adam Blackburn (wicd)\n", " ___|+|___ Dan O'Reilly (wicd)\n", " |---------| Andrew Psaltis (this ui)\n", "---------------------------------------------------"] From 066237718f49851b9e1c21293ba009afe11645da Mon Sep 17 00:00:00 2001 From: Robby Workman Date: Thu, 1 Jan 2009 02:02:26 -0600 Subject: [PATCH 21/50] Fixed up setup.py and wpath.py to install the curses client. Added a wicd-curses wrapper script to /usr/bin Made curses *.py files executable All of this passes the build test, but not the "WFM" test. :) --- curses/curses_misc.py | 0 curses/prefs_curses.py | 0 curses/wicd-curses.py | 0 in/scripts=wicd-curses.in | 2 ++ in/wicd=wpath.py.in | 1 + setup.py | 9 ++++++++- 6 files changed, 11 insertions(+), 1 deletion(-) mode change 100644 => 100755 curses/curses_misc.py mode change 100644 => 100755 curses/prefs_curses.py mode change 100644 => 100755 curses/wicd-curses.py create mode 100755 in/scripts=wicd-curses.in diff --git a/curses/curses_misc.py b/curses/curses_misc.py old mode 100644 new mode 100755 diff --git a/curses/prefs_curses.py b/curses/prefs_curses.py old mode 100644 new mode 100755 diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py old mode 100644 new mode 100755 diff --git a/in/scripts=wicd-curses.in b/in/scripts=wicd-curses.in new file mode 100755 index 0000000..9b56c42 --- /dev/null +++ b/in/scripts=wicd-curses.in @@ -0,0 +1,2 @@ +#!/bin/bash +exec python -O %LIB%wicd-curses.py $@ diff --git a/in/wicd=wpath.py.in b/in/wicd=wpath.py.in index 2cf55ec..33282e7 100755 --- a/in/wicd=wpath.py.in +++ b/in/wicd=wpath.py.in @@ -64,6 +64,7 @@ no_install_man = %NO_INSTALL_MAN% no_install_kde = %NO_INSTALL_KDE% no_install_acpi = %NO_INSTALL_ACPI% no_install_docs = %NO_INSTALL_DOCS% +no_install_ncurses = %NO_INSTALL_NCURSES% def chdir(file): """Change directory to the location of the specified file. diff --git a/setup.py b/setup.py index 65ee989..a1e2efb 100755 --- a/setup.py +++ b/setup.py @@ -84,7 +84,8 @@ class configure(Command): ('no-install-kde', None, 'do not install the kde autostart file'), ('no-install-acpi', None, 'do not install the suspend.d and resume.d acpi scripts'), ('no-install-pmutils', None, 'do not install the pm-utils hooks'), - ('no-install-docs', None, 'do not install the auxiliary documentation') + ('no-install-docs', None, 'do not install the auxiliary documentation'), + ('no-install-ncurses', None, 'do not install the ncurses client') ] @@ -117,6 +118,7 @@ class configure(Command): self.no_install_acpi = False self.no_install_pmutils = False self.no_install_docs = False + self.no_install_ncurses = False # Determine the default init file location on several different distros @@ -392,6 +394,11 @@ try: (wpath.backends, ['wicd/backends/be-external.py', 'wicd/backends/be-ioctl.py']), (wpath.autostart, ['other/wicd-tray.desktop', ]), ] + if not wpath.no_install_ncurses: + data.append(( wpath.lib, ['curses/curses_misc.py'])) + data.append(( wpath.lib, ['curses/prefs_curses.py'])) + data.append(( wpath.lib, ['curses/wicd-curses.py'])) + data.append(( wpath.bin, ['scripts/wicd-curses'])) piddir = os.path.dirname(wpath.pidfile) if not piddir.endswith('/'): piddir += '/' From 93ef894c4585dd68f99dbd3e8449e67cedac8086 Mon Sep 17 00:00:00 2001 From: Robby Workman Date: Fri, 2 Jan 2009 20:25:16 -0600 Subject: [PATCH 22/50] Removed "in keys" from line 415 per NaCl's suggestion. --- curses/prefs_curses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/curses/prefs_curses.py b/curses/prefs_curses.py index 3dd275a..da8c39d 100755 --- a/curses/prefs_curses.py +++ b/curses/prefs_curses.py @@ -412,7 +412,7 @@ class PrefsDialog(urwid.WidgetWrap): overlay.keypress(dim, k) if self.CANCEL_PRESSED: return False - if self.OK_PRESSED in keys: + if self.OK_PRESSED: return True From 0b0f3e09687e643e34478f1821a926c1c5259f07 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Fri, 2 Jan 2009 22:12:58 -0500 Subject: [PATCH 23/50] curses/curses_misc.py: meta+right or meta+left now move the selected tab right and left respectively. Focus goes back to the tabs, though. Fixed a bug in ComboBox where show_first does nothing Restored get_selected to its original state curses/prefs_curses.py: Moved the automatic reconnect category to "General Settings" Made the backend selector actually select the selected backend at first Reset the button statuses each time we load the settings meta+enter now saves+closes the preferences dialog curses/wicd-curses.py: Turned the wired list into a list of custom SelTexts, so that they can do the connecting/script-choosing/configuring/etc, instead of the dialog itself Offset the version in the about dialog a little less Recycle the old preferences dialog instead of making a new one if we run it more than once --- curses/curses_misc.py | 31 +++++++----- curses/prefs_curses.py | 40 +++++++++++----- curses/wicd-curses.py | 106 +++++++++++++++++++++++++++-------------- 3 files changed, 115 insertions(+), 62 deletions(-) diff --git a/curses/curses_misc.py b/curses/curses_misc.py index 91d9c2a..478dbcd 100644 --- a/curses/curses_misc.py +++ b/curses/curses_misc.py @@ -120,15 +120,19 @@ class TabColumns(urwid.WidgetWrap): def keypress(self,size,key): self._w.keypress(size,key) - wid = self.pile.get_focus().get_body() - if wid == self.columns: - # lw = self.listbox.body - # lw.pop(1) - self.active_tab.set_attr('body') - self.columns.get_focus().set_attr('tab active') - self.active_tab = self.columns.get_focus() - self.gen_pile(self.tab_map[self.active_tab]) - return key + if key == "meta left" or key == "meta right": + self._w.get_body().set_focus(0) + self.keypress(size,key[5:]) + else: + wid = self.pile.get_focus().get_body() + if wid == self.columns: + # lw = self.listbox.body + # lw.pop(1) + self.active_tab.set_attr('body') + self.columns.get_focus().set_attr('tab active') + self.active_tab = self.columns.get_focus() + self.gen_pile(self.tab_map[self.active_tab]) + return key # self.listbox.body = lw @@ -144,7 +148,7 @@ class ComboBox(urwid.WidgetWrap): """A ComboBox of text objects""" class ComboSpace(urwid.WidgetWrap): """The actual menu-like space that comes down from the ComboText""" - def __init__(self,list,body,ui,show_first=0,pos=(0,0),attr=('body','focus')): + def __init__(self,list,body,ui,show_first,pos=(0,0),attr=('body','focus')): """ body : parent widget list : stuff to include in the combobox @@ -163,6 +167,7 @@ class ComboBox(urwid.WidgetWrap): content = [urwid.AttrWrap(SelText(w), attr[0], attr[1]) for w in list] self._listbox = urwid.ListBox(content) + self._listbox.set_focus(show_first) overlay = urwid.Overlay(self._listbox, body, ('fixed left', pos[0]), width + 2, ('fixed top', pos[1]), height) @@ -233,9 +238,9 @@ class ComboBox(urwid.WidgetWrap): def set_show_first(self,show_first): self.show_first = show_first - def build_combobox(self,body,ui,row,show_first=0): + def build_combobox(self,body,ui,row): str,trash = self.label.get_text() - self.cbox = urwid.AttrWrap(SelText([self.list[show_first]+' vvv']), + self.cbox = urwid.AttrWrap(SelText([self.list[self.show_first]+' vvv']), self.attr[0],self.attr[1]) if str != '': w = urwid.Columns([('fixed',len(str),self.label),self.cbox],dividechars=1) @@ -271,7 +276,7 @@ class ComboBox(urwid.WidgetWrap): # Return the index of the selected element def get_selected(self): wid,pos = self.overlay._listbox.get_focus() - return pos + return (wid,pos) # Almost completely ripped from rbreu_filechooser.py: diff --git a/curses/prefs_curses.py b/curses/prefs_curses.py index 3dd275a..3a191a3 100644 --- a/curses/prefs_curses.py +++ b/curses/prefs_curses.py @@ -79,6 +79,9 @@ class PrefsDialog(urwid.WidgetWrap): wired_auto_2_t = language['show_wired_list'] wired_auto_3_t = language['use_last_used_profile'] + auto_reconn_cat_t = ('header','Automatic Reconnection') + auto_reconn_t = 'Automatically reconnect on connection loss' + #### External Programs automatic_t = language['wicd_auto_config'] @@ -113,8 +116,6 @@ class PrefsDialog(urwid.WidgetWrap): wless_cat_t = ('header','Wireless Interface') use_dbm_t = language['display_type_dialog'] - auto_reconn_cat_t = ('header','Automatic Reconnect') - auto_reconn_t = 'Automatically reconnect on connection loss' #### @@ -145,6 +146,9 @@ class PrefsDialog(urwid.WidgetWrap): self.wired_auto_1 = urwid.RadioButton(self.wired_auto_l,wired_auto_1_t) self.wired_auto_2 = urwid.RadioButton(self.wired_auto_l,wired_auto_2_t) self.wired_auto_3 = urwid.RadioButton(self.wired_auto_l,wired_auto_3_t) + + self.auto_reconn_cat = urwid.Text(auto_reconn_cat_t) + self.auto_reconn_checkb = urwid.CheckBox(auto_reconn_t) generalLB = urwid.ListBox([self.net_cat, self.wless_edit,#_blank, self.wired_edit, @@ -156,7 +160,9 @@ class PrefsDialog(urwid.WidgetWrap): self.wired_auto_cat, self.wired_auto_1, self.wired_auto_2, - self.wired_auto_3 + self.wired_auto_3, _blank, + self.auto_reconn_cat, + self.auto_reconn_checkb ]) #### External Programs tab @@ -207,8 +213,6 @@ class PrefsDialog(urwid.WidgetWrap): self.wless_cat = urwid.Text(wless_cat_t) self.use_dbm_checkb = urwid.CheckBox(use_dbm_t) - self.auto_reconn_cat = urwid.Text(auto_reconn_cat_t) - self.auto_reconn_checkb = urwid.CheckBox(auto_reconn_t) advancedLB = urwid.ListBox([self.wpa_cat, self.wpa_cbox,self.wpa_warn,_blank, @@ -217,9 +221,8 @@ class PrefsDialog(urwid.WidgetWrap): self.debug_cat, self.debug_mode_checkb, _blank, self.wless_cat, - self.use_dbm_checkb, _blank, - self.auto_reconn_cat, - self.auto_reconn_checkb]) + self.use_dbm_checkb, _blank + ]) headerList = [self.header0,self.header1,self.header2] @@ -260,6 +263,10 @@ class PrefsDialog(urwid.WidgetWrap): self.__super.__init__(self.tabs) def load_settings(self): + # Reset the buttons + self.CANCEL_PRESSED = False + self.OK_PRESSED = False + ### General Settings # Urwid does not like dbus.Strings as text markups wless_iface = unicode(daemon.GetWirelessInterface()) @@ -282,6 +289,8 @@ class PrefsDialog(urwid.WidgetWrap): # Wired Automatic Connection self.wired_auto_l[daemon.GetWiredAutoConnectMethod()-1] + self.auto_reconn_checkb.set_state(daemon.GetAutoReconnect()) + ### External Programs dhcp_method = daemon.GetDHCPClient() self.dhcp_l[dhcp_method].set_state(True) @@ -314,11 +323,15 @@ class PrefsDialog(urwid.WidgetWrap): self.backends.remove('') self.thebackends= [unicode(w) for w in self.backends] self.backend_cbox.set_list(self.thebackends) + cur_backend = daemon.GetSavedBackend() + try: + self.backend_cbox.set_show_first(self.thebackends.index(cur_backend)) + except ValueError: + self.backend_cbox.set_show_first(0) - # Three last checkboxes + # Two last checkboxes self.debug_mode_checkb.set_state(daemon.GetDebugMode()) self.use_dbm_checkb.set_state(daemon.GetSignalDisplayType()) - self.auto_reconn_checkb.set_state(daemon.GetAutoReconnect()) def save_results(self): """ Pushes the selected settings to the daemon. @@ -329,7 +342,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()]) + daemon.SetWPADriver(self.wpadrivers[self.wpa_cbox.get_selected()[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()) @@ -341,7 +354,7 @@ class PrefsDialog(urwid.WidgetWrap): else: daemon.SetWiredAutoConnectMethod(1) - daemon.SetBackend(self.backends[self.backend_cbox.get_selected()]) + daemon.SetBackend(self.backends[self.backend_cbox.get_selected()[1]]) # External Programs Tab if self.dhcp0.get_state(): @@ -410,9 +423,10 @@ class PrefsDialog(urwid.WidgetWrap): 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 in keys: + if self.OK_PRESSED or 'meta enter' in keys: return True diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index aa5ac35..eb63cc0 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -185,24 +185,10 @@ def gen_network_list(): wlessL = [] for network_id in range(0, wireless.GetNumberOfNetworks()): - # ?: in python - encryption = wireless.GetWirelessProperty(network_id, 'encryption_method') if wireless.GetWirelessProperty(network_id, 'encryption') else 'Unsecured' - theString = ' %*s %25s %9s %17s %6s: %s' % ( gap, - daemon.FormatSignalForPrinting( - str(wireless.GetWirelessProperty(network_id, strenstr))), - wireless.GetWirelessProperty(network_id, 'essid'), - #wireless.GetWirelessProperty(network_id, 'encryption_method'), - encryption, - wireless.GetWirelessProperty(network_id, 'bssid'), - wireless.GetWirelessProperty(network_id, 'mode'), # Master, Ad-Hoc - wireless.GetWirelessProperty(network_id, 'channel') - ) is_active = wireless.GetCurrentSignalStrength("") != 0 and wireless.GetCurrentNetworkID(wireless.GetIwconfig())==network_id - if is_active: - theString = '>'+theString[1:] - wlessL.append(urwid.AttrWrap(SelText(theString),'connected','connected focus')) - else: - wlessL.append(urwid.AttrWrap(SelText(theString),'body','focus')) + + label = NetLabel(network_id,is_active) + wlessL.append(label) return (wiredL,wlessL) def about_dialog(body): @@ -215,7 +201,7 @@ def about_dialog(body): ('green'," /// \\\\\\")," | |/ |/ / / __/ _ / \n", ('green',"/|| // \\\\ ||\\")," |__/|__/_/\__/\_,_/ \n", ('green',"||| ||"),"(|^|)",('green',"|| |||"), -" ($VERSION) \n".replace("$VERSION",daemon.Hello()), +" ($VERSION) \n".replace("$VERSION",daemon.Hello()), ('green',"\\|| \\\\")," |+| ",('green',"// ||/ \n"), ('green'," \\\\\\")," |+| ",('green',"///")," http://wicd.net \n", @@ -242,6 +228,50 @@ def about_dialog(body): if about.b_pressed == 'OK': return False +class NetLabel(urwid.WidgetWrap): + def __init__(self, id, is_active): + # Pick which strength measure to use based on what the daemon says + if daemon.GetSignalDisplayType() == 0: + strenstr = 'quality' + gap = 3 + else: + strenstr = 'strength' + gap = 5 + self.id = id + # All of that network property stuff + self.stren = daemon.FormatSignalForPrinting( + str(wireless.GetWirelessProperty(id, strenstr))) + self.essid = wireless.GetWirelessProperty(id, 'essid') + self.bssid = wireless.GetWirelessProperty(id, 'bssid') + self.encrypt = wireless.GetWirelessProperty(id,'encryption_method') if wireless.GetWirelessProperty(id, 'encryption') else 'Unsecured' + self.mode = wireless.GetWirelessProperty(id, 'mode') # Master, Ad-Hoc + self.channel = wireless.GetWirelessProperty(id, 'channel') + theString = ' %*s %25s %9s %17s %6s: %s' % (gap, + self.stren,self.essid,self.encrypt,self.bssid,self.mode,self.channel) + if is_active: + theString = '>'+theString[1:] + w = urwid.AttrWrap(SelText(theString),'connected','connected focus') + else: + w = urwid.AttrWrap(SelText(theString),'body','focus') + + self.__super.__init__(w) + def selectable(self): + return True + def keypress(self,size,key): + self._w.keypress(size,key) + if key == 'C': + # Configure the network + pass + elif key == 'S': + # Configure scripts + pass + elif key == 'enter': + self.connect() + return key + def connect(self): + # This should work. + wireless.ConnectWireless(self.id) + ######################################## ##### APPLICATION INTERFACE CLASS ######################################## @@ -299,8 +329,10 @@ class appGUI(): self.prev_state = False self.connecting = False self.screen_locked = False - self.connecting = False self.always_show_wired = daemon.GetAlwaysShowWiredInterface() + + self.pref = None + self.update_status() #self.dialog = PrefOverlay(self.frame,self.size) @@ -406,7 +438,7 @@ class appGUI(): # If we are connecting and being called from the idle function, spin # the wheel. if from_idle and self.connecting: - # This is probably the wrong way to do this, but ir works for now. + # This is probably the wrong way to do this, but it works for now. toAppend=self.twirl[self.incr % 4] self.footer2 = urwid.AttrWrap(urwid.Text(text+' '+toAppend),'important') self.frame.set_footer(urwid.BoxAdapter( @@ -463,6 +495,7 @@ class appGUI(): if "f5" in keys: wireless.Scan() if "enter" in keys: + # TODO: Make this totally go away by superclassing ComboBox # Should be a function of the labels, I think. self.call_connect() if "D" in keys: @@ -476,11 +509,11 @@ class appGUI(): # Prevents automatic reconnecting if that option is enabled daemon.SetForcedDisconnect(True) if "P" in keys: - dialog = PrefsDialog(self.frame,(0,1),ui, - dbusmanager.get_dbus_ifaces()) - # There is some lag in using the buttons. Not my fault. - if dialog.run(ui,self.size,self.frame): - dialog.save_results() + if not self.pref: + self.pref = PrefsDialog(self.frame,(0,1),ui, + dbusmanager.get_dbus_ifaces()) + if self.pref.run(ui,self.size,self.frame): + self.pref.save_results() self.update_ui() if "A" in keys: about_dialog(self.frame) @@ -491,13 +524,15 @@ class appGUI(): self.frame.keypress( self.size, k ) if " " in keys: - #self.set_status('space pressed on wiredCB!') - wid,pos = self.wiredCB.get_body().get_selected() - text,attr = wid.get_text() - wired.ReadWiredNetworkProfile(text) - # Make sure our internal reference to the combobox matches the - # one found in the pile. - self.wiredCB = self.thePile.get_focus() + focus = self.thePile.get_focus() + if focus == self.wiredCB: + #self.set_status('space pressed on wiredCB!') + wid,pos = self.wiredCB.get_body().get_selected() + text,attr = wid.get_text() + wired.ReadWiredNetworkProfile(text) + # Make sure our internal reference to the combobox matches the + # one found in the pile. + #self.wiredCB = self.thePile.get_focus() return True @@ -510,9 +545,8 @@ class appGUI(): self.connect(self,'wired',0) #return "Wired network %i" % pos elif wid is self.wlessLB: - #self.footer1 = urwid.Text("Wireless!") - wid2,pos = self.wlessLB.get_focus() - self.connect(self,'wireless',pos) + # Do nothing + pass else: self.set_status("call_connect() failed! This is definitely a bug!") #return "Failure!" @@ -602,7 +636,7 @@ def setup_dbus(force=True): # Suggestions as to what should go here print "Can't connect to the daemon. Are you sure it is running?" print "Please check the wicd log for error messages." - raise + #raise # return False # <- Will need soon. bus = dbusmanager.get_bus() dbus_ifaces = dbusmanager.get_dbus_ifaces() From 5b8417e8a87f3a2dc6be9c414e3426643db87636 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Sat, 3 Jan 2009 22:57:41 -0500 Subject: [PATCH 24/50] curses/curses_misc.py: meta+left/right now sets focus back to whereever you were in the list. curses/wicd-curses.py: Made a custom combobox for the wired networks. The one during the last commit was actually the wireless list. (Hopefully) made the wired network show up when it is actually active. Removed appGUI.call_connect and appGUI.connect. They are no longer needed. in/man=wicd-curses.8.in: ADDED. wicd-curses(8) man page setup.py: Install the above man page if we are installing the rest of the curses client --- curses/curses_misc.py | 3 +- curses/wicd-curses.py | 123 +++++++++++++++++++++++----------------- in/man=wicd-curses.8.in | 77 +++++++++++++++++++++++++ setup.py | 1 + 4 files changed, 150 insertions(+), 54 deletions(-) create mode 100644 in/man=wicd-curses.8.in diff --git a/curses/curses_misc.py b/curses/curses_misc.py index 478dbcd..4ed8251 100644 --- a/curses/curses_misc.py +++ b/curses/curses_misc.py @@ -123,6 +123,7 @@ class TabColumns(urwid.WidgetWrap): if key == "meta left" or key == "meta right": self._w.get_body().set_focus(0) self.keypress(size,key[5:]) + self._w.get_body().set_focus(1) else: wid = self.pile.get_focus().get_body() if wid == self.columns: @@ -147,7 +148,7 @@ class ComboBoxException(Exception): class ComboBox(urwid.WidgetWrap): """A ComboBox of text objects""" class ComboSpace(urwid.WidgetWrap): - """The actual menu-like space that comes down from the ComboText""" + """The actual menu-like space that comes down from the ComboBox""" def __init__(self,list,body,ui,show_first,pos=(0,0),attr=('body','focus')): """ body : parent widget diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index eb63cc0..63da620 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -167,23 +167,25 @@ def gen_network_list(): id = 0 wiredL = [] + is_active = wireless.GetWirelessIP('') == None and wired.GetWiredIP('') != None + # This one makes a list of strings to put in a combo box. for profile in wired.GetWiredProfileList(): theString = '%4s %25s' % (id, profile) #### THIS IS wired.blah() in experimental #print config.GetLastUsedWiredNetwork() # Tag if no wireless IP present, and wired one is - is_active = wireless.GetWirelessIP('') == None and wired.GetWiredIP('') != None - if is_active: - theString = '>'+theString[1:] + #if is_active: + # theString = '>'+theString[1:] #wiredL.append(urwid.AttrWrap(SelText(theString),'connected', # 'connected focus')) #else: - # wiredL.append(urwid.AttrWrap(SelText(theString),'body','focus')) + #wiredL.append(urwid.AttrWrap(SelText(theString),'body','focus')) wiredL.append(theString) id+=1 wlessL = [] + # This one makes a list of NetLabels for network_id in range(0, wireless.GetNumberOfNetworks()): is_active = wireless.GetCurrentSignalStrength("") != 0 and wireless.GetCurrentNetworkID(wireless.GetIwconfig())==network_id @@ -228,6 +230,11 @@ def about_dialog(body): if about.b_pressed == 'OK': return False +######################################## +##### URWID SUPPORT CLASSES +######################################## + +# Wireless network label class NetLabel(urwid.WidgetWrap): def __init__(self, id, is_active): # Pick which strength measure to use based on what the daemon says @@ -272,6 +279,50 @@ class NetLabel(urwid.WidgetWrap): # This should work. wireless.ConnectWireless(self.id) +class WiredComboBox(ComboBox): + """ + list : the list of wired network profiles. The rest is self-explanitory. + """ + def init(self,list): + self.theList = list + id = 0 + wiredL = [] + is_active = wireless.GetWirelessIP('') == None and wired.GetWiredIP('') != None + for profile in list: + theString = '%4s %25s' % (id, profile) + #### THIS IS wired.blah() in experimental + #print config.GetLastUsedWiredNetwork() + # Tag if no wireless IP present, and wired one is + if is_active: + theString = '>'+theString[1:] + + #wiredL.append(urwid.AttrWrap(SelText(theString),'connected', + # 'connected focus')) + #else: + # wiredL.append(urwid.AttrWrap(SelText(theString),'body','focus')) + wiredL.append(theString) + id+=1 + self.__super.__init__(list=wiredL,use_enter=False) + self.set_show_first(theList.index(wired.GetDefaultWiredProfile())) + + def keypress(self,size,key): + self.__super.keypress(size,key) + if key == 'C': + # Configure the network + pass + elif key == 'S': + # Configure scripts + pass + elif key == 'enter': + self.connect() + return key + + def connect(self): + wired.ConnectWired() + def get_selected_profile(self): + """Get the selected wired profile""" + return self.theList[self._w.get_selected()[1]] + ######################################## ##### APPLICATION INTERFACE CLASS ######################################## @@ -294,7 +345,7 @@ class appGUI(): self.wlessH=urwid.Filler(urwid.Text("Wireless Network(s)")) wiredL,wlessL = gen_network_list() - self.wiredCB = urwid.Filler(ComboBox(list=wiredL,use_enter=False)) + self.wiredCB = urwid.Filler(WiredComboBox(list=wiredL)) self.wlessLB = urwid.ListBox(wlessL) # Stuff I used to simulate large lists #spam = SelText('spam') @@ -305,8 +356,9 @@ class appGUI(): # spam,spam,spam,spam] ] #self.spamLB = urwid.ListBox(spamL) - # Choose whether to show the wired part of the interface. - if daemon.GetAlwaysShowWiredInterface(): + # Choose whether to show the wired part of the interface, if a cable + # is plugged in, or the + if daemon.GetAlwaysShowWiredInterface() or wired.CheckPluggedIn(): self.thePile = urwid.Pile([('fixed',1,self.wiredH), ('fixed',1,self.wiredCB), ('fixed',1,self.wlessH), @@ -329,7 +381,7 @@ class appGUI(): self.prev_state = False self.connecting = False self.screen_locked = False - self.always_show_wired = daemon.GetAlwaysShowWiredInterface() + #self.always_show_wired = daemon.GetAlwaysShowWiredInterface() self.pref = None @@ -365,18 +417,17 @@ class appGUI(): self.wiredCB.get_body().set_list(wiredL) self.wiredCB.get_body().build_combobox(self.frame,ui,3) self.wlessLB.body = urwid.SimpleListWalker(wlessL) - # If the "Always Show Wired" part of the interface changes, change - # along with it. - if daemon.GetAlwaysShowWiredInterface() != self.always_show_wired: - if daemon.GetAlwaysShowWiredInterface(): - self.thePile = urwid.Pile([('fixed',1,self.wiredH), - ('fixed',1,self.wiredCB), - ('fixed',1,self.wlessH), - self.wlessLB] ) - else: - self.thePile = urwid.Pile([('fixed',1,self.wlessH),self.wlessLB] ) + + 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] ) + else: + self.thePile = urwid.Pile([('fixed',1,self.wlessH),self.wlessLB] ) self.frame.body = self.thePile - self.always_show_wired = not self.always_show_wired + #self.always_show_wired = not self.always_show_wired self.prev_state = state # Update the footer/status bar @@ -494,10 +545,6 @@ class appGUI(): return False if "f5" in keys: wireless.Scan() - if "enter" in keys: - # TODO: Make this totally go away by superclassing ComboBox - # Should be a function of the labels, I think. - self.call_connect() if "D" in keys: # Disconnect from all networks. daemon.Disconnect() @@ -536,36 +583,6 @@ class appGUI(): return True - # Bring back memories, anyone? - def call_connect(self): - wid = self.thePile.get_focus() - if wid is self.wiredCB: - #wid2,pos = self.wiredCB.get_focus() - # Apparently, connect() doesn't care about the networkid - self.connect(self,'wired',0) - #return "Wired network %i" % pos - elif wid is self.wlessLB: - # Do nothing - pass - else: - self.set_status("call_connect() failed! This is definitely a bug!") - #return "Failure!" - - def connect(self, event, nettype, networkid): - """ Initiates the connection process in the daemon. """ - if nettype == "wireless": - # I need to do something that is similar to this in this UI, but - # I don't have an "advanced settings" dialog yet. - #if not self.check_encryption_valid(networkid, - # networkentry.advanced_dialog): - # self.edit_advanced(None, None, nettype, networkid, networkentry) - # return False - wireless.ConnectWireless(networkid) - elif nettype == "wired": - wired.ConnectWired() - self.update_status() - - ######################################## ##### INITIALIZATION FUNCTIONS ######################################## diff --git a/in/man=wicd-curses.8.in b/in/man=wicd-curses.8.in new file mode 100644 index 0000000..a2fa070 --- /dev/null +++ b/in/man=wicd-curses.8.in @@ -0,0 +1,77 @@ +.TH WICD-CURSES "8" "January 2009" "wicd-curses" +.SH NAME +.B wicd-curses +\- curses-based wicd(8) controller +.SH DESCRIPTION +wicd-curses is a curses-based network controller that uses the Wired/Wireless Internet Connection Daemon (wicd) to control your network connections. It is suitable to run in terminal multiplexers like screen(1). + +It is designed to imitate the GTK-based wicd-client(1) as much as possible, and uses the Urwid (http://excess.org/urwid) console widget library to vastly simplify development. + +This man page only documents the current status of wicd-curses. This may/may not be the most up-to-date document. +.SH "ARGUMENTS" +These are not implemented yet. +.TP +.BR "\-r" , " \-\-raw\-screen" +Use Urwid's raw console display, instead of the (faster) curses-based one. This may be useful if you are experiencing unicode problems. +.SH CONTROLS +All of these are case sensitive. +.TP +.BR enter +Connect to selected network +.TP +.BR "F8 " or " Q" +Quit the client. +.TP +.BR D +Disconnect all devices from network connections +.TP +.BR ESC +If connecting to a network, stop doing so +.TP +.BR "F5 " or " R" +Refresh the network list +.TP +.BR P +Bring up the preferences controller +.PP +The following are not implemented yet: +.TP +.BR C +Bring up network configuration controller for the selected network +.TP +.BR S +Bring up the script selector for the selected network (requires superuser privileges) + +.SH "FILES" +These are not used yet. +.TP +.I ~/.wicd/WHEREAREMYFILES +Reminder that your network configuration files are not here ;-) +.TP +.I %LIB%keymap.py +Tenative location of the system keymap +.TP +.I %LIB%colors.py +Tenative location of the system color schemes +.TP +.I ~/.wicd/keymap.py +Custom keybindings. Also where you can (later) disable the mouse. +.TP +.I ~/.wicd/colors.py +Custom color schemes. +.SH "SEE ALSO" +.BR wicd-client (1), +.BR wicd (8) + +.SH BUGS +Probably lots. ;-) + +If you happen to find one, ask about it on #wicd on freenode, or submit a bug report to http://launchpad.net/wicd, branch experimental-nacl. + +.SH WICD-CURSES AUTHOR +Andrew Psaltis + +.SH WICD AUTHORS +Adam Blackburn +.br +Dan O'Reilly diff --git a/setup.py b/setup.py index a1e2efb..38a9244 100755 --- a/setup.py +++ b/setup.py @@ -399,6 +399,7 @@ try: data.append(( wpath.lib, ['curses/prefs_curses.py'])) data.append(( wpath.lib, ['curses/wicd-curses.py'])) data.append(( wpath.bin, ['scripts/wicd-curses'])) + data.append(( wpath.mandir + 'man8', ['man/wicd-curses.8'])) piddir = os.path.dirname(wpath.pidfile) if not piddir.endswith('/'): piddir += '/' From c60713cdd63772500e1f8fd80ae19e69739a2265 Mon Sep 17 00:00:00 2001 From: Robby Workman Date: Sun, 4 Jan 2009 02:31:01 -0600 Subject: [PATCH 25/50] s/Tenative/Tentative/g in wicd-curses(8) --- in/man=wicd-curses.8.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/in/man=wicd-curses.8.in b/in/man=wicd-curses.8.in index a2fa070..ee285ed 100644 --- a/in/man=wicd-curses.8.in +++ b/in/man=wicd-curses.8.in @@ -49,10 +49,10 @@ These are not used yet. Reminder that your network configuration files are not here ;-) .TP .I %LIB%keymap.py -Tenative location of the system keymap +Tentative location of the system keymap .TP .I %LIB%colors.py -Tenative location of the system color schemes +Tentative location of the system color schemes .TP .I ~/.wicd/keymap.py Custom keybindings. Also where you can (later) disable the mouse. From 68036d91ac4ad0694dfc54af9e94b05619a1dfb7 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Sun, 4 Jan 2009 20:33:31 -0500 Subject: [PATCH 26/50] curses/curses_misc.py: Added DynWrapper, a wrapper class with which we can dynamically change the selectability of a widget. Removed ToggleEdit, replaced by DynWrapper. curses/netentry_curses.py: ADDED. Network entry configurator dialog. Has a base class for the common elements of the wired/wireless NetEntries. curses/prefs_curses.py: Replaced ToggleEdits with DynWrapped Edits. curses/wicd-curses.py: Rebuilt the connect function into the main keyhandler. I discovered that implementing that the way I had previously done it would have made displaying the dialogs a bit more difficult Added support for running the NetEntry selector in/man=wicd-curses.8.in, curses/README: Modified to say that the NetEntry dialog is now a WIP (Raise it with 'C') setup.py: Install netentry_curses.py if we are installing the rest of the curses client Install the man page only if we want to install the rest of the man pages and the curses client --- curses/README | 7 ++- curses/curses_misc.py | 63 +++++++++---------- curses/netentry_curses.py | 124 ++++++++++++++++++++++++++++++++++++++ curses/prefs_curses.py | 13 ++-- curses/wicd-curses.py | 64 ++++++++++++++------ in/man=wicd-curses.8.in | 4 +- setup.py | 4 +- 7 files changed, 220 insertions(+), 59 deletions(-) create mode 100644 curses/netentry_curses.py diff --git a/curses/README b/curses/README index 7586196..d443845 100644 --- a/curses/README +++ b/curses/README @@ -2,8 +2,8 @@ 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's not going to install itself until I -work on it more and figure out how to use distutils. +That's all there is to it, really. It installs unless you disable 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 @@ -18,10 +18,13 @@ D : disconnect from active network 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 A : Display "About" dialog IN DIALOGS: ESC or Q: Quit dialog without saving information (if present) +Meta+Left/Right: Change tabs Left/Right +Meta+Enter : Quit dialog and save information diff --git a/curses/curses_misc.py b/curses/curses_misc.py index 4ed8251..78f0945 100644 --- a/curses/curses_misc.py +++ b/curses/curses_misc.py @@ -40,43 +40,44 @@ class SelText(urwid.Text): """Don't handle any keys.""" return key -class ToggleEdit(urwid.WidgetWrap): - """A edit that can be rendered unselectable by somethhing like a checkbox""" - def __init__(self, caption='', state=True, - attr=('editbx','editfc'),attrnsens='body'): - """ - caption : the Edit's caption - state : the Edit's current sensitivity - attr : tuple of (attr_no_focus, attr_focus) - attrnsens: attr to use when not sensitive - """ - edit = urwid.Edit(caption) - curattr = attr[0] if state == True else attrnsens - w = urwid.AttrWrap(edit,curattr,attr[1]) - self.sensitive=state - self.__super.__init__(w) +# This class is annoying. ^_^ +class DynWrap(urwid.AttrWrap): + """ + Makes an object have mutable selectivity. Attributes will change like + those in an AttrWrap - # Kinda like the thing in PyGTK + w = widget to wrap + sensitive = current selectable state + attrs = tuple of (attr_sens,attr_not_sens) + attrfoc = attributes when in focus, defaults to nothing + """ + + def __init__(self,w,sensitive=True,attrs=('editbx','editnfc'),focus_attr='editfc'): + self.attrs=attrs + self._sensitive = sensitive + + cur_attr = attrs[0] if sensitive else attrs[1] + + self.__super.__init__(w,cur_attr,focus_attr) + + def get_sensitive(self): + return self._sensitive def set_sensitive(self,state): - self.sensitive=state - if state: - self._w.set_attr('editbx') + if state : + self.set_attr(self.attrs[0]) else: - self._w.set_attr('body') + self.set_attr(self.attrs[1]) + self._sensitive = state + property(get_sensitive,set_sensitive) - def set_edit_text(self,text): - self._w.set_edit_text(text) - - def get_edit_text(self): - return self._w.get_edit_text() + def get_attrs(self): + return self._attrs + def set_attrs(self,attrs): + self.attrs = attrs + property(get_attrs,set_attrs) - # If we aren't sensitive, don't be selectable def selectable(self): - return self.sensitive - - # Do what an edit does with keys - def keypress(self,size,key): - return self._w.keypress(size,key) + return self._sensitive # Tabbed interface, mostly for use in the Preferences Dialog class TabColumns(urwid.WidgetWrap): diff --git a/curses/netentry_curses.py b/curses/netentry_curses.py new file mode 100644 index 0000000..2eb4d8f --- /dev/null +++ b/curses/netentry_curses.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python + +# Copyright (C) 2009 Andrew Psaltis + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import urwid +from curses_misc import Dialog,DynWrap +import wicd.misc as misc + +language = misc.get_language_list_gui() +# 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): + def __init__(self,dbus): + static_ip_t = language['use_static_ip'] + ip_t = ('editcp',language['ip']+': ') + netmask_t = ('editcp',language['netmask']+':') + gateway_t = ('editcp',language['gateway']+':') + + use_static_dns_t = language['use_static_dns'] + use_global_dns_t = language['use_global_dns'] + dns_dom_t = ('editcp',language['dns_domain']+': ') + search_dom_t = ('editcp',language['search_domain']+':') + dns1_t = ('editcp',language['dns']+ ' ' + language['1']+':'+' '*8) + dns2_t = ('editcp',language['dns']+ ' ' + language['2']+':'+' '*8) + dns3_t = ('editcp',language['dns']+ ' ' + language['3']+':'+' '*8) + + cancel_t = 'cancel' + ok_t = 'OK' + + self.static_ip_cb = urwid.CheckBox(static_ip_t, + on_state_change=self.static_ip_set_state) + self.ip_edit =DynWrap(urwid.Edit(ip_t),False) + self.netmask_edit=DynWrap(urwid.Edit(netmask_t),False) + self.gateway_edit=DynWrap(urwid.Edit(gateway_t),False) + + + self.use_static_dns_cb = urwid.CheckBox(use_static_dns_t, + on_state_change=self.dns_toggle) + self.use_global_dns_cb = DynWrap(urwid.CheckBox(use_global_dns_t, + on_state_change=self.dns_toggle),False,('body','editnfc'),None) + checkb_cols = urwid.Columns([self.use_static_dns_cb, + self.use_global_dns_cb]) + self.dns_dom_edit = DynWrap(urwid.Edit(dns_dom_t) ,False) + self.search_dom_edit = DynWrap(urwid.Edit(search_dom_t),False) + self.dns1 = DynWrap(urwid.Edit(dns1_t) ,False) + self.dns2 = DynWrap(urwid.Edit(dns2_t) ,False) + self.dns3 = DynWrap(urwid.Edit(dns3_t) ,False) + + _blank = urwid.Text('') + + self._listbox = urwid.ListBox([self.static_ip_cb, + self.ip_edit, + self.netmask_edit, + _blank, + checkb_cols, + self.dns_dom_edit,self.search_dom_edit, + self.dns1,self.dns2,self.dns3 + ]) + + #self._frame = urwid.Frame(self._listbox) + self.__super.__init__(self._listbox) + + 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) + + def dns_toggle(self,checkb,new_state,user_data=None): + if checkb == self.use_static_dns_cb: + for w in [ self.dns_dom_edit,self.search_dom_edit, + self.dns1,self.dns2,self.dns3 ]: + w.set_sensitive(new_state) + if not new_state: + self.use_global_dns_cb.set_state(False,do_callback=False) + self.use_global_dns_cb.set_sensitive(new_state) + # use_global_dns_cb is DynWrapped + if checkb == self.use_global_dns_cb.get_w(): + for w in [ self.dns_dom_edit,self.search_dom_edit, + self.dns1,self.dns2,self.dns3 ]: + w.set_sensitive(not new_state) + + # We need a network ID for this, and I am not sure how to get it yet. + # TODO: Implement this + #def load_settings(self): + + def run(self,ui,dim,display): + width,height = ui.get_cols_rows() + + overlay = urwid.Overlay(self, display, ('fixed left', 0),width + , ('fixed top',1), height-3) + #self.ready_comboboxes(ui,overlay) + + keys = True + while True: + if keys: + ui.draw_screen(dim, overlay.render(dim, True)) + keys = ui.get_input() + + 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 diff --git a/curses/prefs_curses.py b/curses/prefs_curses.py index 3a191a3..8ba6461 100755 --- a/curses/prefs_curses.py +++ b/curses/prefs_curses.py @@ -22,7 +22,7 @@ import urwid.curses_display from wicd import misc from wicd import dbusmanager -from curses_misc import SelText,ToggleEdit,ComboBox,TabColumns +from curses_misc import SelText,DynWrap,ComboBox,TabColumns daemon = None wireless = None @@ -133,11 +133,12 @@ class PrefsDialog(urwid.WidgetWrap): global_dns_state = False self.global_dns_checkb = urwid.CheckBox(global_dns_t,global_dns_state, on_state_change=self.global_dns_trigger) - self.search_dom = ToggleEdit(search_dom_t,global_dns_state) - self.dns_dom = ToggleEdit(dns_dom_t,global_dns_state) - self.dns1 = ToggleEdit(dns1_t,global_dns_state) - self.dns2 = ToggleEdit(dns2_t,global_dns_state) - self.dns3 = ToggleEdit(dns3_t,global_dns_state) + self.search_dom = DynWrap(urwid.Edit(search_dom_t),global_dns_state) + self.dns_dom = DynWrap(urwid.Edit(dns_dom_t),global_dns_state) + self.dns1 = DynWrap(urwid.Edit(dns1_t),global_dns_state) + self.dns2 = DynWrap(urwid.Edit(dns2_t),global_dns_state) + self.dns3 = DynWrap(urwid.Edit(dns3_t),global_dns_state) + self.always_show_wired_checkb = urwid.CheckBox(always_show_wired_t) diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 63da620..7133dd0 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -54,8 +54,8 @@ from time import sleep # Curses UIs for other stuff from curses_misc import SelText,ComboBox,Dialog -import prefs_curses from prefs_curses import PrefsDialog +from netentry_curses import NetEntryBase language = misc.get_language_list_gui() # Whew. Now on to more interesting stuff: @@ -265,16 +265,16 @@ class NetLabel(urwid.WidgetWrap): def selectable(self): return True def keypress(self,size,key): - self._w.keypress(size,key) - if key == 'C': - # Configure the network - pass - elif key == 'S': + return self._w.keypress(size,key) + #if key == 'C': + # conf = NetEntryBase(dbusmanager.get_dbus_ifaces()) + # conf.run(ui,ui.get_cols_rows(),) + #elif key == 'S': # Configure scripts - pass - elif key == 'enter': - self.connect() - return key + # pass + #elif key == 'enter': + # self.connect() + #return key def connect(self): # This should work. wireless.ConnectWireless(self.id) @@ -307,15 +307,15 @@ class WiredComboBox(ComboBox): def keypress(self,size,key): self.__super.keypress(size,key) - if key == 'C': + #if key == 'C': # Configure the network - pass - elif key == 'S': + # pass + #elif key == 'S': # Configure scripts - pass - elif key == 'enter': - self.connect() - return key + # pass + #elif key == 'enter': + # self.connect() + #return key def connect(self): wired.ConnectWired() @@ -345,7 +345,7 @@ class appGUI(): self.wlessH=urwid.Filler(urwid.Text("Wireless Network(s)")) wiredL,wlessL = gen_network_list() - self.wiredCB = urwid.Filler(WiredComboBox(list=wiredL)) + self.wiredCB = urwid.Filler(ComboBox(list=wiredL)) self.wlessLB = urwid.ListBox(wlessL) # Stuff I used to simulate large lists #spam = SelText('spam') @@ -549,6 +549,17 @@ class appGUI(): # Disconnect from all networks. daemon.Disconnect() self.update_netlist() + # Guess what! I actually need to put this here, else I'll have tons of + # references to self.frame lying around. ^_^ + if "enter" in keys: + focus = self.thePile.get_focus() + if focus == self.wiredCB: + self.connect("wired",0) + else: + # wless list only other option + wid,pos = self.thePile.get_focus().get_focus() + self.connect("wireless",pos) + if "esc" in keys: # Force disconnect here if connection in progress if self.connecting: @@ -570,6 +581,10 @@ class appGUI(): continue self.frame.keypress( self.size, k ) + if "C" in keys: + 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: @@ -582,6 +597,18 @@ class appGUI(): #self.wiredCB = self.thePile.get_focus() return True + # TODO: Update this to use the networkentry stuff + def connect(self, nettype, networkid, networkentry=None): + """ Initiates the connection process in the daemon. """ + if nettype == "wireless": + #if not self.check_encryption_valid(networkid, + # networkentry.advanced_dialog): + # self.edit_advanced(None, None, nettype, networkid, networkentry) + # return False + wireless.ConnectWireless(networkid) + elif nettype == "wired": + wired.ConnectWired() + self.update_status() ######################################## ##### INITIALIZATION FUNCTIONS @@ -610,6 +637,7 @@ def main(): ('editcp', 'default', 'default', 'standout'), ('editbx', 'light gray', 'dark blue'), ('editfc', 'white','dark blue', 'bold'), + ('editnfc','dark gray','default'), ('tab active','dark green','light gray'), # Simple colors around text ('green','dark green','default'), diff --git a/in/man=wicd-curses.8.in b/in/man=wicd-curses.8.in index a2fa070..d3846d9 100644 --- a/in/man=wicd-curses.8.in +++ b/in/man=wicd-curses.8.in @@ -34,10 +34,12 @@ Refresh the network list .BR P Bring up the preferences controller .PP -The following are not implemented yet: +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: .TP .BR S Bring up the script selector for the selected network (requires superuser privileges) diff --git a/setup.py b/setup.py index 38a9244..293f2bf 100755 --- a/setup.py +++ b/setup.py @@ -398,8 +398,10 @@ try: data.append(( wpath.lib, ['curses/curses_misc.py'])) data.append(( wpath.lib, ['curses/prefs_curses.py'])) data.append(( wpath.lib, ['curses/wicd-curses.py'])) + data.append(( wpath.lib, ['curses/netentry_curses.py'])) data.append(( wpath.bin, ['scripts/wicd-curses'])) - data.append(( wpath.mandir + 'man8', ['man/wicd-curses.8'])) + if not wpath.no_install_man: + data.append(( wpath.mandir + 'man8', ['man/wicd-curses.8'])) piddir = os.path.dirname(wpath.pidfile) if not piddir.endswith('/'): piddir += '/' From 2eaa3e3694afd7c204634f1c5fd4fdf3d04e9ced Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Sun, 4 Jan 2009 20:36:12 -0500 Subject: [PATCH 27/50] in/man=wicd-curses.8.in: Apparently I can't spell "tentative" properly. Thanks to rworkman. --- in/man=wicd-curses.8.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/in/man=wicd-curses.8.in b/in/man=wicd-curses.8.in index d3846d9..670b37d 100644 --- a/in/man=wicd-curses.8.in +++ b/in/man=wicd-curses.8.in @@ -51,10 +51,10 @@ These are not used yet. Reminder that your network configuration files are not here ;-) .TP .I %LIB%keymap.py -Tenative location of the system keymap +Tentative location of the system keymap .TP .I %LIB%colors.py -Tenative location of the system color schemes +Tentative location of the system color schemes .TP .I ~/.wicd/keymap.py Custom keybindings. Also where you can (later) disable the mouse. From bb8cfb2b9db7c50668edc175a004dfd3034cb2b8 Mon Sep 17 00:00:00 2001 From: Robby Workman Date: Mon, 5 Jan 2009 23:12:49 -0600 Subject: [PATCH 28/50] Added logic for kde4-config (kde4's equivalent to kde-config) --- setup.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/setup.py b/setup.py index 293f2bf..92815a4 100755 --- a/setup.py +++ b/setup.py @@ -189,13 +189,22 @@ class configure(Command): else: self.kdedir = kdedir_candidate + '/share/autostart' except (OSError, ValueError): - # If kde-config isn't present or returns an error, then we can - # assume that kde isn't installed on the user's system - self.no_install_kde = True - # If it turns out that the assumption above is wrong, then we'll - # do this instead: - #pass # use our default - + # If kde-config isn't present, we'll check for kde-4.x + try: + kde4temp = subprocess.Popen(["kde4-config","--prefix"], stdout=subprocess.PIPE) + returncode = kde4temp.wait() # let it finish, and get the exit code + kde4dir_candidate = kde4temp.stdout.readline().strip() # read stdout + if len(kde4dir_candidate) == 0 or returncode != 0 or not os.path.isabs(kde4dir_candidate): + raise ValueError + else: + self.kdedir = kde4dir_candidate + '/share/autostart' + except (OSError, ValueError): + # If neither kde-config nor kde4-config are not present or + # return an error, then we can assume that kde isn't installed + # on the user's system + self.no_install_kde = True + # If the assumption above turns out to be wrong, do this: + #pass # use our default self.python = '/usr/bin/python' self.pidfile = '/var/run/wicd/wicd.pid' From 4ab56b11830652c23b7ce457acf2adaa95368e94 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Tue, 6 Jan 2009 19:02:27 -0500 Subject: [PATCH 29/50] Checkpoint in WirelessNetEntry development curses/curses_misc.py: Refactored some DynWrap internals Added MaskingEdit, a password edit Modified ComboBox to use a DynWrap internally instead of an AttrWrap curses/netentry_curses.py: Added most of the WirelessNetEntry. It doesn't save information yet, but it does load most of it. Support for viewing the templated network settings is not implemented yet. curses/wicd-curses.py: Activated support for the WirelessNetEntry configurator. The wired one is not implemented yet. --- curses/curses_misc.py | 89 +++++++++++++--- curses/netentry_curses.py | 215 ++++++++++++++++++++++++++++++++++---- curses/prefs_curses.py | 2 +- curses/wicd-curses.py | 27 +++-- 4 files changed, 289 insertions(+), 44 deletions(-) diff --git a/curses/curses_misc.py b/curses/curses_misc.py index 78f0945..06bfb77 100644 --- a/curses/curses_misc.py +++ b/curses/curses_misc.py @@ -5,7 +5,7 @@ wicd-curses. """ -# Copyright (C) 2008-9 Andrew Psaltis +# Copyright (C) 2008-2009 Andrew Psaltis # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -53,7 +53,7 @@ class DynWrap(urwid.AttrWrap): """ def __init__(self,w,sensitive=True,attrs=('editbx','editnfc'),focus_attr='editfc'): - self.attrs=attrs + self._attrs=attrs self._sensitive = sensitive cur_attr = attrs[0] if sensitive else attrs[1] @@ -63,22 +63,78 @@ class DynWrap(urwid.AttrWrap): def get_sensitive(self): return self._sensitive def set_sensitive(self,state): - if state : - self.set_attr(self.attrs[0]) + if state: + self.set_attr(self._attrs[0]) else: - self.set_attr(self.attrs[1]) + self.set_attr(self._attrs[1]) self._sensitive = state property(get_sensitive,set_sensitive) def get_attrs(self): return self._attrs def set_attrs(self,attrs): - self.attrs = attrs + self._attrs = attrs property(get_attrs,set_attrs) def selectable(self): return self._sensitive +class MaskingEditException(Exception): + pass + +# Password-style edit +class MaskingEdit(urwid.Edit): + """ + mask_mode = one of: + "always" : everything is a '*' all of the time + "on_focus" : everything is a '*' only when not in focus + "off" : everything is always unmasked + mask_char = the single character that masks all other characters in the field + """ + def __init__(self, caption = "", edit_text = "", multiline = False, + align = 'left', wrap = 'space', allow_tab = False, + edit_pos = None, layout=None, mask_mode="masked",mask_char='*'): + self.mask_mode = mask_mode + if len(mask_char) > 1: + raise MaskingEditException('Masks of more than one character are not supported!') + self.mask_char = mask_char + self.__super.__init__(caption,edit_text,multiline,align,wrap,allow_tab,edit_pos,layout) + + def get_mask_mode(self): + return self.mask_mode + def set_mask_mode(self,mode): + self.mask_mode = mode + + def get_masked_text(self): + return self.mask_char*len(self.get_edit_text()) + + def render(self,(maxcol,), focus=False): + """ + Render edit widget and return canvas. Include cursor when in + focus. + """ + # If we aren't masking anything ATM, then act like an Edit. No problems. + if self.mask_mode == "off" or (self.mask_mode == 'on_focus' and focus == True): + canv = self.__super.render((maxcol,),focus) + # The cache messes this thing up, because I am totally changing what is + # displayed. + self._invalidate() + return canv + # Else, we have a slight mess to deal with... + + self._shift_view_to_cursor = not not focus # force bool + + text, attr = self.get_text() + text = text[:len(self.caption)]+self.get_masked_text() + trans = self.get_line_translation( maxcol, (text,attr) ) + canv = urwid.canvas.apply_text_layout(text, attr, trans, maxcol) + + if focus: + canv = urwid.CompositeCanvas(canv) + canv.cursor = self.get_cursor_coords((maxcol,)) + + return canv + # Tabbed interface, mostly for use in the Preferences Dialog class TabColumns(urwid.WidgetWrap): """ @@ -146,6 +202,9 @@ class ComboBoxException(Exception): # A "combo box" of SelTexts # I based this off of the code found here: # http://excess.org/urwid/browser/contrib/trunk/rbreu_menus.py +# This is a hack. It isn't without quirks, but it more or less works. +# We need to wait for changes in urwid's Canvas controls before we can actually +# make a real ComboBox. class ComboBox(urwid.WidgetWrap): """A ComboBox of text objects""" class ComboSpace(urwid.WidgetWrap): @@ -202,7 +261,7 @@ class ComboBox(urwid.WidgetWrap): #def get_size(self): - def __init__(self,label='',list=[],attr=('body','focus'),use_enter=True,show_first=0): + def __init__(self,label='',list=[],attrs=('body','editnfc'),focus_attr='focus',use_enter=True,show_first=0): """ label : bit of text that preceeds the combobox. If it is "", then ignore it @@ -214,13 +273,14 @@ class ComboBox(urwid.WidgetWrap): """ self.label = urwid.Text(label) - self.attr = attr + self.attrs = attrs + self.focus_attr = focus_attr self.list = list str,trash = self.label.get_text() self.overlay = None - - self.cbox = urwid.AttrWrap(SelText(' vvv'),attr[0],attr[1]) + #w,sensitive=True,attrs=('editbx','editnfc'),focus_attr='editfc') + self.cbox = DynWrap(SelText(' vvv'),attrs=attrs,focus_attr=focus_attr) # Unicode will kill me sooner or later. ^_^ if label != '': w = urwid.Columns([('fixed',len(str),self.label),self.cbox],dividechars=1) @@ -242,8 +302,7 @@ class ComboBox(urwid.WidgetWrap): def build_combobox(self,body,ui,row): str,trash = self.label.get_text() - self.cbox = urwid.AttrWrap(SelText([self.list[self.show_first]+' vvv']), - self.attr[0],self.attr[1]) + self.cbox = DynWrap(SelText([self.list[self.show_first]+' 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, @@ -273,13 +332,17 @@ class ComboBox(urwid.WidgetWrap): # Most obvious thing ever. :-) def selectable(self): - return True + 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_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 diff --git a/curses/netentry_curses.py b/curses/netentry_curses.py index 2eb4d8f..71f0d18 100644 --- a/curses/netentry_curses.py +++ b/curses/netentry_curses.py @@ -1,4 +1,8 @@ #!/usr/bin/env python +""" + netentry_curses -- everyone's favorite networks settings dialogs... in text + form! +""" # Copyright (C) 2009 Andrew Psaltis @@ -18,14 +22,49 @@ # MA 02110-1301, USA. import urwid -from curses_misc import Dialog,DynWrap +from curses_misc import Dialog,DynWrap,MaskingEdit,ComboBox import wicd.misc as misc +from wicd.misc import noneToString, stringToNone, noneToBlankString, to_bool + +def error(ui,parent,message): + """Shows an error dialog (or something that resembles one)""" + # /\ + # /!!\ + # /____\ + dialog = Dialog(message,[OK],('body','body','focus'),40,6) + + 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() + +daemon = None +wired = None +wireless = None +# Call this first! +def dbus_init(dbus_ifaces): + global daemon,wired,wireless + daemon = dbus_ifaces['daemon'] + 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): - def __init__(self,dbus): + def __init__(self): static_ip_t = language['use_static_ip'] ip_t = ('editcp',language['ip']+': ') netmask_t = ('editcp',language['netmask']+':') @@ -49,12 +88,12 @@ class NetEntryBase(urwid.WidgetWrap): self.gateway_edit=DynWrap(urwid.Edit(gateway_t),False) - self.use_static_dns_cb = urwid.CheckBox(use_static_dns_t, + self.static_dns_cb = urwid.CheckBox(use_static_dns_t, on_state_change=self.dns_toggle) - self.use_global_dns_cb = DynWrap(urwid.CheckBox(use_global_dns_t, + self.global_dns_cb = DynWrap(urwid.CheckBox(use_global_dns_t, on_state_change=self.dns_toggle),False,('body','editnfc'),None) - checkb_cols = urwid.Columns([self.use_static_dns_cb, - self.use_global_dns_cb]) + checkb_cols = urwid.Columns([self.static_dns_cb, + self.global_dns_cb]) self.dns_dom_edit = DynWrap(urwid.Edit(dns_dom_t) ,False) self.search_dom_edit = DynWrap(urwid.Edit(search_dom_t),False) self.dns1 = DynWrap(urwid.Edit(dns1_t) ,False) @@ -63,39 +102,73 @@ class NetEntryBase(urwid.WidgetWrap): _blank = urwid.Text('') - self._listbox = urwid.ListBox([self.static_ip_cb, - self.ip_edit, - self.netmask_edit, - _blank, - checkb_cols, - self.dns_dom_edit,self.search_dom_edit, - self.dns1,self.dns2,self.dns3 - ]) + + walker = urwid.SimpleListWalker([self.static_ip_cb, + self.ip_edit, + self.netmask_edit, + self.gateway_edit, + _blank, + checkb_cols, + self.dns_dom_edit,self.search_dom_edit, + self.dns1,self.dns2,self.dns3 + ]) + self._listbox = urwid.ListBox(walker) #self._frame = urwid.Frame(self._listbox) - self.__super.__init__(self._listbox) + self._frame = urwid.Frame(self._listbox) + self.__super.__init__(self._frame) 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) def dns_toggle(self,checkb,new_state,user_data=None): - if checkb == self.use_static_dns_cb: + if checkb == self.static_dns_cb: for w in [ self.dns_dom_edit,self.search_dom_edit, self.dns1,self.dns2,self.dns3 ]: w.set_sensitive(new_state) if not new_state: - self.use_global_dns_cb.set_state(False,do_callback=False) - self.use_global_dns_cb.set_sensitive(new_state) + self.global_dns_cb.set_state(False,do_callback=False) + self.global_dns_cb.set_sensitive(new_state) # use_global_dns_cb is DynWrapped - if checkb == self.use_global_dns_cb.get_w(): + if checkb == self.global_dns_cb.get_w(): for w in [ self.dns_dom_edit,self.search_dom_edit, self.dns1,self.dns2,self.dns3 ]: w.set_sensitive(not new_state) - # We need a network ID for this, and I am not sure how to get it yet. - # TODO: Implement this - #def load_settings(self): + # 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(): + 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())) + else: + self.set_net_prop("ip", '') + 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(): + 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('use_static_dns', True) + self.set_net_prop('use_global_dns', True) + else: + self.set_net_prop('use_static_dns', False) + self.set_net_prop('use_global_dns', False) + self.set_net_prop('dns_domain', '') + self.set_net_prop("search_domain", '') + self.set_net_prop("dns1", '') + self.set_net_prop("dns2", '') + self.set_net_prop("dns3", '') def run(self,ui,dim,display): width,height = ui.get_cols_rows() @@ -122,3 +195,101 @@ class NetEntryBase(urwid.WidgetWrap): # return False #if self.OK_PRESSED or 'meta enter' in keys: # return True + +######################################## + +class WirelessNetEntry(NetEntryBase): + def __init__(self,networkID): + NetEntryBase.__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._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.encrypt_types = misc.LoadEncryptionMethods() + self.set_values() + + def encryption_toggle(self,chkbox,new_state,user_data=None): + self.encryption_combo.set_sensitive(new_state) + + def set_values(self): + """ Set the various network settings to the right values. """ + networkID = self.networkID + self.ip_edit.set_edit_text(self.format_entry(networkID,"ip")) + self.netmask_edit.set_edit_text(self.format_entry(networkID,"netmask")) + self.gateway_edit.set_edit_text(self.format_entry(networkID,"gateway")) + + self.global_dns_cb.set_state(bool(wireless.GetWirelessProperty(networkID, + 'use_global_dns'))) + self.static_dns_cb.set_state(bool(wireless.GetWirelessProperty(networkID, + 'use_static_dns'))) + + self.dns1.set_edit_text(self.format_entry(networkID, "dns1")) + self.dns2.set_edit_text(self.format_entry(networkID, "dns2")) + self.dns3.set_edit_text(self.format_entry(networkID, "dns3")) + self.dns_dom_edit.set_edit_text(self.format_entry(networkID, "dns_domain")) + self.search_dom_edit.set_edit_text(self.format_entry(networkID, "search_domain")) + + + #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'))) + + activeID = -1 # Set the menu to this item when we are done + user_enctype = wireless.GetWirelessProperty(networkID, "enctype") + for x, enc_type in enumerate(self.encrypt_types): + 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() + + def set_net_prop(self, option, value): + """ Sets the given option to the given value for this network. """ + wireless.SetWirelessProperty(self.networkID, option, value) + + def format_entry(self, networkid, label): + """ Helper method for fetching/formatting wireless properties. """ + return noneToBlankString(wireless.GetWirelessProperty(networkid, label)) + + def run(self,ui,dim,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 + , ('fixed top',1), height-3) + self.encryption_combo.build_combobox(overlay,ui,14) + + keys = True + while True: + if keys: + ui.draw_screen(dim, overlay.render(dim, True)) + keys = ui.get_input() + + 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 diff --git a/curses/prefs_curses.py b/curses/prefs_curses.py index 8ba6461..4f19361 100755 --- a/curses/prefs_curses.py +++ b/curses/prefs_curses.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (C) 2008-9 Andrew Psaltis +# Copyright (C) 2008-2009 Andrew Psaltis # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 7133dd0..fc483aa 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -1,13 +1,13 @@ #!/usr/bin/env python -""" wicd-curses -- a (curses-based) console interface to wicd +""" wicd-curses. (curses/urwid-based) console interface to wicd Provides the a console UI for wicd, so that people with broken X servers can -at least get a network connection. Or those who don't like using X. :-) +at least get a network connection. Or those who don't like using X. ;-) """ -# Copyright (C) 2008-9 Andrew Psaltis +# Copyright (C) 2008-2009 Andrew Psaltis # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -55,10 +55,10 @@ from time import sleep # Curses UIs for other stuff from curses_misc import SelText,ComboBox,Dialog from prefs_curses import PrefsDialog -from netentry_curses import NetEntryBase +import netentry_curses +from netentry_curses import WirelessNetEntry language = misc.get_language_list_gui() -# Whew. Now on to more interesting stuff: ######################################## ##### SUPPORT CLASSES @@ -582,8 +582,17 @@ class appGUI(): self.frame.keypress( self.size, k ) if "C" in keys: - self.netentry = NetEntryBase(dbusmanager.get_dbus_ifaces()) - self.netentry.run(ui,self.size,self.frame) + 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() @@ -678,7 +687,7 @@ def setup_dbus(force=True): dbusmanager.connect_to_dbus() except DBusException: # I may need to be a little more verbose here. - # Suggestions as to what should go here + # Suggestions as to what should go here, please? print "Can't connect to the daemon. Are you sure it is running?" print "Please check the wicd log for error messages." #raise @@ -690,6 +699,8 @@ def setup_dbus(force=True): wired = dbus_ifaces['wired'] DBUS_AVAIL = True + + netentry_curses.dbus_init(dbus_ifaces) return True setup_dbus() From d1846cb6279835c1281ca706d0b127cbd76b7184 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Fri, 9 Jan 2009 20:42:12 -0500 Subject: [PATCH 30/50] curses/curses_misc.py: Refactored some ComboBox internals Renamed show_first to focus in ComboBox Added callback support curses/netentry_curses.py: Renamed NetEntryBase to AdvancedSettingsDialog, and WirelessNetEntry to WirelessSettingsDialog The "WirelessSettingsDialog" is complete. :-) Raise it by pressing "C" on a wireless network. Much of the code was taken from netentry.py. The buttons aren't pretty like they are in the Preferences Dialog, but they are fully functional. curses/prefs_curses.py: Refactored to accommodate the ComboBox changes Added a warning about changing backends curses/wicd-curses.py: Refactored to accommodate changes to the rest of the program Added a constantly displayed message saying how to exit the program, other than ctrl+c curses/TODO: Removed a bunch of stuff that is already implemented, added some stuff that needs to be implemented curses/README: Added/clearified some things --- curses/README | 25 ++--- curses/TODO | 17 +--- curses/curses_misc.py | 38 ++++---- curses/netentry_curses.py | 188 +++++++++++++++++++++++++++++--------- curses/prefs_curses.py | 10 +- curses/wicd-curses.py | 15 ++- in/man=wicd-curses.8.in | 12 ++- 7 files changed, 210 insertions(+), 95 deletions(-) diff --git a/curses/README b/curses/README index d443845..bf4aebd 100644 --- a/curses/README +++ b/curses/README @@ -2,30 +2,33 @@ 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 -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..56eb346 100644 --- a/curses/TODO +++ b/curses/TODO @@ -1,17 +1,10 @@ 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 "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 06bfb77..dfbfd84 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,16 +332,18 @@ 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() diff --git a/curses/netentry_curses.py b/curses/netentry_curses.py index 71f0d18..79f3703 100644 --- a/curses/netentry_curses.py +++ b/curses/netentry_curses.py @@ -31,13 +31,13 @@ def error(ui,parent,message): # /\ # /!!\ # /____\ - dialog = Dialog(message,[OK],('body','body','focus'),40,6) + dialog = Dialog([('important','ERROR: '),message],['OK'],('body','body','focus'),40,6,parent) keys = True dim = ui.get_cols_rows() while True: if keys: - ui.draw_screen(dim, about.render(dim, True)) + ui.draw_screen(dim, dialog.render(dim, True)) keys = ui.get_input() if "window resize" in keys: @@ -61,10 +61,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 +81,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 +105,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 +122,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 +157,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 +166,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 +216,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 +267,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 +277,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,15 +299,85 @@ 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, 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']) + 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 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 , ('fixed top',1), height-3) self.encryption_combo.build_combobox(overlay,ui,14) + #self.change_encrypt_method() + #self._w.body.body.append(self.pile_encrypt) keys = True while True: @@ -281,15 +385,15 @@ class WirelessNetEntry(NetEntryBase): ui.draw_screen(dim, overlay.render(dim, True)) keys = ui.get_input() + for k in keys: + #Send key to underlying widget: + 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: + 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..c771798 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()) diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index fc483aa..cedecc2 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -56,7 +56,7 @@ from time import sleep from curses_misc import SelText,ComboBox,Dialog from prefs_curses import PrefsDialog import netentry_curses -from netentry_curses import WirelessNetEntry +from netentry_curses import WirelessSettingsDialog language = misc.get_language_list_gui() @@ -303,7 +303,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) @@ -503,8 +503,9 @@ 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 @@ -585,12 +586,10 @@ class appGUI(): focus = self.thePile.get_focus() if focus == self.wiredCB: pass - #self.connect("wired",0) else: - # wless list only other option + # wireless list only other option wid,pos = self.thePile.get_focus().get_focus() - WirelessNetEntry(pos).run(ui,self.size,self.frame) - #self.connect("wireless",pos) + WirelessSettingsDialog(pos).run(ui,self.size,self.frame) #self.netentry = NetEntryBase(dbusmanager.get_dbus_ifaces()) #self.netentry.run(ui,self.size,self.frame) diff --git a/in/man=wicd-curses.8.in b/in/man=wicd-curses.8.in index 670b37d..5913828 100644 --- a/in/man=wicd-curses.8.in +++ b/in/man=wicd-curses.8.in @@ -39,11 +39,19 @@ The following is a work in progress and might not be fully functional as of yet. .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 I +Bring up hidden network scanning dialog +.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 From 84cb49a6fc9ca5aac15c8539d88421c7b156b382 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Sun, 11 Jan 2009 13:05:01 -0500 Subject: [PATCH 31/50] curses/prefs_curses.py: Finished refactoring to accommodate the ComboBox changes curses/wicd-curses.py: Moved some of the keybinding code around in/other=WHEREAREMYFILES.in: ADDED. File telling the user where the wicd config files are. Usually symlinked to ~/.wicd/WHEREAREMYFILES and installed to the documentation directory in/scripts=wicd-client.in: Make ~/.wicd and link WHEREAREMYFILES if it has not been done so already. Start wicd-curses if there is no X server on this console (determined by the presence of $DISPLAY), and add a file detailing this man/wicd-client.1: Added note about wicd-client starting wicd-curses setup.py: Install WHEREAREMYFILES along with the rest of the documentation --- curses/prefs_curses.py | 4 ++-- curses/wicd-curses.py | 12 +++++----- in/other=WHEREAREMYFILES.in | 14 ++++++++++++ in/scripts=wicd-client.in | 45 +++++++++++++++++++++++++++++++++++++ man/wicd-client.1 | 2 ++ setup.py | 5 +++-- 6 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 in/other=WHEREAREMYFILES.in diff --git a/curses/prefs_curses.py b/curses/prefs_curses.py index c771798..49737e0 100755 --- a/curses/prefs_curses.py +++ b/curses/prefs_curses.py @@ -345,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()) @@ -357,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(): diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index cedecc2..10eaecf 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -576,12 +576,6 @@ class appGUI(): self.update_ui() if "A" in keys: about_dialog(self.frame) - for k in keys: - 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: @@ -593,6 +587,12 @@ class appGUI(): #self.netentry = NetEntryBase(dbusmanager.get_dbus_ifaces()) #self.netentry.run(ui,self.size,self.frame) + for k in keys: + if k == "window resize": + self.size = ui.get_cols_rows() + continue + self.frame.keypress( self.size, k ) + if " " in keys: focus = self.thePile.get_focus() if focus == self.wiredCB: 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< Date: Sun, 11 Jan 2009 19:40:29 -0500 Subject: [PATCH 32/50] Progress is being made, apparently curses/curses_misc.py: Made Dialog a bit more generic with the new Dialog2, also supports mouse events. Included TextDialog and InputDialog as subclasses of Dialog2 curses/netentry_curses.py: Changed error() to support Dialog2 Added support for mouse events curses/prefs_curses.py: Added support for mouse events curses/wicd-curses.py: Added support for wicd's hidden wireless-network functionality (Really) finished refactoring for the changes in ComboBox Made some transitions a bit more immediate by calling update_ui() manually Refactored to about_dialog to support Dialog2 Added support for mouse events (clicking to select, mostly) Added support for retaining current list netlist focus throughout screen updates (Hopefully) Added support for handling an instance of 0 available wireless networks in/man=wicd-curses.8.in: Hidden network support is fully functional man/wicd-client.1: Added a word. (You'll live.) setup.py: From last commit: Added the python "shebang" to the top of the file --- curses/README | 1 + curses/TODO | 1 - curses/curses_misc.py | 181 ++++++++++++++++++++++++-------------- curses/netentry_curses.py | 39 ++++---- curses/prefs_curses.py | 5 ++ curses/wicd-curses.py | 121 +++++++++++++++++-------- in/man=wicd-curses.8.in | 6 +- man/wicd-client.1 | 2 +- 8 files changed, 228 insertions(+), 128 deletions(-) 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 From 2685a4977997d6ec8a160e55e0773620bd16bbba Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Tue, 13 Jan 2009 18:13:24 -0500 Subject: [PATCH 33/50] curses/curses_misc.py: Modified TextDialog to use a listbox as opposed to one long text box Aligned the header on the right in Dialog2 by default curses/wicd-curses.py: Removed the traceback if the user presses ctrl+c Refactored about_dialog to support the modified TextDialog Added a help dialog. Raise it with "H" Refactored some code in the appGUI constructor so that I can recycle update_netlist() curses/TODO, curses/README, in/man=wicd-curses.8.in: Help dialog now active in/man=wicd-curses.8.in: Removed redundant scipt selector command --- curses/README | 3 +- curses/TODO | 1 - curses/curses_misc.py | 11 +++-- curses/wicd-curses.py | 94 ++++++++++++++++++++++++----------------- in/man=wicd-curses.8.in | 9 ++-- 5 files changed, 66 insertions(+), 52 deletions(-) diff --git a/curses/README b/curses/README index 3faa1c8..01cec1f 100644 --- a/curses/README +++ b/curses/README @@ -25,7 +25,8 @@ 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 +I : Raise the "Scan for hidden networks" dialog +H : Raise help 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 6c81304..22a63c9 100644 --- a/curses/TODO +++ b/curses/TODO @@ -5,5 +5,4 @@ Things to do (in no particular order): * Make keystrokes customizable * Make color schemes customizable * 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 f26d4c6..e79a74c 100644 --- a/curses/curses_misc.py +++ b/curses/curses_misc.py @@ -370,7 +370,7 @@ class Dialog2(urwid.WidgetWrap): self.frame = urwid.Frame( body, focus_part='footer') if text is not None: - self.frame.header = urwid.Pile( [urwid.Text(text), + self.frame.header = urwid.Pile( [urwid.Text(text,align='right'), urwid.Divider()] ) w = self.frame self.view = w @@ -428,13 +428,12 @@ class Dialog2(urwid.WidgetWrap): def unhandled_key(self, size, key): pass +# Simple dialog with text in it and "OK" class TextDialog(Dialog2): - def __init__(self, text, height, width, header=None): + def __init__(self, text, height, width, header=None,align='left'): 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)] + for line in text: + l.append( urwid.Text( line,align=align)) body = urwid.ListBox(l) body = urwid.AttrWrap(body, 'body') diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 637b34b..53c896f 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -79,7 +79,7 @@ class wrap_exceptions: loop.quit() ui.stop() print "\nTerminated by user." - raise + #raise except DBusException: gobject.source_remove(redraw_tag) # Quit the loop @@ -211,23 +211,39 @@ def about_dialog(body): # The ASCII Art "Wicd" was made from the "smslant" font on one of those # online ASCII big text generators. theText = [ -('green'," /// \\\\\\")," _ ___ __\n", -('green'," /// \\\\\\")," | | /| / (_)______/ /\n", -('green'," /// \\\\\\")," | |/ |/ / / __/ _ / \n", -('green',"/|| // \\\\ ||\\")," |__/|__/_/\__/\_,_/ \n", -('green',"||| ||"),"(|^|)",('green',"|| |||"), -" ($VERSION) \n".replace("$VERSION",daemon.Hello()), +[('green'," /// \\\\\\")," _ ___ __"], +[('green'," /// \\\\\\")," | | /| / (_)______/ /"], +[('green'," /// \\\\\\")," | |/ |/ / / __/ _ / "], +[('green',"/|| // \\\\ ||\\")," |__/|__/_/\__/\_,_/ "], +[('green',"||| ||"),"(|^|)",('green',"|| |||"), +" ($VERSION) ".replace("$VERSION",daemon.Hello())], -('green',"\\|| \\\\")," |+| ",('green',"// ||/ \n"), -('green'," \\\\\\")," |+| ",('green',"///")," http://wicd.net \n", -('green'," \\\\\\")," |+| ",('green',"///")," Brought to you by:\n", -('green'," \\\\\\")," |+| ",('green',"///")," Adam Blackburn (wicd)\n", -" ___|+|___ Dan O'Reilly (wicd)\n", -" |---------| Andrew Psaltis (this ui)\n", -"---------------------------------------------------"] - about = TextDialog(theText,55,14) +[('green',"\\|| \\\\")," |+| ",('green',"// ||/ ")], +[('green'," \\\\\\")," |+| ",('green',"///")," http://wicd.net"], +[('green'," \\\\\\")," |+| ",('green',"///")," Brought to you by:"], +[('green'," \\\\\\")," |+| ",('green',"///")," Adam Blackburn (wicd)"], +" ___|+|___ Dan O'Reilly (wicd)", +" |---------| Andrew Psaltis (this ui)", +"-----------------------------------------------------"] + about = TextDialog(theText,16,55,header=('header','About Wicd')) about.run(ui,body) +def help_dialog(body): + theText = [ +"For more detailed help, consult the wicd-curses(8) man page.", +"", "All controls are case sensitive", +[('bold','H')," Display this help dialog"], +[('bold','enter')," Connect to selected network"], +[('bold','D')," Disconnect from all networks"], +[('bold','ESC')," Stop a network connection in progress"], +[('bold','F5')," or ", ('bold','R')," Refresh network list"], +[('bold','P')," Prefrences dialog"], +[('bold','I')," Scan for hidden networks"], +[('bold','S')," Select scripts"] + ] + help = TextDialog(theText,15,62,header=('header',"Wicd-Curses Help")) + help.run(ui,body) + ######################################## ##### URWID SUPPORT CLASSES ######################################## @@ -335,6 +351,8 @@ class appGUI(): 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' + self.WIRED_IDX = 1 + self.WLESS_IDX = 3 #wrap1 = urwid.AttrWrap(txt, 'black') #fill = urwid.Filler(txt) @@ -345,9 +363,16 @@ class appGUI(): #if wireless.GetNumberOfNetworks() == 0: # wireless.Scan() - wiredL,wlessL = gen_network_list() + self.focusloc = (1,0) + + # These are empty to make sure that things go my way. + wiredL,wlessL = [],[]# = gen_network_list() + self.frame = None + self.wiredCB = urwid.Filler(ComboBox(list=wiredL,use_enter=False)) self.wlessLB = urwid.ListBox(wlessL) + self.update_netlist(force_check=True,firstrun=True) + # Stuff I used to simulate large lists #spam = SelText('spam') #spamL = [ urwid.AttrWrap( w, None, 'focus' ) for w in [spam,spam,spam, @@ -357,15 +382,6 @@ class appGUI(): # spam,spam,spam,spam] ] #self.spamLB = urwid.ListBox(spamL) - # Choose whether to show the wired part of the interface, if a cable - # is plugged in, or the - if daemon.GetAlwaysShowWiredInterface() or wired.CheckPluggedIn(): - self.thePile = urwid.Pile([('fixed',1,self.wiredH), - ('fixed',1,self.wiredCB), - ('fixed',1,self.wlessH), - self.wlessLB] ) - else: - self.thePile = urwid.Pile([('fixed',1,self.wlessH),self.wlessLB] ) self.footer1 = urwid.AttrWrap(urwid.Text("Something important will eventually go here."),'body') self.footer2 = urwid.AttrWrap(urwid.Text("If you are seeing this, then something has gone wrong!"),'important') self.footerList = urwid.ListBox([self.footer1,self.footer2]) @@ -384,7 +400,6 @@ class appGUI(): self.screen_locked = False #self.always_show_wired = daemon.GetAlwaysShowWiredInterface() - self.focusloc = (1,0) self.pref = None @@ -400,8 +415,6 @@ class appGUI(): def unlock_screen(self): 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() @@ -420,9 +433,9 @@ class appGUI(): # This might need to be cleaned up later. if self.thePile.get_focus() is self.wiredCB: - wlessorwired = 1 + wlessorwired = self.WIRED_IDX else : - wlessorwired = 3 + wlessorwired = self.WLESS_IDX if self.thePile.get_focus() == self.no_wlan: where = 0 elif self.thePile.get_focus() == self.wiredCB: @@ -436,21 +449,24 @@ class appGUI(): # 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() + def update_netlist(self,state=None, x=None, force_check=False,firstrun=False): + if not firstrun: + self.update_focusloc() """ Updates the overall network list.""" if not state: state, x = daemon.GetConnectionStatus() - if self.prev_state != state or force_check: + if force_check or self.prev_state != state: wiredL,wlessL = gen_network_list() #self.wiredCB = urwid.Filler(ComboBox(wiredL,self.frame,ui,3, # use_enter=False)) self.wiredCB.get_body().set_list(wiredL) self.wiredCB.get_body().build_combobox(self.frame,ui,3) if len(wlessL) != 0: - self.wlessLB.body = urwid.SimpleListWalker(wlessL) + self.wlessLB = urwid.ListBox(wlessL) + #self.wlessLB.body = urwid.SimpleListWalker(wlessL) else: - self.wlessLB.body = urwid.SimpleListWalker([self.no_wlan]) + self.wlessLB = self.no_wlan + #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), @@ -460,7 +476,7 @@ class appGUI(): #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: + if self.focusloc[0] == self.WIRED_IDX: self.thePile.get_focus().get_body().set_focus(self.focusloc[1]) else: self.thePile.get_focus().set_focus(self.focusloc[1]) @@ -631,7 +647,8 @@ class appGUI(): #self.netentry.run(ui,self.size,self.frame) if "I" in keys: self.raise_hidden_network_dialog() - + if "H" in keys: + help_dialog(self.frame) for k in keys: if urwid.is_mouse_event(k): event, button, col, row = k @@ -700,7 +717,8 @@ def main(): # Simple colors around text ('green','dark green','default'), ('blue','dark blue','default'), - ('red','dark red','default')]) + ('red','dark red','default'), + ('bold','default','default','bold')]) # This is a wrapper around a function that calls another a function that is a # wrapper around a infinite loop. Fun. ui.run_wrapper(run) diff --git a/in/man=wicd-curses.8.in b/in/man=wicd-curses.8.in index 7d81ba9..090b042 100644 --- a/in/man=wicd-curses.8.in +++ b/in/man=wicd-curses.8.in @@ -36,6 +36,9 @@ Bring up the preferences controller .TP .BR I Bring up hidden network scanning dialog +.TP +.BR H +Bring up a rather simplistic help dialog. Of course, it mentions this man page first. :-) .PP The following is a work in progress and might not be fully functional as of yet. .TP @@ -46,12 +49,6 @@ 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 From 6e9eb1cd65a73154a52ee1ec8e0035df64d44093 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Thu, 15 Jan 2009 21:46:35 -0500 Subject: [PATCH 34/50] curses/wicd-curses.py: ListBox focus-maintaining code completely debugged --- curses/wicd-curses.py | 64 +++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 53c896f..212a178 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -104,6 +104,7 @@ class wrap_exceptions: # Zap the screen ui.stop() # Print out standard notification: + print "\nEXCEPTION!" print "Please report this to the maintainer and/or file a bug report with the backtrace below:" print redraw_tag @@ -400,7 +401,6 @@ class appGUI(): self.screen_locked = False #self.always_show_wired = daemon.GetAlwaysShowWiredInterface() - self.pref = None self.update_status() @@ -432,24 +432,24 @@ class appGUI(): # 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: + #self.set_status(str(self.frame.get_body().get_focus())+ ' '+ str(self.wiredCB)) + if self.thePile.get_focus() == self.wiredCB: wlessorwired = self.WIRED_IDX - else : - wlessorwired = self.WLESS_IDX - 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] - + else:#self.thePile.get_focus() == self.wlessLB : + wlessorwired = self.WLESS_IDX + if self.wlessLB == self.no_wlan: + where = None + else: + where = self.frame.get_body().get_focus().get_focus()[1] + #where = self.wlessLB.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,firstrun=False): + # Run focus-collecting code if we are not running this for the first time if not firstrun: self.update_focusloc() """ Updates the overall network list.""" @@ -462,31 +462,42 @@ class appGUI(): self.wiredCB.get_body().set_list(wiredL) self.wiredCB.get_body().build_combobox(self.frame,ui,3) if len(wlessL) != 0: - self.wlessLB = urwid.ListBox(wlessL) - #self.wlessLB.body = urwid.SimpleListWalker(wlessL) + if self.wlessLB == self.no_wlan: + self.wlessLB = urwid.ListBox(wlessL) + else: + self.wlessLB.body = urwid.SimpleListWalker(wlessL) else: self.wlessLB = self.no_wlan - #self.wlessLB.body = urwid.SimpleListWalker([self.no_wlan]) if daemon.GetAlwaysShowWiredInterface() or wired.CheckPluggedIn(): #if daemon.GetAlwaysShowWiredInterface(): + #if firstrun: self.thePile = urwid.Pile([('fixed',1,self.wiredH), ('fixed',1,self.wiredCB), ('fixed',1,self.wlessH), self.wlessLB] ) + if not firstrun: + self.frame.body = self.thePile #self.focusloc = (self.thePile.get_focus(), # self.thePile.get_focus().get_focus()[1]) self.thePile.set_focus(self.focusloc[0]) if self.focusloc[0] == self.WIRED_IDX: self.thePile.get_focus().get_body().set_focus(self.focusloc[1]) else: - self.thePile.get_focus().set_focus(self.focusloc[1]) + if self.wlessLB is not self.no_wlan: + self.thePile.get_focus().set_focus(self.focusloc[1]) + else: + self.thePile.set_focus(self.wiredCB) 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]) + if not firstrun: + self.frame.body = self.thePile + #if self.focusloc[0] == self.wlessLB: + self.wlessLB.set_focus(self.focusloc[1]) + #self.thePile.get_focus().set_focus(self.focusloc[1]) #self.always_show_wired = not self.always_show_wired self.prev_state = state + if not firstrun: + self.update_ui() # Update the footer/status bar @wrap_exceptions() @@ -529,6 +540,7 @@ class appGUI(): return True else: self.set_status(language['not_connected']) + self.update_ui() return True @@ -542,6 +554,8 @@ class appGUI(): # something, and we aren't connecting to something, return False # immediately. if from_idle and not self.connecting: + self.update_netlist() + self.update_ui() return False toAppend = '' # If we are connecting and being called from the idle function, spin @@ -558,12 +572,15 @@ class appGUI(): # Not necessary in the end, but I will be using footer1 for stuff in # the long run, so I might as well put something there. incr = 0 + @wrap_exceptions() def idle_incr(self): - theText = "" + theText = " " + #if self.special != None: + # theText += self.special if self.connecting: - theText = "-- Connecting -- Press ESC to cancel " + 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.footer1 = urwid.Text(str(self.incr) + theText+quit_note,wrap='clip') self.incr+=1 return True @@ -612,8 +629,9 @@ class appGUI(): # Guess what! I actually need to put this here, else I'll have tons of # references to self.frame lying around. ^_^ if "enter" in keys: - focus = self.thePile.get_focus() - if focus is self.wiredCB: + focus = self.frame.body.get_focus() + if focus == self.wiredCB: + self.special = focus self.connect("wired",0) else: # wless list only other option From be30004f0f59bb4ca7cf14a0879a1600ef1d4808 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Sat, 17 Jan 2009 15:13:53 -0500 Subject: [PATCH 35/50] Wired network control support is now more-or-less complete curses/curses_misc.py: Made set_focus() actually set the focus Added ability for combobox to rebuild itself curses/netentry_curses: Added WiredSettingsDialog. Sometimes, the "Defaultness" of the network takes a little while to show up in the dialog. Don't know why yet. Reorganized some of the AdvancedSettingsDialog code curses/wicd-curses.py: Reactivated WiredComboBox Added support for WiredSettingsDialog Added ability to create and delete wired network profiles Fixed bug where the program could crash on the end of scanning networks if timing is slightly off Display the screen locker immediately after initiating a scan curses/README,TODO: Wired network support is complete in/man=wicd-curses.8.in: Wired network support is now complete Added revision information to the bottom of the man page --- curses/README | 4 +- curses/TODO | 1 - curses/curses_misc.py | 15 +++++- curses/netentry_curses.py | 99 ++++++++++++++++++++++++++++++------- curses/wicd-curses.py | 95 +++++++++++++++++++++-------------- in/man=wicd-curses.8.in | 10 ++-- in/other=WHEREAREMYFILES.in | 10 ++-- 7 files changed, 167 insertions(+), 67 deletions(-) diff --git a/curses/README b/curses/README index 01cec1f..cfda201 100644 --- a/curses/README +++ b/curses/README @@ -22,11 +22,11 @@ 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 (only works for - wireless at the moment) +C : Display network configuration for selected network A : Display "About" dialog I : Raise the "Scan for hidden networks" dialog H : Raise help dialog +delete : Delete selected wired network profile (from the wired ComboBox) 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 22a63c9..129fe2f 100644 --- a/curses/TODO +++ b/curses/TODO @@ -1,6 +1,5 @@ Things to do (in no particular order): -* Make a network config dialog for wired interfaces * Implement a keyhandler function for the overall frame * Make keystrokes customizable * Make color schemes customizable diff --git a/curses/curses_misc.py b/curses/curses_misc.py index e79a74c..9cd0346 100644 --- a/curses/curses_misc.py +++ b/curses/curses_misc.py @@ -295,17 +295,28 @@ class ComboBox(urwid.WidgetWrap): self.use_enter = use_enter # The Focus self.focus = focus + # The callback and friends self.callback = callback self.user_args = user_args + + # Widget references to simplify some things + self.body = None + self.ui = None + self.row = None def set_list(self,list): self.list = list def set_focus(self,index): self.focus = index + self.cbox.set_w(SelText(self.list[index]+' vvv')) + def rebuild_combobox(self): + self.build_combobox(self.body,self.ui,self.row) def build_combobox(self,body,ui,row): str,trash = self.label.get_text() + + 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) @@ -319,6 +330,7 @@ class ComboBox(urwid.WidgetWrap): self.set_w(w) self.body = body self.ui = ui + self.row = row # If we press space or enter, be a combo box! def keypress(self,size,key): @@ -331,7 +343,8 @@ class ComboBox(urwid.WidgetWrap): raise ComboBoxException('ComboBox must be built before use!') retval = self.overlay.show(self.ui,self.body) if retval != None: - self.cbox.set_w(SelText(retval+' vvv')) + self.set_focus(self.list.index(retval)) + #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) diff --git a/curses/netentry_curses.py b/curses/netentry_curses.py index 09fa7f8..4274625 100644 --- a/curses/netentry_curses.py +++ b/curses/netentry_curses.py @@ -136,7 +136,7 @@ class AdvancedSettingsDialog(urwid.WidgetWrap): self.global_dns_cb.set_sensitive(new_state) # use_global_dns_cb is DynWrapped if checkb == self.global_dns_cb.get_w(): - for w in [ self.dns_dom_edit,self.search_dom_edit, + for w in [self.dns_dom_edit,self.search_dom_edit, self.dns1,self.dns2,self.dns3 ]: w.set_sensitive(not new_state) @@ -174,31 +174,93 @@ class AdvancedSettingsDialog(urwid.WidgetWrap): self.set_net_prop("dns2", '') self.set_net_prop("dns3", '') + def prerun(self,ui,dim,display): + pass 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.prerun(ui,dim,display) #self.ready_comboboxes(ui,overlay) 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(): + return True + if self.CANCEL_PRESSED: + return False + +class WiredSettingsDialog(AdvancedSettingsDialog): + def __init__(self,name): + global wired, daemon + AdvancedSettingsDialog.__init__(self) + self.set_default = urwid.CheckBox(language['default_wired']) + #self.cur_default = + # Add widgets to listbox + self._w.body.body.append(self.set_default) + self._w.body.body.append(self.button_cols) + + self.prof_name = name + self._w.header = urwid.Text( ('header',">Configuring preferences for wired profile \"%s\"" % self.prof_name),align='right' ) + + self.set_values() + def set_net_prop(self,option,value): + wired.SetWiredProperty(option,value) + def set_values(self): + self.ip_edit.set_edit_text(self.format_entry("ip")) + self.netmask_edit.set_edit_text(self.format_entry("netmask")) + self.gateway_edit.set_edit_text(self.format_entry("gateway")) + + self.global_dns_cb.set_state(bool(wired.GetWiredProperty('use_global_dns'))) + self.static_dns_cb.set_state(bool(wired.GetWiredProperty('use_static_dns'))) + + self.dns1.set_edit_text(self.format_entry( "dns1")) + self.dns2.set_edit_text(self.format_entry( "dns2")) + self.dns3.set_edit_text(self.format_entry( "dns3")) + self.dns_dom_edit.set_edit_text(self.format_entry("dns_domain")) + self.search_dom_edit.set_edit_text(self.format_entry("search_domain")) + + self.set_default.set_state(to_bool(wired.GetWiredProperty("default"))) + + def save_settings(self): + AdvancedSettingsDialog.save_settings(self) + if self.set_default.get_state(): + wired.UnsetWiredDefault() + print self.set_default.get_state() + if self.set_default.get_state(): + bool = True + else: + bool = False + wired.SetWiredProperty("default",bool) + wired.SaveWiredNetworkProfile(self.prof_name) + return True + + def format_entry(self, label): + """ Helper method to fetch and format wired properties. """ + return noneToBlankString(wired.GetWiredProperty(label)) + def prerun(self,ui,dim,display): + pass ######################################## @@ -257,6 +319,13 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): self.global_settings_chkbox.set_state(bool(wireless.GetWirelessProperty(networkID ,'use_settings_globally'))) + # 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() activeID = -1 # Set the menu to this item when we are done user_enctype = wireless.GetWirelessProperty(networkID, "enctype") for x, enc_type in enumerate(self.encrypt_types): @@ -270,12 +339,6 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): #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. """ @@ -363,7 +426,7 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): self.overlay = urwid.Overlay(self, display, ('fixed left', 0),width , ('fixed top',1), height-3) self.encryption_combo.build_combobox(self.overlay,ui,14) - #self.change_encrypt_method() + self.change_encrypt_method() #self._w.body.body.append(self.pile_encrypt) keys = True diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 212a178..279aa32 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -56,7 +56,7 @@ from time import sleep from curses_misc import SelText,ComboBox,TextDialog,InputDialog from prefs_curses import PrefsDialog import netentry_curses -from netentry_curses import WirelessSettingsDialog, error +from netentry_curses import WirelessSettingsDialog, WiredSettingsDialog,error language = misc.get_language_list_gui() @@ -181,10 +181,10 @@ def gen_network_list(): id = 0 wiredL = [] - is_active = wireless.GetWirelessIP('') == None and wired.GetWiredIP('') != None + #is_active = wireless.GetWirelessIP('') == None and wired.GetWiredIP('') != None # This one makes a list of strings to put in a combo box. - for profile in wired.GetWiredProfileList(): - theString = '%4s %25s' % (id, profile) + #for profile in wired.GetWiredProfileList(): + #theString = '%4s %25s' % (id, profile) #### THIS IS wired.blah() in experimental #print config.GetLastUsedWiredNetwork() # Tag if no wireless IP present, and wired one is @@ -195,9 +195,9 @@ def gen_network_list(): # 'connected focus')) #else: #wiredL.append(urwid.AttrWrap(SelText(theString),'body','focus')) - wiredL.append(theString) - id+=1 - + #wiredL.append(theString) + #id+=1 + wiredL = wired.GetWiredProfileList() wlessL = [] # This one makes a list of NetLabels for network_id in range(0, wireless.GetNumberOfNetworks()): @@ -298,10 +298,16 @@ class WiredComboBox(ComboBox): """ list : the list of wired network profiles. The rest is self-explanitory. """ - def init(self,list): + def __init__(self,list): + self.ADD_PROFILE = '---Add a new profile---' + self.__super.__init__(use_enter=False) + self.set_list(list) + #self.set_focus(self.theList.index(wired.GetDefaultProfile())) + + def set_list(self,list): self.theList = list - id = 0 - wiredL = [] + id=0 + wiredL=[] is_active = wireless.GetWirelessIP('') == None and wired.GetWiredIP('') != None for profile in list: theString = '%4s %25s' % (id, profile) @@ -317,11 +323,37 @@ class WiredComboBox(ComboBox): # wiredL.append(urwid.AttrWrap(SelText(theString),'body','focus')) wiredL.append(theString) id+=1 - self.__super.__init__(list=wiredL,use_enter=False) - self.set_focus(theList.index(wired.GetDefaultWiredProfile())) + wiredL.append(self.ADD_PROFILE) + if is_active: + self.attrs = ('connected','editnfc') + self.focus_attr = 'connected focus' + else : + self.attrs = ('body','editnfc') + self.focus_attr = 'focus' + self.list = wiredL + if self.theList != []: + wired.ReadWiredNetworkProfile(self.get_selected_profile()) def keypress(self,size,key): - self.__super.keypress(size,key) + prev_focus = self.get_focus()[1] + key = self.__super.keypress(size,key) + if self.get_focus()[1] == len(self.list)-1: + dialog = InputDialog(('header',"Add new wired profile"),7,30) + + exitcode,name = dialog.run(ui,self.body) + if exitcode == 0: + wired.CreateWiredNetworkProfile(name,False) + self.set_list(wired.GetWiredProfileList()) + self.rebuild_combobox() + self.set_focus(prev_focus) + self.overlay._listbox.set_focus(prev_focus) + else: + wired.ReadWiredNetworkProfile(self.get_selected_profile()) + if key == 'delete': + wired.DeleteWiredNetworkProfile(self.get_selected_profile()) + self.set_list(wired.GetWiredProfileList()) + self.rebuild_combobox() + return key #if key == 'C': # Configure the network # pass @@ -332,11 +364,9 @@ class WiredComboBox(ComboBox): # self.connect() #return key - def connect(self): - wired.ConnectWired() def get_selected_profile(self): """Get the selected wired profile""" - return self.theList[self._w.get_selected()[1]] + return self.theList[self.get_focus()[1]] ######################################## ##### APPLICATION INTERFACE CLASS @@ -370,7 +400,7 @@ class appGUI(): wiredL,wlessL = [],[]# = gen_network_list() self.frame = None - self.wiredCB = urwid.Filler(ComboBox(list=wiredL,use_enter=False)) + self.wiredCB = urwid.Filler(WiredComboBox(wiredL)) self.wlessLB = urwid.ListBox(wlessL) self.update_netlist(force_check=True,firstrun=True) @@ -411,11 +441,12 @@ class appGUI(): def lock_screen(self): self.frame.set_body(self.screen_locker) self.screen_locked = True + self.update_ui() def unlock_screen(self): + self.update_netlist(force_check=True) self.frame.set_body(self.thePile) self.screen_locked = False - self.update_netlist(force_check=True) self.update_ui() def raise_hidden_network_dialog(self): @@ -436,12 +467,12 @@ class appGUI(): if self.thePile.get_focus() == self.wiredCB: wlessorwired = self.WIRED_IDX where = self.thePile.get_focus().get_body().get_focus()[1] - else:#self.thePile.get_focus() == self.wlessLB : + else: #self.thePile.get_focus() == self.wlessLB : wlessorwired = self.WLESS_IDX if self.wlessLB == self.no_wlan: where = None else: - where = self.frame.get_body().get_focus().get_focus()[1] + where = self.thePile.get_focus().get_focus()[1] #where = self.wlessLB.get_focus()[1] self.focusloc = (wlessorwired,where) # Be clunky until I get to a later stage of development. @@ -498,6 +529,9 @@ class appGUI(): self.prev_state = state if not firstrun: self.update_ui() + if firstrun: + if wired.GetDefaultWiredNetwork() != None: + self.wiredCB.get_body().set_focus(wired.GetWiredProfileList().index(wired.GetDefaultWiredNetwork())) # Update the footer/status bar @wrap_exceptions() @@ -591,16 +625,11 @@ class appGUI(): #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() @@ -621,6 +650,7 @@ class appGUI(): loop.quit() return False if "f5" in keys: + self.lock_screen() wireless.Scan() if "D" in keys: # Disconnect from all networks. @@ -656,7 +686,8 @@ class appGUI(): if "C" in keys: focus = self.thePile.get_focus() if focus == self.wiredCB: - pass + WiredSettingsDialog(self.wiredCB.get_body(). + get_selected_profile()).run(ui,self.size,self.frame) else: # wireless list only other option wid,pos = self.thePile.get_focus().get_focus() @@ -677,18 +708,6 @@ class appGUI(): self.size = ui.get_cols_rows() continue self.frame.keypress( self.size, k ) - - 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_focus() - text,attr = wid.get_text() - wired.ReadWiredNetworkProfile(text) - # Make sure our internal reference to the combobox matches the - # one found in the pile. - #self.wiredCB = self.thePile.get_focus() - return True # TODO: Update this to use the networkentry stuff def connect(self, nettype, networkid, networkentry=None): diff --git a/in/man=wicd-curses.8.in b/in/man=wicd-curses.8.in index 090b042..2d6a921 100644 --- a/in/man=wicd-curses.8.in +++ b/in/man=wicd-curses.8.in @@ -1,4 +1,5 @@ -.TH WICD-CURSES "8" "January 2009" "wicd-curses" +.\" First revision was r203 +.TH WICD-CURSES "8" "January 2009" "wicd-curses-r247" .SH NAME .B wicd-curses \- curses-based wicd(8) controller @@ -39,11 +40,14 @@ Bring up hidden network scanning dialog .TP .BR H Bring up a rather simplistic help dialog. Of course, it mentions this man page first. :-) -.PP -The following is a work in progress and might not be fully functional as of yet. +.\".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 +.TP +.BR delete +Delete the selected wired network profile (from the wired combo box at the top) .PP The following are not implemented yet: .TP diff --git a/in/other=WHEREAREMYFILES.in b/in/other=WHEREAREMYFILES.in index 61363e9..cec81a3 100644 --- a/in/other=WHEREAREMYFILES.in +++ b/in/other=WHEREAREMYFILES.in @@ -1,8 +1,10 @@ -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. +WHERE ARE MY FILES?! -For a more detailed (and complete) description what is in each directory, consult the -man pages for wicd(8) and wicd-curses(8). +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 From ce64ce0aa2c98dbeffc8395766e6fd774900bdc8 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Sat, 17 Jan 2009 20:10:10 -0500 Subject: [PATCH 36/50] curses/configscript_curses.py: ADDED. Script configurator. More or less done. curses/wicd-curses.py: Added suport for the script configurator curses/README, in/man=wicd-curses.8.in: Script configurator now active setup.py: Install configscript_curses.py with the rest of the stuff --- curses/README | 2 + curses/configscript_curses.py | 139 ++++++++++++++++++++++++++++++++++ curses/curses_misc.py | 5 ++ curses/wicd-curses.py | 47 +++++++++++- in/man=wicd-curses.8.in | 4 +- setup.py | 1 + 6 files changed, 195 insertions(+), 3 deletions(-) create mode 100755 curses/configscript_curses.py diff --git a/curses/README b/curses/README index cfda201..a9cc12b 100644 --- a/curses/README +++ b/curses/README @@ -26,6 +26,8 @@ C : Display network configuration for selected network A : Display "About" dialog I : Raise the "Scan for hidden networks" dialog H : Raise help dialog +S : Configure scripts (calls an external program, requires superuser + privileges delete : Delete selected wired network profile (from the wired ComboBox) IN DIALOGS (Meta usually is "Alt"): diff --git a/curses/configscript_curses.py b/curses/configscript_curses.py new file mode 100755 index 0000000..e0c4b8e --- /dev/null +++ b/curses/configscript_curses.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python + +"""configscript_curses.py +Kind of like configscript.py, except writtwn using urwid. + +Also recycles a lot of configscript.py, too. :-) +""" + +# Copyright (C) 2009 Andrew Psaltis + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +from wicd import misc +import configscript +from configscript import write_scripts,get_script_info,get_val,none_to_blank,blank_to_none + +import urwid +import urwid.curses_display +import sys +import os + +_ = misc.get_gettext() + +language = {} +language['configure_scripts'] = _("Configure Scripts") +language['before_script'] = _("Pre-connection Script") +language['after_script'] = _("Post-connection Script") +language['disconnect_script'] = _("Disconnection Script") + +def main(argv): + global ui,frame + if len(argv) < 2: + print 'Network id to configure is missing, aborting.' + sys.exit(1) + + ui = urwid.curses_display.Screen() + ui.register_palette( [ + ('body','default','default'), + ('focus','dark magenta','light gray'), + ('editcp', 'default', 'default', 'standout'), + ('editbx', 'light gray', 'dark blue'), + ('editfc', 'white','dark blue', 'bold')] ) + + network = argv[1] + network_type = argv[2] + + script_info = get_script_info(network, network_type) + + blank = urwid.Text('') + pre_entry_t = ('body',language['before_script']+': ') + post_entry_t = ('body',language['after_script']+': ') + disconnect_entry_t = ('body',language['disconnect_script']+': ') + + global pre_entry,post_entry,disconnect_entry + pre_entry = urwid.AttrWrap(urwid.Edit(pre_entry_t, + none_to_blank(script_info.get('pre_entry'))),'editbx','editfc' ) + post_entry = urwid.AttrWrap(urwid.Edit(post_entry_t, + none_to_blank(script_info.get('post_entry'))),'editbx','editfc' ) + + disconnect_entry = urwid.AttrWrap(urwid.Edit(disconnect_entry_t, + none_to_blank(script_info.get('disconnect_entry'))),'editbx','editfc' ) + + # The buttons + ok_button = urwid.AttrWrap(urwid.Button('OK',ok_callback),'body','focus') + cancel_button = urwid.AttrWrap(urwid.Button('Cancel',cancel_callback),'body','focus') + + button_cols = urwid.Columns([ok_button,cancel_button],dividechars=1) + + lbox = urwid.Pile([('fixed',2,urwid.Filler(pre_entry)), + #('fixed',urwid.Filler(blank),1), + ('fixed',2,urwid.Filler(post_entry)), + ('fixed',2,urwid.Filler(disconnect_entry)), + #blank,blank,blank,blank,blank, + urwid.Filler(button_cols,'bottom') + ]) + frame = urwid.Frame(lbox) + result = ui.run_wrapper(run) + + if result == True: + script_info["pre_entry"] = blank_to_none(pre_entry.get_edit_text()) + script_info["post_entry"] = blank_to_none(post_entry.get_edit_text()) + script_info["disconnect_entry"] = blank_to_none(disconnect_entry.get_edit_text()) + write_scripts(network, network_type, script_info) + +OK_PRESSED = False +CANCEL_PRESSED = False +def ok_callback(button_object,user_data=None): + global OK_PRESSED + OK_PRESSED = True +def cancel_callback(button_object,user_data=None): + global CANCEL_PRESSED + CANCEL_PRESSED = True +def run(): + dim = ui.get_cols_rows() + ui.set_mouse_tracking() + + keys = True + while True: + if keys: + ui.draw_screen(dim, frame.render(dim, True)) + keys = ui.get_input() + + 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: + if urwid.is_mouse_event(k): + event, button, col, row = k + frame.mouse_event( dim, + event, button, col, row, + focus=True) + else: + frame.keypress(dim, k) + # Check if buttons are pressed. + if CANCEL_PRESSED: + return False + if OK_PRESSED or 'meta enter' in keys: + return True + +if __name__ == '__main__': + if os.getuid() != 0: + print "Root privileges are required to configure scripts. Exiting." + sys.exit(0) + main(sys.argv) diff --git a/curses/curses_misc.py b/curses/curses_misc.py index 9cd0346..97b0eae 100644 --- a/curses/curses_misc.py +++ b/curses/curses_misc.py @@ -483,3 +483,8 @@ class InputDialog(Dialog2): def on_exit(self, exitcode): return exitcode, self.edit.get_edit_text() + +# Pile that has an edit and a label saying that the file at the path specified +# does not exist +#class FileGuessEdit(urwid.WidgetWrap): +# def __init__(self,caption='', diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 279aa32..12427ee 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -45,7 +45,8 @@ from dbus import version as dbus_version import gobject # Other important wicd-related stuff -import wicd.misc as misc +from wicd import wpath +from wicd import misc from wicd import dbusmanager # Internal Python stuff @@ -58,6 +59,10 @@ from prefs_curses import PrefsDialog import netentry_curses from netentry_curses import WirelessSettingsDialog, WiredSettingsDialog,error +# Stuff about getting the script configurer running +from grp import getgrgid +from os import getgroups,system + language = misc.get_language_list_gui() ######################################## @@ -245,6 +250,36 @@ def help_dialog(body): help = TextDialog(theText,15,62,header=('header',"Wicd-Curses Help")) help.run(ui,body) +def run_configscript(netname,nettype): + loop.quit() + ui.stop() + argv = netname + ' ' +nettype + + #cmd = '/usr/lib/configscript_curses.py '+argv + cmd = wpath.lib+'configscript_curses.py '+argv + # Check whether we can sudo. Hopefully this is complete + glist = [] + for i in getgroups(): + glist.append(getgrgid(i)[0]) + if 'root' in glist: + precmd = '' + precmdargv = '' + postcmd = '' + elif 'admin' in glist or 'wheel' in glist: + precmd = 'sudo' + precmdargv = '' + postcmd = '' + else: + precmd = 'su' + precmdargv = ' -c "' + postcmd = '"' + print "Calling command: " + precmd + precmdargv + cmd + postcmd + sys.stdout.flush() + system(precmd+precmdargv+cmd+postcmd) + raw_input("Press enter!") + main() + + ######################################## ##### URWID SUPPORT CLASSES ######################################## @@ -698,6 +733,16 @@ class appGUI(): self.raise_hidden_network_dialog() if "H" in keys: help_dialog(self.frame) + if "S" in keys: + focus = self.thePile.get_focus() + if focus == self.wiredCB: + nettype = 'wired' + netname = self.wiredCB.get_body().get_selected_profile() + else: + nettype = 'wireless' + netname = str(self.wiredLB.get_focus()[1]) + run_configscript(netname,nettype) + for k in keys: if urwid.is_mouse_event(k): event, button, col, row = k diff --git a/in/man=wicd-curses.8.in b/in/man=wicd-curses.8.in index 2d6a921..67bacb2 100644 --- a/in/man=wicd-curses.8.in +++ b/in/man=wicd-curses.8.in @@ -48,8 +48,8 @@ Bring up network configuration controller for the selected network .TP .BR delete Delete the selected wired network profile (from the wired combo box at the top) -.PP -The following are not implemented yet: +.\".PP +.\"The following are not implemented yet: .TP .BR S Bring up the script selector for the selected network (requires superuser privileges) diff --git a/setup.py b/setup.py index 31d21bb..49fb036 100755 --- a/setup.py +++ b/setup.py @@ -409,6 +409,7 @@ try: data.append(( wpath.lib, ['curses/prefs_curses.py'])) data.append(( wpath.lib, ['curses/wicd-curses.py'])) data.append(( wpath.lib, ['curses/netentry_curses.py'])) + data.append(( wpath.lib, ['curses/configscript_curses.py'])) data.append(( wpath.bin, ['scripts/wicd-curses'])) if not wpath.no_install_man: data.append(( wpath.mandir + 'man8/', ['man/wicd-curses.8'])) From a25693d1abd7b4478f3ad483e83efaabeb4f9894 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Tue, 20 Jan 2009 23:41:44 -0500 Subject: [PATCH 37/50] curses/curses_misc.py: Added support for setting the text in the input dialog Changed "body" to "parent" in ComboBox. set_focus() unconditionally sets the focus now Moved error() to this file. It fits better here, anyway. Reverted TextDialog to its previous state curses/netentry_curses.py: Moved error() to curses_misc.py curses/wicd-curses.py: "Deimplemented" the script configurator, at the suggestion of various folks #wicd, and replaced it with a simple instructions dialog. My original code is still there, just commented out. Added support for renaming wired network profiles (F2 when over the combo box) Fixed various issues caused when deleting wired network profiles. Refactored the help/about dialogs to support the old TextDialog curses/README, in/man=wicd-curses.8.in: Script configurator has been "changed" --- curses/README | 4 +- curses/curses_misc.py | 35 ++++++++----- curses/netentry_curses.py | 9 +--- curses/wicd-curses.py | 106 ++++++++++++++++++++++++++------------ in/man=wicd-curses.8.in | 13 +++-- 5 files changed, 109 insertions(+), 58 deletions(-) diff --git a/curses/README b/curses/README index a9cc12b..afe8d66 100644 --- a/curses/README +++ b/curses/README @@ -26,9 +26,9 @@ C : Display network configuration for selected network A : Display "About" dialog I : Raise the "Scan for hidden networks" dialog H : Raise help dialog -S : Configure scripts (calls an external program, requires superuser - privileges +S : Provide instructions for configuring scripts delete : Delete selected wired network profile (from the wired ComboBox) +F2 : Rename selected wired network profile (from the wired ComboBox) IN DIALOGS (Meta usually is "Alt"): ESC or Q: Quit dialog without saving information (if present) diff --git a/curses/curses_misc.py b/curses/curses_misc.py index 97b0eae..0dfc374 100644 --- a/curses/curses_misc.py +++ b/curses/curses_misc.py @@ -24,6 +24,15 @@ wicd-curses. import urwid +# Uses code that is towards the bottom +def error(ui,parent,message): + """Shows an error dialog (or something that resembles one)""" + # /\ + # /!!\ + # /____\ + dialog = TextDialog(message,6,40,('important',"ERROR")) + return dialog.run(ui,parent) + # My savior. :-) # Although I could have made this myself pretty easily, just want to give credit where # its due. @@ -301,7 +310,7 @@ class ComboBox(urwid.WidgetWrap): self.user_args = user_args # Widget references to simplify some things - self.body = None + self.parent = None self.ui = None self.row = None def set_list(self,list): @@ -310,25 +319,27 @@ class ComboBox(urwid.WidgetWrap): def set_focus(self,index): self.focus = index self.cbox.set_w(SelText(self.list[index]+' vvv')) + if self.overlay: + self.overlay._listbox.set_focus(index) def rebuild_combobox(self): - self.build_combobox(self.body,self.ui,self.row) - def build_combobox(self,body,ui,row): + self.build_combobox(self.parent,self.ui,self.row) + def build_combobox(self,parent,ui,row): str,trash = self.label.get_text() 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.focus, + self.overlay = self.ComboSpace(self.list,parent,ui,self.focus, pos=(len(str)+1,row)) else: w = urwid.Columns([self.cbox]) - self.overlay = self.ComboSpace(self.list,body,ui,self.focus, + self.overlay = self.ComboSpace(self.list,parent,ui,self.focus, pos=(0,row)) self.set_w(w) - self.body = body + self.parent = parent self.ui = ui self.row = row @@ -341,7 +352,7 @@ class ComboBox(urwid.WidgetWrap): # Die if the user didn't prepare the combobox overlay if self.overlay == None: raise ComboBoxException('ComboBox must be built before use!') - retval = self.overlay.show(self.ui,self.body) + retval = self.overlay.show(self.ui,self.parent) if retval != None: self.set_focus(self.list.index(retval)) #self.cbox.set_w(SelText(retval+' vvv')) @@ -444,9 +455,9 @@ class Dialog2(urwid.WidgetWrap): # Simple dialog with text in it and "OK" class TextDialog(Dialog2): def __init__(self, text, height, width, header=None,align='left'): - l = [] - for line in text: - l.append( urwid.Text( line,align=align)) + l = [urwid.Text(text)] + #for line in text: + # l.append( urwid.Text( line,align=align)) body = urwid.ListBox(l) body = urwid.AttrWrap(body, 'body') @@ -461,8 +472,8 @@ class TextDialog(Dialog2): self.frame.set_focus('footer') class InputDialog(Dialog2): - def __init__(self, text, height, width,ok_name='OK'): - self.edit = urwid.Edit(wrap='clip') + def __init__(self, text, height, width,ok_name='OK',edit_text=''): + self.edit = urwid.Edit(wrap='clip',edit_text=edit_text) body = urwid.ListBox([self.edit]) body = urwid.AttrWrap(body, 'editbx','editfc') diff --git a/curses/netentry_curses.py b/curses/netentry_curses.py index 4274625..8141664 100644 --- a/curses/netentry_curses.py +++ b/curses/netentry_curses.py @@ -22,17 +22,10 @@ # MA 02110-1301, USA. import urwid -from curses_misc import TextDialog,DynWrap,MaskingEdit,ComboBox +from curses_misc import TextDialog,DynWrap,MaskingEdit,ComboBox,error import wicd.misc as misc from wicd.misc import noneToString, stringToNone, noneToBlankString, to_bool -def error(ui,parent,message): - """Shows an error dialog (or something that resembles one)""" - # /\ - # /!!\ - # /____\ - dialog = TextDialog(message,40,6,('important',"ERROR")) - return dialog.run(ui,parent) language = misc.get_language_list_gui() diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 12427ee..9f7e201 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -54,10 +54,10 @@ import sys from time import sleep # Curses UIs for other stuff -from curses_misc import SelText,ComboBox,TextDialog,InputDialog +from curses_misc import SelText,ComboBox,TextDialog,InputDialog,error from prefs_curses import PrefsDialog import netentry_curses -from netentry_curses import WirelessSettingsDialog, WiredSettingsDialog,error +from netentry_curses import WirelessSettingsDialog, WiredSettingsDialog # Stuff about getting the script configurer running from grp import getgrgid @@ -217,40 +217,59 @@ def about_dialog(body): # The ASCII Art "Wicd" was made from the "smslant" font on one of those # online ASCII big text generators. theText = [ -[('green'," /// \\\\\\")," _ ___ __"], -[('green'," /// \\\\\\")," | | /| / (_)______/ /"], -[('green'," /// \\\\\\")," | |/ |/ / / __/ _ / "], -[('green',"/|| // \\\\ ||\\")," |__/|__/_/\__/\_,_/ "], -[('green',"||| ||"),"(|^|)",('green',"|| |||"), -" ($VERSION) ".replace("$VERSION",daemon.Hello())], +('green'," /// \\\\\\")," _ ___ __\n", +('green'," /// \\\\\\")," | | /| / (_)______/ /\n", +('green'," /// \\\\\\")," | |/ |/ / / __/ _ / \n", +('green',"/|| // \\\\ ||\\")," |__/|__/_/\__/\_,_/ \n", +('green',"||| ||"),"(|^|)",('green',"|| |||"), +" ($VERSION) \n".replace("$VERSION",daemon.Hello()), -[('green',"\\|| \\\\")," |+| ",('green',"// ||/ ")], -[('green'," \\\\\\")," |+| ",('green',"///")," http://wicd.net"], -[('green'," \\\\\\")," |+| ",('green',"///")," Brought to you by:"], -[('green'," \\\\\\")," |+| ",('green',"///")," Adam Blackburn (wicd)"], -" ___|+|___ Dan O'Reilly (wicd)", -" |---------| Andrew Psaltis (this ui)", +('green',"\\|| \\\\")," |+| ",('green',"// ||/ \n"), +('green'," \\\\\\")," |+| ",('green',"///")," http://wicd.net\n", +('green'," \\\\\\")," |+| ",('green',"///")," Brought to you by:\n", +('green'," \\\\\\")," |+| ",('green',"///")," Adam Blackburn (wicd)\n", +" ___|+|___ Dan O'Reilly (wicd)\n", +" |---------| Andrew Psaltis (this ui)\n", "-----------------------------------------------------"] about = TextDialog(theText,16,55,header=('header','About Wicd')) about.run(ui,body) def help_dialog(body): theText = [ -"For more detailed help, consult the wicd-curses(8) man page.", -"", "All controls are case sensitive", -[('bold','H')," Display this help dialog"], -[('bold','enter')," Connect to selected network"], -[('bold','D')," Disconnect from all networks"], -[('bold','ESC')," Stop a network connection in progress"], -[('bold','F5')," or ", ('bold','R')," Refresh network list"], -[('bold','P')," Prefrences dialog"], -[('bold','I')," Scan for hidden networks"], -[('bold','S')," Select scripts"] +"For more detailed help, consult the wicd-curses(8) man page.\n", +"\n", "All controls are case sensitive\n", +('bold','H')," Display this help dialog\n", +('bold','enter')," Connect to selected network\n", +('bold','D')," Disconnect from all networks\n", +('bold','ESC')," Stop a network connection in progress\n", +('bold','F5')," or ", ('bold','R')," Refresh network list\n", +('bold','P')," Prefrences dialog\n", +('bold','I')," Scan for hidden networks\n", +('bold','S')," Select scripts\n" ] help = TextDialog(theText,15,62,header=('header',"Wicd-Curses Help")) help.run(ui,body) -def run_configscript(netname,nettype): +def run_configscript(parent,netname,nettype): + configfile = wpath.etc+netname+'-settings.conf' + header = 'profile' if nettype == 'wired' else 'BSSID' + profname = netname if nettype == 'wired' else wireless.GetWirelessProperty( + netname,'bssid') + + theText = [ + """To avoid various complications, wicd-curses does not support directly editing the scripts directly. However, you can edit them manually. First, (as root)", open the "%s" config file, and look for the section labeled by the %s in question. In this case, this is: + +[%s] + +Once here, you can adjust (or add) the "beforescript", "afterscript", and "disconnectscript" variables as needed, to change the preconnect, postconnect, and disconnect scripts respectively. + +Alternatively, you can configure the wireless networks by ESSID, by looking for the "[]" field in the config file.""" % (configfile,header,profname)] + dialog = TextDialog(theText,16,80) + dialog.run(ui,parent) + # This code works with many distributions, but not all of them. So, to + # limit complications, it has been deactivated. If you want to run it, + # be my guest. Be sure to deactivate the above stuff first. + """ loop.quit() ui.stop() argv = netname + ' ' +nettype @@ -265,7 +284,7 @@ def run_configscript(netname,nettype): precmd = '' precmdargv = '' postcmd = '' - elif 'admin' in glist or 'wheel' in glist: + elif 'admin' in glist or 'wheel' in glist or 'sudo' in glist: precmd = 'sudo' precmdargv = '' postcmd = '' @@ -278,7 +297,7 @@ def run_configscript(netname,nettype): system(precmd+precmdargv+cmd+postcmd) raw_input("Press enter!") main() - + """ ######################################## ##### URWID SUPPORT CLASSES @@ -369,25 +388,47 @@ class WiredComboBox(ComboBox): if self.theList != []: wired.ReadWiredNetworkProfile(self.get_selected_profile()) + #def rebuild_combobox(self): + # pass def keypress(self,size,key): prev_focus = self.get_focus()[1] key = self.__super.keypress(size,key) if self.get_focus()[1] == len(self.list)-1: dialog = InputDialog(('header',"Add new wired profile"),7,30) - exitcode,name = dialog.run(ui,self.body) + exitcode,name = dialog.run(ui,self.parent) if exitcode == 0: wired.CreateWiredNetworkProfile(name,False) self.set_list(wired.GetWiredProfileList()) self.rebuild_combobox() self.set_focus(prev_focus) - self.overlay._listbox.set_focus(prev_focus) else: wired.ReadWiredNetworkProfile(self.get_selected_profile()) if key == 'delete': + if len(self.theList) == 1: + error(self.ui,self.parent,"Cannot delete the last wired profile. Try renaming it ('F2')") + return key wired.DeleteWiredNetworkProfile(self.get_selected_profile()) + # Return to the top of the list if something is deleted. + + if wired.GetDefaultWiredNetwork() != None: + self.set_focus(self.theList.index(wired.GetDefaultWiredNetwork())) + else: + prev_focus -= 1 + self.set_focus(prev_focus) self.set_list(wired.GetWiredProfileList()) self.rebuild_combobox() + if key == 'f2': + dialog = InputDialog(('header',"Rename wired profile"),7,30, + edit_text=unicode(self.get_selected_profile())) + exitcode,name = dialog.run(ui,self.parent) + if exitcode == 0: + # Save the new one, then kill the old one + wired.SaveWiredNetworkProfile(name) + wired.DeleteWiredNetworkProfile(self.get_selected_profile()) + self.set_list(wired.GetWiredProfileList()) + self.set_focus(self.theList.index(name)) + self.rebuild_combobox() return key #if key == 'C': # Configure the network @@ -401,7 +442,8 @@ class WiredComboBox(ComboBox): def get_selected_profile(self): """Get the selected wired profile""" - return self.theList[self.get_focus()[1]] + loc = self.get_focus()[1] + return self.theList[loc] ######################################## ##### APPLICATION INTERFACE CLASS @@ -684,7 +726,7 @@ class appGUI(): if "f8" in keys or 'Q' in keys: loop.quit() return False - if "f5" in keys: + if "f5" in keys or 'R' in keys: self.lock_screen() wireless.Scan() if "D" in keys: @@ -741,7 +783,7 @@ class appGUI(): else: nettype = 'wireless' netname = str(self.wiredLB.get_focus()[1]) - run_configscript(netname,nettype) + run_configscript(self.frame,netname,nettype) for k in keys: if urwid.is_mouse_event(k): diff --git a/in/man=wicd-curses.8.in b/in/man=wicd-curses.8.in index 67bacb2..944452f 100644 --- a/in/man=wicd-curses.8.in +++ b/in/man=wicd-curses.8.in @@ -1,5 +1,5 @@ .\" First revision was r203 -.TH WICD-CURSES "8" "January 2009" "wicd-curses-r247" +.TH WICD-CURSES "8" "January 2009" "wicd-curses-r250" .SH NAME .B wicd-curses \- curses-based wicd(8) controller @@ -47,13 +47,18 @@ Bring up a rather simplistic help dialog. Of course, it mentions this man page Bring up network configuration controller for the selected network .TP .BR delete -Delete the selected wired network profile (from the wired combo box at the top) +Delete the selected wired network profile (from the wired network combo box at the top) +.TP +.BR F2 +Rename the selected wired network profile (from the wired network combo box at the top) .\".PP .\"The following are not implemented yet: .TP .BR S -Bring up the script selector for the selected network (requires superuser privileges) -.SH "FILES" +.\"Bring up the script selector for the selected network (requires superuser privileges) +Bring up instructions on how to edit the scripts. I have implemented a way to do this in the interface itself, but making it function with all Linux distros would be difficult. Since you are reading this, you should know how to do what I suggest. ;-) + +".SH "FILES" These are not used yet. .TP .I ~/.wicd/WHEREAREMYFILES From da576e2ff9531c415b4218aa99b6d584fd5d8ed2 Mon Sep 17 00:00:00 2001 From: Robby Workman Date: Wed, 21 Jan 2009 22:35:46 -0600 Subject: [PATCH 38/50] Added crux support to setup.py --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index b8bd9b9..e2d4fe2 100755 --- a/setup.py +++ b/setup.py @@ -154,6 +154,8 @@ class configure(Command): elif os.path.exists('/etc/pld-release'): self.init = '/etc/rc.d/init.d/' self.initfile = 'init/pld/wicd' + elif os.path.exists('/usr/bin/crux'): + self.init = '/etc/rc.d/' else: self.init = 'FAIL' self.initfile = 'FAIL' From 784076926a83479f27baa0e9e16e6b2cb33ee953 Mon Sep 17 00:00:00 2001 From: Robby Workman Date: Fri, 23 Jan 2009 16:04:07 -0600 Subject: [PATCH 39/50] Some nitpick edits to wicd-client's section that checks for X and offers to launch the curses client. This is largely personal preference, so no offense will be taken by merge refusal, but I'm not convinced that "friendliness" belongs in the file comments :-) --- in/scripts=wicd-client.in | 47 +++++++++++++++------------------------ 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/in/scripts=wicd-client.in b/in/scripts=wicd-client.in index f535254..49288fc 100755 --- a/in/scripts=wicd-client.in +++ b/in/scripts=wicd-client.in @@ -1,10 +1,10 @@ #!/bin/bash -BOLD=`tput bold` -BLUE=`tput setaf 4` -NC=`tput sgr0` +BOLD=$(tput bold) +BLUE=$(tput setaf 4) +NC=$(tput sgr0) # check_firstrun() if [ ! -d ~/.wicd ]; then - mkdir ~/.wicd + mkdir -p ~/.wicd fi # Make sure the user knows WHEREAREMYFILES ;-) if [ -e %DOCDIR%WHEREAREMYFILES ] && [ ! -L ~/.wicd/WHEREAREMYFILES ]; then @@ -12,34 +12,23 @@ if [ -e %DOCDIR%WHEREAREMYFILES ] && [ ! -L ~/.wicd/WHEREAREMYFILES ]; then 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..." + printf "NOTICE: You do not have an X server active on this console, \n" + printf "so ${BOLD}${BLUE}wicd-curses${NC} will be started instead. \n" + printf "Please see the wicd-client and/or wicd-curses manual pages \n" + printf "for more information about this error and resulting message. \n" + printf "\n" + printf "This message will not be displayed again. \n" + printf "Press enter to continue... \n" - read junk - cat >>~/.wicd/CLIENT_CURSES_WARNING<> ~/.wicd/CLIENT_CURSES_WARNING << EOF +The wicd-client script checks for the existence of this file to determine +whether it should warn the user before launching wicd-curses instead, in +the event of the gui client being launched outside of the X Window environment. -Please keep this file. If you remove it, then wicd-client will bark at -you if you try to launch wicd-client on a screen that is not running X. - -Or, you could just run "touch ~/.wicd/CLIENT_CURSES_WARNING", and the same -objective will be met. - -Have a nice day. - -~The Wicd Developers +If you delete this file, then wicd-client will print the warning if it is +launched outside of X (and then recreate this file again). EOF - #touch ~/.wicd/CLIENT_CURSES_WARNING fi exec %BIN%wicd-curses fi From 932bd324727c6fbccd663de3bfe4ed1d1ac8eb98 Mon Sep 17 00:00:00 2001 From: Robby Workman Date: Fri, 23 Jan 2009 16:06:53 -0600 Subject: [PATCH 40/50] Fix a misspelling in wicd-client.1, and add linewraps at <80 chars in the raw text. --- man/wicd-client.1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/man/wicd-client.1 b/man/wicd-client.1 index 115217c..9925b0c 100644 --- a/man/wicd-client.1 +++ b/man/wicd-client.1 @@ -4,7 +4,9 @@ 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) instead. It will warn you the first time this happens. +If wicd-curses(8) is installed, 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 From abf05c782fbf933b56e2b56adc56d33142cef4a6 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Fri, 23 Jan 2009 21:13:36 -0500 Subject: [PATCH 41/50] Ad-hoc network support is added ("O"). This commit is should be the last one containing new interface elements. :-D This also may not work directly from the install. I need to change some stuff first. curses/curses_misc.py: Fixed bug in Dialog2 where mouse clicks would cause the program to crash Added DynEdit and DynIntEdit, Simple DynWrapped widgets, nothing special about them curses/wicd-curses.py: Added support for Ad-Hoc network controls (I don't know exactly how this works) curses/README,TODO,in/man=wicd-curses.8.in: Ad-Hoc network support has been added --- curses/README | 1 + curses/TODO | 1 - curses/curses_misc.py | 29 +++++++++++++---- curses/wicd-curses.py | 71 ++++++++++++++++++++++++++++++++++++++++- in/man=wicd-curses.8.in | 5 ++- 5 files changed, 97 insertions(+), 10 deletions(-) diff --git a/curses/README b/curses/README index afe8d66..a10ba07 100644 --- a/curses/README +++ b/curses/README @@ -29,6 +29,7 @@ H : Raise help dialog S : Provide instructions for configuring scripts delete : Delete selected wired network profile (from the wired ComboBox) F2 : Rename selected wired network profile (from the wired ComboBox) +O : Raise ad-hoc network 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 129fe2f..9861ba4 100644 --- a/curses/TODO +++ b/curses/TODO @@ -3,5 +3,4 @@ Things to do (in no particular order): * Implement a keyhandler function for the overall frame * Make keystrokes customizable * Make color schemes customizable -* Implement a "make an ad-hoc network" dialog * Perform a mass code cleanup diff --git a/curses/curses_misc.py b/curses/curses_misc.py index 0dfc374..fbe607d 100644 --- a/curses/curses_misc.py +++ b/curses/curses_misc.py @@ -88,6 +88,20 @@ class DynWrap(urwid.AttrWrap): def selectable(self): return self._sensitive +# Just an Edit Dynwrapped to the most common specifications +class DynEdit(DynWrap): + def __init__(self,caption='',edit_text='',sensitive=True,attrs=('editbx','editnfc'),focus_attr='editfc'): + caption = ('editcp',caption + ': ') + edit = urwid.Edit(caption,edit_text) + self.__super.__init__(edit,sensitive,attrs,focus_attr) + +# Just an IntEdit Dynwrapped to the most common specifications +class DynIntEdit(DynWrap): + def __init__(self,caption='',edit_text='',sensitive=True,attrs=('editbx','editnfc'),focus_attr='editfc'): + caption = ('editcp',caption + ':') + edit = urwid.IntEdit(caption,edit_text) + self.__super.__init__(edit,sensitive,attrs,focus_attr) + class MaskingEditException(Exception): pass @@ -436,13 +450,14 @@ class Dialog2(urwid.WidgetWrap): 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) + else: + 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] ) diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 9f7e201..d69e4e2 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -54,7 +54,7 @@ import sys from time import sleep # Curses UIs for other stuff -from curses_misc import SelText,ComboBox,TextDialog,InputDialog,error +from curses_misc import SelText,DynEdit,DynIntEdit,ComboBox,Dialog2,TextDialog,InputDialog,error from prefs_curses import PrefsDialog import netentry_curses from netentry_curses import WirelessSettingsDialog, WiredSettingsDialog @@ -445,6 +445,66 @@ class WiredComboBox(ComboBox): loc = self.get_focus()[1] return self.theList[loc] +# Dialog2 that initiates an Ad-Hoc network connection +class AdHocDialog(Dialog2): + def __init__(self): + essid_t = language['essid'] + ip_t = language['ip'] + channel_t = language['channel'] + key_t = " " + language['key'] + use_ics_t = language['use_ics'] + use_encrypt_t = language['use_wep_encryption'] + + self.essid_edit = DynEdit(essid_t) + self.ip_edit = DynEdit(ip_t) + self.channel_edit = DynIntEdit(channel_t) + self.key_edit = DynEdit(key_t,sensitive=False) + + self.use_ics_chkb = urwid.CheckBox(use_ics_t) + self.use_encrypt_chkb = urwid.CheckBox(use_encrypt_t, + on_state_change=self.encrypt_callback) + + blank = urwid.Text('') + + # Set defaults + self.essid_edit.set_edit_text("My_Adhoc_Network") + self.ip_edit.set_edit_text("169.254.12.10") + self.channel_edit.set_edit_text("3") + + l = [self.essid_edit,self.ip_edit,self.channel_edit,blank, + self.use_ics_chkb,self.use_encrypt_chkb,self.key_edit] + #for line in text: + # l.append( urwid.Text( line,align=align)) + body = urwid.ListBox(l) + #body = urwid.AttrWrap(body, 'body') + + header = ('header',"Create an Ad-Hoc network") + Dialog2.__init__(self, header, 15, 50, body) + self.add_buttons([('OK',1),('Cancel',-1)]) + self.frame.set_focus('body') + + def encrypt_callback(self,chkbox,new_state,user_info=None): + self.key_edit.set_sensitive(new_state) + + 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.buttons.set_focus(0) + self.view.keypress( size, k ) + def on_exit(self,exitcode): + data = ( self.essid_edit.get_edit_text(), + self.ip_edit.get_edit_text(), + self.channel_edit.get_edit_text(), + self.use_ics_chkb.get_state(), + self.use_encrypt_chkb.get_state(), + self.key_edit.get_edit_text()) + + return exitcode, data ######################################## ##### APPLICATION INTERFACE CLASS ######################################## @@ -784,6 +844,15 @@ class appGUI(): nettype = 'wireless' netname = str(self.wiredLB.get_focus()[1]) run_configscript(self.frame,netname,nettype) + if "O" in keys: + exitcode,data = AdHocDialog().run(ui,self.frame) + #essid,ip,channel,use_ics,use_encrypt,key_edit + if exitcode == 1: + wireless.CreateAdHocNetwork(data[0], + data[2], + data[1], "WEP", + data[5], + data[4], False) for k in keys: if urwid.is_mouse_event(k): diff --git a/in/man=wicd-curses.8.in b/in/man=wicd-curses.8.in index 944452f..3d69222 100644 --- a/in/man=wicd-curses.8.in +++ b/in/man=wicd-curses.8.in @@ -1,5 +1,5 @@ .\" First revision was r203 -.TH WICD-CURSES "8" "January 2009" "wicd-curses-r250" +.TH WICD-CURSES "8" "January 2009" "wicd-curses-r251" .SH NAME .B wicd-curses \- curses-based wicd(8) controller @@ -57,6 +57,9 @@ Rename the selected wired network profile (from the wired network combo box at t .BR S .\"Bring up the script selector for the selected network (requires superuser privileges) Bring up instructions on how to edit the scripts. I have implemented a way to do this in the interface itself, but making it function with all Linux distros would be difficult. Since you are reading this, you should know how to do what I suggest. ;-) +.TP +.BR O +Raise the Ad-Hoc network creation dialog ".SH "FILES" These are not used yet. From 1b17fde01582153522f6b6d3cfd16dbc80159247 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Fri, 23 Jan 2009 22:13:27 -0500 Subject: [PATCH 42/50] setup.py: Added support for keeping track of the revisions of the curses client (%CURSES_REVNO%) curses/wicd-curses.py: Added the ad-hoc controls to the Help dialog Set wireless scans to be synchronous (True), to adapt to an API change in mainline Added support for OptionParser, added and implemented the option that was described in the man page (and -h (help) and --version) in/wicd=wpath.py.in: Added a curses_revision flag in/man=wicd-curses.8.in: Option parsing has been implemented. Added the %CURSES_REVNO% flag to the man page. Fixed an accidental " added to one of the headers --- curses/wicd-curses.py | 53 ++++++++++++++++++++--------------------- in/man=wicd-curses.8.in | 5 ++-- in/wicd=wpath.py.in | 1 + setup.py | 2 ++ 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index d69e4e2..9cd9815 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -34,8 +34,7 @@ at least get a network connection. Or those who don't like using X. ;-) """ # UI stuff -#import urwid.raw_display -import urwid.curses_display +# This library is the only reason why I wrote this program. import urwid # DBus communication stuff @@ -57,11 +56,16 @@ from time import sleep from curses_misc import SelText,DynEdit,DynIntEdit,ComboBox,Dialog2,TextDialog,InputDialog,error from prefs_curses import PrefsDialog import netentry_curses + from netentry_curses import WirelessSettingsDialog, WiredSettingsDialog +from optparse import OptionParser + # Stuff about getting the script configurer running -from grp import getgrgid -from os import getgroups,system +#from grp import getgrgid +#from os import getgroups,system + +CURSES_REVNO=wpath.curses_revision language = misc.get_language_list_gui() @@ -245,7 +249,8 @@ def help_dialog(body): ('bold','F5')," or ", ('bold','R')," Refresh network list\n", ('bold','P')," Prefrences dialog\n", ('bold','I')," Scan for hidden networks\n", -('bold','S')," Select scripts\n" +('bold','S')," Select scripts\n", +('bold','O')," Set up Ad-hoc network\n" ] help = TextDialog(theText,15,62,header=('header',"Wicd-Curses Help")) help.run(ui,body) @@ -335,15 +340,6 @@ class NetLabel(urwid.WidgetWrap): return True def keypress(self,size,key): return self._w.keypress(size,key) - #if key == 'C': - # conf = NetEntryBase(dbusmanager.get_dbus_ifaces()) - # conf.run(ui,ui.get_cols_rows(),) - #elif key == 'S': - # Configure scripts - # pass - #elif key == 'enter': - # self.connect() - #return key def connect(self): # This should work. wireless.ConnectWireless(self.id) @@ -430,15 +426,6 @@ class WiredComboBox(ComboBox): self.set_focus(self.theList.index(name)) self.rebuild_combobox() return key - #if key == 'C': - # Configure the network - # pass - #elif key == 'S': - # Configure scripts - # pass - #elif key == 'enter': - # self.connect() - #return key def get_selected_profile(self): """Get the selected wired profile""" @@ -593,7 +580,7 @@ class appGUI(): # 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.Scan(True) wireless.SetHiddenNetworkESSID("") def update_focusloc(self): @@ -788,7 +775,7 @@ class appGUI(): return False if "f5" in keys or 'R' in keys: self.lock_screen() - wireless.Scan() + wireless.Scan(True) if "D" in keys: # Disconnect from all networks. daemon.Disconnect() @@ -846,7 +833,7 @@ class appGUI(): run_configscript(self.frame,netname,nettype) if "O" in keys: exitcode,data = AdHocDialog().run(ui,self.frame) - #essid,ip,channel,use_ics,use_encrypt,key_edit + #data = (essid,ip,channel,use_ics,use_encrypt,key_edit) if exitcode == 1: wireless.CreateAdHocNetwork(data[0], data[2], @@ -888,7 +875,15 @@ def main(): # We are _not_ python. misc.RenameProcess('wicd-curses') - ui = urwid.curses_display.Screen() + # Import the screen based on whatever the user picked. + # The raw_display will have some features that may be useful to users + # later + if options.rawscreen: + import urwid.raw_display + ui = urwid.raw_display.Screen() + else: + import urwid.curses_display + ui = urwid.curses_display.Screen() # Default Color scheme. # Other potential color schemes can be found at: # http://excess.org/urwid/wiki/RecommendedPalette @@ -970,6 +965,10 @@ setup_dbus() ##### MAIN ENTRY POINT ######################################## if __name__ == '__main__': + parser = OptionParser(version="wicd-curses-%s (using wicd %s)" % (CURSES_REVNO,daemon.Hello())) + parser.add_option("-r", "--raw-screen",action="store_true",dest='rawscreen', + help="use urwid's raw screen controller") + (options,args) = parser.parse_args() main() # Make sure that the terminal does not try to overwrite the last line of # the program, so that everything looks pretty. diff --git a/in/man=wicd-curses.8.in b/in/man=wicd-curses.8.in index 3d69222..f2b9df6 100644 --- a/in/man=wicd-curses.8.in +++ b/in/man=wicd-curses.8.in @@ -1,5 +1,5 @@ .\" First revision was r203 -.TH WICD-CURSES "8" "January 2009" "wicd-curses-r251" +.TH WICD-CURSES "8" "January 2009" "wicd-curses-%CURSES_REVNO%" .SH NAME .B wicd-curses \- curses-based wicd(8) controller @@ -10,7 +10,6 @@ It is designed to imitate the GTK-based wicd-client(1) as much as possible, and This man page only documents the current status of wicd-curses. This may/may not be the most up-to-date document. .SH "ARGUMENTS" -These are not implemented yet. .TP .BR "\-r" , " \-\-raw\-screen" Use Urwid's raw console display, instead of the (faster) curses-based one. This may be useful if you are experiencing unicode problems. @@ -61,7 +60,7 @@ Bring up instructions on how to edit the scripts. I have implemented a way to d .BR O Raise the Ad-Hoc network creation dialog -".SH "FILES" +.SH "FILES" These are not used yet. .TP .I ~/.wicd/WHEREAREMYFILES diff --git a/in/wicd=wpath.py.in b/in/wicd=wpath.py.in index 33282e7..fa4a753 100755 --- a/in/wicd=wpath.py.in +++ b/in/wicd=wpath.py.in @@ -19,6 +19,7 @@ current = os.path.dirname(os.path.realpath(__file__)) + '/' version = '%VERSION%' revision = '%REVNO%' +curses_revision = '%CURSES_REVNO%' # DIRECTORIES diff --git a/setup.py b/setup.py index b8bd9b9..f049b14 100755 --- a/setup.py +++ b/setup.py @@ -27,6 +27,7 @@ import subprocess # VERSIONNUMBER VERSION_NUM = '1.6.0' REVISION_NUM = 'unknown' +CURSES_REVNO = 'r254' try: if not os.path.exists('vcsinfo.py'): @@ -266,6 +267,7 @@ class configure(Command): # other things to replace that aren't arguments line = line.replace('%VERSION%', str(VERSION_NUM)) line = line.replace('%REVNO%', str(REVISION_NUM)) + line = line.replace('%CURSES_REVNO%', str(CURSES_REVNO)) item_out.write(line) From ff11a52abb2e5453b96005ad3c3cb4a74e7c0748 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Sun, 25 Jan 2009 23:05:46 -0500 Subject: [PATCH 43/50] curses/prefs_curses.py: Added support for the "Prefer Wired Networks" function. --- curses/prefs_curses.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/curses/prefs_curses.py b/curses/prefs_curses.py index b5d1ef9..f6c8d2d 100755 --- a/curses/prefs_curses.py +++ b/curses/prefs_curses.py @@ -27,7 +27,7 @@ from curses_misc import SelText,DynWrap,ComboBox,TabColumns daemon = None wireless = None wired = None -# Will work for now, I guess. + language = misc.get_language_list_gui() class PrefsDialog(urwid.WidgetWrap): @@ -64,6 +64,7 @@ class PrefsDialog(urwid.WidgetWrap): wired_t = ('editcp',language['wired_interface']+': ') wless_t = ('editcp',language['wireless_interface']+':') always_show_wired_t = 'Always show wired interface' + prefer_wired_t = 'Always switch to a wired connection when available' global_dns_cat_t = ('header','Global DNS Servers') global_dns_t = ('editcp',language['use_global_dns']) @@ -127,7 +128,7 @@ class PrefsDialog(urwid.WidgetWrap): self.net_cat = urwid.Text(net_cat_t) self.wired_edit = urwid.AttrWrap(urwid.Edit(wired_t),'editbx','editfc') self.wless_edit = urwid.AttrWrap(urwid.Edit(wless_t),'editbx','editfc') - + self.prefer_wired_chkbx = urwid.CheckBox(prefer_wired_t) self.global_dns_cat = urwid.Text(global_dns_cat_t) # Default the global DNS settings to off. They will be reenabled later # if so required. @@ -154,7 +155,8 @@ class PrefsDialog(urwid.WidgetWrap): generalLB = urwid.ListBox([self.net_cat, self.wless_edit,#_blank, self.wired_edit, - self.always_show_wired_checkb,_blank, + self.always_show_wired_checkb, + self.prefer_wired_chkbx,_blank, self.global_dns_cat, self.global_dns_checkb,#_blank, self.search_dom,self.dns_dom, @@ -279,7 +281,7 @@ class PrefsDialog(urwid.WidgetWrap): self.always_show_wired_checkb.set_state( daemon.GetAlwaysShowWiredInterface()) - + self.prefer_wired_chkbx.set_state(daemon.GetPreferWiredNetwork()) # DNS self.global_dns_checkb.set_state(daemon.GetUseGlobalDNS()) theDNS = daemon.GetGlobalDNSAddresses() @@ -350,6 +352,7 @@ class PrefsDialog(urwid.WidgetWrap): daemon.SetAutoReconnect(self.auto_reconn_checkb.get_state()) daemon.SetDebugMode(self.debug_mode_checkb.get_state()) daemon.SetSignalDisplayType(int(self.use_dbm_checkb.get_state())) + daemon.SetPreferWiredNetwork(bool(self.prefer_wired_chkbx.get_state())) if self.wired_auto_2.get_state(): daemon.SetWiredAutoConnectMethod(2) elif self.wired_auto_3.get_state(): From 26e636e2f2e3da536f57b8a31563f85f974ccad0 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Tue, 27 Jan 2009 21:46:52 -0500 Subject: [PATCH 44/50] wicd/misc.py: Fixed a typo in get_language_list_gui (%CURSES_REVNO%) curses/wicd-curses.py: Added in some translations (not done yet) curses/prefs_curses.py: Added all of the translations Removed the warning about changing the backends (since it is useless) --- curses/prefs_curses.py | 29 ++++++++++++++--------------- curses/wicd-curses.py | 13 ++++++------- setup.py | 2 +- wicd/misc.py | 2 +- 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/curses/prefs_curses.py b/curses/prefs_curses.py index f6c8d2d..1c92f82 100755 --- a/curses/prefs_curses.py +++ b/curses/prefs_curses.py @@ -60,13 +60,13 @@ class PrefsDialog(urwid.WidgetWrap): #### # General Settings - net_cat_t = ('header','Network Interfaces') + net_cat_t = ('header',language['network_interfaces']) wired_t = ('editcp',language['wired_interface']+': ') wless_t = ('editcp',language['wireless_interface']+':') - always_show_wired_t = 'Always show wired interface' - prefer_wired_t = 'Always switch to a wired connection when available' + always_show_wired_t = language['wired_always_on'] + prefer_wired_t = language['always_switch_to_wired'] - global_dns_cat_t = ('header','Global DNS Servers') + global_dns_cat_t = ('header',language['global_dns_servers']) global_dns_t = ('editcp',language['use_global_dns']) dns_dom_t = ('editcp',' DNS Domain: ') search_dom_t = ('editcp',' Search domain:') @@ -75,13 +75,13 @@ class PrefsDialog(urwid.WidgetWrap): dns3_t = ('editcp',' DNS server 3: ') - wired_auto_cat_t= ('header','Wired Autoconnect Settings') + wired_auto_cat_t= ('header',language['wired_autoconnect_settings']) wired_auto_1_t = language['use_default_profile'] wired_auto_2_t = language['show_wired_list'] wired_auto_3_t = language['use_last_used_profile'] - auto_reconn_cat_t = ('header','Automatic Reconnection') - auto_reconn_t = 'Automatically reconnect on connection loss' + auto_reconn_cat_t = ('header',language['automatic_reconnection']) + auto_reconn_t = language['auto_reconnect'] #### External Programs automatic_t = language['wicd_auto_config'] @@ -102,20 +102,20 @@ class PrefsDialog(urwid.WidgetWrap): #### Advanced Settings #wpa_t=('editcp',language['wpa_supplicant_driver']+':') - wpa_cat_t=('header','WPA_Supplicant') + wpa_cat_t=('header',language['wpa_supplicant']) wpa_t=('editcp','Driver:') wpa_list = ['spam','double spam','triple spam','quadruple spam'] - wpa_warn_t = ('important','You should almost always use wext as the WPA Supplicant Driver') + wpa_warn_t = ('important',language['always_use_wext']) 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') + #backend_warn_t = ('important','Changes to the backend (probably) requires a daemon restart') - debug_cat_t = ('header','Debugging') + debug_cat_t = ('header',language['debugging']) debug_mode_t = language['use_debug_mode'] - wless_cat_t = ('header','Wireless Interface') + wless_cat_t = ('header',language['wireless_interface']) use_dbm_t = language['display_type_dialog'] @@ -210,7 +210,6 @@ 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) @@ -222,7 +221,7 @@ class PrefsDialog(urwid.WidgetWrap): advancedLB = urwid.ListBox([self.wpa_cat, self.wpa_cbox,self.wpa_warn,_blank, self.backend_cat, - self.backend_cbox,self.backend_warn,_blank, + self.backend_cbox,_blank, self.debug_cat, self.debug_mode_checkb, _blank, self.wless_cat, @@ -262,7 +261,7 @@ class PrefsDialog(urwid.WidgetWrap): #self.walker = urwid.SimpleListWalker(content) #self.listbox = urwid.ListBox(self.walker) #self._linebox = urwid.LineBox(self._listbox) - self.tabs = TabColumns(headerList,lbList,'Preferences',self.button_cols) + self.tabs = TabColumns(headerList,lbList,language['preferences'],self.button_cols) #overlay = urwid.Overlay(self.tabs, body, ('fixed left', pos[0]), # width, ('fixed top', pos[1]), height) self.__super.__init__(self.tabs) diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 9cd9815..8db06ee 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -100,7 +100,7 @@ class wrap_exceptions: 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." + print "Please restart the daemon, and then restart wicd-curses." raise except : # If the UI isn't inactive (redraw_tag wouldn't normally be @@ -324,7 +324,7 @@ class NetLabel(urwid.WidgetWrap): str(wireless.GetWirelessProperty(id, strenstr))) self.essid = wireless.GetWirelessProperty(id, 'essid') self.bssid = wireless.GetWirelessProperty(id, 'bssid') - self.encrypt = wireless.GetWirelessProperty(id,'encryption_method') if wireless.GetWirelessProperty(id, 'encryption') else 'Unsecured' + self.encrypt = wireless.GetWirelessProperty(id,'encryption_method') if wireless.GetWirelessProperty(id, 'encryption') else language['unsecured'] self.mode = wireless.GetWirelessProperty(id, 'mode') # Master, Ad-Hoc self.channel = wireless.GetWirelessProperty(id, 'channel') theString = ' %*s %25s %9s %17s %6s: %s' % (gap, @@ -390,7 +390,7 @@ class WiredComboBox(ComboBox): prev_focus = self.get_focus()[1] key = self.__super.keypress(size,key) if self.get_focus()[1] == len(self.list)-1: - dialog = InputDialog(('header',"Add new wired profile"),7,30) + dialog = InputDialog(('header',"Add a new wired profile"),7,30) exitcode,name = dialog.run(ui,self.parent) if exitcode == 0: @@ -465,7 +465,7 @@ class AdHocDialog(Dialog2): body = urwid.ListBox(l) #body = urwid.AttrWrap(body, 'body') - header = ('header',"Create an Ad-Hoc network") + header = ('header',language['create_adhoc_network']) Dialog2.__init__(self, header, 15, 50, body) self.add_buttons([('OK',1),('Cancel',-1)]) self.frame.set_focus('body') @@ -503,8 +503,8 @@ class appGUI(): # Happy screen saying that you can't do anything because we're scanning # 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.screen_locker = urwid.Filler(urwid.Text(('important',language['scanning_stand_by']), align='center')) + self.no_wlan = urwid.Filler(urwid.Text(('important',language['no_wireless_networks_found']), align='center')) self.TITLE = 'Wicd Curses Interface' self.WIRED_IDX = 1 self.WLESS_IDX = 3 @@ -542,7 +542,6 @@ class appGUI(): self.footerList = urwid.ListBox([self.footer1,self.footer2]) # Pop takes a number! #walker.pop(1) - nothingness = urwid.Filler(urwid.Text('Hello, world!')) self.frame = urwid.Frame(self.thePile, header=header, footer=urwid.BoxAdapter(self.footerList,2)) diff --git a/setup.py b/setup.py index 82de34d..032029b 100755 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ import subprocess # VERSIONNUMBER VERSION_NUM = '1.6.0' REVISION_NUM = 'unknown' -CURSES_REVNO = 'r254' +CURSES_REVNO = 'r260' try: if not os.path.exists('vcsinfo.py'): diff --git a/wicd/misc.py b/wicd/misc.py index 356f9d4..cb425dc 100644 --- a/wicd/misc.py +++ b/wicd/misc.py @@ -553,7 +553,7 @@ def get_language_list_gui(): language['global_dns_servers'] = _("Global DNS servers") language['network_interfaces'] = _("Network Interfaces") language['connecting_to_daemon'] = _("Connecting to daemon...") - langauge['cannot_connect_to_daemon'] = _("Can't connect to the daemon, trying to start it automatically...") + language['cannot_connect_to_daemon'] = _("Can't connect to the daemon, trying to start it automatically...") language['could_not_connect'] = _("Could not connect to wicd's D-Bus interface. Check the wicd log for error messages.") return language From b5f6fcc702307db2ca531644b9f76c6efea62514 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Thu, 29 Jan 2009 15:55:32 -0500 Subject: [PATCH 45/50] Merged in (only) r261 of rworkman's branch, which quotes the strings in the wicd-client script. Also, the revision numbers of the mainline have changed on me. r263 contained all of the translations that I requested. --- in/scripts=wicd-client.in | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/in/scripts=wicd-client.in b/in/scripts=wicd-client.in index 49288fc..a8e2a93 100755 --- a/in/scripts=wicd-client.in +++ b/in/scripts=wicd-client.in @@ -3,15 +3,15 @@ BOLD=$(tput bold) BLUE=$(tput setaf 4) NC=$(tput sgr0) # check_firstrun() -if [ ! -d ~/.wicd ]; then - mkdir -p ~/.wicd +if [ ! -d "~/.wicd" ]; then + mkdir -p "~/.wicd" fi # Make sure the user knows WHEREAREMYFILES ;-) -if [ -e %DOCDIR%WHEREAREMYFILES ] && [ ! -L ~/.wicd/WHEREAREMYFILES ]; then - ln -s %DOCDIR%WHEREAREMYFILES ~/.wicd/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 + if [ ! -f "~/.wicd/CLIENT_CURSES_WARNING" ]; then printf "NOTICE: You do not have an X server active on this console, \n" printf "so ${BOLD}${BLUE}wicd-curses${NC} will be started instead. \n" printf "Please see the wicd-client and/or wicd-curses manual pages \n" @@ -21,7 +21,7 @@ if [ "$DISPLAY" = "" ] && [ -x "%BIN%wicd-curses" ]; then printf "Press enter to continue... \n" read _junk - cat >> ~/.wicd/CLIENT_CURSES_WARNING << EOF + cat >> "~/.wicd/CLIENT_CURSES_WARNING" << EOF The wicd-client script checks for the existence of this file to determine whether it should warn the user before launching wicd-curses instead, in the event of the gui client being launched outside of the X Window environment. From e030e5980d95047c38f7abc830d20a335fdbda12 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Thu, 29 Jan 2009 23:25:02 -0500 Subject: [PATCH 46/50] curses/wicd-curses.py: Applied some typographical changes from rworkman Fixed the script showing dialog for wireless networks. --- curses/wicd-curses.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 8db06ee..ab6029f 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -259,17 +259,16 @@ def run_configscript(parent,netname,nettype): configfile = wpath.etc+netname+'-settings.conf' header = 'profile' if nettype == 'wired' else 'BSSID' profname = netname if nettype == 'wired' else wireless.GetWirelessProperty( - netname,'bssid') - + int(netname),'bssid') theText = [ - """To avoid various complications, wicd-curses does not support directly editing the scripts directly. However, you can edit them manually. First, (as root)", open the "%s" config file, and look for the section labeled by the %s in question. In this case, this is: + """To avoid various complications, wicd-curses does not support editing the scripts directly. However, you can edit them manually. First, (as root)", open the "%s" config file, and look for the section labeled by the %s in question. For example, this network is: [%s] -Once here, you can adjust (or add) the "beforescript", "afterscript", and "disconnectscript" variables as needed, to change the preconnect, postconnect, and disconnect scripts respectively. +You can also configure the wireless networks by looking for the "[]" field in the config file. -Alternatively, you can configure the wireless networks by ESSID, by looking for the "[]" field in the config file.""" % (configfile,header,profname)] - dialog = TextDialog(theText,16,80) +Once there, you can adjust (or add) the "beforescript", "afterscript", and "disconnectscript" variables as needed, to change the preconnect, postconnect, and disconnect scripts respectively. Note that you will be specifying the full path to the scripts - not the actual script contents. You will need to add/edit the script contents separately. Refer to the wicd manual page for more information.""" % (configfile,header,profname)] + dialog = TextDialog(theText,20,80) dialog.run(ui,parent) # This code works with many distributions, but not all of them. So, to # limit complications, it has been deactivated. If you want to run it, @@ -828,7 +827,7 @@ class appGUI(): netname = self.wiredCB.get_body().get_selected_profile() else: nettype = 'wireless' - netname = str(self.wiredLB.get_focus()[1]) + netname = str(self.wlessLB.get_focus()[1]) run_configscript(self.frame,netname,nettype) if "O" in keys: exitcode,data = AdHocDialog().run(ui,self.frame) From d137cbad85a142b6091e3c9c1cb685ba0cc874b2 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Fri, 30 Jan 2009 00:30:33 -0500 Subject: [PATCH 47/50] curses/wicd-curses.py: Added some stuff to the help dialog. '?' and 'h' now raise the help dialog 'q' now quits the client. Keymaps are now colored white in the help dialog. --- curses/wicd-curses.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index ab6029f..6bf2779 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -242,7 +242,7 @@ def help_dialog(body): theText = [ "For more detailed help, consult the wicd-curses(8) man page.\n", "\n", "All controls are case sensitive\n", -('bold','H')," Display this help dialog\n", +('bold','H')," or ",('bold','h'),' or ',('bold','?')," Display this help dialog\n", ('bold','enter')," Connect to selected network\n", ('bold','D')," Disconnect from all networks\n", ('bold','ESC')," Stop a network connection in progress\n", @@ -250,9 +250,10 @@ def help_dialog(body): ('bold','P')," Prefrences dialog\n", ('bold','I')," Scan for hidden networks\n", ('bold','S')," Select scripts\n", -('bold','O')," Set up Ad-hoc network\n" +('bold','O')," Set up Ad-hoc network\n", +('bold','C')," Configure Selected Network\n" ] - help = TextDialog(theText,15,62,header=('header',"Wicd-Curses Help")) + help = TextDialog(theText,17,62,header=('header',"Wicd-Curses Help")) help.run(ui,body) def run_configscript(parent,netname,nettype): @@ -768,7 +769,7 @@ class appGUI(): keys = ui.get_input() # Should make a keyhandler method, but this will do until I get around to # that stage - if "f8" in keys or 'Q' in keys: + if "f8" in keys or 'Q' in keys or 'q' in keys: loop.quit() return False if "f5" in keys or 'R' in keys: @@ -818,7 +819,7 @@ class appGUI(): #self.netentry.run(ui,self.size,self.frame) if "I" in keys: self.raise_hidden_network_dialog() - if "H" in keys: + if "H" in keys or 'h' in keys or '?' in keys: help_dialog(self.frame) if "S" in keys: focus = self.thePile.get_focus() @@ -904,7 +905,7 @@ def main(): ('green','dark green','default'), ('blue','dark blue','default'), ('red','dark red','default'), - ('bold','default','default','bold')]) + ('bold','white','default','bold')]) # This is a wrapper around a function that calls another a function that is a # wrapper around a infinite loop. Fun. ui.run_wrapper(run) From 7cde91e14a1df2ce951de7fce153f7c773e4af86 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Fri, 30 Jan 2009 23:46:07 -0500 Subject: [PATCH 48/50] curses/configscript_curses.py: Fixed the typo that rworkman noticed. curses/wicd-curses.py: Ensured that the upper status bar updates itself immediately after a connection is made, as opposed to a second or two after the fact curses/README: Added a FAQ and added the new keybindings in/man=wicd-curses.8.in: Added the new keybindings --- curses/README | 45 ++++++++++++++++++++++++----------- curses/configscript_curses.py | 2 +- curses/wicd-curses.py | 3 ++- in/man=wicd-curses.8.in | 4 ++-- 4 files changed, 36 insertions(+), 18 deletions(-) diff --git a/curses/README b/curses/README index a10ba07..57fa171 100644 --- a/curses/README +++ b/curses/README @@ -16,24 +16,41 @@ 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 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 -A : Display "About" dialog -I : Raise the "Scan for hidden networks" dialog -H : Raise help dialog -S : Provide instructions for configuring scripts -delete : Delete selected wired network profile (from the wired ComboBox) -F2 : Rename selected wired network profile (from the wired ComboBox) -O : Raise ad-hoc network dialog +F5 : refresh wireless networks +F8 or Q or q: quit +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 +A : Display "About" dialog +I : Raise the "Scan for hidden networks" dialog +H or h or ? : Raise help dialog +S : Provide instructions for configuring scripts +delete : Delete selected wired network profile (from the wired ComboBox) +F2 : Rename selected wired network profile (from the wired ComboBox) +O : Raise ad-hoc network dialog IN DIALOGS (Meta usually is "Alt"): ESC or Q: Quit dialog without saving information (if present) Meta+Left/Right: Change tabs Left/Right (if tabs present) Meta+Enter : Quit dialog and save information +FAQ (WIP): + +What is wicd-curses? + See above. :-) + +Why didn't you call it wicd-urwid? There is a hachoir-urwid package out there. + I first called this "urwicd". However, due to the relative obscurity of + the urwid package, and the fact that many more people know what "curses" + is, I named it wicd-curses. After all, it _does_ use curses (by default, + anyway). + +Why don't you support lower-case keybindings for most of the commands? + I was trying to prevent mass chaos from happening because of mashing keys. + Of course, if you unwittingly have caps-lock on, that's going to cause said + chaos, too, so you might want to check that (or ask me about changing the + keymaps to ctrl/meta+KEY) + ~NaCl diff --git a/curses/configscript_curses.py b/curses/configscript_curses.py index e0c4b8e..46f1e60 100755 --- a/curses/configscript_curses.py +++ b/curses/configscript_curses.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """configscript_curses.py -Kind of like configscript.py, except writtwn using urwid. +Kind of like configscript.py, except written using urwid. Also recycles a lot of configscript.py, too. :-) """ diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 6bf2779..d72e368 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -712,6 +712,7 @@ class appGUI(): # immediately. if from_idle and not self.connecting: self.update_netlist() + self.update_status() self.update_ui() return False toAppend = '' @@ -851,7 +852,7 @@ class appGUI(): continue self.frame.keypress( self.size, k ) return True - # TODO: Update this to use the networkentry stuff + def connect(self, nettype, networkid, networkentry=None): """ Initiates the connection process in the daemon. """ if nettype == "wireless": diff --git a/in/man=wicd-curses.8.in b/in/man=wicd-curses.8.in index f2b9df6..06fa930 100644 --- a/in/man=wicd-curses.8.in +++ b/in/man=wicd-curses.8.in @@ -19,7 +19,7 @@ All of these are case sensitive. .BR enter Connect to selected network .TP -.BR "F8 " or " Q" +.BR "F8 " or " Q " or " q" Quit the client. .TP .BR D @@ -37,7 +37,7 @@ Bring up the preferences controller .BR I Bring up hidden network scanning dialog .TP -.BR H +.BR "H " or " h " or " ?" Bring up a rather simplistic help dialog. Of course, it mentions this man page first. :-) .\".PP .\"The following is a work in progress and might not be fully functional as of yet. From a89e45f0c89c2bff38ffb37d0c9dd0b6f77c9363 Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Sat, 31 Jan 2009 01:33:11 -0500 Subject: [PATCH 49/50] curses/configscript_curses.py: Added translations Removed the redundant run() function in WirelessSettingsDialog curses/wicd-curses.py: Added translations, some still missing. wicd/misc.py: Added some translations that are not in the database, but are in the translator --- curses/netentry_curses.py | 40 ++++---------------------------- curses/wicd-curses.py | 48 ++++++++++++++++----------------------- setup.py | 2 +- wicd/misc.py | 5 ++++ 4 files changed, 31 insertions(+), 64 deletions(-) diff --git a/curses/netentry_curses.py b/curses/netentry_curses.py index 8141664..805c9a7 100644 --- a/curses/netentry_curses.py +++ b/curses/netentry_curses.py @@ -215,7 +215,8 @@ class WiredSettingsDialog(AdvancedSettingsDialog): self._w.body.body.append(self.button_cols) self.prof_name = name - self._w.header = urwid.Text( ('header',">Configuring preferences for wired profile \"%s\"" % self.prof_name),align='right' ) + title = ">"+language['configuring_wired'].replace('$A',self.prof_name) + self._w.header = urwid.Text( ('header',title),align='right' ) self.set_values() def set_net_prop(self,option,value): @@ -277,8 +278,8 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): 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' ) + title = ">"+language['configuring_wireless'].replace('$A',wireless.GetWirelessProperty(networkID,'essid')).replace('$B',wireless.GetWirelessProperty(networkID,'bssid')) + self._w.header = urwid.Text(('header',title),align='right' ) def encryption_toggle(self,chkbox,new_state,user_data=None): self.encryption_combo.set_sensitive(new_state) @@ -412,37 +413,6 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): 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() - self.overlay = urwid.Overlay(self, display, ('fixed left', 0),width - , ('fixed top',1), height-3) + def prerun(self,ui,dim,display): 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, 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 - 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/wicd-curses.py b/curses/wicd-curses.py index d72e368..a8fb3c8 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -68,6 +68,8 @@ from optparse import OptionParser CURSES_REVNO=wpath.curses_revision language = misc.get_language_list_gui() +# We need 'Connecting' without the '...' +language['connecting']=misc.get_language_list_tray()['connecting'] ######################################## ##### SUPPORT CLASSES @@ -87,7 +89,7 @@ class wrap_exceptions: gobject.source_remove(redraw_tag) loop.quit() ui.stop() - print "\nTerminated by user." + print "\n"+language['terminated'] #raise except DBusException: gobject.source_remove(redraw_tag) @@ -95,12 +97,7 @@ class wrap_exceptions: 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 then restart wicd-curses." + print "\n"+language['dbus_fail'] raise except : # If the UI isn't inactive (redraw_tag wouldn't normally be @@ -113,10 +110,7 @@ class wrap_exceptions: # Zap the screen ui.stop() # Print out standard notification: - - print "\nEXCEPTION!" - print "Please report this to the maintainer and/or file a bug report with the backtrace below:" - print redraw_tag + print "\n" + language['exception'] # Flush the buffer so that the notification is always above the # backtrace sys.stdout.flush() @@ -230,7 +224,7 @@ def about_dialog(body): ('green',"\\|| \\\\")," |+| ",('green',"// ||/ \n"), ('green'," \\\\\\")," |+| ",('green',"///")," http://wicd.net\n", -('green'," \\\\\\")," |+| ",('green',"///")," Brought to you by:\n", +('green'," \\\\\\")," |+| ",('green',"///")," ",language["brought_to_you"],"\n", ('green'," \\\\\\")," |+| ",('green',"///")," Adam Blackburn (wicd)\n", " ___|+|___ Dan O'Reilly (wicd)\n", " |---------| Andrew Psaltis (this ui)\n", @@ -262,13 +256,12 @@ def run_configscript(parent,netname,nettype): profname = netname if nettype == 'wired' else wireless.GetWirelessProperty( int(netname),'bssid') theText = [ - """To avoid various complications, wicd-curses does not support editing the scripts directly. However, you can edit them manually. First, (as root)", open the "%s" config file, and look for the section labeled by the %s in question. For example, this network is: + language['cannot_edit_scripts_1'].replace('$A',configfile).replace('$B',header), +"\n\n["+profname+"]\n\n", +# Translation needs to be changed to accomidate this text below. +"""You can also configure the wireless networks by looking for the "[]" field in the config file. -[%s] - -You can also configure the wireless networks by looking for the "[]" field in the config file. - -Once there, you can adjust (or add) the "beforescript", "afterscript", and "disconnectscript" variables as needed, to change the preconnect, postconnect, and disconnect scripts respectively. Note that you will be specifying the full path to the scripts - not the actual script contents. You will need to add/edit the script contents separately. Refer to the wicd manual page for more information.""" % (configfile,header,profname)] +Once there, you can adjust (or add) the "beforescript", "afterscript", and "disconnectscript" variables as needed, to change the preconnect, postconnect, and disconnect scripts respectively. Note that you will be specifying the full path to the scripts - not the actual script contents. You will need to add/edit the script contents separately. Refer to the wicd manual page for more information."""] dialog = TextDialog(theText,20,80) dialog.run(ui,parent) # This code works with many distributions, but not all of them. So, to @@ -349,7 +342,7 @@ class WiredComboBox(ComboBox): list : the list of wired network profiles. The rest is self-explanitory. """ def __init__(self,list): - self.ADD_PROFILE = '---Add a new profile---' + self.ADD_PROFILE = '---'+language["add_new_profile"]+'---' self.__super.__init__(use_enter=False) self.set_list(list) #self.set_focus(self.theList.index(wired.GetDefaultProfile())) @@ -390,7 +383,7 @@ class WiredComboBox(ComboBox): prev_focus = self.get_focus()[1] key = self.__super.keypress(size,key) if self.get_focus()[1] == len(self.list)-1: - dialog = InputDialog(('header',"Add a new wired profile"),7,30) + dialog = InputDialog(('header',language["add_new_wired_profile"]),7,30) exitcode,name = dialog.run(ui,self.parent) if exitcode == 0: @@ -402,7 +395,7 @@ class WiredComboBox(ComboBox): wired.ReadWiredNetworkProfile(self.get_selected_profile()) if key == 'delete': if len(self.theList) == 1: - error(self.ui,self.parent,"Cannot delete the last wired profile. Try renaming it ('F2')") + error(self.ui,self.parent,language["no_delete_last_profile"]) return key wired.DeleteWiredNetworkProfile(self.get_selected_profile()) # Return to the top of the list if something is deleted. @@ -415,7 +408,7 @@ class WiredComboBox(ComboBox): self.set_list(wired.GetWiredProfileList()) self.rebuild_combobox() if key == 'f2': - dialog = InputDialog(('header',"Rename wired profile"),7,30, + dialog = InputDialog(('header',language["rename_wired_profile"]),7,30, edit_text=unicode(self.get_selected_profile())) exitcode,name = dialog.run(ui,self.parent) if exitcode == 0: @@ -505,7 +498,7 @@ class appGUI(): # Will need a translation sooner or later self.screen_locker = urwid.Filler(urwid.Text(('important',language['scanning_stand_by']), align='center')) self.no_wlan = urwid.Filler(urwid.Text(('important',language['no_wireless_networks_found']), align='center')) - self.TITLE = 'Wicd Curses Interface' + self.TITLE = language['wicd_curses'] self.WIRED_IDX = 1 self.WLESS_IDX = 3 @@ -573,7 +566,7 @@ class appGUI(): self.update_ui() def raise_hidden_network_dialog(self): - dialog = InputDialog(('header','Select Hidden Network ESSID'),7,30,'Scan') + dialog = InputDialog(('header',language["select_hidden_essid"]),7,30,language['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 @@ -736,8 +729,8 @@ class appGUI(): #if self.special != None: # theText += self.special if self.connecting: - theText += "-- Connecting -- Press ESC to cancel " - quit_note = "-- Press F8 or Q to quit." + theText += "-- "+language['connecting']+' -- '+language["esc_to_cancel"] + quit_note = language["press_to_quit"] self.footer1 = urwid.Text(str(self.incr) + theText+quit_note,wrap='clip') self.incr+=1 return True @@ -944,8 +937,7 @@ def setup_dbus(force=True): except DBusException: # I may need to be a little more verbose here. # Suggestions as to what should go here, please? - print "Can't connect to the daemon. Are you sure it is running?" - print "Please check the wicd log for error messages." + print language['cannot_connect_to_daemon'] #raise # return False # <- Will need soon. bus = dbusmanager.get_bus() diff --git a/setup.py b/setup.py index 032029b..51da700 100755 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ import subprocess # VERSIONNUMBER VERSION_NUM = '1.6.0' REVISION_NUM = 'unknown' -CURSES_REVNO = 'r260' +CURSES_REVNO = 'r266' try: if not os.path.exists('vcsinfo.py'): diff --git a/wicd/misc.py b/wicd/misc.py index 18cd838..3c4e238 100644 --- a/wicd/misc.py +++ b/wicd/misc.py @@ -567,6 +567,11 @@ def get_language_list_gui(): language["esc_to_cancel"] = _("Press ESC to cancel") language["press_to_quit"] = _("Press F8 or Q to quit.") + language['terminated'] = _("Terminated by user") + language['wicd_curses'] = _("Wicd Curses Interface") + language['dbus_fail'] = _("DBus failure! This is most likely caused by the wicd daemon stopping while wicd-curses is running. Please restart the daemon, and then restart wicd-curses.") + + return language def get_language_list_tray(): From b86ec8667c4c1b3be98bcb428c9b2d392dacd1ee Mon Sep 17 00:00:00 2001 From: Andrew Psaltis Date: Sat, 31 Jan 2009 02:07:50 -0500 Subject: [PATCH 50/50] curses/wicd-curses.py: Made the tagged wireless network actually show the network we're connected to, or not, as the case may be. Added ' -- ' to the upper statusbar Also, in the last commit, configscript_curses should be netentry_curses --- curses/wicd-curses.py | 4 ++-- setup.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index a8fb3c8..1b59b54 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -204,7 +204,7 @@ def gen_network_list(): wlessL = [] # This one makes a list of NetLabels for network_id in range(0, wireless.GetNumberOfNetworks()): - is_active = wireless.GetCurrentSignalStrength("") != 0 and wireless.GetCurrentNetworkID(wireless.GetIwconfig())==network_id + is_active = wireless.GetCurrentSignalStrength("") != 0 and wireless.GetCurrentNetworkID(wireless.GetIwconfig())==network_id and wireless.GetWirelessIP('') != None label = NetLabel(network_id,is_active) wlessL.append(label) @@ -730,7 +730,7 @@ class appGUI(): # theText += self.special if self.connecting: theText += "-- "+language['connecting']+' -- '+language["esc_to_cancel"] - quit_note = language["press_to_quit"] + quit_note = ' -- '+language["press_to_quit"] self.footer1 = urwid.Text(str(self.incr) + theText+quit_note,wrap='clip') self.incr+=1 return True diff --git a/setup.py b/setup.py index 51da700..2cd9e0c 100755 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ import subprocess # VERSIONNUMBER VERSION_NUM = '1.6.0' REVISION_NUM = 'unknown' -CURSES_REVNO = 'r266' +CURSES_REVNO = 'r269' try: if not os.path.exists('vcsinfo.py'):