Drag-and-drop pasteboard data - cocoa

I'm trying to write some simple code to drag-and-drop the contents of a text file onto a window. With some help from an earlier post and an Apple example I've now got the basics of drag-and-drop up and running.
Unfortunately however, Apple's sample code deals only with images. Can anyone please tell me how I'd modify their "pasteboard" method (shown below) to send the contents of a simple 'dot.txt' file?
- (void)pasteboard:(NSPasteboard*)sender provideDataForType:(NSString*)type
{
//------------------------------------------------------
// method called by pasteboard to support promised drag types.
//--------------------------------------------------------
//sender has accepted the drag and now we need to send the data for the type we promised
if([type compare: NSTIFFPboardType]==NSOrderedSame)
{
//set data for TIFF type on the pasteboard as requested
[sender setData:[[self image] TIFFRepresentation] forType:NSTIFFPboardType];
}
else if([type compare: NSPDFPboardType]==NSOrderedSame)
{
[sender setData:[self dataWithPDFInsideRect:[self bounds]] forType:NSPDFPboardType];
}
}
Thanks :-)

Can anyone please tell me how I'd modify their "pasteboard" method (shown below) to send the contents of a simple 'dot.txt' file?
The caller is asking you to send data of a certain type. If you can provide data of that type, do so by putting it on the pasteboard. If you can't, do nothing.

Related

How Do I Add Other Pasteboard Types to an HFS Promise Drag in Cocoa?

I'm trying to kick off a drag in my Mac app. I want the drag to offer both a native UTI, and also a file promise, so that the user can drag a clipping to the desktop.
According to Apple's obsolete documentation, the way to achieve this is:
Kick off the "promise" drag with dragPromisedFilesOfTypes:fromRect:source:slideBack:event:
Add additional pasteboard types by overriding dragImage:at:offset:event:pasteboard:source:slideBack:
The problem with this is that Apple has since replaced AppKit's dragImage: method with beginDraggingSession: ...and dragPromisedFilesOfTypes: does not appear to call it.
What's the best way to go about this now?
So it looks like you have to set up the promise yourself. For example:
let writer = NSPasteboardItem()
// We can provide "MP3" data, and/or a "File promise"
writer.setDataProvider(
data_source,
forTypes: [ kUTTypeMP3, kPasteboardTypeFileURLPromise]
)
// If the receiver wants the "File promise", we'll
// be writing a "CAF file" for them
writer.setString( AVFileTypeCoreAudioFormat, forType: kPasteboardTypeFilePromiseContent )
let drag_item = NSDraggingItem( pasteboardWriter: writer )
let drag_session = self.beginDraggingSession( with: [drag_item], event: event, source: self )
In this example, I set up a normal drag that can provide an MP3 immediately, or a promise for a CAF file.
By kicking off the drag in such a manner, "namesOfPromisedFilesDropped:" gets called, just as it would with "dragPromisedFilesOfTypes:" but we also have the ability to set non-promise content.
Edit: Thanks to jnadeau for pointing out that macOS 10.12 adds "NSFilePromiseProvider" which is probably simpler. I need to support 10.10 and 10.11, but I mention this in case someone else finds it useful.

How to Fix Error: Incompatible Pointer Types Assigning to

Let me preface this by saying I'm new so I might not be the best at asking questions but here it goes. I am getting this error when I hit build in XCode with this code.
-(IBAction)unwindToRecipeDetails:(UIStoryboardSegue*)segue
{
ChangeRecipeDetailViewController *source = [segue sourceViewController];
recipeLabel = source.textView; // error: Incompatible Pointer Types Assigning to UILabel from UITextField
}
Here's what I'm trying to do. I based the code off of this snippet which works...
-(IBAction)unwindToRecipeBook:(UIStoryboardSegue *)segue;
{
AddRecipeViewController *source = [segue sourceViewController];
RecipeItem *item = source.recipeItem;
}
This is supposed to make AddRecipeViewController the data source for the initial RecipeBook page when the user navigates backward. I'm trying to implement the same thing for when a user navigates backward from the ChangeRecipe page to the RecipeDetails page.
Apparently I mixed two different types of code in the error, UILabel and UITextField. I get that they are incompatible but what could I change either one to in order to make it work. It is a little different than what I am basing my code off of in that I don't just want to transfer the same text, I want to change its format as well.
Again, I'm new at this so if anyone needs more information I'll gladly post it. Thanks.
Update 1: Palpatim: Thank you. Your solution worked. So to clarify, in order to transfer text I have to put .text after the initial source. This combines two unlike objects and transfers only text to text. Is this correct? I'm new at coding and am just trying to learn.
Philip Mills: I meant I wanted to change the format of the text when I transfer it from something that is editable like a textview to something static like a label.
Thanks for the help.

How can I intercept the result of openDocument before NSDocument loads?

