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

@@ -18,8 +18,8 @@
@interface MPOutlineDataSource ()
@property (weak) KPKGroup *draggedGroup;
@property (weak) KPKEntry *draggedEntry;
@property (weak) KPKGroup *localDraggedGroup;
@property (weak) KPKEntry *localDraggedEntry;
@end
@@ -27,104 +27,173 @@
@implementation MPOutlineDataSource
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pasteboard {
self.draggedGroup = nil;
if([items count] == 1) {
id item = [[items lastObject] representedObject];
if(![item isKindOfClass:[KPKGroup class]]) {
return NO;
}
[pasteboard setString:self.draggedGroup.name forType:KPKGroupUTI];
self.draggedGroup = item;
return (nil != self.draggedGroup.parent);
KPKGroup *draggedGroup = item;
[pasteboard writeObjects:@[draggedGroup]];
return (nil != draggedGroup.parent);
}
return NO;
}
- (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;
NSDragOperation oprationMask = NSDragOperationMove;
NSDragOperation operationMask = NSDragOperationMove;
/*
If we can support copy on drag, this can be used
to optain the dragging modifier mask the user presses
if([info draggingSourceOperationMask] == NSDragOperationCopy) {
oprationMask = NSDragOperationCopy;
}
*/
NSPasteboard *pasteBoard = [info draggingPasteboard];
NSArray *types = [pasteBoard types];
if([types count] > 1 || [types count] == 0) {
return NSDragOperationNone; // We cannot work with more than one type
BOOL localCopy = NO;
if([info draggingSourceOperationMask] == NSDragOperationCopy) {
operationMask = NSDragOperationCopy;
localCopy = YES;
}
/* Check if the Target is the root group */
id targetItem = [item representedObject];
if( ![targetItem isKindOfClass:[KPKGroup class]] && ![targetItem isKindOfClass:[KPKEntry class]]) {
if( ![targetItem isKindOfClass:[KPKGroup class]] ) {
return NSDragOperationNone; // Block all unknown types
}
MPDocument *document = [[[outlineView window] windowController] document];
NSString *draggedType = [types lastObject];
if([draggedType isEqualToString:KPKGroupUTI]) {
// dragging group
self.draggedEntry = nil;
}
else if([draggedType isEqualToString:KPKUUIDUTI]) {
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
NSPasteboard *pasteBoard = [info draggingPasteboard];
KPKGroup *draggedGroup = nil;
KPKEntry *draggedEntry = nil;
BOOL couldReadPasteboard = [self _readDataFromPasteboard:pasteBoard group:&draggedGroup entry:&draggedEntry];
if(!couldReadPasteboard) {
return NSDragOperationNone;
}
KPKGroup *targetGroup = targetItem;
BOOL validTarget = YES;
if(self.draggedGroup) {
if( self.draggedGroup == targetGroup ) {
MPDocument *document = [[[outlineView window] windowController] document];
/* Dragging Groups */
if(draggedGroup) {
self.localDraggedGroup = [document findGroup:draggedGroup.uuid];
if( [draggedGroup.uuid isEqual:targetGroup.uuid] ) {
return NSDragOperationNone; // Groups cannot be moved inside themselves
}
if( self.draggedGroup.parent == targetGroup ) {
validTarget &= index != NSOutlineViewDropOnItemIndex;
validTarget &= index != [self.draggedGroup.parent.groups indexOfObject:self.draggedGroup];
if(self.localDraggedGroup) {
if( self.localDraggedGroup.parent == targetGroup ) {
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) {
validTarget = self.draggedEntry.parent != targetGroup;
[outlineView setDropItem:item dropChildIndex:NSOutlineViewDropOnItemIndex];
else if(draggedEntry) {
self.localDraggedEntry = [document findEntry:draggedEntry.uuid];
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 {
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];
if(![targetItem isKindOfClass:[KPKGroup class]]) {
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;
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];
if([draggedType isEqualToString:KPKGroupUTI]) {
[self.draggedGroup moveToGroup:targetGroup atIndex:index];
[self.draggedGroup.undoManager setActionName:NSLocalizedString(@"MOVE_GROUP", "")];
// dragging group
NSArray *groups = [pasteboard readObjectsForClasses:@[[KPKGroup class]] options:nil];
if([groups count] != 1) {
return NO;
}
*group = [groups lastObject];
return YES;
}
else if([draggedType isEqualToString:KPKUUIDUTI]) {
[self.draggedEntry moveToGroup:targetGroup atIndex:index];
[self.draggedEntry.undoManager setActionName:NSLocalizedString(@"MOVE_ENTRY", "")];
else if([draggedType isEqualToString:KPKEntryUTI]) {
NSArray *entries = [pasteboard readObjectsForClasses:@[[KPKEntry class]] options:nil];
if([entries count] != 1) {
return NO; // NO entry readable
}
*entry = [entries lastObject];
return YES;
}
return NO;
}
@end