NSPopupButton hierarchical binding - cocoa

I am learning about Cocoa binding and as part of that working on a simple testbed where I populate a NSPopUpButton with some options via a NSArrayController. It all shows up fine and I can change the button selection. I then tried to bind the title of NSWindow to display the string of the data the NSPopUpButton is bound to. It works as far as startup goes..showing the first item in the popup... but no matter the change in the popup selection the title doesn't change. This all works fine if I swap NSPopUpButton with NSTableView. Am I right in thinking that NSPopUpButton does not track user selection, and that if I want to track that I need to set a property in my model to track that?
Thanks!

Related

NSOutlineView with manual Cocoa bindings

I have an NSOutlineView that is bound to a NSTreeController. The details are like this:
the treeController has class mode, and CommonListData as the Class Name, which has a "children" property
the treeController also has "content array" bound to File's Owner's "headersArray" (of type NSArray). The "headersArray" is an array of CommonListData items
the NSOutlineView has bindings for "Content" to the treeController's arrangedObjects
the view-based outlineView is designed in Interface Builder, with each cell view has lots of elements. Each element (labels, images etc) have 'value' bindings to the NSTableCellView with the relevant objectValue.xxx model key paths
The setup is fairly simple, and it all works fine in adding and deleting objects. But the problem is that it doesn't use any of the NSOutlineView / NSTableView animations when adding or removing items from the outline view. The table just reloads itself if I add or remove any element to the treeController, or directly to the headersArray's children objects. I'm not sure if that is a limitation with Cocoa Bindings or what.
In any case, I am consider whether I can disable all the bindings and do this manually. The only drawback is that the NSOutlineView cell views have complicated elements on them, and I don't want to have to map the view elements to the data in code. Ideally it should keep the bindings in the NSTableViewCell.
So my question is:
Is it possible to keep the bindings within Interface Builder in a NSTableCellView, but not bind the content to the treeController? Or is there an alternative to binding "arrangedObjects", such that adding and removing data from the NSTreeController doesn't trigger an update to the UI?
It would help to have some more control over the bindings, so that I can trigger the animations correctly, and not have it just jump around with every update.
I believe the bindings of the views within the cell view are independent of the bindings of the outline view's content. Whether the outline view uses bindings or not, it eventually sets the objectValue property of the cell view. So long as that's done in a KVO-compliant manner (which it is), any bindings to that property will work.

Specify editing NSTextField inside NSPopover on appearance

