/*
|
/*
|
* Copyright (c) 2009, Jim Riggs, Christian Serving, L.L.C.
|
* Copyright (c) 2009, Jim Riggs, Christian Serving, L.L.C.
|
|
|
*
|
*
|
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
* modification, are permitted provided that the following conditions are
|
* modification, are permitted provided that the following conditions are
|
* met:
|
* met:
|
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
* * Redistributions in binary form must reproduce the above
|
* * Redistributions in binary form must reproduce the above
|
* copyright notice, this list of conditions and the following
|
* copyright notice, this list of conditions and the following
|
* disclaimer in the documentation and/or other materials provided
|
* disclaimer in the documentation and/or other materials provided
|
* with the distribution.
|
* with the distribution.
|
* * Neither the name of Christian Serving, L.L.C. nor the names of
|
* * Neither the name of Christian Serving, L.L.C. nor the names of
|
* its contributors may be used to endorse or promote products
|
* its contributors may be used to endorse or promote products
|
* derived from this software without specific prior written
|
* derived from this software without specific prior written
|
* permission.
|
* permission.
|
*
|
*
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
*/
|
*/
|
|
|
#import "TruePreviewMessageViewer.h"
|
#import "TruePreviewMessageViewer.h"
|
|
|
@implementation TruePreviewMessageViewer
|
@implementation TruePreviewMessageViewer
|
|
|
#pragma mark Class methods
|
#pragma mark Class methods
|
|
|
+ (NSMutableDictionary*)truePreviewTimers {
|
+ (NSMutableDictionary*)truePreviewTimers {
|
static NSMutableDictionary* sTimers = nil;
|
static NSMutableDictionary* sTimers = nil;
|
|
|
if (sTimers == nil) {
|
if (sTimers == nil) {
|
sTimers = [[NSMutableDictionary alloc] initWithCapacity:1];
|
sTimers = [[NSMutableDictionary alloc] initWithCapacity:1];
|
}
|
}
|
|
|
return sTimers;
|
return sTimers;
|
}
|
}
|
|
|
#pragma mark Swizzled instance methods
|
#pragma mark Swizzled instance methods
|
|
|
- (void)truePreviewDealloc {
|
- (void)truePreviewDealloc {
|
[self truePreviewReset];
|
[self truePreviewReset];
|
[[[self class] truePreviewTimers ]
|
[[[self class] truePreviewTimers ]
|
removeObjectForKey:[NSNumber numberWithUnsignedLong:(unsigned long)self]
|
removeObjectForKey:[NSNumber numberWithUnsignedLong:(unsigned long)self]
|
];
|
];
|
[self truePreviewDealloc];
|
[self truePreviewDealloc];
|
}
|
}
|
|
|
- (void)truePreviewForwardAsAttachment:(id)inSender {
|
- (void)truePreviewForwardAsAttachment:(id)inSender {
|
id theMessage = [self currentDisplayedMessage];
|
id theMessage = [self currentDisplayedMessage];
|
|
|
if ([theMessage isKindOfClass:NSClassFromString(@"LibraryMessage")]) {
|
if ([theMessage isKindOfClass:NSClassFromString(@"LibraryMessage")]) {
|
NSDictionary* theSettings = [theMessage truePreviewSettings];
|
NSDictionary* theSettings = [theMessage truePreviewSettings];
|
|
|
if ([[theSettings objectForKey:@"forward"] boolValue]) {
|
if ([[theSettings objectForKey:@"forward"] boolValue]) {
|
[self truePreviewReset];
|
[self truePreviewReset];
|
[theMessage truePreviewMarkAsViewed];
|
[theMessage truePreviewMarkAsViewed];
|
}
|
}
|
}
|
}
|
|
|
[self truePreviewForwardAsAttachment:inSender];
|
[self truePreviewForwardAsAttachment:inSender];
|
}
|
}
|
|
|
- (void)truePreviewForwardMessage:(id)inSender {
|
- (void)truePreviewForwardMessage:(id)inSender {
|
id theMessage = [self currentDisplayedMessage];
|
id theMessage = [self currentDisplayedMessage];
|
|
|
if ([theMessage isKindOfClass:NSClassFromString(@"LibraryMessage")]) {
|
if ([theMessage isKindOfClass:NSClassFromString(@"LibraryMessage")]) {
|
NSDictionary* theSettings = [theMessage truePreviewSettings];
|
NSDictionary* theSettings = [theMessage truePreviewSettings];
|
|
|
if ([[theSettings objectForKey:@"forward"] boolValue]) {
|
if ([[theSettings objectForKey:@"forward"] boolValue]) {
|
[self truePreviewReset];
|
[self truePreviewReset];
|
[theMessage truePreviewMarkAsViewed];
|
[theMessage truePreviewMarkAsViewed];
|
}
|
}
|
}
|
}
|
|
|
[self truePreviewForwardMessage:inSender];
|
[self truePreviewForwardMessage:inSender];
|
}
|
}
|
|
|
- (void)truePreviewMarkAsRead:(id)inSender {
|
- (void)truePreviewMarkAsRead:(id)inSender {
|
[self truePreviewReset];
|
[self truePreviewReset];
|
[self truePreviewMarkAsRead:inSender];
|
[self truePreviewMarkAsRead:inSender];
|
}
|
}
|
|
|
- (void)truePreviewMarkAsUnread:(id)inSender {
|
- (void)truePreviewMarkAsUnread:(id)inSender {
|
[self truePreviewReset];
|
[self truePreviewReset];
|
[self truePreviewMarkAsUnread:inSender];
|
[self truePreviewMarkAsUnread:inSender];
|
}
|
}
|
|
|
- (void)truePreviewMessageNoLongerDisplayedInTextView:(NSNotification*)inNotification {
|
- (void)truePreviewMessageNoLongerDisplayedInTextView:(NSNotification*)inNotification {
|
[self truePreviewMessageNoLongerDisplayedInTextView:inNotification];
|
[self truePreviewMessageNoLongerDisplayedInTextView:inNotification];
|
|
|
// we receive notifications from all MessageContentControllers
|
// we receive notifications from all MessageContentControllers
|
if ([inNotification object ] != object_getIvar (self, class_getInstanceVariable ([self class], "_contentController" ))) {
|
if ([inNotification object ] != object_getIvar (self, class_getInstanceVariable ([self class], "_contentController" ))) {
|
return;
|
return;
|
}
|
}
|
|
|
[self truePreviewReset];
|
[self truePreviewReset];
|
}
|
}
|
|
|
- (void)truePreviewMessageWasDisplayedInTextView:(NSNotification*)inNotification {
|
- (void)truePreviewMessageWasDisplayedInTextView:(NSNotification*)inNotification {
|
[self truePreviewMessageWasDisplayedInTextView:inNotification];
|
[self truePreviewMessageWasDisplayedInTextView:inNotification];
|
|
|
// we receive notifications from all MessageContentControllers
|
// we receive notifications from all MessageContentControllers
|
if ([inNotification object ] != object_getIvar (self, class_getInstanceVariable ([self class], "_contentController" ))) {
|
if ([inNotification object ] != object_getIvar (self, class_getInstanceVariable ([self class], "_contentController" ))) {
|
return;
|
return;
|
}
|
}
|
|
|
id theMessage = [[inNotification userInfo] objectForKey:@"MessageKey"];
|
id theMessage = [[inNotification userInfo] objectForKey:@"MessageKey"];
|
|
|
if ([theMessage isKindOfClass:NSClassFromString(@"LibraryMessage")]) {
|
if ([theMessage isKindOfClass:NSClassFromString(@"LibraryMessage")]) {
|
NSDictionary* theSettings = [theMessage truePreviewSettings];
|
NSDictionary* theSettings = [theMessage truePreviewSettings];
|
|
|
if (
|
if (
|
([[theSettings objectForKey:@"delay"] floatValue] == TRUEPREVIEW_DELAY_IMMEDIATE)
|
([[theSettings objectForKey:@"delay"] floatValue] == TRUEPREVIEW_DELAY_IMMEDIATE)
|
|| (
|
|| (
|
[[theSettings objectForKey:@"window"] boolValue]
|
[[theSettings objectForKey:@"window"] boolValue]
|
&& [self isKindOfClass:NSClassFromString(@"SingleMessageViewer")]
|
&& [self isKindOfClass:NSClassFromString(@"SingleMessageViewer")]
|
)
|
)
|
) {
|
) {
|
[self truePreviewReset];
|
[self truePreviewReset];
|
[theMessage truePreviewMarkAsViewed];
|
[theMessage truePreviewMarkAsViewed];
|
|
|
return;
|
return;
|
}
|
}
|
|
|
float theDelay = [[theSettings objectForKey:@"delay"] floatValue];
|
float theDelay = [[theSettings objectForKey:@"delay"] floatValue];
|
|
|
if (theDelay > TRUEPREVIEW_DELAY_IMMEDIATE) {
|
if (theDelay > TRUEPREVIEW_DELAY_IMMEDIATE) {
|
[self truePreviewReset];
|
[self truePreviewReset];
|
[self
|
[self
|
truePreviewSetTimer:[NSTimer
|
truePreviewSetTimer:[NSTimer
|
scheduledTimerWithTimeInterval:theDelay
|
scheduledTimerWithTimeInterval:theDelay
|
target:self
|
target:self
|
selector:@selector(truePreviewTimerFired:)
|
selector:@selector(truePreviewTimerFired:)
|
userInfo:nil
|
userInfo:nil
|
repeats:NO
|
repeats:NO
|
]
|
]
|
];
|
];
|
}
|
}
|
|
|
if (
|
if (
|
![self isKindOfClass:NSClassFromString(@"SingleMessageViewer")]
|
![self isKindOfClass:NSClassFromString(@"SingleMessageViewer")]
|
&& [[theSettings objectForKey:@"scroll"] boolValue]
|
&& [[theSettings objectForKey:@"scroll"] boolValue]
|
) {
|
) {
|
|
// listen for selection change (mouse down ) on message content view
|
|
[[NSNotificationCenter defaultCenter]
|
|
addObserver:self
|
|
selector:@selector(truePreviewMessageClickedOrScrolled:)
|
|
name:@"WebViewDidChangeSelectionNotification"
|
|
object: [[object_getIvar (self, class_getInstanceVariable ([self class], "_contentController" )) currentDisplay ] contentView ]
|
|
];
|
|
|
// listen for bounds change notification on the message's clip view
|
// listen for bounds change notification on the message's clip view
|
[[NSNotificationCenter defaultCenter]
|
[[NSNotificationCenter defaultCenter]
|
addObserver:self
|
addObserver:self
|
selector:@selector(truePreviewBoundsDidChange:)
|
selector:@selector(truePreviewMessageClickedOrScrolled:)
|
name:NSViewBoundsDidChangeNotification
|
name:NSViewBoundsDidChangeNotification
|
object: [[[[object_getIvar (self, class_getInstanceVariable ([self class], "_contentController" )) currentDisplay ] contentView ] enclosingScrollView ] contentView ]
|
object: [[[[object_getIvar (self, class_getInstanceVariable ([self class], "_contentController" )) currentDisplay ] contentView ] enclosingScrollView ] contentView ]
|
];
|
];
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
- (void)truePreviewReplyAllMessage:(id)inSender {
|
- (void)truePreviewReplyAllMessage:(id)inSender {
|
id theMessage = [self currentDisplayedMessage];
|
id theMessage = [self currentDisplayedMessage];
|
|
|
if ([theMessage isKindOfClass:NSClassFromString(@"LibraryMessage")]) {
|
if ([theMessage isKindOfClass:NSClassFromString(@"LibraryMessage")]) {
|
NSDictionary* theSettings = [theMessage truePreviewSettings];
|
NSDictionary* theSettings = [theMessage truePreviewSettings];
|
|
|
if ([[theSettings objectForKey:@"reply"] boolValue]) {
|
if ([[theSettings objectForKey:@"reply"] boolValue]) {
|
[self truePreviewReset];
|
[self truePreviewReset];
|
[theMessage truePreviewMarkAsViewed];
|
[theMessage truePreviewMarkAsViewed];
|
}
|
}
|
}
|
}
|
|
|
[self truePreviewReplyAllMessage:inSender];
|
[self truePreviewReplyAllMessage:inSender];
|
}
|
}
|
|
|
- (void)truePreviewReplyMessage:(id)inSender {
|
- (void)truePreviewReplyMessage:(id)inSender {
|
id theMessage = [self currentDisplayedMessage];
|
id theMessage = [self currentDisplayedMessage];
|
|
|
if ([theMessage isKindOfClass:NSClassFromString(@"LibraryMessage")]) {
|
if ([theMessage isKindOfClass:NSClassFromString(@"LibraryMessage")]) {
|
NSDictionary* theSettings = [theMessage truePreviewSettings];
|
NSDictionary* theSettings = [theMessage truePreviewSettings];
|
|
|
if ([[theSettings objectForKey:@"reply"] boolValue]) {
|
if ([[theSettings objectForKey:@"reply"] boolValue]) {
|
[self truePreviewReset];
|
[self truePreviewReset];
|
[theMessage truePreviewMarkAsViewed];
|
[theMessage truePreviewMarkAsViewed];
|
}
|
}
|
}
|
}
|
|
|
[self truePreviewReplyMessage:inSender];
|
[self truePreviewReplyMessage:inSender];
|
}
|
}
|
|
|
#pragma mark Accessors
|
#pragma mark Accessors
|
|
|
- (NSTimer*)truePreviewTimer {
|
- (NSTimer*)truePreviewTimer {
|
return [[[self class] truePreviewTimers ]
|
return [[[self class] truePreviewTimers ]
|
objectForKey:[NSNumber numberWithUnsignedLong:(unsigned long)self]
|
objectForKey:[NSNumber numberWithUnsignedLong:(unsigned long)self]
|
];
|
];
|
}
|
}
|
|
|
- (void)truePreviewSetTimer:(NSTimer*)inTimer {
|
- (void)truePreviewSetTimer:(NSTimer*)inTimer {
|
[[[self class] truePreviewTimers ]
|
[[[self class] truePreviewTimers ]
|
setObject:inTimer
|
setObject:inTimer
|
forKey:[NSNumber numberWithUnsignedLong:(unsigned long)self]
|
forKey:[NSNumber numberWithUnsignedLong:(unsigned long)self]
|
];
|
];
|
}
|
}
|
|
|
#pragma mark Instance methods
|
#pragma mark Instance methods
|
|
|
- (void)truePreviewReset {
|
- (void)truePreviewReset {
|
NSTimer* theTimer = [self truePreviewTimer];
|
NSTimer* theTimer = [self truePreviewTimer];
|
|
|
if ((theTimer != nil) && [theTimer isValid]) {
|
if ((theTimer != nil) && [theTimer isValid]) {
|
[theTimer invalidate];
|
[theTimer invalidate];
|
}
|
}
|
|
|
// stop observing when changed
|
// stop observing when changed
|
|
[[NSNotificationCenter defaultCenter]
|
|
removeObserver:self
|
|
name:@"WebViewDidChangeSelectionNotification"
|
|
object: [[object_getIvar (self, class_getInstanceVariable ([self class], "_contentController" )) currentDisplay ] contentView ]
|
|
];
|
[[NSNotificationCenter defaultCenter]
|
[[NSNotificationCenter defaultCenter]
|
removeObserver:self
|
removeObserver:self
|
name:NSViewBoundsDidChangeNotification
|
name:NSViewBoundsDidChangeNotification
|
object: [[[[object_getIvar (self, class_getInstanceVariable ([self class], "_contentController" )) currentDisplay ] contentView ] enclosingScrollView ] contentView ]
|
object: [[[[object_getIvar (self, class_getInstanceVariable ([self class], "_contentController" )) currentDisplay ] contentView ] enclosingScrollView ] contentView ]
|
];
|
];
|
}
|
}
|
|
|
- (void)truePreviewTimerFired:(NSTimer*)inTimer {
|
- (void)truePreviewTimerFired:(NSTimer*)inTimer {
|
[self truePreviewReset];
|
[self truePreviewReset];
|
|
|
if ([[self currentDisplayedMessage] isKindOfClass:NSClassFromString(@"LibraryMessage")]) {
|
if ([[self currentDisplayedMessage] isKindOfClass:NSClassFromString(@"LibraryMessage")]) {
|
[[self currentDisplayedMessage] truePreviewMarkAsViewed];
|
[[self currentDisplayedMessage] truePreviewMarkAsViewed];
|
}
|
}
|
}
|
}
|
|
|
- (void)truePreviewBoundsDidChange:(NSNotification*)inNotification {
|
- (void)truePreviewMessageClickedOrScrolled:(NSNotification*)inNotification {
|
// ignore the first time we get the notification; it may be an initial scroll
|
// ignore the first time we get the notification; it may be an initial scroll
|
// to the origin after changing messages
|
// to the origin after changing messages
|
static BOOL sIsFirstTime = YES;
|
static BOOL sIsFirstTime = YES;
|
|
|
if (sIsFirstTime) {
|
if ([NSViewBoundsDidChangeNotification isEqualToString:[inNotification name]] && sIsFirstTime) {
|
sIsFirstTime = NO;
|
sIsFirstTime = NO;
|
|
|
return;
|
return;
|
}
|
}
|
|
|
sIsFirstTime = YES;
|
sIsFirstTime = YES;
|
|
|
[self truePreviewReset];
|
[self truePreviewReset];
|
|
|
if ([[self currentDisplayedMessage] isKindOfClass:NSClassFromString(@"LibraryMessage")]) {
|
if ([[self currentDisplayedMessage] isKindOfClass:NSClassFromString(@"LibraryMessage")]) {
|
[[self currentDisplayedMessage] truePreviewMarkAsViewed];
|
[[self currentDisplayedMessage] truePreviewMarkAsViewed];
|
}
|
}
|
}
|
}
|
|
|
@end
|
@end
|
|
|
|
|