1"""ClassBrowser.py -- A simple class browser, demonstrating the use of an NSBrowser. 2 3To build the demo program, run this line in Terminal.app: 4 5 $ python setup.py py2app -A 6 7This creates a directory "dist" containing ClassBrowser.app. (The 8-A option causes the files to be symlinked to the .app bundle instead 9of copied. This means you don't have to rebuild the app if you edit the 10sources or nibs.) 11 12See also the iClass demo. 13""" 14 15from PyObjCTools import AppHelper 16from objc import getClassList, objc_object 17from Foundation import * 18 19 20try: 21 import AddressBook 22except ImportError: 23 pass 24 25try: 26 import PreferencePanes 27except ImportError: 28 pass 29 30try: 31 import InterfaceBuilder 32except ImportError: 33 pass 34 35def _sortClasses(classList): 36 classes = [(cls.__name__, cls) for cls in classList] 37 classes.sort() 38 return [cls for name, cls in classes] 39 40 41class ClassBrowserDelegate (NSObject): 42 browser = objc.IBOutlet() 43 pathLabel = objc.IBOutlet() 44 table = objc.IBOutlet() 45 46 selectedClassMethods = None 47 48 def awakeFromNib(self): 49 classes = getClassList() 50 rootClasses = [] 51 for cls in classes: 52 if cls.__base__ == objc_object: 53 rootClasses.append(cls) 54 rootClasses = _sortClasses(rootClasses) 55 self.columns = [rootClasses] 56 self.browser.setMaxVisibleColumns_(7) 57 self.browser.setMinColumnWidth_(150) 58 self.selectedClass = None 59 self.selectedClassMethods = None 60 61 def browser_willDisplayCell_atRow_column_(self, browser, cell, row, col): 62 cell.setLeaf_(not self.columns[col][row].__subclasses__()) 63 cell.setStringValue_(self.columns[col][row].__name__) 64 65 def browser_numberOfRowsInColumn_(self, browser, col): 66 if col == 0: 67 return len(self.columns[0]) 68 del self.columns[col:] 69 cls = self.columns[col - 1][browser.selectedRowInColumn_(col - 1)] 70 subclasses = _sortClasses(cls.__subclasses__()) 71 self.columns.append(subclasses) 72 return len(subclasses) 73 74 @objc.IBAction 75 def browserAction_(self, browser): 76 self.pathLabel.setStringValue_(browser.path()) 77 78 self.selectedClass = None 79 self.selectedClassMethods = None 80 col = len(self.columns) 81 row = -1 82 while row == -1: 83 col -= 1 84 if col < 0: 85 break 86 row = self.browser.selectedRowInColumn_(col) 87 if row >= 0: 88 self.selectedClass = self.columns[col][row] 89 # Classes get initialized lazily, upon the first attribute access, 90 # only after that cls.__dict__ actually contains the methods. 91 # Do a dummy hasattr() to make sure the class is initialized. 92 hasattr(self.selectedClass, "alloc") 93 self.selectedClassMethods = [ 94 '-' + obj.selector for obj in self.selectedClass.pyobjc_instanceMethods.__dict__.values() 95 if hasattr(obj, "selector") 96 ] 97 self.selectedClassMethods += [ 98 '+' + obj.selector for obj in self.selectedClass.pyobjc_classMethods.__dict__.values() 99 if hasattr(obj, "selector") 100 ] 101 self.selectedClassMethods.sort() 102 103 self.table.reloadData() 104 105 # table view delegate methods 106 def numberOfRowsInTableView_(self, tableView): 107 if self.selectedClassMethods is None: 108 return 0 109 return len(self.selectedClassMethods) 110 111 def tableView_objectValueForTableColumn_row_(self, tableView, col, row): 112 return str(self.selectedClassMethods[row]) 113 114 def tableView_shouldEditTableColumn_row_(self, tableView, col, row): 115 return 0 116 117if __name__ == "__main__": 118 AppHelper.runEventLoop() 119