2
0

An experimental new mac ui that blurs the whole screen.

This commit is contained in:
Maarten Billemont 2014-06-21 21:56:28 -04:00
parent 1433c0851e
commit c5fc87b7b5
12 changed files with 1364 additions and 843 deletions

View File

@ -21,6 +21,7 @@
#import "MPElementModel.h"
#import "MPMacAppDelegate.h"
#import "MPAppDelegate_Store.h"
#import "MPPasswordDialogController.h"
#define MPAlertChangeType @"MPAlertChangeType"
#define MPAlertChangeLogin @"MPAlertChangeLogin"
@ -204,7 +205,7 @@
[context deleteObject:element];
[context saveToStore];
[((MPPasswordWindowController *)self.collectionView.window.windowController) updateElements];
[((MPPasswordDialogController *)self.collectionView.window.windowController) updateElements];
}];
break;
}

View File

@ -8,8 +8,8 @@
#import <Cocoa/Cocoa.h>
#import "MPAppDelegate_Shared.h"
#import "MPPasswordWindowController.h"
#import "RHStatusItemView.h"
#import "MPPasswordWindowController.h"
@interface MPMacAppDelegate : MPAppDelegate_Shared<NSApplicationDelegate>

View File

@ -9,12 +9,13 @@
#import "MPMacAppDelegate.h"
#import "MPAppDelegate_Key.h"
#import "MPAppDelegate_Store.h"
#import "MPPasswordWindowController.h"
#import <Carbon/Carbon.h>
#import <ServiceManagement/ServiceManagement.h>
#define LOGIN_HELPER_BUNDLE_ID @"com.lyndir.lhunath.MasterPassword.Mac.LoginHelper"
@interface UbiquityStoreManager (Private)
@interface UbiquityStoreManager(Private)
- (void)markCloudStoreCorrupted;
@ -25,7 +26,7 @@
@property(nonatomic, strong) NSWindowController *initialWindow;
@end
@implementation MPMacAppDelegate
@implementation MPMacAppDelegate { NSWindow *_window; }
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfour-char-constants"
@ -50,7 +51,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
// Extract the hotkey ID.
EventHotKeyID hotKeyID;
GetEventParameter( theEvent, kEventParamDirectObject, typeEventHotKeyID,
NULL, sizeof(hotKeyID), NULL, &hotKeyID );
NULL, sizeof( hotKeyID ), NULL, &hotKeyID );
// Check which hotkey this was.
if (hotKeyID.signature == MPShowHotKey.signature && hotKeyID.id == MPShowHotKey.id) {
@ -100,7 +101,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
fetchRequest.sortDescriptors = @[ [NSSortDescriptor sortDescriptorWithKey:@"lastUsed" ascending:NO] ];
NSArray *users = [context executeFetchRequest:fetchRequest error:&error];
if (!users)
err(@"Failed to load users: %@", error);
err( @"Failed to load users: %@", error );
if (![users count]) {
NSMenuItem *noUsersItem = [self.usersItem.submenu addItemWithTitle:@"No users" action:NULL keyEquivalent:@""];
@ -111,7 +112,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
self.usersItem.state = NSMixedState;
for (MPUserEntity *user in users) {
NSMenuItem *userItem = [[NSMenuItem alloc] initWithTitle:user.name action:@selector(selectUser:) keyEquivalent:@""];
NSMenuItem *userItem = [[NSMenuItem alloc] initWithTitle:user.name action:@selector( selectUser: ) keyEquivalent:@""];
[userItem setTarget:self];
[userItem setRepresentedObject:[user objectID]];
[[self.usersItem submenu] addItem:userItem];
@ -139,7 +140,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
self.activeUser = (MPUserEntity *)[context existingObjectWithID:[item representedObject] error:&error];
if (error)
err(@"While looking up selected user: %@", error);
err( @"While looking up selected user: %@", error );
}
- (void)showMenu {
@ -206,7 +207,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
[moc saveToStore];
NSError *error = nil;
if (![moc obtainPermanentIDsForObjects:@[ newUser ] error:&error])
err(@"Failed to obtain permanent object ID for new user: %@", error);
err( @"Failed to obtain permanent object ID for new user: %@", error );
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self updateUsers];
@ -290,19 +291,19 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
[MPConfig get].delegate = self;
__weak id weakSelf = self;
[self addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) {
dispatch_async(dispatch_get_main_queue(), ^{
dispatch_async( dispatch_get_main_queue(), ^{
[weakSelf updateMenuItems];
});
} );
} forKeyPath:@"key" options:0 context:nil];
[self addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) {
dispatch_async(dispatch_get_main_queue(), ^{
dispatch_async( dispatch_get_main_queue(), ^{
[weakSelf updateMenuItems];
});
} );
} forKeyPath:@"activeUser" options:0 context:nil];
[self addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) {
dispatch_async(dispatch_get_main_queue(), ^{
dispatch_async( dispatch_get_main_queue(), ^{
[weakSelf updateMenuItems];
});
} );
} forKeyPath:@"storeManager.cloudAvailable" options:0 context:nil];
// Status item.
@ -311,18 +312,18 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
self.statusView.image = [NSImage imageNamed:@"menu-icon"];
self.statusView.menu = self.statusMenu;
self.statusView.target = self;
self.statusView.action = @selector(showMenu);
self.statusView.action = @selector( showMenu );
[[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil
queue:[NSOperationQueue mainQueue] usingBlock:
^(NSNotification *note) {
[self updateUsers];
}];
[self updateUsers];
}];
[[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidImportChangesNotification object:nil
queue:[NSOperationQueue mainQueue] usingBlock:
^(NSNotification *note) {
[self updateUsers];
}];
[self updateUsers];
}];
[[NSNotificationCenter defaultCenter] addObserverForName:MPCheckConfigNotification object:nil
queue:[NSOperationQueue mainQueue] usingBlock:
^(NSNotification *note) {
@ -346,16 +347,16 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
// Global hotkey.
EventHotKeyRef hotKeyRef;
EventTypeSpec hotKeyEvents[1] = { { .eventClass = kEventClassKeyboard, .eventKind = kEventHotKeyPressed } };
OSStatus status = InstallApplicationEventHandler(NewEventHandlerUPP( MPHotKeyHander ), GetEventTypeCount( hotKeyEvents ),
hotKeyEvents, (__bridge void *)self, NULL);
OSStatus status = InstallApplicationEventHandler( NewEventHandlerUPP( MPHotKeyHander ), GetEventTypeCount( hotKeyEvents ),
hotKeyEvents, (__bridge void *)self, NULL );
if (status != noErr)
err(@"Error installing application event handler: %i", (int)status);
err( @"Error installing application event handler: %i", (int)status );
status = RegisterEventHotKey( 35 /* p */, controlKey + cmdKey, MPShowHotKey, GetApplicationEventTarget(), 0, &hotKeyRef );
if (status != noErr)
err(@"Error registering 'show' hotkey: %i", (int)status);
err( @"Error registering 'show' hotkey: %i", (int)status );
status = RegisterEventHotKey( 35 /* p */, controlKey + optionKey + cmdKey, MPLockHotKey, GetApplicationEventTarget(), 0, &hotKeyRef );
if (status != noErr)
err(@"Error registering 'lock' hotkey: %i", (int)status);
err( @"Error registering 'lock' hotkey: %i", (int)status );
// Initial display.
[NSApp activateIgnoringOtherApps:YES];
@ -372,9 +373,9 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
[MPMacConfig get].usedUserName = activeUser.name;
PearlMainQueue(^{
PearlMainQueue( ^{
[self updateUsers];
});
} );
}
- (void)updateMenuItems {
@ -467,7 +468,7 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
if (SMLoginItemSetEnabled( (__bridge CFStringRef)LOGIN_HELPER_BUNDLE_ID, (Boolean)enabled ) == true)
loginItemEnabled = enabled;
else
wrn(@"Failed to set login item.");
wrn( @"Failed to set login item." );
}
self.openAtLoginItem.state = loginItemEnabled? NSOnState: NSOffState;
@ -481,11 +482,11 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
for (NSDictionary *job in jobs)
if ([LOGIN_HELPER_BUNDLE_ID isEqualToString:[job objectForKey:@"Label"]]) {
dbg(@"loginItemEnabled: %@", @([[job objectForKey:@"OnDemand"] boolValue]));
dbg( @"loginItemEnabled: %@", @([[job objectForKey:@"OnDemand"] boolValue]) );
return [[job objectForKey:@"OnDemand"] boolValue];
}
dbg(@"loginItemEnabled: not found");
dbg( @"loginItemEnabled: not found" );
return NO;
}

View File

@ -0,0 +1,23 @@
//
// MPPasswordDialogController.h
// MasterPassword-Mac
//
// Created by Maarten Billemont on 04/03/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@class MPElementModel;
@interface MPPasswordDialogController : NSWindowController<NSTextFieldDelegate, NSCollectionViewDelegate>
@property(nonatomic, strong) NSMutableArray *elements;
@property(nonatomic, strong) NSIndexSet *elementSelectionIndexes;
@property(nonatomic, weak) IBOutlet NSTextField *siteField;
@property(nonatomic, weak) IBOutlet NSView *contentContainer;
@property(nonatomic, weak) IBOutlet NSTextField *userLabel;
@property(nonatomic, weak) IBOutlet NSCollectionView *siteCollectionView;
- (void)updateElements;
@end

View File

