From bb4094f238baf4de92503c2ecf2a48f325b60d8f Mon Sep 17 00:00:00 2001 From: Matthias Neeracher Date: Mon, 22 Aug 2011 03:54:09 +0200 Subject: [PATCH] Implement copy & paste --- Medianno/MADocWindow.h | 1 + Medianno/MADocWindow.mm | 3 + Medianno/MADocument.mm | 7 ++- Medianno/MADragging.h | 11 +++- Medianno/MADragging.mm | 126 +++++++++++++++++++++++++++++++++++----- Medianno/MATagWindow.h | 2 + Medianno/MATagWindow.mm | 2 +- 7 files changed, 133 insertions(+), 19 deletions(-) diff --git a/Medianno/MADocWindow.h b/Medianno/MADocWindow.h index c490fd9..16bf838 100644 --- a/Medianno/MADocWindow.h +++ b/Medianno/MADocWindow.h @@ -38,6 +38,7 @@ - (IBAction)mediaSkipBackward:(id)sender; - (IBAction)mediaSkipForward:(id)sender; - (IBAction)toggleMediaPlay:(id)sender; +- (IBAction)delete:(id)sender; - (QTTime)currentMovieTime; - (void)moviePanelDidAppear; - (void)moviePanelDidClose; diff --git a/Medianno/MADocWindow.mm b/Medianno/MADocWindow.mm index d8bb2f2..cb4e3fe 100644 --- a/Medianno/MADocWindow.mm +++ b/Medianno/MADocWindow.mm @@ -282,6 +282,9 @@ static const char * kMADocWindowObserver = "MADocWindowObserver"; ) return YES; + if ([item action] == @selector(paste:)) + return [self canPaste]; + NSMenuItem * menuItem = (NSMenuItem *)item; if ([item action] == @selector(toggleMediaPlay:)) { if ([currentMovie rate] > 0.0f) diff --git a/Medianno/MADocument.mm b/Medianno/MADocument.mm index f9f7e9b..f1984a8 100644 --- a/Medianno/MADocument.mm +++ b/Medianno/MADocument.mm @@ -44,8 +44,11 @@ { NSString * path = [url absoluteString]; NSNumber * size; - [url getResourceValue:&size forKey:NSURLFileSizeKey error:nil]; - int64_t fileSize = [size longLongValue]; + int64_t fileSize; + if ([url getResourceValue:&size forKey:NSURLFileSizeKey error:nil]) + fileSize = [size longLongValue]; + else + fileSize = 0; NSTimeInterval fileDate = [date timeIntervalSinceReferenceDate]; NSManagedObjectContext *moc = [self managedObjectContext]; diff --git a/Medianno/MADragging.h b/Medianno/MADragging.h index b6dbe53..0424f26 100644 --- a/Medianno/MADragging.h +++ b/Medianno/MADragging.h @@ -9,10 +9,16 @@ #import #import "MADocWindow.h" #import "MATagWindow.h" +#import "MAAppController.h" @interface MADocWindow (Dragging) - (void)registerOurDragTypes; +- (BOOL)canPaste; + +- (IBAction)cut:(id)sender; +- (IBAction)copy:(id)sender; +- (IBAction)paste:(id)sender; @end @@ -20,4 +26,7 @@ - (void)registerOurDragTypes; -@end \ No newline at end of file +- (IBAction)cut:(id)sender; +- (IBAction)copy:(id)sender; + +@end diff --git a/Medianno/MADragging.mm b/Medianno/MADragging.mm index 1b9cb6f..147270f 100644 --- a/Medianno/MADragging.mm +++ b/Medianno/MADragging.mm @@ -15,12 +15,15 @@ #define kMADragType @"org.aereperennius.medianno" +static NSPointerArray * sValidPasteboardData; + @interface MAPasteboardData : NSObject { NSArray * contents; } - (id)initWithArray:(NSArray *)array; + (id)pasteboardDataWithArray:(NSArray *)array; ++ (NSArray *)arrayFromPasteboard:(NSPasteboard *)pboard; @end @@ -28,8 +31,13 @@ - (id)initWithArray:(NSArray *)array { + if (!sValidPasteboardData) + sValidPasteboardData = [[NSPointerArray alloc] initWithOptions:NSPointerFunctionsZeroingWeakMemory]; self = [super init]; contents = array; + if ([sValidPasteboardData count] > 10) + [sValidPasteboardData compact]; + [sValidPasteboardData addPointer:contents]; return self; } @@ -39,6 +47,17 @@ return [[[MAPasteboardData alloc] initWithArray:array] autorelease]; } ++ (NSArray *)arrayFromPasteboard:(NSPasteboard *)pboard +{ + if (NSNumber * drag = [pboard propertyListForType:kMADragType]) { + NSArray * possibleArray = (NSArray *)[drag longValue]; + for (NSUInteger count = [sValidPasteboardData count]; count--; ) + if ([sValidPasteboardData pointerAtIndex:count] == possibleArray) + return possibleArray; + } + return nil; +} + - (NSArray *)writableTypesForPasteboard:(NSPasteboard *)pasteboard { MAMedia * media; @@ -96,10 +115,30 @@ return YES; } -- (Class)classOfDraggedObjects:(id)drag +- (IBAction)copy:(id)sender { - NSArray * dragObjects = (NSArray *)[drag longValue]; + NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSGeneralPboard]; + NSResponder * responder = [[self window] firstResponder]; + while (responder && responder != self) { + if (responder == mediaTable) { + [self tableView:mediaTable writeRowsWithIndexes:[mediaController selectionIndexes] toPasteboard:pboard]; + break; + } else if (responder == annotationTable) { + [self tableView:annotationTable writeRowsWithIndexes:[annotationController selectionIndexes] toPasteboard:pboard]; + break; + } + responder = [responder nextResponder]; + } +} + +- (IBAction)cut:(id)sender +{ + [self copy:sender]; + [self delete:sender]; +} +- (Class)classOfDraggedObjects:(NSArray *)dragObjects +{ return [dragObjects count] ? [[dragObjects objectAtIndex:0] class] : nil; } @@ -110,9 +149,9 @@ // if (tableView == [info draggingSource]) return NSDragOperationNone; - NSPasteboard * pb = [info draggingPasteboard]; + NSPasteboard * pboard = [info draggingPasteboard]; id drag; - if ((drag = [pb propertyListForType:kMADragType])) { + if ((drag = [MAPasteboardData arrayFromPasteboard:pboard])) { // // We don't allow media drops in annotation table // @@ -131,11 +170,11 @@ } return NSDragOperationCopy; } else if (tableView == mediaTable) { - if ((drag = [pb propertyListForType:NSFilenamesPboardType])) { + if ((drag = [pboard propertyListForType:NSFilenamesPboardType])) { [tableView setDropRow:row dropOperation:NSTableViewDropAbove]; return NSDragOperationLink; - } else if ((drag = [pb stringForType:(NSString *)kUTTypeURL]) - || (drag = [pb stringForType:(NSString *)kUTTypeFileURL]) + } else if ((drag = [pboard stringForType:(NSString *)kUTTypeURL]) + || (drag = [pboard stringForType:(NSString *)kUTTypeFileURL]) ) { [tableView setDropRow:row dropOperation:NSTableViewDropAbove]; return NSDragOperationLink; @@ -146,7 +185,7 @@ - (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)dropOperation { - NSPasteboard * pb = [info draggingPasteboard]; + NSPasteboard * pboard = [info draggingPasteboard]; MADocument * doc = [self document]; MAMedia * media = nil; @@ -159,22 +198,69 @@ } id drag; - if ((drag = [pb propertyListForType:kMADragType])) { - for (id obj in (NSArray *)[drag longValue]) + if ((drag = [MAPasteboardData arrayFromPasteboard:pboard])) { + for (id obj in drag) [obj copyToDocument:doc withMedia:media]; - } else if ((drag = [pb propertyListForType:NSFilenamesPboardType])) { + } else if ((drag = [pboard propertyListForType:NSFilenamesPboardType])) { NSMutableArray * urls = [NSMutableArray array]; for (NSString * path in drag) [urls addObject:[NSURL fileURLWithPath:path]]; [self addMedia:urls]; - } else if ((drag = [pb stringForType:(NSString *)kUTTypeURL]) - || (drag = [pb stringForType:(NSString *)kUTTypeFileURL]) + } else if ((drag = [pboard stringForType:(NSString *)kUTTypeURL]) + || (drag = [pboard stringForType:(NSString *)kUTTypeFileURL]) ) { [self addMedia:[NSArray arrayWithObject:[NSURL URLWithString:drag]]]; } return YES; } +- (IBAction)paste:(id)sender +{ + NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSGeneralPboard]; + MADocument * doc = [self document]; + NSManagedObjectContext *moc = [doc managedObjectContext]; + + id drag; + if ((drag = [MAPasteboardData arrayFromPasteboard:pboard])) { + MAMedia * media = [self currentMedia]; + for (id obj in drag) + if ([obj managedObjectContext] != moc) + [obj copyToDocument:doc withMedia:media]; + } else if ((drag = [pboard propertyListForType:NSFilenamesPboardType])) { + NSMutableArray * urls = [NSMutableArray array]; + for (NSString * path in drag) + [urls addObject:[NSURL fileURLWithPath:path]]; + [self addMedia:urls]; + } else if ((drag = [pboard stringForType:(NSString *)kUTTypeURL]) + || (drag = [pboard stringForType:(NSString *)kUTTypeFileURL]) + ) { + [self addMedia:[NSArray arrayWithObject:[NSURL URLWithString:drag]]]; + } +} + +- (BOOL)canPaste +{ + NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSGeneralPboard]; + id drag; + if ((drag = [MAPasteboardData arrayFromPasteboard:pboard])) { + MAMedia * media = [self currentMedia]; + if (![drag count]) + return NO; + id obj = [drag objectAtIndex:0]; + if ([obj managedObjectContext] == [[self document] managedObjectContext]) + return NO; + else + return [obj class] != [MAAnno class] || media; + } else if ((drag = [pboard propertyListForType:NSFilenamesPboardType])) { + return YES; + } else if ((drag = [pboard stringForType:(NSString *)kUTTypeURL]) + || (drag = [pboard stringForType:(NSString *)kUTTypeFileURL]) + ) { + return YES; + } + return NO; +} + @end @implementation MATagWindow (Dragging) @@ -191,9 +277,19 @@ { NSArray * objects = [[tagController arrangedObjects] objectsAtIndexes:rowIndexes]; [pboard clearContents]; - [pboard writeObjects:[NSArray arrayWithObject:[MAPasteboardData pasteboardDataWithArray:objects]]]; - + [pboard writeObjects:[NSArray arrayWithObject:[MAPasteboardData pasteboardDataWithArray:objects]]]; return YES; } +- (IBAction)copy:(id)sender +{ + [self tableView:nil writeRowsWithIndexes:[tagController selectionIndexes] toPasteboard:[NSPasteboard pasteboardWithName:NSGeneralPboard]]; +} + +- (IBAction)cut:(id)sender +{ + [self copy:sender]; + [self delete:sender]; +} + @end diff --git a/Medianno/MATagWindow.h b/Medianno/MATagWindow.h index aa01d05..090f903 100644 --- a/Medianno/MATagWindow.h +++ b/Medianno/MATagWindow.h @@ -16,6 +16,8 @@ @property (assign) NSDocument * currentDocument; - (IBAction)toggleWindow:(id)sender; +- (IBAction)delete:(id)sender; + - (BOOL)validateUserInterfaceItem:(id )item; @end diff --git a/Medianno/MATagWindow.mm b/Medianno/MATagWindow.mm index 36e00af..468b999 100644 --- a/Medianno/MATagWindow.mm +++ b/Medianno/MATagWindow.mm @@ -48,7 +48,7 @@ if (![self isWindowLoaded] || ![[self window] isVisible]) return NO; - if ([item action] == @selector(delete:)) + if ([item action] == @selector(delete:) || [item action] == @selector(cut:) || [item action] == @selector(copy:)) return [tagController selectionIndex] != NSNotFound; return NO;