Added duplicate entry with options

This commit is contained in:
michael starke
2017-06-08 15:40:08 +02:00
parent 6771d68454
commit 8dd465866e
10 changed files with 172 additions and 42 deletions

View File

@@ -1,26 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="12121" systemVersion="16F73" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="12121"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner"/>
<customObject id="-2" userLabel="File's Owner" customClass="MPDuplicateEntryOptionsWindowController">
<connections>
<outlet property="duplicateHistoryCheckButton" destination="DG4-bd-Jhl" id="jU7-PF-AQy"/>
<outlet property="referencePasswordCheckButton" destination="YDe-Wa-lXV" id="I7r-ry-zTz"/>
<outlet property="referenceUsernameCheckButton" destination="KYV-1i-31e" id="mwD-m5-tiZ"/>
<outlet property="window" destination="QvC-M9-y7g" id="LQj-Pb-B9y"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="QvC-M9-y7g">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="364" height="115"/>
<rect key="contentRect" x="196" y="240" width="161" height="135"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
<view key="contentView" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="364" height="115"/>
<rect key="frame" x="0.0" y="0.0" width="310" height="135"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<button translatesAutoresizingMaskIntoConstraints="NO" id="KYV-1i-31e">
<rect key="frame" x="18" y="79" width="312" height="18"/>
<buttonCell key="cell" type="check" title="Replace password and username with refernces" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="O9X-XH-n8o">
<button verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="KYV-1i-31e">
<rect key="frame" x="18" y="99" width="274" height="18"/>
<buttonCell key="cell" type="check" title="Reference username instead of copying it" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="O9X-XH-n8o">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="TFC-xG-RlB">
<rect key="frame" x="163" y="13" width="133" height="32"/>
<buttonCell key="cell" type="push" title="Duplicate Entry" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="WqI-qH-ARf">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="duplicateEntry:" target="-2" id="e6Z-Kp-sfb"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="0j0-db-9Wu">
<rect key="frame" x="81" y="13" width="82" height="32"/>
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="x6e-bE-Y6R">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
Gw
</string>
</buttonCell>
<connections>
<action selector="cancel:" target="-2" id="g8K-Ga-tWv"/>
</connections>
</button>
<button translatesAutoresizingMaskIntoConstraints="NO" id="YDe-Wa-lXV">
<rect key="frame" x="18" y="79" width="272" height="18"/>
<buttonCell key="cell" type="check" title="Reference password instead of copying it" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="daA-QV-CDq">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
@@ -32,39 +68,25 @@
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="TFC-xG-RlB">
<rect key="frame" x="217" y="13" width="133" height="32"/>
<buttonCell key="cell" type="push" title="Duplicate Entry" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="WqI-qH-ARf">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="0j0-db-9Wu">
<rect key="frame" x="135" y="13" width="82" height="32"/>
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="x6e-bE-Y6R">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
Gw
</string>
</buttonCell>
</button>
</subviews>
<constraints>
<constraint firstItem="DG4-bd-Jhl" firstAttribute="top" secondItem="YDe-Wa-lXV" secondAttribute="bottom" constant="6" symbolic="YES" id="1hs-wf-aEe"/>
<constraint firstItem="KYV-1i-31e" firstAttribute="leading" secondItem="EiT-Mj-1SZ" secondAttribute="leading" constant="20" id="2MP-Nd-nEI"/>
<constraint firstAttribute="bottom" secondItem="TFC-xG-RlB" secondAttribute="bottom" constant="20" symbolic="YES" id="7dL-yz-Jec"/>
<constraint firstAttribute="trailing" secondItem="TFC-xG-RlB" secondAttribute="trailing" constant="20" symbolic="YES" id="Bp5-7H-WQn"/>
<constraint firstItem="TFC-xG-RlB" firstAttribute="leading" secondItem="0j0-db-9Wu" secondAttribute="trailing" constant="12" id="Mo1-NA-twC"/>
<constraint firstItem="YDe-Wa-lXV" firstAttribute="leading" secondItem="KYV-1i-31e" secondAttribute="leading" id="NqU-4e-nL1"/>
<constraint firstItem="TFC-xG-RlB" firstAttribute="centerY" secondItem="0j0-db-9Wu" secondAttribute="centerY" id="OI2-vr-Dxa"/>
<constraint firstItem="DG4-bd-Jhl" firstAttribute="top" secondItem="KYV-1i-31e" secondAttribute="bottom" constant="6" id="Qsu-7N-dnm"/>
<constraint firstItem="KYV-1i-31e" firstAttribute="leading" secondItem="DG4-bd-Jhl" secondAttribute="leading" id="TpN-gj-FoI"/>
<constraint firstItem="TFC-xG-RlB" firstAttribute="top" secondItem="DG4-bd-Jhl" secondAttribute="bottom" constant="20" symbolic="YES" id="dbV-TU-M0Z"/>
<constraint firstItem="TFC-xG-RlB" firstAttribute="top" relation="greaterThanOrEqual" secondItem="DG4-bd-Jhl" secondAttribute="bottom" constant="20" symbolic="YES" id="dbV-TU-M0Z"/>
<constraint firstItem="YDe-Wa-lXV" firstAttribute="top" secondItem="KYV-1i-31e" secondAttribute="bottom" constant="6" symbolic="YES" id="lS4-f0-hSy"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="YDe-Wa-lXV" secondAttribute="trailing" constant="20" symbolic="YES" id="sth-Lq-2Qj"/>
<constraint firstItem="KYV-1i-31e" firstAttribute="top" secondItem="EiT-Mj-1SZ" secondAttribute="top" constant="20" id="tvk-Ic-tmq"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="KYV-1i-31e" secondAttribute="trailing" constant="20" symbolic="YES" id="xhH-o0-KHo"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="DG4-bd-Jhl" secondAttribute="trailing" constant="20" symbolic="YES" id="xnL-R7-g2p"/>
</constraints>
</view>
<point key="canvasLocation" x="79" y="236"/>
<point key="canvasLocation" x="-787" y="-72"/>
</window>
</objects>
</document>