@ -0,0 +1,477 @@
//
// MPPasswordDialogController.m
// MasterPassword-Mac
//
// Created by Maarten Billemont on 04/03/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#import "MPPasswordDialogController.h"
#import "MPMacAppDelegate.h"
#import "MPAppDelegate_Key.h"
#import "MPAppDelegate_Store.h"
#import "MPElementModel.h"
#define MPAlertUnlockMP @"MPAlertUnlockMP"
#define MPAlertIncorrectMP @"MPAlertIncorrectMP"
#define MPAlertCreateSite @"MPAlertCreateSite"
@interface MPPasswordDialogController()
@property(nonatomic) BOOL inProgress;
@property(nonatomic, strong) NSOperationQueue *backgroundQueue;
@property(nonatomic, strong) NSAlert *loadingDataAlert;
@property(nonatomic) BOOL closing;
@end
@implementation MPPasswordDialogController
#pragma mark - Life
- (void)windowDidLoad {
if ([[MPMacConfig get].dialogStyleHUD boolValue]) {
self.window.styleMask = NSHUDWindowMask | NSTitledWindowMask | NSUtilityWindowMask | NSClosableWindowMask;
self.userLabel.textColor = [NSColor whiteColor];
}
else {
self.window.styleMask = NSTexturedBackgroundWindowMask | NSResizableWindowMask | NSTitledWindowMask | NSClosableWindowMask;
self.userLabel.textColor = [NSColor controlTextColor];
}
self.backgroundQueue = [NSOperationQueue new];
self.backgroundQueue.maxConcurrentOperationCount = 1;
[[MPMacAppDelegate get] addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) {
// [MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
// if (![MPAlgorithmDefault migrateUser:[[MPMacAppDelegate get] activeUserInContext:moc]])
// [NSAlert alertWithMessageText:@"Migration Needed" defaultButton:@"OK" alternateButton:nil otherButton:nil
// informativeTextWithFormat:@"Certain sites require explicit migration to get updated to the latest version of the "
// @"Master Password algorithm. For these sites, a migration button will appear. Migrating these sites will cause "
// @"their passwords to change. You'll need to update your profile for that site with the new password."];
// [moc saveToStore];
// }];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self ensureLoadedAndUnlockedOrCloseIfLoggedOut:YES];
[self updateElements];
}];
} forKeyPath:@"key" options:NSKeyValueObservingOptionInitial context:nil];
[[NSNotificationCenter defaultCenter] addObserverForName:NSWindowDidBecomeKeyNotification object:self.window
queue:[NSOperationQueue mainQueue] usingBlock:
^(NSNotification *note) {
[self ensureLoadedAndUnlockedOrCloseIfLoggedOut:NO];
[self.siteField selectText:nil];
[self updateElements];
}];
[[NSNotificationCenter defaultCenter] addObserverForName:NSWindowWillCloseNotification object:self.window
queue:[NSOperationQueue mainQueue] usingBlock:
^(NSNotification *note) {
NSWindow *sheet = [self.window attachedSheet];
if (sheet)
[NSApp endSheet:sheet];
[NSApp hide:nil];
self.closing = NO;
}];
[[NSNotificationCenter defaultCenter] addObserverForName:MPSignedOutNotification object:nil
queue:[NSOperationQueue mainQueue] usingBlock:
^(NSNotification *note) {
self.userLabel.stringValue = @"";
self.siteField.stringValue = @"";
self.elements = nil;
[self ensureLoadedAndUnlockedOrCloseIfLoggedOut:YES];
}];
[[NSNotificationCenter defaultCenter] addObserverForName:MPSignedInNotification object:nil
queue:[NSOperationQueue mainQueue] usingBlock:
^(NSNotification *note) {
self.userLabel.stringValue = PearlString( @"%@'s password for:",
[[MPMacAppDelegate get] activeUserForMainThread].name );
}];
[[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil
queue:[NSOperationQueue mainQueue] usingBlock:
^(NSNotification *note) {
[self ensureLoadedAndUnlockedOrCloseIfLoggedOut:NO];
}];
[super windowDidLoad];
}
- (void)close {
self.closing = YES;
[super close];
}
#pragma mark - NSAlert
- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
if (contextInfo == MPAlertIncorrectMP) {
[self close];
return;
}
if (contextInfo == MPAlertUnlockMP) {
switch (returnCode) {
case NSAlertFirstButtonReturn: {
// "Unlock" button.
self.contentContainer.alphaValue = 0;
self.inProgress = YES;
NSString *password = [(NSSecureTextField *)alert.accessoryView stringValue];
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserInContext:moc];
NSString *userName = activeUser.name;
BOOL success = [[MPMacAppDelegate get] signInAsUser:activeUser saveInContext:moc
usingMasterPassword:password];
self.inProgress = NO;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
if (success)
self.contentContainer.alphaValue = 1;
else {
[[NSAlert alertWithError:[NSError errorWithDomain:MPErrorDomain code:0 userInfo:@{
NSLocalizedDescriptionKey : PearlString( @"Incorrect master password for user %@", userName )
}]] beginSheetModalForWindow:self.window modalDelegate:self
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertIncorrectMP];
}
}];
}];
break;
}
case NSAlertSecondButtonReturn: {
// "Change" button.
NSAlert *alert_ = [NSAlert new];
[alert_ addButtonWithTitle:@"Update"];
[alert_ addButtonWithTitle:@"Cancel"];
[alert_ setMessageText:@"Changing Master Password"];
[alert_ setInformativeText:@"This will allow you to log in with a different master password.\n\n"
@"Note that you will only see the sites and passwords for the master password you log in with.\n"
@"If you log in with a different master password, your current sites will be unavailable.\n\n"
@"You can always change back to your current master password later.\n"
@"Your current sites and passwords will then become available again."];
if ([alert_ runModal] == NSAlertFirstButtonReturn) {
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserInContext:context];
activeUser.keyID = nil;
[[MPMacAppDelegate get] forgetSavedKeyFor:activeUser];
[[MPMacAppDelegate get] signOutAnimated:YES];
[context saveToStore];
}];
}
break;
}
case NSAlertThirdButtonReturn: {
// "Cancel" button.
[self close];
break;
}
default:
break;
}
return;
}
if (contextInfo == MPAlertCreateSite) {
switch (returnCode) {
case NSAlertFirstButtonReturn: {
// "Create" button.
[[MPMacAppDelegate get] addElementNamed:[self.siteField stringValue] completion:^(MPElementEntity *element) {
if (element)
PearlMainQueue( ^{ [self updateElements]; } );
}];
break;
}
case NSAlertThirdButtonReturn:
// "Cancel" button.
break;
default:
break;
}
}
}
#pragma mark - NSCollectionViewDelegate
#pragma mark - NSTextFieldDelegate
- (void)doCommandBySelector:(SEL)commandSelector {
if (commandSelector == @selector(insertNewline:))
[self useSite];
}
- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector {
if (commandSelector == @selector(cancel:))
[self close];
if (commandSelector == @selector(moveUp:))
self.elementSelectionIndexes =
[NSIndexSet indexSetWithIndex:MAX(self.elementSelectionIndexes.firstIndex, (NSUInteger)1) - 1];
if (commandSelector == @selector(moveDown:))
self.elementSelectionIndexes =
[NSIndexSet indexSetWithIndex:MIN(self.elementSelectionIndexes.firstIndex + 1, self.elements.count - 1)];
if (commandSelector == @selector(moveLeft:))
[[self selectedView].animator setBoundsOrigin:NSZeroPoint];
if (commandSelector == @selector(moveRight:))
[[self selectedView].animator setBoundsOrigin:NSMakePoint( self.siteCollectionView.frame.size.width / 2, 0 )];
if (commandSelector == @selector(insertNewline:))
[self useSite];
else
return NO;
return YES;
}
- (void)controlTextDidChange:(NSNotification *)note {
if (note.object != self.siteField)
return;
// Update the site content as the site name changes.
if ([[NSApp currentEvent] type] == NSKeyDown &&
[[[NSApp currentEvent] charactersIgnoringModifiers] isEqualToString:@"\r"]) { // Return while completing.
[self useSite];
return;
}
// if ([[NSApp currentEvent] type] == NSKeyDown &&
// [[[NSApp currentEvent] charactersIgnoringModifiers] characterAtIndex:0] == 0x1b) { // Escape while completing.
// [self trySiteWithAction:NO];
// return;
// }
[self updateElements];
}
#pragma mark - Private
- (BOOL)ensureLoadedAndUnlockedOrCloseIfLoggedOut:(BOOL)closeIfLoggedOut {
if (![self ensureStoreLoaded])
return NO;
if (self.closing || self.inProgress || !self.window.isKeyWindow)
return NO;
return [self ensureUnlocked:closeIfLoggedOut];
}
- (BOOL)ensureStoreLoaded {
if ([MPMacAppDelegate managedObjectContextForMainThreadIfReady]) {
// Store loaded.
if (self.loadingDataAlert.window)
[NSApp endSheet:self.loadingDataAlert.window];
return YES;
}
[self.loadingDataAlert = [NSAlert alertWithMessageText:@"Opening Your Data" defaultButton:@"..." alternateButton:nil otherButton:nil
informativeTextWithFormat:@""]
beginSheetModalForWindow:self.window modalDelegate:self
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:nil];
return NO;
}
- (BOOL)ensureUnlocked:(BOOL)closeIfLoggedOut {
__block BOOL unlocked = NO;
[MPMacAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *moc) {
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserInContext:moc];
NSString *userName = activeUser.name;
if (!activeUser) {
// No user to sign in with.
if (closeIfLoggedOut)
[self close];
return;
}
if ([MPMacAppDelegate get].key) {
// Already logged in.
unlocked = YES;
return;
}
if (activeUser.saveKey && closeIfLoggedOut) {
// App was locked, don't instantly unlock again.
[self close];
return;
}
if ([[MPMacAppDelegate get] signInAsUser:activeUser saveInContext:moc usingMasterPassword:nil]) {
// Loaded the key from the keychain.
unlocked = YES;
return;
}
// Ask the user to set the key through his master password.
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
if ([MPMacAppDelegate get].key)
return;
[self.siteField setStringValue:@""];
NSAlert *alert = [NSAlert new];
[alert addButtonWithTitle:@"Unlock"];
[alert addButtonWithTitle:@"Change"];
[alert addButtonWithTitle:@"Cancel"];
[alert setMessageText:@"Master Password is locked."];
[alert setInformativeText:PearlString( @"The master password is required to unlock the application for:\n\n%@", userName )];
NSSecureTextField *passwordField = [[NSSecureTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )];
[alert setAccessoryView:passwordField];
[alert layout];
[alert beginSheetModalForWindow:self.window modalDelegate:self
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertUnlockMP];
[passwordField becomeFirstResponder];
}];
}];
return unlocked;
}
- (void)updateElements {
if (![MPMacAppDelegate get].key) {
self.elements = nil;
return;
}
NSString *query = [self.siteField.currentEditor string];
[MPMacAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"lastUsed" ascending:NO]];
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"(%@ == '' OR name BEGINSWITH[cd] %@) AND user == %@",
query, query, [[MPMacAppDelegate get] activeUserInContext:context]];
NSError *error = nil;
NSArray *siteResults = [context executeFetchRequest:fetchRequest error:&error];
if (!siteResults) {
err(@"While fetching elements for completion: %@", error);
return;
}
NSMutableArray *newElements = [NSMutableArray arrayWithCapacity:[siteResults count]];
for (MPElementEntity *element in siteResults)
[newElements addObject:[[MPElementModel alloc] initWithEntity:element]];
self.elements = newElements;
if (!self.selectedElement)
self.elementSelectionIndexes = [newElements count]? [NSIndexSet indexSetWithIndex:0]: nil;
}];
}
- (NSUInteger)selectedIndex {
if (!self.elementSelectionIndexes)
return NSNotFound;
NSUInteger selectedIndex = self.elementSelectionIndexes.firstIndex;
if (selectedIndex >= self.elements.count)
return NSNotFound;
return selectedIndex;
}
- (NSBox *)selectedView {
NSUInteger selectedIndex = [self selectedIndex];
if (selectedIndex == NSNotFound)
return nil;
return (NSBox *)[self.siteCollectionView itemAtIndex:selectedIndex].view;
}
- (MPElementModel *)selectedElement {
NSUInteger selectedIndex = [self selectedIndex];
if (selectedIndex == NSNotFound)
return nil;
return (MPElementModel *)self.elements[selectedIndex];
}
- (void)setSelectedElement:(MPElementModel *)element {
self.elementSelectionIndexes = [NSIndexSet indexSetWithIndex:[self.elements indexOfObject:element]];
}
- (void)useSite {
MPElementModel *selectedElement = [self selectedElement];
if (selectedElement) {
// Performing action while content is available. Copy it.
[self copyContent:selectedElement.content];
[self close];
NSUserNotification *notification = [NSUserNotification new];
notification.title = @"Password Copied";
if (selectedElement.loginName.length)
notification.subtitle = PearlString( @"%@ at %@", selectedElement.loginName, selectedElement.site );
else
notification.subtitle = selectedElement.site;
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
}
else {
NSString *siteName = [self.siteField stringValue];
if ([siteName length])
// Performing action without content but a site name is written.
[self createNewSite:siteName];
}
}
- (void)copyContent:(NSString *)content {
[[NSPasteboard generalPasteboard] declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
if (![[NSPasteboard generalPasteboard] setString:content forType:NSPasteboardTypeString]) {
wrn(@"Couldn't copy password to pasteboard.");
return;
}
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
[[self.selectedElement entityInContext:moc] use];
[moc saveToStore];
}];
}
- (void)createNewSite:(NSString *)siteName {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSAlert *alert = [NSAlert new];
[alert addButtonWithTitle:@"Create"];
[alert addButtonWithTitle:@"Cancel"];
[alert setMessageText:@"Create site?"];
[alert setInformativeText:PearlString( @"Do you want to create a new site named:\n\n%@", siteName )];
[alert beginSheetModalForWindow:self.window modalDelegate:self
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertCreateSite];
}];
}
#pragma mark - KVO
- (void)setElementSelectionIndexes:(NSIndexSet *)elementSelectionIndexes {
// First reset bounds.
PearlMainQueue(^{
NSUInteger selectedIndex = self.elementSelectionIndexes.firstIndex;
if (selectedIndex != NSNotFound && selectedIndex < self.elements.count)
[[self selectedView].animator setBoundsOrigin:NSZeroPoint];
} );
_elementSelectionIndexes = elementSelectionIndexes;
}
- (void)insertObject:(MPElementModel *)model inElementsAtIndex:(NSUInteger)index {
[self.elements insertObject:model atIndex:index];
}
- (void)removeObjectFromElementsAtIndex:(NSUInteger)index {
[self.elements removeObjectAtIndex:index];
}
@end

View File

