Cocoa Data Binding - One view object bound to two 'enabled' properties - macos

Using Cocoa Data Binding I have bound a button's 'enabled' property to two separate 'Model Key Paths' (Enabled and Enabled2).
The idea is that the button will become enabled if either of these properties is true.
Unfortunately, it only works if both become true.
Can anyone help me change this logic from AND to OR?

Cool question-- I'm going to make a shot in the dark, I can't confirm it for you until tomorrow, but try this maybe?
Create a new property, enabledOrEnabled2 (maybe with a better name).
Override the getter (-(BOOL)enabledOrEnabled2) for this property,
to just return (Enabled || Enabled2)
Set the Key Path to be enabledOrEnabled2
I'm a little skeptical if this will work because Cocoa Bindings work by using KVC and KVO. So atm, your view controller is observing your Enabled and Enabled2 properties. What happens during runtime is that Cocoa will override your properties w/ their own KVO properties that look and act just like you think they would. Except the setters have been overridden, to send out notifications to observers.
I think the problem with my solution is that -(void)setEnabledOrEnabled2 will never be called, because you will only be setting your Enabled and Enabled2 properties. Therefore, the Cocoa overridden -(void)setEnabledOrEnabled2 will never notify your observing view controller
EDIT: Just read #stevesilva's comment, and didn't even know that dependent keys was a thing. Looks like you could definitely implement it this way if you wanted to
Actually, a first-thought hack would be to switch from overriding the getter (like I first recommended), and instead override the setters: -(void)setEnabled and -(void)setEnabled2, and add a line, something like: _enabledOrEnabled2 = _Enabled || _Enabled2. That way anytime you set your two BOOL properties, it will update enabledOrEnabled2, which will then send a notification out to it's observer, your view controller.
But now that I've written that out, I was wondering about the second part of Cocoa Bindings, KVC to modify the model whenever the view sees changes.
And because you are actually using Bindings on an Enabled state-- I actually don't think you should be using Bindings. This is because the view can't actually be modified (i.e, you can't modify the enabled state of a button). So you wouldn't ever need to use KVC to change enabledOrEnabled2, you only need your button to observe BOOLs to know if it should be enabled or not.
So scrap everything I said thusfar--
What you should do is still modify the setters ( -(void)setEnabled and -(void)setEnabled2 ), and before setting the ivar you should add a line:
[self.button setEnabled:(_Enabled || _Enabled2)];
That should do the trick for ya :)
Sorry for rambling a bit, I feel like the info I wrote initially may be helpful so I decided not to delete it

Related

Duplicate of first entry in navigation bar in custom Visual Studio Language Service

I'm implementing a Visual Studio Language Service for a custom scripting language used internally at my company, and I've run into an issue with the navigation bar implemented as a subclass of TypeAndMemberDropdownBars. The subclass is created by my LanguageService subclass' LanguageService.CreateDropDownHelper method.
In the OnSynchronizeDropdowns method I'm iterating through the types defined in the file and adding DropDownMembers to the passed-in array to fill out the navigation bar. The issue I'm seeing is that the first item in the array is being duplicated and placed at the end of the listing by code that I don't have access to. This extra item does not behave correctly when selected (nothing happens), but doesn't seem to cause any other issues; the rest of the items in the list work fine. Additionally, this only seems to happen for the type dropdown box - the members dropdown box does not display this behavior.
I'm hoping someone else has seen and resolved this issue and could provide some assistance. Thanks!
Turns out this was caused by me calling LanguageService.SynchronizeDropdowns from my LanguageService.ParseSource method, which was being called on a background thread. I've fixed the problem by setting a flag when ParseSource does a Check parse, and then implementing a check for that flag in my LanguageService.OnIdle function that will call SynchronizeDropdowns. It's now working as expected!
A better solution is to implement the LanguageService.OnParseComplete callback, and call SynchronizeDropdowns from there. OnParseComplete is always called from the main thread, so this prevents any synchronization issues from coming up, and also keeps you from having to keep track of whether or not you need to call SynchronizeDropdowns().

Custom editor in QAbstractTableModel