I'm working on an app that presents an NSPopover containing a number of NSTextFields. While I can tab between these fields as I expect, the popover is selecting a particular text field to be in the editing state when it appears, and it's not the field I want to edit; I'd like to be able to define which text field is editing on popover appearance programmatically (or in Interface Builder). How can I do this?
I've set up the appropriate key view loop by connecting IB outlets for all the various text fields involved, and I've hooked up the popover's nextResponder property to the text field I want to edit first, but that doesn't seem to have an effect - the popover will still select its preferred text field instead of mine. The Window Programming Guide suggests that I set the initialFirstResponder outlet of the window to the view I want selected, but an NSPopover is not an NSWindow and has no initialFirstResponder property (unless I'm missing something obvious).
Is there any way to specify which NSTextField I want to be editing when an NSPopover appears?
I think you said you tried using -makeFirstResponder: and passing the text field. This will set the window's firstResponder, but that's not the same as initialFirstResponder and the window must have initialFirstResponder set to something other than nil in order to respect the key view loop. (Source) A slight tweak to what you tried worked for me:
- (void)popoverWillShow:(NSNotification *)notification
{
// Set the window's initialFirstResponder so that the key view loop isn't auto-recalculated.
[[myField window] setInitialFirstResponder:myField];
}
I think you can make this work by setting all the text field's that you don't want to have focus to "selectable" instead of "Editable" in IB, this should leave the one text field you want to start with as the first responder. Then, in your popoverDidShow: method, set them all back to editable, and you should be able to tab between them as usual.

CoreData-bound NSTableView loses input focus when items change, but only if sorted

I have an NSTableView in a dialogue box which is bound to a collection of CoreData model instances via an NSArrayController in 'Entity Name' mode. The table displays the names of the array of managed objects in a single column. This works well.
The names in the table rows are editable. If the user edits a name when there is no sorting applied to the table then editing proceeds normally. After pressing Return, the new name is recorded and input focus stays in the NSTableView. However, if the column heading in the table view is clicked upon in order to sort the table of names, input focus goes astray after editing. It stays within the window, or wider view (not sure which), but it goes out of the table; the focus ring vanishes and the background colour of the highlighted item changes from blue to grey. Pressing Tab pops input focus back into the table view again.
This only happens if the table contents are sorted. If "Continuously Updates Value" is chosen for the binding, it's catastrophic as the minute any characters are entered, the table view seems to want to re-sort itself (that's OK) and focus jumps out of it (that's not OK as the user was in the middle of trying to type something).
As far as this aspect of the system is concerned, there's no code - it's all done with bindings established in Interface Builder. Presumably, I've inadvertently set or cleared some option that I shouldn't have.
In case it helps the reader figure out what's up - I also have a modal sheet attached to the dialogue box containing the NSTableView. The sheet is used to edit the details of an item selected in the table view. The controls in this are also connected with bindings to the CoreData model using the same NSArrayController as the dialogue box 'behind' the sheet. The same problem is seen - as soon as a new name is typed in, focus is pulled back to the dialogue box 'behind' the modal sheet.
The only code involved is that used to handle the 'edit this item' action and start the modal session for the sheet.
What's going on? Where is the focus going and why is being moved just because of re-sorting in the NSTableView?
Thanks!
The entities NSArrayController had "Auto Rearrange Content" ticked in the relevant Interface Builder inspector panel. This wasn't doing what I thought it would do and was the cause of the focus stealing problem.
I finally narrowed this down by creating a bare bones CoreData application which just added names to a table view. Almost no code required; 99.5% Interface Builder and bindings, with just an extra outlet and a single line of glue code to tell the array controller for the CoreData model about the Managed Object Context instantiated in the application delegate by code that Interface Builder had auto-generated. Setting the "Auto Rearrange Content" flag in the test program provoked the same strange input focus behaviour.
So if you've got focus stealing problems with a table of objects bound to CoreData through an array controller, check your array controller's auto-rearrange flag!

How to add text to NSTableView

I made a Cocoa application that has an NSTableView, an NSTextField, and an NSButton. The user enters text into the text field and clicks the button. When the user does this, I want the text in the textfield to be placed in the NSTableView. I find that I can't even bind an IBOutlet to a cell in the NSTableView. What should be done?
The Model-View-Controller pattern, which is used extensively in Cocoa is your friend here.
What you need to do is to bind the NSTableView to an array (The model). Then configure the button so that a click tells the controller to add the content of the text field to the array and if the bindings are set up correctly the NSTableView (The View) will be updated.
What I think you need to do is make a class, AppController for instance which will be your data source and the delegate of the NSTableView. So you need the following.
Two IBOutlets (one for the NSTextField and one for the NSTableView)
An IBAction for the NSButton.
Make those connections in Interface Builder.
Remember to use the mandatory delegate methods (there are two of them) so you can add the data from your data source (usually a collection class..an array, dictionary...etc.

How do I make an NSPopupButton that has a menu with images AND text?

I have a list of applications and I'd like to make an NSPopupButton that shows a menu of application names with their icon to the left of each item.
I've been able to bind the NSPopupButton to my array of items, but there isn't a binding entry for an image. I thought I could put a cell in there and bind the cell as an image and as text, but I can't find an appropriate cell in IB.
Is there a clean and simple way to do this using bindings? Do I have to write a custom cell?
There is no way to bind the images as well as the titles of the menu items using a stock NSPopUpButton. You will have to subclass it and write an IBPlugin to expose the subclass. And, of course, you should handle the cell as well.
I've found mixing Bindings with NSPopUpButton to be a bag of hurt for a variety of reasons, including the impossibility of separators and of out-of-model menu items such as “Default” or “All”. Consider using a different control, such as a source list, or populating and re-populating the pop-up menu manually.
NSMenuItem has Image binding (in "Parameters" section waaaaaayyyyy down). So I think that you should bind that value to a path in your array of running applications. You can get an icon for your app using shared NSWorkspace object.

Resources