@ -0,0 +1,380 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5056" systemVersion="13D65" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment defaultVersion="1080" identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="5056"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="MPPasswordDialogController">
<connections>
<outlet property="contentContainer" destination="143" id="214"/>
<outlet property="siteCollectionView" destination="pr9-BO-vQV" id="Bnh-WQ-RaO"/>
<outlet property="siteField" destination="182" id="224"/>
<outlet property="userLabel" destination="216" id="223"/>
<outlet property="window" destination="22" id="40"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application"/>
<window title="Master Password" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="22" customClass="NSPanel">
<windowStyleMask key="styleMask" titled="YES" closable="YES" resizable="YES" texturedBackground="YES"/>
<rect key="contentRect" x="600" y="530" width="480" height="320"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="900"/>
<value key="minSize" type="size" width="480" height="320"/>
<value key="maxSize" type="size" width="480" height="320"/>
<view key="contentView" wantsLayer="YES" id="23">
<rect key="frame" x="0.0" y="0.0" width="480" height="320"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="143">
<rect key="frame" x="0.0" y="0.0" width="480" height="320"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="182">
<rect key="frame" x="140" y="256" width="200" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<constraints>
<constraint firstAttribute="width" constant="200" id="258"/>
</constraints>
<shadow key="shadow" blurRadius="2">
<color key="color" name="controlShadowColor" catalog="System" colorSpace="catalog"/>
</shadow>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="center" placeholderString="Site name" usesSingleLineMode="YES" bezelStyle="round" id="185">
<font key="font" metaFont="cellTitle"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<outlet property="delegate" destination="-2" id="188"/>
</connections>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="216">
<rect key="frame" x="146" y="286" width="188" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" alignment="center" title="Maarten Billemont's password for:" usesSingleLineMode="YES" id="217">
<font key="font" metaFont="palette"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<scrollView autohidesScrollers="YES" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" hasVerticalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tjI-mV-s8H">
<rect key="frame" x="0.0" y="0.0" width="480" height="248"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<clipView key="contentView" id="mfh-QT-ClZ">
<rect key="frame" x="1" y="1" width="478" height="246"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<collectionView selectable="YES" maxNumberOfColumns="1" id="pr9-BO-vQV">
<rect key="frame" x="0.0" y="0.0" width="478" height="246"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="primaryBackgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="secondaryBackgroundColor" name="controlAlternatingRowColor" catalog="System" colorSpace="catalog"/>
<connections>
<binding destination="jTN-Q9-Ajn" name="content" keyPath="arrangedObjects" id="dtF-fs-Fpe"/>
<binding destination="-2" name="selectionIndexes" keyPath="elementSelectionIndexes" previousBinding="dtF-fs-Fpe" id="UFy-9F-18H"/>
<outlet property="delegate" destination="-2" id="4cD-GP-imR"/>
<outlet property="itemPrototype" destination="QBZ-sO-HQn" id="QAi-HN-YUc"/>
</connections>
</collectionView>
</subviews>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</clipView>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="6vP-Im-BRg">
<rect key="frame" x="-100" y="-100" width="233" height="15"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="vs6-1G-hvM">
<rect key="frame" x="-100" y="-100" width="15" height="143"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
<button horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="tLu-3k-QiL">
<rect key="frame" x="449" y="288" width="25" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="help" bezelStyle="helpButton" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="51o-8V-9eq">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
</subviews>
<constraints>
<constraint firstItem="216" firstAttribute="top" secondItem="143" secondAttribute="top" constant="20" symbolic="YES" id="218"/>
<constraint firstItem="182" firstAttribute="top" secondItem="216" secondAttribute="bottom" constant="8" symbolic="YES" id="221"/>
<constraint firstAttribute="bottom" secondItem="tjI-mV-s8H" secondAttribute="bottom" id="6y8-tJ-1sX"/>
<constraint firstItem="tLu-3k-QiL" firstAttribute="top" secondItem="143" secondAttribute="top" constant="8" id="9h7-dN-MqZ"/>
<constraint firstAttribute="trailing" secondItem="tLu-3k-QiL" secondAttribute="trailing" constant="8" id="UQN-Ab-fIg"/>
<constraint firstAttribute="centerX" secondItem="182" secondAttribute="centerX" id="W6t-BO-Njn"/>
<constraint firstAttribute="trailing" secondItem="tjI-mV-s8H" secondAttribute="trailing" id="aKe-a9-Br8"/>
<constraint firstItem="tjI-mV-s8H" firstAttribute="leading" secondItem="143" secondAttribute="leading" id="d8F-JD-EhR"/>
<constraint firstItem="tjI-mV-s8H" firstAttribute="top" secondItem="182" secondAttribute="bottom" constant="8" symbolic="YES" id="izG-uH-9BF"/>
<constraint firstAttribute="centerX" secondItem="216" secondAttribute="centerX" id="mkv-5E-dy5"/>
</constraints>
</customView>
</subviews>
<constraints>
<constraint firstItem="143" firstAttribute="leading" secondItem="23" secondAttribute="leading" id="145"/>
<constraint firstItem="143" firstAttribute="bottom" secondItem="23" secondAttribute="bottom" id="147"/>
<constraint firstItem="143" firstAttribute="trailing" secondItem="23" secondAttribute="trailing" id="148"/>
<constraint firstItem="143" firstAttribute="top" secondItem="23" secondAttribute="top" id="150"/>
</constraints>
</view>
<connections>
<outlet property="delegate" destination="-2" id="39"/>
</connections>
</window>
<collectionViewItem id="QBZ-sO-HQn" customClass="MPElementCollectionView">
<connections>
<outlet property="view" destination="bhu-Ky-PQq" id="jZh-jC-6bL"/>
</connections>
</collectionViewItem>
<arrayController objectClassName="MPElementModel" id="jTN-Q9-Ajn">
<connections>
<binding destination="-2" name="contentArray" keyPath="self.elements" id="8Uz-14-YG0"/>
</connections>
</arrayController>
<box autoresizesSubviews="NO" wantsLayer="YES" boxType="custom" borderType="none" titlePosition="noTitle" id="bhu-Ky-PQq">
<rect key="frame" x="0.0" y="0.0" width="960" height="61"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<view key="contentView">
<rect key="frame" x="0.0" y="0.0" width="960" height="61"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="xwJ-Pu-glP">
<rect key="frame" x="6" y="35" width="60" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<shadow key="shadow" blurRadius="1">
<size key="offset" width="0.0" height="1"/>
<color key="color" white="0.0" alpha="0.59999999999999998" colorSpace="calibratedWhite"/>
</shadow>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="apple.com" usesSingleLineMode="YES" id="ymH-M0-M5d">
<font key="font" size="12" name="Exo2.0-Light"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="QBZ-sO-HQn" name="value" keyPath="representedObject.site" id="4as-ow-WbD"/>
</connections>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Cn5-nt-e6X">
<rect key="frame" x="362" y="35" width="111" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<shadow key="shadow" blurRadius="1">
<size key="offset" width="0.0" height="1"/>
<color key="color" white="0.0" alpha="0.59999999999999998" colorSpace="calibratedWhite"/>
</shadow>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="lhunath@lyndir.com" usesSingleLineMode="YES" id="Px4-pS-kwG">
<font key="font" size="12" name="Exo2.0-Light"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="QBZ-sO-HQn" name="value" keyPath="representedObject.loginName" id="C2s-1d-p2H">
<dictionary key="options">
<bool key="NSContinuouslyUpdatesValue" value="YES"/>
</dictionary>
</binding>
</connections>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="a1n-Sf-Mw6">
<rect key="frame" x="6" y="8" width="206" height="38"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<shadow key="shadow" blurRadius="1">
<size key="offset" width="0.0" height="1"/>
<color key="color" white="0.0" alpha="0.59999999999999998" colorSpace="calibratedWhite"/>
</shadow>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="RutuTutnTeni4," id="7jb-Fa-xX3">
<font key="font" size="24" name="SourceCodePro-Light"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="QBZ-sO-HQn" name="value" keyPath="representedObject.content" id="41c-PF-OeH">
<dictionary key="options">
<bool key="NSContinuouslyUpdatesValue" value="YES"/>
</dictionary>
</binding>
</connections>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mp4-r1-7Xg">
<rect key="frame" x="440" y="8" width="33" height="38"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<shadow key="shadow" blurRadius="1">
<size key="offset" width="0.0" height="1"/>
<color key="color" white="0.0" alpha="0.59999999999999998" colorSpace="calibratedWhite"/>
</shadow>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="12" id="Vb9-nO-cWY">
<font key="font" size="24" name="SourceCodePro-Light"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="QBZ-sO-HQn" name="value" keyPath="representedObject.uses" id="gSt-Nd-lVa">
<dictionary key="options">
<bool key="NSContinuouslyUpdatesValue" value="YES"/>
</dictionary>
</binding>
</connections>
</textField>
<box autoresizesSubviews="NO" horizontalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="tsT-Xh-Nxb">
<rect key="frame" x="477" y="0.0" width="5" height="61"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<font key="titleFont" metaFont="system"/>
</box>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="vEl-aL-Qd4">
<rect key="frame" x="791" y="27" width="167" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="lhunath@lyndir.com" bezelStyle="rounded" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="sl3-bH-Hh2">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="updateLoginName:" target="QBZ-sO-HQn" id="pJI-k8-LRl"/>
<binding destination="QBZ-sO-HQn" name="title" keyPath="representedObject.loginName" id="uaP-Y1-bz6">
<dictionary key="options">
<string key="NSNullPlaceholder">Click to set login name</string>
</dictionary>
</binding>
</connections>
</button>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="d2a-pG-7CW">
<rect key="frame" x="528" y="31" width="127" height="26"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" title="Long Password" bezelStyle="rounded" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" selectedItem="7Bj-S7-WSd" id="RZo-c7-kqA">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" title="OtherViews" id="mQN-XZ-YKz">
<items>
<menuItem title="Long Password" state="on" id="7Bj-S7-WSd"/>
<menuItem title="Item 2" id="WUd-69-IBV"/>
<menuItem title="Item 3" id="pgH-yZ-G0J"/>
</items>
</menu>
</popUpButtonCell>
<connections>
<binding destination="QBZ-sO-HQn" name="contentValues" keyPath="representedObject.typeNames" id="eyo-f9-MwY"/>
<binding destination="QBZ-sO-HQn" name="selectedIndex" keyPath="representedObject.typeIndex" previousBinding="eyo-f9-MwY" id="dpI-HX-GpX"/>
</connections>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="npg-mh-AfY">
<rect key="frame" x="486" y="36" width="38" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Type:" id="U2E-DE-2j4">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="hqw-ZP-4c1">
<rect key="frame" x="486" y="11" width="59" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Number:" id="CDU-Ah-QDj">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="QBZ-sO-HQn" name="hidden" keyPath="counterHidden" id="xlz-gk-Gwc"/>
</connections>
</textField>
<stepper horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="JPX-xQ-VKZ">
<rect key="frame" x="565" y="6" width="19" height="27"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<stepperCell key="cell" alignment="left" minValue="1" maxValue="100" doubleValue="1" autorepeat="NO" id="ELG-fy-nVF"/>
<connections>
<binding destination="QBZ-sO-HQn" name="hidden" keyPath="counterHidden" id="3FO-ks-R7U"/>
<binding destination="QBZ-sO-HQn" name="value" keyPath="representedObject.counter" id="awJ-Vg-RUn"/>
</connections>
</stepper>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="kZI-sG-dEn">
<rect key="frame" x="549" y="11" width="13" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="1" id="EUB-gJ-7Db">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="QBZ-sO-HQn" name="hidden" keyPath="counterHidden" id="ZFX-79-eAY"/>
<binding destination="QBZ-sO-HQn" name="value" keyPath="representedObject.counter" id="20y-tn-B5k"/>
</connections>
</textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="qOt-Rp-G9T">
<rect key="frame" x="877" y="2" width="81" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Delete" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="QCU-VC-W0u">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="delete:" target="QBZ-sO-HQn" id="mLJ-JY-5fz"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="5YU-4W-4gz">
<rect key="frame" x="727" y="2" width="150" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Change Password" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="NQY-Oo-Eid">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="updateContent:" target="QBZ-sO-HQn" id="J8f-vx-10A"/>
<binding destination="QBZ-sO-HQn" name="hidden" keyPath="updateContentHidden" id="UwG-p5-kH4"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="bzg-90-kmh">
<rect key="frame" x="748" y="36" width="43" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Login:" id="uxE-6c-RjC">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
</view>
<constraints>
<constraint firstItem="hqw-ZP-4c1" firstAttribute="centerY" secondItem="qOt-Rp-G9T" secondAttribute="centerY" id="6xp-tI-BkX"/>
<constraint firstItem="npg-mh-AfY" firstAttribute="leading" secondItem="tsT-Xh-Nxb" secondAttribute="trailing" constant="8" id="7kp-OB-3BI"/>
<constraint firstItem="kZI-sG-dEn" firstAttribute="leading" secondItem="hqw-ZP-4c1" secondAttribute="trailing" constant="8" symbolic="YES" id="8qK-Et-c1F"/>
<constraint firstItem="d2a-pG-7CW" firstAttribute="leading" secondItem="npg-mh-AfY" secondAttribute="trailing" constant="8" symbolic="YES" id="F6X-FD-kEX"/>
<constraint firstItem="Cn5-nt-e6X" firstAttribute="top" secondItem="bhu-Ky-PQq" secondAttribute="top" constant="8" id="FWS-tY-KkM"/>
<constraint firstItem="hqw-ZP-4c1" firstAttribute="top" secondItem="npg-mh-AfY" secondAttribute="bottom" constant="8" symbolic="YES" id="GuG-5I-quA"/>
<constraint firstItem="hqw-ZP-4c1" firstAttribute="leading" secondItem="tsT-Xh-Nxb" secondAttribute="trailing" constant="8" id="Hzf-XZ-auZ"/>
<constraint firstItem="tsT-Xh-Nxb" firstAttribute="leading" secondItem="Cn5-nt-e6X" secondAttribute="trailing" constant="8" id="LjD-10-tVU"/>
<constraint firstItem="tsT-Xh-Nxb" firstAttribute="top" secondItem="bhu-Ky-PQq" secondAttribute="top" id="ODH-Nx-QdY"/>
<constraint firstItem="qOt-Rp-G9T" firstAttribute="centerY" secondItem="5YU-4W-4gz" secondAttribute="centerY" id="PdB-X5-eqF"/>
<constraint firstItem="xwJ-Pu-glP" firstAttribute="leading" secondItem="bhu-Ky-PQq" secondAttribute="leading" constant="8" id="QAM-jm-t0y"/>
<constraint firstAttribute="centerY" secondItem="tsT-Xh-Nxb" secondAttribute="centerY" id="Rpi-lc-dZ1"/>
<constraint firstItem="tsT-Xh-Nxb" firstAttribute="leading" secondItem="mp4-r1-7Xg" secondAttribute="trailing" constant="8" id="Xfc-Jq-2Rb"/>
<constraint firstAttribute="trailing" secondItem="vEl-aL-Qd4" secondAttribute="trailing" constant="8" id="ZZu-AS-C07"/>
<constraint firstAttribute="bottom" secondItem="tsT-Xh-Nxb" secondAttribute="bottom" id="ds1-7i-B7I"/>
<constraint firstItem="a1n-Sf-Mw6" firstAttribute="leading" secondItem="bhu-Ky-PQq" secondAttribute="leading" constant="8" id="e3g-2s-yee"/>
<constraint firstItem="npg-mh-AfY" firstAttribute="centerY" secondItem="vEl-aL-Qd4" secondAttribute="centerY" id="ftr-2Z-9J0"/>
<constraint firstItem="npg-mh-AfY" firstAttribute="centerY" secondItem="d2a-pG-7CW" secondAttribute="centerY" id="g9a-r0-EOo"/>
<constraint firstAttribute="bottom" secondItem="mp4-r1-7Xg" secondAttribute="bottom" constant="8" id="jCW-5H-6pT"/>
<constraint firstAttribute="centerX" secondItem="tsT-Xh-Nxb" secondAttribute="centerX" id="kx6-g0-jUW"/>
<constraint firstAttribute="bottom" secondItem="a1n-Sf-Mw6" secondAttribute="bottom" constant="8" id="mWW-rt-kl2"/>
<constraint firstItem="npg-mh-AfY" firstAttribute="top" secondItem="bhu-Ky-PQq" secondAttribute="top" constant="8" id="n7Z-EF-Dcm"/>
<constraint firstItem="qOt-Rp-G9T" firstAttribute="leading" secondItem="5YU-4W-4gz" secondAttribute="trailing" constant="12" symbolic="YES" id="uWm-hE-itO"/>
<constraint firstAttribute="trailing" secondItem="qOt-Rp-G9T" secondAttribute="trailing" constant="8" id="x6J-1l-rU4"/>
<constraint firstItem="hqw-ZP-4c1" firstAttribute="centerY" secondItem="kZI-sG-dEn" secondAttribute="centerY" id="xZ7-Mc-9dq"/>
<constraint firstItem="vEl-aL-Qd4" firstAttribute="leading" secondItem="bzg-90-kmh" secondAttribute="trailing" constant="8" symbolic="YES" id="z7h-om-WAV"/>
<constraint firstItem="xwJ-Pu-glP" firstAttribute="top" secondItem="bhu-Ky-PQq" secondAttribute="top" constant="8" id="z8k-ot-NjU"/>
<constraint firstItem="bzg-90-kmh" firstAttribute="centerY" secondItem="vEl-aL-Qd4" secondAttribute="centerY" id="zbz-Qg-uHO"/>
<constraint firstItem="JPX-xQ-VKZ" firstAttribute="centerY" secondItem="kZI-sG-dEn" secondAttribute="centerY" id="zcO-M3-gyr"/>
<constraint firstItem="JPX-xQ-VKZ" firstAttribute="leading" secondItem="kZI-sG-dEn" secondAttribute="trailing" constant="8" symbolic="YES" id="zvB-Vk-IL2"/>
</constraints>
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
<color key="fillColor" name="selectedControlColor" catalog="System" colorSpace="catalog"/>
<connections>
<binding destination="QBZ-sO-HQn" name="transparent" keyPath="selected" id="Tpz-Rp-lA7">
<dictionary key="options">
<string key="NSValueTransformerName">NSNegateBoolean</string>
</dictionary>
</binding>
</connections>
</box>
</objects>
</document>

