From 2109e0f81e6c6747b8d07d4d362169fd0256bec9 Mon Sep 17 00:00:00 2001 From: Johannes Findeisen Date: Mon, 2 Dec 2013 01:15:39 +0100 Subject: [PATCH] added example tree structure to urlish and a TODO with a lot to think about --- linspector/frontends/urlish.py | 221 ++++++++++++++++++++++++++++----- 1 file changed, 188 insertions(+), 33 deletions(-) diff --git a/linspector/frontends/urlish.py b/linspector/frontends/urlish.py index 6fb54f3..ec20f56 100644 --- a/linspector/frontends/urlish.py +++ b/linspector/frontends/urlish.py @@ -21,36 +21,41 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . """ +""" +TODO: + + General: + + - think about if a simple scrollable list of jobs may be a lot easier to use + in combination with some tabs for job list, hostgroup jobs, host jobs etc. + i think this is a lot more flexible when reloading data. using the current + we have to rebuild the complete tree on reloading. or figure out how to + rebuild only selected nodes on reload. when using a tab/list based solution + we could even build a tab that on shows current errors, one for warnings etc. + these could we rebuild on access or on key stroke. these lists then only need + some action handlers for disabling/enabling or for showing detailed + information about the selected job. i think the tab/list approach is much + easier to handle then jumping like a monkey through a tree structure... ;) + + For the tree based solution: + + - remove all this global stuff and set needed stuff as arguments + + - fix mouse handling; nice feature to select stuff using the mouse. currently + it raises an exception. +""" + import urwid from logging import getLogger from linspector.frontends.frontend import Frontend -__version__ = "0.1.1" +__version__ = "0.1.2" logger = getLogger(__name__) -class JobWidget(urwid.FlowWidget): - def __init__(self): - pass - - -class JobListBox(urwid.WidgetWrap): - def __init__(self): - self.body = urwid.SimpleListWalker([]) - self.listbox = urwid.ListBox(self.body) - urwid.WidgetWrap.__init__(self, self.listbox) - - def keypress(self, size, key): - if key == ':': - main_frame.set_focus('footer') - command_prompt.set_caption(':') - else: - return self.listbox.keypress(size, key) - - class CommandPrompt(urwid.Edit): def __init__(self): urwid.Edit.__init__(self, '') @@ -141,13 +146,91 @@ class CommandPrompt(urwid.Edit): return urwid.Edit.keypress(self, size, key) -def update(main_loop, user_data): - thread_count = interface.get_thread_count() - header_bar.set_text(" Linspector," - " Jobs: " + str(interface.get_job_count()) + - " Threads: " + str(thread_count["Num Threads"]) + - "/" + str(thread_count["Max Threads"])) - main_loop.set_alarm_in(1, update) +class ExampleTreeWidget(urwid.TreeWidget): + def __init__(self, node): + self.__super.__init__(node) + #self.expanded = False + #self.update_expanded_icon() + + def get_display_text(self): + return self.get_node().get_value()['name'] + + +class ExampleNode(urwid.TreeNode): + def load_widget(self): + return ExampleTreeWidget(self) + + +class ServiceParentNode(urwid.ParentNode): + def load_widget(self): + return ExampleTreeWidget(self) + + def load_child_keys(self): + data = self.get_value() + return range(len(data['children'])) + + def load_child_node(self, key): + childdata = self.get_value()['children'][key] + childdepth = self.get_depth() + 1 + if 'children' in childdata: + childclass = ServiceParentNode + else: + childclass = ExampleNode + return childclass(childdata, parent=self, key=key, depth=childdepth) + + +class HostParentNode(urwid.ParentNode): + def load_widget(self): + return ExampleTreeWidget(self) + + def load_child_keys(self): + data = self.get_value() + return range(len(data['children'])) + + def load_child_node(self, key): + childdata = self.get_value()['children'][key] + childdepth = self.get_depth() + 1 + if 'children' in childdata: + childclass = ServiceParentNode + else: + childclass = ExampleNode + return childclass(childdata, parent=self, key=key, depth=childdepth) + + +class HostgroupParentNode(urwid.ParentNode): + def load_widget(self): + return ExampleTreeWidget(self) + + def load_child_keys(self): + data = self.get_value() + return range(len(data['children'])) + + def load_child_node(self, key): + childdata = self.get_value()['children'][key] + childdepth = self.get_depth() + 1 + if 'children' in childdata: + childclass = HostParentNode + else: + childclass = ExampleNode + return childclass(childdata, parent=self, key=key, depth=childdepth) + + +class RootParentNode(urwid.ParentNode): + def load_widget(self): + return ExampleTreeWidget(self) + + def load_child_keys(self): + data = self.get_value() + return range(len(data['children'])) + + def load_child_node(self, key): + childdata = self.get_value()['children'][key] + childdepth = self.get_depth() + 1 + if 'children' in childdata: + childclass = HostgroupParentNode + else: + childclass = ExampleNode + return childclass(childdata, parent=self, key=key, depth=childdepth) class UrlishFrontend(Frontend): @@ -162,26 +245,98 @@ class UrlishFrontend(Frontend): global loop global interface - palette = [('top', 'white', 'dark red'), + palette = [('body', 'white', 'black'), + ('foot_bar', 'white', 'black'), + ('top', 'white', 'dark red'), ('status', 'white', 'dark blue'), ('prompt', 'white', 'black')] + foot_text = [('title', "Navigation:"), " ", + ('key', "UP"), ",", ('key', "DOWN"), ",", + ('key', "PAGE UP"), ",", ('key', "PAGE DOWN"), + " ", + ('key', "+"), ",", + ('key', "-"), " ", + ('key', "LEFT"), " ", + ('key', "HOME"), " ", + ('key', "END")] + interface = linspector_interface + top_node = RootParentNode(get_example_tree()) + job_list_box = urwid.TreeListBox(urwid.TreeWalker(top_node)) + job_list_box.offset_rows = 1 + header_message = ' Linspector (' + str(linspector_interface.get_version()) + ')' header_bar = urwid.Text(header_message, align='left') header = urwid.Pile([urwid.AttrMap(header_bar, 'top')]) command_prompt = CommandPrompt() + foot_bar = urwid.Text(foot_text, align='left') + welcome_message = ' Type ":h " for help, ":q " to quit' status_bar = urwid.Text(welcome_message, align='left') - footer = urwid.Pile([urwid.AttrMap(status_bar, 'status'), urwid.AttrMap(command_prompt, 'prompt')]) - - job_list_box = JobListBox() + footer = urwid.Pile([urwid.AttrMap(foot_bar, 'foot_bar'), + urwid.AttrMap(status_bar, 'status'), + urwid.AttrMap(command_prompt, 'prompt')]) main_frame = urwid.Frame(body=job_list_box, header=header, footer=footer) - loop = urwid.MainLoop(main_frame, palette) + loop = urwid.MainLoop(main_frame, palette, unhandled_input=self.unhandled_input, handle_mouse=False) loop.set_alarm_in(0, update) - loop.run() \ No newline at end of file + loop.run() + + @staticmethod + def unhandled_input(key): + if key in (':'): + main_frame.set_focus('footer') + command_prompt.set_caption(':') + elif key in ('c'): + #collapse all children of current node + pass + elif key in ('C'): + #collapse all nodes + pass + elif key in ('d'): + #disable all jobs for current node + pass + elif key in ('e'): + #enable all jobs for current node + pass + elif key in ('r'): + #reload child data of current node + pass + elif key in ('R'): + #reload child data of all nodes + pass + elif key in ('x'): + #expand all children of current node + pass + elif key in ('X'): + #expand all nodes + pass + + +def update(main_loop, user_data): + thread_count = interface.get_thread_count() + header_bar.set_text(" Linspector," + " Jobs: " + str(interface.get_job_count()) + + " Threads: " + str(thread_count["Num Threads"]) + + "/" + str(thread_count["Max Threads"])) + main_loop.set_alarm_in(1, update) + + +def get_example_tree(): + retval = {"name": "ROOT", "children": []} + for i in range(10): + retval['children'].append({"name": "HOSTGROUP " + str(i)}) + retval['children'][i]['children'] = [] + for j in range(5): + retval['children'][i]['children'].append({"name": "HOST " + str(i) + "." + str(j)}) + retval['children'][i]['children'][j]['children'] = [] + for k in range(3): + retval['children'][i]['children'][j]['children'].append({"name": "SERVICE " + str(i) + + "." + str(j) + + "." + str(k)}) + return retval \ No newline at end of file