mirror of
https://github.com/MacPass/MacPass.git
synced 2025-12-14 18:42:24 +00:00
Using new KeePassKit API, simple multi selection support
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9060" systemVersion="15B42" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9532" systemVersion="15D21" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9060"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9532"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="MPInspectorViewController">
|
||||
@@ -27,10 +27,9 @@
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="2930" customClass="HNHUIGradientView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="278" height="30"/>
|
||||
<subviews>
|
||||
<button hidden="YES" verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3109">
|
||||
<button verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3109">
|
||||
<rect key="frame" x="219" y="2" width="39" height="25"/>
|
||||
<animations/>
|
||||
<buttonCell key="cell" type="roundTextured" title="Edit" bezelStyle="texturedRounded" imagePosition="left" alignment="center" enabled="NO" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="3110">
|
||||
<buttonCell key="cell" type="roundTextured" title="Edit" bezelStyle="texturedRounded" imagePosition="left" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="3110">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
@@ -38,10 +37,9 @@
|
||||
<action selector="beginEditingSelectedItem:" target="-1" id="DRJ-M6-PkP"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button hidden="YES" verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3126">
|
||||
<button verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3126">
|
||||
<rect key="frame" x="154" y="2" width="57" height="25"/>
|
||||
<animations/>
|
||||
<buttonCell key="cell" type="roundTextured" title="Cancel" bezelStyle="texturedRounded" alignment="center" enabled="NO" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="3127">
|
||||
<buttonCell key="cell" type="roundTextured" title="Cancel" bezelStyle="texturedRounded" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="3127">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
@@ -51,7 +49,6 @@
|
||||
</button>
|
||||
<button hidden="YES" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="jBD-3D-knW">
|
||||
<rect key="frame" x="20" y="2" width="59" height="25"/>
|
||||
<animations/>
|
||||
<buttonCell key="cell" type="roundTextured" title="History" bezelStyle="texturedRounded" alignment="center" enabled="NO" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="w1z-1n-b0m">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
@@ -68,7 +65,6 @@
|
||||
<constraint firstItem="3109" firstAttribute="centerY" secondItem="2930" secondAttribute="centerY" id="3139"/>
|
||||
<constraint firstItem="3109" firstAttribute="leading" secondItem="3126" secondAttribute="trailing" constant="8" symbolic="YES" id="3140"/>
|
||||
</constraints>
|
||||
<animations/>
|
||||
</customView>
|
||||
<imageView translatesAutoresizingMaskIntoConstraints="NO" id="2998" customClass="MPPopupImageView">
|
||||
<rect key="frame" x="20" y="620" width="32" height="32"/>
|
||||
@@ -76,7 +72,6 @@
|
||||
<constraint firstAttribute="width" constant="32" id="3027"/>
|
||||
<constraint firstAttribute="height" constant="32" id="3028"/>
|
||||
</constraints>
|
||||
<animations/>
|
||||
<imageCell key="cell" alignment="left" imageScaling="proportionallyUpOrDown" image="NSActionTemplate" id="2999"/>
|
||||
<connections>
|
||||
<action selector="pickIcon:" target="-2" id="6wh-Ka-Thl"/>
|
||||
@@ -84,7 +79,6 @@
|
||||
</imageView>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="249" translatesAutoresizingMaskIntoConstraints="NO" id="3013">
|
||||
<rect key="frame" x="58" y="628" width="202" height="17"/>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" truncatesLastVisibleLine="YES" allowsUndo="NO" sendsActionOnEndEditing="YES" title="Label" usesSingleLineMode="YES" id="3014">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -100,21 +94,18 @@
|
||||
<subviews>
|
||||
<tabView type="noTabsNoBorder" initialItem="2896" translatesAutoresizingMaskIntoConstraints="NO" id="2895">
|
||||
<rect key="frame" x="0.0" y="0.0" width="278" height="370"/>
|
||||
<animations/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<tabViewItems>
|
||||
<tabViewItem label="Entry" identifier="2" id="2897">
|
||||
<view key="view" id="2898">
|
||||
<rect key="frame" x="0.0" y="0.0" width="278" height="370"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<animations/>
|
||||
</view>
|
||||
</tabViewItem>
|
||||
<tabViewItem label="Group" identifier="1" id="2896">
|
||||
<view key="view" id="2899">
|
||||
<rect key="frame" x="0.0" y="0.0" width="278" height="370"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<animations/>
|
||||
</view>
|
||||
</tabViewItem>
|
||||
<tabViewItem label="NoSelection" identifier="" id="2974">
|
||||
@@ -124,7 +115,6 @@
|
||||
<subviews>
|
||||
<textField verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2985">
|
||||
<rect key="frame" x="80" y="194" width="119" height="24"/>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="No Selection" id="2986">
|
||||
<font key="font" metaFont="system" size="20"/>
|
||||
<color key="textColor" name="controlShadowColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -136,7 +126,6 @@
|
||||
<constraint firstAttribute="centerY" secondItem="2985" secondAttribute="centerY" constant="20.5" id="TSQ-BR-XdP"/>
|
||||
<constraint firstAttribute="centerX" secondItem="2985" secondAttribute="centerX" constant="-0.5" id="UAO-rN-hO7"/>
|
||||
</constraints>
|
||||
<animations/>
|
||||
</view>
|
||||
</tabViewItem>
|
||||
</tabViewItems>
|
||||
@@ -149,7 +138,6 @@
|
||||
<constraint firstAttribute="bottom" secondItem="2895" secondAttribute="bottom" id="3165"/>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="100" id="qtg-Fq-2nL"/>
|
||||
</constraints>
|
||||
<animations/>
|
||||
</customView>
|
||||
<customView id="3147">
|
||||
<rect key="frame" x="0.0" y="371" width="278" height="211"/>
|
||||
@@ -157,7 +145,6 @@
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="PzR-P9-3al">
|
||||
<rect key="frame" x="18" y="192" width="36" height="14"/>
|
||||
<animations/>
|
||||
<textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Notes" id="hwn-UY-9Cr">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="disabledControlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -173,7 +160,6 @@
|
||||
<textView importsGraphics="NO" richText="NO" allowsUndo="YES" verticallyResizable="YES" allowsNonContiguousLayout="YES" smartInsertDelete="YES" id="g24-gQ-foD">
|
||||
<rect key="frame" x="0.0" y="0.0" width="236" height="177"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<size key="minSize" width="236" height="177"/>
|
||||
<size key="maxSize" width="463" height="10000000"/>
|
||||
@@ -182,19 +168,15 @@
|
||||
<size key="maxSize" width="463" height="10000000"/>
|
||||
</textView>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</clipView>
|
||||
<animations/>
|
||||
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="YES" id="ozT-Yy-2vu">
|
||||
<rect key="frame" x="-100" y="-100" width="87" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="Dgu-8Y-sx3">
|
||||
<rect key="frame" x="221" y="1" width="16" height="177"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
</scroller>
|
||||
</scrollView>
|
||||
</subviews>
|
||||
@@ -207,10 +189,8 @@
|
||||
<constraint firstAttribute="trailing" secondItem="0V7-UG-vEA" secondAttribute="trailing" constant="20" symbolic="YES" id="VyI-AI-Rmt"/>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="100" id="gZ6-Vo-6rK"/>
|
||||
</constraints>
|
||||
<animations/>
|
||||
</customView>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<holdingPriorities>
|
||||
<real value="251"/>
|
||||
<real value="249"/>
|
||||
@@ -233,7 +213,6 @@
|
||||
<constraint firstAttribute="trailing" secondItem="3145" secondAttribute="trailing" id="3154"/>
|
||||
<constraint firstItem="3145" firstAttribute="leading" secondItem="2894" secondAttribute="leading" id="3155"/>
|
||||
</constraints>
|
||||
<animations/>
|
||||
<point key="canvasLocation" x="268" y="-437"/>
|
||||
</customView>
|
||||
</objects>
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="694" height="595"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" alternatingRowBackgroundColors="YES" multipleSelection="NO" rowSizeStyle="automatic" headerView="676" viewBased="YES" id="55" customClass="MPTableView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="694" height="572"/>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" alternatingRowBackgroundColors="YES" typeSelect="NO" rowSizeStyle="automatic" headerView="676" viewBased="YES" id="55" customClass="MPTableView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="695" height="572"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<size key="intercellSpacing" width="3" height="2"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -190,7 +190,7 @@
|
||||
</tableCellView>
|
||||
</prototypeCellViews>
|
||||
</tableColumn>
|
||||
<tableColumn width="198" minWidth="10" maxWidth="3.4028234663852886e+38" id="614">
|
||||
<tableColumn width="199" minWidth="10" maxWidth="3.4028234663852886e+38" id="614">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -204,10 +204,10 @@
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="616">
|
||||
<rect key="frame" x="494" y="1" width="198" height="17"/>
|
||||
<rect key="frame" x="494" y="1" width="199" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="617">
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="617">
|
||||
<rect key="frame" x="1" y="0.0" width="196" height="17"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="618">
|
||||
<font key="font" metaFont="system"/>
|
||||
@@ -232,8 +232,8 @@
|
||||
</subviews>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</clipView>
|
||||
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="56">
|
||||
<rect key="frame" x="0.0" y="549" width="694" height="16"/>
|
||||
<scroller key="horizontalScroller" verticalHuggingPriority="750" horizontal="YES" id="56">
|
||||
<rect key="frame" x="0.0" y="579" width="694" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="58">
|
||||
@@ -241,7 +241,7 @@
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<tableHeaderView key="headerView" id="676">
|
||||
<rect key="frame" x="0.0" y="0.0" width="694" height="23"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="695" height="23"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</tableHeaderView>
|
||||
</scrollView>
|
||||
|
||||
@@ -48,12 +48,11 @@
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id<NSDraggingInfo>)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)dropOperation {
|
||||
MPDocument *document = [[[tableView window] windowController] document];
|
||||
id entry = document.selectedEntry;
|
||||
MPDocument *document = tableView.window.windowController.document;
|
||||
KPKEntry *entry = document.selectedEntries.count == 1 ? document.selectedEntries.lastObject : nil;
|
||||
|
||||
NSPasteboard *draggingPasteBoard = [info draggingPasteboard];
|
||||
NSArray *classArray = [NSArray arrayWithObject:[NSURL class]];
|
||||
NSArray *arrayOfURLs = [draggingPasteBoard readObjectsForClasses:classArray options:nil];
|
||||
NSArray *arrayOfURLs = [draggingPasteBoard readObjectsForClasses:@[[NSArray class]] options:nil];
|
||||
|
||||
for(NSURL *fileUrl in arrayOfURLs) {
|
||||
[document addAttachment:fileUrl toEntry:entry];
|
||||
|
||||
@@ -33,16 +33,14 @@
|
||||
@implementation MPAttachmentTableViewDelegate
|
||||
|
||||
- (void)tableViewSelectionDidChange:(NSNotification *)notification {
|
||||
NSTableView *tableView = [notification object];
|
||||
MPDocument *document = [[[tableView window] windowController] document];
|
||||
NSIndexSet *allColumns = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [[tableView tableColumns] count])];
|
||||
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [document.selectedEntry.binaries count] )];
|
||||
NSTableView *tableView = notification.object;
|
||||
NSIndexSet *allColumns = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, tableView.numberOfColumns)];
|
||||
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, tableView.numberOfRows )];
|
||||
[tableView reloadDataForRowIndexes:indexSet columnIndexes:allColumns];
|
||||
}
|
||||
|
||||
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
|
||||
/* Decide what view to use */
|
||||
MPDocument *document = [[[tableView window] windowController] document];
|
||||
NSIndexSet *selectedIndexes = [tableView selectedRowIndexes];
|
||||
NSTableCellView *view;
|
||||
if([selectedIndexes containsIndex:row]) {
|
||||
@@ -54,11 +52,10 @@
|
||||
view = [tableView makeViewWithIdentifier:@"NormalCell" owner:tableView];
|
||||
}
|
||||
/* Bind view */
|
||||
KPKEntry *entry = document.selectedEntry;
|
||||
NSAssert([entry.binaries count] > row, @"Indes needs to be valid for binaries");
|
||||
KPKBinary *binary = entry.binaries[row];
|
||||
[[view textField] bind:NSValueBinding toObject:binary withKeyPath:@"name" options:nil];
|
||||
[[view imageView] setImage:[[NSWorkspace sharedWorkspace] iconForFileType:[binary.name pathExtension]]];
|
||||
KPKBinary *binary = view.objectValue;
|
||||
NSString *nameKeyPath = [NSString stringWithFormat:@"%@.%@", NSStringFromSelector(@selector(objectValue)), NSStringFromSelector(@selector(name))];
|
||||
[view.textField bind:NSValueBinding toObject:view withKeyPath:nameKeyPath options:nil];
|
||||
view.imageView.image = [[NSWorkspace sharedWorkspace] iconForFileType:binary.name.pathExtension];
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -73,18 +70,18 @@
|
||||
NSMenu *menu = [[NSMenu alloc] init];
|
||||
/* Image for Popup button */
|
||||
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:@""];
|
||||
[item setImage:[NSImage imageNamed:NSImageNameActionTemplate]];
|
||||
item.image = [NSImage imageNamed:NSImageNameActionTemplate];
|
||||
[menu addItem:item];
|
||||
/* Quicklook */
|
||||
[menu addItemWithTitle:NSLocalizedString(@"PREVIEW", "") action:@selector(toggleQuicklookPreview:) keyEquivalent:@""];
|
||||
/* Save */
|
||||
item = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"SAVE", "") action:@selector(saveAttachment:) keyEquivalent:@""];
|
||||
[item setTarget:self.viewController];
|
||||
item.target = self.viewController;
|
||||
[menu addItem:item];
|
||||
/* Remove */
|
||||
[menu addItem:[NSMenuItem separatorItem]];
|
||||
item = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"DELETE", "") action:@selector(removeAttachment:) keyEquivalent:@""];
|
||||
[item setTarget:self.viewController];
|
||||
item.target = self.viewController;
|
||||
[menu addItem:item];
|
||||
|
||||
return menu;
|
||||
|
||||
@@ -116,7 +116,9 @@ typedef NS_ENUM(NSUInteger, MPContextTab) {
|
||||
- (void)_didChangeCurrentItem:(NSNotification *)notification {
|
||||
MPDocument *document = [notification object];
|
||||
|
||||
BOOL showTrash = document.tree.metaData.useTrash && (document.selectedItem.isTrashed || document.selectedItem.isTrash);
|
||||
KPKNode *node = document.selectedNodes.count == 1 ? document.selectedNodes.firstObject : nil;
|
||||
|
||||
BOOL showTrash = document.tree.metaData.useTrash && (node.isTrashed || node.isTrash);
|
||||
if(showTrash && ! document.hasSearch) {
|
||||
self.activeTab = MPContextTabTrash;
|
||||
[self _updateBindings];
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
//
|
||||
// MPDocument+EditingSession.m
|
||||
// MacPass
|
||||
//
|
||||
// Created by Michael Starke on 30/05/14.
|
||||
// Copyright (c) 2014 HicknHack Software GmbH. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPDocument.h"
|
||||
|
||||
#import "KeePassKit/KeePassKit.h"
|
||||
|
||||
NSString *const MPDocumentDidBeginEditingSelectedItem = @"com.hicknhack.macpass.MPDocumentDidBeginEditingSelectedItem";
|
||||
NSString *const MPDocumentDidCancelChangesToSelectedItem = @"com.hicknhack.macpass.MPDocumentDidCancelChangesToSelectedItem";
|
||||
NSString *const MPDocumentDidCommitChangesToSelectedItem = @"com.hicknhack.macpass.MPDocumentDidCommitChangesToSelectedItem";
|
||||
|
||||
@implementation MPDocument (EditingSession)
|
||||
|
||||
- (BOOL)hasActiveEditingSession {
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)commitChangesToSelectedItem:(id)sender {
|
||||
/* Force any lingering updates to be written */
|
||||
/* FIXME explore potential usage of:
|
||||
* NSObject(NSEditorRegistration)
|
||||
* NSObject(NSEditor)
|
||||
*/
|
||||
[((NSWindowController *)self.windowControllers.firstObject).window makeFirstResponder:nil];
|
||||
|
||||
/* update the data */
|
||||
[self.selectedItem commitEditing];
|
||||
if(self.selectedItem.asEntry) {
|
||||
[self.undoManager setActionName:NSLocalizedString(@"UPDATE_ENTRY", "")];
|
||||
}
|
||||
else if(self.selectedItem.asGroup) {
|
||||
[self.undoManager setActionName:NSLocalizedString(@"UPDATE_GROUP", "")];
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidCommitChangesToSelectedItem object:self];
|
||||
}
|
||||
|
||||
- (void)cancelChangesToSelectedItem:(id)sender {
|
||||
[self.selectedItem cancelEditing];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidCancelChangesToSelectedItem object:self];
|
||||
}
|
||||
|
||||
- (void)beginEditingSelectedItem:(id)sender {
|
||||
if(nil == self.selectedItem) {
|
||||
return;
|
||||
}
|
||||
[self.selectedItem beginEditing];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidBeginEditingSelectedItem object:self];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -14,7 +14,6 @@ NSString *const MPDocumentDidExitHistoryNotification = @"MPDocumentDidExitHisto
|
||||
@implementation MPDocument (HistoryBrowsing)
|
||||
|
||||
- (void)showHistory:(id)sender {
|
||||
NSAssert(self.selectedEntry && self.selectedItem == (id)self.selectedEntry, @"Entry needs to be selected for history browsing!");
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidEnterHistoryNotification object:self];
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@ NSString *const kMPDocumentSearchResultsKey = @"kMPDocumentSearchResul
|
||||
dispatch_async(backgroundQueue, ^{
|
||||
NSArray *results = [weakSelf _findEntriesMatchingCurrentSearch];
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
weakSelf.selectedEntry = nil;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidChangeSearchResults object:weakSelf userInfo:@{ kMPDocumentSearchResultsKey: results }];
|
||||
});
|
||||
});
|
||||
|
||||
@@ -56,7 +56,6 @@ APPKIT_EXTERN NSString *const MPDocumentGroupKey;
|
||||
@class KPKAttribute;
|
||||
@class KPKCompositeKey;
|
||||
@class KPKNode;
|
||||
@class KPKEditingSession;
|
||||
|
||||
@interface MPDocument : NSDocument <MPTargetNodeResolving>
|
||||
|
||||
@@ -76,9 +75,15 @@ APPKIT_EXTERN NSString *const MPDocumentGroupKey;
|
||||
/*
|
||||
State (active group/entry)
|
||||
*/
|
||||
@property (nonatomic, weak) KPKEntry *selectedEntry;
|
||||
@property (nonatomic, weak) KPKGroup *selectedGroup;
|
||||
@property (nonatomic, weak) KPKNode *selectedItem;
|
||||
//@property (nonatomic, weak) KPKEntry *selectedEntry;
|
||||
//@property (nonatomic, weak) KPKGroup *selectedGroup;
|
||||
//@property (nonatomic, weak) KPKNode *selectedItem;
|
||||
|
||||
|
||||
@property (nonatomic, copy, readonly) NSArray<KPKNode *> *selectedNodes;
|
||||
@property (nonatomic, copy) NSArray<KPKGroup *> *selectedGroups;
|
||||
@property (nonatomic, copy) NSArray<KPKEntry *> *selectedEntries;
|
||||
|
||||
|
||||
/*
|
||||
Search - see MPDocument+Search for further details
|
||||
|
||||
@@ -67,6 +67,8 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey
|
||||
@property (nonatomic, strong) NSData *encryptedData;
|
||||
@property (nonatomic, strong) MPTreeDelegate *treeDelgate;
|
||||
|
||||
@property (nonatomic, copy) NSArray<KPKNode *> *selectedNodes;
|
||||
|
||||
@property (assign) BOOL readOnly;
|
||||
@property (strong) NSURL *lockFileURL;
|
||||
|
||||
@@ -374,26 +376,6 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey
|
||||
self.tree.trash = trash;
|
||||
}
|
||||
|
||||
- (void)setSelectedGroup:(KPKGroup *)selectedGroup {
|
||||
if(_selectedGroup != selectedGroup) {
|
||||
_selectedGroup = selectedGroup;
|
||||
}
|
||||
self.selectedItem = _selectedGroup;
|
||||
}
|
||||
|
||||
- (void)setSelectedEntry:(KPKEntry *)selectedEntry {
|
||||
if(_selectedEntry != selectedEntry) {
|
||||
_selectedEntry = selectedEntry;
|
||||
}
|
||||
self.selectedItem = selectedEntry;
|
||||
}
|
||||
|
||||
- (void)setSelectedItem:(KPKNode *)selectedItem {
|
||||
if(_selectedItem != selectedItem) {
|
||||
_selectedItem = selectedItem;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentCurrentItemChangedNotification object:self];
|
||||
}
|
||||
}
|
||||
- (void)setTree:(KPKTree *)tree {
|
||||
if(_tree != tree) {
|
||||
_tree = tree;
|
||||
@@ -404,6 +386,28 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
- (void)setSelectedNodes:(NSArray<KPKNode *> *)selectedNodes {
|
||||
if(![_selectedNodes isEqualToArray:selectedNodes]) {
|
||||
_selectedNodes = [selectedNodes copy];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentCurrentItemChangedNotification object:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setSelectedGroups:(NSArray<KPKGroup *> *)selectedGroups {
|
||||
if(![self.selectedGroups isEqualToArray:selectedGroups]) {
|
||||
_selectedGroups = [selectedGroups copy];
|
||||
}
|
||||
self.selectedNodes = self.selectedGroups;
|
||||
}
|
||||
|
||||
- (void)setSelectedEntries:(NSArray<KPKEntry *> *)selectedEntries {
|
||||
if(![self.selectedEntries isEqualToArray:selectedEntries]) {
|
||||
_selectedEntries = [selectedEntries copy];
|
||||
}
|
||||
self.selectedNodes = self.selectedEntries;
|
||||
}
|
||||
|
||||
#pragma mark Data Accesors
|
||||
|
||||
- (KPKEntry *)findEntry:(NSUUID *)uuid {
|
||||
@@ -451,8 +455,8 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey
|
||||
if(defaultPassword) {
|
||||
newEntry.password = defaultPassword;
|
||||
}
|
||||
[parent addEntry:newEntry];
|
||||
[parent.undoManager setActionName:NSLocalizedString(@"ADD_ENTRY", "")];
|
||||
[newEntry addToGroup:parent];
|
||||
[newEntry.undoManager setActionName:NSLocalizedString(@"ADD_ENTRY", "")];
|
||||
NSDictionary *userInfo = @{ MPDocumentEntryKey: newEntry };
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidAddEntryNotification object:self userInfo:userInfo];
|
||||
return newEntry;
|
||||
@@ -468,7 +472,8 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey
|
||||
KPKGroup *newGroup = [self.tree createGroup:parent];
|
||||
newGroup.title = NSLocalizedString(@"DEFAULT_GROUP_NAME", @"Title for a newly created group");
|
||||
newGroup.iconId = MPIconFolder;
|
||||
[parent addGroup:newGroup];
|
||||
[newGroup addToGroup:parent];
|
||||
[newGroup.undoManager setActionName:NSLocalizedString(@"ADD_GROUP", "")];
|
||||
NSDictionary *userInfo = @{ MPDocumentGroupKey : newGroup };
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPDocumentDidAddGroupNotification object:self userInfo:userInfo];
|
||||
return newGroup;
|
||||
@@ -491,19 +496,24 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey
|
||||
[self _presentTrashAlertForItem:node];
|
||||
return;
|
||||
}
|
||||
|
||||
// if(node.asGroup == self.selectedGroup) {
|
||||
// self.selectedGroup = node.asGroup;
|
||||
// }
|
||||
// if(node.asEntry == self.selectedEntry) {
|
||||
// self.selectedEntry = node.asEntry;
|
||||
// }
|
||||
|
||||
if(!self.tree.metaData.useTrash) {
|
||||
/* Display warning about permanently removing items! */
|
||||
}
|
||||
[node trashOrRemove];
|
||||
BOOL permanent = (nil == self.trash);
|
||||
BOOL permanent = !node.isTrashed;
|
||||
if(node.asGroup) {
|
||||
[self.undoManager setActionName:permanent ? NSLocalizedString(@"DELETE_GROUP", "Delete Group") : NSLocalizedString(@"TRASH_GROUP", "Move Group to Trash")];
|
||||
if(self.selectedGroup == node) {
|
||||
self.selectedGroup = nil;
|
||||
}
|
||||
}
|
||||
else if(node.asEntry) {
|
||||
[self.undoManager setActionName:permanent ? NSLocalizedString(@"DELETE_ENTRY", "") : NSLocalizedString(@"TRASH_ENTRY", "Move Entry to Trash")];
|
||||
if(self.selectedEntry == node) {
|
||||
self.selectedEntry = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,7 +564,6 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey
|
||||
[node.undoManager removeAllActionsWithTarget:group];
|
||||
}
|
||||
[node remove];
|
||||
[node.undoManager removeAllActionsWithTarget:node];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -569,18 +578,21 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey
|
||||
NSUUID *entryUUID = [sender representedObject];
|
||||
if(entryUUID) {
|
||||
KPKEntry *templateEntry = [self findEntry:entryUUID];
|
||||
if(templateEntry && self.selectedGroup) {
|
||||
KPKGroup *group = self.selectedGroups.count == 1 ? self.selectedGroups.firstObject : nil;
|
||||
if(templateEntry && group) {
|
||||
KPKEntry *copy = [templateEntry copyWithTitle:templateEntry.title options:kKPKCopyOptionNone];
|
||||
[self.selectedGroup addEntry:copy];
|
||||
[self.selectedGroup.undoManager setActionName:NSLocalizedString(@"ADD_TREMPLATE_ENTRY", "")];
|
||||
[copy addToGroup:group];
|
||||
[self.undoManager setActionName:NSLocalizedString(@"ADD_TREMPLATE_ENTRY", "")];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)duplicateEntry:(id)sender {
|
||||
/*
|
||||
KPKEntry *duplicate = [self.selectedEntry copyWithTitle:nil options:kKPKCopyOptionNone];
|
||||
[self.selectedEntry.parent addEntry:duplicate];
|
||||
[duplicate addToGroup:self.selectedEntry.parent];
|
||||
[self.undoManager setActionName:NSLocalizedString(@"DUPLICATE_ENTRY", "")];
|
||||
*/
|
||||
}
|
||||
|
||||
- (void)duplicateEntryWithOptions:(id)sender {
|
||||
@@ -715,11 +727,12 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey
|
||||
#pragma mark MPTargetNodeResolving
|
||||
|
||||
- (KPKEntry *)currentTargetEntry {
|
||||
return self.selectedEntry;
|
||||
return self.selectedEntries.firstObject;
|
||||
//return self.selectedEntry;
|
||||
}
|
||||
|
||||
- (KPKGroup *)currentTargetGroup {
|
||||
return self.selectedGroup;
|
||||
return self.selectedGroups.firstObject;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -82,10 +82,10 @@ typedef void (^MPPasswordChangedBlock)(BOOL didChangePassword);
|
||||
- (void)windowDidLoad {
|
||||
[super windowDidLoad];
|
||||
|
||||
[[self window] setDelegate:self.documentWindowDelegate];
|
||||
[[self window] registerForDraggedTypes:@[NSURLPboardType]];
|
||||
self.window.delegate = self.documentWindowDelegate;
|
||||
[self.window registerForDraggedTypes:@[NSURLPboardType]];
|
||||
|
||||
MPDocument *document = [self document];
|
||||
MPDocument *document = self.document;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didRevertDocument:) name:MPDocumentDidRevertNotifiation object:document];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didUnlockDatabase:) name:MPDocumentDidUnlockDatabaseNotification object:document];
|
||||
@@ -104,7 +104,7 @@ typedef void (^MPPasswordChangedBlock)(BOOL didChangePassword);
|
||||
self.window.toolbar = self.toolbar;
|
||||
self.toolbarDelegate.toolbar = self.toolbar;
|
||||
|
||||
[self.splitView setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
self.splitView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
|
||||
NSView *outlineView = self.outlineViewController.view;
|
||||
NSView *inspectorView = self.inspectorViewController.view;
|
||||
@@ -128,7 +128,7 @@ typedef void (^MPPasswordChangedBlock)(BOOL didChangePassword);
|
||||
[self showEntries];
|
||||
}
|
||||
|
||||
[self.splitView setAutosaveName:@"SplitView"];
|
||||
self.splitView.autosaveName = @"SplitView";
|
||||
}
|
||||
|
||||
- (NSSearchField *)searchField {
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
}
|
||||
/* Currently not working, as the underlying operations do not get the unomanager */
|
||||
MPDocument *document = [[[sender draggingDestinationWindow] windowController] document];
|
||||
KPKGroup *parentGroup = document.selectedGroup ? document.selectedGroup : document.root;
|
||||
KPKGroup *parentGroup = document.selectedGroups.count == 1 ? document.selectedGroups.firstObject : document.root;
|
||||
[document.undoManager beginUndoGrouping];
|
||||
KPKEntry *entry = [document createEntry:parentGroup];
|
||||
BOOL didOk = (entry != nil);
|
||||
|
||||
@@ -131,7 +131,8 @@ static NSString *kMPContentBindingString3 = @"content.%@.%@.%@";
|
||||
}
|
||||
|
||||
- (void)setupBindings:(MPDocument *)document {
|
||||
[self.entryController bind:NSContentObjectBinding toObject:document withKeyPath:NSStringFromSelector(@selector(selectedEntry)) options:nil];
|
||||
[self.entryController bind:NSContentObjectBinding toObject:self withKeyPath:NSStringFromSelector(@selector(representedObject)) options:nil];
|
||||
// [self.entryController bind:NSContentObjectBinding toObject:document withKeyPath:NSStringFromSelector(@selector(selectedEntry)) options:nil];
|
||||
}
|
||||
|
||||
- (void)registerNotificationsForDocument:(MPDocument *)document {
|
||||
@@ -247,7 +248,7 @@ static NSString *kMPContentBindingString3 = @"content.%@.%@.%@";
|
||||
|
||||
- (BOOL)acceptsPreviewPanelControl:(QLPreviewPanel *)panel {
|
||||
if(self.activeTab == MPEntryTabFiles) {
|
||||
return ([self.attachmentTableView selectedRow] != -1);
|
||||
return (self.attachmentTableView.selectedRow != -1);
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ NSString *const _MPTableSecurCellView = @"PasswordCell";
|
||||
BOOL _didUnlock;
|
||||
}
|
||||
|
||||
@property (strong) NSArrayController *entryArrayController;
|
||||
//@property (strong) NSArrayController *entryArrayController;
|
||||
@property (strong) MPContextBarViewController *contextBarViewController;
|
||||
@property (strong) NSArray *filteredEntries;
|
||||
|
||||
@@ -94,6 +94,8 @@ NSString *const _MPTableSecurCellView = @"PasswordCell";
|
||||
_dataSource.viewController = self;
|
||||
_menuDelegate = [[MPEntryContextMenuDelegate alloc] init];
|
||||
_contextBarViewController = [[MPContextBarViewController alloc] init];
|
||||
NSString *entriesKeyPath = [NSString stringWithFormat:@"%@.%@", NSStringFromSelector(@selector(representedObject)), NSStringFromSelector(@selector(entries))];
|
||||
[_entryArrayController bind:NSContentBinding toObject:self withKeyPath:entriesKeyPath options:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -164,6 +166,7 @@ NSString *const _MPTableSecurCellView = @"PasswordCell";
|
||||
|
||||
[self.entryTable bind:NSContentBinding toObject:self.entryArrayController withKeyPath:NSStringFromSelector(@selector(arrangedObjects)) options:nil];
|
||||
[self.entryTable bind:NSSortDescriptorsBinding toObject:self.entryArrayController withKeyPath:NSStringFromSelector(@selector(sortDescriptors)) options:nil];
|
||||
[self.entryTable bind:NSSelectionIndexesBinding toObject:self.entryArrayController withKeyPath:NSStringFromSelector(@selector(selectionIndexes)) options:nil];
|
||||
self.entryTable.dataSource = self.dataSource;
|
||||
|
||||
// bind NSArrayController sorting so that sort order gets auto-saved
|
||||
@@ -341,22 +344,17 @@ NSString *const _MPTableSecurCellView = @"PasswordCell";
|
||||
return; // Not the right table view
|
||||
}
|
||||
MPDocument *document = self.windowController.document;
|
||||
if(tableView.selectedRow < 0 || tableView.selectedRowIndexes.count > 1) {
|
||||
document.selectedEntry = nil;
|
||||
}
|
||||
else {
|
||||
document.selectedEntry = self.entryArrayController.arrangedObjects[tableView.selectedRow];
|
||||
}
|
||||
document.selectedEntries = self.entryArrayController.selectedObjects;
|
||||
}
|
||||
|
||||
#pragma mark MPTargetItemResolving
|
||||
- (KPKEntry *)currentTargetEntry {
|
||||
NSInteger activeRow = [self.entryTable clickedRow];
|
||||
NSInteger activeRow = self.entryTable.clickedRow;
|
||||
/* Fall back to selection e.g. for toolbar actions */
|
||||
if(activeRow < 0 ) {
|
||||
activeRow = [self.entryTable selectedRow];
|
||||
activeRow = self.entryTable.selectedRow;
|
||||
}
|
||||
if(activeRow >= 0 && activeRow <= [[self.entryArrayController arrangedObjects] count]) {
|
||||
if(activeRow >= 0 && activeRow <= [self.entryArrayController.arrangedObjects count]) {
|
||||
return [self.entryArrayController arrangedObjects][activeRow];
|
||||
}
|
||||
return nil;
|
||||
@@ -368,60 +366,55 @@ NSString *const _MPTableSecurCellView = @"PasswordCell";
|
||||
return entry;
|
||||
}
|
||||
MPDocument *document = self.windowController.document;
|
||||
return document.selectedItem;
|
||||
return document.selectedNodes.firstObject;
|
||||
}
|
||||
|
||||
#pragma mark MPDocument Notifications
|
||||
- (void)_didChangeCurrentItem:(NSNotification *)notification {
|
||||
MPDocument *document = [notification object];
|
||||
|
||||
if(!document.selectedGroup && !document.hasSearch) {
|
||||
if(document.selectedGroups.count != 1 && !document.hasSearch) {
|
||||
/* no group selection out of search is wrong */
|
||||
[self.entryArrayController unbind:NSContentArrayBinding];
|
||||
[self.entryArrayController setContent:nil];
|
||||
self.representedObject = nil;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
If a group is the current item, see if we already show that group
|
||||
also test if an element has been selected (issue #257)
|
||||
*/
|
||||
if(document.selectedItem == document.selectedGroup && document.selectedItem != nil) {
|
||||
if(document.selectedNodes.firstObject == document.selectedGroups.firstObject && document.selectedNodes.count > 0) {
|
||||
if(document.hasSearch) {
|
||||
/* If search was active, stop it and exit */
|
||||
[document exitSearch:self];
|
||||
}
|
||||
else if([[self.entryArrayController content] count] > 0) {
|
||||
KPKEntry *entry = [[self.entryArrayController content] lastObject];
|
||||
if(entry.parent == document.selectedGroup) {
|
||||
else if([self.entryArrayController.content count] > 0) {
|
||||
KPKEntry *entry = [self.entryArrayController.content lastObject];
|
||||
if(entry.parent == document.selectedGroups.lastObject) {
|
||||
return; // we are showing the correct object right now.
|
||||
}
|
||||
}
|
||||
[self.entryArrayController unbind:NSContentArrayBinding];
|
||||
[self.entryArrayController bind:NSContentArrayBinding toObject:document.selectedGroup withKeyPath:NSStringFromSelector(@selector(entries)) options:nil];
|
||||
self.representedObject = document.selectedGroups.count == 1 ? document.selectedGroups.firstObject : nil;
|
||||
}
|
||||
[self _updateContextBar];
|
||||
}
|
||||
|
||||
- (void)_didBecomFirstResponder:(NSNotification *)notification {
|
||||
MPDocument *document = [[self windowController] document];
|
||||
MPDocument *document = self.windowController.document;
|
||||
document.selectedEntries = self.entryArrayController.selectedObjects;
|
||||
|
||||
/*
|
||||
if(document.selectedEntry.parent == document.selectedGroup || document.hasSearch) {
|
||||
document.selectedItem = document.selectedEntry;
|
||||
}
|
||||
else {
|
||||
document.selectedEntry = nil;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
- (void)_didAddItem:(NSNotification *)notification {
|
||||
MPDocument *document = [[self windowController] document];
|
||||
if(!document.selectedGroup) {
|
||||
/* TODO: show group? */
|
||||
return; // No group selected
|
||||
}
|
||||
KPKEntry *entry = document.selectedGroup.entries.lastObject;
|
||||
if(!entry) {
|
||||
return; // No Entry found, nothing to select.
|
||||
}
|
||||
NSDictionary *dict = notification.userInfo;
|
||||
KPKEntry *entry = dict[MPDocumentEntryKey];
|
||||
NSUInteger row = [self.entryArrayController.arrangedObjects indexOfObject:entry];
|
||||
[self.entryTable scrollRowToVisible:row];
|
||||
[self.entryTable selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
|
||||
@@ -440,13 +433,13 @@ NSString *const _MPTableSecurCellView = @"PasswordCell";
|
||||
|
||||
- (void)_didExitSearch:(NSNotification *)notification {
|
||||
[[self.entryTable tableColumnWithIdentifier:MPEntryTableParentColumnIdentifier] setHidden:YES];
|
||||
MPDocument *document = [[self windowController] document];
|
||||
document.selectedItem = document.selectedGroup;
|
||||
// TODO: really necessary?
|
||||
if( nil == document.selectedItem && nil == document.selectedGroup ) {
|
||||
[self.entryArrayController unbind:NSContentArrayBinding];
|
||||
[self.entryArrayController setContent:nil];
|
||||
}
|
||||
// MPDocument *document = [[self windowController] document];
|
||||
// document.selectedItem = document.selectedGroup;
|
||||
// // TODO: really necessary?
|
||||
// if( nil == document.selectedItem && nil == document.selectedGroup ) {
|
||||
// [self.entryArrayController unbind:NSContentArrayBinding];
|
||||
// [self.entryArrayController setContent:nil];
|
||||
// }
|
||||
[self _updateContextBar];
|
||||
}
|
||||
|
||||
@@ -469,13 +462,13 @@ NSString *const _MPTableSecurCellView = @"PasswordCell";
|
||||
[self _showContextBar];
|
||||
/* TODO: Show modification date column if not present? */
|
||||
MPDocument *document = [[self windowController] document];
|
||||
[self.entryArrayController bind:NSContentArrayBinding toObject:document.selectedEntry withKeyPath:NSStringFromSelector(@selector(history)) options:nil];
|
||||
//[self.entryArrayController bind:NSContentArrayBinding toObject:document.selectedEntry withKeyPath:NSStringFromSelector(@selector(history)) options:nil];
|
||||
}
|
||||
|
||||
- (void)_didExitHistory:(NSNotification *)notification {
|
||||
[self _hideContextBar];
|
||||
MPDocument *document = [[self windowController] document];
|
||||
document.selectedItem = document.selectedEntry;
|
||||
//document.selectedItem = document.selectedEntry;
|
||||
}
|
||||
|
||||
|
||||
@@ -483,7 +476,9 @@ NSString *const _MPTableSecurCellView = @"PasswordCell";
|
||||
- (void)_updateContextBar {
|
||||
MPDocument *document = [[self windowController] document];
|
||||
if(!document.hasSearch) {
|
||||
BOOL showTrash = document.tree.metaData.useTrash && (document.selectedGroup.isTrash || document.selectedItem.isTrashed);
|
||||
KPKGroup *group = self.representedObject;
|
||||
KPKNode *node = document.selectedNodes.count == 1 ? document.selectedNodes.firstObject : nil;
|
||||
BOOL showTrash = document.tree.metaData.useTrash && (group.isTrash || node.isTrashed);
|
||||
if(showTrash) {
|
||||
[self _showContextBar];
|
||||
}
|
||||
|
||||
@@ -84,7 +84,8 @@
|
||||
}
|
||||
|
||||
- (void)setupBindings:(MPDocument *)document {
|
||||
[self.groupController bind:NSContentObjectBinding toObject:document withKeyPath:NSStringFromSelector(@selector(selectedGroup)) options:nil];
|
||||
[self.groupController bind:NSContentObjectBinding toObject:self withKeyPath:NSStringFromSelector(@selector(representedObject)) options:nil];
|
||||
//[self.groupController bind:NSContentObjectBinding toObject:document withKeyPath:NSStringFromSelector(@selector(selectedGroup)) options:nil];
|
||||
}
|
||||
|
||||
- (void)_establishBindings {
|
||||
|
||||
@@ -190,9 +190,9 @@ typedef NS_ENUM(NSUInteger, MPContentTab) {
|
||||
self.popover.behavior = NSPopoverBehaviorTransient;
|
||||
MPDatePickingViewController *controller = [[MPDatePickingViewController alloc] init];
|
||||
controller.popover = self.popover;
|
||||
MPDocument *document = self.windowController.document;
|
||||
if(document.selectedItem.timeInfo.expirationDate) {
|
||||
controller.date = document.selectedItem.timeInfo.expirationDate;
|
||||
KPKNode *node = self.representedObject;
|
||||
if(node.timeInfo.expirationDate) {
|
||||
controller.date = node.timeInfo.expirationDate;
|
||||
}
|
||||
self.popover.contentViewController = controller;
|
||||
[self.popover showRelativeToRect:NSZeroRect ofView:sender preferredEdge:NSMinYEdge];
|
||||
@@ -216,16 +216,19 @@ typedef NS_ENUM(NSUInteger, MPContentTab) {
|
||||
}
|
||||
|
||||
- (void)_setIcon:(NSInteger)iconId {
|
||||
MPDocument *document = [[self windowController] document];
|
||||
BOOL useDefault = (iconId == -1);
|
||||
switch (self.activeTab) {
|
||||
case MPGroupTab:
|
||||
document.selectedGroup.iconId = useDefault ? [KPKGroup defaultIcon] : iconId;
|
||||
case MPGroupTab: {
|
||||
KPKGroup *group = self.nodeController.content;
|
||||
group.iconId = useDefault ? [KPKGroup defaultIcon] : iconId;
|
||||
break;
|
||||
}
|
||||
|
||||
case MPEntryTab:
|
||||
document.selectedEntry.iconId = useDefault ? [KPKEntry defaultIcon]: iconId;
|
||||
case MPEntryTab: {
|
||||
KPKEntry *entry = self.nodeController.content;
|
||||
entry.iconId = useDefault ? [KPKEntry defaultIcon]: iconId;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
@@ -233,8 +236,8 @@ typedef NS_ENUM(NSUInteger, MPContentTab) {
|
||||
}
|
||||
|
||||
- (void)_setExpiryDate:(NSDate *)date {
|
||||
MPDocument *document = [[self windowController] document];
|
||||
document.selectedItem.timeInfo.expirationDate = date;
|
||||
KPKNode *node = self.representedObject;
|
||||
node.timeInfo.expirationDate = date;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
@@ -268,18 +271,19 @@ typedef NS_ENUM(NSUInteger, MPContentTab) {
|
||||
|
||||
- (void)_didChangeCurrentItem:(NSNotification *)notification {
|
||||
MPDocument *document = notification.object;
|
||||
if(document.selectedItem.asGroup) {
|
||||
KPKNode *node = document.selectedNodes.count == 1 ? document.selectedNodes.firstObject : nil;
|
||||
if(node.asGroup) {
|
||||
self.activeTab = MPGroupTab;
|
||||
}
|
||||
else if(document.selectedItem.asEntry) {
|
||||
else if(node.asEntry) {
|
||||
self.activeTab = MPEntryTab;
|
||||
}
|
||||
else {
|
||||
self.activeTab = MPEmptyTab;
|
||||
}
|
||||
self.nodeController.content = document.selectedItem;
|
||||
self.entryViewController.representedObject = document.selectedItem.asEntry;
|
||||
self.groupViewController.representedObject = document.selectedItem.asGroup;
|
||||
self.nodeController.content = node;
|
||||
self.entryViewController.representedObject = node.asEntry;
|
||||
self.groupViewController.representedObject = node.asGroup;
|
||||
}
|
||||
|
||||
- (IBAction)beginEditing:(id)sender {
|
||||
|
||||
@@ -140,8 +140,8 @@
|
||||
if(draggedGroup) {
|
||||
if(copyItem || (nil == self.localDraggedGroup) ) {
|
||||
draggedGroup = [draggedGroup copyWithTitle:nil options:kKPKCopyOptionNone];
|
||||
[targetGroup addGroup:draggedGroup atIndex:index];
|
||||
[targetGroup.undoManager setActionName:NSLocalizedString(@"COPY_GROUP", "")];
|
||||
[draggedGroup addToGroup:targetGroup atIndex:index];
|
||||
[draggedGroup.undoManager setActionName:NSLocalizedString(@"COPY_GROUP", "")];
|
||||
return YES;
|
||||
}
|
||||
else if(self.localDraggedGroup) {
|
||||
@@ -156,8 +156,8 @@
|
||||
else if(draggedEntry) {
|
||||
if(copyItem || (nil == self.localDraggedEntry)) {
|
||||
draggedEntry = [draggedEntry copyWithTitle:nil options:kKPKCopyOptionNone];
|
||||
[targetGroup addEntry:draggedEntry];
|
||||
[targetGroup.undoManager setActionName:NSLocalizedString(@"COPY_ENTRY", "")];
|
||||
[draggedEntry addToGroup:targetGroup];
|
||||
[draggedEntry.undoManager setActionName:NSLocalizedString(@"COPY_ENTRY", "")];
|
||||
return YES;
|
||||
}
|
||||
else if(self.localDraggedEntry) {
|
||||
|
||||
@@ -17,6 +17,18 @@
|
||||
|
||||
@implementation MPOutlineView
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
|
||||
- (void)viewDidMoveToSuperview {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
if(self.enclosingScrollView) {
|
||||
[self _setupNotifications];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent *)theEvent {
|
||||
[super mouseDown:theEvent];
|
||||
if(_didBecomeFirstResponder) {
|
||||
@@ -36,4 +48,15 @@
|
||||
return [super resignFirstResponder];
|
||||
}
|
||||
|
||||
- (void)_setupNotifications {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
if(self.enclosingScrollView.contentView) {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didChangeFrame:) name:NSViewBoundsDidChangeNotification object:self.enclosingScrollView.contentView];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_didChangeFrame:(NSNotification *)notification {
|
||||
NSLog(@"DidChangeFrame:%@", NSStringFromRect(self.bounds));
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -71,13 +71,14 @@ NSString *const _MPOutlinveViewHeaderViewIdentifier = @"HeaderCell";
|
||||
}
|
||||
|
||||
- (void)didLoadView {
|
||||
self.outlineView.menu = [self _contextMenu];
|
||||
self.outlineView.allowsEmptySelection = YES;
|
||||
self.outlineView.floatsGroupRows = NO;
|
||||
self.outlineView.doubleAction = @selector(_doubleClickedGroup:);
|
||||
self.outlineView.allowsMultipleSelection = YES;
|
||||
[self.outlineView setDelegate:self];
|
||||
[self.outlineView setMenu:[self _contextMenu]];
|
||||
[self.outlineView setAllowsEmptySelection:YES];
|
||||
[self.outlineView setFloatsGroupRows:NO];
|
||||
[self.outlineView registerForDraggedTypes:@[ KPKGroupUTI, KPKEntryUTI ]];
|
||||
[self.outlineView setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES];
|
||||
[self.outlineView setDoubleAction:@selector(_doubleClickedGroup:)];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(_didBecomeFirstResponder:)
|
||||
@@ -94,12 +95,13 @@ NSString *const _MPOutlinveViewHeaderViewIdentifier = @"HeaderCell";
|
||||
|
||||
- (void)showOutline {
|
||||
if(!_bindingEstablished) {
|
||||
MPDocument *document = [[self windowController] document];
|
||||
[_treeController setChildrenKeyPath:NSStringFromSelector(@selector(groups))];
|
||||
[_treeController bind:NSContentBinding toObject:document withKeyPath:NSStringFromSelector(@selector(tree)) options:nil];
|
||||
[_outlineView bind:NSContentBinding toObject:_treeController withKeyPath:NSStringFromSelector(@selector(arrangedObjects)) options:nil];
|
||||
MPDocument *document = self.windowController.document;
|
||||
self.treeController.childrenKeyPath = NSStringFromSelector(@selector(groups));
|
||||
[self.treeController bind:NSContentBinding toObject:document withKeyPath:NSStringFromSelector(@selector(tree)) options:nil];
|
||||
[self.outlineView bind:NSContentBinding toObject:self.treeController withKeyPath:NSStringFromSelector(@selector(arrangedObjects)) options:nil];
|
||||
[self.outlineView bind:NSSelectionIndexPathsBinding toObject:self.treeController withKeyPath:NSStringFromSelector(@selector(selectionIndexPaths)) options:nil];
|
||||
[self bind:NSStringFromSelector(@selector(databaseNameWrapper)) toObject:document.tree.metaData withKeyPath:NSStringFromSelector(@selector(databaseName)) options:nil];
|
||||
[_outlineView setDataSource:self.datasource];
|
||||
[self.outlineView setDataSource:self.datasource];
|
||||
_bindingEstablished = YES;
|
||||
}
|
||||
NSTreeNode *node = [_outlineView itemAtRow:0];
|
||||
@@ -119,7 +121,7 @@ NSString *const _MPOutlinveViewHeaderViewIdentifier = @"HeaderCell";
|
||||
[self.outlineView collapseItem:node];
|
||||
}
|
||||
}
|
||||
for(NSTreeNode *child in [node childNodes]) {
|
||||
for(NSTreeNode *child in node.childNodes) {
|
||||
[self _expandItems:child];
|
||||
}
|
||||
}
|
||||
@@ -133,9 +135,9 @@ NSString *const _MPOutlinveViewHeaderViewIdentifier = @"HeaderCell";
|
||||
|
||||
#pragma mark MPTargetNodeResolving
|
||||
- (KPKGroup *)currentTargetGroup {
|
||||
NSInteger row = [self.outlineView clickedRow];
|
||||
NSInteger row = self.outlineView.clickedRow;
|
||||
if( row < 0 ) {
|
||||
row = [self.outlineView selectedRow];
|
||||
row = self.outlineView.selectedRow;
|
||||
}
|
||||
return [[self.outlineView itemAtRow:row] representedObject];
|
||||
}
|
||||
@@ -145,8 +147,8 @@ NSString *const _MPOutlinveViewHeaderViewIdentifier = @"HeaderCell";
|
||||
if(group) {
|
||||
return group;
|
||||
}
|
||||
MPDocument *document = [[self windowController] document];
|
||||
return document.selectedItem;
|
||||
MPDocument *document = self.windowController.document;
|
||||
return document.selectedNodes.firstObject;
|
||||
}
|
||||
|
||||
#pragma mark Notifications
|
||||
@@ -165,7 +167,8 @@ NSString *const _MPOutlinveViewHeaderViewIdentifier = @"HeaderCell";
|
||||
return; // Nothing we need to worry about
|
||||
}
|
||||
MPDocument *document = [[self windowController] document];
|
||||
document.selectedItem = document.selectedGroup;
|
||||
document.selectedGroups = self.treeController.selectedObjects;
|
||||
//document.selectedItem = document.selectedGroup;
|
||||
}
|
||||
|
||||
# pragma mark MPDocument Notifications
|
||||
@@ -229,10 +232,13 @@ NSString *const _MPOutlinveViewHeaderViewIdentifier = @"HeaderCell";
|
||||
}
|
||||
|
||||
- (void)outlineViewSelectionDidChange:(NSNotification *)notification {
|
||||
NSTreeNode *treeNode = [_outlineView itemAtRow:[_outlineView selectedRow]];
|
||||
KPKGroup *selectedGroup = [treeNode representedObject];
|
||||
MPDocument *document = [[self windowController] document];
|
||||
document.selectedGroup = selectedGroup;
|
||||
MPDocument *document = self.windowController.document;
|
||||
if(![self.treeController.selectedObjects.firstObject isKindOfClass:[KPKTree class]]) {
|
||||
document.selectedGroups = self.treeController.selectedObjects;
|
||||
}
|
||||
else {
|
||||
document.selectedGroups = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldShowOutlineCellForItem:(id)item {
|
||||
|
||||
@@ -19,11 +19,12 @@
|
||||
}
|
||||
|
||||
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
|
||||
MPDocument *document = [[[tableView window] windowController] document];
|
||||
NSTableCellView *view = [tableView makeViewWithIdentifier:@"WindowAssociationCell" owner:tableView];
|
||||
KPKEntry *entry = document.selectedEntry;
|
||||
KPKWindowAssociation *association = entry.autotype.associations[row];
|
||||
[[view textField] bind:NSValueBinding toObject:association withKeyPath:@"windowTitle" options:nil];
|
||||
NSString *windowTitleKeyPath = [NSString stringWithFormat:@"%@.%@",
|
||||
NSStringFromSelector(@selector(objectValue)),
|
||||
NSStringFromSelector(@selector(windowTitle))];
|
||||
|
||||
[view.textField bind:NSValueBinding toObject:view withKeyPath:windowTitleKeyPath options:nil];
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" selectionHighlightStyle="sourceList" multipleSelection="NO" autosaveColumns="NO" rowHeight="24" rowSizeStyle="automatic" viewBased="YES" indentationPerLevel="16" outlineTableColumn="231" id="228" customClass="MPOutlineView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="272" height="449"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="272" height="0.0"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<size key="intercellSpacing" width="3" height="0.0"/>
|
||||
<color key="backgroundColor" name="_sourceListBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -92,6 +92,7 @@
|
||||
<constraint firstItem="241" firstAttribute="centerY" secondItem="240" secondAttribute="centerY" id="349"/>
|
||||
<constraint firstItem="243" firstAttribute="bottom" secondItem="241" secondAttribute="bottom" id="388"/>
|
||||
<constraint firstAttribute="trailing" secondItem="243" secondAttribute="trailing" constant="3" id="389"/>
|
||||
<constraint firstAttribute="trailing" secondItem="243" secondAttribute="trailing" constant="3" id="4Vg-BQ-zVQ"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outlet property="imageView" destination="241" id="247"/>
|
||||
|
||||
Reference in New Issue
Block a user