Refactor uwldap constants
[public/pyceo-broken.git] / ceo / urwid / widgets.py
1 import urwid, ldap
2 from ceo.urwid.window import raise_back, push_window
3 import ceo.ldapi as ldapi
4
5 csclub_uri = "ldap://ldap1.csclub.uwaterloo.ca/ ldap://ldap2.csclub.uwaterloo.ca"
6 csclub_base = "dc=csclub,dc=uwaterloo,dc=ca"
7
8 def menu_items(items):
9     return [ urwid.AttrWrap( ButtonText( cb, data, txt ), 'menu', 'selected') for (txt, cb, data) in items ]
10
11 def push_wizard(name, pages, dimensions=(50, 10)):
12     state = {}
13     wiz = Wizard()
14     for page in pages:
15         if type(page) != tuple:
16             page = (page, )
17         wiz.add_panel( page[0](state, *page[1:]) )
18     push_window( urwid.Filler( urwid.Padding(
19         urwid.LineBox(wiz), 'center', dimensions[0]),
20         'middle', dimensions[1] ), name )
21
22 class ButtonText(urwid.Text):
23     def __init__(self, callback, data, *args, **kwargs):
24         self.callback = callback
25         self.data = data
26         urwid.Text.__init__(self, *args, **kwargs)
27     def selectable(self):
28         return True
29     def keypress(self, size, key):
30         if key == 'enter' and self.callback:
31             self.callback(self.data)
32         else:
33             return key
34
35 class SingleEdit(urwid.Edit):
36     def keypress(self, size, key):
37         if key == 'enter':
38             return urwid.Edit.keypress(self, size, 'down')
39         else:
40             return urwid.Edit.keypress(self, size, key)
41
42 class SingleIntEdit(urwid.IntEdit):
43     def keypress(self, size, key):
44         if key == 'enter':
45             return urwid.Edit.keypress(self, size, 'down')
46         else:
47             return urwid.Edit.keypress(self, size, key)
48
49 class WordEdit(SingleEdit):
50     def valid_char(self, ch):
51         return urwid.Edit.valid_char(self, ch) and ch != ' '
52
53 class LdapWordEdit(WordEdit):
54     ldap = None
55     index = None
56
57     def __init__(self, uri, base, attr, *args):
58         try:
59             self.ldap = ldap.initialize(uri)
60             self.ldap.simple_bind_s("", "")
61         except ldap.LDAPError:
62             return WordEdit.__init__(self, *args)
63         self.base = base
64         self.attr = ldapi.escape(attr)
65         return WordEdit.__init__(self, *args)
66
67     def keypress(self, size, key):
68         if (key == 'tab' or key == 'shift tab') and self.ldap != None:
69             if self.index != None:
70                 if key == 'tab':
71                     self.index = (self.index + 1) % len(self.choices)
72                 elif key == 'shift tab':
73                     self.index = (self.index - 1) % len(self.choices)
74                 text = self.choices[self.index]
75                 self.set_edit_text(text)
76                 self.set_edit_pos(len(text))
77             else:
78                 try:
79                     text = self.get_edit_text()
80                     search = ldapi.escape(text)
81                     matches = self.ldap.search_s(self.base,
82                         ldap.SCOPE_SUBTREE, '(%s=%s*)' % (self.attr, search))
83                     self.choices = [ text ]
84                     for match in matches:
85                         (_, attrs) = match
86                         self.choices += attrs['uid']
87                     self.choices.sort()
88                     self.index = 0
89                     self.keypress(size, key)
90                 except ldap.LDAPError, e:
91                     pass
92         else:
93             self.index = None
94             return WordEdit.keypress(self, size, key)
95
96 class LdapFilterWordEdit(LdapWordEdit):
97     def __init__(self, uri, base, attr, map, *args):
98         LdapWordEdit.__init__(self, uri, base, attr, *args)
99         self.map = map
100     def keypress(self, size, key):
101         if self.ldap != None:
102             if key == 'enter' or key == 'down' or key == 'up':
103                 search = ldapi.escape(self.get_edit_text())
104                 try:
105                     matches = self.ldap.search_s(self.base,
106                         ldap.SCOPE_SUBTREE, '(%s=%s)' % (self.attr, search))
107                     if len(matches) > 0:
108                         (_, attrs) = matches[0]
109                         for (k, v) in self.map.items():
110                             if attrs.has_key(k) and len(attrs[k]) > 0:
111                                 v.set_edit_text(attrs[k][0])
112                 except ldap.LDAPError:
113                     pass
114         return LdapWordEdit.keypress(self, size, key)
115
116 class PassEdit(SingleEdit):
117     def get_text(self):
118         text = urwid.Edit.get_text(self)
119         return (self.caption + " " * len(self.get_edit_text()), text[1])
120
121 class Wizard(urwid.WidgetWrap):
122     def __init__(self):
123         self.selected = None
124         self.panels = []
125
126         self.panelwrap = urwid.WidgetWrap( urwid.SolidFill() )
127         self.back = urwid.Button("Back", self.back)
128         self.next = urwid.Button("Next", self.next)
129         self.buttons = urwid.Columns( [ self.back, self.next ], dividechars=3, focus_column=1 )
130         pad = urwid.Padding( self.buttons, ('fixed right', 2), 19 )
131         self.pile = urwid.Pile( [self.panelwrap, ('flow', pad)], 0 )
132         urwid.WidgetWrap.__init__(self, self.pile)
133
134     def add_panel(self, panel):
135         self.panels.append( panel )
136         if len(self.panels) == 1:
137             self.select(0)
138
139     def select(self, panelno, set_focus=True):
140         if 0 <= panelno < len(self.panels):
141             self.selected = panelno
142             self.panelwrap.set_w( self.panels[panelno] )
143             self.panels[panelno].activate()
144
145             if set_focus:
146                 if self.panels[panelno].focusable():
147                     self.pile.set_focus( 0 )
148                 else:
149                     self.pile.set_focus( 1 )
150
151     def next(self, *args, **kwargs):
152         if self.panels[self.selected].check():
153             self.select( self.selected )
154             return
155         self.select(self.selected + 1)
156
157     def back(self, *args, **kwargs):
158         if self.selected == 0:
159             raise_back()
160         self.select(self.selected - 1, False)
161
162 class WizardPanel(urwid.WidgetWrap):
163     def __init__(self, state):
164         self.state = state
165         self.init_widgets()
166         self.box = urwid.ListBox( urwid.SimpleListWalker( self.widgets ) )
167         urwid.WidgetWrap.__init__( self, self.box )
168     def init_widgets(self):
169         self.widgets = []
170     def focus_widget(self, widget):
171         self.box.set_focus( self.widgets.index( widget ) )
172     def focusable(self):
173         return True
174     def check(self):
175         return
176     def activate(self):
177         return