"Path browser" - 4 scrolled lists displaying:
    directories on sys.path
    modules in selected directory
    classes in selected module
    methods of selected class

Sinlge clicking in a directory, module or class item updates the next
column with info about the selected item.  Double clicking in a
module, class or method item opens the file (and selects the clicked
item if it is a class or method).

I guess eventually I should be using a tree widget for this, but the
ones I've seen don't work well enough, so for now I use the old
Smalltalk or NeXT style multi-column hierarchical browser.
diff --git a/Tools/idle/PathBrowser.py b/Tools/idle/PathBrowser.py
new file mode 100644
index 0000000..06c9ff7
--- /dev/null
+++ b/Tools/idle/PathBrowser.py
@@ -0,0 +1,151 @@
+import os
+import sys
+import imp
+import string
+import tkMessageBox
+
+from MultiScrolledLists import MultiScrolledLists
+
+class PathBrowser(MultiScrolledLists):
+    
+    def __init__(self, flist):
+        self.flist = flist
+        MultiScrolledLists.__init__(self, flist.root, 4)
+    
+    def longtitle(self):
+        return "Path Browser"
+    
+    def width(self, i):
+        return 30
+    
+    def height(self, i):
+        return 20
+    
+    def subtitle(self, i):
+        if i == 0:
+            return "Path Entries (sys.path)"
+        if i-1 >= len(self.path):
+            return ""
+        if i == 1:
+            return self.path[0]
+        if i == 2:
+            return "Classes in " + self.path[1]
+        if i == 3:
+            s = self.path[2]
+            i = string.find(s, "(")
+            if i > 0:
+                s = s[:i]
+            return "Methods of " + s
+        return ""
+    
+    def items(self, i):
+        if i == 0:
+            return sys.path
+        if i == 1:
+            return self.listmodules()
+        if i == 2:
+            return self.listclasses()
+        if i == 3:
+            return self.listmethods()
+    
+    def listmodules(self):
+        dir = self.path[0]
+        modules = {}
+        suffixes = imp.get_suffixes()
+        allnames = os.listdir(dir)
+        sorted = []
+        for suff, mode, flag in suffixes:
+            i = -len(suff)
+            for name in allnames:
+                normed_name = os.path.normcase(name)
+                if normed_name[i:] == suff:
+                    mod_name = name[:i]
+                    if not modules.has_key(mod_name):
+                        modules[mod_name] = None
+                        sorted.append((normed_name, name))
+        sorted.sort()
+        names = []
+        for nn, name in sorted:
+            names.append(name)
+        return names
+    
+    def listclasses(self):
+        import pyclbr
+        dir = self.path[0]
+        file = self.path[1]
+        name, ext = os.path.splitext(file)
+        if os.path.normcase(ext) != ".py":
+            self.top.bell()
+            return []
+        try:
+            dict = pyclbr.readmodule(name, [dir] + sys.path)
+        except ImportError, msg:
+            tkMessageBox.showerror("Import error", str(msg), parent=root)
+            return []
+        items = []
+        self.classes = {}
+        for key, cl in dict.items():
+            if cl.module == name:
+                s = key
+                if cl.super:
+                    supers = []
+                    for sup in cl.super:
+                        sname = sup.name
+                        if sup.module != cl.module:
+                            sname = "%s.%s" % (sup.module, sname)
+                        supers.append(sname)
+                    s = s + "(%s)" % string.join(supers, ", ")
+                items.append((cl.lineno, s))
+                self.classes[s] = cl
+        items.sort()
+        list = []
+        for item, s in items:
+            list.append(s)
+        return list
+    
+    def listmethods(self):
+        try:
+            cl = self.classes[self.path[2]]
+        except (IndexError, KeyError):
+            return []
+        items = []
+        for name, lineno in cl.methods.items():
+            items.append((lineno, name))
+        items.sort()
+        list = []
+        for item, name in items:
+            list.append(name)
+        return list
+    
+    def on_double(self, index, i):
+        if i == 0:
+            return
+        if i >= 1:
+            dir = self.path[0]
+            file = self.path[1]
+            name, ext = os.path.splitext(file)
+            if os.path.normcase(ext) != ".py":
+                self.top.bell()
+                return
+            fullname = os.path.join(dir, file)
+            edit = self.flist.open(fullname)
+            if i >= 2:
+                classname = self.path[2]
+                try:
+                    cl = self.classes[classname]
+                except KeyError:
+                    cl = None
+                else:
+                    if i == 2:
+                        edit.gotoline(cl.lineno)
+                    else:
+                        methodname = self.path[3]
+                        edit.gotoline(cl.methods[methodname])
+
+
+def main():
+    import PyShell
+    PathBrowser(PyShell.flist)
+
+if __name__ == "__main__":
+    main()