Primitivus: profile manager

- new custom widgets: Password, List, GenericDialog, InputDialog, ConfirmationDialog
This commit is contained in:
Goffi 2010-07-01 15:35:56 +08:00
commit ab067174ff
4 changed files with 256 additions and 6 deletions

View file

@ -0,0 +1,179 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Primitivus: a SAT frontend
Copyright (C) 2009, 2010 Jérôme Poisson (goffi@goffi.org)
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 3 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, see <http://www.gnu.org/licenses/>.
"""
import urwid
class Password(urwid.Edit):
def __init__(self, *args, **kwargs):
self.hidden_char=kwargs['hidden_char'] if kwargs.has_key('hidden_char') else '*'
self.__real_text=''
super(Password, self).__init__(*args, **kwargs)
def set_edit_text(self, text):
self.__real_text = text
hidden_txt = len(text)*'*'
super(Password, self).set_edit_text(hidden_txt)
def get_edit_text(self):
return self.__real_text
class SelectableText(urwid.FlowWidget):
signals = ['change']
def __init__(self, text, align='left'):
self.text=unicode(text)
self.align = align
self.__selected=False
def getValue(self):
return self.text
def setState(self, selected, invisible=False):
"""Change state
@param selected: boolean state value
@param invisible: don't emit change signal if True"""
assert(type(selected)==bool)
self.__selected=selected
if not invisible:
self._emit("change", self.__selected)
self._invalidate()
def getState(self):
return self.__selected
def selectable(self):
return True
def keypress(self, size, key):
if key==' ' or key=='enter':
self.setState(not self.__selected)
else:
return key
def rows(self,size,focus=False):
return self.display_widget(size, focus).rows(size, focus)
def render(self, size, focus=False):
return self.display_widget(size, focus).render(size, focus)
def display_widget(self, size, focus):
attr = 'selected' if self.__selected else 'default'
if focus:
attr+="_focus"
return urwid.Text((attr,self.text), align=self.align)
class List(urwid.WidgetWrap):
signals = ['change']
def __init__(self, options, style=[], align='left', on_state_change=None, user_data=None):
assert(options)
self.single = 'single' in style
self.align = align
if on_state_change:
urwid.connect_signal(self, 'change', on_state_change, user_data)
widgets = [SelectableText(option,align) for option in options]
for widget in widgets:
urwid.connect_signal(widget, 'change', self.__onStateChange)
self.content = urwid.SimpleListWalker(widgets)
self.list_box = urwid.ListBox(self.content)
if self.single:
self.content[0].setState(True)
display_widget = urwid.BoxAdapter(self.list_box, min(len(options),5))
urwid.WidgetWrap.__init__(self, display_widget)
def __onStateChange(self, widget, selected):
if self.single:
if not selected:
#if in single mode, it's forbidden to unselect a value
widget.setState(True, invisible=True)
return
else:
self.unselectAll(invisible=True)
widget.setState(True, invisible=True)
self._emit("change")
def unselectAll(self, invisible=False):
for widget in self.content:
if widget.getState():
widget.setState(False, invisible)
widget._invalidate()
def getValues(self):
result = []
for widget in self.content:
if widget.getState():
result.append(widget.getValue())
return result
def changeValues(self, new_values):
widgets = [SelectableText(self, option) for option in new_values]
self.content[:] = widgets
def selectValue(self, value):
self.unselectAll()
idx = 0
for widget in self.content:
if widget.getValue() == value:
widget.setState(True)
self.list_box.set_focus(idx)
return
idx+=1
class genericDialog(urwid.WidgetWrap):
def __init__(self, widgets_lst, title, style=[], **kwargs):
frame_header = urwid.AttrMap(urwid.Text(title,'center'),'title')
buttons = None
if "OK/CANCEL" in style:
buttons = [urwid.Button(_("Cancel"), kwargs['cancel_cb']),
urwid.Button(_("Ok"), kwargs['ok_cb'], kwargs['ok_value'])]
elif "YES/NO" in style:
buttons = [urwid.Button(_("Yes"), kwargs['yes_cb']),
urwid.Button(_("No"), kwargs['no_cb'], kwargs['yes_value'])]
if buttons:
buttons_flow = urwid.GridFlow(buttons, max([len(button.get_label()) for button in buttons])+4, 1, 1, 'center')
widgets_lst.append(buttons_flow)
body_content = urwid.SimpleListWalker(widgets_lst)
frame_body = urwid.ListBox(body_content)
frame = urwid.Frame(frame_body, frame_header)
decorated_frame = urwid.LineBox(frame)
urwid.WidgetWrap.__init__(self, decorated_frame)
class InputDialog(genericDialog):
def __init__(self, title, instrucions, style=['OK/CANCEL'], **kwargs):
instr_wid = urwid.Text(instrucions+':')
edit_box = urwid.Edit()
genericDialog.__init__(self, [instr_wid,edit_box], title, style, ok_value=edit_box, **kwargs)
class ConfirmDialog(genericDialog):
def __init__(self, title, style=['YES/NO'], **kwargs):
genericDialog.__init__(self, [], title, style, yes_value=None, **kwargs)

