| 1 | #!/usr/bin/env python |
|---|
| 2 | |
|---|
| 3 | # Copyright (C) 2008 Simon Cross |
|---|
| 4 | # |
|---|
| 5 | # This program is free software; you can redistribute it and/or modify |
|---|
| 6 | # it under the terms of the GNU General Public License as published by |
|---|
| 7 | # the Free Software Foundation; either version 2, or (at your option) |
|---|
| 8 | # any later version. |
|---|
| 9 | # |
|---|
| 10 | # This program is distributed in the hope that it will be useful, |
|---|
| 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | # GNU General Public License for more details. |
|---|
| 14 | # |
|---|
| 15 | # You should have received a copy of the GNU General Public License |
|---|
| 16 | # along with this program; if not, write to the Free Software |
|---|
| 17 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|---|
| 18 | |
|---|
| 19 | """A simple extension to strip common prefixes from tab titles.""" |
|---|
| 20 | |
|---|
| 21 | import string |
|---|
| 22 | import gtk |
|---|
| 23 | |
|---|
| 24 | def find_longest_prefix(titles): |
|---|
| 25 | """Find longest prefix from list of titles. Return "" if not common prefix.""" |
|---|
| 26 | if not titles: |
|---|
| 27 | return "" |
|---|
| 28 | |
|---|
| 29 | remaining_titles = list(titles) |
|---|
| 30 | length = 0 |
|---|
| 31 | |
|---|
| 32 | while True: |
|---|
| 33 | length += 1 |
|---|
| 34 | prefix_map = {} |
|---|
| 35 | |
|---|
| 36 | for title in remaining_titles: |
|---|
| 37 | if len(title) < length: |
|---|
| 38 | continue |
|---|
| 39 | prefix = title[:length] |
|---|
| 40 | prefix_map.setdefault(prefix,[]) |
|---|
| 41 | prefix_map[prefix].append(title) |
|---|
| 42 | |
|---|
| 43 | for prefix, title_list in prefix_map.items(): |
|---|
| 44 | if len(title_list) <= 1: |
|---|
| 45 | del prefix_map[prefix] |
|---|
| 46 | |
|---|
| 47 | if len(prefix_map) == 0: |
|---|
| 48 | length -= 1 |
|---|
| 49 | break |
|---|
| 50 | |
|---|
| 51 | remaining_titles = list() |
|---|
| 52 | for title_list in prefix_map.values(): |
|---|
| 53 | remaining_titles.extend(title_list) |
|---|
| 54 | |
|---|
| 55 | assert remaining_titles |
|---|
| 56 | |
|---|
| 57 | return remaining_titles[0][:length] |
|---|
| 58 | |
|---|
| 59 | def find_common_prefixes(tabs_to_titles, strip_chars): |
|---|
| 60 | """Modify values to remove common prefixes containing end_chars.""" |
|---|
| 61 | tabs_to_titles = tabs_to_titles.copy() |
|---|
| 62 | unprocessed = set(tabs_to_titles.keys()) |
|---|
| 63 | |
|---|
| 64 | while True: |
|---|
| 65 | prefix = find_longest_prefix([tabs_to_titles[x] for x in unprocessed]) |
|---|
| 66 | if prefix == "": |
|---|
| 67 | break |
|---|
| 68 | stripped_prefix = prefix.rstrip(strip_chars) |
|---|
| 69 | for tab in list(unprocessed): |
|---|
| 70 | title = tabs_to_titles[tab] |
|---|
| 71 | if title.startswith(prefix): |
|---|
| 72 | unprocessed.remove(tab) |
|---|
| 73 | if title != prefix: |
|---|
| 74 | tabs_to_titles[tab] = title[len(stripped_prefix):] |
|---|
| 75 | |
|---|
| 76 | return tabs_to_titles |
|---|
| 77 | |
|---|
| 78 | class TabStripExtension(object): |
|---|
| 79 | def __init__(self): |
|---|
| 80 | self.handler_ids = {} |
|---|
| 81 | |
|---|
| 82 | def set_tab_title(self, notebook, tab, title): |
|---|
| 83 | """Set notebook tab title -- is there a better way?""" |
|---|
| 84 | tab_label = notebook.get_tab_label(tab) |
|---|
| 85 | labels = [x for x in tab_label.get_children() if isinstance(x, gtk.Label)] |
|---|
| 86 | if labels: |
|---|
| 87 | labels[0].set_label(title) |
|---|
| 88 | |
|---|
| 89 | def handler(self, notebook, page, page_numargs): |
|---|
| 90 | """When an event occurs, check to see if there are new common prefixes.""" |
|---|
| 91 | tabs = notebook.get_children() |
|---|
| 92 | strip_chars = string.letters + string.digits |
|---|
| 93 | |
|---|
| 94 | tabs_to_titles = dict([(t, t.props.title) for t in tabs]) |
|---|
| 95 | tabs_to_titles = find_common_prefixes(tabs_to_titles, strip_chars) |
|---|
| 96 | |
|---|
| 97 | for tab, title in tabs_to_titles.items(): |
|---|
| 98 | self.set_tab_title(notebook, tab, title) |
|---|
| 99 | |
|---|
| 100 | def attach_window(self, window): |
|---|
| 101 | """Attach to a window.""" |
|---|
| 102 | notebook = window.get_notebook() |
|---|
| 103 | self.handler_ids[notebook] = notebook.connect_after("switch-page", self.handler) |
|---|
| 104 | |
|---|
| 105 | def detach_window(self, window): |
|---|
| 106 | """Detach from a window.""" |
|---|
| 107 | notebook = window.get_notebook() |
|---|
| 108 | notebook.disconnect(self.handler_ids[notebook]) |
|---|
| 109 | del self.handler_ids[notebook] |
|---|
| 110 | |
|---|
| 111 | def test_prefix_finding(): |
|---|
| 112 | """Test prefix finding code.""" |
|---|
| 113 | assert find_longest_prefix(["", "abc", "abab"]) == "ab" |
|---|
| 114 | assert find_longest_prefix(["abcd", "abcd"]) == "abcd" |
|---|
| 115 | assert find_longest_prefix(["foo - bar", "foo - eep", "other"]) == "foo - " |
|---|
| 116 | |
|---|
| 117 | s = string.letters + string.digits |
|---|
| 118 | assert find_common_prefixes({ 1: "abcd", 2: "abcd" }, s) == { 1: "abcd", 2: "abcd" } |
|---|
| 119 | assert find_common_prefixes({ 1: "foo - bar", 2: "foo - eep" }, s) == { 1: "bar", 2: "eep" } |
|---|
| 120 | assert find_common_prefixes({ 1: "foo - bar", 2: "foo - eep", 3: "fop" }, s) == { 1: "bar", 2: "eep", 3: "fop" } |
|---|
| 121 | |
|---|
| 122 | if __name__ == "__main__": |
|---|
| 123 | test_prefix_finding() |
|---|
| 124 | else: |
|---|
| 125 | import epiphany |
|---|
| 126 | ext = TabStripExtension() |
|---|
| 127 | attach_window = ext.attach_window |
|---|
| 128 | detach_window = ext.detach_window |
|---|