Dropping Files onto Dock Icon in Cocoa - cocoa

How can I drop a file(or select to open it in Finder) of a type specified in the Info.plist onto my dock icon and then calling a method with the full path of the file?

If you've set up your Info.plist's CFBundleDocumentTypes array properly (either 'LSItemContentTypes' or 'CFBundleTypeExtensions'), then you just need to set up an NSApplication delegate and implement the delegate method, application:openFile:.
If you're expecting multiple files to be dropped at once, implement application:openFiles:.
For promised files (NSFilesPromisePboardType/kPasteboardTypeFileURLPromise) see Dropping promised files on to application icon in Dock.

Here's an updated solution for Xcode 5.
In AppDelegate.m
-(BOOL)application:(NSApplication *)sender openFile:(NSString *)filename
{
NSLog(#"%#", filename);
return YES;
}
And in Xcode setup Document Types under Project > Targets > Info:
Check settings in Info.plist in case you have an empty 'Document Content Type UTIs' array which should be filled out properly or else deleted.
Your Info.plist should look something like this:

On current systems you can use a UTI instead of the old-style four-char types (such as fold above). In Xcode's document type editor, make a new type with:
Name: Folder
Identifier: public.folder
public.folder is a subtype of public.directory. public.folder matches directories that appear as such to the user, i.e. not packages like .app wrappers.

Select your application in the target group of the side pane and use get info. Then in the new window select the properties tab to add a new document type. Name it "Folder" for convenience and the OS Types needs to be "fold"; the store type and role you can leave as is.

If you're actually making a document-based app, setting it up to give you the path will have you doing far more work than you need to. Simply use the document-based application template. The document controller will create an instance of the right class for you; you need only write that class.
An application you create this way will handle file drops (by opening them as documents) for free.

Related

how to implement "show recents" item on OS 10.9 and later

I notice on Mac, every app on docker, when it's not opened and ctrl click it, there will be a pop-up menu, inside has a menu item called "show recents", when open the app this item will become "show all windows". I want to know how to make it work cuz right now, when I click it on my own app, it has nothing to show.
I have tested using doc controller and use noteNewRecentDocumentURL: method, but still, both "open recent" item in "file" and "show recents" in docker, it doesn't show my url I just added.
I do not know, where you click on the app to show the menu. The recent documents list is shown
in the app's File menu in the submenu Open Recent
in the dock menu for the app as a list with one item per document
likely at some other places related to the app
However where it is shown, the list is automatically managed by [NSDocumentController sharedDocumentController], which is added to the project template for document-based applications. If you do not have a document-based application you should re-check, whether this would be the better choice. But you can use [NSDocumentController sharedDocumentController] in a non-document-based application as well:
In some situations, it is worthwhile to subclass NSDocumentController in non-NSDocument-based applications to get some of its features. For example, the NSDocumentController management of the Open Recent menu is useful in applications that don’t use subclasses of NSDocument.
Documentation
There is a section Managing the Open Recent Menu containing the description of the method -noteNewRecentDocumentURL: in the documentation of NSDocumentController. You have to send this message to the shared instance,
whenever you want to add an item to the recent docs list:
[[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:theURLOfTheDocYourAppOpens];
Please note:
Applications not based on NSDocument must also implement the application:openFile: method in the application delegate to handle requests from the Open Recent menu command.
If you do not want to use the document controller, you have to maintain the list yourself and add it to the different locations manually. You can start here. I do not recommend that.
Here's code for use with Xamarin.Mac.
// Add the file to the menu. Note creation of file url.
void AddFileToOpenRecentMenu(string filePath)
{
var fileUrl = NSUrl.FromFilename(filePath);
NSDocumentController.SharedDocumentController.NoteNewRecentDocumentURL(fileUrl);
}
// Open the file selected from the menu (in AppDelegate.cs)
[Export("application:openFile:")]
public override bool OpenFile(NSApplication sender, string filename)
{
var keepFileInMenu = ProcessFile(filename);
return keepFileInMenu;
}

How to register a custom non-document UTI / file type for OSX to recognize it?

I've read all the tickets about this issue, but I still don't get it right. I have a non-document OSX app (for OSX Lion and MountainLion). I want this app to export and import custom data, associated with a custom file extension ".iobs". Internally, these files are just data archived with [NSKeyedArchiver archivedDataWithRootObject:], and saved onto the disk with the "iobs" extension.
So, my check list is this:
1) Export mechanism: checked. My app create correctly .iobs files. If I run "file <filename.iobs>" in the Terminal, I get "iObserve_exportedItems.iobs: Apple binary property list"
2) Declaration of an exported UTI, checked. As shown in the image below. I did NOT declared a custom Document type, since it I never use NSDocument inside my app, and there is no point. Anyway, I already tried and failed. I've tried also different combinations of "Conforms To" entries, but with no success.
3) Is there any 3rd point??? Do I need to start my app once to let the system know? I just ran it in Debug from Xcode so far, and this has no effect. So I guess my Info.plist is wrong, but I filled it from within Xcode4 interface, so???
Thanks for any help, hint, question, suggestion.
Ok, so apparently, I do have to declare a document type even if I don't specify a document class. See the attached screenshot. Note that leaving only the Document UTI doesn't work. I do need the two (exported UTI and document type). Note also that if I say it conforms to com.apple.binary-property-list, I don't have the right icon.
And for those who wonder, there is nothing to do to "register" a type (and its subsequent changes) apart from launching the app once.

file's owner of xib is not what i expect