View file

@ -51,7 +51,12 @@ logging.basicConfig(level=logging.CRITICAL, #TODO: configure it to put messages
###
const_APP_NAME = "Primitivus"
const_PALETTE = [('title', 'black', 'light gray', 'standout,underline'),]
const_PALETTE = [('title', 'black', 'light gray', 'standout,underline'),
('selected', 'default', 'dark red'),
('selected_focus', 'default,bold', 'dark red'),
('default', 'default', 'default'),
('default_focus', 'default,bold', 'default'),
]
class PrimitivusApp(QuickApp):
@ -70,6 +75,7 @@ class PrimitivusApp(QuickApp):
raise urwid.ExitMainLoop()
def __buildMainWidget(self):
#main_widget = urwid.Filler(ProfileManager(self))
main_widget = ProfileManager(self)
return main_widget

View file

@ -20,15 +20,81 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import urwid
from custom_widgets import Password,List,InputDialog,ConfirmDialog
class ProfileManager(urwid.WidgetWrap):
def __init__(self, host):
self.host = host
#profiles list
profiles = self.host.bridge.getProfilesList()
widgets = [urwid.Text(str(profiles))]
content = urwid.SimpleListWalker(widgets)
display_widget = urwid.Frame(urwid.ListBox(content),urwid.AttrMap(urwid.Text("Profile Manager",align='center'),'title'))
urwid.WidgetWrap.__init__(self, display_widget)
profiles.sort()
#login & password box must be created before list because of onProfileChange
self.login_wid = urwid.Edit(_('Login:'),align='center')
self.pass_wid = Password(_('Password:'),align='center')
self.list_profile = List(profiles, style=['single'], align='center', on_state_change=self.onProfileChange)
#toto = urwid.Padding(urwid.Text('toto'), align='center')
#new & delete buttons
buttons = [urwid.Button(_("New"), self.onNewProfile),
urwid.Button(_("Delete"), self.onDeleteProfile)]
buttons_flow = urwid.GridFlow(buttons, max([len(button.get_label()) for button in buttons])+4, 1, 1, 'center')
#second part: login information:
divider = urwid.Divider('-')
#connect button
connect_button = urwid.Button(_("Connect"), self.onConnectProfile)
#we now build the widget
body_content = urwid.SimpleListWalker([buttons_flow,self.list_profile,divider,self.login_wid, self.pass_wid, connect_button])
frame_body = urwid.ListBox(body_content)
frame = urwid.Frame(frame_body,urwid.AttrMap(urwid.Text("Profile Manager",align='center'),'title'))
self.main_widget = urwid.LineBox(frame)
urwid.WidgetWrap.__init__(self, self.main_widget)
def __refillProfiles(self):
"""Update the list of profiles"""
profiles = self.host.bridge.getProfilesList()
profiles.sort()
self.list_profile.changeValues(profiles)
def cancelDialog(self, button):
self._set_w(self.main_widget)
def newProfile(self, button, edit):
self._set_w(self.main_widget)
name = edit.get_edit_text()
self.host.bridge.createProfile(name)
self.__refillProfiles()
self.list_profile.selectValue(name)
def deleteProfile(self, button):
self._set_w(self.main_widget)
self.host.bridge.deleteProfile(self.list_profile.getValues()[0])
self.__refillProfiles()
def onNewProfile(self, e):
pop_up_widget = InputDialog(_("New profile"), _("Please enter a new profile name"), cancel_cb=self.cancelDialog, ok_cb=self.newProfile)
display_widget = urwid.Overlay(pop_up_widget, self.main_widget, 'center', ('relative', 40), 'middle', ('relative', 40))
self._set_w(display_widget)
def onDeleteProfile(self, e):
pop_up_widget = ConfirmDialog(_("Are you sure you want to delete the profile %s ?") % self.list_profile.getValues()[0], no_cb=self.cancelDialog, yes_cb=self.deleteProfile)
display_widget = urwid.Overlay(pop_up_widget, self.main_widget, 'center', ('relative', 40), 'middle', ('relative', 40))
self._set_w(display_widget)
def onProfileChange(self, list_wid):
profile_name = list_wid.getValues()[0]
jabberID = self.host.bridge.getParamA("JabberID", "Connection", profile_key=profile_name)
password = self.host.bridge.getParamA("Password", "Connection", profile_key=profile_name)
self.login_wid.set_edit_text(jabberID)
self.pass_wid.set_edit_text(password)
def onConnectProfile(self, button):
pass

View file

@ -138,7 +138,6 @@ class ProfileManager(wx.Panel):
old_pass = self.host.bridge.getParamA("Password", "Connection", profile_key=profile)
new_jid = self.login_jid.GetValue()
new_pass = self.login_pass.GetValue()
print "old: %s, new: %s, old_pass: %s, new_pass: %s" % (old_jid, new_jid, old_pass, new_pass)
if old_jid != new_jid:
debug(_('Saving new JID and server'))
self.host.bridge.setParam("JabberID", new_jid, "Connection", profile)