diff options
Diffstat (limited to 'source4/python/gtkdictbrowser.py')
-rwxr-xr-x | source4/python/gtkdictbrowser.py | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/source4/python/gtkdictbrowser.py b/source4/python/gtkdictbrowser.py new file mode 100755 index 0000000000..dd8bed8f47 --- /dev/null +++ b/source4/python/gtkdictbrowser.py @@ -0,0 +1,272 @@ +#!/usr/bin/python +# +# Browse a Python dictionary in a two pane graphical interface written +# in GTK. +# +# The GtkDictBrowser class is supposed to be generic enough to allow +# applications to override enough methods and produce a +# domain-specific browser provided the information is presented as a +# Python dictionary. +# +# Possible applications: +# +# - Windows registry browser +# - SPOOLSS printerdata browser +# - tdb file browser +# + +from gtk import * +import string, re + +class GtkDictBrowser: + + def __init__(self, dict): + self.dict = dict + + # This variable stores a list of (regexp, function) used to + # convert the raw value data to a displayable string. + + self.get_value_text_fns = [] + self.get_key_text = lambda x: x + + # We can filter the list of keys displayed using a regex + + self.filter_regex = "" + + # Create and configure user interface widgets. A string argument is + # used to set the window title. + + def build_ui(self, title): + win = GtkWindow() + win.set_title(title) + + win.connect("destroy", mainquit) + + hpaned = GtkHPaned() + win.add(hpaned) + hpaned.set_border_width(5) + hpaned.show() + + vbox = GtkVBox() + hpaned.add1(vbox) + vbox.show() + + scrolled_win = GtkScrolledWindow() + scrolled_win.set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC) + vbox.pack_start(scrolled_win) + scrolled_win.show() + + hbox = GtkHBox() + vbox.pack_end(hbox, expand = 0, padding = 5) + hbox.show() + + label = GtkLabel("Filter:") + hbox.pack_start(label, expand = 0, padding = 5) + label.show() + + self.entry = GtkEntry() + hbox.pack_end(self.entry, padding = 5) + self.entry.show() + + self.entry.connect("activate", self.filter_activated) + + self.list = GtkList() + self.list.set_selection_mode(SELECTION_MULTIPLE) + self.list.set_selection_mode(SELECTION_BROWSE) + scrolled_win.add_with_viewport(self.list) + self.list.show() + + self.list.connect("select_child", self.key_selected) + + scrolled_win = GtkScrolledWindow() + scrolled_win.set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC) + hpaned.add2(scrolled_win) + scrolled_win.set_usize(500,400) + scrolled_win.show() + + self.text = GtkText() + self.text.set_editable(FALSE) + scrolled_win.add_with_viewport(self.text) + self.text.show() + + self.text.connect("event", self.event_handler) + + self.menu = GtkMenu() + self.menu.show() + + self.font = load_font("fixed") + + self.update_keylist() + + win.show() + + # Add a key to the left hand side of the user interface + + def add_key(self, key): + display_key = self.get_key_text(key) + list_item = GtkListItem(display_key) + list_item.set_data("raw_key", key) # Store raw key in item data + self.list.add(list_item) + list_item.show() + + # Event handler registered by build_ui() + + def event_handler(self, event, menu): + return FALSE + + # Set the text to appear in the right hand side of the user interface + + def set_value_text(self, item): + + # Clear old old value in text window + + self.text.delete_text(0, self.text.get_length()) + + if type(item) == str: + + # The text widget has trouble inserting text containing NULL + # characters. + + item = string.replace(item, "\x00", ".") + + self.text.insert(self.font, None, None, item) + + else: + + # A non-text item + + self.text.insert(self.font, None, None, repr(item)) + + # This function is called when a key is selected in the left hand side + # of the user interface. + + def key_selected(self, list, list_item): + key = list_item.children()[0].get() + + # Look for a match in the value display function list + + text = self.dict[list_item.get_data("raw_key")] + + for entry in self.get_value_text_fns: + if re.match(entry[0], key): + text = entry[1](text) + break + + self.set_value_text(text) + + # Refresh the key list by removing all items and re-inserting them. + # Items are only inserted if they pass through the filter regexp. + + def update_keylist(self): + self.list.remove_items(self.list.children()) + self.set_value_text("") + for k in self.dict.keys(): + if re.match(self.filter_regex, k): + self.add_key(k) + + # Invoked when the user hits return in the filter text entry widget. + + def filter_activated(self, entry): + self.filter_regex = entry.get_text() + self.update_keylist() + + # Register a key display function + + def register_get_key_text_fn(self, fn): + self.get_key_text = fn + + # Register a value display function + + def register_get_value_text_fn(self, regexp, fn): + self.get_value_text_fns.append((regexp, fn)) + +# +# A utility function to convert a string to the standard hex + ascii format. +# To display all values in hex do: +# register_get_value_text_fn("", gtkdictbrowser.hex_string) +# + +def hex_string(data): + """Return a hex dump of a string as a string. + + The output produced is in the standard 16 characters per line hex + + ascii format: + + 00000000: 40 00 00 00 00 00 00 00 40 00 00 00 01 00 04 80 @....... @....... + 00000010: 01 01 00 00 00 00 00 01 00 00 00 00 ........ .... + """ + + pos = 0 # Position in data + line = 0 # Line of data + + hex = "" # Hex display + ascii = "" # ASCII display + + result = "" + + while pos < len(data): + + # Start with header + + if pos % 16 == 0: + hex = "%08x: " % (line * 16) + ascii = "" + + # Add character + + hex = hex + "%02x " % (ord(data[pos])) + + if ord(data[pos]) < 32 or ord(data[pos]) > 176: + ascii = ascii + '.' + else: + ascii = ascii + data[pos] + + pos = pos + 1 + + # Add separator if half way + + if pos % 16 == 8: + hex = hex + " " + ascii = ascii + " " + + # End of line + + if pos % 16 == 0: + result = result + "%s %s\n" % (hex, ascii) + line = line + 1 + + # Leftover bits + + if pos % 16 != 0: + + # Pad hex string + + for i in range(0, (16 - (pos % 16))): + hex = hex + " " + + # Half way separator + + if (pos % 16) < 8: + hex = hex + " " + + result = result + "%s %s\n" % (hex, ascii) + + return result + +# For testing purposes, create a fixed dictionary to browse with + +if __name__ == "__main__": + + dict = {"chicken": "ham", "spam": "fun", "subdict": {"a": "b", "c": "d"}} + + db = GtkDictBrowser(dict) + + db.build_ui("GtkDictBrowser") + + # Override Python's handling of ctrl-c so we can break out of the + # gui from the command line. + + import signal + signal.signal(signal.SIGINT, signal.SIG_DFL) + + mainloop() |