[node-patches] Change in ovirt-node[master]: Add and improve several modules
fabiand at fedoraproject.org
fabiand at fedoraproject.org
Tue Dec 11 20:09:32 UTC 2012
Fabian Deutsch has uploaded a new change for review.
Change subject: Add and improve several modules
......................................................................
Add and improve several modules
Change-Id: Ibe9d524ab38b006e2bc3f521fa560288a19f0f95
Signed-off-by: Fabian Deutsch <fabiand at fedoraproject.org>
---
M scripts/tui/src/app
A scripts/tui/src/ovirt/node/app.py
A scripts/tui/src/ovirt/node/main.py
M scripts/tui/src/ovirt/node/plugins/__init__.py
M scripts/tui/src/ovirt/node/plugins/example.py
M scripts/tui/src/ovirt/node/tui.py
A scripts/tui/src/ovirt/node/utils.py
A scripts/tui/src/ovirt/node/widgets.py
8 files changed, 450 insertions(+), 211 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/ovirt-node refs/changes/67/9867/1
diff --git a/scripts/tui/src/app b/scripts/tui/src/app
index b4cbd9d..1ea2e40 100755
--- a/scripts/tui/src/app
+++ b/scripts/tui/src/app
@@ -1,3 +1,3 @@
#!/bin/bash
-PYTHONPATH=$PYTHONPATH:. python -B -m ovirt.node.tui "$@"
+PYTHONPATH=$PYTHONPATH:. python -B -m ovirt.node.main "$@"
diff --git a/scripts/tui/src/ovirt/node/app.py b/scripts/tui/src/ovirt/node/app.py
new file mode 100644
index 0000000..d362575
--- /dev/null
+++ b/scripts/tui/src/ovirt/node/app.py
@@ -0,0 +1,39 @@
+"""
+Representing the whole application (not just the TUI).
+Basically the application consists of two parts: Plugins and TUI
+which communicate with each other.
+"""
+
+import logging
+
+import ovirt.node.tui
+
+logging.basicConfig(level=logging.DEBUG,
+ filename="app.log", filemode="w")
+LOGGER = logging.getLogger(__name__)
+
+
+class Application(object):
+ plugins = []
+
+ ui = None
+
+ def __init__(self):
+ self.ui = ovirt.node.tui.UrwidTUI(self)
+
+ def __load_plugins(self):
+ self.plugins = [m.Plugin() for m in ovirt.node.plugins.load_all()]
+
+ for plugin in self.plugins:
+ LOGGER.debug("Loading plugin %s" % plugin)
+ self.ui.register_plugin(plugin.ui_name(), plugin)
+
+ def __drop_to_shell(self):
+ with self.ui.suspended():
+ ovirt.node.utils.system("reset ; bash")
+
+ def run(self):
+ self.__load_plugins()
+ self.ui.register_hotkey("f12", self.__drop_to_shell)
+ self.ui.footer = "Press ctrl+x or esc to quit."
+ self.ui.run()
diff --git a/scripts/tui/src/ovirt/node/main.py b/scripts/tui/src/ovirt/node/main.py
new file mode 100644
index 0000000..ec8d946
--- /dev/null
+++ b/scripts/tui/src/ovirt/node/main.py
@@ -0,0 +1,10 @@
+"""
+Create an application instance an start it.
+"""
+
+import ovirt.node.app
+
+
+if __name__ == '__main__':
+ app = ovirt.node.app.Application()
+ app.run()
diff --git a/scripts/tui/src/ovirt/node/plugins/__init__.py b/scripts/tui/src/ovirt/node/plugins/__init__.py
index f152529..0fb7c91 100644
--- a/scripts/tui/src/ovirt/node/plugins/__init__.py
+++ b/scripts/tui/src/ovirt/node/plugins/__init__.py
@@ -79,6 +79,26 @@
A dict of validators
"""
+ def validate(self, path, value):
+ """Validates a value against the validator of a given path
+
+ Args:
+ path: A model path for a validator
+ value: The value to be validated
+
+ Returns:
+ True on a valid value or if there is no validator for a path
+
+ Raises:
+ InvalidData on any invalid data
+ """
+ if path in self.validators():
+ msg = self.validators()[path](value)
+ # True and None are allowed values
+ if msg not in [True, None]:
+ raise ovirt.node.plugins.InvalidData(msg)
+ return True
+
def has_ui(self):
"""Determins if a page for this should be displayed in the UI
@@ -152,55 +172,100 @@
class Widget(object):
- _enabled = True
- _signals = None
+ _signal_cbs = None
+ signals = []
+ signaling_properties = []
- def enabled(self, is_enabled=None):
- if is_enabled in [True, False]:
- self.emit_signal("enabled[change]", is_enabled)
- self._enabled = is_enabled
- return self._enabled
+ def __init__(self):
+ """Registers all widget signals.
+ All signals must be given in self.signals
+ """
+ for name in self.signals:
+ self._register_signal(name)
+ for name in self.signaling_properties:
+ self._register_signaling_property(name)
+
+ def _register_signal(self, name):
+ """Each signal that get's emitted must be registered using this
+ function.
+
+ This is just to have an overview over the signals.
+ """
+ if self._signal_cbs is None:
+ self._signal_cbs = {}
+ if name not in self._signal_cbs:
+ self._signal_cbs[name] = []
+# LOGGER.debug("Registered new signal '%s' for '%s'" % (name, self))
def connect_signal(self, name, cb):
- if self._signals is None:
- self._signals = {}
- if name not in self._signals:
- self._signals[name] = []
- self._signals[name].append(cb)
+ """Connect an callback to a signal
+ """
+ assert name in self._signal_cbs, "Unregistered signal '%s'" % name
+ self._signal_cbs[name].append(cb)
def emit_signal(self, name, userdata=None):
- if self._signals is None or \
- name not in self._signals:
+ """Emit a signal
+ """
+ if self._signal_cbs is None or name not in self._signal_cbs:
return False
- for cb in self._signals[name]:
+ for cb in self._signal_cbs[name]:
LOGGER.debug("CB for sig %s: %s" % (name, cb))
cb(self, userdata)
+
+ def _register_signaling_property(self, name):
+ LOGGER.debug("Registered new property '%s' for '%s'" % (name, self))
+ if "_%s" % name not in self.__dict__:
+ self.__dict__["_%s" % name] = None
+ self._register_signal("%s[change]" % name)
+
+ def _signaling_property(self, name, valid_value_cb, new_value):
+ if valid_value_cb():
+ self.emit_signal("%s[change]" % name, new_value)
+ self.__dict__["_%s" % name] = new_value
+ return self.__dict__["_%s" % name]
+
+class InputWidget(Widget):
+ signaling_properties = ["enabled"]
+
+ def enabled(self, is_enabled=None):
+ return self._signaling_property("enabled", \
+ lambda: is_enabled in [True, False],
+ is_enabled)
class Label(Widget):
"""Represents a r/o label
"""
- def __init__(self, label):
- self.label = label
+ signaling_properties = ["text"]
+ def __init__(self, text):
+ self._text = text
+ super(Label, self).__init__()
+
+ def text(self, value=None):
+ return self._signaling_property("text", \
+ lambda: value != None,
+ value)
class Header(Label):
pass
-class Entry(Widget):
+class Entry(InputWidget):
"""Represents an entry field
TODO multiline
"""
+
def __init__(self, label, value=None, initial_value_from_model=True,
enabled=True):
self.label = label
self.value = value
self.initial_value_from_model = initial_value_from_model
self._enabled = enabled
+ super(Entry, self).__init__()
-class Password(Entry):
+class PasswordEntry(Entry):
pass
diff --git a/scripts/tui/src/ovirt/node/plugins/example.py b/scripts/tui/src/ovirt/node/plugins/example.py
index fc4150b..fbb28a8 100644
--- a/scripts/tui/src/ovirt/node/plugins/example.py
+++ b/scripts/tui/src/ovirt/node/plugins/example.py
@@ -7,7 +7,7 @@
import ovirt.node.plugins
import ovirt.node.valid
-from ovirt.node.plugins import Header, Entry, Password
+from ovirt.node.plugins import Header, Entry, PasswordEntry
LOGGER = logging.getLogger(__name__)
@@ -48,7 +48,7 @@
("foo.section", Header("Subsection")),
("foo.hostname", Entry(label="Hostname")),
("foo.port", Entry(label="Port")),
- ("foo.password", Password(label="Password")),
+ ("foo.password", PasswordEntry(label="Password")),
]
self._widgets = dict(widgets)
return widgets
@@ -57,28 +57,29 @@
"""Applies the changes to the plugins model, will do all required logic
"""
LOGGER.debug("checking %s" % changes)
- if "foo.bar" in changes:
- LOGGER.debug("Found foo.bar")
+ if "foo.hostname" in changes:
+ LOGGER.debug("Found foo.hostname")
- if "/" in changes["foo.bar"]:
+ if "/" in changes["foo.hostname"]:
raise ovirt.node.plugins.InvalidData("No slash allowed")
- if len(changes["foo.bar"]) < 5:
+ if len(changes["foo.hostname"]) < 5:
raise ovirt.node.plugins.Concern("Should be at least 5 chars")
self._model.update(changes)
- if "dis" in changes["foo.bar"]:
- self._widgets["foo.bar2"].enabled(False)
+ if "dis" in changes["foo.hostname"]:
+ self._widgets["foo.port"].enabled(False)
LOGGER.debug("change to dis")
+ self._widgets["foo.section"].text(changes["foo.hostname"])
#raise ovirt.node.plugins.ContentRefreshRequest()
else:
- self._widgets["foo.bar2"].enabled(True)
+ self._widgets["foo.port"].enabled(True)
- if "foo.bar2" in changes:
- LOGGER.debug("Found foo.bar2")
+ if "foo.port" in changes:
+ LOGGER.debug("Found foo.port")
- if "/" in changes["foo.bar2"]:
+ if "/" in changes["foo.port"]:
raise ovirt.node.plugins.InvalidData("No slashes allowed")
return True
diff --git a/scripts/tui/src/ovirt/node/tui.py b/scripts/tui/src/ovirt/node/tui.py
index c412f2e..6ac711c 100644
--- a/scripts/tui/src/ovirt/node/tui.py
+++ b/scripts/tui/src/ovirt/node/tui.py
@@ -3,90 +3,18 @@
import urwid
import logging
-import os
import ovirt.node
+import ovirt.node.widgets
import ovirt.node.plugins
+import ovirt.node.utils
-
-logging.basicConfig(level=logging.DEBUG,
- filename="app.log", filemode="w")
LOGGER = logging.getLogger(__name__)
-class SelectableText(urwid.Text):
- """A Text widget that can be selected to be highlighted
- """
- def selectable(self):
- return True
-
- def keypress(self, size, key):
- return key
-
-
-class PluginMenuEntry(urwid.AttrMap):
- """An entry in the main menu
- """
- __text = None
-
- def __init__(self, title, plugin):
- self.__text = SelectableText(title)
- self.__text.plugin = plugin
- super(PluginMenuEntry, self).__init__(self.__text, 'menu.entry',
- 'menu.entry:focus')
-
-
-class PluginMenu(urwid.WidgetWrap):
- """The main menu listing all available plugins (which have a UI)
- """
- __pages = None
- __walker = None
- __list = None
- __list_attrmap = None
- __linebox = None
- __linebox_attrmap = None
-
- signals = ['changed']
-
- def __init__(self, pages):
- self.__pages = pages
- self.__build_walker()
- self.__build_list()
- self.__build_linebox()
- super(PluginMenu, self).__init__(self.__linebox_attrmap)
-
- def __build_walker(self):
- items = []
- for title, plugin in self.__pages.items():
- if plugin.has_ui():
- item = PluginMenuEntry(title, plugin)
- items.append(item)
- else:
- LOGGER.warning("No UI page for plugin %s" % plugin)
- self.__walker = urwid.SimpleListWalker(items)
-
- def __build_list(self):
- self.__list = urwid.ListBox(self.__walker)
-
- def __on_item_change():
- widget, position = self.__list.get_focus()
- plugin = widget.original_widget.plugin
- urwid.emit_signal(self, "changed", plugin)
-
- urwid.connect_signal(self.__walker, 'modified', __on_item_change)
-
- self.__list_attrmap = urwid.AttrMap(self.__list, "main.menu")
-
- def __build_linebox(self):
- self.__linebox = urwid.LineBox(self.__list_attrmap)
- self.__linebox_attrmap = urwid.AttrMap(self.__linebox,
- "main.menu.frame")
-
- def set_focus(self, n):
- self.__list.set_focus(n)
-
-
class UrwidTUI(object):
+ app = None
+
__pages = {}
__hotkeys = {}
@@ -105,16 +33,17 @@
('main.menu.frame', 'light gray', ''),
('plugin.widget.entry', 'dark gray', ''),
('plugin.widget.entry.frame', 'light gray', ''),
- ('plugin.widget.disabled', 'light gray', 'dark gray'),
+ ('plugin.widget.disabled', 'dark gray', 'light gray'),
('plugin.widget.notice', 'light red', ''),
('plugin.widget.header', 'light blue', 'light gray'),
]
- def __init__(self):
- pass
+ def __init__(self, app):
+ LOGGER.info("Creating urwid tui for '%s'" % app)
+ self.app = app
def __build_menu(self):
- self.__menu = PluginMenu(self.__pages)
+ self.__menu = ovirt.node.widgets.PluginMenu(self.__pages)
def menu_item_changed(plugin):
self.__change_to_page(plugin)
@@ -132,78 +61,58 @@
return urwid.Frame(body, header, footer)
def __build_widget_for_item(self, plugin, path, item):
+ item_to_widget_map = {
+ ovirt.node.plugins.Label: ovirt.node.widgets.Label,
+ ovirt.node.plugins.Header: ovirt.node.widgets.Header,
+ ovirt.node.plugins.Entry: ovirt.node.widgets.Entry,
+ ovirt.node.plugins.PasswordEntry: ovirt.node.widgets.PasswordEntry
+ }
+
+ assert type(item) in item_to_widget_map.keys(), \
+ "No widget for item type"
+
widget = None
+ widget_class = item_to_widget_map[type(item)]
- if type(item) is ovirt.node.plugins.Entry or \
- type(item) is ovirt.node.plugins.Password:
- label_text = urwid.Text("\n" + item.label + ":")
- label = label_text
- mask = None
- if type(item) is ovirt.node.plugins.Password:
- mask = "*"
- edit = urwid.Edit(mask=mask)
- edit_attrmap = urwid.AttrMap(edit, "plugin.widget.entry")
- linebox = urwid.LineBox(edit_attrmap)
- linebox_attrmap = urwid.AttrMap(linebox,
- "plugin.widget.entry.frame")
- entry = linebox_attrmap
- main_widget = urwid.Columns([label, entry])
-
- notice_text = urwid.Text("")
- notice_attrmap = urwid.AttrMap(notice_text, "plugin.widget.notice")
- notice_widget = notice_attrmap
-
- widget = urwid.Pile([main_widget, notice_widget])
-
+ if type(item) in [ovirt.node.plugins.Entry, \
+ ovirt.node.plugins.PasswordEntry]:
+ value = None
if item.initial_value_from_model:
value = plugin.model()[path]
- if value:
- edit.set_edit_text(value)
- def on_change(widget, new_value):
- LOGGER.debug("Widget content changed for path '%s'" % path)
+ widget = widget_class(item.label, value)
+
+ def on_item_enabled_change_cb(w, v):
+ LOGGER.debug("Model changed, updating widget '%s': %s" % (w, v))
+ if widget.selectable() != v:
+ widget.enable(v)
+ item.connect_signal("enabled[change]", on_item_enabled_change_cb)
+
+ def on_widget_value_change(widget, new_value):
+ LOGGER.debug("Widget changed, updating model '%s'" % path)
try:
- if path in plugin.validators():
- msg = plugin.validators()[path](new_value)
- # True and None are allowed
- if msg not in [True, None]:
- raise ovirt.node.plugins.InvalidData(msg)
-
+ plugin.validate(path, new_value)
plugin._on_ui_change({path: new_value})
- notice_text.set_text("")
+ widget.notice = ""
except ovirt.node.plugins.Concern as e:
LOGGER.error("Concern when updating: %s" % e)
except ovirt.node.plugins.InvalidData as e:
- notice_text.set_text(e.message)
+ widget.notice = e.message
LOGGER.error("Invalid data when updating: %s" % e)
+ urwid.connect_signal(widget, 'change', on_widget_value_change)
- urwid.connect_signal(edit, 'change', on_change)
+ elif type(item) in [ovirt.node.plugins.Header, \
+ ovirt.node.plugins.Label]:
+ widget = widget_class(item.text())
- def foo(w, v):
- if edit.selectable() == v:
- return True
- else:
- edit.selectable = lambda: v
- LOGGER.debug("dissing")
- if v:
- edit_attrmap.set_attr_map({None: ""})
- else:
- edit_attrmap.set_attr_map({
- None: "plugin.widget.disabled"
- })
- item.connect_signal("enabled[change]", foo)
-
- elif type(item) is ovirt.node.plugins.Header:
- label = urwid.Text("\n %s\n" % item.label)
- label_attrmap = urwid.AttrMap(label, "plugin.widget.header")
- widget = label_attrmap
-
- elif type(item) is ovirt.node.plugins.Label:
- label = urwid.Text(item.label)
- widget = urwid.AttrMap(label, "plugin.widget.label")
+ def on_item_text_change_cb(w, v):
+ LOGGER.debug("Model changed, updating widget '%s': %s" % (w, v))
+# widget.text(v)
+ self.popup("foo")
+ item.connect_signal("text[change]", on_item_text_change_cb)
return widget
@@ -234,7 +143,15 @@
def __filter_hotkeys(self, keys, raw):
key = str(keys)
LOGGER.debug("Keypress: %s" % key)
+ if type(self.__loop.widget) is ovirt.node.widgets.ModalDialog:
+ LOGGER.debug("Modal dialog escape: %s" % key)
+ dialog = self.__loop.widget
+ if dialog.escape_key in keys:
+ self.__loop.widget = dialog.previous_widget
+ return
+
if key in self.__hotkeys.keys():
+ LOGGER.debug("Running hotkeys: %s" % key)
self.__hotkeys[key]()
return keys
@@ -245,18 +162,9 @@
def popup(self, msg=None, buttons=None):
LOGGER.debug("Launching popup")
- class Dialog(urwid.PopUpLauncher):
-
- def create_pop_up(self):
- return urwid.Filler(urwid.Text("Fooo"))
-
- def get_pop_up_parameters(self):
- return {'left': 0,
- 'top': 1,
- 'overlay_width': 30,
- 'overlay_height': 4}
- dialog = Dialog(self.__page_frame)
- dialog.open_pop_up()
+ dialog = ovirt.node.widgets.ModalDialog(urwid.Filler(urwid.Text(msg)), "Title",
+ "esc", self.__loop.widget)
+ self.__loop.widget = dialog
def suspended(self):
"""Supspends the screen to do something in the foreground
@@ -300,34 +208,3 @@
self.palette,
input_filter=self.__filter_hotkeys)
self.__loop.run()
-
-
-class App(object):
- plugins = []
-
- ui = None
-
- def __init__(self, ui):
- self.ui = ui
-
- def __load_plugins(self):
- self.plugins = [m.Plugin() for m in ovirt.node.plugins.load_all()]
-
- for plugin in self.plugins:
- LOGGER.debug("Adding plugin %s" % plugin)
- self.ui.register_plugin(plugin.ui_name(), plugin)
-
- def __drop_to_shell(self):
- with self.ui.suspended():
- os.system("reset ; bash")
-
- def run(self):
- self.__load_plugins()
- self.ui.register_hotkey("f12", self.__drop_to_shell)
- self.ui.footer = "Press ctrl+x or esc to quit."
- self.ui.run()
-
-if __name__ == '__main__':
- ui = UrwidTUI()
- app = App(ui)
- app.run()
diff --git a/scripts/tui/src/ovirt/node/utils.py b/scripts/tui/src/ovirt/node/utils.py
new file mode 100644
index 0000000..bd6b070
--- /dev/null
+++ b/scripts/tui/src/ovirt/node/utils.py
@@ -0,0 +1,57 @@
+"""
+Some convenience functions
+"""
+
+import subprocess
+import logging
+
+LOGGER = logging.getLogger(__name__)
+
+
+def popen_closefds(*args, **kwargs):
+ """subprocess.Popen wrapper to not leak file descriptors
+
+ Args:
+ cmd: Cmdline to be run
+
+ Returns:
+ Popen object
+ """
+ kwargs.update({
+ "close_fds": True
+ })
+ return subprocess.Popen(*args, **kwargs)
+
+
+def system(cmd):
+ """Run a non-interactive command, or where the user shall input something
+
+ Args:
+ cmd: Cmdline to be run
+
+ Returns:
+ retval of the process
+ """
+ return popen_closefds(cmd, shell=True).wait()
+
+
+def pipe(cmd, stdin=None):
+ """Run a command interactively and cath it's output.
+ This functions allows to pass smoe input to a running command.
+
+ Args:
+ cmd: Commandline to be run
+
+ Returns:
+ A tuple (success, stdout)
+ """
+
+ LOGGER.debug("run '%s'" % cmd)
+ system_cmd = popen_closefds(cmd, shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ stdout, stderr = system_cmd.communicate(stdin)
+ if stdout:
+ LOGGER.debug("out '%s'" % stdout)
+ if stderr:
+ LOGGER.warning("error '%s'" % stderr)
+ return (system_cmd.returncode == 0, stdout)
diff --git a/scripts/tui/src/ovirt/node/widgets.py b/scripts/tui/src/ovirt/node/widgets.py
new file mode 100644
index 0000000..471841d
--- /dev/null
+++ b/scripts/tui/src/ovirt/node/widgets.py
@@ -0,0 +1,190 @@
+"""
+Widgets for oVirt Node's urwid TUI
+"""
+import urwid
+import logging
+
+LOGGER = logging.getLogger(__name__)
+
+
+class SelectableText(urwid.Text):
+ """A Text widget that can be selected to be highlighted
+ """
+ def selectable(self):
+ return True
+
+ def keypress(self, size, key):
+ return key
+
+
+class PluginMenuEntry(urwid.AttrMap):
+ """An entry in the main menu
+ """
+ __text = None
+
+ def __init__(self, title, plugin):
+ self.__text = SelectableText(title)
+ self.__text.plugin = plugin
+ super(PluginMenuEntry, self).__init__(self.__text, 'menu.entry',
+ 'menu.entry:focus')
+
+
+class PluginMenu(urwid.WidgetWrap):
+ """The main menu listing all available plugins (which have a UI)
+ """
+ __pages = None
+ __walker = None
+ __list = None
+ __list_attrmap = None
+ __linebox = None
+ __linebox_attrmap = None
+
+ signals = ['changed']
+
+ def __init__(self, pages):
+ self.__pages = pages
+ self.__build_walker()
+ self.__build_list()
+ self.__build_linebox()
+ super(PluginMenu, self).__init__(self.__linebox_attrmap)
+
+ def __build_walker(self):
+ items = []
+ for title, plugin in self.__pages.items():
+ if plugin.has_ui():
+ item = PluginMenuEntry(title, plugin)
+ items.append(item)
+ else:
+ LOGGER.warning("No UI page for plugin %s" % plugin)
+ self.__walker = urwid.SimpleListWalker(items)
+
+ def __build_list(self):
+ self.__list = urwid.ListBox(self.__walker)
+
+ def __on_item_change():
+ widget, position = self.__list.get_focus()
+ plugin = widget.original_widget.plugin
+ urwid.emit_signal(self, "changed", plugin)
+
+ urwid.connect_signal(self.__walker, 'modified', __on_item_change)
+
+ self.__list_attrmap = urwid.AttrMap(self.__list, "main.menu")
+
+ def __build_linebox(self):
+ self.__linebox = urwid.LineBox(self.__list_attrmap)
+ self.__linebox_attrmap = urwid.AttrMap(self.__linebox,
+ "main.menu.frame")
+
+ def set_focus(self, n):
+ self.__list.set_focus(n)
+
+
+class DialogBox(urwid.WidgetWrap):
+ def __init__(self, body, title, bodyattr=None, titleattr=None):
+ self.body = urwid.LineBox(body)
+ self.title = urwid.Text(title)
+ if titleattr is not None:
+ self.title = urwid.AttrMap(self.title, titleattr)
+ if bodyattr is not None:
+ self.body = urwid.AttrMap(self.body, bodyattr)
+
+ box = urwid.Overlay(self.title, self.body,
+ align='center',
+ valign='top',
+ width=len(title),
+ height=None,
+ )
+ urwid.WidgetWrap.__init__(self, box)
+
+ def selectable(self):
+ return self.body.selectable()
+
+ def keypress(self, size, key):
+ return self.body.keypress(size, key)
+
+
+class ModalDialog(urwid.Overlay):
+ def __init__(self, body, title, escape_key, previous_widget, bodyattr=None,
+ titleattr=None):
+ self.escape_key = escape_key
+ self.previous_widget = previous_widget
+
+ if type(body) in [str, unicode]:
+ body = urwid.Text(body)
+
+ box = DialogBox(body, title, bodyattr, titleattr)
+
+ super(ModalDialog, self).__init__(box, previous_widget, 'center',
+ ('relative', 70), 'middle',
+ ('relative', 70))
+
+
+class Label(urwid.WidgetWrap):
+ """A read only widget representing a label
+ """
+
+ def __init__(self, text):
+ self._label = urwid.Text(text)
+ self._label_attrmap = urwid.AttrMap(self._label,
+ "plugin.widget.label")
+ super(Label, self).__init__(self._label_attrmap)
+
+ def text(self, value=None):
+ if value != None:
+ self._label.set_text(value)
+ return self._label.get_text()
+
+class Header(Label):
+ """A read only widget representing a header
+ """
+
+ def __init__(self, text):
+ super(Header, self).__init__("\n %s\n" % text)
+ self._label_attrmap.set_attr_map({None: "plugin.widget.header"})
+
+
+class Entry(urwid.WidgetWrap):
+
+ signals = ['change']
+
+ notice = property(lambda self: self._notice.get_text(), \
+ lambda self, v: self._notice.set_text(v))
+
+ selectable = lambda self: True
+
+ def enable(self, is_enabled):
+ self.selectable = lambda: is_enabled
+ if is_enabled:
+ self._edit_attrmap.set_attr_map({None: ""})
+ else:
+ self._edit_attrmap.set_attr_map({
+ None: "plugin.widget.disabled"
+ })
+
+ def __init__(self, label, value=None, mask=None):
+ self._label = urwid.Text("\n" + label + ":")
+ self._edit = urwid.Edit(mask=mask)
+ self._edit_attrmap = urwid.AttrMap(self._edit, "plugin.widget.entry")
+ self._linebox = urwid.LineBox(self._edit_attrmap)
+ self._linebox_attrmap = urwid.AttrMap(self._linebox,
+ "plugin.widget.entry.frame")
+ self._columns = urwid.Columns([self._label, self._linebox_attrmap])
+
+ self._notice = urwid.Text("")
+ self._notice_attrmap = urwid.AttrMap(self._notice,
+ "plugin.widget.notice")
+
+ self._pile = urwid.Pile([self._columns, self._notice_attrmap])
+
+ if value:
+ self._edit.set_edit_text(value)
+
+ def on_widget_change_cb(widget, new_value):
+ urwid.emit_signal(self, 'change', self, new_value)
+ urwid.connect_signal(self._edit, 'change', on_widget_change_cb)
+
+ super(Entry, self).__init__(self._pile)
+
+class PasswordEntry(Entry):
+ def __init__(self, label, value=None):
+ super(PasswordEntry, self).__init__(label, value, mask="*")
--
To view, visit http://gerrit.ovirt.org/9867
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ibe9d524ab38b006e2bc3f521fa560288a19f0f95
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-node
Gerrit-Branch: master
Gerrit-Owner: Fabian Deutsch <fabiand at fedoraproject.org>
More information about the node-patches
mailing list