mirror of
https://github.com/MacPass/MacPass.git
synced 2025-12-13 19:22:25 +00:00
Attachments now can be dragged out onto the finder.
This commit is contained in:
@@ -72,7 +72,7 @@
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="124">
|
||||
<rect key="frame" x="241" y="428" width="32" height="25"/>
|
||||
<rect key="frame" x="241" y="428" width="32" height="23"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="32" id="176"/>
|
||||
</constraints>
|
||||
@@ -96,9 +96,9 @@
|
||||
<rect key="frame" x="20" y="26" width="253" height="396"/>
|
||||
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="F3N-QI-Di5">
|
||||
<rect key="frame" x="1" y="1" width="251" height="394"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnSelection="YES" multipleSelection="NO" autosaveColumns="NO" rowHeight="36" rowSizeStyle="automatic" viewBased="YES" id="137">
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" multipleSelection="NO" autosaveColumns="NO" rowHeight="36" rowSizeStyle="automatic" viewBased="YES" id="137">
|
||||
<rect key="frame" x="0.0" y="0.0" width="251" height="394"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<size key="intercellSpacing" width="3" height="2"/>
|
||||
@@ -172,7 +172,7 @@
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="42g-QS-XtW">
|
||||
<rect key="frame" x="205" y="5" width="40" height="25"/>
|
||||
<rect key="frame" x="205" y="6" width="40" height="23"/>
|
||||
<popUpButtonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" alignment="center" lineBreakMode="truncatingTail" borderStyle="border" imageScaling="proportionallyDown" inset="2" pullsDown="YES" altersStateOfSelectedItem="NO" id="nJc-UT-cas">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="menu"/>
|
||||
@@ -217,11 +217,11 @@
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="100" id="KFw-Ma-DSd"/>
|
||||
</constraints>
|
||||
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="138">
|
||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="138">
|
||||
<rect key="frame" x="1" y="147" width="52" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="139">
|
||||
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="139">
|
||||
<rect key="frame" x="37" y="1" width="16" height="2"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
@@ -342,7 +342,7 @@
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="59">
|
||||
<rect key="frame" x="20" y="519" width="251" height="25"/>
|
||||
<rect key="frame" x="20" y="520" width="251" height="23"/>
|
||||
<buttonCell key="cell" type="roundTextured" title="Generate" bezelStyle="texturedRounded" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="64">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
@@ -371,7 +371,7 @@
|
||||
</connections>
|
||||
</secureTextField>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="61">
|
||||
<rect key="frame" x="239" y="549" width="32" height="25"/>
|
||||
<rect key="frame" x="239" y="550" width="32" height="23"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="32" id="rSr-fw-11t"/>
|
||||
</constraints>
|
||||
@@ -398,7 +398,7 @@
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8">
|
||||
<rect key="frame" x="239" y="437" width="32" height="25"/>
|
||||
<rect key="frame" x="239" y="438" width="32" height="23"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="32" id="Ped-nx-uti"/>
|
||||
</constraints>
|
||||
@@ -456,7 +456,7 @@
|
||||
</connections>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="QSX-Xo-tcH">
|
||||
<rect key="frame" x="20" y="18" width="251" height="25"/>
|
||||
<rect key="frame" x="20" y="19" width="251" height="23"/>
|
||||
<buttonCell key="cell" type="roundTextured" title="Show Plugin Data" bezelStyle="texturedRounded" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="X9y-K7-lix">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
@@ -643,15 +643,15 @@
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="160" id="B8z-Sq-4j9"/>
|
||||
</constraints>
|
||||
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="Y4S-4R-dwJ">
|
||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="Y4S-4R-dwJ">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="abK-py-K7A">
|
||||
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="abK-py-K7A">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
</scrollView>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Iy9-9L-Aev">
|
||||
<rect key="frame" x="249" y="106" width="32" height="25"/>
|
||||
<rect key="frame" x="249" y="107" width="32" height="23"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="32" id="mjs-Yf-Cb2"/>
|
||||
</constraints>
|
||||
@@ -664,7 +664,7 @@
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="AAj-Ak-z46">
|
||||
<rect key="frame" x="209" y="106" width="32" height="25"/>
|
||||
<rect key="frame" x="209" y="107" width="32" height="23"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="32" id="vWY-ez-gy9"/>
|
||||
</constraints>
|
||||
@@ -721,7 +721,7 @@
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="m1C-m8-BKR">
|
||||
<rect key="frame" x="249" y="8" width="32" height="25"/>
|
||||
<rect key="frame" x="249" y="9" width="32" height="23"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="32" id="Ek5-IH-qGo"/>
|
||||
</constraints>
|
||||
@@ -734,7 +734,7 @@
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="HDS-Bz-jrr">
|
||||
<rect key="frame" x="249" y="325" width="32" height="25"/>
|
||||
<rect key="frame" x="249" y="326" width="32" height="23"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="32" id="CbR-2P-dZH"/>
|
||||
</constraints>
|
||||
@@ -844,7 +844,7 @@
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="198">
|
||||
<rect key="frame" x="190" y="8" width="32" height="25"/>
|
||||
<rect key="frame" x="190" y="9" width="32" height="23"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="32" id="215"/>
|
||||
</constraints>
|
||||
@@ -854,7 +854,7 @@
|
||||
</buttonCell>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="tDI-EL-JGB">
|
||||
<rect key="frame" x="150" y="8" width="32" height="25"/>
|
||||
<rect key="frame" x="150" y="9" width="32" height="23"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="32" id="JGO-sl-fdM"/>
|
||||
</constraints>
|
||||
@@ -889,12 +889,13 @@
|
||||
</tableColumns>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<nil key="backgroundColor"/>
|
||||
</clipView>
|
||||
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="192">
|
||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="192">
|
||||
<rect key="frame" x="1" y="130" width="259" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="191">
|
||||
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="191">
|
||||
<rect key="frame" x="224" y="17" width="15" height="102"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
|
||||
@@ -21,11 +21,13 @@
|
||||
//
|
||||
|
||||
#import "MPAttachmentTableDataSource.h"
|
||||
#import "KPKBinary+MPAdditions.h"
|
||||
#import "MPDocument.h"
|
||||
|
||||
@implementation MPAttachmentTableDataSource
|
||||
|
||||
- (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id<NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)dropOperation {
|
||||
/* allow drag between databases? */
|
||||
NSPasteboard *draggingPasteBoard = [info draggingPasteboard];
|
||||
NSArray *arrayOfURLs = [draggingPasteBoard readObjectsForClasses:@[NSURL.class] options:nil];
|
||||
NSUInteger numberOfDirectories = 0;
|
||||
@@ -33,7 +35,7 @@
|
||||
if(url.fileURL || url.fileReferenceURL) {
|
||||
NSError *error = nil;
|
||||
NSDictionary *resourceKeys = [url resourceValuesForKeys:@[NSURLIsDirectoryKey] error:&error];
|
||||
if( [resourceKeys[ NSURLIsDirectoryKey ] boolValue] == YES ) {
|
||||
if([resourceKeys[NSURLIsDirectoryKey] boolValue] == YES) {
|
||||
numberOfDirectories++;
|
||||
}
|
||||
continue;
|
||||
@@ -43,6 +45,10 @@
|
||||
if(numberOfDirectories == arrayOfURLs.count) {
|
||||
return NSDragOperationNone;
|
||||
}
|
||||
|
||||
if(dropOperation == NSTableViewDropOn) {
|
||||
[tableView setDropRow:row+1 dropOperation:NSTableViewDropAbove];
|
||||
}
|
||||
return NSDragOperationCopy;
|
||||
}
|
||||
|
||||
@@ -50,40 +56,67 @@
|
||||
MPDocument *document = tableView.window.windowController.document;
|
||||
KPKEntry *entry = document.selectedEntries.count == 1 ? document.selectedEntries.lastObject : nil;
|
||||
|
||||
NSPasteboard *draggingPasteBoard = [info draggingPasteboard];
|
||||
NSArray *arrayOfURLs = [draggingPasteBoard readObjectsForClasses:@[NSURL.class] options:nil];
|
||||
NSArray *arrayOfURLs = [info.draggingPasteboard readObjectsForClasses:@[NSURL.class] options:nil];
|
||||
|
||||
for(NSURL *fileUrl in arrayOfURLs) {
|
||||
[document addAttachment:fileUrl toEntry:entry];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(NSTableView *)tableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pboard {
|
||||
return NO;
|
||||
|
||||
/*
|
||||
NSString *extension;
|
||||
|
||||
if([rowIndexes count] != 1) {
|
||||
return NO; // We only work with one file at a time
|
||||
[pboard declareTypes:@[NSFilesPromisePboardType] owner:nil];
|
||||
MPDocument *document = tableView.window.windowController.document;
|
||||
KPKEntry *entry = document.selectedEntries.count == 1 ? document.selectedEntries.lastObject : nil;
|
||||
NSMutableArray *fileNames = [[NSMutableArray alloc] init];
|
||||
for(KPKBinary *binary in [entry.binaries objectsAtIndexes:rowIndexes]) {
|
||||
if(binary.name) {
|
||||
[fileNames addObject:binary.name];
|
||||
}
|
||||
}
|
||||
MPDocument *document = [[[tableView window] windowController] document];
|
||||
id entry = document.selectedEntry;
|
||||
NSUInteger row = [rowIndexes lastIndex];
|
||||
if([entry isKindOfClass:[Kdb3Entry class]]) {
|
||||
Kdb3Entry *entryV3 = (Kdb3Entry *)entry;
|
||||
extension = [entryV3.binaryDesc pathExtension];
|
||||
}
|
||||
else if([entry isKindOfClass:[Kdb4Entry class]]) {
|
||||
Kdb4Entry *entryV4 = (Kdb4Entry *)entry;
|
||||
BinaryRef *binaryRef = entryV4.binaries[row];
|
||||
extension = [binaryRef.key pathExtension];
|
||||
}
|
||||
NSString *uti = CFBridgingRelease(UTTypeCreatePreferredIdentifierForTag( kUTTagClassFilenameExtension, (__bridge CFStringRef)(extension), NULL ));
|
||||
|
||||
[pboard setPropertyList:@[uti] forType:(NSString *)kPasteboardTypeFilePromiseContent];
|
||||
[pboard setPropertyList:@[uti] forType:(NSString *)kPasteboardTypeFileURLPromise ];
|
||||
return YES;*/
|
||||
[pboard setPropertyList:fileNames forType:NSFilesPromisePboardType];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)tableView:(NSTableView *)tableView namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination forDraggedRowsWithIndexes:(NSIndexSet *)indexSet {
|
||||
MPDocument *document = tableView.window.windowController.document;
|
||||
KPKEntry *entry = document.selectedEntries.count == 1 ? document.selectedEntries.lastObject : nil;
|
||||
NSMutableArray<NSString *> *fileNames = [[NSMutableArray alloc] init];
|
||||
NSArray<KPKBinary *> *draggedBinaries = [entry.binaries objectsAtIndexes:indexSet];
|
||||
for(KPKBinary *binary in draggedBinaries) {
|
||||
if(binary.name) {
|
||||
[fileNames addObject:binary.name];
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0);
|
||||
dispatch_async(queue, ^{
|
||||
NSError *error;
|
||||
NSURL *saveLocation = [dropDestination URLByAppendingPathComponent:binary.name];
|
||||
BOOL success = [binary saveToLocation:saveLocation error:&error];
|
||||
if(!success && error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[NSApp presentError:error];
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return [fileNames copy];
|
||||
}
|
||||
|
||||
/*
|
||||
- (id<NSPasteboardWriting>)tableView:(NSTableView *)tableView pasteboardWriterForRow:(NSInteger)row {
|
||||
MPDocument *document = tableView.window.windowController.document;
|
||||
KPKEntry *entry = document.selectedEntries.count == 1 ? document.selectedEntries.lastObject : nil;
|
||||
|
||||
if(!entry) {
|
||||
return nil;
|
||||
}
|
||||
if (@available(macOS 10.12, *)) {
|
||||
KPKBinary *binary = entry.binaries[row];
|
||||
NSFilePromiseProvider *provider = [[NSFilePromiseProvider alloc] initWithFileType:(NSString *)kUTTypeXML delegate:binary];
|
||||
return provider;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
*/
|
||||
|
||||
@end
|
||||
|
||||
@@ -131,6 +131,7 @@ typedef NS_ENUM(NSUInteger, MPEntryTab) {
|
||||
self.attachmentTableView.delegate = _attachmentTableDelegate;
|
||||
self.attachmentTableView.dataSource = _attachmentDataSource;
|
||||
[self.attachmentTableView registerForDraggedTypes:@[NSFilenamesPboardType]];
|
||||
[self.attachmentTableView setDraggingSourceOperationMask:NSDragOperationCopy forLocal:NO];
|
||||
|
||||
/* extract custom field table view */
|
||||
NSView *customFieldTableView = self.customFieldsTableView;
|
||||
|
||||
@@ -34,6 +34,10 @@
|
||||
// FIXME: change drag image to use only the first column regardless of drag start
|
||||
|
||||
- (id<NSPasteboardWriting>)tableView:(NSTableView *)tableView pasteboardWriterForRow:(NSInteger)row {
|
||||
if(MPDisplayModeEntries != self.viewController.displayMode) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
id item = self.viewController.entryArrayController.arrangedObjects[row];
|
||||
if([item isKindOfClass:KPKEntry.class]) {
|
||||
return item;
|
||||
@@ -41,7 +45,16 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)tableView:(NSTableView *)tableView draggingSession:(NSDraggingSession *)session willBeginAtPoint:(NSPoint)screenPoint forRowIndexes:(nonnull NSIndexSet *)rowIndexes {
|
||||
session.draggingFormation = NSDraggingFormationList;
|
||||
}
|
||||
|
||||
- (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id<NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)dropOperation {
|
||||
/* we do not accept drops if we are in history or search display mode */
|
||||
if(MPDisplayModeEntries != self.viewController.displayMode) {
|
||||
return NSDragOperationNone;
|
||||
}
|
||||
|
||||
BOOL makeCopy = (info.draggingSourceOperationMask == NSDragOperationCopy);
|
||||
if(dropOperation == NSTableViewDropOn) {
|
||||
[tableView setDropRow:row+1 dropOperation:NSTableViewDropAbove];
|
||||
@@ -49,8 +62,48 @@
|
||||
return makeCopy ? NSDragOperationCopy : NSDragOperationMove;
|
||||
}
|
||||
|
||||
- (void)tableView:(NSTableView *)tableView draggingSession:(NSDraggingSession *)session willBeginAtPoint:(NSPoint)screenPoint forRowIndexes:(nonnull NSIndexSet *)rowIndexes {
|
||||
session.draggingFormation = NSDraggingFormationList;
|
||||
- (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id<NSDraggingInfo>)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)dropOperation {
|
||||
/* local drag */
|
||||
BOOL copyItems = info.draggingSourceOperationMask == NSDragOperationCopy;
|
||||
MPDocument *document = tableView.window.windowController.document;
|
||||
if(document.currentTargetGroups.count != 1) {
|
||||
return NO;
|
||||
}
|
||||
KPKGroup *targetGroup = document.currentTargetGroups.firstObject;
|
||||
if(info.draggingSource == tableView) {
|
||||
if(copyItems) {
|
||||
for(NSUUID *entryUUID in [self _readEntryUUIDsFromPasterboard:info.draggingPasteboard].reverseObjectEnumerator) {
|
||||
KPKEntry *entry = [[document findEntry:entryUUID] copyWithTitle:nil options:kKPKCopyOptionNone];
|
||||
[entry addToGroup:targetGroup atIndex:row];
|
||||
[entry.undoManager setActionName:NSLocalizedString(@"COPY_ENTRY", @"Action name when an entry was moved")];
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(NSUUID *entryUUID in [self _readEntryUUIDsFromPasterboard:info.draggingPasteboard].reverseObjectEnumerator) {
|
||||
KPKEntry *entry = [document findEntry:entryUUID];
|
||||
[entry moveToGroup:entry.parent atIndex:row];
|
||||
[entry.undoManager setActionName:NSLocalizedString(@"MOVE_ENTRY", @"Action name when an entry was moved")];
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
else {
|
||||
// external drop
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSArray<NSUUID *> *)_readEntryUUIDsFromPasterboard:(NSPasteboard *)pasteboard {
|
||||
if([pasteboard.types containsObject:KPKEntryUUDIUTI]) {
|
||||
if([pasteboard canReadObjectForClasses:@[NSUUID.class] options:nil]) {
|
||||
return [pasteboard readObjectsForClasses:@[NSUUID.class] options:nil];
|
||||
}
|
||||
}
|
||||
return @[];
|
||||
}
|
||||
|
||||
- (NSArray<KPKEntry *> *)_readEntriesFromPasteboard:(NSPasteboard *)pasteboard {
|
||||
return @[];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user