NSWindow won't accept drag and dropped files - cocoa

I'm trying to get a window I've created to accept files dropped onto it from the finder and all that happens when I try and drag a file onto the window is it snaps back to where it was on the desktop. Clearly I'm not setting something up right.
Inside the NSWindowController:initWithWindow: I'm doing:
[self.window registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
I've tried putting this line in the view as well and no luck. What am I missing? Is there something I need to set in the .xib file as well?
Where do I need to put the -(BOOL)performDragOperation: function? Is that in my custom NSWindowController class? Is that what is failing?

Have you followed (or read) the documentation? The relevant section is titled "Receiving Drag Operations.
Most importantly, for a general view (or window), you need to implement -draggingEntered: as a first step and return the proper NSDragOperation (or at least not NSDragOperationNone) to "validate" the proposed drop. Without answering this, a drop won't even be allowed (so you'll never receive -prepareForDragOperation:, -performDragOperation: or -concludeDragOperation:).
Something else to consider: Do you really want the whole window to act as the dragging destination? More often, it's best to use a specific view that gives visual feedback to the user when -draggingUpdated: is called.

Related

Separating windows on fly

Good evening.
I have two controllers. Call them NSViewController1 and NSViewController2. Controllers placed on one NSWindow and have some network logic. It's not very good to delete them from memory while program is running.
I would like to create button. If user click on button, single window should separate on two windows. First of new window should contain NSViewController1 and second window should contain NSViewController2. Much better if switching is animated.
What is the best way to implement described behavior? May be somebody saw an open source project with this task?
It would be best if you had a controller which controls both your window controllers, as well as both of your view controllers.
If the button is clicked, you can send a message to this controller and remove the second view from the window and add it to the other window.
And of course adjust the frame of those. I guess it's not that big of a deal.

Focus wrongly preserved by Lion