View File

@@ -159,6 +159,7 @@ FOUNDATION_EXPORT NSString *const MPDocumentGroupKey;
- (KPKAttribute *)createCustomAttribute:(KPKEntry *)entry;
- (void)deleteNode:(KPKNode *)node;
- (void)duplicateEntryWithOptions:(KPKCopyOptions)options;
#pragma mark Actions
/**
@@ -172,11 +173,8 @@ FOUNDATION_EXPORT NSString *const MPDocumentGroupKey;
* @param sender sender, that should respond to representedObject and return an NSUUID for the template to use
*/
- (IBAction)createEntryFromTemplate:(id)sender;
- (IBAction)duplicateEntry:(id)sender;
- (IBAction)duplicateEntryWithOptions:(id)sender;
@end
@interface MPDocument (Attachments)

View File

@@ -699,18 +699,18 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGrou
}
- (void)duplicateEntry:(id)sender {
[self duplicateEntryWithOptions:kKPKCopyOptionNone];
}
- (void)duplicateEntryWithOptions:(KPKCopyOptions)options {
BOOL plural = self.selectedEntries.count > 1;
for(KPKEntry *entry in self.selectedEntries) {
KPKEntry *duplicate = [entry copyWithTitle:nil options:kKPKCopyOptionNone];
KPKEntry *duplicate = [entry copyWithTitle:nil options:options];
[duplicate addToGroup:entry.parent];
}
[self.undoManager setActionName:NSLocalizedString(@"DUPLICATE_ENTRY", "")];
[self.undoManager setActionName:plural ? NSLocalizedString(@"DUPLICATE_ENTRIES", "") : NSLocalizedString(@"DUPLICATE_ENTRY", "")];
}
- (void)duplicateEntryWithOptions:(id)sender {
}
#pragma mark Validation
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
return [self validateUserInterfaceItem:menuItem];

View File

