class ABPerson(objc.Category(AddressBook.ABPerson)): # Pull first and last name, organization, and record flags # If the entry is a company, display the organization name instead def displayName(self): firstName = self.valueForProperty_(AddressBook.kABFirstNameProperty) lastName = self.valueForProperty_(AddressBook.kABLastNameProperty) companyName = self.valueForProperty_(AddressBook.kABOrganizationProperty) flags = self.valueForProperty_(AddressBook.kABPersonFlags) if flags is None: flags = 0 if (flags & AddressBook.kABShowAsMask) == AddressBook.kABShowAsCompany: if len(companyName): return companyName lastNameFirst = ( flags & AddressBook.kABNameOrderingMask ) == AddressBook.kABLastNameFirst hasFirstName = firstName is not None hasLastName = lastName is not None if hasLastName and hasFirstName: if lastNameFirst: return Cocoa.NSString.stringWithString_("%s %s" % (lastName, firstName)) else: return Cocoa.NSString.stringWithString_("%s %s" % (firstName, lastName)) if hasLastName: return lastName return firstName def compareDisplayNames_(self, person): return self.displayName().localizedCaseInsensitiveCompare_(person.displayName())
class NSAnimationContext(objc.Category(NSAnimationContext)): @classmethod def __enter__(cls): cls.beginGrouping() @classmethod def __exit__(cls, exc_type, exc_value, exc_tb): cls.endGrouping() return False
class Methods(objc.Category(Methods)): def categoryMethod(self): return True def categoryMethod2(self): return False def anotherClassMethod(self): return "hello" anotherClassMethod = classmethod(anotherClassMethod)
class SDL_QuartzWindow(objc.Category(SDL_QuartzWindow)): def canBecomeKeyWindow(self): return True def canBecomeMainWindow(self): return True def acceptsFirstResponder(self): return True def becomeFirstResponder(self): return True def resignFirstResponder(self): return True
class NSObjectCat(objc.Category(NSObjectCat)): """ This is a docstring """ def withDocStringMethod(self): return 42
class BaseClassRedef(objc.Category(BaseClassRedef)): def foo(self): return 2
class list(objc.Category(list)): pass
class NSFoo(objc.Category(NSObject)): pass
class NSObject(objc.Category(NSObject), object): pass
class NSGraphicsContext(objc.Category(NSGraphicsContext)): @classmethod def savedGraphicsState(self): return _ctxHelper()
class NSColor(objc.Category(Cocoa.NSColor)): @classmethod def randomColor(self): return Cocoa.NSColor.colorWithCalibratedRed_green_blue_alpha_( random.uniform(0, 1), random.uniform(0, 1), random.uniform(0, 1), 1)
def Category(classname): return objc.Category(objc.lookUpClass(classname))
class NSObjectCat2(objc.Category(NSObjectCat2)): @classmethod def aClassMethod(cls): return 1
class EditingMessageWebView(objc.Category(objc.runtime.EditingMessageWebView)): @swizzle(objc.runtime.EditingMessageWebView, 'decreaseIndentation:') def decreaseIndentation_(self, original, sender): # Call the original Mail.app decreaseIndentation: selector for rich # text messages. if self.contentElement().className() != 'ApplePlainTextBody': return original(self, sender) # If we have a selection, remove indentation on all lines which # overlap it. Otherwise, remove indentation on the line containing # the cursor. Combine the operation into a single undo group for UI # purposes. self.undoManager().beginUndoGrouping() affinity = self.selectionAffinity() selection = self.selectedDOMRange() if self.selectedRange().length == 0: self.moveToBeginningOfParagraph_(None) self.moveToEndOfParagraphAndModifySelection_(None) if not self.selectedText().strip(): if self.selectedText(): self.deleteBackward_(None) elif self.selectedText()[:self._indentWidth].isspace(): self.moveToBeginningOfParagraph_(None) for _ in xrange(self._indentWidth): self.deleteForward_(None) else: last = self.selectedRange().length self.moveToEndOfDocumentAndModifySelection_(None) last = self.selectedRange().length - last while self.selectedRange().length > last: self.moveToBeginningOfParagraph_(None) self.moveToEndOfParagraphAndModifySelection_(None) if not self.selectedText().strip(): if self.selectedText(): self.deleteBackward_(None) elif self.selectedText()[:self._indentWidth].isspace(): self.moveToBeginningOfParagraph_(None) for _ in xrange(self._indentWidth): self.deleteForward_(None) self.moveToEndOfParagraph_(None) self.moveForward_(None) self.moveToEndOfDocumentAndModifySelection_(None) self.moveBackward_(None) self.setSelectedDOMRange_affinity_(selection, affinity) self.undoManager().endUndoGrouping() def fillParagraph(self): # Note the quote level of the current paragraph and the location of # the end of the message to avoid attempts to move beyond it. self.moveToEndOfDocumentAndModifySelection_(None) last = self.selectedRange().location + self.selectedRange().length self.moveToBeginningOfParagraph_(None) self.selectParagraph_(None) level = self.quoteLevelAtStartOfSelection() # If we are on a blank line, move down to the start of the next # paragraph block and finish. if not self.selectedText().strip(): while True: self.moveDown_(None) self.selectParagraph_(None) location = self.selectedRange().location if location + self.selectedRange().length >= last: self.moveToEndOfParagraph_(None) return if self.selectedText().strip(): self.moveToBeginningOfParagraph_(None) return # Otherwise move to the start of this paragraph block, working # upward until we hit the start of the message, a blank line or a # change in quote level. while self.selectedRange().location > 0: self.moveUp_(None) if self.quoteLevelAtStartOfSelection() != level: self.moveDown_(None) break self.selectParagraph_(None) if not self.selectedText().strip(): self.moveDown_(None) break self.moveToBeginningOfParagraph_(None) # Insert a temporary placeholder space character to avoid any # assumptions about Mail.app's strange and somewhat unpredictable # handling of newlines between block elements. self.insertText_(' ') self.moveToEndOfParagraphAndModifySelection_(None) # Now extend the selection forward line-by-line until we hit a blank # line, a change in quote level or the end of the message. affinity = self.selectionAffinity() selection = self.selectedDOMRange() while True: location = self.selectedRange().location if location + self.selectedRange().length >= last: break self.moveDown_(None) self.moveToEndOfParagraphAndModifySelection_(None) if self.quoteLevelAtStartOfSelection() != level: break if not self.selectedText().strip(): break selection.setEnd__(self.selectedDOMRange().endContainer(), self.selectedDOMRange().endOffset()) self.setSelectedDOMRange_affinity_(selection, affinity) # Finally, extend the selection forward to encompass any blank lines # following the paragraph block, regardless of quote level. Store # the minimum quote level of this paragraph block and the next. while True: location = self.selectedRange().location if location + self.selectedRange().length >= last: minimum = 0 break self.moveDown_(None) self.moveToBeginningOfParagraph_(None) self.moveToEndOfParagraphAndModifySelection_(None) if self.selectedText().strip(): minimum = min(self.quoteLevelAtStartOfSelection(), level) break selection.setEnd__(self.selectedDOMRange().endContainer(), self.selectedDOMRange().endOffset()) self.setSelectedDOMRange_affinity_(selection, affinity) # Re-fill the text allowing for quote level and retaining block # indentation, then insert it to replace the selection. text = fill(self.selectedText().expandtabs(), level) + '\n' self.insertTextWithoutReplacement_(text) # Reduce the quote level of the trailing blank line if necessary, # then remove the placeholder character and position the cursor at # the start of the next paragraph block. item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_( 'Decrease', 'changeQuoteLevel:', '') item.setTag_(-1) for _ in xrange(level - minimum): self.changeQuoteLevel_(item) selection = self.selectedDOMRange() for _ in xrange(text.count('\n')): self.moveUp_(None) self.moveToBeginningOfParagraph_(None) self.deleteForward_(None) self.setSelectedDOMRange_affinity_(selection, affinity) self.moveForward_(None) def fillText(self): # MailWrap only works correctly on plain text messages, so ignore # any requests to format paragraphs in rich-text/HTML messages. if self.contentElement().className() != 'ApplePlainTextBody': return # If we have a selection, format all paragraph blocks which overlap # it. Otherwise, format the paragraph block containing the cursor. # Combine the operation into a single undo group for UI purposes. self.undoManager().beginUndoGrouping() if self.selectedRange().length == 0: self.fillParagraph() self.moveToEndOfDocumentAndModifySelection_(None) else: last = self.selectedRange().length self.moveToEndOfDocumentAndModifySelection_(None) last = self.selectedRange().length - last while self.selectedRange().length > last: self.fillParagraph() self.moveToEndOfDocumentAndModifySelection_(None) if self.selectedRange().length > 0: self.moveBackward_(None) else: self.deleteBackward_(None) self.undoManager().endUndoGrouping() @swizzle(objc.runtime.EditingMessageWebView, 'increaseIndentation:') def increaseIndentation_(self, original, sender): # Call the original Mail.app increaseIndentation: selector for rich # text messages. if self.contentElement().className() != 'ApplePlainTextBody': return original(self, sender) # If we have a selection, indent all lines which overlap it. # Otherwise, indent the line containing the cursor. Combine the # operation into a single undo group for UI purposes. self.undoManager().beginUndoGrouping() affinity = self.selectionAffinity() selection = self.selectedDOMRange() if self.selectedRange().length == 0: self.moveToBeginningOfParagraph_(None) self.insertText_(' ' * self._indentWidth) self.moveToBeginningOfParagraph_(None) self.moveToEndOfParagraphAndModifySelection_(None) if not self.selectedText().strip(): self.deleteBackward_(None) else: last = self.selectedRange().length self.moveToEndOfDocumentAndModifySelection_(None) last = self.selectedRange().length - last while self.selectedRange().length > last: self.moveToBeginningOfParagraph_(None) self.insertText_(' ' * self._indentWidth) self.moveToBeginningOfParagraph_(None) self.moveToEndOfParagraphAndModifySelection_(None) if self.selectedText().strip(): self.moveForward_(None) else: self.deleteBackward_(None) self.moveForward_(None) self.moveToEndOfDocumentAndModifySelection_(None) self.moveBackward_(None) self.setSelectedDOMRange_affinity_(selection, affinity) self.undoManager().endUndoGrouping() def insertTextWithoutReplacement_(self, text): if self.isAutomaticTextReplacementEnabled(): self.setAutomaticTextReplacementEnabled_(False) self.insertText_(text) self.setAutomaticTextReplacementEnabled_(True) else: self.insertText_(text) def quoteLevelAtStartOfSelection(self): return self.selectedDOMRange().startContainer().quoteLevel() def selectedText(self): return self.selectedDOMRange().stringValue() or '' def wrapLine(self): # Select the current line, and break it into lines of the correct # width, allowing for quoting overhead and retaining the # indentation. self.moveToBeginningOfParagraph_(None) self.moveToEndOfParagraphAndModifySelection_(None) # Wrap the line allowing for quote level and retaining indentation, # then insert it to replace the selection. level = self.quoteLevelAtStartOfSelection() text = fill(self.selectedText().expandtabs(), level) # Insert the wrapped text to replace the selection, temporarily # disabling text replacement to avoid unintended substitutions. # Finally, position the cursor at the start of the next line. self.insertTextWithoutReplacement_(text) self.moveForward_(None) def wrapText(self): # MailWrap only works correctly on plain text messages, so ignore # any requests to format paragraphs in rich-text/HTML messages. if self.contentElement().className() != 'ApplePlainTextBody': return # If we have a selection, wrap all lines which overlap it. # Otherwise, wrap the line containing the cursor. Combine the # operation into a single undo group for UI purposes. self.undoManager().beginUndoGrouping() if self.selectedRange().length == 0: self.wrapLine() else: last = self.selectedRange().length self.moveToEndOfDocumentAndModifySelection_(None) last = self.selectedRange().length - last while self.selectedRange().length > last: self.wrapLine() self.moveToEndOfDocumentAndModifySelection_(None) if self.selectedRange().length > 0: self.moveBackward_(None) self.undoManager().endUndoGrouping()
class DocumentEditor(objc.Category(objc.runtime.DocumentEditor)): @swizzle(objc.runtime.DocumentEditor, 'finishLoadingEditor') def finishLoadingEditor(self, original): # Let Mail.app complete its own preparation of the new message and # the document editor before we do our own cleanups. original(self) if self.messageType() in [1, 2]: # We only modify messages resulting from a reply or reply-to-all # action. Begin by stripping stray blank lines at the beginning # of the message body and around cited text. view = self.webView() document = view.mainFrame().DOMDocument() view.contentElement().removeStrayLinefeeds() blockquotes = document.getElementsByTagName_('BLOCKQUOTE') for index in xrange(blockquotes.length()): if blockquotes.item_(index): blockquotes.item_(index).removeStrayLinefeeds() # If we are configured to fix the attribution string, remove the # 'On DATE, at TIME, ' prefix from the first line, which will # always be the attribution in an unmodified reply. Also ensure # that the attribution and the blank line following it are not # incorrectly quoted by a bug in Mail.app 8.0. if self._fixAttribution: view.moveToBeginningOfDocument_(None) view.moveToEndOfParagraphAndModifySelection_(None) view.moveForwardAndModifySelection_(None) item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_( 'Decrease', 'changeQuoteLevel:', '') item.setTag_(-1) view.changeQuoteLevel_(item) attribution = view.selectedDOMRange().stringValue() attribution = attribution.rsplit(',', 1)[-1].lstrip() if view.isAutomaticTextReplacementEnabled(): view.setAutomaticTextReplacementEnabled_(False) view.insertText_(attribution) view.setAutomaticTextReplacementEnabled_(True) else: view.insertText_(attribution) if self._placeCursorAtEnd: # Place the cursor at the end of the quoted text but before # the signature if present, separated from the quoted text by # a blank line. signature = document.getElementById_('AppleMailSignature') if signature: range = document.createRange() range.selectNode_(signature) view.setSelectedDOMRange_affinity_(range, 0) view.moveUp_(None) else: view.moveToEndOfDocument_(None) view.insertParagraphSeparator_(None) view.insertParagraphSeparator_(None) else: view.moveToBeginningOfDocument_(None) view.insertParagraphSeparator_(None) view.insertParagraphSeparator_(None) view.moveToBeginningOfDocument_(None) view.undoManager().removeAllActions() self.backEnd().setHasChanges_(False)
class list(objc.Category(list)): # noqa: A001 pass
class NSURLRequest(objc.Category(NSURLRequest)): @classmethod def allowsAnyHTTPSCertificateForHost_(cls, host): # Use setting? settings = SIPSimpleSettings() return not settings.tls.verify_server
class NSObjectCat3(objc.Category(NSObjectCat3)): classValue = "aap" def getClassValue(self): return self.classValue
class Methods(objc.Category(Methods)): outlet = objc.IBOutlet()
class NSEvent(objc.Category(Cocoa.NSEvent)): def locationInView_(self, view): return view.convertPoint_fromView_(self.locationInWindow(), None)
class NSObject(objc.Category(NSObject)): def myCategoryMethod(self): return True def myCategoryMethod2(self): return False
class NSObject(objc.Category(NSObject)): @objc.namedSelector(b"_pyobjc_performOnThread:") def _pyobjc_performOnThread_(self, callinfo): try: sel, arg = callinfo # XXX: PyObjC's methodForSelector implementation doesn't work # with Python methods, using getattr instead # m = self.methodForSelector_(sel) m = getattr(self, _str(sel)) m(arg) except: import traceback traceback.print_exc(file=sys.stderr) @objc.namedSelector(b"_pyobjc_performOnThreadWithResult:") def _pyobjc_performOnThreadWithResult_(self, callinfo): try: sel, arg, result = callinfo # m = self.methodForSelector_(sel) m = getattr(self, _str(sel)) r = m(arg) result.append((True, r)) except: result.append((False, sys.exc_info())) if hasattr(NSObject, "performSelector_onThread_withObject_waitUntilDone_"): @objc.namedSelector( b"pyobjc_performSelector:onThread:withObject:waitUntilDone:" ) def pyobjc_performSelector_onThread_withObject_waitUntilDone_( self, aSelector, thread, arg, wait ): """ A version of performSelector:onThread:withObject:waitUntilDone: that will log exceptions in the called method (instead of aborting the NSRunLoop on the other thread). """ self.performSelector_onThread_withObject_waitUntilDone_( b"_pyobjc_performOnThread:", thread, (aSelector, arg), wait ) @objc.namedSelector( b"pyobjc_performSelector:onThread:withObject:waitUntilDone:modes:" ) def pyobjc_performSelector_onThread_withObject_waitUntilDone_modes_( self, aSelector, thread, arg, wait, modes ): """ A version of performSelector:onThread:withObject:waitUntilDone:modes: that will log exceptions in the called method (instead of aborting the NSRunLoop on the other thread). """ self.performSelector_onThread_withObject_waitUntilDone_modes_( b"_pyobjc_performOnThread:", thread, (aSelector, arg), wait, modes ) @objc.namedSelector(b"pyobjc_performSelector:withObject:afterDelay:") def pyobjc_performSelector_withObject_afterDelay_(self, aSelector, arg, delay): """ A version of performSelector:withObject:afterDelay: that will log exceptions in the called method (instead of aborting the NSRunLoop). """ self.performSelector_withObject_afterDelay_( b"_pyobjc_performOnThread:", (aSelector, arg), delay ) @objc.namedSelector(b"pyobjc_performSelector:withObject:afterDelay:inModes:") def pyobjc_performSelector_withObject_afterDelay_inModes_( self, aSelector, arg, delay, modes ): """ A version of performSelector:withObject:afterDelay:inModes: that will log exceptions in the called method (instead of aborting the NSRunLoop). """ self.performSelector_withObject_afterDelay_inModes_( b"_pyobjc_performOnThread:", (aSelector, arg), delay, modes ) if hasattr(NSObject, "performSelectorInBackground_withObject_"): @objc.namedSelector(b"pyobjc_performSelectorInBackground:withObject:") def pyobjc_performSelectorInBackground_withObject_(self, aSelector, arg): """ A version of performSelectorInBackground:withObject: that will log exceptions in the called method (instead of aborting the NSRunLoop). """ self.performSelectorInBackground_withObject_( b"_pyobjc_performOnThread:", (aSelector, arg) ) @objc.namedSelector(b"pyobjc_performSelectorOnMainThread:withObject:waitUntilDone:") def pyobjc_performSelectorOnMainThread_withObject_waitUntilDone_( self, aSelector, arg, wait ): """ A version of performSelectorOnMainThread:withObject:waitUntilDone: that will log exceptions in the called method (instead of aborting the NSRunLoop in the main thread). """ self.performSelectorOnMainThread_withObject_waitUntilDone_( b"_pyobjc_performOnThread:", (aSelector, arg), wait ) @objc.namedSelector( b"pyobjc_performSelectorOnMainThread:withObject:waitUntilDone:modes:" ) def pyobjc_performSelectorOnMainThread_withObject_waitUntilDone_modes_( self, aSelector, arg, wait, modes ): """ A version of performSelectorOnMainThread:withObject:waitUntilDone:modes: that will log exceptions in the called method (instead of aborting the NSRunLoop in the main thread). """ self.performSelectorOnMainThread_withObject_waitUntilDone_modes_( b"_pyobjc_performOnThread:", (aSelector, arg), wait, modes ) # And some a some versions that return results @objc.namedSelector(b"pyobjc_performSelectorOnMainThread:withObject:modes:") def pyobjc_performSelectorOnMainThread_withObject_modes_( self, aSelector, arg, modes ): """ Simular to performSelectorOnMainThread:withObject:waitUntilDone:modes:, but: - always waits until done - returns the return value of the called method - if the called method raises an exception, this will raise the same exception """ result = [] self.performSelectorOnMainThread_withObject_waitUntilDone_modes_( b"_pyobjc_performOnThreadWithResult:", (aSelector, arg, result), True, modes ) isOK, result = result[0] if isOK: return result else: exc_type, exc_value, exc_trace = result _raise(exc_type, exc_value, exc_trace) @objc.namedSelector(b"pyobjc_performSelectorOnMainThread:withObject:") def pyobjc_performSelectorOnMainThread_withObject_(self, aSelector, arg): result = [] self.performSelectorOnMainThread_withObject_waitUntilDone_( b"_pyobjc_performOnThreadWithResult:", (aSelector, arg, result), True ) isOK, result = result[0] if isOK: return result else: exc_type, exc_value, exc_trace = result _raise(exc_type, exc_value, exc_trace) if hasattr(NSObject, "performSelector_onThread_withObject_waitUntilDone_"): # These methods require Leopard, don't define them if the # platform functionality isn't present. @objc.namedSelector(b"pyobjc_performSelector:onThread:withObject:modes:") def pyobjc_performSelector_onThread_withObject_modes_( self, aSelector, thread, arg, modes ): result = [] self.performSelector_onThread_withObject_waitUntilDone_modes_( b"_pyobjc_performOnThreadWithResult:", thread, (aSelector, arg, result), True, modes, ) isOK, result = result[0] if isOK: return result else: exc_type, exc_value, exc_trace = result _raise(exc_type, exc_value, exc_trace) @objc.namedSelector(b"pyobjc_performSelector:onThread:withObject:") def pyobjc_performSelector_onThread_withObject_(self, aSelector, thread, arg): result = [] self.performSelector_onThread_withObject_waitUntilDone_( b"_pyobjc_performOnThreadWithResult:", thread, (aSelector, arg, result), True, ) isOK, result = result[0] if isOK: return result else: exc_type, exc_value, exc_trace = result _raise(exc_type, exc_value, exc_trace)
class NSBundle(objc.Category(NS.Bundle)): @objc.typedSelector(NS.Bundle.bundleIdentifier.signature) def uitoolsBundleIdentifier(self): if self == NSBundle.mainBundle(): return bundle_id return self.uitoolsBundleIdentifier()