I am writing a program which will load and process XML data. If the XML file contains a single XML 'Dictionary' then it will need to open an NSDocument window (so far, so good - I can do this!), but if the XML file contains an array of Dictionaries then it should open up a list window, from which the individual Dictionaries can be opened into an NSDocument.
Because File->Open sends an action to First Responder->openDocument before the document window opens, I think that the openDocument function is not part of NSDocument. I'd like, therefore, to be able to intercept the open function before it hands off to NSDocument - just to check if the document is one that I want to be opening as a document rather than as my natty list view.
If, on the other hand, openDocument is an NSDocument function, how can I quietly close the NSDocument window and hand the XML list to my list window without raising an error in this one scenario? Of course, I don't want to suppress errors altogether - because there may be legitimate reasons to raise an error (unreadable file, bad syntax etc)
I realise that what I'm trying to do is a little unorthodox - but hopefully its possible. Any ideas?
openDocument: is an instance method of NSDocumentController.
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSDocumentController_Class/Reference/Reference.html#//apple_ref/doc/uid/20000030-openDocument_
You can subclass the NSDocumentController with your own. This will allow you to intercept openDocument:.
If you want to check the file before creating a document, you'll need to use NSOpenPanel for the open file dialog. Then call openDocumentWithContentsOfURL:display:completionHandler: when you want to create the document. If you don't want to create the document, you can trigger whatever you want to do instead.
Just add a function to handle openDocument to your app delegate
func openDocument(sender: AnyObject) {
print("openDocument got called")
}
run app and press cmd+o

Core data app does not save my data, why?

I am writing my first core data app. For some reason, my edits are gone after quitting and restarting the app. Saving, closing window, and re-opening (without quitting) retains the data. If I open the saved file in textedit, I see my edited field. Something must go wrong during reading. Perhaps I forgot to change a setting somewhere? Does anyone recognize this behavior?
Are you saving the NSManagedObjectContext after making changes to your model objects?
Try
NSError *error;
if (![myContext save:&error]) {
// Handle error
}
The save message returns a BOOL for success. You should check that value to see if the save was successful. If not, the NSError reference that you pass in will contain information on why the save may have failed.
If you post your code, I might be able to help further.
The array controllers should have "prepares content" turned on. Otherwise, loading does not populate the array, and another save permentently removes the edits!

Cocoa Drag and Drop, reading back the data

Ok, I have a NSOutlineView set up, and I want it to capture PDF's if a pdf is dragged into the NSOutlineView.
My first question, I have the following code:
[outlineView registerForDraggedTypes:[NSArray arrayWithObjects:NSStringPboardType, NSFilenamesPboardType, nil]];
In all the apple Docs and examples I've seen I've also seen something like MySupportedType being an object registered for dragging. What does this mean? Do I change the code to be:
[outlineView registerForDraggedTypes:[NSArray arrayWithObjects:#"pdf", NSStringPboardType, NSFilenamesPboardType, nil]];
Currently I have it set up to recognize drag and drop, and I can even make it spit out the URL of the dragged file once the drag is accepted, however, this leads me to my second question. I want to keep a copy of those PDF's app side. I suppose, and correct me if I'm wrong, that the best way to do this is to grab the data off the clipboard, save it in some persistant store, and that's that. (as apposed to using some sort of copy command and literally copying the file to the app director.)
That being said, I'm not sure how to do that. I've the code:
- (BOOL)outlineView:(NSOutlineView *)ov acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(NSInteger)childIndex
{
NSPasteboard *pboard = [info draggingPasteboard];
NSURL *fileURL;
if ( [[pboard types] containsObject:NSURLPboardType] ) {
fileURL = [NSURL URLFromPasteboard:pboard];
// Perform operation using the file’s URL
}
NSData *data = [pboard dataForType:#"NSPasteboardTypePDF"];
But this never actually gets any data. Like I said before, it does get the URL, just not the data.
Does anyone have any advise on how to get this going? Thanks so much!
Dragged Types
Dragged types are just strings that define a system pasteboard type (like NSFilenamesPboardType) or your app's own internal type (like "MyWidgetIdentifierType" to identify a widget by some internal ID).
A drag type of "PDF" doesn't get you anything. You might as well call it "Bob8374Type" ... if you don't give your app the ability to recognize the type (or nothing ever puts anything into the pasteboard for that type), it's utterly useless. You're working with dragged files, so NSFilenamesPboardType is correct.
NSPasteboardTypePDF won't help you unless there is NSPasteboardTypePDF data on the pasteboard. When files are dragged, you get NSFilenamesPboardType. Doesn't matter if the file is .pdf or .xyz; you're only getting paths.
Copy the File or Store a Path
You need to decide whether you intend to copy the dropped PDF or just store a path (or better yet, file system reference) to it. If you're going to copy the PDF, you'll need to make sure you're aware of the proper storage locations (like the Application Support folder, etc).
Assuming you really do want to copy the dropped pdfs somewhere, you don't need the PDF data. You can use NSFileManager to copy (or move) the file at the given path to a new location. If you have some other storage mechanism (ie, you want to suck the PDF data of the file into some other data structure), you can just get the PDF data directly using NSData's +dataWithContentsOfURL:options:error: and do with its data what you please.

Resources