Does anyone have an example of using a QWidget as an editor in a QAbstractTableModel?
I have a column which when edited should create a QCombobox with the list of choices.
The docs seem to suggest I need to write a QAbstractItemDelegate and a custom paint function but that seems overkill to simply pop-up a standard QCombobox in Qt::EditRole.
Note - the combo box contents are the same for every row and it only needs to be shown when somebody clicks in the cell.
I know this should be simple but I can't get it to work. It's easy for a QTableWidget based table - but I need it for a very large data table.
The docs seem to suggest I need to write a QAbstractItemDelegate and a custom paint function but that seems overkill to simply pop-up a standard QCombobox in Qt::EditRole.
You don't need to go that far. One way is to subclass QStyledItemDelegate and then override createEditor() so that it returns your prepopulated combo box. Its setEditorData and setModelData functions will probably already suffice if you`re using basic Qt value types.
If you need something more generic that works across many different models, you can create a QItemEditorFactory that associates your editor with the correct type. This also works well with custom types.
When indicated by your view's EditTrigger, your view will get the delegate specific to the cell on which the edit is being invoked and call delegate->createEditor(...) which can then size the combo box according to the options parameter as well as set the current entry to the value specified by the model, although most of this should be handled by the QStyledItemDelegate. Thus, you won't have to worry about the Qt::EditRole directly as the view will handle that.
Did you try and have a look at the following example from Qt :
Spin Box Delegate Example
Maybe it will give you a much clearer view on the subject !
Hope it helps a bit !

Trouble with data not saving with bindings and shared NSUserDefaults in IB

I'm having a bit of a strange issue that I can't quite figure out. I'm somewhat of a n00b to Interface Builder. What I am trying to do seems like it should be simple, but it's not working for some reason.
In interface builder I have a preferences window with a simple NSTextField. I have set the value binding to the Shared User Defaults Controller with the controller key "values" and model key "test". I build/run my app and open the preferences window, type some random value into said text field, close the window. Command-Q the app. Then in a shell i do a "defaults read com.xxx.yyy" for my app and the key and value are nowhere to be found. That being said, it seems like the next time I fire up the app and change the value it works but only if I switch focus off of the NSTextField before closing the window.
In the documentation for NSUserDefaults it says that the shared controller saves values immediately, am I missing something stupid here?
Thanks for any help.
I'm answering this a long time after it was asked in case others find it useful.
It sounds like you need to set "Continuously Updates Values" for the text field you've bound. Otherwise, the value is only sent and, accordingly, the preferences only updated when something happens to 'finalise' the edit. That's usually triggered by pressing Return and probably also happens when you switch focus away from the window (though I just tested this in one of my own applications and it didn't seem to commit the edit).

What are some good ways of managing settings in gui applications?

If I have a setting that is accessible via a menu item or configuration window that can change at runtime, for example "bold text on/off"; what are some good ways of ensuring that all applicable components are aware the value of this setting?
You didn't provide specifics of an implementation language, so the asnwer will be somewhat generic.
Assuming your GUI is in a language which supports even model (e.g. Java), simply have an event handler for any component which should be affected by settings and which gets triggered on an event "setting changed". Then call such event from the setting config window. Don't forget to redraw when all components are done updating (ore redraw as each component is updated).
An additional point is to hopefully have generic sub-components used.
As an example, if you are using label text with a certain font which is configurable, then use a common "label with configurable font" class which ensures you never need to assign the above event listener to every label you create.
If there will be a lot of setting I have implemented a sqlite DB to hold the changes for smaller amount of changes key value pair in a file is good enough. Then implement a observer design pattern so when any changes are done a list of gui classes are called to do the change.

Is it possible to access the previous/current value of a proxy object using KVO?

I've got an NSArrayController, and I'm using KVO to observe the Old/New values of it's selection method.
This works perfectly (triggers when the selection changes, the usual) except that the items in the change dictionary are all null instead of being the old/new selected object. [arrayController selection] still returns the proper object, but I'd like to be able to access the previously selected object as well if possible (my workaround will probably be to observe the selected index instead and see if that works).
The only possible reason for this I've come up with is perhaps it's because the NSArrayController is a proxy object.
So is this the expected behavior, or is something weird going on?
EDIT: I tried observing just the Indexes, but that didn't work either. Both old and new keys still show up as null.
mmalc's Cocoa bindings page says:
The change dictionary doesn't contain old and new values. This is not your fault, it's due to a bug in the controller. This bug will not be fixed in the forseeable future.
For plain KVO (as opposed to bindings), try observing the selectedObjects property instead of the selection property. That will give you a straightforward array of objects instead of the proxy objects which are used by the Cocoa bindings system. I believe the old/new keys should accurately reflect the change in the selection that way.
Are you using NSKeyValueObservingOptionNew, and NSKeyValueObservingOptionOld in the options of addObserver:forKeyPath:options:context:?
If you could show us some code it would be helpful.

Resources