Passing data to a specific open NSDocument? - objective-c

I have been having lots of trouble with this one. I need to have an NSViewController and an NSView pass integer's to a specific document. I really want it to pass the data to the document represented by the key window (I hope that makes sense), but the way I am doing passes the data to all of the open documents.
I am using a document based application, from the Xcode template (Cocoa application with the "Document based application" box checked. Is there any way to do this?
I did not post my code because it really is too embarrassing. Basically, I have a "getter" method in the NSViewController, but I still have not thought of a good way to pass the data back. I ended up with hundreds of lines of code that are supposed to make the document pull the data back with another "getter" method, but they don't do anything.
Is there any documentation on this?

The key window may not have a document behind it, it is just the window that will receive events first, I think what you may be after is -[NSApplication mainWindow] which you can get the window controller for and from that the document, alternatively you could observer the NSWindowDidBecomeMainNotification to keep track of which window is now main or you could use the method -[NSAppliation orderedDocuments] to get the front document. Personnaly I like the NSNotification but there may be resins you prefer one of the other methods.

Related

Intercepting NSDocument close before "Save changes?" sheet

I have an NSDocument-based app where a window for the document may have child windows that need to be queried for changes before the document can close. So I tried to intercept the closing of the document window to do this, but I can't find a reliable way.
I tried to use -[Document canCloseDocumentWithDelegate:shouldCloseSelector:contextInfo:] for this, but apparenty this is only called when the document has changes (signalled by -updateChangeCount). If there are no changes, this never gets called.
My other attempt to use the view controller's viewWillDisappear to update the document failed too, as this is too late to register any changes with the document, so they do not get saved (canCloseDocumentWithDelegate:... has already been called at this point.)
What would be the best way to solve this?
Well, I'd say that if the child windows contains changes that have to asked for before the document is closed, the document has changes. And this should be reflected in the (main) document window. However, …
Likely -shouldCloseWindow: should be called, if the document does not contain changes and therefore the document system does not ask for saving itself.

Disregard sheet with single text field using escape key

So this is my setup:
A trivial NSWindow with a single NSTextField for user entry plus an 'Accept' type NSButton.
The window is displayed for my document window as a sheet using beginSheetModalForWindow:completionHandler:
I'd like to close the sheet when the user presses the escape key, however all I get is the funny system sound telling me it's not really expecting an escape key at that point.
There are several similar questions suggesting we should just check for cancelOperation somewhere in the responder chain. Thing is, my window controller (for the window/dialog in the sheet) isn't even in the responder chain when I'm checking it in the debugger.
For the sheet displayed in the way aforementioned the responder chain is still all about my document window. Weird.
So any hints how to properly hook up to either cancelOperation or the Escape key would be much appreciated!
Since your sheet can be cancelled, you should probably add a Cancel button to it to make that possibility clear to the user. If you do that, and set the keyboard shortcut of that Cancel button to the escape key in IB, then it ought to Just Work. I think it is important that the name of the button is actually "Cancel", though; I recall reading that AppKit does some special glue magic behind the scenes based on that button name.
And by the way, it seems like your window controller should be in the responder chain, assuming it is an actual NSWindowController set up in the proper way; see Apple's doc here. Not sure why the debugger indicates that it isn't, but it should be, as far as I can tell. If it really isn't, that might indicate something more deeply wrong with how you're setting up the sheet. I'm not sure about that, though, since I haven't tried it myself.

QInputDialog like thing in Cocoa/Xcode?

I'm fairly new to Xcode and Cocoa/Objective-C and I'm trying to implement something as simple as a QInputDialog that can be re-used throughout the program - with a unique message to the user each time it is launched and return a string as a result.
I have searched the web and found multiple methods but nothing seems to be quite clear or concise - well enough for me to understand anyway.
Is there anything out there as simple as:
Create/Launch a window from a method with a new message label to the user in the form of a string.
Has an NSTextField to receive the users input.
Close the window and return the string from the text field (if accepted) to the calling method.
??
Modal prompts for input are very un-Mac-like. It's like smashing the user's face in with a cricket bat and yelling “TELL ME THE ANSWER NOW!”
The correct solution is to put your text field into a non-modal window, so that the value is already ready when the user invokes whatever action needs the value. Beep and show the “hey, you forgot this” icon if the user hasn't filled in the field and you need a value there. If the field is not relevant in the window the user starts the action from, or if you're going to need several facts as input, then show another window, non-modally, with its own window controller, to take in all the input you'll need for the action.
A separate, non-modal window will also enable the user to fill out and/or perform multiple such actions in parallel.
If you must demand the value with a modal dialog, you can and should make it a sheet, but you'll still need to build the panel and its contents from scratch in IB or code.
See also the Sheet Programming Guide and the chapter on windows in the Human Interface Guidelines.

Connecting Menu Items in Document Based Applications

I've already asked a couple questions on this topic, and haven't really received a real answer on how to do it (it actually received the "Tumbleweed Badge" lol).
I have a document based application (meaning the Menu.Xib is separate from MyDocument.Xib).
Say I want to add a 'Bold' button, or a Check Spelling button (items that are listed in Menu.xib (under Format > Font etc) to MyDocument (the primary interface). I cannot figure out how to do this.
Any help would be greatly appreciated (I will reward an answer immediately if it works, this has stumped me for a couple weeks now).
I tried adding a Font Manager to MyDocument.Xib and connecting that way, but the Bold button only enables, it doesn't disable. Plus, Spell Check etc can't be activated via Font Manager.
There has to be a better way to do this.
The Apple Documentation is incredibly vague.
This is exactly what the First Responder object in IB is for. It is a proxy object for connecting actions. Any action messages sent to it will be passed down the responder chain to the first oobject that accepts them. For document based applications, the responder chain includes the current document. So, to connect the menu item to your document:
Add the action to First Responder, if needed. You can do this from IB's inspector window.
Connect the action to First Responder as if it were a normal object.
Implement the action method in your document.
If you need to add a message to the first responder programatically, set the object's target to nil.

NSWindow does not respond to keystroke command-s

It may be very simple, but I cannot find it:
I have three windows in three separate NIBs in my application. One is opened when a new document is opened, the other two can be opened from the program's window menu.
The problem is: two windows (in them the one that is opened at the beginning) accepts the normal keystroke as for example command-s for save, and the other one does not and gives a warning sound instead. I cannot figure out the difference between the two windows or their controllers. I know it will have to do with the responder chain, but I am left clueless.
Any ideas?
Check to make sure that the window's delegate is set to the window controller, and that the window controller implements -saveDocument: (or whatever action the Save item is connected to).
Windows don't respond to key combinations. Menu items do. In response to being pressed (whether using the mouse, using a key combination, or using Accessibility), the menu item sends its action message down the responder chain.
You get a beep when nothing in the responder chain responds to the action message.
Assuming that this is an NSDocument-based application and you've started Apple's doc-based-app template, the menu item's action is saveDocument:, and the NSDocument object is the object that responds to that message. When your document windows are active, their documents are in the responder chain, so the menu item that sends that action message is enabled. When your third window is active, the document is not in the responder chain; nothing else responds to that message, so the menu item is disabled.
This problem isn't specific to Save—it affects all action messages that should go through to the document object. One important other example is Print: The user will probably mean to print the document, not the third window.
You've probably made this third window a kind of window that exists as a peer to the other windows. Besides this responder-chain problem you're having, the user will also probably not realize that they have left the document; they expect to still be able to do document things. Consider making it a utility panel instead.
If you really do have a good reason to make this window whatever kind of window it is, you'll need to keep the last-active document object in the responder chain when this third window becomes main, while at the same time handling the case where the window becomes main because a document window (possibly the last one) has closed.
Well, it turns out that I implemented the third window in a way where I created it with its controller using initWithNibFile, ran a procedure in the controller and then sent it a [window close] command because I did not want it to appear on the screen yet. That somehow took it out of the document-associated window, no idea why. No I migrated that specific called procedure into the document controller itself, treat the window like the second window and voila, it works again.