Changed drag and drop architecture to use pasteboard and encoded entries/groups

First steps to enhance drag and drop to for cross document dragging and inter-document copying
This commit is contained in:
michael starke
2013-09-15 23:41:02 +02:00
parent bd9587dddd
commit 64e56fd876
4 changed files with 138 additions and 170 deletions

View File

@@ -50,7 +50,6 @@
<int key="NSvFlags">268</int> <int key="NSvFlags">268</int>
<string key="NSFrame">{{57, 409}, {204, 17}}</string> <string key="NSFrame">{{57, 409}, {204, 17}}</string>
<reference key="NSSuperview" ref="233312071"/> <reference key="NSSuperview" ref="233312071"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="45251842"/> <reference key="NSNextKeyView" ref="45251842"/>
<string key="NSReuseIdentifierKey">_NS:1535</string> <string key="NSReuseIdentifierKey">_NS:1535</string>
<string key="NSAntiCompressionPriority">{249, 750}</string> <string key="NSAntiCompressionPriority">{249, 750}</string>
@@ -100,7 +99,6 @@
</set> </set>
<string key="NSFrame">{{20, 401}, {32, 32}}</string> <string key="NSFrame">{{20, 401}, {32, 32}}</string>
<reference key="NSSuperview" ref="233312071"/> <reference key="NSSuperview" ref="233312071"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="990836775"/> <reference key="NSNextKeyView" ref="990836775"/>
<string key="NSReuseIdentifierKey">_NS:9</string> <string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="NSEnabled">YES</bool> <bool key="NSEnabled">YES</bool>
@@ -126,10 +124,10 @@
<array class="NSMutableArray" key="NSSubviews"> <array class="NSMutableArray" key="NSSubviews">
<object class="NSButton" id="830540359"> <object class="NSButton" id="830540359">
<reference key="NSNextResponder" ref="381395509"/> <reference key="NSNextResponder" ref="381395509"/>
<int key="NSvFlags">-2147483380</int> <int key="NSvFlags">268</int>
<string key="NSFrame">{{20, 2}, {172, 25}}</string> <string key="NSFrame">{{20, 2}, {42, 25}}</string>
<reference key="NSSuperview" ref="381395509"/> <reference key="NSSuperview" ref="381395509"/>
<reference key="NSWindow"/> <reference key="NSNextKeyView"/>
<string key="NSReuseIdentifierKey">_NS:22</string> <string key="NSReuseIdentifierKey">_NS:22</string>
<bool key="NSEnabled">YES</bool> <bool key="NSEnabled">YES</bool>
<object class="NSButtonCell" key="NSCell" id="348505851"> <object class="NSButtonCell" key="NSCell" id="348505851">
@@ -139,12 +137,8 @@
<reference key="NSSupport" ref="240853158"/> <reference key="NSSupport" ref="240853158"/>
<string key="NSCellIdentifier">_NS:22</string> <string key="NSCellIdentifier">_NS:22</string>
<reference key="NSControlView" ref="830540359"/> <reference key="NSControlView" ref="830540359"/>
<int key="NSButtonFlags">918306816</int> <int key="NSButtonFlags">-2034483200</int>
<int key="NSButtonFlags2">163</int> <int key="NSButtonFlags2">163</int>
<object class="NSCustomResource" key="NSNormalImage">
<string key="NSClassName">NSImage</string>
<string key="NSResourceName">07_NotepadTemplate</string>
</object>
<string key="NSAlternateContents"/> <string key="NSAlternateContents"/>
<string key="NSKeyEquivalent"/> <string key="NSKeyEquivalent"/>
<int key="NSPeriodicDelay">400</int> <int key="NSPeriodicDelay">400</int>
@@ -155,7 +149,6 @@
</array> </array>
<string key="NSFrameSize">{278, 30}</string> <string key="NSFrameSize">{278, 30}</string>
<reference key="NSSuperview" ref="233312071"/> <reference key="NSSuperview" ref="233312071"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="830540359"/> <reference key="NSNextKeyView" ref="830540359"/>
<string key="NSReuseIdentifierKey">_NS:9</string> <string key="NSReuseIdentifierKey">_NS:9</string>
<string key="NSClassName">HNHGradientView</string> <string key="NSClassName">HNHGradientView</string>
@@ -165,7 +158,7 @@
<int key="NSvFlags">12</int> <int key="NSvFlags">12</int>
<string key="NSFrame">{{0, 30}, {278, 369}}</string> <string key="NSFrame">{{0, 30}, {278, 369}}</string>
<reference key="NSSuperview" ref="233312071"/> <reference key="NSSuperview" ref="233312071"/>
<reference key="NSWindow"/> <reference key="NSNextKeyView" ref="906788312"/>
<string key="NSReuseIdentifierKey">_NS:9</string> <string key="NSReuseIdentifierKey">_NS:9</string>
<array class="NSMutableArray" key="NSTabViewItems"> <array class="NSMutableArray" key="NSTabViewItems">
<object class="NSTabViewItem" id="367063082"> <object class="NSTabViewItem" id="367063082">
@@ -175,7 +168,7 @@
<int key="NSvFlags">256</int> <int key="NSvFlags">256</int>
<string key="NSFrameSize">{278, 369}</string> <string key="NSFrameSize">{278, 369}</string>
<reference key="NSSuperview" ref="45251842"/> <reference key="NSSuperview" ref="45251842"/>
<reference key="NSWindow"/> <reference key="NSNextKeyView" ref="381395509"/>
<string key="NSReuseIdentifierKey">_NS:28</string> <string key="NSReuseIdentifierKey">_NS:28</string>
</object> </object>
<string key="NSLabel">Entry</string> <string key="NSLabel">Entry</string>
@@ -253,7 +246,6 @@
</array> </array>
<string key="NSFrameSize">{278, 443}</string> <string key="NSFrameSize">{278, 443}</string>
<reference key="NSSuperview"/> <reference key="NSSuperview"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="621131831"/> <reference key="NSNextKeyView" ref="621131831"/>
<string key="NSReuseIdentifierKey">_NS:9</string> <string key="NSReuseIdentifierKey">_NS:9</string>
<string key="NSClassName">NSView</string> <string key="NSClassName">NSView</string>
@@ -956,110 +948,17 @@
<nil key="activeLocalization"/> <nil key="activeLocalization"/>
<dictionary class="NSMutableDictionary" key="localizations"/> <dictionary class="NSMutableDictionary" key="localizations"/>
<nil key="sourceID"/> <nil key="sourceID"/>
<int key="maxID">3116</int> <int key="maxID">3117</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<array class="NSMutableArray" key="referencedPartialClassDescriptions">
<object class="IBPartialClassDescription">
<string key="className">HNHGradientView</string>
<string key="superclassName">NSView</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">./Classes/HNHGradientView.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">MPInspectorViewController</string>
<string key="superclassName">MPViewController</string>
<object class="NSMutableDictionary" key="actions">
<string key="NS.key.0">showImagePopup:</string>
<string key="NS.object.0">id</string>
</object>
<object class="NSMutableDictionary" key="actionInfosByName">
<string key="NS.key.0">showImagePopup:</string>
<object class="IBActionInfo" key="NS.object.0">
<string key="name">showImagePopup:</string>
<string key="candidateClassName">id</string>
</object>
</object>
<dictionary class="NSMutableDictionary" key="outlets">
<string key="bottomBar">HNHGradientView</string>
<string key="createdTextField">NSTextField</string>
<string key="itemImageView">MPPopupImageView</string>
<string key="itemNameTextField">NSTextField</string>
<string key="modifiedTextField">NSTextField</string>
<string key="noSelectionInfo">NSTextField</string>
<string key="tabView">NSTabView</string>
</dictionary>
<dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
<object class="IBToOneOutletInfo" key="bottomBar">
<string key="name">bottomBar</string>
<string key="candidateClassName">HNHGradientView</string>
</object>
<object class="IBToOneOutletInfo" key="createdTextField">
<string key="name">createdTextField</string>
<string key="candidateClassName">NSTextField</string>
</object>
<object class="IBToOneOutletInfo" key="itemImageView">
<string key="name">itemImageView</string>
<string key="candidateClassName">MPPopupImageView</string>
</object>
<object class="IBToOneOutletInfo" key="itemNameTextField">
<string key="name">itemNameTextField</string>
<string key="candidateClassName">NSTextField</string>
</object>
<object class="IBToOneOutletInfo" key="modifiedTextField">
<string key="name">modifiedTextField</string>
<string key="candidateClassName">NSTextField</string>
</object>
<object class="IBToOneOutletInfo" key="noSelectionInfo">
<string key="name">noSelectionInfo</string>
<string key="candidateClassName">NSTextField</string>
</object>
<object class="IBToOneOutletInfo" key="tabView">
<string key="name">tabView</string>
<string key="candidateClassName">NSTabView</string>
</object>
</dictionary>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">./Classes/MPInspectorViewController.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">MPPopupImageView</string>
<string key="superclassName">NSImageView</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">./Classes/MPPopupImageView.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">MPViewController</string>
<string key="superclassName">NSViewController</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">./Classes/MPViewController.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">NSLayoutConstraint</string>
<string key="superclassName">NSObject</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">./Classes/NSLayoutConstraint.h</string>
</object>
</object>
</array>
</object> </object>
<object class="IBClassDescriber" key="IBDocument.Classes"/>
<int key="IBDocument.localizationMode">0</int> <int key="IBDocument.localizationMode">0</int>
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string> <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool> <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
<int key="IBDocument.defaultPropertyAccessControl">3</int> <int key="IBDocument.defaultPropertyAccessControl">3</int>
<dictionary class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes"> <object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
<string key="07_NotepadTemplate">{128, 128}</string> <string key="NS.key.0">NSActionTemplate</string>
<string key="NSActionTemplate">{15, 15}</string> <string key="NS.object.0">{15, 15}</string>
</dictionary> </object>
<bool key="IBDocument.UseAutolayout">YES</bool> <bool key="IBDocument.UseAutolayout">YES</bool>
</data> </data>
</archive> </archive>

