NSTextField custom subclass and "No selection" placeholder - objective-c

I have a custom NSTextField subclass which is bound to the property of a managed object. During its drawRect method it is required that I know whether the stringValue of the field is nil (either caused by the managed objects attribute being nil or no managed object being selected), an empty string or a "normal" string.
As far as I can tell the string value is never nil, even when the bound attribute of the managed object is nil or no managed object is selected. Am I correct or missing something?
Note: I have tried various settings in the bindings panel but this does not seem to work.
EDIT: Maybe to clarify, the effect I'm after is something as shown in Xcode when there's no selection:
The difference is, I want my "badge" to turn up when the string is an empty string (although with a slightly different message in it). I want to suppress this effect when the string is nil and use the default placeholders from the mapping panel.

Related

Using NSPopupButton and Cocoa Binding with predefined class

I have a NSPopupButton. Also, I have a NSArray of objects with ClassA type, which is a predefined class and I don't have access to its code.
I'm trying to populate a NSPopupButton with this NSArray, so I used Cocoa Bindings. I set the content to the array, so for each item, it will use -description for the item label. But I want to use my own labels. How can I do this?
I already tried using "Content Values" alongside my custom NSValueTransform, that converts ClassA objects to NSString, but that didn't helped; it seems that my transform never called. I can't also apply my NSValueTransform to "Content" binding, because that breaks the "Selected Objects" (it passes the string instead of the actual object). For fixing this, I filled the "Content Objects" with proper values, but that didn't work, either.

How do I access the properties of UITextField's selectedTextRange UITextPosition objects?

I'm trying to establish the start and end positions of a text selection of a UITextField instance, using its selectedTextRange property (as gained from the UITextInput protocol). However, I have no idea how to access the properties of the UITextPosition objects that make up the start and end properties of selectedTextRange.
Apple's docs on UITextPosition are woeful at this time, providing no methods or properties, though I know there are such properties in the object, because NSLogging one gives this:
<UITextPositionImpl: 0x6aaeb60>
<<WebVisiblePosition: 0x6aa40e0>(offset=5, context=([s|a], [u+0073|u+0061])>
In this example, the 'offset' is correct, and the context shows the characters either side of the selection point ('s' and 'a'), but I don't know how to access this nebulous WebVisiblePosition class. So, in short, is there a way of retrieving the details I want using UITextPosition objects from UITextField?
Of course, just after asking my question I found the answer, in this SO question: UITextPosition in UITextField.
It seems that when used as part of UITextField, the UITextPosition objects are not meant to be tinkered with directly, but used to feed other methods. In this case, the method offsetFromPosition:toPosition:, along with the text field property beginningOfDocument, can be used to return an NSInteger of a selection index.

IKImageBrowserView appears to not bind properly

my question relates to Interface Builder and an IKImageBrowserView not implementing bindings as I would expect.
I have a fairly long key path to get to an NSArrayController, the contents of which I want to display in the IKImageBrowserView.
This is the key path I am binding an NSTextField's Display Pattern binding to:
currentOrder.imagesArray.unvalidatedImages.arrangedObjects.#count of the AppDelegate.
This works fine and gives me the number of unvalidated items in the array of images belonging to the current order, which is what it is supposed to.
When I attempt to bind the following key path to the IKImageBrowserView's content: currentOrder.imagesArray.unvalidatedImages.arrangedObjects of the AppDelegate, Interface Builder gives no error but instead acts as if I hadn't entered anything. When I click back to the inspector, the bindings key path is blank again.
It does however log the following to the Console:
Ignoring exception related to working with bindings: NSUnknownKeyException, [<NSCustomObject> addObserver:<IKImageBrowserView ...> forKeyPath:#"currentOrder.imagesArray.unvalidatedImages.arrangedObjects" ...] was sent to an object that is not KVC-compliant for the "currentOrder" property.
My AppDelegate implements currentOrder as an #property retained and all sub-keys are also #properties. I can be sure that these properties are KVC-okay because the NSTextField above is able to read changes without a problem. Interestingly enough the IKImageBrowserView's selectionIndexes is able to bind to ...unvalidatedImages.selectionIndexes, it's only the content that can't.
I have implemented a workaround whereby I have placed an NSArrayController in my nib file and bound the Content Array to ...arrangedObjects then bound the IKImageBrowserView to the array controller but would be very happy to have a neater solution, or at least to know whether I am doing anything wrong.
Thank you!
Did you try implementing the methods of <IKImageBrowserDataSource> in your app delegate, and using the _dataSource connection instead of a binding? That works for me, and is how the Apple tutorial has you do it.
You basically only need to implement – numberOfItemsInImageBrowser: and – imageBrowser:itemAtIndex: to provide the data, which isn't too bad. The slightly trickier part is to implement an <IKImageBrowserItem> class to wrap your data, but even that doesn't require massive effort. The tutorial linked above should help a lot.

setSelectsInsertedObjects on NSArrayController not actually selecting

I Have an NSArrayController bound to a NSUserDefaults controller, with setSelectsInsertedObjects set to YES in Interface Builder, but when I click Add, the previously select object gets unselected, instead of selecting the newly added object.
What am I missing?
How are you binding them? If it is through NSArrayController's 'content' binding, then I believe it tries to bind the selectionIndexes to the same object. This class (NSIndexSet) does not work with NSUserDefaults (I have no idea why, but I've had the same problem in the past - I think it has something to do with it's object lifecycle; it gets initialized as empty and then adds indexes or something). What setSelectsInsertedObjects is doing is just automatically updating the selectionIndexes when a new object is added, and basically your NSUserDefaults controller is messing that up. I'm not sure where it is, but I think if you hunt around NSArrayController's bindings you will find one for selectionIndexes (or something related) that was automatically bound to NSUserDefaults for you; if you uncheck that, things should work.
That's pretty much what selectsInsertedObjects means, as I understand it. When the user adds a new item, the new item is selected, replacing the previous selection.
If you want different behavior, you could extend NSArrayController or create your own controller class that uses NSArrayController as a delegate, perhaps based on NSProxy. I believe you'd need to override add: to:
save the current selection
call the parent add:
merge the current selection with the saved selection
set the selection to the merged selection
However, I don't know enough about NSArrayController internals to say whether this would work.

Maintain Undo In Modified, Bound, NSAttributedString

I've got an attributed string bound to a NSTextView. I'm using a method that is called (using KVO) every time the string is edited to add background color attributes to string based on a regEx match. I do this by creating a new mutable attributed string with -initWithAttributedString: then -beginEditing, -addAttribute:, -endEditing. Once I've added all the background color attributes I want, I call the string's setter [self setTextViewString:mutableAttributedString] The issue is, that if there actually are any attributes added to the string, it kills undo and moves the cursor to the end of the string.
How can I maintain undo? I've maintained cursor position by calling the textView's selectedRanges and setSelectedRanges: methods on either side of the setter, but this still seems a bit hackish.
I wasn't able to bind the textview directly to the mutableattributedstring, but it seems like there should be a more direct way to modify the bound string so it doesn't mess up editing.
PS, the addition of attributes happens after the KVO method finishes by calling -performSelectorOnMainThread: It was the only way I could get the added attributes to display.
[self setTextView:mutableAttributedString]
Pardon? You're setting your textView to an attributed string? Wouldn't it make more sense to keep your text view there?
Try getting the text view's textStorage and replacing its contents with the new attributed string by sending the text storage a setAttributedString: message.