I'd really appreciate an answer to this, but can't afford a bounty (!).
Here we have a very simple GUI: the user just enters a source word and a target word in two text boxes, then presses a button. Then a lot of whirring takes place, and half a second later an answer is shown. The user goes on doing this until bored, then closes the app. Naturally, when the app restarts, the focus should be on the source, and I am hoping there is a neater way of achieving this than the one described. The commenter below has confirmed my feeling that the problem was an artefact of Lion persistence, which is a real nuisance in simple cases like this.
I set an NSTextField as First Responder (using the window's makeFirstResponder) in the awakeFromNib method of a simple 'controller' class, in a simple Cocoa application in Xcode 4.3, running under Lion.
The makeFirstResponder works fine the first time the app is loaded after reboot, but on every rerun the focus is set to the last field accessed. (I had tried connecting the window's initialFirstResponder outlet to the desired NSTextField, but got the same problem).
I fixed it finally by calling an initialisation function from the NSApplication delegate, and putting the makeFirstResponder call there.
The fix is a bit messy - I added a global variable to the controller, and initialised it to self in awakeFromNib.
I add the information that the Cocoa part of the app is simple, but the bulk of it is a mass of STL stuff in .cpp files, ported from Windows.
Deselect the "Restorable" check box in the attributes inspector for your window in IB. Of course, you then won't have the other behaviors you get with a restorable window like remembering its position and size.

MacRuby + Interface Builder: How to display, then close, then display a window again

I'm a complete n00b with MacRuby and Cocoa, so keep that in mind when answering - I need lots of details and explanation. :)
I've set up a simple project that has 2 windows in it, both of which are built with Interface Builder. The first window is a simple list of accounts using a table view. It has a "+" button below the table. When I click the + button, I want to show an "Add New Account" window.
I also have an AccountsController < NSWindowController and a AddNewAccountController < NSWindowController class, set up as the delegates for these windows, with the appropriate button click methods wired up, and outlets to reference the needed windows.
When I click the "+" button in the Accounts window, I have this code fire:
#add_account.center
#add_account.display
#add_account.makeKeyAndOrderFront(nil)
#add_account.orderFrontRegardless
this works great the first time I click the + button. Everything shows up, I'm able to enter my data and have it bind to my model. however, when I close the add new account form, things start going bad.
if I set the add new account window to release on close, then the second time I click the + button, the window will still pop up but it's frozen. i can't click any buttons, enter any data, or even close the form. i assume this is because the form's code has been released, so there is no message loop processing the form... but i'm not entirely sure about this.
if i set the add new account window to not release on close, then the second time i click the + button, the window shows up fine and it is usable - but it still has all the data that i had previously entered... it's still bound to my previous Account class instance.
what am I doing wrong? what's the correct way to create a new instance of the Add New Account form, create a new Account model, bind that model to the form and show the form, when I click the + button on the Accounts form?
... this is all being done on OSX 10.6.6, 64bit, with XCode 3.2.4
The issue is that it doesn't create the window each time. Release on close is a bit of an annoying option and generally is only used if you know the window controller is also being released when the window closes. (Note I've never used MacRuby so I'll be giving code in Obj-C as I know that it is correct, hopefully you can convert it. I'll be assuming GC is on as it should be with MacRuby).
Now there are two ways to do this. I'm not entirely sure how your NIB/classes are set up as it could be one of two ways.
--
The first way to solve it is to use the outlets you use to reference the form elements to blank them out when you display the window again eg [myTextField setStringValue:#""]. If you're using cocoa bindings then it's a little trickier, but basically you have to make sure the bound object is blanked out. I would recommend against bindings though if you are new to Cocoa.
--
The second way is to make the AddNewAccountController class a subclass of NSWindowController. When you press the + button you would then create a new instance of it and display it (remember to store it in an ivar). The best way to do it would be as so:
if (!addAccountController) {
addAccountController = [[AddNewAccountController alloc] initWithWindowNibName:#"AddNewAccountController"];
[[addAccountController window] setDelegate:self];
}
[addAccountController showWindow:self];
This prevents a new instance being made if the window is already visible. You then need to implement the delegate:
- (void)windowWillClose:(NSNotification *)notification {
//If you don't create the account in the AddNewAccountController then do it here
addAccountController = nil;
}
Obviously you would need to move the window to a separate NIB called "AddNewAccountController". In this NIB make sure to set the class of the File's Owner to AddNewAccountController and then to connect the File's Owner's window outlet to the window.
When all this is set up, you will get a fresh controller/window each time. It also has the benefit of splitting up nibs and controllers into more focused units.
--
One last thing. While it is fine to do something like this in a window, you may want to eventually look at doing this via a sheet, as it would then prevent the possibility of the add account window getting hidden behind other windows.

load nibs in cocoa

How can I load a nib inside of another window?
I tried initWithWindowName,
if (mmController == NULL)
mmController = [[mainMenu alloc] initWithWindowNibName:#"mainMenu"];
[mmController showWindow:self];
but it opens a new window.
I also tried loadNibNamed
[NSBundle loadNibNamed:#"mainGame" owner:self];
and it succeeded, but when I try to use the same method to get back to the main menu,
[NSBundle loadNibNamed:#"mainMenu" owner:self];
it doesn't work. It does nothing at all...
Any ideas?
I tried initWithWindowName,
You mean initWithWindow¹Nib²Name³:, which takes the name (3) of a nib (2) containing a window (1).
if (mmController == NULL)
This should be nil, not NULL, since you are comparing an Objective-C object pointer.
mmController = [[mainMenu alloc] initWithWindowNibName:#"mainMenu"];
What is mainMenu here? It must be a class, but what is it a subclass of?
[mmController showWindow:self];
From this message and the previous message, I'm guessing mainMenu is a subclass of NSWindowController.
Guessing should not be required. You should name your classes specifically, so that anybody can tell what the class is and its instances are merely by the class name.
Brevity is a virtue, but if you need to go long, go long. We've got modern tools with name completion. The tab key can eliminate the sole advantage of an abbreviated name.
but it opens a new window.
Yes. You created a window by loading it from a nib, and then you told the window controller to show that window. Showing a new window is the expected result.
I also tried loadNibNamed
[NSBundle loadNibNamed:#"mainGame" owner:self];
and it succeeded, but when I try to use the same method to get back to the main menu,
There is no “get back”. Loading a nib is simply creating objects by loading them from an archive. You can load the same nib multiple times, and loading a nib does not somehow undo the results of loading a previous nib.
You may want to read the Resource Programming Guide, which covers nibs as well as image and sound files, and the Bundle Programming Guide.
If you want to hide the window you loaded from the mainGame nib, do that. The term for this in AppKit is “ordering out” (as opposed to “ordering in”, which “ordering front” and “ordering back” are specific ways of doing).
[NSBundle loadNibNamed:#"mainMenu" owner:self];
it doesn't work. It does nothing at all...
Are you trying to load the MainMenu nib that came with your project? If so, make sure you get the case right—you don't want your app to be broken for people who run it from a case-sensitive volume, nor do you want it to be broken for people who use the default case-insensitive file-system.
If that's not what you're trying to do, then it isn't clear what you are trying to do. MainMenu is normally the nib containing the main menu (the contents of the menu bar); naming any other nib “mainMenu” or anything like that is going to cause confusion at best and problems at worst. If this is supposed to be some other nib, you should give it a different name.
Either way, this is not what you need to do. If you want to hide the window you loaded from mainGame, then you need to hide that window, not load a different nib.
Moreover, once the window is loaded, do not load it again (unless you close and release it). Once you have loaded it, you can simply order it back in. Most probably, you will want to both make it key and order it front.
On the Mac, you are not limited to one window at a time; indeed, your app has multiple windows (at least three), no matter what you do. The APIs are built around your ability to show multiple windows.
See the Window Programming Guide for more information.
How can I load a nib inside of another window?
As Justin Meiners already told you, you may want NSViewController for that, although you can go without and just load the nib containing the view directly using loadNibNamed:.
Be warned that NSViewController is not nearly as powerful/featureful as Cocoa Touch's UIViewController.
You'll want to read the View Programming Guide for this.

Cocoa: What NSTextView the insertion point is currently blinking in?

Given an NSApp object (aka [NSApplication sharedApplication]), how can I get the currently active NSTextView, where the insertion point is blinking right now (if there is one)? :-)
I can go [[NSApp keyWindow] contentView] and try traversing the whole view hierarchy, but that seems too hard. Ideal code would be: [NSApp focusedTextView].
I tryed firstResponder for an app and a window, and also fieldEditor:forObject:, but this does not return anything interesting (at least, to me).
By the way, if anybody knows how to get the system wide current text view, that would be even cooler (Accessibility APIs won’t work: it won’t return a Cocoa NSTextView).
Thanks
The -firstResponder function returns the field editor. So if you want the real view you might need to check the first responder's delegate to get to it. Also see field editor for details.
There is probably no way to get it system wide as a NSTextViews since that object is in general in a different process space.
By the way, if anybody knows how to get the system wide current text view, that would be even cooler (Accessibility APIs won’t work: it won’t return a Cocoa NSTextView).
Not possible. NSTextViews are per-process; you can't get a proxy to an NSTextView from another process without that other process serving it up through an NSConnection. You're just going to have to use Accessibility.
On the bright side, using Accessibility means your app should (in theory) also work with Carbon apps that use MLTE/HITextView.

Resources