Connecting Menu Items in Document Based Applications - objective-c

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.

Related

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.

Passing data to a specific open NSDocument?

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.

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 two DialogBoxes in GWT

In my GWT project, I'm trying to get it so two DialogBoxes can pass information between each other. One of them holds a MapWidget, and when a button is pressed in the other DialogBox, the position information is received from that other DialogBox's MapWidget. Does anyone have any tips for how I should coordinate between having two different DialogBoxes show up? Should I wrap the code for the two in a Composite? Furthermore, is there an example anywhere of dealing with two DialogBoxes at once in GWT? For example, if I click outside of the two boxes, both should be dismissed. I'm wondering if there's a way to keep both of them in focus at once, so I can switch between the two without causing either to disappear.
Sharing Data Between Dialog Boxes
In my opinion, the "correct" way to do this would be to implement some sort of MVP structure in the application so that a presenter manages the view (DialogBoxes, among other things) and knows how to pass simple data to the view for it to display (the presenter would handle the MapWidget data, the view would take care of displaying it on the DOM).
However, if you're looking for a quicker/more simpler approach, you have a couple of options (which you choose really depends on the application structure):
Create a Composite, as you mentioned, that knows how to pass the necessary data back and forth. By having the Composite manage the data object and tell the two DialogBoxes how to display it, you are actually approaching an MVP architecture within your Composite.
Subclass DialogBox into a class that contains a HandlerManager (sometimes used as an "Event Bus") that fires events when the button is pressed. You can create events that are designed to pass data back and forth between the two DialogBoxes (even make them type-safe with type parameters). See this StackOverflow question for details on using a HandlerManager. The MVP article, linked above, also has some good information on using an event bus.
Model-View-Presenter is a tried-and-true method of structuring an application that results in more testable code, better project structure, and can help guide you when making decisions like this. I strongly recommend checking it out if you haven't already.
Sharing Auto-Hide Functionality
GWT's PopupPanel (on which DialogBox is based) offers a method addAutoHidePartner(Element) which is describe thusly:
Mouse events that occur within an autoHide partner will not hide a panel set to autoHide.
So, you can create two auto-hiding DialogBoxes that only close when you click outside both of them (e.g., they do not close when you click within either of the boxes) with the following code:
// Create the dialog boxes
DialogBox dbox1 = new DialogBox(true, false);
DialogBox dbox2 = new DialogBox(true, false);
// Set some visual options
dbox1.setPopupPosition(10, 10);
dbox2.setPopupPosition(200, 10);
dbox1.setAnimationEnabled(true);
dbox2.setAnimationEnabled(false);
// Set the dialog boxes' caption and content
dbox1.setHTML("Dialog Box 1");
dbox2.setHTML("Dialog Box 2");
dbox1.setWidget(new HTML("This is the first dialog box."));
dbox2.setWidget(new HTML("This is the second dialog box."));
// Making dobx2 a partner of dbox1 means clicking
// in dbox2 won't cause dbox1 to close
dbox1.addAutoHidePartner(dbox2.getElement());
// Similarly, setting dbox1 as a partner of dbox2 means
// clicking in dbox1 won't cause dbox2 to close
dbox2.addAutoHidePartner(dbox1.getElement());
// Show the dialog boxes
dbox1.show();
dbox2.show();
You can interact with either of the dialog boxes without the other closing. Omit the appropriate call to setAutoHidePartner if you only want a one-way partnership.

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.