NSTextField in NSPopOver beeping instead of sending action to target (document) - objective-c

I have a document-based Cocoa (Mac)/Objective-C application. I'm showing a popover on one of the views in my document window's view; the popover contains only an NSTextField, whose target is the first responder (I have also tried wiring it directly to the File's Owner, which is the document) and whose action is a selector that my NSDocument subclass responds to.
Problem is, when I press return in my field, it just beeps at me. It does not appear to send the action to the document. The document certainly doesn't receive it.
(I can type into the field just fine, but when I want to send the field's action, it refuses.)
There are no exceptions logged in the debugger console.
I have confirmed (by breaking in the debugger in validateUserInterfaceItem: and then opening a menu) that the field's target and action are set as expected. I did a Find using the selector reported by the debugger in my document class to confirm that the selector is indeed correct (no typos).
I'll note that validateUserInterfaceItem: isn't called on the return key-press. I don't remember whether it's supposed to get called by text fields or not.

Related

Cocoa text menu and modifying fonts in NSOutlineView

The system supplied text menu works by sending a number of messages like changeFont: modifyFont: and addFontTrait: up the first responder chain until it reaches an NSTextView for example.
I'd like to extend this to control row styles in my NSOutlineView but I have only been able to override changeFont: in my window controller and intercept the message (maybe a better place to do this but it works for now). This works for changing fonts but the other menu items like Bold, Bigger, Smaller which use modifyFont: and addFontTrait: aren't ever getting called in the window controller so I can't modify their behavior to work on the outline view. Interestingly they appear selectable in the menu but only changeFont: is called and as I understand it I need to get a tag value from the NSMenuItem which is the sender of the methods modifyFont: and addFontTrait:.
Does anyone know how to implement this functionality by getting those other methods to be called anywhere? Thanks!
This is documented in the Cocoa Text Architecture Guide: Font Handling – Handling Font Changes. The -addFontTrait: and -modifyFont: messages are not sent up the responder chain. They are sent directly to the font manager. The font manager makes a note of the requested modifications and sends -changeFont: up the responder chain.
You should only need to implement -changeFont: as you have.
You do not get the tag from the menu item. The font manager does that. That's the source of the information that the font manager records internally.
Your -changeFont: method should call -convertFont: on the font manager, passing the current font. That method will return a new font modified as per the recorded change request. You would do that for all the fonts which should be affected. (For example, you might have a selection with multiple fonts in it.)
You do not normally have direct access to the requested modifications, such as "add the Bold trait" or "make the font bigger".
You can customize the font manager by subclassing NSFontManager and passing your subclass to +[NSFontManager setFontManagerFactory:] very early in app start-up. In your custom font manager, you can separately track the changes requested by the various action messages like -addFontTrait:. Here is where you would check the tag of the sender. Then, in your outline view you could query the properties of your the sender of -changeFont:, after verifying that it's an instance of your subclass, to determine what change(s) were requested.
Remember, though, that your custom subclass will be used throughout your app, not just for your outline view. So, your customizations should be in addition to the normal behavior of NSFontManager, not instead of, so it doesn't break stuff.

Get the representedObject values of NSCollectionViewItem NSButton click

I have read some questions and I find some very confusing and I don't really know if they answer my question.
I have an NSCollectionView implemented and connected to a Core Data context, everything shows correctly.
Now what I have is buttons in the view prototype, and when I click this buttons I need to get the value of the representedObject of that cloned view.
I have read and read and some parts are confusing to me, so I'm looking for a simple explanation.
Thank you for your time.
An action method takes one argument:
- (IBAction) collectionViewButtonClicked:(id)sender {
}
That sender is the control or other UI element (e.g., menu item) that sent the message.
With that argument, when your action method gets called, you know which button was clicked.
A button is a kind of control, and every control is backed by at least one cell. Cells have represented objects, too.
So, first, set the represented object of your button's cell to the collection view item that owns the button. (You can do this in the nib editor.) Then, in your action method, get the button's cell, then the cell's represented object (which is the item), then the item's represented object.
If the representedObject outlet doesn't show up in the nib editor, you probably have the button selected, not its cell. I recommend opening the nib editor's outline view using the button in the lower-left and then never, ever closing it.

NSTextField setEnabled

I have a NSTextField object in my window which has to be disabled when a check box is clicked.
I have written a IBAction to receive the check box click and disabled/enabled the text filed based on the check box state.
[mName setEnabled: [mNameCheck state]];
This work fine with the basic functionality, but I found some strange behavior.
You update some detail in the text filed and click on check box the text filed get disabled old content.
Example:
Stage 1: Text filed has the content
"Name"
Stage 2: Update the text filed
content as "Girish"
Stage 3: Click check box (to disable
the text filed)
Stage 4: Text filed disable with the
content as "Name"
The issue get resolved if I resign the responder and set responder to some other controller before the text field is disabled.
In my case I can not assign the responder to check box(it does not take) or any other controller so I did some thing like bellow which works fine
[mName resignFirstResponder];
[mName becomeFirstResponder];
resign and assign responder with same controller.
I am just wondering is this solution is correct or any better solution to this issue?
As the docs state, do NOT call -resignFirstResponder or -becomeFirstResponder directly. Call -[NSWindow makeFirstResponder:] instead. It is acceptable to pass in nil and status will pass to the window itself.
You could try calling -[NSWindow selectNextKeyView:] although I'm not entirely certain what will happen if it doesn't find a valid next key view. Try it and see. If that doesn't work you'll have to fallback to calling -nextValidKeyView and -makeFirstResponder yourself.
If you set the text field to be Continuous in Interface Builder, the value of the field will be set as soon as a change is made in the field rather than when it loses focus. You can programmatically set this value with [yourTextField setContinuous:YES].

Enabling open file menu item in a non-document-based application

I would like to enable the grayed out open file menu item within a non-document-based application. Document-based applications automatically give you a nice open file dialog with file extension filters based on plist entries etc... Surely, a simple elegant method exist to re-enable this functionality.
I have...
Added document types to the project properties window
Assigned my controller class as the application delegate
Added the delegate application:openFile: to my controller class
First, make sure your File->Open menu item's selector is connected to the openDocument: action of the First Responder.
Second, make sure you are responding to the action. Take a look at the Responder chain of a non-document application with an NSWindowController object. Any object within your responder chain can respond to the message, but it is best to pick the object which is the most capable and appropriate. Once you have decided which class in your responder chain is the most appropriate to handle the message, add the openDocument: action to it's implementation and write your code to respond to it accordingly.
The key is that something along the menu item's responder chain has to respond to the -openDocument: action. Normally it's the NSDocumentController. I'd take a look at how an empty document-based application sets up that menu item.

"First Responder" - Did I get that right?

Let me summarize this shortly: A "First Responder" in a nib file is an object, which represents the UI control element that has the user's focus. So if the user clicks on a control, the nib sets that clicked UI control as First Responder. In my app I could make an outlet to that "First Responder" from the nib, so that I could for example send a message "make red font color" to whatever the user has activated by clicking.
And then, if this First Responder UI control does not understand that message, the message gets passed up in the responder chain, until a parent element or grandparent (and so on) UI control element understands the message. Otherwise it will be ignored.
So First Responder always establishes a "link" to the UI control that has focus. Is that right?
Right overall picture, wrong implementation details in the first paragraph.
A "First Responder" in a NibFile is an Object …
No, actually, First Responder is nil. Connecting a UI control (e.g., button) to First Responder in a nib is equivalent to [control setTarget:nil] in code.
The reason for the First Responder fake-object in the nib window is that, in IB, you set target and action at the same time (ctrl-drag to target, choose action from pop-up menu). You can't set the action and leave the target unset, like you can in code, so to set it to nil, you need to do so explicitly. That's what First Responder is for: it's a fake object representing nil, so you can set the target and action the same way you would do when setting it to a specific real target.
Of course, you can't use this to set anything else to nil, only views' targets. You can only use it to mean First Responder, not anything else.
So if the user klicks on an UI control, the Nib sets …
The nib doesn't do anything. It's just a freeze-dried collection of objects stored on disk. Even when you instantiate NSNib, all you're doing is defrosting some objects. It's the objects that do things.
In the case at hand, when you unarchive the control you connected to First Responder from the nib, its target is set to nil (remember, that's what First Responder really is: a target of nil). When a control's target is nil, and the user clicks on it, it sends its action to whichever responder is the first responder at the time.
Your second and third paragraphs are correct.
Your understanding is incomplete. The responder chain includes more than what we'd usually think of as "UI controls," including most importantly the current document. One of the big benefits is that it allows you to interact with the conceptually "current" whatever — current window, current text field, current document, etc — without a lot of messing around to find it.
A responder is any object that will perform actions (call functions) when events (such as clicking on buttons) occur. The responder chain is a sequence of objects each contained in one another - for example a button inside a panel inside a window. When an event occurs, we iterate through the chain until we find an object that does not have a responder set to nil and which can therefore respond to the event. So instead of providing a responder object for each button in a window, we can provide a single responder for the whole window. The first responder is simply the first object inside the responder chain - linking an event to the first responder allows the event to pass up the chain.
Check this link out it does a good job explaining. I think you have the gist of it:
http://cocoadev.com/FirstResponder
From the source:
The FirstResponder is the first object
in the responder chain that is given
the opportunity to respond to an event.