diff --git a/MacPass.xcodeproj/project.pbxproj b/MacPass.xcodeproj/project.pbxproj index 10a6597b..acdfbe19 100644 --- a/MacPass.xcodeproj/project.pbxproj +++ b/MacPass.xcodeproj/project.pbxproj @@ -257,6 +257,7 @@ 4CC59C2721AF0893005E8D6B /* MPPathControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CC59C2621AF0893005E8D6B /* MPPathControl.m */; }; 4CC663E7216F7A7100E33965 /* MPPluginRepositoryBrowserViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CC663E5216F7A7100E33965 /* MPPluginRepositoryBrowserViewController.m */; }; 4CC6DB7A17D23719002C6091 /* KPKNode+IconImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CC6DB7917D23719002C6091 /* KPKNode+IconImage.m */; }; + 4CC91B6B27D7E7E6001E9517 /* MPInspectorEditorView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CC91B6A27D7E7E6001E9517 /* MPInspectorEditorView.m */; }; 4CCA8E9B18D91ED9001A6754 /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CCA8E9A18D91ED9001A6754 /* Quartz.framework */; }; 4CCCE8011D75CA48006AA951 /* MPArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCE8001D75CA48006AA951 /* MPArrayController.m */; }; 4CCEDE2A179F203B008402BE /* MPOutlineView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCEDE29179F203B008402BE /* MPOutlineView.m */; }; @@ -848,6 +849,8 @@ 4CC663E5216F7A7100E33965 /* MPPluginRepositoryBrowserViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPPluginRepositoryBrowserViewController.m; sourceTree = ""; }; 4CC6DB7817D23719002C6091 /* KPKNode+IconImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "KPKNode+IconImage.h"; sourceTree = ""; }; 4CC6DB7917D23719002C6091 /* KPKNode+IconImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "KPKNode+IconImage.m"; sourceTree = ""; }; + 4CC91B6927D7E7E6001E9517 /* MPInspectorEditorView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPInspectorEditorView.h; sourceTree = ""; }; + 4CC91B6A27D7E7E6001E9517 /* MPInspectorEditorView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPInspectorEditorView.m; sourceTree = ""; }; 4CCA7EEC1797866F00B0B55E /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/GeneralPreferences.strings; sourceTree = ""; }; 4CCA8E9A18D91ED9001A6754 /* Quartz.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quartz.framework; path = System/Library/Frameworks/Quartz.framework; sourceTree = SDKROOT; }; 4CCCE7FF1D75CA48006AA951 /* MPArrayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPArrayController.h; sourceTree = ""; }; @@ -1275,6 +1278,8 @@ 4CFC53BE16E94729007396BE /* MPShadowBox.m */, 4C4A100D176286FD00BBF2CA /* MPTableView.h */, 4C4A100E176286FD00BBF2CA /* MPTableView.m */, + 4CC91B6927D7E7E6001E9517 /* MPInspectorEditorView.h */, + 4CC91B6A27D7E7E6001E9517 /* MPInspectorEditorView.m */, ); name = Views; sourceTree = ""; @@ -2266,6 +2271,7 @@ 4CBA2ABA17074C07006D8139 /* MPSettingsHelper.m in Sources */, 4C77E37A15B84A240093A587 /* MPAppDelegate.m in Sources */, 3C0CDED821D28BF700B2A10B /* MPTouchBarButtonCreator.m in Sources */, + 4CC91B6B27D7E7E6001E9517 /* MPInspectorEditorView.m in Sources */, 4C37A84015B8B474005EF8EE /* MPOutlineDataSource.m in Sources */, 4CA0B2F915BCAF6700654E32 /* MPGeneralPreferencesController.m in Sources */, 4C8F0C791FD05A6A00BE157F /* NSString+MPPrettyPasswordDisplay.m in Sources */, diff --git a/MacPass/MPEntryAttributeViewController.h b/MacPass/MPEntryAttributeViewController.h index b6a407f2..b59714f2 100644 --- a/MacPass/MPEntryAttributeViewController.h +++ b/MacPass/MPEntryAttributeViewController.h @@ -23,9 +23,9 @@ NS_ASSUME_NONNULL_BEGIN @property (strong) IBOutlet HNHUISecureTextField *valueTextField; @property (strong) IBOutlet NSButton *toggleProtectedButton; @property (strong) IBOutlet NSButton *removeButton; +@property (strong) IBOutlet NSButton *actionButton; -- (void)updateValues; -- (void)updateEditing; +- (void)updateValuesAndEditing; @end diff --git a/MacPass/MPEntryAttributeViewController.m b/MacPass/MPEntryAttributeViewController.m index e5884075..0bd5b1e8 100644 --- a/MacPass/MPEntryAttributeViewController.m +++ b/MacPass/MPEntryAttributeViewController.m @@ -10,6 +10,7 @@ #import #import #import "MPPasteBoardController.h" +#import "MPInspectorEditorView.h" NSString *nameForDefaultKey(NSString *key) { static NSDictionary *mapping; @@ -51,6 +52,10 @@ NSString *nameForDefaultKey(NSString *key) { - (void)viewDidLoad { [super viewDidLoad]; + + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(_didEnterMouse:) name:MPInspectorEditorViewMouseEnteredNotification object:self.view]; + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(_didExitMouse:) name:MPInspectorEditorViewMouseExitedNotification object:self.view]; + NSString *placeHolder = NSLocalizedString(@"NONE", "Placeholder text for input fields if no entry or group is selected"); self.keyTextField.placeholderString = placeHolder; self.valueTextField.placeholderString = placeHolder; @@ -58,17 +63,11 @@ NSString *nameForDefaultKey(NSString *key) { self.toggleProtectedButton.action = @selector(toggleDisplay:); self.toggleProtectedButton.target = self.valueTextField; - [self updateValues]; - [self updateEditing]; + self.actionButton.action = @selector(_copyText:); + self.actionButton.target = self; + self.actionButton.hidden = YES; - __weak MPEntryAttributeViewController *welf = self; - self.valueTextField.buttonTitle = NSLocalizedString(@"COPY", "Button to copy the value of an Attribute"); - self.valueTextField.buttonActionBlock = ^void(NSTextField *tf) { - NSText *text = [welf.view.window fieldEditor:NO forObject:welf.valueTextField]; - if([text isKindOfClass:NSTextView.class]) { - [welf textField:welf.valueTextField textView:(NSTextView *)text performAction:@selector(copy:)]; - } - }; + [self updateValuesAndEditing]; } - (KPKAttribute *)representedAttribute { @@ -80,7 +79,7 @@ NSString *nameForDefaultKey(NSString *key) { - (void)setIsEditor:(BOOL)isEditor { _isEditor = isEditor; - [self updateEditing]; + [self updateValuesAndEditing]; } - (void)setRepresentedObject:(id)representedObject { @@ -101,8 +100,14 @@ NSString *nameForDefaultKey(NSString *key) { } _isDefaultAttribute = self.representedAttribute.isDefault; - [self updateEditing]; - [self updateValues]; + [self updateValuesAndEditing]; +} + +- (void)_copyText:(id)sender { + NSText *text = [self.view.window fieldEditor:NO forObject:self.valueTextField]; + if([text isKindOfClass:NSTextView.class]) { + [self textField:self.valueTextField textView:(NSTextView *)text performAction:@selector(copy:)]; + } } - (BOOL)textField:(NSTextField *)textField textView:(NSTextView *)textView performAction:(SEL)action { @@ -145,10 +150,11 @@ NSString *nameForDefaultKey(NSString *key) { } - (void)_didChangeAttribute:(NSNotification *)notification { - [self updateValues]; + [self updateValuesAndEditing]; } -- (void)updateValues { +- (void)updateValuesAndEditing { + /* values */ self.view.hidden = self.isEditor ? NO : self.representedAttribute.value.length == 0; NSString *localizedKey = nameForDefaultKey(self.representedAttribute.key); @@ -162,15 +168,14 @@ NSString *nameForDefaultKey(NSString *key) { self.valueTextField.stringValue = self.representedAttribute.value ? self.representedAttribute.value : @""; self.valueTextField.showPassword = !self.representedAttribute.protect; -} - -- (void)updateEditing { - self.view.hidden = self.isEditor ? NO : self.representedAttribute.value.length == 0; + + /* editor */ self.keyTextField.editable = !_isDefaultAttribute && self.isEditor; self.valueTextField.editable = self.isEditor; self.keyTextField.selectable = YES; self.valueTextField.selectable = YES; self.toggleProtectedButton.hidden = _isDefaultAttribute; + self.removeButton.hidden = !self.isEditor ? YES : _isDefaultAttribute; // set draws background first, since bezeld might have side effects @@ -179,6 +184,14 @@ NSString *nameForDefaultKey(NSString *key) { self.valueTextField.bezeled = self.isEditor; } +- (void)_didEnterMouse:(NSNotification *)notification { + self.actionButton.hidden = self.isEditor; +} + +- (void)_didExitMouse:(NSNotification *)notification { + self.actionButton.hidden = YES; +} + -(void)commitChanges { if(!self.isEditor) { // do not commit changes if we are no editor! diff --git a/MacPass/MPEntryAttributeViewController.xib b/MacPass/MPEntryAttributeViewController.xib index ad422b7c..ef87ef05 100644 --- a/MacPass/MPEntryAttributeViewController.xib +++ b/MacPass/MPEntryAttributeViewController.xib @@ -8,6 +8,7 @@ + @@ -17,7 +18,7 @@ - + @@ -32,11 +33,11 @@ - + - + @@ -47,29 +48,38 @@ + + + diff --git a/MacPass/MPEntryInspectorViewController.m b/MacPass/MPEntryInspectorViewController.m index 58f97f25..656ef64e 100644 --- a/MacPass/MPEntryInspectorViewController.m +++ b/MacPass/MPEntryInspectorViewController.m @@ -343,6 +343,7 @@ typedef NS_ENUM(NSUInteger, MPEntryTab) { self.passwordEditorViewController.isEditor = !self.passwordEditorViewController.isEditor; self.urlEditorViewController.isEditor = !self.urlEditorViewController.isEditor; self.expiresEditorViewController.isEditor = !self.expiresEditorViewController.isEditor; + self.iconViewController.isEditor = !self.iconViewController.isEditor; //self.totpViewController.isEditor = !self.totpViewController.isEditor; } diff --git a/MacPass/MPEntryPasswordAttributeViewController.m b/MacPass/MPEntryPasswordAttributeViewController.m index b4f457ef..0a789de3 100644 --- a/MacPass/MPEntryPasswordAttributeViewController.m +++ b/MacPass/MPEntryPasswordAttributeViewController.m @@ -37,16 +37,13 @@ }; } -- (void)updateValues { +- (void)updateValuesAndEditing { self.view.hidden = (!self.isEditor && self.representedAttribute.value.length == 0); self.passwordTextField.stringValue = self.representedAttribute.value ? self.representedAttribute.value : @""; -} - -- (void)updateEditing { + /* editor */ self.generatePasswordButton.hidden = !self.isEditor; self.passwordTextField.editable = self.isEditor; self.passwordTextField.selectable = YES; } - @end diff --git a/MacPass/MPInspectorEditorView.h b/MacPass/MPInspectorEditorView.h new file mode 100644 index 00000000..feae3fd7 --- /dev/null +++ b/MacPass/MPInspectorEditorView.h @@ -0,0 +1,21 @@ +// +// MPInspectorEditorView.h +// MacPass +// +// Created by Michael Starke on 08.03.22. +// Copyright © 2022 HicknHack Software GmbH. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXPORT NSString *const MPInspectorEditorViewMouseEnteredNotification; +FOUNDATION_EXPORT NSString *const MPInspectorEditorViewMouseExitedNotification; + + +@interface MPInspectorEditorView : NSView + +@end + +NS_ASSUME_NONNULL_END diff --git a/MacPass/MPInspectorEditorView.m b/MacPass/MPInspectorEditorView.m new file mode 100644 index 00000000..848bcb57 --- /dev/null +++ b/MacPass/MPInspectorEditorView.m @@ -0,0 +1,37 @@ +// +// MPInspectorEditorView.m +// MacPass +// +// Created by Michael Starke on 08.03.22. +// Copyright © 2022 HicknHack Software GmbH. All rights reserved. +// + +#import "MPInspectorEditorView.h" + +NSString *const MPInspectorEditorViewMouseEnteredNotification = @"com.hicknhacksoftware.macpass.MPInspectorEditorViewMouseEnteredNotification"; +NSString *const MPInspectorEditorViewMouseExitedNotification = @"com.hicknhacksoftware.macpass.MPInspectorEditorViewMouseExitedNotification"; + +@interface MPInspectorEditorView () + +@property (strong) NSTrackingArea *trackingArea; + +@end + +@implementation MPInspectorEditorView + +- (void)mouseEntered:(NSEvent *)event { + [NSNotificationCenter.defaultCenter postNotificationName:MPInspectorEditorViewMouseEnteredNotification object:self]; +} + +- (void)mouseExited:(NSEvent *)event { + [NSNotificationCenter.defaultCenter postNotificationName:MPInspectorEditorViewMouseExitedNotification object:self]; +} + +- (void)updateTrackingAreas { + [super updateTrackingAreas]; + [self removeTrackingArea:self.trackingArea]; + self.trackingArea = [[NSTrackingArea alloc] initWithRect:self.bounds options:NSTrackingActiveAlways|NSTrackingMouseEnteredAndExited owner:self userInfo:nil]; + [self addTrackingArea:self.trackingArea]; +} + +@end diff --git a/MacPass/MPNodeIconViewController.m b/MacPass/MPNodeIconViewController.m index 6fe1f6b8..b5f20cce 100644 --- a/MacPass/MPNodeIconViewController.m +++ b/MacPass/MPNodeIconViewController.m @@ -14,6 +14,8 @@ @interface MPNodeIconViewController () @property (strong) IBOutlet NSImageView *imageView; @property (strong) IBOutlet NSTextField *textField; +@property (copy) NSUUID *iconUUID; +@property NSUInteger iconId; @end @implementation MPNodeIconViewController @@ -27,7 +29,6 @@ } - (void)setRepresentedObject:(id)representedObject { - // FIXME: register for correct notifications if(self.representedNode) { KPKNode *node = self.representedNode; if(node.asEntry) { @@ -57,7 +58,7 @@ NSLog(@"Inconsitant state for notification handling"); } } - [self _updateValues]; + [self _updateValueAndEditing]; } - (KPKNode *)representedNode { @@ -67,31 +68,30 @@ return nil; } -- (void)_updateValues { +- (void)setIsEditor:(BOOL)isEditor { + _isEditor = isEditor; + [self _updateValueAndEditing]; +} + +- (void)_updateValueAndEditing { + self.imageView.enabled = self.isEditor; + self.iconUUID = self.representedNode.iconUUID; + self.iconId = self.representedNode.iconId; self.imageView.image = self.representedNode.iconImage; self.textField.stringValue = self.representedNode.title.length > 0 ? self.representedNode.title : @""; } - (void)commitChanges { - // fixme + self.representedNode.iconUUID = self.iconUUID; + self.representedNode.iconId = self.iconId; } - - (void)_willChangeNode:(NSNotification *)notification { } - (void)_didChangeNode:(NSNotification *)notification { - [self _updateValues]; + [self _updateValueAndEditing]; } -/* -- (BOOL)commitEditingAndReturnError:(NSError *__autoreleasing _Nullable * _Nullable)error { - <#code#> -} - -- (void)encodeWithCoder:(nonnull NSCoder *)coder { - <#code#> -} -*/ @end