View File

@@ -28,8 +28,8 @@
if(![item isKindOfClass:[KPKEntry class]]) { if(![item isKindOfClass:[KPKEntry class]]) {
return NO; return NO;
} }
KPKEntry *entry = (KPKEntry *)item; KPKEntry *draggedEntry = (KPKEntry *)item;
[pboard writeObjects:@[entry.uuid]]; [pboard writeObjects:@[draggedEntry]];
return YES; return YES;
} }

View File

@@ -18,8 +18,8 @@
@interface MPOutlineDataSource () @interface MPOutlineDataSource ()
@property (weak) KPKGroup *draggedGroup; @property (weak) KPKGroup *localDraggedGroup;
@property (weak) KPKEntry *draggedEntry; @property (weak) KPKEntry *localDraggedEntry;
@end @end
@@ -27,104 +27,173 @@
@implementation MPOutlineDataSource @implementation MPOutlineDataSource
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pasteboard { - (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pasteboard {
self.draggedGroup = nil;
if([items count] == 1) { if([items count] == 1) {
id item = [[items lastObject] representedObject]; id item = [[items lastObject] representedObject];
if(![item isKindOfClass:[KPKGroup class]]) { if(![item isKindOfClass:[KPKGroup class]]) {
return NO; return NO;
} }
[pasteboard setString:self.draggedGroup.name forType:KPKGroupUTI]; KPKGroup *draggedGroup = item;
self.draggedGroup = item; [pasteboard writeObjects:@[draggedGroup]];
return (nil != self.draggedGroup.parent); return (nil != draggedGroup.parent);
} }
return NO; return NO;
} }
- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id<NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index { - (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id<NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index {
/* Clean up our local search */
self.localDraggedEntry = nil;
self.localDraggedGroup = nil;
info.animatesToDestination = YES; info.animatesToDestination = YES;
NSDragOperation oprationMask = NSDragOperationMove; NSDragOperation operationMask = NSDragOperationMove;
/* /*
If we can support copy on drag, this can be used If we can support copy on drag, this can be used
to optain the dragging modifier mask the user presses to optain the dragging modifier mask the user presses
if([info draggingSourceOperationMask] == NSDragOperationCopy) {
oprationMask = NSDragOperationCopy;
}
*/ */
BOOL localCopy = NO;
NSPasteboard *pasteBoard = [info draggingPasteboard]; if([info draggingSourceOperationMask] == NSDragOperationCopy) {
NSArray *types = [pasteBoard types]; operationMask = NSDragOperationCopy;
if([types count] > 1 || [types count] == 0) { localCopy = YES;
return NSDragOperationNone; // We cannot work with more than one type
} }
/* Check if the Target is the root group */
id targetItem = [item representedObject]; id targetItem = [item representedObject];
if( ![targetItem isKindOfClass:[KPKGroup class]] && ![targetItem isKindOfClass:[KPKEntry class]]) { if( ![targetItem isKindOfClass:[KPKGroup class]] ) {
return NSDragOperationNone; // Block all unknown types return NSDragOperationNone; // Block all unknown types
} }
MPDocument *document = [[[outlineView window] windowController] document];
NSString *draggedType = [types lastObject]; NSPasteboard *pasteBoard = [info draggingPasteboard];
if([draggedType isEqualToString:KPKGroupUTI]) { KPKGroup *draggedGroup = nil;
// dragging group KPKEntry *draggedEntry = nil;
self.draggedEntry = nil; BOOL couldReadPasteboard = [self _readDataFromPasteboard:pasteBoard group:&draggedGroup entry:&draggedEntry];
} if(!couldReadPasteboard) {
else if([draggedType isEqualToString:KPKUUIDUTI]) { return NSDragOperationNone;
NSArray *uuids = [pasteBoard readObjectsForClasses:@[[NSUUID class]] options:nil];
if([uuids count] != 1) {
return NSDragOperationNone; // NO entry readable
}
self.draggedGroup = nil;
self.draggedEntry = [document findEntry:[uuids lastObject]];
}
else {
return NSDragOperationNone; // unkonw type
} }
KPKGroup *targetGroup = targetItem; KPKGroup *targetGroup = targetItem;
BOOL validTarget = YES; BOOL validTarget = YES;
if(self.draggedGroup) { MPDocument *document = [[[outlineView window] windowController] document];
if( self.draggedGroup == targetGroup ) { /* Dragging Groups */
if(draggedGroup) {
self.localDraggedGroup = [document findGroup:draggedGroup.uuid];
if( [draggedGroup.uuid isEqual:targetGroup.uuid] ) {
return NSDragOperationNone; // Groups cannot be moved inside themselves return NSDragOperationNone; // Groups cannot be moved inside themselves
} }
if( self.draggedGroup.parent == targetGroup ) { if(self.localDraggedGroup) {
validTarget &= index != NSOutlineViewDropOnItemIndex; if( self.localDraggedGroup.parent == targetGroup ) {
validTarget &= index != [self.draggedGroup.parent.groups indexOfObject:self.draggedGroup]; validTarget &= index != NSOutlineViewDropOnItemIndex;
validTarget &= index != [self.localDraggedGroup.parent.groups indexOfObject:self.localDraggedGroup];
}
BOOL isAnchesor = [self.localDraggedGroup isAnchestorOfGroup:targetGroup];
validTarget &= !isAnchesor;
}
else {
operationMask = NSDragOperationCopy;
} }
BOOL isAnchesor = [self.draggedGroup isAnchestorOfGroup:targetGroup];
validTarget &= !isAnchesor;
} }
else if(self.draggedEntry) { else if(draggedEntry) {
validTarget = self.draggedEntry.parent != targetGroup; self.localDraggedEntry = [document findEntry:draggedEntry.uuid];
[outlineView setDropItem:item dropChildIndex:NSOutlineViewDropOnItemIndex]; if(self.localDraggedEntry) {
/* local Copy is always valid regardless of parent */
validTarget = localCopy ? YES : self.localDraggedEntry.parent != targetGroup;
[outlineView setDropItem:item dropChildIndex:NSOutlineViewDropOnItemIndex];
}
else {
/* Entry copy is always valid */
operationMask = NSDragOperationCopy;
}
} }
return validTarget ? oprationMask : NSDragOperationNone; return validTarget ? operationMask : NSDragOperationNone;
} }
- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id<NSDraggingInfo>)info item:(id)item childIndex:(NSInteger)index { - (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id<NSDraggingInfo>)info item:(id)item childIndex:(NSInteger)index {
info.animatesToDestination = YES; info.animatesToDestination = YES;
NSPasteboard *pasteBoard = [info draggingPasteboard];
NSArray *types = [pasteBoard types];
if([types count] > 1 || [types count] == 0) {
return NO; // We cannot work with more than one type
}
id targetItem = [item representedObject]; id targetItem = [item representedObject];
if(![targetItem isKindOfClass:[KPKGroup class]]) { if(![targetItem isKindOfClass:[KPKGroup class]]) {
return NO; // Wrong return NO; // Wrong
} }
NSPasteboard *pasteBoard = [info draggingPasteboard];
KPKGroup *draggedGroup = nil;
KPKEntry *draggedEntry = nil;
BOOL validPateboard = [self _readDataFromPasteboard:pasteBoard group:&draggedGroup entry:&draggedEntry];
if(!validPateboard) {
return NO;
}
BOOL copyItem = ([info draggingSourceOperationMask] == NSDragOperationCopy);
KPKGroup *targetGroup = (KPKGroup *)targetItem; KPKGroup *targetGroup = (KPKGroup *)targetItem;
if(draggedGroup) {
if(copyItem || (nil == self.localDraggedGroup) ) {
/*
Scenarios:
a) Local copy
b) Drag from other document
*/
return NO;
}
else if(self.localDraggedGroup) {
/* Simple move */
[self.localDraggedGroup moveToGroup:targetGroup atIndex:index];
[self.localDraggedGroup.undoManager setActionName:NSLocalizedString(@"MOVE_GROUP", "")];
return YES;
}
/* Nothing valid */
return NO;
}
else if(draggedEntry) {
if(copyItem || (nil == self.localDraggedEntry)) {
/*
Scenarios:
a) Local copy
b) Drag from other document
*/
return NO;
}
else if(self.localDraggedEntry) {
[self.localDraggedEntry moveToGroup:targetGroup atIndex:index];
[self.localDraggedEntry.undoManager setActionName:NSLocalizedString(@"MOVE_ENTRY", "")];
return YES;
}
}
return NO;
}
- (BOOL)_readDataFromPasteboard:(NSPasteboard *)pasteboard group:(KPKGroup **)group entry:(KPKEntry **)entry;{
if(entry == NULL || group == NULL) {
return NO; // Need valid pointers
}
/* Cleanup old stuff */
NSArray *types = [pasteboard types];
if([types count] > 1 || [types count] == 0) {
return NO;
}
NSString *draggedType = [types lastObject]; NSString *draggedType = [types lastObject];
if([draggedType isEqualToString:KPKGroupUTI]) { if([draggedType isEqualToString:KPKGroupUTI]) {
[self.draggedGroup moveToGroup:targetGroup atIndex:index]; // dragging group
[self.draggedGroup.undoManager setActionName:NSLocalizedString(@"MOVE_GROUP", "")]; NSArray *groups = [pasteboard readObjectsForClasses:@[[KPKGroup class]] options:nil];
if([groups count] != 1) {
return NO;
}
*group = [groups lastObject];
return YES; return YES;
} }
else if([draggedType isEqualToString:KPKUUIDUTI]) { else if([draggedType isEqualToString:KPKEntryUTI]) {
[self.draggedEntry moveToGroup:targetGroup atIndex:index]; NSArray *entries = [pasteboard readObjectsForClasses:@[[KPKEntry class]] options:nil];
[self.draggedEntry.undoManager setActionName:NSLocalizedString(@"MOVE_ENTRY", "")]; if([entries count] != 1) {
return NO; // NO entry readable
}
*entry = [entries lastObject];
return YES; return YES;
} }
return NO; return NO;
} }
@end @end

View File

@@ -73,7 +73,7 @@ NSString *const _MPOutlinveViewHeaderViewIdentifier = @"HeaderCell";
[_outlineView setMenu:[self _contextMenu]]; [_outlineView setMenu:[self _contextMenu]];
[_outlineView setAllowsEmptySelection:YES]; [_outlineView setAllowsEmptySelection:YES];
[_outlineView setFloatsGroupRows:NO]; [_outlineView setFloatsGroupRows:NO];
[_outlineView registerForDraggedTypes:@[ KPKGroupUTI, KPKUUIDUTI ]]; [_outlineView registerForDraggedTypes:@[ KPKGroupUTI, KPKEntryUTI ]];
[_outlineView setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES]; [_outlineView setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES];
[_bottomBar setBorderType:HNHBorderTop]; [_bottomBar setBorderType:HNHBorderTop];
[_addGroupButton setAction:[MPActionHelper actionOfType:MPActionAddGroup]]; [_addGroupButton setAction:[MPActionHelper actionOfType:MPActionAddGroup]];