Flycut/AppController.m

727 lines
No EOL
26 KiB
Objective-C
Executable file

//
// AppController.m
// Jumpcut
//
// Created by Steve Cook on 4/3/06.
// Copyright 2006 __MyCompanyName__. All rights reserved.
//
// This code is open-source software subject to the MIT License; see the homepage
// at <http://jumpcut.sourceforge.net/> for details.
#import "AppController.h"
#import "SGHotKey.h"
#import "SGHotKeyCenter.h"
#import "SRRecorderCell.h"
#import "UKLoginItemRegistry.h"
#import "NSWindow+TrueCenter.h"
#define _DISPLENGTH 40
@implementation AppController
- (id)init
{
[[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:15],
@"displayNum",
[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:[NSNumber numberWithInt:9],[NSNumber numberWithInt:1179648],nil] forKeys:[NSArray arrayWithObjects:@"keyCode",@"modifierFlags",nil]],
@"ShortcutRecorder mainHotkey",
[NSNumber numberWithInt:40],
@"rememberNum",
[NSNumber numberWithInt:1],
@"savePreference",
[NSNumber numberWithInt:0],
@"menuIcon",
[NSNumber numberWithFloat:.25],
@"bezelAlpha",
[NSNumber numberWithBool:YES],
@"stickyBezel",
[NSNumber numberWithBool:NO],
@"wraparoundBezel",
[NSNumber numberWithBool:NO],// No by default
@"loadOnStartup",
[NSNumber numberWithBool:YES],
@"menuSelectionPastes",
// Flycut new options
[NSNumber numberWithFloat:500.0],
@"bezelWidth",
[NSNumber numberWithFloat:320.0],
@"bezelHeight",
nil]
];
return [super init];
}
- (void)awakeFromNib
{
// We no longer get autosave from ShortcutRecorder, so let's set the recorder by hand
if ( [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"ShortcutRecorder mainHotkey"] ) {
[mainRecorder setKeyCombo:SRMakeKeyCombo([[[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"ShortcutRecorder mainHotkey"] objectForKey:@"keyCode"] intValue],
[[[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"ShortcutRecorder mainHotkey"] objectForKey:@"modifierFlags"] intValue] )
];
};
// Initialize the JumpcutStore
clippingStore = [[JumpcutStore alloc] initRemembering:[[NSUserDefaults standardUserDefaults] integerForKey:@"rememberNum"]
displaying:[[NSUserDefaults standardUserDefaults] integerForKey:@"displayNum"]
withDisplayLength:_DISPLENGTH];
NSRect screenFrame = [[NSScreen mainScreen] frame];
widthSlider.maxValue = screenFrame.size.width;
heightSlider.maxValue = screenFrame.size.height;
// Set up the bezel window
NSRect windowFrame = NSMakeRect(0, 0,
[[NSUserDefaults standardUserDefaults] floatForKey:@"bezelWidth"],
[[NSUserDefaults standardUserDefaults] floatForKey:@"bezelHeight"]);
bezel = [[BezelWindow alloc] initWithContentRect:windowFrame
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO];
[bezel trueCenter];
[bezel setDelegate:self];
// Create our pasteboard interface
jcPasteboard = [NSPasteboard generalPasteboard];
[jcPasteboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
pbCount = [[NSNumber numberWithInt:[jcPasteboard changeCount]] retain];
// Build the statusbar menu
statusItem = [[[NSStatusBar systemStatusBar]
statusItemWithLength:NSVariableStatusItemLength] retain];
[statusItem setHighlightMode:YES];
if ( [[NSUserDefaults standardUserDefaults] integerForKey:@"menuIcon"] == 1 ) {
[statusItem setTitle:[NSString stringWithFormat:@"%C",0x2704]];
} else if ( [[NSUserDefaults standardUserDefaults] integerForKey:@"menuIcon"] == 2 ) {
[statusItem setTitle:[NSString stringWithFormat:@"%C",0x2702]];
} else {
[statusItem setImage:[NSImage imageNamed:@"com.generalarcade.flycut.16.png"]];
}
[statusItem setMenu:jcMenu];
[statusItem setEnabled:YES];
// If our preferences indicate that we are saving, load the dictionary from the saved plist
// and use it to get everything set up.
if ( [[NSUserDefaults standardUserDefaults] integerForKey:@"savePreference"] >= 1 ) {
[self loadEngineFromPList];
}
// Build our listener timer
pollPBTimer = [[NSTimer scheduledTimerWithTimeInterval:(1.0)
target:self
selector:@selector(pollPB:)
userInfo:nil
repeats:YES] retain];
// Finish up
srTransformer = [[[SRKeyCodeTransformer alloc] init] retain];
pbBlockCount = [[NSNumber numberWithInt:0] retain];
[pollPBTimer fire];
// Stack position starts @ 0 by default
stackPosition = 0;
[NSApp activateIgnoringOtherApps: YES];
}
-(IBAction) activateAndOrderFrontStandardAboutPanel:(id)sender
{
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
[[NSApplication sharedApplication] orderFrontStandardAboutPanel:sender];
}
-(IBAction) setBezelAlpha:(id)sender
{
// In a masterpiece of poorly-considered design--because I want to eventually
// allow users to select from a variety of bezels--I've decided to create the
// bezel programatically, meaning that I have to go through AppController as
// a cutout to allow the user interface to interact w/the bezel.
[bezel setAlpha:[sender floatValue]];
}
-(IBAction) setBezelWidth:(id)sender
{
NSSize bezelSize = NSMakeSize([sender floatValue], bezel.frame.size.height);
NSRect windowFrame = NSMakeRect( 0, 0, bezelSize.width, bezelSize.height);
[bezel setFrame:windowFrame display:NO];
[bezel trueCenter];
}
-(IBAction) setBezelHeight:(id)sender
{
NSSize bezelSize = NSMakeSize(bezel.frame.size.width, [sender floatValue]);
NSRect windowFrame = NSMakeRect( 0, 0, bezelSize.width, bezelSize.height);
[bezel setFrame:windowFrame display:NO];
[bezel trueCenter];
}
-(IBAction) switchMenuIcon:(id)sender
{
if ([sender indexOfSelectedItem] == 1 ) {
[statusItem setImage:nil];
[statusItem setTitle:[NSString stringWithFormat:@"%C",0x2704]];
} else if ( [sender indexOfSelectedItem] == 2 ) {
[statusItem setImage:nil];
[statusItem setTitle:[NSString stringWithFormat:@"%C",0x2702]];
} else {
[statusItem setTitle:@""];
[statusItem setImage:[NSImage imageNamed:@"com.generalarcade.flycut.16.png"]];
}
}
-(IBAction) setRememberNumPref:(id)sender
{
int choice;
int newRemember = [sender intValue];
if ( newRemember < [clippingStore jcListCount] &&
! issuedRememberResizeWarning &&
! [[NSUserDefaults standardUserDefaults] boolForKey:@"stifleRememberResizeWarning"]
) {
choice = NSRunAlertPanel(@"Resize Stack",
@"Resizing the stack to a value below its present size will cause clippings to be lost.",
@"Resize", @"Cancel", @"Don't Warn Me Again");
if ( choice == NSAlertAlternateReturn ) {
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithInt:[clippingStore jcListCount]]
forKey:@"rememberNum"];
[self updateMenu];
return;
} else if ( choice == NSAlertOtherReturn ) {
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:YES]
forKey:@"stifleRememberResizeWarning"];
} else {
issuedRememberResizeWarning = YES;
}
}
if ( newRemember < [[NSUserDefaults standardUserDefaults] integerForKey:@"displayNum"] ) {
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithInt:newRemember]
forKey:@"displayNum"];
}
[clippingStore setRememberNum:newRemember];
[self updateMenu];
}
-(IBAction) setDisplayNumPref:(id)sender
{
[self updateMenu];
}
-(IBAction) showPreferencePanel:(id)sender
{
int checkLoginRegistry = [UKLoginItemRegistry indexForLoginItemWithPath:[[NSBundle mainBundle] bundlePath]];
if ( checkLoginRegistry >= 1 ) {
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:YES]
forKey:@"loadOnStartup"];
} else {
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:NO]
forKey:@"loadOnStartup"];
}
if ([prefsPanel respondsToSelector:@selector(setCollectionBehavior:)])
[prefsPanel setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces];
[NSApp activateIgnoringOtherApps: YES];
[prefsPanel makeKeyAndOrderFront:self];
issuedRememberResizeWarning = NO;
}
-(IBAction)toggleLoadOnStartup:(id)sender {
if ( [[NSUserDefaults standardUserDefaults] boolForKey:@"loadOnStartup"] ) {
[UKLoginItemRegistry addLoginItemWithPath:[[NSBundle mainBundle] bundlePath] hideIt:NO];
} else {
[UKLoginItemRegistry removeLoginItemWithPath:[[NSBundle mainBundle] bundlePath]];
}
}
- (void)pasteFromStack
{
if ( [clippingStore jcListCount] > stackPosition ) {
[self addClipToPasteboardFromCount:stackPosition];
[self performSelector:@selector(hideApp) withObject:nil afterDelay:0.2];
[self performSelector:@selector(fakeCommandV) withObject:nil afterDelay:0.2];
} else {
[self performSelector:@selector(hideApp) withObject:nil afterDelay:0.2];
}
}
- (void)metaKeysReleased
{
if ( ! isBezelPinned ) {
[self pasteFromStack];
}
}
-(void)fakeCommandV
/*" +fakeCommandV synthesizes keyboard events for Cmd-v Paste
shortcut. "*/
{
CGEventSourceRef sourceRef = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
if (!sourceRef)
{
NSLog(@"No event source");
return;
}
//9 = "v"
CGEventRef eventDown = CGEventCreateKeyboardEvent(sourceRef, (CGKeyCode)9, true);
CGEventSetFlags(eventDown, kCGEventFlagMaskCommand);
CGEventRef eventUp = CGEventCreateKeyboardEvent(sourceRef, (CGKeyCode)9, false);
CGEventPost(kCGHIDEventTap, eventDown);
CGEventPost(kCGHIDEventTap, eventUp);
CFRelease(eventDown);
CFRelease(eventUp);
CFRelease(sourceRef);
}
-(void)pollPB:(NSTimer *)timer
{
NSString *type = [jcPasteboard availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]];
if ( [pbCount intValue] != [jcPasteboard changeCount] ) {
// Reload pbCount with the current changeCount
// Probably poor coding technique, but pollPB should be the only thing messing with pbCount, so it should be okay
[pbCount release];
pbCount = [[NSNumber numberWithInt:[jcPasteboard changeCount]] retain];
if ( type != nil ) {
NSString *contents = [jcPasteboard stringForType:type];
if ( contents == nil ) {
// NSLog(@"Contents: Empty");
} else {
if (( [clippingStore jcListCount] == 0 || ! [contents isEqualToString:[clippingStore clippingContentsAtPosition:0]])
&& ! [pbCount isEqualTo:pbBlockCount] ) {
[clippingStore addClipping:contents
ofType:type ];
// The below tracks our position down down down... Maybe as an option?
// if ( [clippingStore jcListCount] > 1 ) stackPosition++;
stackPosition = 0;
[self updateMenu];
if ( [[NSUserDefaults standardUserDefaults] integerForKey:@"savePreference"] >= 2 ) {
[self saveEngine];
}
}
}
} else {
// NSLog(@"Contents: Non-string");
}
}
}
- (void)processBezelKeyDown:(NSEvent *)theEvent
{
int newStackPosition;
// AppControl should only be getting these directly from bezel via delegation
if ( [theEvent type] == NSKeyDown )
{
if ( [theEvent keyCode] == [mainRecorder keyCombo].code )
{
if ( [theEvent modifierFlags] & NSShiftKeyMask )
{
[self stackUp];
} else {
[self stackDown];
}
return;
}
unichar pressed = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
switch ( pressed ) {
case 0x1B:
[self hideApp];
break;
case 0x3: case 0xD: // Enter or Return
[self pasteFromStack];
break;
case NSUpArrowFunctionKey:
case NSLeftArrowFunctionKey:
[self stackUp];
break;
case NSDownArrowFunctionKey:
case NSRightArrowFunctionKey:
[self stackDown];
break;
case NSHomeFunctionKey:
if ( [clippingStore jcListCount] > 0 ) {
stackPosition = 0;
[bezel setCharString:[NSString stringWithFormat:@"%d of %d", stackPosition + 1, [clippingStore jcListCount]]];
//[bezel setCharString:[NSString stringWithFormat:@"%d", stackPosition + 1]];
[bezel setText:[clippingStore clippingContentsAtPosition:stackPosition]];
}
break;
case NSEndFunctionKey:
if ( [clippingStore jcListCount] > 0 ) {
stackPosition = [clippingStore jcListCount] - 1;
[bezel setCharString:[NSString stringWithFormat:@"%d of %d", stackPosition + 1, [clippingStore jcListCount]]];
[bezel setText:[clippingStore clippingContentsAtPosition:stackPosition]];
}
break;
case NSPageUpFunctionKey:
if ( [clippingStore jcListCount] > 0 ) {
stackPosition = stackPosition - 10; if ( stackPosition < 0 ) stackPosition = 0;
[bezel setCharString:[NSString stringWithFormat:@"%d of %d", stackPosition + 1, [clippingStore jcListCount]]];
[bezel setText:[clippingStore clippingContentsAtPosition:stackPosition]];
}
break;
case NSPageDownFunctionKey:
if ( [clippingStore jcListCount] > 0 ) {
stackPosition = stackPosition + 10; if ( stackPosition >= [clippingStore jcListCount] ) stackPosition = [clippingStore jcListCount] - 1;
[bezel setCharString:[NSString stringWithFormat:@"%d of %d", stackPosition + 1, [clippingStore jcListCount]]];
[bezel setText:[clippingStore clippingContentsAtPosition:stackPosition]];
}
break;
case NSBackspaceCharacter: break;
case NSDeleteCharacter: break;
case NSDeleteFunctionKey: break;
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: // Numeral
case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
// We'll currently ignore the possibility that the user wants to do something with shift.
// First, let's set the new stack count to "10" if the user pressed "0"
newStackPosition = pressed == 0x30 ? 9 : [[NSString stringWithCharacters:&pressed length:1] intValue] - 1;
if ( [clippingStore jcListCount] >= newStackPosition ) {
stackPosition = newStackPosition;
[bezel setCharString:[NSString stringWithFormat:@"%d of %d", stackPosition + 1, [clippingStore jcListCount]]];
[bezel setText:[clippingStore clippingContentsAtPosition:stackPosition]];
}
break;
default: // It's not a navigation/application-defined thing, so let's figure out what to do with it.
NSLog(@"PRESSED %d", pressed);
NSLog(@"CODE %ld", [mainRecorder keyCombo].code);
break;
}
}
}
- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
//Create our hot key
[self toggleMainHotKey:[NSNull null]];
}
- (void) showBezel
{
if ( [clippingStore jcListCount] > 0 && [clippingStore jcListCount] > stackPosition ) {
[bezel setCharString:[NSString stringWithFormat:@"%d of %d", stackPosition + 1, [clippingStore jcListCount]]];
[bezel setText:[clippingStore clippingContentsAtPosition:stackPosition]];
}
if ([bezel respondsToSelector:@selector(setCollectionBehavior:)])
[bezel setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces]; [bezel makeKeyAndOrderFront:nil];
isBezelDisplayed = YES;
}
- (void) hideBezel
{
[bezel orderOut:nil];
[bezel setCharString:@""];
isBezelDisplayed = NO;
}
-(void)hideApp
{
[self hideBezel];
isBezelPinned = NO;
[NSApp hide:self];
}
- (void) applicationWillResignActive:(NSApplication *)app; {
// This should be hidden anyway, but just in case it's not.
[self hideBezel];
}
- (void)hitMainHotKey:(SGHotKey *)hotKey
{
if ( ! isBezelDisplayed ) {
[NSApp activateIgnoringOtherApps:YES];
if ( [[NSUserDefaults standardUserDefaults] boolForKey:@"stickyBezel"] ) {
isBezelPinned = YES;
}
[self showBezel];
} else {
[self stackDown];
}
}
- (IBAction)toggleMainHotKey:(id)sender
{
if (mainHotKey != nil)
{
[[SGHotKeyCenter sharedCenter] unregisterHotKey:mainHotKey];
[mainHotKey release];
mainHotKey = nil;
}
mainHotKey = [[SGHotKey alloc] initWithIdentifier:@"mainHotKey"
keyCombo:[SGKeyCombo keyComboWithKeyCode:[mainRecorder keyCombo].code
modifiers:[mainRecorder cocoaToCarbonFlags: [mainRecorder keyCombo].flags]]];
[mainHotKey setName: @"Activate Flycut HotKey"]; //This is typically used by PTKeyComboPanel
[mainHotKey setTarget: self];
[mainHotKey setAction: @selector(hitMainHotKey:)];
[[SGHotKeyCenter sharedCenter] registerHotKey:mainHotKey];
}
-(IBAction)clearClippingList:(id)sender {
int choice;
[NSApp activateIgnoringOtherApps:YES];
choice = NSRunAlertPanel(@"Clear Clipping List",
@"Do you want to clear all recent clippings?",
@"Clear", @"Cancel", nil);
// on clear, zap the list and redraw the menu
if ( choice == NSAlertDefaultReturn ) {
[clippingStore clearList];
[self updateMenu];
if ( [[NSUserDefaults standardUserDefaults] integerForKey:@"savePreference"] >= 1 ) {
[self saveEngine];
}
[bezel setText:@""];
}
}
- (void)updateMenu {
NSArray *returnedDisplayStrings = [clippingStore previousDisplayStrings:[[NSUserDefaults standardUserDefaults] integerForKey:@"displayNum"]];
NSArray *menuItems = [[[jcMenu itemArray] reverseObjectEnumerator] allObjects];
NSArray *clipStrings = [[returnedDisplayStrings reverseObjectEnumerator] allObjects];
int passedSeparator = 0;
//remove clippings from menu
for (NSMenuItem *oldItem in menuItems) {
if( [oldItem isSeparatorItem]) {
passedSeparator++;
} else if ( passedSeparator == 2 ) {
[jcMenu removeItem:oldItem];
}
}
for(NSString *pbMenuTitle in clipStrings) {
NSMenuItem *item;
item = [[NSMenuItem alloc] initWithTitle:pbMenuTitle
action:@selector(processMenuClippingSelection:)
keyEquivalent:@""];
[item setTarget:self];
[item setEnabled:YES];
[jcMenu insertItem:item atIndex:0];
// Way back in 0.2, failure to release the new item here was causing a quite atrocious memory leak.
[item release];
}
}
-(IBAction)processMenuClippingSelection:(id)sender
{
int index=[[sender menu] indexOfItem:sender];
[self addClipToPasteboardFromCount:index];
if ( [[NSUserDefaults standardUserDefaults] boolForKey:@"menuSelectionPastes"] ) {
[self performSelector:@selector(hideApp) withObject:nil];
[self performSelector:@selector(fakeCommandV) withObject:nil afterDelay:0.2];
}
}
-(BOOL) isValidClippingNumber:(NSNumber *)number {
return ( ([number intValue] + 1) <= [clippingStore jcListCount] );
}
-(NSString *) clippingStringWithCount:(int)count {
if ( [self isValidClippingNumber:[NSNumber numberWithInt:count]] ) {
return [clippingStore clippingContentsAtPosition:count];
} else { // It fails -- we shouldn't be passed this, but...
return @"";
}
}
-(void) setPBBlockCount:(NSNumber *)newPBBlockCount
{
[newPBBlockCount retain];
[pbBlockCount release];
pbBlockCount = newPBBlockCount;
}
-(BOOL)addClipToPasteboardFromCount:(int)indexInt
{
NSString *pbFullText;
NSArray *pbTypes;
if ( (indexInt + 1) > [clippingStore jcListCount] ) {
// We're asking for a clipping that isn't there yet
// This only tends to happen immediately on startup when not saving, as the entire list is empty.
NSLog(@"Out of bounds request to jcList ignored.");
return false;
}
pbFullText = [self clippingStringWithCount:indexInt];
pbTypes = [NSArray arrayWithObjects:@"NSStringPboardType",NULL];
[jcPasteboard declareTypes:pbTypes owner:NULL];
[jcPasteboard setString:pbFullText forType:@"NSStringPboardType"];
[self setPBBlockCount:[NSNumber numberWithInt:[jcPasteboard changeCount]]];
return true;
}
-(void) loadEngineFromPList
{
NSString *path = [[NSString
stringWithString:@"~/Library/Application Support/Flycut/JCEngine.save"] stringByExpandingTildeInPath];
NSDictionary *loadDict = [[NSDictionary alloc] initWithContentsOfFile:path];
NSArray *savedJCList;
NSRange loadRange;
int rangeCap;
if ( loadDict != nil ) {
savedJCList = [loadDict objectForKey:@"jcList"];
if ( [savedJCList isKindOfClass:[NSArray class]] ) {
int rememberNumPref = [[NSUserDefaults standardUserDefaults]
integerForKey:@"rememberNum"];
// There's probably a nicer way to prevent the range from going out of bounds, but this works.
rangeCap = [savedJCList count] < rememberNumPref ? [savedJCList count] : rememberNumPref;
loadRange = NSMakeRange(0, rangeCap);
NSArray *toBeRestoredClips = [[[savedJCList subarrayWithRange:loadRange] reverseObjectEnumerator] allObjects];
for( NSDictionary *aSavedClipping in toBeRestoredClips) {
[clippingStore addClipping:[aSavedClipping objectForKey:@"Contents"]
ofType:[aSavedClipping objectForKey:@"Type"]];
}
} else {
NSLog(@"Not array");
}
[self updateMenu];
[loadDict release];
}
}
-(void) stackDown
{
stackPosition++;
if ( [clippingStore jcListCount] > stackPosition ) {
[bezel setCharString:[NSString stringWithFormat:@"%d of %d", stackPosition + 1, [clippingStore jcListCount]]];
[bezel setText:[clippingStore clippingContentsAtPosition:stackPosition]];
} else {
if ( [[NSUserDefaults standardUserDefaults] boolForKey:@"wraparoundBezel"] ) {
stackPosition = 0;
[bezel setCharString:[NSString stringWithFormat:@"%d of %d", 1, [clippingStore jcListCount]]];
[bezel setText:[clippingStore clippingContentsAtPosition:stackPosition]];
} else {
stackPosition--;
}
}
}
-(void) stackUp
{
stackPosition--;
if ( stackPosition < 0 ) {
if ( [[NSUserDefaults standardUserDefaults] boolForKey:@"wraparoundBezel"] ) {
stackPosition = [clippingStore jcListCount] - 1;
[bezel setCharString:[NSString stringWithFormat:@"%d of %d", stackPosition + 1, [clippingStore jcListCount]]];
[bezel setText:[clippingStore clippingContentsAtPosition:stackPosition]];
} else {
stackPosition = 0;
}
}
if ( [clippingStore jcListCount] > stackPosition ) {
[bezel setCharString:[NSString stringWithFormat:@"%d of %d", stackPosition + 1, [clippingStore jcListCount]]];
[bezel setText:[clippingStore clippingContentsAtPosition:stackPosition]];
}
}
-(void) saveEngine
{
NSMutableDictionary *saveDict;
NSMutableArray *jcListArray = [NSMutableArray array];
int i;
BOOL isDir;
NSString *path;
path = [[NSString stringWithString:@"~/Library/Application Support/Flycut"] stringByExpandingTildeInPath];
if ( ![[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir] || ! isDir ) {
NSLog(@"Creating Application Support directory");
[[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES
attributes:[NSDictionary dictionaryWithObjectsAndKeys:
@"NSFileModificationDate", [NSNull null],
@"NSFileOwnerAccountName", [NSNull null],
@"NSFileGroupOwnerAccountName", [NSNull null],
@"NSFilePosixPermissions", [NSNull null],
@"NSFileExtensionsHidden", [NSNull null],
nil]
error:nil
];
}
saveDict = [NSMutableDictionary dictionaryWithCapacity:3];
[saveDict setObject:@"0.7" forKey:@"version"];
[saveDict setObject:[NSNumber numberWithInt:[[NSUserDefaults standardUserDefaults] integerForKey:@"rememberNum"]]
forKey:@"rememberNum"];
[saveDict setObject:[NSNumber numberWithInt:_DISPLENGTH]
forKey:@"displayLen"];
[saveDict setObject:[NSNumber numberWithInt:[[NSUserDefaults standardUserDefaults] integerForKey:@"displayNum"]]
forKey:@"displayNum"];
for ( i = 0 ; i < [clippingStore jcListCount]; i++) {
[jcListArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
[clippingStore clippingContentsAtPosition:i], @"Contents",
[clippingStore clippingTypeAtPosition:i], @"Type",
[NSNumber numberWithInt:i], @"Position",
nil
]
];
}
[saveDict setObject:jcListArray forKey:@"jcList"];
if ( [saveDict writeToFile:[path stringByAppendingString:@"/JCEngine.save"] atomically:true] ) {
// NSLog(@"Engine contents saved.");
} else {
NSLog(@"Engine contents NOT saved.");
}
}
- (void)setHotKeyPreferenceForRecorder:(SRRecorderControl *)aRecorder {
if (aRecorder == mainRecorder) {
[[NSUserDefaults standardUserDefaults] setObject:
[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:[NSNumber numberWithInt:[mainRecorder keyCombo].code],[NSNumber numberWithInt:[mainRecorder keyCombo].flags],nil] forKeys:[NSArray arrayWithObjects:@"keyCode",@"modifierFlags",nil]]
forKey:@"ShortcutRecorder mainHotkey"];
}
}
- (BOOL)shortcutRecorder:(SRRecorderControl *)aRecorder isKeyCode:(NSInteger)keyCode andFlagsTaken:(NSUInteger)flags reason:(NSString **)aReason {
return NO;
}
- (void)shortcutRecorder:(SRRecorderControl *)aRecorder keyComboDidChange:(KeyCombo)newKeyCombo {
if (aRecorder == mainRecorder) {
[self toggleMainHotKey: aRecorder];
[self setHotKeyPreferenceForRecorder: aRecorder];
}
NSLog(@"code: %lu, flags: %lu", newKeyCombo.code, newKeyCombo.flags);
}
- (void)applicationWillTerminate:(NSNotification *)notification {
if ( [[NSUserDefaults standardUserDefaults] integerForKey:@"savePreference"] >= 1 ) {
NSLog(@"Saving on exit");
[self saveEngine];
}
//Unregister our hot key (not required)
[[SGHotKeyCenter sharedCenter] unregisterHotKey: mainHotKey];
[mainHotKey release];
mainHotKey = nil;
[self hideBezel];
[[NSDistributedNotificationCenter defaultCenter]
removeObserver:self
name:@"AppleKeyboardPreferencesChangedNotification"
object:nil];
[[NSDistributedNotificationCenter defaultCenter]
removeObserver:self
name:@"AppleSelectedInputSourcesChangedNotification"
object:nil];
}
- (void) dealloc {
[bezel release];
[srTransformer release];
[super dealloc];
}
@end