Пример #1
0
class MailApp(Category(MailApp)):
    @classmethod
    def registerQuoteFixApplication(cls, app):
        cls.app = app

    @swizzle(MailApp, 'sendEvent:')
    def sendEvent(self, original, event):
        if not hasattr(self, 'app'):
            original(self, event)
            return

        # Keep track of an active Opt key
        if event.type() == NSFlagsChanged:
            flags = event.modifierFlags()
            self.app.toggle_key_active = (
                flags & NSAlternateKeyMask) and not (flags & NSControlKeyMask)

        # Handle reply/reply-all (XXX: won't work if you have assigned a different shortcut key to these actions)
        if self.app.toggle_key_active and event.type(
        ) == NSKeyDown and event.charactersIgnoringModifiers().lower() == 'r':
            # Strip the Opt-key from the event
            event = NSEvent.keyEventWithType_location_modifierFlags_timestamp_windowNumber_context_characters_charactersIgnoringModifiers_isARepeat_keyCode_(
                event.type(), event.locationInWindow(),
                event.modifierFlags() & ~NSAlternateKeyMask, event.timestamp(),
                event.windowNumber(), event.context(), event.characters(),
                event.charactersIgnoringModifiers(), event.isARepeat(),
                event.keyCode())
        original(self, event)
Пример #2
0
    class ComposeViewController(Category(ComposeViewController)):
        @classmethod
        def registerQuoteFixApplication(cls, app):
            cls.app = app

        @swizzle(ComposeViewController, 'finishLoadingEditor',
                 '_finishLoadingEditor')
        def finishLoadingEditor(self, original):
            logger.debug('[ComposeViewController finishLoadingEditor]')
            original(self)
            self.fix()

            # Don't let any changes made during quotefixing trigger the 'Save
            # to Drafts' alert.
            self.setHasUserMadeChanges_(False)
            self.backEnd().setHasChanges_(False)

        @swizzle(ComposeViewController, 'show')
        def show(self, original):
            logger.debug('[ComposeViewController show]')
            original(self)

            # If toggle key is active, temporarily switch the active state
            is_active = self.app.toggle_key_active ^ self.app.is_active
            if not is_active or not self.app.is_quotefixing:
                return

            # When the compose view should be shown, we assume any animations
            # are done and we can position the cursor.
            view = self.composeWebView()
            htmldom = view.mainFrame().DOMDocument()
            if self.app.move_cursor_to_top:
                view.moveToBeginningOfDocument_(self)
            elif not self.move_above_new_signature(htmldom, view):
                view.moveToEndOfDocument_(self)
Пример #3
0
class NSTreeController(Category(ak.NSTreeController)):
    """Category to make ak.NSTreeController more useable

    Based on extension by Wil Shipley
    http://www.wilshipley.com/blog/2006/04/pimp-my-code-part-10-whining-about.html

    See also:
    http://jonathandann.wordpress.com/2008/04/06/using-nstreecontroller/
    http://www.cocoabuilder.com/archive/message/cocoa/2008/5/18/207078
    """
    def setSelectedObject_(self, obj):
        self.setSelectedObjects_([obj])

    def setSelectedObjects_(self, objects):
        paths = [self.indexPathForObject_(obj) for obj in objects]
        self.setSelectionIndexPaths_(paths)

    def objectAtArrangedIndexPath_(self, path):
        return self.arrangedObjects().objectAtIndexPath_(path)

    def nodeAtArrangedIndexPath_(self, path):
        return self.arrangedObjects().nodeAtIndexPath_(path)

    def nodeForObject_(self, obj):
        return self.nodeAtArrangedIndexPath_(self.indexPathForObject_(obj))

    def indexPathForObject_(self, obj):
        return self._indexPathFromIndexPath_inChildren_toObject_(
            None, self.content(), obj)

    def _indexPathFromIndexPath_inChildren_toObject_(self, basePath, children,
                                                     obj):
        for childIndex, child in enumerate(children):
            lkp = self.leafKeyPath()
            if lkp and child.valueForKeyPath_(lkp):
                childsChildren = []
            else:
                ckp = self.countKeyPath()
                if ckp:
                    childCount = child.valueForKeyPath_(ckp).unsignedIntValue()
                if ckp and not childCount:
                    childsChildren = []
                else:
                    childsChildren = child.valueForKeyPath_(
                        self.childrenKeyPath())
            if obj is child or childsChildren:
                if basePath is None:
                    path = fn.NSIndexPath.indexPathWithIndex_(childIndex)
                else:
                    path = basePath.indexPathByAddingIndex_(childIndex)
                if obj is child:
                    return path
                if childsChildren:
                    path = self._indexPathFromIndexPath_inChildren_toObject_(
                        path, childsChildren, obj)
                    if path is not None:
                        return path
        return None
Пример #4
0
    class DocumentEditor(Category(DocumentEditor)):
        @classmethod
        def registerQuoteFixApplication(cls, app):
            cls.app = app

        @swizzle(DocumentEditor, 'finishLoadingEditor')
        def finishLoadingEditor(self, original):
            logger.debug('DocumentEditor finishLoadingEditor')
            original(self)
            self.fix()