i'm using xcode4.
i have a xib window (perhaps copyed by another one, i forgot because i have made it some times ago) named: chooseCharacter.xib
i have the chooseCharacter.h and .m as view controller (i thought)
i have added
-(IBAction)doneButtonClick;
on the chooseCharacter.h but i've not seen it in interface builder actions...
i have added this on HighScoreViewController.h and it now shows up...
however, if i put it on HighScoreViewController.h i must put the implementation in chooseCharacter.m or i get
-[ChooseCharacter doneButtonClick]: unrecognized selector sent to instance 0xcc0d9b0'
seems that the window is binded with a file's owner that is HighScoreViewController.h but search implementation in ChooseCharacter.m!!!
how can i bind the xib to the right file?
thanks
found it.
selecting in interface builder, file's owner and clicking in identity inspector under class was HighScoreViewController, changed to chooseCharacter now it works

How does Xcode setup a document based application?

I am learning Cocoa and my understanding from reading the documentation is that when an application starts the following happens:
A shared application instance is created.
The main nib file is looked up from the applications property list so that the application knows which nib to load.
the run loop is started.
This is fine and makes sense for s single windowed application however I am confused by what xcode does when a document based application is created.
In this case there are two nib files; the first contains the application menu and the second contains the window which represents the NSDocument subclass. when I run the application a new document window is opened automatically.
Based on my understanding of how the application works outlined above I don't understand how my application knows to open the document window once the menu nib has been looked up from the property list. There is no code generated to do this as far as I can see (except for the windowNibName method but where is this called from?)
Can anyone tell me what xcode does differently so that the application knows that it is document based and therefore needs to open a document window?
Update:
What I am trying to understand is how Xcode knows how to do something different if my application is set up as a document based application rather than a single window application. As far as I am aware there is no setting to specify this and Xcode doesn't appear to generate any code to give this different behaviour.
From reading the documents over the last couple of days I think I know how this works but am not sure:
_NSApplication_has a delegate method applicationOpensUntitledFile which is called by the applications delegate.
NSDocumentController is set as the applications delegate by default and the default implementation looks for the presence of the CFBundledTypeInfo to determine if the document is document based or not and responds as is appropriate for the application (I.E. YES for document based application and NO for single window applications).
The majority of the time when a single window application is created the application delegate is replaced by a custom AppController anyway which usually wont contain a definition for the applicationOpenUntitledFile method as it is not appropriate for the type of application.
Hopefully any Cocoa experts can confirm if my understanding is correct or if I am barking up the wrong tree.
When you create a document-based application, you get a few things:
A subclass of NSDocument
A new xib file for this document, in addition to MainMenu.xib
A CFBundleDocumentTypes entry in Info.plist, which tells the app about your NSDocument subclass
When your app opens, the shared NSDocumentController will create a new untitled document using the CFBundleDocumentTypes information.
For more information, read The Document-Based Application Project Template and the rest of the document-based applications guide.
I assume your right. If you create a non based document application, add the document types informations in the -Info.plist and set the delegate of NSApplication in the main.m as following
int main(int argc, const char * argv[])
{
[[NSApplication sharedApplication] setDelegate:[NSDocumentController sharedDocumentController]];
[[NSBundle mainBundle] loadNibNamed:#"MainMenu" owner:NSApp topLevelObjects:nil];
[NSApp run];
}
The behaviour seems to be the same as the the default Document-Based Application template.
No, your assumption is not right, look at the implementation of GNUstep version, in the NSApplication's finishLaunching method:
NSDocumentController *sdc;
sdc = [NSDocumentController sharedDocumentController];
if ([[sdc documentClassNames] count] > 0)
{
didAutoreopen = [sdc _reopenAutosavedDocuments];
}
So it create a instance of NSDocumentController automatically.

Where did the icon come from?

Is there a unix tool to which I can pass a file and have it tell me where the icon for the file is coming from?
What I am looking for is something like this:
$WhoProvidedIcon /Path/To/file.myex
UTI: com.myapplication.document
PLIST: /path/to/myapplication.app/Contents/Info.plist
ICON: /path/to/myapplication.app/Contents/Resources/BaseDoc.icns
Icons for most applications on Mac OSX are stored within the app bundle themselves. If you right click on the .app and then select Show Package Contents then go to Contents -> Resources you should see the icon in there.
There are at least three different place from which the OS will provide the icon.
In one situation, NSWorkspace can be used to help identify the location:
NSString* uti = [ws typeOfFile:#"/Users/egorr/Desktop/file.vwx" error:&error];
NSLog( #"UTI: %#", uti );
NSLog( #"UTI localized description: %#", [ws localizedDescriptionForType:uti] );
NSLog( #"UTI error description: %#",[error localizedDescription] );
NSURL* utiDeclarationURL = (NSURL*)UTTypeCopyDeclaringBundleURL( (CFStringRef)uti );
NSLog( #"UTI declaration URL: %#", utiDeclarationURL );
NSDictionary* utiDeclaration = (NSDictionary*)UTTypeCopyDeclaration( (CFStringRef)uti );
NSLog( #"UTI declaration: %#", utiDeclaration );
This won't quite get the path to the icon, but it will get one the application from which the declaration came for the UTI.
An icon might also be supplied from a Quick Look plugin and output from qlmanage can be used to determine if this is the case.
A user can, in Finder's Get Info window, set the application they prefer for all files of a given "type". One can set text file types to always open in TextMate, for example. TextMate the app provides custom file icons for all the file types it can save in. After making this change in Finder's get info windows, all files of that type will have an icon that has been provided by TextMate and registered with a UTI. To determine whether this is the case, one would need to look at the launch services database - lsregister -dump
I don't know of any specific tools that provide this information. However, it sounds like you have overlapping extensions. If Finder.app is showing an icon for a file then you should be able to just look in the info window for the file and see what application is listed to open the document by default. Then look at the .plist file for that application to see if it is using your extension. The info window should also say what kind of document it is which could be useful if the application that is supplying the icon has been deleted, or otherwise not listed as the default application.

Resources