1from Foundation import NSObject, NSBundle 2from objc import selector, getClassList, objc_object, IBOutlet, IBAction 3 4import objc 5import AppKit 6objc.setVerbose(1) 7 8try: 9 import AddressBook 10except ImportError: 11 pass 12 13try: 14 import PreferencePanes 15except ImportError: 16 pass 17 18try: 19 import InterfaceBuilder 20except ImportError: 21 pass 22 23WRAPPED={} 24class Wrapper (NSObject): 25 """ 26 NSOutlineView doesn't retain values, which means we cannot use normal 27 python values as values in an outline view. 28 """ 29 def init_(self, value): 30 self.value = value 31 return self 32 33 def __str__(self): 34 return '<Wrapper for %s>'%self.value 35 36 def description(self): 37 return str(self) 38 39def wrap_object(obj): 40 if WRAPPED.has_key(obj): 41 return WRAPPED[obj] 42 else: 43 WRAPPED[obj] = Wrapper.alloc().init_(obj) 44 return WRAPPED[obj] 45 46def unwrap_object(obj): 47 if obj is None: 48 return obj 49 return obj.value 50 51methodIdentifier = { 52 'objc_method':0, 53 'python_method':1, 54 'signature':2 55} 56 57def classPath(cls): 58 if cls == objc_object: 59 return '' 60 elif cls.__bases__[0] == objc_object: 61 return cls.__name__ 62 else: 63 return '%s : %s'%(classPath(cls.__bases__[0]), cls.__name__) 64 65SYSFRAMEWORKS_DIR='/System/Library/Frameworks/' 66def classBundle(cls): 67 framework = NSBundle.bundleForClass_(cls).bundlePath() 68 if framework.startswith(SYSFRAMEWORKS_DIR): 69 framework = framework[len(SYSFRAMEWORKS_DIR):] 70 if framework.endswith('.framework'): 71 framework = framework[:-len('.framework')] 72 return framework 73 74class ClassesDataSource (NSObject): 75 __slots__ = ('_classList', '_classTree', '_methodInfo', '_classInfo') 76 77 classLabel = IBOutlet() 78 classTable = IBOutlet() 79 frameworkLabel = IBOutlet() 80 methodTable = IBOutlet() 81 searchBox = IBOutlet() 82 window = IBOutlet() 83 84 def clearClassInfo(self): 85 self._methodInfo = [] 86 self.methodTable.reloadData() 87 self.window.setTitle_('iClass') 88 89 90 def setClassInfo(self, cls): 91 self.window.setTitle_('iClass: %s'%cls.__name__) 92 self.classLabel.setStringValue_(classPath(cls)) 93 self.frameworkLabel.setStringValue_(classBundle(cls)) 94 self._methodInfo = [] 95 for nm, meth in cls.pyobjc_instanceMethods.__dict__.items(): 96 if not isinstance(meth, selector): 97 continue 98 self._methodInfo.append( 99 ('-'+meth.selector, nm, meth.signature)) 100 101 for nm, meth in cls.pyobjc_classMethods.__dict__.items(): 102 if not isinstance(meth, selector): 103 continue 104 self._methodInfo.append( 105 ('+'+meth.selector, nm, meth.signature)) 106 self._methodInfo.sort() 107 self.methodTable.reloadData() 108 109 def outlineViewSelectionDidChange_(self, notification): 110 rowNr = self.classTable.selectedRow() 111 if rowNr == -1: 112 self.clearClassInfo() 113 else: 114 item = self.classTable.itemAtRow_(rowNr) 115 self.setClassInfo(unwrap_object(item)) 116 117 def showClass(self, cls): 118 # First expand the tree (to make item visible) 119 super = cls.__bases__[0] 120 if super == objc_object: 121 return 122 123 self.showClass(super) 124 item = wrap_object(super) 125 rowNr = self.classTable.rowForItem_(item) 126 self.classTable.expandItem_(item) 127 128 def selectClass(self, cls): 129 self.showClass(cls) 130 131 item = wrap_object(cls) 132 rowNr = self.classTable.rowForItem_(item) 133 134 self.classTable.scrollRowToVisible_(rowNr) 135 self.classTable.selectRow_byExtendingSelection_(rowNr, False) 136 137 @IBAction 138 def searchClass_(self, event): 139 val = self.searchBox.stringValue() 140 if not val: 141 return 142 143 found = None 144 for cls in self._classTree.keys(): 145 if not cls: continue 146 if cls.__name__ == val: 147 self.setClassInfo(cls) 148 self.selectClass(cls) 149 return 150 elif cls.__name__.startswith(val): 151 if not found: 152 found = cls 153 elif len(cls.__name__) > len(found.__name__): 154 found = cls 155 156 # mvl 2009-03-02: fix case where no match is found caused exception: 157 if (found is None): return 158 159 self.setClassInfo(found) 160 self.selectClass(found) 161 162 163 def refreshClasses(self): 164 self._classList = getClassList() 165 self._classTree = {} 166 self._methodInfo = [] 167 168 for cls in self._classList: 169 super = cls.__bases__[0] 170 if super == objc_object: 171 super = None 172 else: 173 super = super 174 if not self._classTree.has_key(cls): 175 self._classTree[cls] = [] 176 177 if self._classTree.has_key(super): 178 self._classTree[super].append(cls) 179 else: 180 self._classTree[super] = [ cls ] 181 182 for lst in self._classTree.values(): 183 lst.sort() 184 185 def init(self): 186 self._classInfo = getClassList() 187 self.refreshClasses() 188 return self 189 190 def awakeFromNib(self): 191 self._classInfo = getClassList() 192 self.refreshClasses() 193 194 195 def outlineView_child_ofItem_(self, outlineview, index, item): 196 return wrap_object(self._classTree[unwrap_object(item)][index]) 197 198 def outlineView_isItemExpandable_(self, outlineview, item): 199 return len(self._classTree[unwrap_object(item)]) != 0 200 201 202 def outlineView_numberOfChildrenOfItem_(self, outlineview, item): 203 return len(self._classTree[unwrap_object(item)]) 204 205 def outlineView_objectValueForTableColumn_byItem_(self, outlineview, column, item): 206 if item is None: 207 return '<None>' 208 else: 209 v = item.value 210 return v.__name__ 211 212 213 def numberOfRowsInTableView_(self, aTableView): 214 return len(self._methodInfo) 215 216 def tableView_objectValueForTableColumn_row_(self, 217 aTableView, aTableColumn, rowIndex): 218 return self._methodInfo[rowIndex][methodIdentifier[aTableColumn.identifier()]] 219