/trunk/Source
* @updated $Date$ |
*/ |
|
#import <AppKit/NSPreferences.h> |
#import <AppKit/NSPreferencesModule.h> |
#import <Message/MailAccount.h> |
|
#import "TruePreview.h" |
|
/*! |
* @class |
* The <code>TruePreviewPreferencesModule</code> class is the subclass of |
* @updated $Date$ |
*/ |
|
#import <Message/LibraryMessage.h> |
|
#import "TruePreview.h" |
|
/*! |
* @category |
* @class |
* Adds a method for overriding the "mark as viewed" behavior of |
* <code>LibraryMessage</code>. |
* @version \@(#) $Id$ |
* @updated $Date$ |
*/ |
@interface LibraryMessage (TruePreviewLibraryMessage) |
@interface TruePreviewLibraryMessage : NSObject { |
} |
|
#pragma mark Instance methods |
/*! @group Instance methods */ |
#pragma mark Swizzled instance methods |
/*! @group Swizzled instance methods */ |
|
/*! |
* Does nothing. The replacement behavior is handled in |
* <code>-[TableViewManager setCurrentDisplayedMessage]</code>. |
* <code>TruePreviewMessageViewer</code>. |
*/ |
- (void)truePreviewMarkAsViewed; |
|
#pragma mark Instance methods |
/*! @group Instance methods */ |
|
/*! |
* Returns the TruePreview settings appropriate for this message. |
* @result |
* An <code>NSMutableDictionary</code> containing the keys <code>delay</code>, |
* <code>window</code>, and <code>scroll</code> and their respective values |
* based on the default settings and/or the settings for this message's |
* account. |
*/ |
- (NSMutableDictionary*)truePreviewSettings; |
|
@end |
|
- (void)willBeDisplayed { |
[super willBeDisplayed]; |
|
|
// build the list of accounts |
NSDictionary* theAccountDict = [[NSUserDefaults standardUserDefaults] objectForKey:@"TruePreviewAccountSettings"]; |
NSMutableArray* theAccounts = [NSMutableArray array]; |
NSEnumerator* theEnum = [[[MailAccount remoteAccounts] valueForKey:@"displayName"] objectEnumerator]; |
NSEnumerator* theEnum = [[[NSClassFromString(@"MailAccount") remoteAccounts] valueForKey:@"displayName"] objectEnumerator]; |
NSString* theDisplayName = nil; |
|
|
while (theDisplayName = [theEnum nextObject]) { |
NSMutableDictionary* theAccount = [[theAccountDict objectForKey:theDisplayName] mutableCopy]; |
[theAccounts |
addObject:((theAccount == nil) |
? [NSMutableDictionary dictionaryWithObject:theDisplayName forKey:@"displayName"] |
: theAccount |
) |
NSMutableDictionary* theAccount = [NSMutableDictionary dictionaryWithObjectsAndKeys: |
theDisplayName, @"displayName", |
[NSNumber numberWithInt:TRUEPREVIEW_DELAY_DEFAULT], @"delay", |
[NSNumber numberWithInt:TRUEPREVIEW_DELAY_DEFAULT], @"window", |
[NSNumber numberWithInt:TRUEPREVIEW_DELAY_DEFAULT], @"scroll", |
nil |
]; |
|
[theAccount addEntriesFromDictionary:[theAccountDict objectForKey:theDisplayName]]; |
[theAccounts addObject:theAccount]; |
} |
|
// watch the array for changes to save the user defaults |
[theAccounts |
addObserver:self |
toObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [theAccounts count])] |
forKeyPath:@"custom" |
forKeyPath:@"delay" |
options:0 |
context:theAccounts |
]; |
[theAccounts |
addObserver:self |
toObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [theAccounts count])] |
forKeyPath:@"delay" |
forKeyPath:@"window" |
options:0 |
context:theAccounts |
]; |
|
[theAccounts |
addObserver:self |
toObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [theAccounts count])] |
forKeyPath:@"scroll" |
options:0 |
context:theAccounts |
]; |
|
[fldAccountArrayController setContent:theAccounts]; |
} |
|
} |
|
[[NSUserDefaults standardUserDefaults] setObject:theAccountDict forKey:@"TruePreviewAccountSettings"]; |
[[NSUserDefaults standardUserDefaults] synchronize]; |
} |
|
@end |
|
#import "TruePreviewLibraryMessage.h" |
|
@implementation LibraryMessage (TruePreviewLibraryMessage) |
@implementation TruePreviewLibraryMessage |
|
#pragma mark Instance methods |
#pragma mark Swizzled instance methods |
|
- (void)truePreviewMarkAsViewed { |
/* nothing */ |
} |
|
#pragma mark Instance methods |
|
- (NSMutableDictionary*)truePreviewSettings { |
NSMutableDictionary* theSettings = [NSMutableDictionary dictionaryWithObjectsAndKeys: |
[[NSUserDefaults standardUserDefaults] objectForKey:@"TruePreviewDelay"], @"delay", |
[[NSUserDefaults standardUserDefaults] objectForKey:@"TruePreviewWindow"], @"window", |
[[NSUserDefaults standardUserDefaults] objectForKey:@"TruePreviewScroll"], @"scroll", |
nil |
]; |
NSMutableDictionary* theAccountSettings = [ |
[[NSUserDefaults standardUserDefaults] objectForKey:@"TruePreviewAccountSettings"] |
objectForKey:[[self account] displayName] |
]; |
|
if (theAccountSettings != nil) { |
for (id theKey in [NSArray arrayWithObjects:@"delay", @"window", @"scroll", nil]) { |
id theValue = [theAccountSettings objectForKey:theKey]; |
|
if ((theValue != nil) && ([theValue intValue] != TRUEPREVIEW_DELAY_DEFAULT)) { |
[theSettings setObject:theValue forKey:theKey]; |
} |
} |
} |
|
return theSettings; |
} |
|
@end |
|
#import <objc/objc-class.h> |
|
#import <Mail/MVMailBundle.h> |
#import <Mail/TableViewManager.h> |
#import <Message/LibraryMessage.h> |
|
#import "TruePreviewLibraryMessage.h" |
#import "TruePreviewMessageViewer.h" |
#import "TruePreviewPreferences.h" |
#import "TruePreviewPreferencesModule.h" |
#import "TruePreviewPreferenceValueTransformer.h" |
|
/*! |
* @class |
* The <code>TruePreview</code> class is the subclass of |
* <code>MVMailBundle</code> that provide the plugin entrypoint for the |
* <code>MVMailBundle</code> that provides the plugin entrypoint for the |
* TruePreview plugin. |
* @version \@(#) $Id$ |
* @updated $Date$ |
*/ |
@interface TruePreview : MVMailBundle { |
@interface TruePreview : NSObject { |
} |
|
#pragma mark Class initialization |
/*! @group Class methods */ |
|
/*! |
* Adds the methods from this class to the specified class. This is in essence |
* adding a category, but we do it through the objective-c runtime, because of |
* the "hiding" of classes in >= 10.6. |
* @param inClass |
* The <code>Class</code> to which this class's methods should be added. |
*/ |
+ (void)truePreviewAddAsCategoryToClass:(Class)inClass; |
|
/*! |
* Swaps ("swizzles") two methods. Based on |
* <a href="http://www.cocoadev.com/index.pl?MethodSwizzling">http://www.cocoadev.com/index.pl?MethodSwizzling</a>. |
* @param inOriginalSelector |
*/ |
|
#ifdef __OBJC__ |
#import <Cocoa/Cocoa.h> |
#import <Cocoa/Cocoa.h> |
|
#define TRUEPREVIEW_DELAY_MAX 30 |
#define TRUEPREVIEW_DELAY_IMMEDIATE 0 |
#define TRUEPREVIEW_DELAY_DEFAULT -1 |
#define TRUEPREVIEW_DELAY_NEVER -2 |
|
#endif |
* @updated $Date$ |
*/ |
|
#import <AppKit/NSPreferences.h> |
|
#import "TruePreview.h" |
|
/*! |
* @category |
* @class |
* Adds a method for overriding the preference-loading behavior of |
* <code>NSPreferences</code>. |
* @version \@(#) $Id$ |
* @updated $Date$ |
*/ |
@interface NSPreferences (TruePreviewPreferences) |
@interface TruePreviewPreferences : NSObject { |
} |
|
#pragma mark Class methods |
/*! @group Class methods */ |
#pragma mark Swizzled class methods |
/*! @group Swizzled class methods */ |
|
/*! |
* Adds the TruePreview preferences. |
#pragma mark Class initialization |
|
+ (void)initialize { |
[TruePreview registerBundle]; |
if (self == [TruePreview class]) { |
class_setSuperclass(self, NSClassFromString(@"MVMailBundle")); |
} |
|
[super registerBundle]; |
|
// register the preferences value transformers |
[NSValueTransformer |
setValueTransformer:[[TruePreviewPreferenceValueTransformer alloc] init] |
forName:@"TruePreviewPreferenceValueTransformer" |
]; |
[NSValueTransformer |
setValueTransformer:[[TruePreviewPreferenceValueTransformerDelay alloc] init] |
forName:@"TruePreviewPreferenceValueTransformerDelay" |
]; |
[NSValueTransformer |
setValueTransformer:[[TruePreviewPreferenceValueTransformerDelayEditIndicator alloc] init] |
forName:@"TruePreviewPreferenceValueTransformerDelayEditIndicator" |
]; |
|
// add our "categories" |
[TruePreviewLibraryMessage truePreviewAddAsCategoryToClass:NSClassFromString(@"LibraryMessage")]; |
[TruePreviewMessageViewer truePreviewAddAsCategoryToClass:NSClassFromString(@"MessageViewer")]; |
[TruePreviewPreferences truePreviewAddAsCategoryToClass:NSClassFromString(@"NSPreferences")]; |
|
// do our swizzles |
[NSPreferences |
truePreviewSwizzleMethod:@selector(sharedPreferences) |
withMethod:@selector(truePreviewSharedPreferences) |
isClassMethod:YES |
]; |
[LibraryMessage |
[NSClassFromString(@"LibraryMessage") |
truePreviewSwizzleMethod:@selector(markAsViewed) |
withMethod:@selector(truePreviewMarkAsViewed) |
isClassMethod:NO |
]; |
[TableViewManager |
truePreviewSwizzleMethod:@selector(setCurrentDisplayedMessage:) |
withMethod:@selector(truePreviewSetCurrentDisplayedMessage:) |
[NSClassFromString(@"MessageViewer") |
truePreviewSwizzleMethod:@selector(dealloc) |
withMethod:@selector(truePreviewDealloc) |
isClassMethod:NO |
]; |
[NSClassFromString(@"MessageViewer") |
truePreviewSwizzleMethod:@selector(markAsRead:) |
withMethod:@selector(truePreviewMarkAsRead:) |
isClassMethod:NO |
]; |
[NSClassFromString(@"MessageViewer") |
truePreviewSwizzleMethod:@selector(markAsUnread:) |
withMethod:@selector(truePreviewMarkAsUnread:) |
isClassMethod:NO |
]; |
[NSClassFromString(@"MessageViewer") |
truePreviewSwizzleMethod:@selector(messageWasDisplayedInTextView:) |
withMethod:@selector(truePreviewMessageWasDisplayedInTextView:) |
isClassMethod:NO |
]; |
[NSClassFromString(@"MessageViewer") |
truePreviewSwizzleMethod:@selector(messageNoLongerDisplayedInTextView:) |
withMethod:@selector(truePreviewMessageNoLongerDisplayedInTextView:) |
isClassMethod:NO |
]; |
[NSClassFromString(@"NSPreferences") |
truePreviewSwizzleMethod:@selector(sharedPreferences) |
withMethod:@selector(truePreviewSharedPreferences) |
isClassMethod:YES |
]; |
|
// set defaults |
[[NSUserDefaults standardUserDefaults] |
registerDefaults:[NSDictionary |
dictionaryWithObject:[NSNumber numberWithInt:0] forKey:@"TruePreviewDelay" |
registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys: |
[NSNumber numberWithInt:TRUEPREVIEW_DELAY_IMMEDIATE], @"TruePreviewDelay", |
[NSNumber numberWithInt:NSOnState], @"TruePreviewWindow", |
[NSNumber numberWithInt:NSOffState], @"TruePreviewScroll", |
nil |
] |
]; |
|
// we're all set |
NSLog( |
@"Loaded TruePreview plugin %@", |
[[NSBundle bundleForClass:[TruePreview class]] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey] |
} |
|
+ (NSString*)preferencesOwnerClassName { |
return NSStringFromClass([TruePreviewPreferencesModule class]); |
return @"TruePreviewPreferencesModule"; |
} |
|
+ (NSString*)preferencesPanelName { |
|
#pragma mark Class methods |
|
+ (void)truePreviewAddAsCategoryToClass:(Class)inClass { |
unsigned int theCount = 0; |
Method* theMethods = class_copyMethodList(object_getClass([self class]), &theCount); |
Class theClass = object_getClass(inClass); |
unsigned int i = 0; |
|
while (YES) { |
for (i = 0; i < theCount; i++) { |
if ( |
!class_addMethod( |
theClass, |
method_getName(theMethods[i]), |
method_getImplementation(theMethods[i]), |
method_getTypeEncoding(theMethods[i]) |
) |
) { |
NSLog( |
@"truePreviewAddAsCategoryToClass: could not add %@ to %@", |
NSStringFromSelector(method_getName(theMethods[i])), |
inClass |
); |
} |
} |
|
if (theMethods != nil) { |
free(theMethods); |
} |
|
if (theClass != inClass) { |
theClass = inClass; |
theMethods = class_copyMethodList([self class], &theCount); |
} |
else { |
break; |
} |
} |
} |
|
+ (void)truePreviewSwizzleMethod:(SEL)inOriginalSelector withMethod:(SEL)inReplacementSelector isClassMethod:(BOOL)inIsClassMethod { |
Method theOriginalMethod = (!inIsClassMethod |
? class_getInstanceMethod([self class], inOriginalSelector) |
: class_getClassMethod([self class], inReplacementSelector) |
); |
|
#if __OBJC2__ |
method_exchangeImplementations(theOriginalMethod, theReplacementMethod); |
#else |
char* theOriginalTypes = theOriginalMethod->method_types; |
|
theOriginalMethod->method_types = theReplacementMethod->method_types; |
theReplacementMethod->method_types = theOriginalTypes; |
|
IMP theOriginalImp = theOriginalMethod->method_imp; |
|
theOriginalMethod->method_imp = theReplacementMethod->method_imp; |
theReplacementMethod->method_imp = theOriginalImp; |
#endif |
} |
|
@end |
|
#import "TruePreviewPreferences.h" |
|
@implementation NSPreferences (TruePreviewPreferences) |
@implementation TruePreviewPreferences |
|
#pragma mark Class methods |
#pragma mark Swizzled class methods |
|
+ (id)truePreviewSharedPreferences { |
static BOOL sAdded = NO; |
NSPreferences* thePreferences = [NSPreferences truePreviewSharedPreferences]; |
id thePreferences = [NSClassFromString(@"NSPreferences") truePreviewSharedPreferences]; |
|
if ((thePreferences != nil) && !sAdded) { |
sAdded = YES; |
|
[[NSPreferences truePreviewSharedPreferences] |
[[NSClassFromString(@"NSPreferences") truePreviewSharedPreferences] |
addPreferenceNamed:[TruePreview preferencesPanelName] |
owner:[TruePreviewPreferencesModule sharedInstance] |
]; |
} |
|
return [NSPreferences truePreviewSharedPreferences]; |
return [NSClassFromString(@"NSPreferences") truePreviewSharedPreferences]; |
} |
|
@end |