@@ -51,6 +51,8 @@
- (IBAction)createEntry:(id)sender;
- (IBAction)delete:(id)sender;
- (IBAction)duplicateEntryWithOptions:(id)sender;
- (IBAction)pickExpiryDate:(id)sender;
- (IBAction)performAutotypeForEntry:(id)sender;

View File

@@ -15,6 +15,7 @@
#import "MPDatabaseSettingsWindowController.h"
#import "MPDocument.h"
#import "MPDocumentWindowDelegate.h"
#import "MPDuplicateEntryOptionsWindowController.h"
#import "MPEntryViewController.h"
#import "MPFixAutotypeWindowController.h"
#import "MPInspectorViewController.h"
@@ -397,6 +398,27 @@ typedef void (^MPPasswordChangedBlock)(BOOL didChangePassword);
[self.document deleteNode:node];
}
}
- (void)duplicateEntryWithOptions:(id)sender {
MPDuplicateEntryOptionsWindowController *wc = [[MPDuplicateEntryOptionsWindowController alloc] init];
__weak MPDocumentWindowController *welf = self;
[self.window beginSheet:wc.window completionHandler:^(NSModalResponse returnCode) {
if(returnCode == NSModalResponseOK) {
KPKCopyOptions options = kKPKCopyOptionNone;
if(wc.referenceUsername) {
options |= kKPKCopyOptionReferenceUsername;
}
if(wc.referencePassword) {
options |= kKPKCopyOptionReferencePassword;
}
if(wc.duplicateHistory) {
options |= kKPKCopyOptionCopyHistory;
}
[((MPDocument *)welf.document) duplicateEntryWithOptions:options];
}
}];
}
- (void)pickExpiryDate:(id)sender {
[self.inspectorViewController pickExpiryDate:sender];

View File

@@ -0,0 +1,17 @@
//
// MPDuplicateEntryOptionsWindowController.h
// MacPass
//
// Created by Michael Starke on 08.06.17.
// Copyright © 2017 HicknHack Software GmbH. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface MPDuplicateEntryOptionsWindowController : NSWindowController
@property (readonly) BOOL referencePassword;
@property (readonly) BOOL referenceUsername;
@property (readonly) BOOL duplicateHistory;
@end

View File

@@ -0,0 +1,63 @@
//
// MPDuplicateEntryOptionsWindowController.m
// MacPass
//
// Created by Michael Starke on 08.06.17.
// Copyright © 2017 HicknHack Software GmbH. All rights reserved.
//
#import "MPDuplicateEntryOptionsWindowController.h"
@interface MPDuplicateEntryOptionsWindowController ()
@property BOOL referencePassword;
@property BOOL referenceUsername;
@property BOOL duplicateHistory;
@property (weak) IBOutlet NSButton *referenceUsernameCheckButton;
@property (weak) IBOutlet NSButton *referencePasswordCheckButton;
@property (weak) IBOutlet NSButton *duplicateHistoryCheckButton;
@end
@implementation MPDuplicateEntryOptionsWindowController
- (instancetype)initWithWindow:(NSWindow *)window {
self = [super initWithWindow:window];
if(self) {
_referencePassword = NO;
_referenceUsername = NO;
_duplicateHistory = NO;
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)coder {
self = [super initWithCoder:coder];
if(self) {
_referencePassword = NO;
_referenceUsername = NO;
_duplicateHistory = NO;
}
return self;
}
- (NSString *)windowNibName {
return @"DuplicateEntryOptionsWindow";
}
- (void)windowDidLoad {
[super windowDidLoad];
[self.referencePasswordCheckButton bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(referencePassword)) options:nil];
[self.referenceUsernameCheckButton bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(referenceUsername)) options:nil];
[self.duplicateHistoryCheckButton bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(duplicateHistory)) options:nil];
}
- (IBAction)duplicateEntry:(id)sender {
[self.window.sheetParent endSheet:self.window returnCode:NSModalResponseOK];
}
- (IBAction)cancel:(id)sender {
[self.window.sheetParent endSheet:self.window returnCode:NSModalResponseCancel];
}
@end