diff --git a/MacPass.xcodeproj/project.pbxproj b/MacPass.xcodeproj/project.pbxproj index 0bf84533..ca0b742c 100644 --- a/MacPass.xcodeproj/project.pbxproj +++ b/MacPass.xcodeproj/project.pbxproj @@ -114,6 +114,7 @@ 4C473A7F18AFD6340073FD2E /* KPKTestReference.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C473A7E18AFD6340073FD2E /* KPKTestReference.m */; }; 4C473A8718AFD85B0073FD2E /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C473A8518AFD7250073FD2E /* XCTest.framework */; }; 4C4A100F176286FD00BBF2CA /* MPTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C4A100E176286FD00BBF2CA /* MPTableView.m */; }; + 4C4B728518E4B9B400A1A5D5 /* MPDockTileHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C4B728418E4B9B400A1A5D5 /* MPDockTileHelper.m */; }; 4C4B7EE917A45EC6000234C7 /* MPDatePickingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C4B7EE717A45EC5000234C7 /* MPDatePickingViewController.m */; }; 4C4B7EEE17A467E1000234C7 /* MPGroupInspectorViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C4B7EEC17A467E1000234C7 /* MPGroupInspectorViewController.m */; }; 4C4B7EF317A467FC000234C7 /* MPEntryInspectorViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C4B7EF117A467FC000234C7 /* MPEntryInspectorViewController.m */; }; @@ -559,6 +560,8 @@ 4C48A56018BE932100278A2D /* HNHCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HNHCommon.h; sourceTree = ""; }; 4C4A100D176286FD00BBF2CA /* MPTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPTableView.h; sourceTree = ""; }; 4C4A100E176286FD00BBF2CA /* MPTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPTableView.m; sourceTree = ""; }; + 4C4B728318E4B9B400A1A5D5 /* MPDockTileHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPDockTileHelper.h; sourceTree = ""; }; + 4C4B728418E4B9B400A1A5D5 /* MPDockTileHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPDockTileHelper.m; sourceTree = ""; }; 4C4B7EE617A45EC5000234C7 /* MPDatePickingViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPDatePickingViewController.h; sourceTree = ""; }; 4C4B7EE717A45EC5000234C7 /* MPDatePickingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPDatePickingViewController.m; sourceTree = ""; }; 4C4B7EEB17A467E1000234C7 /* MPGroupInspectorViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPGroupInspectorViewController.h; sourceTree = ""; }; @@ -1267,6 +1270,8 @@ 4C26C33E18D8C92100CF1A1C /* MPTemporaryFileStorage.m */, 4C88C66718D9F8D600F43852 /* MPTemporaryFileStorageCenter.h */, 4C88C66818D9F8D600F43852 /* MPTemporaryFileStorageCenter.m */, + 4C4B728318E4B9B400A1A5D5 /* MPDockTileHelper.h */, + 4C4B728418E4B9B400A1A5D5 /* MPDockTileHelper.m */, ); name = Helper; sourceTree = ""; @@ -2321,6 +2326,7 @@ 4C74DD07177BD1640034A9DB /* MPCustomFieldView.m in Sources */, 4C4FCE15177CFE6B00BBF7AE /* MPCustomFieldTableCellView.m in Sources */, 4C26C34B18D8D5A300CF1A1C /* MPPreviewViewController.m in Sources */, + 4C4B728518E4B9B400A1A5D5 /* MPDockTileHelper.m in Sources */, 4C52A244177D7B9F0000D88F /* HNHScrollView.m in Sources */, 4CC7EA1B17807E7E0089D4F3 /* HNHRoundedTextFieldCellHelper.m in Sources */, 4C5FE9AE17843CE20001D5A8 /* MPSelectedAttachmentTableCellView.m in Sources */, diff --git a/MacPass/MPAppDelegate.m b/MacPass/MPAppDelegate.m index 5388fe2e..8e62885b 100644 --- a/MacPass/MPAppDelegate.m +++ b/MacPass/MPAppDelegate.m @@ -32,6 +32,7 @@ #import "MPAutotypeDaemon.h" #import "MPDocumentWindowController.h" #import "MPFixAutotypeWindowController.h" +#import "MPDockTileHelper.h" #import "MPTemporaryFileStorageCenter.h" @@ -45,6 +46,7 @@ NSString *const MPDidChangeStoredKeyFilesSettings = @"com.hicknhack.macpass.MPDi MPServerDaemon *serverDaemon; MPLockDaemon *lockDaemon; MPAutotypeDaemon *autotypeDaemon; + MPDockTileHelper *dockTileHelper; BOOL _shouldOpenFile; // YES if app was started to open a } @@ -147,6 +149,7 @@ NSString *const MPDidChangeStoredKeyFilesSettings = @"com.hicknhack.macpass.MPDi serverDaemon = [[MPServerDaemon alloc] init]; lockDaemon = [[MPLockDaemon alloc] init]; autotypeDaemon = [[MPAutotypeDaemon alloc] init]; + dockTileHelper = [[MPDockTileHelper alloc] init]; } - (NSString *)applicationName { diff --git a/MacPass/MPAutotypeDaemon.m b/MacPass/MPAutotypeDaemon.m index fb737982..c3dbc2c1 100644 --- a/MacPass/MPAutotypeDaemon.m +++ b/MacPass/MPAutotypeDaemon.m @@ -29,12 +29,16 @@ NSString *const kMPApplciationNameKey = @"applicationName"; @interface MPAutotypeDaemon () @property (nonatomic, assign) BOOL enabled; -@property (copy) NSString *lastFrontMostApplication; +@property (copy) NSString *targetApplicationName; +@property (copy) NSString *targetWindowTitle; @end @implementation MPAutotypeDaemon +#pragma mark - +#pragma mark Lifecylce + - (id)init { self = [super init]; if (self) { @@ -51,7 +55,9 @@ NSString *const kMPApplciationNameKey = @"applicationName"; [self unbind:@"enabled"]; } +#pragma mark - #pragma mark Properties + - (void)setEnabled:(BOOL)enabled { if(_enabled != enabled) { _enabled = enabled; @@ -59,6 +65,9 @@ NSString *const kMPApplciationNameKey = @"applicationName"; } } +#pragma mark - +#pragma mark Actions + - (void)executeAutotypeWithSelectedMatch:(id)sender { NSMenuItem *item = [self.matchSelectionButton selectedItem]; MPAutotypeContext *context = [item representedObject]; @@ -68,16 +77,33 @@ NSString *const kMPApplciationNameKey = @"applicationName"; - (void)cancelAutotypeSelection:(id)sender { [self.matchSelectionWindow orderOut:sender]; - if(self.lastFrontMostApplication) { - [MPAutotypeDaemon _orderApplicationToFront:self.lastFrontMostApplication]; + if(self.targetApplicationName) { + [MPAutotypeDaemon _orderApplicationToFront:self.targetApplicationName]; } } -- (void)_didPressHotKey { +#pragma mark - +#pragma mark Hotkey evaluation - /* Reset the applciation on every keypress */ - self.lastFrontMostApplication = nil; - +- (void)_didPressHotKey { + [self _performAutotypeUsingCurrentWindowAndApplication:YES]; +} + +- (void)_performAutotypeUsingCurrentWindowAndApplication:(BOOL)useCurrentWindowAndApplication { + if(useCurrentWindowAndApplication) { + [self _updateTargetApplicationAndWindow]; + } + + MPDocument *document = [self _findAutotypeDocument]; + if(!document) { + return; // nothing to do + } + + MPAutotypeContext *context = [self _autotypeContextInDocument:document forWindowTitle:self.targetWindowTitle]; + [self _performAutotypeForContext:context]; +} + +- (MPDocument *)_findAutotypeDocument { NSArray *documents = [NSApp orderedDocuments]; MPDocument *currentDocument = nil; for(MPDocument *openDocument in documents) { @@ -86,40 +112,42 @@ NSString *const kMPApplciationNameKey = @"applicationName"; break; } } - if(!currentDocument) { - return; // No need to search in closed documents + BOOL hasOpenDocuments = [documents count] > 0; + if(!currentDocument && hasOpenDocuments) { + [NSApp activateIgnoringOtherApps:YES]; + [[NSApp mainWindow] makeKeyAndOrderFront:self]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didUnlockDatabase:) name:MPDocumentDidUnlockDatabaseNotification object:nil]; } - /* - Determine the window title of the current front most application - Start searching the db for the best fit (based on title, then on window associations - */ - NSDictionary *frontApplicationInfoDict = [self _frontMostApplicationInfoDict]; - NSString *windowTitle = frontApplicationInfoDict[kMPWindowTitleKey]; - self.lastFrontMostApplication = frontApplicationInfoDict[kMPApplciationNameKey]; + return currentDocument; +} + +- (MPAutotypeContext *)_autotypeContextInDocument:(MPDocument *)document forWindowTitle:(NSString *)windowTitle { /* Query the document to generate a autotype command list for the window title We do not care where this came form, just get the autotype commands */ - NSArray *autotypeCandidates = [currentDocument autotypContextsForWindowTitle:windowTitle]; - NSInteger candiates = [autotypeCandidates count]; - if(candiates == 0) { - return; // No Entries found. + NSArray *autotypeCandidates = [document autotypContextsForWindowTitle:windowTitle]; + NSUInteger candidates = [autotypeCandidates count]; + if(candidates == 0) { + return nil; } - if(candiates > 1) { - [self _presentSelectionWindow:autotypeCandidates]; - return; // Nothing to do, we get called back by the window + if(candidates == 1 ) { + return [autotypeCandidates lastObject]; } - [self _performAutotypeForContext:autotypeCandidates[0]]; + [self _presentSelectionWindow:autotypeCandidates]; + return nil; // Nothing to do, we get called back by the window } - (void)_performAutotypeForContext:(MPAutotypeContext *)context { + if(nil == context) { + return; // No context to work with + } dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSArray *commands = [MPAutotypeCommand commandsForContext:context]; - [MPAutotypeDaemon _orderApplicationToFront:self.lastFrontMostApplication]; + [MPAutotypeDaemon _orderApplicationToFront:self.targetApplicationName]; BOOL lastCommandWasPaste = NO; for(MPAutotypeCommand *command in commands) { if(lastCommandWasPaste) { - NSLog(@"Sleeping for pasting!"); usleep(1000*1000); } [command execute]; @@ -128,6 +156,9 @@ NSString *const kMPApplciationNameKey = @"applicationName"; }); } +#pragma mark - +#pragma mark Hotkey Registration + - (void)_registerHotKey { [[DDHotKeyCenter sharedHotKeyCenter] registerHotKeyWithKeyCode:kVK_ANSI_M modifierFlags:(NSCommandKeyMask | NSAlternateKeyMask ) @@ -188,6 +219,17 @@ NSString *const kMPApplciationNameKey = @"applicationName"; /* Setup Items in Popup */ } +#pragma mark - +#pragma mark MPDocument Notifications + +- (void)_didUnlockDatabase:(NSNotification *)notification { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [self _performAutotypeUsingCurrentWindowAndApplication:NO]; +} + +#pragma mark - +#pragma mark Application information + + (void)_orderApplicationToFront:(NSString *)applicationName { //NSLog(@"Moving %@ to the front.", applicationName); NSString *appleScript = [[NSString alloc] initWithFormat:@"activate application \"%@\"", applicationName]; @@ -199,5 +241,14 @@ NSString *const kMPApplciationNameKey = @"applicationName"; } } +- (void)_updateTargetApplicationAndWindow { + /* + Determine the window title of the current front most application + Start searching the db for the best fit (based on title, then on window associations + */ + NSDictionary *frontApplicationInfoDict = [self _frontMostApplicationInfoDict]; + self.targetApplicationName = frontApplicationInfoDict[kMPApplciationNameKey]; + self.targetWindowTitle = frontApplicationInfoDict[kMPWindowTitleKey]; +} @end diff --git a/MacPass/MPAutotypePaste.m b/MacPass/MPAutotypePaste.m index bb644ade..66d0b916 100644 --- a/MacPass/MPAutotypePaste.m +++ b/MacPass/MPAutotypePaste.m @@ -28,7 +28,6 @@ } - (void)execute { - [NSThread isMainThread] ? NSLog(@"MainThread") : NSLog(@"NonMainThread"); if([self.pasteData length] > 0) { MPPasteBoardController *controller = [MPPasteBoardController defaultController]; [controller copyObjects:@[self.pasteData]]; diff --git a/MacPass/MPDockTileHelper.h b/MacPass/MPDockTileHelper.h new file mode 100644 index 00000000..135e2f77 --- /dev/null +++ b/MacPass/MPDockTileHelper.h @@ -0,0 +1,13 @@ +// +// MPDockTileHelper.h +// MacPass +// +// Created by Michael Starke on 27/03/14. +// Copyright (c) 2014 HicknHack Software GmbH. All rights reserved. +// + +#import + +@interface MPDockTileHelper : NSObject + +@end diff --git a/MacPass/MPDockTileHelper.m b/MacPass/MPDockTileHelper.m new file mode 100644 index 00000000..46b07c3e --- /dev/null +++ b/MacPass/MPDockTileHelper.m @@ -0,0 +1,64 @@ +// +// MPDockTileHelper.m +// MacPass +// +// Created by Michael Starke on 27/03/14. +// Copyright (c) 2014 HicknHack Software GmbH. All rights reserved. +// + +#import "MPDockTileHelper.h" +#import "MPPasteBoardController.h" + +@interface MPDockTileHelper () { + BOOL _pasteboardCleard; +} + +@property (assign) NSTimeInterval timeStamp; + +@end + +@implementation MPDockTileHelper + +- (instancetype)init { + self = [super init]; + if (self) { + MPPasteBoardController *controller = [MPPasteBoardController defaultController]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didCopyToPastboard:) name:MPPasteBoardControllerDidCopyObjects object:controller]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didClearPasteboard:) name:MPPasteBoardControllerDidClearClipboard object:controller]; + } + return self; +} + +- (void)didCopyToPastboard:(NSNotification *)notification { + self.timeStamp = [NSDate timeIntervalSinceReferenceDate]; + _pasteboardCleard = NO; + if([MPPasteBoardController defaultController].clearTimeout > 0) { + [self updateBadge]; + } +} + +- (void)didClearPasteboard:(NSNotification *)notification { + _pasteboardCleard = YES; + if([MPPasteBoardController defaultController].clearTimeout > 0) { + [[NSApp dockTile] setBadgeLabel:NSLocalizedString(@"CLEARING_PASTEBOARD","")]; + } + [self performSelector:@selector(clearBadge) withObject:nil afterDelay:1]; +} + +- (void)clearBadge { + [[NSApp dockTile] setBadgeLabel:nil]; +} + +- (void)updateBadge { + if(_pasteboardCleard) { + return; + } + NSTimeInterval timeOut = [MPPasteBoardController defaultController].clearTimeout; + NSTimeInterval countDown = timeOut - ([NSDate timeIntervalSinceReferenceDate] - self.timeStamp); + if(countDown > 0) { + [[NSApp dockTile] setBadgeLabel:[[NSString alloc] initWithFormat:@"%d", (int)countDown]]; + [self performSelector:@selector(updateBadge) withObject:nil afterDelay:1]; + } +} + +@end diff --git a/MacPass/MPDocument.m b/MacPass/MPDocument.m index fa06c996..3527bcdd 100644 --- a/MacPass/MPDocument.m +++ b/MacPass/MPDocument.m @@ -262,6 +262,7 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey /* Locking needs to be lossless hence just use the XML format */ _encryptedData = [self.tree encryptWithPassword:self.compositeKey forVersion:KPKXmlVersion error:&error]; self.tree = nil; + [[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidLockDatabaseNotification object:self]; } - (BOOL)unlockWithPassword:(NSString *)password keyFileURL:(NSURL *)keyFileURL error:(NSError *__autoreleasing*)error{ @@ -280,6 +281,9 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey else { self.compositeKey = nil; // clear the key? } + if(isUnlocked) { + [[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidUnlockDatabaseNotification object:self]; + } return isUnlocked; } diff --git a/MacPass/MPPasteBoardController.h b/MacPass/MPPasteBoardController.h index 806bd90c..66ab6740 100644 --- a/MacPass/MPPasteBoardController.h +++ b/MacPass/MPPasteBoardController.h @@ -1,5 +1,5 @@ -// // MPPastBoardController.h +// // MacPass // // Created by Michael Starke on 02.03.13. diff --git a/MacPass/MPPasteBoardController.m b/MacPass/MPPasteBoardController.m index 78bb34e5..6362776c 100644 --- a/MacPass/MPPasteBoardController.m +++ b/MacPass/MPPasteBoardController.m @@ -11,7 +11,7 @@ /* Notifications */ NSString *const MPPasteBoardControllerDidCopyObjects = @"com.hicknhack.macpass.MPPasteBoardControllerDidCopyObjects"; -NSString *const MPPasteBoardControllerDidClearClipboard = @"com.hicknhack.macpass.MPPasteBoardControllerDidCopyObjects"; +NSString *const MPPasteBoardControllerDidClearClipboard = @"com.hicknhack.macpass.MPPasteBoardControllerDidClearClipboard"; @interface MPPasteBoardController () @@ -73,7 +73,6 @@ NSString *const MPPasteBoardControllerDidClearClipboard = @"com.hicknhack.macpas } - (void)copyObjects:(NSArray *)objects { - NSLog(@"ShoudlCopy %@", objects); /* Should we save the old content ?*/ [[NSPasteboard generalPasteboard] clearContents]; [[NSPasteboard generalPasteboard] writeObjects:objects]; @@ -96,9 +95,9 @@ NSString *const MPPasteBoardControllerDidClearClipboard = @"com.hicknhack.macpas - (void)_setupBindings { NSUserDefaultsController *userDefaultsController = [NSUserDefaultsController sharedUserDefaultsController]; NSString *clearOnShutdownKeyPath = [NSString stringWithFormat:@"values.%@", kMPSettingsKeyClearPasteboardOnQuit]; + [self bind:NSStringFromSelector(@selector(clearPasteboardOnShutdown)) toObject:userDefaultsController withKeyPath:clearOnShutdownKeyPath options:nil]; NSString *clearTimoutKeyPath = [NSString stringWithFormat:@"values.%@", kMPSettingsKeyPasteboardClearTimeout]; - [self bind:@"clearPasteboardOnShutdown" toObject:userDefaultsController withKeyPath:clearOnShutdownKeyPath options:nil]; - [self bind:@"clearTimeout" toObject:userDefaultsController withKeyPath:clearTimoutKeyPath options:nil]; + [self bind:NSStringFromSelector(@selector(clearTimeout)) toObject:userDefaultsController withKeyPath:clearTimoutKeyPath options:nil]; } @end diff --git a/MacPass/de.lproj/Localizable.strings b/MacPass/de.lproj/Localizable.strings index 284f207f..d21fed7c 100644 Binary files a/MacPass/de.lproj/Localizable.strings and b/MacPass/de.lproj/Localizable.strings differ diff --git a/MacPass/en.lproj/Localizable.strings b/MacPass/en.lproj/Localizable.strings index 1618758d..d9bc7547 100644 Binary files a/MacPass/en.lproj/Localizable.strings and b/MacPass/en.lproj/Localizable.strings differ diff --git a/MacPass/fr.lproj/Localizable.strings b/MacPass/fr.lproj/Localizable.strings index 73031cbf..128b2922 100644 Binary files a/MacPass/fr.lproj/Localizable.strings and b/MacPass/fr.lproj/Localizable.strings differ