Пример #5
0
    class MessageHeaders(Category(MessageHeaders)):
        @classmethod
        def registerQuoteFixApplication(cls, app):
            cls.app = app

        @swizzle(MessageHeaders,
                 'htmlStringShowingHeaderDetailLevel:useBold:useGray:')
        def htmlStringShowingHeaderDetailLevel_useBold_useGray_(
                self, original, level, bold, gray):
            if self.app.use_custom_forwarding_attribution and self.app.remove_apple_mail_forward_attribution:
                return ''
            return original(self, level, bold, gray)
Пример #6
0
class NSUserDefaults(Category(lookUpClass('NSUserDefaults'))):
    @property
    def bool(self):
        return DictProxy(self, 'bool')

    @property
    def string(self):
        return DictProxy(self, 'string')

    @property
    def object(self):
        return DictProxy(self, 'object')

    @property
    def int(self):
        return DictProxy(self, 'int')
Пример #7
0
class NSOutlineView(Category(ak.NSOutlineView)):
    """Category to improve usability of ak.NSOutlineView

    Originally based on extension by Wil Shipley
    http://www.wilshipley.com/blog/2006/04/pimp-my-code-part-10-whining-about.html

    See also:
    http://jonathandann.wordpress.com/2008/04/06/using-nstreecontroller/
    http://www.cocoabuilder.com/archive/message/cocoa/2008/5/18/207078
    """
    def realItemForOpaqueItem_(self, item):
        return representedObject(item)

    def iterVisibleObjects(self):
        """Iterate (row, visible object) pairs"""
        for row in range(self.numberOfRows()):
            item = self.itemAtRow_(row)
            yield row, representedObject(item)
Пример #8
0
class DocumentEditor(Category(DocumentEditor)):
    @classmethod
    def registerMailTrackApplication(cls, app):
        cls.app = app

    @swizzle(DocumentEditor, 'finishLoadingEditor')
    def finishLoadingEditor(self, original):
        logger.debug('DocumentEditor finishLoadingEditor')

        # execute original finishLoadingEditor()
        original(self)

        try:
            # if toggle key is active, temporarily switch the active state
            is_active = self.app.toggle_key_active ^ self.app.is_active

            # check if we can proceed
            if not is_active:
                logger.debug(
                    "MailTrack is not active, so no MailTracking for you!")
                return

            # grab composeView instance (this is the WebView which contains the
            # message editor) and check for the right conditions
            try:
                view = objc.getInstanceVariable(self, 'composeWebView')
            except:
                # was renamed in Lion
                view = objc.getInstanceVariable(self, '_composeWebView')

            # grab some other variables we need to perform our business
            backend = self.backEnd()
            htmldom = view.mainFrame().DOMDocument()
            htmlroot = htmldom.documentElement()
            messageType = self.messageType()

            # XXX: hack alert! if message type is DRAFT, but we can determine this
            # is actually a Send Again action, adjust the message type.
            origmsg = backend.originalMessage()
            if origmsg and messageType == DRAFT:
                # get the message viewer for this message
                viewer = MessageViewer.existingViewerShowingMessage_(origmsg)
                if not viewer:
                    # XXX: this happens with conversation view active, not sure if this is stable enough though
                    messageType = SENDAGAIN
                elif viewer:
                    # get the mailbox for the viewer
                    mailboxes = viewer.selectedMailboxes()
                    # get the Drafts mailbox
                    draftmailbox = viewer.draftsMailbox()
                    # check if they're the same; if not, it's a Send-Again
                    if draftmailbox not in mailboxes:
                        messageType = SENDAGAIN

            # send original HTML to menu for debugging
            self.app.html = htmlroot.innerHTML()

            if not self.app.is_mailtracking:
                logger.debug(
                    'mailtracking turned off in preferences, skipping that part'
                )
            elif messageType not in self.app.message_types_to_track:
                logger.debug('message type "%s" not in %s, not tracking' %
                             (messageType, self.app.message_types_to_track))
            else:
                # move cursor to end of document
                view.moveToEndOfDocument_(self)

                # perform some general cleanups
                logger.debug('calling cleanup_layout()')
                if self.cleanup_layout(htmlroot, backend):
                    backend.setHasChanges_(False)

                # move cursor to end of document
                if self.app.move_cursor_to_top:
                    view.moveToBeginningOfDocument_(self)

            # move to beginning of line
            logger.debug('calling view.moveToBeginningOfLine()')
            view.moveToBeginningOfLine_(self)

            # done
            logger.debug('MailTracking done')
        except Exception:
            logger.critical(traceback.format_exc())
            if self.app.is_debugging:
                NSRunAlertPanel(
                    'MailTrack caught an exception',
                    'The MailTrack plug-in caught an exception:\n\n' +
                    traceback.format_exc() +
                    '\nPlease contact the developer quoting the contents of this alert.',
                    None, None, None)