View File

@ -0,0 +1,23 @@
/**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
//
// MPPasswordWindow.h
// MPPasswordWindow
//
// Created by lhunath on 2014-06-19.
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface MPPasswordWindow : NSWindow
@end

View File

@ -0,0 +1,43 @@
/**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
//
// MPPasswordWindow.h
// MPPasswordWindow
//
// Created by lhunath on 2014-06-19.
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
//
#import "MPPasswordWindow.h"
@implementation MPPasswordWindow
#pragma mark - Life
- (void)awakeFromNib {
[super awakeFromNib];
self.level = NSScreenSaverWindowLevel;
self.alphaValue = 0;
}
- (BOOL)canBecomeKeyWindow {
return YES;
}
#pragma mark - State
#pragma mark - Private
@end

View File

@ -1,23 +1,27 @@
/**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
//
// MPPasswordWindowController.h
// MasterPassword-Mac
// MPPasswordWindowController
//
// Created by Maarten Billemont on 04/03/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
// Created by lhunath on 2014-06-18.
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@class MPElementModel;
@interface MPPasswordWindowController : NSWindowController<NSTextFieldDelegate, NSCollectionViewDelegate>
@property(nonatomic, strong) NSMutableArray *elements;
@property(nonatomic, strong) NSIndexSet *elementSelectionIndexes;
@property(nonatomic, weak) IBOutlet NSTextField *siteField;
@property(nonatomic, weak) IBOutlet NSView *contentContainer;
@property(nonatomic, weak) IBOutlet NSImageView *blurView;
@property(nonatomic, weak) IBOutlet NSTextField *userLabel;
@property(nonatomic, weak) IBOutlet NSCollectionView *siteCollectionView;
- (void)updateElements;
@property(nonatomic, weak) IBOutlet NSSearchField *siteField;
@end

View File

@ -1,30 +1,24 @@
/**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
//
// MPPasswordWindowController.m
// MasterPassword-Mac
// MPPasswordWindowController.h
// MPPasswordWindowController
//
// Created by Maarten Billemont on 04/03/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
// Created by lhunath on 2014-06-18.
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
//
#import "MPPasswordWindowController.h"
#import "MPMacAppDelegate.h"
#import "MPAppDelegate_Key.h"
#import "MPAppDelegate_Store.h"
#import "MPElementModel.h"
#define MPAlertUnlockMP @"MPAlertUnlockMP"
#define MPAlertIncorrectMP @"MPAlertIncorrectMP"
#define MPAlertCreateSite @"MPAlertCreateSite"
@interface MPPasswordWindowController()
@property(nonatomic) BOOL inProgress;
@property(nonatomic, strong) NSOperationQueue *backgroundQueue;
@property(nonatomic, strong) NSAlert *loadingDataAlert;
@property(nonatomic) BOOL closing;
@end
@implementation MPPasswordWindowController
@ -32,446 +26,78 @@
- (void)windowDidLoad {
if ([[MPMacConfig get].dialogStyleHUD boolValue]) {
self.window.styleMask = NSHUDWindowMask | NSTitledWindowMask | NSUtilityWindowMask | NSClosableWindowMask;
self.userLabel.textColor = [NSColor whiteColor];
}
else {
self.window.styleMask = NSTexturedBackgroundWindowMask | NSResizableWindowMask | NSTitledWindowMask | NSClosableWindowMask;
self.userLabel.textColor = [NSColor controlTextColor];
}
self.backgroundQueue = [NSOperationQueue new];
self.backgroundQueue.maxConcurrentOperationCount = 1;
[[MPMacAppDelegate get] addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) {
// [MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
// if (![MPAlgorithmDefault migrateUser:[[MPMacAppDelegate get] activeUserInContext:moc]])
// [NSAlert alertWithMessageText:@"Migration Needed" defaultButton:@"OK" alternateButton:nil otherButton:nil
// informativeTextWithFormat:@"Certain sites require explicit migration to get updated to the latest version of the "
// @"Master Password algorithm. For these sites, a migration button will appear. Migrating these sites will cause "
// @"their passwords to change. You'll need to update your profile for that site with the new password."];
// [moc saveToStore];
// }];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self ensureLoadedAndUnlockedOrCloseIfLoggedOut:YES];
[self updateElements];
}];
} forKeyPath:@"key" options:NSKeyValueObservingOptionInitial context:nil];
[[NSNotificationCenter defaultCenter] addObserverForName:NSWindowDidBecomeKeyNotification object:self.window
queue:[NSOperationQueue mainQueue] usingBlock:
^(NSNotification *note) {
[self ensureLoadedAndUnlockedOrCloseIfLoggedOut:NO];
[self.siteField selectText:nil];
[self updateElements];
}];
[[NSNotificationCenter defaultCenter] addObserverForName:NSWindowWillCloseNotification object:self.window
queue:[NSOperationQueue mainQueue] usingBlock:
^(NSNotification *note) {
NSWindow *sheet = [self.window attachedSheet];
if (sheet)
[NSApp endSheet:sheet];
[NSApp hide:nil];
self.closing = NO;
}];
[[NSNotificationCenter defaultCenter] addObserverForName:MPSignedOutNotification object:nil
queue:[NSOperationQueue mainQueue] usingBlock:
^(NSNotification *note) {
self.userLabel.stringValue = @"";
self.siteField.stringValue = @"";
self.elements = nil;
[self ensureLoadedAndUnlockedOrCloseIfLoggedOut:YES];
}];
[[NSNotificationCenter defaultCenter] addObserverForName:MPSignedInNotification object:nil
queue:[NSOperationQueue mainQueue] usingBlock:
^(NSNotification *note) {
self.userLabel.stringValue = PearlString( @"%@'s password for:",
[[MPMacAppDelegate get] activeUserForMainThread].name );
}];
[[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil
queue:[NSOperationQueue mainQueue] usingBlock:
^(NSNotification *note) {
[self ensureLoadedAndUnlockedOrCloseIfLoggedOut:NO];
}];
[super windowDidLoad];
// [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationWillBecomeActiveNotification object:nil
// queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
// [self fadeIn];
// }];
// [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationWillResignActiveNotification object:nil
// queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
// [self fadeOut];
// }];
[[NSNotificationCenter defaultCenter] addObserverForName:NSWindowDidBecomeKeyNotification object:self.window
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
[self fadeIn];
[self.siteField becomeFirstResponder];
}];
[[NSNotificationCenter defaultCenter] addObserverForName:NSWindowDidResignKeyNotification object:self.window
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
[self fadeOut];
}];
[[NSNotificationCenter defaultCenter] addObserverForName:MPSignedInNotification object:nil
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
[self updateUser];
}];
[[NSNotificationCenter defaultCenter] addObserverForName:MPSignedOutNotification object:nil
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
[self updateUser];
}];
}
- (void)close {
- (void)updateUser {
self.closing = YES;
[super close];
[MPMacAppDelegate managedObjectContextForMainThreadPerformBlock:^(NSManagedObjectContext *mainContext) {
MPUserEntity *mainActiveUser = [[MPMacAppDelegate get] activeUserInContext:mainContext];
if (mainActiveUser)
self.userLabel.stringValue = strf( @"%@'s password for:", mainActiveUser.name );
else
self.userLabel.stringValue = @"";
}];
}
#pragma mark - NSAlert
- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
if (contextInfo == MPAlertIncorrectMP) {
[self close];
return;
}
if (contextInfo == MPAlertUnlockMP) {
switch (returnCode) {
case NSAlertFirstButtonReturn: {
// "Unlock" button.
self.contentContainer.alphaValue = 0;
self.inProgress = YES;
NSString *password = [(NSSecureTextField *)alert.accessoryView stringValue];
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserInContext:moc];
NSString *userName = activeUser.name;
BOOL success = [[MPMacAppDelegate get] signInAsUser:activeUser saveInContext:moc
usingMasterPassword:password];
self.inProgress = NO;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
if (success)
self.contentContainer.alphaValue = 1;
else {
[[NSAlert alertWithError:[NSError errorWithDomain:MPErrorDomain code:0 userInfo:@{
NSLocalizedDescriptionKey : PearlString( @"Incorrect master password for user %@", userName )
}]] beginSheetModalForWindow:self.window modalDelegate:self
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertIncorrectMP];
}
}];
}];
break;
}
case NSAlertSecondButtonReturn: {
// "Change" button.
NSAlert *alert_ = [NSAlert new];
[alert_ addButtonWithTitle:@"Update"];
[alert_ addButtonWithTitle:@"Cancel"];
[alert_ setMessageText:@"Changing Master Password"];
[alert_ setInformativeText:@"This will allow you to log in with a different master password.\n\n"
@"Note that you will only see the sites and passwords for the master password you log in with.\n"
@"If you log in with a different master password, your current sites will be unavailable.\n\n"
@"You can always change back to your current master password later.\n"
@"Your current sites and passwords will then become available again."];
if ([alert_ runModal] == NSAlertFirstButtonReturn) {
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserInContext:context];
activeUser.keyID = nil;
[[MPMacAppDelegate get] forgetSavedKeyFor:activeUser];
[[MPMacAppDelegate get] signOutAnimated:YES];
[context saveToStore];
}];
}
break;
}
case NSAlertThirdButtonReturn: {
// "Cancel" button.
[self close];
break;
}
default:
break;
}
return;
}
if (contextInfo == MPAlertCreateSite) {
switch (returnCode) {
case NSAlertFirstButtonReturn: {
// "Create" button.
[[MPMacAppDelegate get] addElementNamed:[self.siteField stringValue] completion:^(MPElementEntity *element) {
if (element)
PearlMainQueue( ^{ [self updateElements]; } );
}];
break;
}
case NSAlertThirdButtonReturn:
// "Cancel" button.
break;
default:
break;
}
}
}
#pragma mark - NSCollectionViewDelegate
#pragma mark - NSTextFieldDelegate
- (void)doCommandBySelector:(SEL)commandSelector {
if (commandSelector == @selector(insertNewline:))
[self useSite];
}
- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector {
if (commandSelector == @selector(cancel:))
[self close];
if (commandSelector == @selector(moveUp:))
self.elementSelectionIndexes =
[NSIndexSet indexSetWithIndex:MAX(self.elementSelectionIndexes.firstIndex, (NSUInteger)1) - 1];
if (commandSelector == @selector(moveDown:))
self.elementSelectionIndexes =
[NSIndexSet indexSetWithIndex:MIN(self.elementSelectionIndexes.firstIndex + 1, self.elements.count - 1)];
if (commandSelector == @selector(moveLeft:))
[[self selectedView].animator setBoundsOrigin:NSZeroPoint];
if (commandSelector == @selector(moveRight:))
[[self selectedView].animator setBoundsOrigin:NSMakePoint( self.siteCollectionView.frame.size.width / 2, 0 )];
if (commandSelector == @selector(insertNewline:))
[self useSite];
else
return NO;
return YES;
}
- (void)controlTextDidChange:(NSNotification *)note {
if (note.object != self.siteField)
return;
// Update the site content as the site name changes.
if ([[NSApp currentEvent] type] == NSKeyDown &&
[[[NSApp currentEvent] charactersIgnoringModifiers] isEqualToString:@"\r"]) { // Return while completing.
[self useSite];
return;
}
// if ([[NSApp currentEvent] type] == NSKeyDown &&
// [[[NSApp currentEvent] charactersIgnoringModifiers] characterAtIndex:0] == 0x1b) { // Escape while completing.
// [self trySiteWithAction:NO];
// return;
// }
[self updateElements];
}
#pragma mark - State
#pragma mark - Private
- (BOOL)ensureLoadedAndUnlockedOrCloseIfLoggedOut:(BOOL)closeIfLoggedOut {
- (void)fadeIn {
if (![self ensureStoreLoaded])
return NO;
CGWindowID windowID = (CGWindowID)[self.window windowNumber];
CGImageRef capturedImage = CGWindowListCreateImage( CGRectInfinite, kCGWindowListOptionOnScreenBelowWindow, windowID,
kCGWindowImageBoundsIgnoreFraming );
NSImage *screenImage = [[NSImage alloc] initWithCGImage:capturedImage size:NSMakeSize(
CGImageGetWidth( capturedImage ) / self.window.backingScaleFactor,
CGImageGetHeight( capturedImage ) / self.window.backingScaleFactor )];
if (self.closing || self.inProgress || !self.window.isKeyWindow)
return NO;
NSImage *smallImage = [[NSImage alloc] initWithSize:NSMakeSize(
CGImageGetWidth( capturedImage ) / 20,
CGImageGetHeight( capturedImage ) / 20 )];
[smallImage lockFocus];
[screenImage drawInRect:(NSRect){ .origin = CGPointZero, .size = smallImage.size, }
fromRect:NSZeroRect
operation:NSCompositeSourceOver
fraction:1.0];
[smallImage unlockFocus];
return [self ensureUnlocked:closeIfLoggedOut];
self.blurView.image = smallImage;
[self.window setFrame:self.window.screen.frame display:YES];
[[self.window animator] setAlphaValue:1.0];
}
- (BOOL)ensureStoreLoaded {
- (void)fadeOut {
if ([MPMacAppDelegate managedObjectContextForMainThreadIfReady]) {
// Store loaded.
if (self.loadingDataAlert.window)
[NSApp endSheet:self.loadingDataAlert.window];
return YES;
}
[self.loadingDataAlert = [NSAlert alertWithMessageText:@"Opening Your Data" defaultButton:@"..." alternateButton:nil otherButton:nil
informativeTextWithFormat:@""]
beginSheetModalForWindow:self.window modalDelegate:self
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:nil];
return NO;
}
- (BOOL)ensureUnlocked:(BOOL)closeIfLoggedOut {
__block BOOL unlocked = NO;
[MPMacAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *moc) {
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserInContext:moc];
NSString *userName = activeUser.name;
if (!activeUser) {
// No user to sign in with.
if (closeIfLoggedOut)
[self close];
return;
}
if ([MPMacAppDelegate get].key) {
// Already logged in.
unlocked = YES;
return;
}
if (activeUser.saveKey && closeIfLoggedOut) {
// App was locked, don't instantly unlock again.
[self close];
return;
}
if ([[MPMacAppDelegate get] signInAsUser:activeUser saveInContext:moc usingMasterPassword:nil]) {
// Loaded the key from the keychain.
unlocked = YES;
return;
}
// Ask the user to set the key through his master password.
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
if ([MPMacAppDelegate get].key)
return;
[self.siteField setStringValue:@""];
NSAlert *alert = [NSAlert new];
[alert addButtonWithTitle:@"Unlock"];
[alert addButtonWithTitle:@"Change"];
[alert addButtonWithTitle:@"Cancel"];
[alert setMessageText:@"Master Password is locked."];
[alert setInformativeText:PearlString( @"The master password is required to unlock the application for:\n\n%@", userName )];
NSSecureTextField *passwordField = [[NSSecureTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )];
[alert setAccessoryView:passwordField];
[alert layout];
[alert beginSheetModalForWindow:self.window modalDelegate:self
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertUnlockMP];
[passwordField becomeFirstResponder];
}];
}];
return unlocked;
}
- (void)updateElements {
if (![MPMacAppDelegate get].key) {
self.elements = nil;
return;
}
NSString *query = [self.siteField.currentEditor string];
[MPMacAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"lastUsed" ascending:NO]];
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"(%@ == '' OR name BEGINSWITH[cd] %@) AND user == %@",
query, query, [[MPMacAppDelegate get] activeUserInContext:context]];
NSError *error = nil;
NSArray *siteResults = [context executeFetchRequest:fetchRequest error:&error];
if (!siteResults) {
err(@"While fetching elements for completion: %@", error);
return;
}
NSMutableArray *newElements = [NSMutableArray arrayWithCapacity:[siteResults count]];
for (MPElementEntity *element in siteResults)
[newElements addObject:[[MPElementModel alloc] initWithEntity:element]];
self.elements = newElements;
if (!self.selectedElement)
self.elementSelectionIndexes = [newElements count]? [NSIndexSet indexSetWithIndex:0]: nil;
}];
}
- (NSUInteger)selectedIndex {
if (!self.elementSelectionIndexes)
return NSNotFound;
NSUInteger selectedIndex = self.elementSelectionIndexes.firstIndex;
if (selectedIndex >= self.elements.count)
return NSNotFound;
return selectedIndex;
}
- (NSBox *)selectedView {
NSUInteger selectedIndex = [self selectedIndex];
if (selectedIndex == NSNotFound)
return nil;
return (NSBox *)[self.siteCollectionView itemAtIndex:selectedIndex].view;
}
- (MPElementModel *)selectedElement {
NSUInteger selectedIndex = [self selectedIndex];
if (selectedIndex == NSNotFound)
return nil;
return (MPElementModel *)self.elements[selectedIndex];
}
- (void)setSelectedElement:(MPElementModel *)element {
self.elementSelectionIndexes = [NSIndexSet indexSetWithIndex:[self.elements indexOfObject:element]];
}
- (void)useSite {
MPElementModel *selectedElement = [self selectedElement];
if (selectedElement) {
// Performing action while content is available. Copy it.
[self copyContent:selectedElement.content];
[self close];
NSUserNotification *notification = [NSUserNotification new];
notification.title = @"Password Copied";
if (selectedElement.loginName.length)
notification.subtitle = PearlString( @"%@ at %@", selectedElement.loginName, selectedElement.site );
else
notification.subtitle = selectedElement.site;
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
}
else {
NSString *siteName = [self.siteField stringValue];
if ([siteName length])
// Performing action without content but a site name is written.
[self createNewSite:siteName];
}
}
- (void)copyContent:(NSString *)content {
[[NSPasteboard generalPasteboard] declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
if (![[NSPasteboard generalPasteboard] setString:content forType:NSPasteboardTypeString]) {
wrn(@"Couldn't copy password to pasteboard.");
return;
}
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
[[self.selectedElement entityInContext:moc] use];
[moc saveToStore];
}];
}
- (void)createNewSite:(NSString *)siteName {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSAlert *alert = [NSAlert new];
[alert addButtonWithTitle:@"Create"];
[alert addButtonWithTitle:@"Cancel"];
[alert setMessageText:@"Create site?"];
[alert setInformativeText:PearlString( @"Do you want to create a new site named:\n\n%@", siteName )];
[alert beginSheetModalForWindow:self.window modalDelegate:self
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertCreateSite];
}];
}
#pragma mark - KVO
- (void)setElementSelectionIndexes:(NSIndexSet *)elementSelectionIndexes {
// First reset bounds.
PearlMainQueue(^{
NSUInteger selectedIndex = self.elementSelectionIndexes.firstIndex;
if (selectedIndex != NSNotFound && selectedIndex < self.elements.count)
[[self selectedView].animator setBoundsOrigin:NSZeroPoint];
} );
_elementSelectionIndexes = elementSelectionIndexes;
}
- (void)insertObject:(MPElementModel *)model inElementsAtIndex:(NSUInteger)index {
[self.elements insertObject:model atIndex:index];
}
- (void)removeObjectFromElementsAtIndex:(NSUInteger)index {
[self.elements removeObjectAtIndex:index];
[[self.window animator] setAlphaValue:0.0];
}
@end

View File

@ -7,374 +7,203 @@
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="MPPasswordWindowController">
<connections>
<outlet property="contentContainer" destination="143" id="214"/>
<outlet property="siteCollectionView" destination="pr9-BO-vQV" id="Bnh-WQ-RaO"/>
<outlet property="siteField" destination="182" id="224"/>
<outlet property="userLabel" destination="216" id="223"/>
<outlet property="window" destination="22" id="40"/>
<outlet property="blurView" destination="Bwc-sd-6gm" id="wNV-0x-LJn"/>
<outlet property="siteField" destination="CnS-iI-dhr" id="nPo-Kb-YM2"/>
<outlet property="window" destination="QvC-M9-y7g" id="dPy-F3-9rn"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application"/>
<window title="Master Password" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="22" customClass="NSPanel">
<windowStyleMask key="styleMask" titled="YES" closable="YES" resizable="YES" texturedBackground="YES"/>
<rect key="contentRect" x="600" y="530" width="480" height="320"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="900"/>
<value key="minSize" type="size" width="480" height="320"/>
<value key="maxSize" type="size" width="480" height="320"/>
<view key="contentView" wantsLayer="YES" id="23">
<rect key="frame" x="0.0" y="0.0" width="480" height="320"/>
<window title="Master Password" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hasShadow="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="MPPasswordWindow">
<windowCollectionBehavior key="collectionBehavior" transient="YES" ignoresCycle="YES" fullScreenAuxiliary="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="0.0" y="0.0" width="640" height="480"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="878"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="640" height="480"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="143">
<rect key="frame" x="0.0" y="0.0" width="480" height="320"/>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Bwc-sd-6gm">
<rect key="frame" x="0.0" y="0.0" width="640" height="480"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<contentFilters>
<ciFilter name="CIGaussianBlur">
<configuration>
<null key="inputImage"/>
<real key="inputRadius" value="40"/>
</configuration>
</ciFilter>
<ciFilter name="CIColorControls">
<configuration>
<real key="inputBrightness" value="0.0"/>
<real key="inputContrast" value="1.1000000000000001"/>
<null key="inputImage"/>
<real key="inputSaturation" value="2"/>
</configuration>
</ciFilter>
</contentFilters>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="small-screen" id="ArA-2w-I56"/>
</imageView>
<scrollView focusRingType="none" borderType="none" autohidesScrollers="YES" horizontalLineScroll="37" horizontalPageScroll="10" verticalLineScroll="37" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Bme-XK-MMc">
<rect key="frame" x="120" y="0.0" width="400" height="207"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="e11-59-xSS">
<rect key="frame" x="0.0" y="0.0" width="400" height="207"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="none" columnReordering="NO" columnResizing="NO" multipleSelection="NO" emptySelection="NO" autosaveColumns="NO" rowHeight="35" rowSizeStyle="automatic" viewBased="YES" id="xvJ-5c-vDp">
<rect key="frame" x="0.0" y="0.0" width="403" height="207"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="0.0" colorSpace="calibratedRGB"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn editable="NO" width="400" minWidth="40" maxWidth="1000" id="S71-gk-yF7">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="0.33333298560000002" alpha="1" colorSpace="calibratedWhite"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="dRO-6J-4JL">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES"/>
<prototypeCellViews>
<tableCellView id="Rv8-uU-ieA">
<rect key="frame" x="1" y="1" width="400" height="35"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="pTl-fc-MSY">
<rect key="frame" x="-2" y="0.0" width="404" height="35"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" alignment="center" title="Table View Cell" id="5Ug-eU-C9Y">
<font key="font" size="24" name="Baskerville"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="pTl-fc-MSY" firstAttribute="leading" secondItem="Rv8-uU-ieA" secondAttribute="leading" id="73u-nD-WxM"/>
<constraint firstItem="pTl-fc-MSY" firstAttribute="top" secondItem="Rv8-uU-ieA" secondAttribute="top" id="ER6-pU-Swl"/>
<constraint firstAttribute="trailing" secondItem="pTl-fc-MSY" secondAttribute="trailing" id="Fv4-ob-IQm"/>
<constraint firstAttribute="bottom" secondItem="pTl-fc-MSY" secondAttribute="bottom" id="rde-CC-bsL"/>
</constraints>
<connections>
<outlet property="textField" destination="pTl-fc-MSY" id="Bh8-R0-bFt"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
</tableColumns>
</tableView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="0.0" colorSpace="calibratedRGB"/>
</clipView>
<constraints>
<constraint firstAttribute="width" constant="400" id="qfu-pO-SvM"/>
</constraints>
<scroller key="horizontalScroller" verticalHuggingPriority="750" horizontal="YES" id="8wr-pu-1lc">
<rect key="frame" x="0.0" y="191" width="400" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="mcf-ST-XXI">
<rect key="frame" x="-16" y="17" width="16" height="0.0"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
<button hidden="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="vES-W5-m4x">
<rect key="frame" x="266" y="272" width="109" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="recessed" title="Long Password" bezelStyle="recessed" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Fom-sN-EtZ">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="systemBold" size="12"/>
</buttonCell>
</button>
<searchField focusRingType="none" verticalHuggingPriority="750" setsMaxLayoutWidthAtFirstLayout="YES" translatesAutoresizingMaskIntoConstraints="NO" id="CnS-iI-dhr">
<rect key="frame" x="170" y="215" width="300" height="50"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<constraints>
<constraint firstAttribute="width" constant="300" id="rW7-Vq-4Xy"/>
</constraints>
<searchFieldCell key="cell" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" focusRingType="none" alignment="center" placeholderString="Site Name" drawsBackground="YES" id="ppl-2c-1E9">
<font key="font" size="36" name="Baskerville-Italic"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="0.0" colorSpace="calibratedRGB"/>
</searchFieldCell>
</searchField>
<customView hidden="YES" translatesAutoresizingMaskIntoConstraints="NO" id="d3u-Ze-9uf">
<rect key="frame" x="383" y="271" width="29" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="182">
<rect key="frame" x="140" y="256" width="200" height="22"/>
<stepper horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="XgA-Vl-CKh">
<rect key="frame" x="-3" y="-3" width="19" height="27"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<constraints>
<constraint firstAttribute="width" constant="200" id="258"/>
</constraints>
<shadow key="shadow" blurRadius="2">
<color key="color" name="controlShadowColor" catalog="System" colorSpace="catalog"/>
</shadow>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="center" placeholderString="Site name" usesSingleLineMode="YES" bezelStyle="round" id="185">
<font key="font" metaFont="cellTitle"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<outlet property="delegate" destination="-2" id="188"/>
</connections>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="216">
<rect key="frame" x="146" y="286" width="188" height="14"/>
<stepperCell key="cell" continuous="YES" alignment="left" maxValue="100" id="ikF-n4-xiI"/>
</stepper>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="NvO-kt-eZ2">
<rect key="frame" x="19" y="3" width="12" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" alignment="center" title="Maarten Billemont's password for:" usesSingleLineMode="YES" id="217">
<font key="font" metaFont="palette"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="1" id="dhQ-bJ-rn3">
<font key="font" metaFont="systemBold" size="12"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<scrollView autohidesScrollers="YES" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" hasVerticalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tjI-mV-s8H">
<rect key="frame" x="0.0" y="0.0" width="480" height="248"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<clipView key="contentView" id="mfh-QT-ClZ">
<rect key="frame" x="1" y="1" width="478" height="246"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<collectionView selectable="YES" maxNumberOfColumns="1" id="pr9-BO-vQV">
<rect key="frame" x="0.0" y="0.0" width="478" height="246"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="primaryBackgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="secondaryBackgroundColor" name="controlAlternatingRowColor" catalog="System" colorSpace="catalog"/>
<connections>
<binding destination="jTN-Q9-Ajn" name="content" keyPath="arrangedObjects" id="dtF-fs-Fpe"/>
<binding destination="-2" name="selectionIndexes" keyPath="elementSelectionIndexes" previousBinding="dtF-fs-Fpe" id="UFy-9F-18H"/>
<outlet property="delegate" destination="-2" id="4cD-GP-imR"/>
<outlet property="itemPrototype" destination="QBZ-sO-HQn" id="QAi-HN-YUc"/>
</connections>
</collectionView>
</subviews>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</clipView>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="6vP-Im-BRg">
<rect key="frame" x="-100" y="-100" width="233" height="15"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="vs6-1G-hvM">
<rect key="frame" x="-100" y="-100" width="15" height="143"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
<button horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="tLu-3k-QiL">
<rect key="frame" x="449" y="288" width="25" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="help" bezelStyle="helpButton" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="51o-8V-9eq">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
</subviews>
<constraints>
<constraint firstItem="216" firstAttribute="top" secondItem="143" secondAttribute="top" constant="20" symbolic="YES" id="218"/>
<constraint firstItem="182" firstAttribute="top" secondItem="216" secondAttribute="bottom" constant="8" symbolic="YES" id="221"/>
<constraint firstAttribute="bottom" secondItem="tjI-mV-s8H" secondAttribute="bottom" id="6y8-tJ-1sX"/>
<constraint firstItem="tLu-3k-QiL" firstAttribute="top" secondItem="143" secondAttribute="top" constant="8" id="9h7-dN-MqZ"/>
<constraint firstAttribute="trailing" secondItem="tLu-3k-QiL" secondAttribute="trailing" constant="8" id="UQN-Ab-fIg"/>
<constraint firstAttribute="centerX" secondItem="182" secondAttribute="centerX" id="W6t-BO-Njn"/>
<constraint firstAttribute="trailing" secondItem="tjI-mV-s8H" secondAttribute="trailing" id="aKe-a9-Br8"/>
<constraint firstItem="tjI-mV-s8H" firstAttribute="leading" secondItem="143" secondAttribute="leading" id="d8F-JD-EhR"/>
<constraint firstItem="tjI-mV-s8H" firstAttribute="top" secondItem="182" secondAttribute="bottom" constant="8" symbolic="YES" id="izG-uH-9BF"/>
<constraint firstAttribute="centerX" secondItem="216" secondAttribute="centerX" id="mkv-5E-dy5"/>
<constraint firstAttribute="trailing" secondItem="NvO-kt-eZ2" secondAttribute="trailing" id="4Jx-wu-xIx"/>
<constraint firstAttribute="centerY" secondItem="NvO-kt-eZ2" secondAttribute="centerY" id="7XR-0G-Ptd"/>
<constraint firstAttribute="height" priority="250" id="S2c-OE-l9l"/>
<constraint firstItem="NvO-kt-eZ2" firstAttribute="leading" secondItem="XgA-Vl-CKh" secondAttribute="trailing" constant="8" symbolic="YES" id="V9l-un-zYj"/>
<constraint firstAttribute="centerY" secondItem="XgA-Vl-CKh" secondAttribute="centerY" id="Ye6-AA-god"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="XgA-Vl-CKh" secondAttribute="bottom" id="f3p-gK-Pzg"/>
<constraint firstItem="NvO-kt-eZ2" firstAttribute="top" relation="greaterThanOrEqual" secondItem="d3u-Ze-9uf" secondAttribute="top" id="pdR-fg-9FI"/>
<constraint firstItem="XgA-Vl-CKh" firstAttribute="top" relation="greaterThanOrEqual" secondItem="d3u-Ze-9uf" secondAttribute="top" id="sLs-IG-OES"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="NvO-kt-eZ2" secondAttribute="bottom" id="upD-lF-5lW"/>
<constraint firstItem="XgA-Vl-CKh" firstAttribute="leading" secondItem="d3u-Ze-9uf" secondAttribute="leading" id="vKj-dp-A0D"/>
</constraints>
</customView>
<button hidden="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="1Qo-iG-CQt">
<rect key="frame" x="251" y="300" width="139" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="recessed" title="lhunath@lyndir.com" alternateTitle="Login Name" bezelStyle="recessed" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="QFo-9y-aVe">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="systemBold" size="12"/>
</buttonCell>
</button>
</subviews>
<constraints>
<constraint firstItem="143" firstAttribute="leading" secondItem="23" secondAttribute="leading" id="145"/>
<constraint firstItem="143" firstAttribute="bottom" secondItem="23" secondAttribute="bottom" id="147"/>
<constraint firstItem="143" firstAttribute="trailing" secondItem="23" secondAttribute="trailing" id="148"/>
<constraint firstItem="143" firstAttribute="top" secondItem="23" secondAttribute="top" id="150"/>
<constraint firstAttribute="bottom" secondItem="Bme-XK-MMc" secondAttribute="bottom" id="1kJ-cV-fhc"/>
<constraint firstItem="Bme-XK-MMc" firstAttribute="top" secondItem="CnS-iI-dhr" secondAttribute="bottom" constant="8" symbolic="YES" id="1ta-BC-BdQ"/>
<constraint firstAttribute="bottom" secondItem="Bwc-sd-6gm" secondAttribute="bottom" id="3fF-7g-c6C"/>
<constraint firstItem="vES-W5-m4x" firstAttribute="centerX" secondItem="CnS-iI-dhr" secondAttribute="centerX" id="92S-HP-Vk7"/>
<constraint firstAttribute="centerY" secondItem="CnS-iI-dhr" secondAttribute="centerY" id="HjG-vb-3Qg"/>
<constraint firstItem="d3u-Ze-9uf" firstAttribute="leading" secondItem="vES-W5-m4x" secondAttribute="trailing" constant="8" symbolic="YES" id="Juf-Q3-pkt"/>
<constraint firstItem="CnS-iI-dhr" firstAttribute="top" secondItem="vES-W5-m4x" secondAttribute="bottom" constant="8" symbolic="YES" id="KV1-8O-msX"/>
<constraint firstItem="Bwc-sd-6gm" firstAttribute="top" secondItem="EiT-Mj-1SZ" secondAttribute="top" id="Kqb-ig-5cP"/>
<constraint firstAttribute="centerX" secondItem="CnS-iI-dhr" secondAttribute="centerX" id="Qqi-bu-q65"/>
<constraint firstItem="1Qo-iG-CQt" firstAttribute="centerX" secondItem="vES-W5-m4x" secondAttribute="centerX" id="YEW-63-DI1"/>
<constraint firstAttribute="trailing" secondItem="Bwc-sd-6gm" secondAttribute="trailing" id="gKu-JH-NDR"/>
<constraint firstItem="Bme-XK-MMc" firstAttribute="centerX" secondItem="CnS-iI-dhr" secondAttribute="centerX" id="i7B-jz-xgm"/>
<constraint firstItem="d3u-Ze-9uf" firstAttribute="centerY" secondItem="vES-W5-m4x" secondAttribute="centerY" id="oyK-p1-dQM"/>
<constraint firstItem="Bwc-sd-6gm" firstAttribute="leading" secondItem="EiT-Mj-1SZ" secondAttribute="leading" id="tea-fv-b1S"/>
<constraint firstItem="d3u-Ze-9uf" firstAttribute="top" secondItem="1Qo-iG-CQt" secondAttribute="bottom" constant="8" symbolic="YES" id="vYh-fH-UME"/>
</constraints>
<backgroundFilters>
<ciFilter name="CIGaussianBlur">
<configuration>
<null key="inputImage"/>
<real key="inputRadius" value="10"/>
</configuration>
</ciFilter>
</backgroundFilters>
</view>
<connections>
<outlet property="delegate" destination="-2" id="39"/>
</connections>
</window>
<collectionViewItem id="QBZ-sO-HQn" customClass="MPElementCollectionView">
<connections>
<outlet property="view" destination="bhu-Ky-PQq" id="jZh-jC-6bL"/>
</connections>
</collectionViewItem>
<arrayController objectClassName="MPElementModel" id="jTN-Q9-Ajn">
<connections>
<binding destination="-2" name="contentArray" keyPath="self.elements" id="8Uz-14-YG0"/>
</connections>
</arrayController>
<box autoresizesSubviews="NO" wantsLayer="YES" boxType="custom" borderType="none" titlePosition="noTitle" id="bhu-Ky-PQq">
<rect key="frame" x="0.0" y="0.0" width="960" height="61"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<view key="contentView">
<rect key="frame" x="0.0" y="0.0" width="960" height="61"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="xwJ-Pu-glP">
<rect key="frame" x="6" y="35" width="60" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<shadow key="shadow" blurRadius="1">
<size key="offset" width="0.0" height="1"/>
<color key="color" white="0.0" alpha="0.59999999999999998" colorSpace="calibratedWhite"/>
</shadow>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="apple.com" usesSingleLineMode="YES" id="ymH-M0-M5d">
<font key="font" size="12" name="Exo2.0-Light"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="QBZ-sO-HQn" name="value" keyPath="representedObject.site" id="4as-ow-WbD"/>
</connections>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Cn5-nt-e6X">
<rect key="frame" x="362" y="35" width="111" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<shadow key="shadow" blurRadius="1">
<size key="offset" width="0.0" height="1"/>
<color key="color" white="0.0" alpha="0.59999999999999998" colorSpace="calibratedWhite"/>
</shadow>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="lhunath@lyndir.com" usesSingleLineMode="YES" id="Px4-pS-kwG">
<font key="font" size="12" name="Exo2.0-Light"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="QBZ-sO-HQn" name="value" keyPath="representedObject.loginName" id="C2s-1d-p2H">
<dictionary key="options">
<bool key="NSContinuouslyUpdatesValue" value="YES"/>
</dictionary>
</binding>
</connections>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="a1n-Sf-Mw6">
<rect key="frame" x="6" y="8" width="206" height="38"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<shadow key="shadow" blurRadius="1">
<size key="offset" width="0.0" height="1"/>
<color key="color" white="0.0" alpha="0.59999999999999998" colorSpace="calibratedWhite"/>
</shadow>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="RutuTutnTeni4," id="7jb-Fa-xX3">
<font key="font" size="24" name="SourceCodePro-Light"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="QBZ-sO-HQn" name="value" keyPath="representedObject.content" id="41c-PF-OeH">
<dictionary key="options">
<bool key="NSContinuouslyUpdatesValue" value="YES"/>
</dictionary>
</binding>
</connections>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mp4-r1-7Xg">
<rect key="frame" x="440" y="8" width="33" height="38"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<shadow key="shadow" blurRadius="1">
<size key="offset" width="0.0" height="1"/>
<color key="color" white="0.0" alpha="0.59999999999999998" colorSpace="calibratedWhite"/>
</shadow>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="12" id="Vb9-nO-cWY">
<font key="font" size="24" name="SourceCodePro-Light"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="QBZ-sO-HQn" name="value" keyPath="representedObject.uses" id="gSt-Nd-lVa">
<dictionary key="options">
<bool key="NSContinuouslyUpdatesValue" value="YES"/>
</dictionary>
</binding>
</connections>
</textField>
<box autoresizesSubviews="NO" horizontalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="tsT-Xh-Nxb">
<rect key="frame" x="477" y="0.0" width="5" height="61"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<font key="titleFont" metaFont="system"/>
</box>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="vEl-aL-Qd4">
<rect key="frame" x="791" y="27" width="167" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="lhunath@lyndir.com" bezelStyle="rounded" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="sl3-bH-Hh2">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="updateLoginName:" target="QBZ-sO-HQn" id="pJI-k8-LRl"/>
<binding destination="QBZ-sO-HQn" name="title" keyPath="representedObject.loginName" id="uaP-Y1-bz6">
<dictionary key="options">
<string key="NSNullPlaceholder">Click to set login name</string>
</dictionary>
</binding>
</connections>
</button>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="d2a-pG-7CW">
<rect key="frame" x="528" y="31" width="127" height="26"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" title="Long Password" bezelStyle="rounded" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" selectedItem="7Bj-S7-WSd" id="RZo-c7-kqA">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" title="OtherViews" id="mQN-XZ-YKz">
<items>
<menuItem title="Long Password" state="on" id="7Bj-S7-WSd"/>
<menuItem title="Item 2" id="WUd-69-IBV"/>
<menuItem title="Item 3" id="pgH-yZ-G0J"/>
</items>
</menu>
</popUpButtonCell>
<connections>
<binding destination="QBZ-sO-HQn" name="contentValues" keyPath="representedObject.typeNames" id="eyo-f9-MwY"/>
<binding destination="QBZ-sO-HQn" name="selectedIndex" keyPath="representedObject.typeIndex" previousBinding="eyo-f9-MwY" id="dpI-HX-GpX"/>
</connections>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="npg-mh-AfY">
<rect key="frame" x="486" y="36" width="38" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Type:" id="U2E-DE-2j4">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="hqw-ZP-4c1">
<rect key="frame" x="486" y="11" width="59" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Number:" id="CDU-Ah-QDj">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="QBZ-sO-HQn" name="hidden" keyPath="counterHidden" id="xlz-gk-Gwc"/>
</connections>
</textField>
<stepper horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="JPX-xQ-VKZ">
<rect key="frame" x="565" y="6" width="19" height="27"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<stepperCell key="cell" alignment="left" minValue="1" maxValue="100" doubleValue="1" autorepeat="NO" id="ELG-fy-nVF"/>
<connections>
<binding destination="QBZ-sO-HQn" name="hidden" keyPath="counterHidden" id="3FO-ks-R7U"/>
<binding destination="QBZ-sO-HQn" name="value" keyPath="representedObject.counter" id="awJ-Vg-RUn"/>
</connections>
</stepper>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="kZI-sG-dEn">
<rect key="frame" x="549" y="11" width="13" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="1" id="EUB-gJ-7Db">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="QBZ-sO-HQn" name="hidden" keyPath="counterHidden" id="ZFX-79-eAY"/>
<binding destination="QBZ-sO-HQn" name="value" keyPath="representedObject.counter" id="20y-tn-B5k"/>
</connections>
</textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="qOt-Rp-G9T">
<rect key="frame" x="877" y="2" width="81" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Delete" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="QCU-VC-W0u">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="delete:" target="QBZ-sO-HQn" id="mLJ-JY-5fz"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="5YU-4W-4gz">
<rect key="frame" x="727" y="2" width="150" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Change Password" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="NQY-Oo-Eid">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="updateContent:" target="QBZ-sO-HQn" id="J8f-vx-10A"/>
<binding destination="QBZ-sO-HQn" name="hidden" keyPath="updateContentHidden" id="UwG-p5-kH4"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="bzg-90-kmh">
<rect key="frame" x="748" y="36" width="43" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Login:" id="uxE-6c-RjC">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
</view>
<constraints>
<constraint firstItem="hqw-ZP-4c1" firstAttribute="centerY" secondItem="qOt-Rp-G9T" secondAttribute="centerY" id="6xp-tI-BkX"/>
<constraint firstItem="npg-mh-AfY" firstAttribute="leading" secondItem="tsT-Xh-Nxb" secondAttribute="trailing" constant="8" id="7kp-OB-3BI"/>
<constraint firstItem="kZI-sG-dEn" firstAttribute="leading" secondItem="hqw-ZP-4c1" secondAttribute="trailing" constant="8" symbolic="YES" id="8qK-Et-c1F"/>
<constraint firstItem="d2a-pG-7CW" firstAttribute="leading" secondItem="npg-mh-AfY" secondAttribute="trailing" constant="8" symbolic="YES" id="F6X-FD-kEX"/>
<constraint firstItem="Cn5-nt-e6X" firstAttribute="top" secondItem="bhu-Ky-PQq" secondAttribute="top" constant="8" id="FWS-tY-KkM"/>
<constraint firstItem="hqw-ZP-4c1" firstAttribute="top" secondItem="npg-mh-AfY" secondAttribute="bottom" constant="8" symbolic="YES" id="GuG-5I-quA"/>
<constraint firstItem="hqw-ZP-4c1" firstAttribute="leading" secondItem="tsT-Xh-Nxb" secondAttribute="trailing" constant="8" id="Hzf-XZ-auZ"/>
<constraint firstItem="tsT-Xh-Nxb" firstAttribute="leading" secondItem="Cn5-nt-e6X" secondAttribute="trailing" constant="8" id="LjD-10-tVU"/>
<constraint firstItem="tsT-Xh-Nxb" firstAttribute="top" secondItem="bhu-Ky-PQq" secondAttribute="top" id="ODH-Nx-QdY"/>
<constraint firstItem="qOt-Rp-G9T" firstAttribute="centerY" secondItem="5YU-4W-4gz" secondAttribute="centerY" id="PdB-X5-eqF"/>
<constraint firstItem="xwJ-Pu-glP" firstAttribute="leading" secondItem="bhu-Ky-PQq" secondAttribute="leading" constant="8" id="QAM-jm-t0y"/>
<constraint firstAttribute="centerY" secondItem="tsT-Xh-Nxb" secondAttribute="centerY" id="Rpi-lc-dZ1"/>
<constraint firstItem="tsT-Xh-Nxb" firstAttribute="leading" secondItem="mp4-r1-7Xg" secondAttribute="trailing" constant="8" id="Xfc-Jq-2Rb"/>
<constraint firstAttribute="trailing" secondItem="vEl-aL-Qd4" secondAttribute="trailing" constant="8" id="ZZu-AS-C07"/>
<constraint firstAttribute="bottom" secondItem="tsT-Xh-Nxb" secondAttribute="bottom" id="ds1-7i-B7I"/>
<constraint firstItem="a1n-Sf-Mw6" firstAttribute="leading" secondItem="bhu-Ky-PQq" secondAttribute="leading" constant="8" id="e3g-2s-yee"/>
<constraint firstItem="npg-mh-AfY" firstAttribute="centerY" secondItem="vEl-aL-Qd4" secondAttribute="centerY" id="ftr-2Z-9J0"/>
<constraint firstItem="npg-mh-AfY" firstAttribute="centerY" secondItem="d2a-pG-7CW" secondAttribute="centerY" id="g9a-r0-EOo"/>
<constraint firstAttribute="bottom" secondItem="mp4-r1-7Xg" secondAttribute="bottom" constant="8" id="jCW-5H-6pT"/>
<constraint firstAttribute="centerX" secondItem="tsT-Xh-Nxb" secondAttribute="centerX" id="kx6-g0-jUW"/>
<constraint firstAttribute="bottom" secondItem="a1n-Sf-Mw6" secondAttribute="bottom" constant="8" id="mWW-rt-kl2"/>
<constraint firstItem="npg-mh-AfY" firstAttribute="top" secondItem="bhu-Ky-PQq" secondAttribute="top" constant="8" id="n7Z-EF-Dcm"/>
<constraint firstItem="qOt-Rp-G9T" firstAttribute="leading" secondItem="5YU-4W-4gz" secondAttribute="trailing" constant="12" symbolic="YES" id="uWm-hE-itO"/>
<constraint firstAttribute="trailing" secondItem="qOt-Rp-G9T" secondAttribute="trailing" constant="8" id="x6J-1l-rU4"/>
<constraint firstItem="hqw-ZP-4c1" firstAttribute="centerY" secondItem="kZI-sG-dEn" secondAttribute="centerY" id="xZ7-Mc-9dq"/>
<constraint firstItem="vEl-aL-Qd4" firstAttribute="leading" secondItem="bzg-90-kmh" secondAttribute="trailing" constant="8" symbolic="YES" id="z7h-om-WAV"/>
<constraint firstItem="xwJ-Pu-glP" firstAttribute="top" secondItem="bhu-Ky-PQq" secondAttribute="top" constant="8" id="z8k-ot-NjU"/>
<constraint firstItem="bzg-90-kmh" firstAttribute="centerY" secondItem="vEl-aL-Qd4" secondAttribute="centerY" id="zbz-Qg-uHO"/>
<constraint firstItem="JPX-xQ-VKZ" firstAttribute="centerY" secondItem="kZI-sG-dEn" secondAttribute="centerY" id="zcO-M3-gyr"/>
<constraint firstItem="JPX-xQ-VKZ" firstAttribute="leading" secondItem="kZI-sG-dEn" secondAttribute="trailing" constant="8" symbolic="YES" id="zvB-Vk-IL2"/>
</constraints>
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
<color key="fillColor" name="selectedControlColor" catalog="System" colorSpace="catalog"/>
<connections>
<binding destination="QBZ-sO-HQn" name="transparent" keyPath="selected" id="Tpz-Rp-lA7">
<dictionary key="options">
<string key="NSValueTransformerName">NSNegateBoolean</string>
</dictionary>
</binding>
</connections>
</box>
</objects>
<resources>
<image name="small-screen" width="25" height="15.5"/>
</resources>
</document>

View File

@ -7,12 +7,14 @@
objects = {
/* Begin PBXBuildFile section */
93D390C676DF52DA7E459F19 /* MPPasswordWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39D9D0061FF1159998F06 /* MPPasswordWindow.m */; };
93D392EC39DA43C46C692C12 /* NSDictionary+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */; };
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */; };
93D39C34FE35830EF5BE1D2A /* NSArray+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D396D04E57792A54D437AC /* NSArray+Indexing.h */; };
93D39C5789EFA607CF788082 /* MPElementModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39E73BF5CBF8E5B005CD3 /* MPElementModel.m */; };
93D39C7C2BE7C0E0763B0177 /* MPElementCollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D394495528B10D1B61A2C3 /* MPElementCollectionView.m */; };
93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */; };
93D39F833DEC1C89B2F795AC /* MPPasswordWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A57A7823DE98A0FF83C /* MPPasswordWindowController.m */; };
DA0933CC1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0933CB1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png */; };
DA0933D01747B91B00DE1CEF /* appstore.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0933CF1747B91B00DE1CEF /* appstore.png */; };
DA16B33F170661D4000A0EAB /* libUbiquityStoreManager.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */; };
@ -21,6 +23,10 @@
DA16B344170661EE000A0EAB /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA16B343170661EE000A0EAB /* Cocoa.framework */; };
DA16B345170661F2000A0EAB /* libPearl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC77CAD148291A600BCF976 /* libPearl.a */; };
DA1E4D50176E0E280065E0EF /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA1E4D4F176E0E280065E0EF /* Media.xcassets */; };
DA2508F119511D3600AC23F1 /* MPPasswordWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA2508F019511D3600AC23F1 /* MPPasswordWindowController.xib */; };
DA2508F719513C1400AC23F1 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA16B343170661EE000A0EAB /* Cocoa.framework */; };
DA250924195148B300AC23F1 /* libRMBlurredView.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2508F619513C1400AC23F1 /* libRMBlurredView.a */; };
DA250925195148E200AC23F1 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAEBC45214F6364500987BF6 /* QuartzCore.framework */; };
DA2CA4ED18D323D3007798F8 /* NSError+PearlFullDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4E718D323D3007798F8 /* NSError+PearlFullDescription.m */; };
DA2CA4EE18D323D3007798F8 /* NSError+PearlFullDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4E818D323D3007798F8 /* NSError+PearlFullDescription.h */; };
DA2CA4EF18D323D3007798F8 /* NSArray+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4E918D323D3007798F8 /* NSArray+Pearl.m */; };
@ -57,8 +63,8 @@
DA5E5D021724A667003798D8 /* MPUserEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CB11724A667003798D8 /* MPUserEntity.m */; };
DA5E5D031724A667003798D8 /* MPMacAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CB41724A667003798D8 /* MPMacAppDelegate.m */; };
DA5E5D041724A667003798D8 /* MPMacConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CB61724A667003798D8 /* MPMacConfig.m */; };
DA5E5D051724A667003798D8 /* MPPasswordWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CB81724A667003798D8 /* MPPasswordWindowController.m */; };
DA5E5D061724A667003798D8 /* MPPasswordWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA5E5CB91724A667003798D8 /* MPPasswordWindowController.xib */; };
DA5E5D051724A667003798D8 /* MPPasswordDialogController.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5CB81724A667003798D8 /* MPPasswordDialogController.m */; };
DA5E5D061724A667003798D8 /* MPPasswordDialogController.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA5E5CB91724A667003798D8 /* MPPasswordDialogController.xib */; };
DA5E5D081724A667003798D8 /* MasterPassword.entitlements in Resources */ = {isa = PBXBuildFile; fileRef = DA5E5CBF1724A667003798D8 /* MasterPassword.entitlements */; };
DA5E5D091724A667003798D8 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = DA5E5CC01724A667003798D8 /* Credits.rtf */; };
DA5E5D0A1724A667003798D8 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = DA5E5CC21724A667003798D8 /* InfoPlist.strings */; };
@ -300,11 +306,15 @@
/* Begin PBXFileReference section */
93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Indexing.m"; sourceTree = "<group>"; };
93D39240B5143E01F0B75E96 /* MPElementModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementModel.h; sourceTree = "<group>"; };
93D392C3918763B3B72CF366 /* MPPasswordWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordWindowController.h; sourceTree = "<group>"; };
93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Indexing.h"; sourceTree = "<group>"; };
93D394495528B10D1B61A2C3 /* MPElementCollectionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementCollectionView.m; sourceTree = "<group>"; };
93D3960D320FF8A072B092E3 /* MPElementCollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementCollectionView.h; sourceTree = "<group>"; };
93D396D04E57792A54D437AC /* NSArray+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Indexing.h"; sourceTree = "<group>"; };
93D3977484534E99F9BA579D /* MPPasswordWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordWindow.h; sourceTree = "<group>"; };
93D39A57A7823DE98A0FF83C /* MPPasswordWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordWindowController.m; sourceTree = "<group>"; };
93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+Indexing.m"; sourceTree = "<group>"; };
93D39D9D0061FF1159998F06 /* MPPasswordWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordWindow.m; sourceTree = "<group>"; };
93D39E73BF5CBF8E5B005CD3 /* MPElementModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementModel.m; sourceTree = "<group>"; };
DA0933C91747A56A00DE1CEF /* MPInitialWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MPInitialWindow.xib; sourceTree = "<group>"; };
DA0933CB1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "shot-laptop-leaning-iphone.png"; sourceTree = "<group>"; };
@ -312,6 +322,14 @@
DA16B340170661DB000A0EAB /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
DA16B343170661EE000A0EAB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
DA1E4D4F176E0E280065E0EF /* Media.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Media.xcassets; path = MasterPassword/Media.xcassets; sourceTree = "<group>"; };
DA2508F019511D3600AC23F1 /* MPPasswordWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MPPasswordWindowController.xib; sourceTree = "<group>"; };
DA2508F619513C1400AC23F1 /* libRMBlurredView.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRMBlurredView.a; sourceTree = BUILT_PRODUCTS_DIR; };
DA2508F919513C1400AC23F1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
DA2508FA19513C1400AC23F1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
DA2508FB19513C1400AC23F1 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
DA25090719513C1400AC23F1 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
DA2509261951B86C00AC23F1 /* small-screen.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "small-screen.png"; sourceTree = "<group>"; };
DA2509271951B86C00AC23F1 /* screen.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = screen.png; sourceTree = "<group>"; };
DA2CA4E718D323D3007798F8 /* NSError+PearlFullDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+PearlFullDescription.m"; sourceTree = "<group>"; };
DA2CA4E818D323D3007798F8 /* NSError+PearlFullDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+PearlFullDescription.h"; sourceTree = "<group>"; };
DA2CA4E918D323D3007798F8 /* NSArray+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Pearl.m"; sourceTree = "<group>"; };
@ -369,9 +387,9 @@
DA5E5CB41724A667003798D8 /* MPMacAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPMacAppDelegate.m; sourceTree = "<group>"; };
DA5E5CB51724A667003798D8 /* MPMacConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPMacConfig.h; sourceTree = "<group>"; };
DA5E5CB61724A667003798D8 /* MPMacConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPMacConfig.m; sourceTree = "<group>"; };
DA5E5CB71724A667003798D8 /* MPPasswordWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordWindowController.h; sourceTree = "<group>"; };
DA5E5CB81724A667003798D8 /* MPPasswordWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordWindowController.m; sourceTree = "<group>"; };
DA5E5CB91724A667003798D8 /* MPPasswordWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MPPasswordWindowController.xib; sourceTree = "<group>"; };
DA5E5CB71724A667003798D8 /* MPPasswordDialogController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasswordDialogController.h; sourceTree = "<group>"; };
DA5E5CB81724A667003798D8 /* MPPasswordDialogController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordDialogController.m; sourceTree = "<group>"; };
DA5E5CB91724A667003798D8 /* MPPasswordDialogController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MPPasswordDialogController.xib; sourceTree = "<group>"; };
DA5E5CBA1724A667003798D8 /* MasterPassword-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "MasterPassword-Info.plist"; sourceTree = "<group>"; };
DA5E5CBE1724A667003798D8 /* MasterPassword-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MasterPassword-Prefix.pch"; sourceTree = "<group>"; };
DA5E5CBF1724A667003798D8 /* MasterPassword.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = MasterPassword.entitlements; sourceTree = "<group>"; };
@ -587,6 +605,14 @@
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
DA2508F319513C1400AC23F1 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
DA2508F719513C1400AC23F1 /* Cocoa.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DA4425C81557BED40052177D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@ -599,6 +625,8 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
DA250925195148E200AC23F1 /* QuartzCore.framework in Frameworks */,
DA250924195148B300AC23F1 /* libRMBlurredView.a in Frameworks */,
DAD9B5F01762CAA4001835F9 /* ServiceManagement.framework in Frameworks */,
DABC6C16175D8E3A000C15D4 /* libRHStatusItemView.a in Frameworks */,
DA16B33F170661D4000A0EAB /* libUbiquityStoreManager.a in Frameworks */,
@ -639,6 +667,16 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
DA2508F819513C1400AC23F1 /* Other Frameworks */ = {
isa = PBXGroup;
children = (
DA2508F919513C1400AC23F1 /* Foundation.framework */,
DA2508FA19513C1400AC23F1 /* CoreData.framework */,
DA2508FB19513C1400AC23F1 /* AppKit.framework */,
);
name = "Other Frameworks";
sourceTree = "<group>";
};
DA3B8447190FC5A900246EEA /* iOS */ = {
isa = PBXGroup;
children = (
@ -675,6 +713,7 @@
DAC6326C148680650075AEA5 /* libjrswizzle.a */,
DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */,
DABC6C01175D8C85000C15D4 /* libRHStatusItemView.a */,
DA2508F619513C1400AC23F1 /* libRMBlurredView.a */,
);
name = Products;
sourceTree = "<group>";
@ -695,6 +734,8 @@
DA5BFA4A147E415C00F98B1E /* Foundation.framework */,
DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */,
DA5BFA4E147E415C00F98B1E /* CoreData.framework */,
DA25090719513C1400AC23F1 /* XCTest.framework */,
DA2508F819513C1400AC23F1 /* Other Frameworks */,
);
name = Frameworks;
sourceTree = "<group>";
@ -755,9 +796,9 @@
DA5E5CB41724A667003798D8 /* MPMacAppDelegate.m */,
DA5E5CB51724A667003798D8 /* MPMacConfig.h */,
DA5E5CB61724A667003798D8 /* MPMacConfig.m */,
DA5E5CB71724A667003798D8 /* MPPasswordWindowController.h */,
DA5E5CB81724A667003798D8 /* MPPasswordWindowController.m */,
DA5E5CB91724A667003798D8 /* MPPasswordWindowController.xib */,
DA5E5CB71724A667003798D8 /* MPPasswordDialogController.h */,
DA5E5CB81724A667003798D8 /* MPPasswordDialogController.m */,
DA5E5CB91724A667003798D8 /* MPPasswordDialogController.xib */,
DA5E5CBA1724A667003798D8 /* MasterPassword-Info.plist */,
DA5E5CBE1724A667003798D8 /* MasterPassword-Prefix.pch */,
DA5E5CBF1724A667003798D8 /* MasterPassword.entitlements */,
@ -770,6 +811,11 @@
93D3960D320FF8A072B092E3 /* MPElementCollectionView.h */,
93D39E73BF5CBF8E5B005CD3 /* MPElementModel.m */,
93D39240B5143E01F0B75E96 /* MPElementModel.h */,
DA2508F019511D3600AC23F1 /* MPPasswordWindowController.xib */,
93D39A57A7823DE98A0FF83C /* MPPasswordWindowController.m */,
93D392C3918763B3B72CF366 /* MPPasswordWindowController.h */,
93D39D9D0061FF1159998F06 /* MPPasswordWindow.m */,
93D3977484534E99F9BA579D /* MPPasswordWindow.h */,
);
path = Mac;
sourceTree = "<group>";
@ -842,6 +888,8 @@
DACA23B51705DF7D002C6C22 /* Media */ = {
isa = PBXGroup;
children = (
DA2509261951B86C00AC23F1 /* small-screen.png */,
DA2509271951B86C00AC23F1 /* screen.png */,
DA0933CF1747B91B00DE1CEF /* appstore.png */,
DA0933CB1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png */,
DA5E5D541724F9C8003798D8 /* MasterPassword.iconset */,
@ -1153,6 +1201,13 @@
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
DA2508F419513C1400AC23F1 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
DA4425C91557BED40052177D /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
@ -1294,6 +1349,23 @@
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
DA2508F519513C1400AC23F1 /* RMBlurredView */ = {
isa = PBXNativeTarget;
buildConfigurationList = DA25091519513C1500AC23F1 /* Build configuration list for PBXNativeTarget "RMBlurredView" */;
buildPhases = (
DA2508F219513C1400AC23F1 /* Sources */,
DA2508F319513C1400AC23F1 /* Frameworks */,
DA2508F419513C1400AC23F1 /* Headers */,
);
buildRules = (
);
dependencies = (
);
name = RMBlurredView;
productName = RMBlurredView;
productReference = DA2508F619513C1400AC23F1 /* libRMBlurredView.a */;
productType = "com.apple.product-type.library.static";
};
DA4425CA1557BED40052177D /* UbiquityStoreManager */ = {
isa = PBXNativeTarget;
buildConfigurationList = DA4425D31557BED40052177D /* Build configuration list for PBXNativeTarget "UbiquityStoreManager" */;
@ -1424,6 +1496,7 @@
DAC6326B148680650075AEA5 /* jrswizzle */,
DA4425CA1557BED40052177D /* UbiquityStoreManager */,
DABC6C00175D8C85000C15D4 /* RHStatusItemView */,
DA2508F519513C1400AC23F1 /* RMBlurredView */,
);
};
/* End PBXProject section */
@ -1457,6 +1530,7 @@
DAF4EF59190A828100023C90 /* Exo2.0-Bold.otf in Resources */,
DACA27181705DF81002C6C22 /* avatar-9.png in Resources */,
DACA27191705DF81002C6C22 /* avatar-1@2x.png in Resources */,
DA2508F119511D3600AC23F1 /* MPPasswordWindowController.xib in Resources */,
DACA271A1705DF81002C6C22 /* avatar-11@2x.png in Resources */,
DACA271B1705DF81002C6C22 /* avatar-7@2x.png in Resources */,
DACA271C1705DF81002C6C22 /* avatar-17@2x.png in Resources */,
@ -1497,7 +1571,7 @@
DACA296F1705DF81002C6C22 /* Crashlytics.plist in Resources */,
DACA29731705E1A8002C6C22 /* ciphers.plist in Resources */,
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */,
DA5E5D061724A667003798D8 /* MPPasswordWindowController.xib in Resources */,
DA5E5D061724A667003798D8 /* MPPasswordDialogController.xib in Resources */,
DA5E5D081724A667003798D8 /* MasterPassword.entitlements in Resources */,
DA5E5D091724A667003798D8 /* Credits.rtf in Resources */,
DA5E5D0A1724A667003798D8 /* InfoPlist.strings in Resources */,
@ -1544,6 +1618,13 @@
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
DA2508F219513C1400AC23F1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
DA4425C71557BED40052177D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@ -1573,11 +1654,13 @@
DA5E5D021724A667003798D8 /* MPUserEntity.m in Sources */,
DA5E5D031724A667003798D8 /* MPMacAppDelegate.m in Sources */,
DA5E5D041724A667003798D8 /* MPMacConfig.m in Sources */,
DA5E5D051724A667003798D8 /* MPPasswordWindowController.m in Sources */,
DA5E5D051724A667003798D8 /* MPPasswordDialogController.m in Sources */,
DA5E5D0C1724A667003798D8 /* main.m in Sources */,
DA5E5D0D1724A667003798D8 /* MasterPassword.xcdatamodeld in Sources */,
93D39C7C2BE7C0E0763B0177 /* MPElementCollectionView.m in Sources */,
93D39C5789EFA607CF788082 /* MPElementModel.m in Sources */,
93D39F833DEC1C89B2F795AC /* MPPasswordWindowController.m in Sources */,
93D390C676DF52DA7E459F19 /* MPPasswordWindow.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1686,6 +1769,27 @@
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
DA25091619513C1500AC23F1 /* Debug-Mac */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_ARC = YES;
};
name = "Debug-Mac";
};
DA25091719513C1500AC23F1 /* AdHoc-Mac */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_ARC = YES;
};
name = "AdHoc-Mac";
};
DA25091819513C1500AC23F1 /* AppStore-Mac */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_ARC = YES;
};
name = "AppStore-Mac";
};
DA4425D41557BED40052177D /* Debug-Mac */ = {
isa = XCBuildConfiguration;
buildSettings = {
@ -2108,6 +2212,16 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
DA25091519513C1500AC23F1 /* Build configuration list for PBXNativeTarget "RMBlurredView" */ = {
isa = XCConfigurationList;
buildConfigurations = (
DA25091619513C1500AC23F1 /* Debug-Mac */,
DA25091719513C1500AC23F1 /* AdHoc-Mac */,
DA25091819513C1500AC23F1 /* AppStore-Mac */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = "AdHoc-Mac";
};
DA4425D31557BED40052177D /* Build configuration list for PBXNativeTarget "UbiquityStoreManager" */ = {
isa = XCConfigurationList;
buildConfigurations = (