glenstorey
glenstorey

Reputation: 5154

Disable NSButton when multiple items selected - Cocoa Bindings

I'd like to disable a NSButton when multiple items are selected in a NSTableView which is connected to a NSArrayController. I know I can easily disable a button when nothing is selected (binding to @count), but I'm not sure how to reverse that so that @count has to be == 1 to be enabled.

I am using Swift, but I'm more interested in the best method than a language specific implementation (unless the difference between Swift and Objective C is a big one in this instance).

How can I use Cocoa Bindings to disable a NSButton if the selection includes more than one row?

Upvotes: 1

Views: 714

Answers (2)

Paul Patterson
Paul Patterson

Reputation: 6918

Assuming your existing binding binds your button's enabled binding to your array controller's selectionIndexes property, you can achieve what you're after with a value transformer:

enter image description here

The button's state will be updated any time there's a change to the array controller's selectionIndexes property. Part of this update will involve a call to your value transformer, where the incoming value will be the updated selectionIndexes. Your transformer logic must transform this object into a boolean (enabled, or not-enabled), which will in turn determine the state of the button:

@objc(SelectionIndexesCountIsOneOrZeroTransformer)
public class SelectionIndexesCountIsOneOrZeroTransformer): NSValueTransformer {

    override public class func allowsReverseTransformation() -> Bool {
        return false
    }

    override public class func transformedValueClass() -> AnyClass {
        return NSNumber.self
    }

    override public func transformedValue(value: AnyObject?) -> AnyObject? {
        var retval = false

        if let indexSet = value as? NSIndexSet {
            retval = (indexSet.count < 2)
        }

        return retval
    }
}

Upvotes: 2

vadian
vadian

Reputation: 285180

  • We assume that the class containing the table view is called tableViewController
  • Declare a property selectionIndexes in tableViewController.

    Objective-C:

    @property NSIndexSet *selectionIndexes;
    

    Swift:

    dynamic var selectionIndexes = NSIndexSet()
    
  • Bind Selection Indexes of the table view to that property.

  • In tableViewController add these two methods

    Objective-C:

    + (NSSet *)keyPathsForValuesAffectingEnableButton
    {
      return [NSSet setWithObject:@"selectionIndexes"];
    }
    
    - (BOOL)enableButton
    {
      return self.selectionIndexes.count < 2;
    }
    

    Swift:

    override class func keyPathsForValuesAffectingEnableButton(key : String) -> Set<String> {
         return Set<String>(["selectionIndexes"])
    }
    
    func enableButton() -> Bool
    {
      return selectionIndexes.count < 2
    }
    

    keyPathsForValuesAffecting<key> is a method to easily implement a key-value observer.

  • Now bind the Enabled property of the button to enableButton of tableViewController.

If you are using an array controller, bind Selection Indexes of the table view to selectionIndexes of the array controller and Selection Indexes of the array controller to selectionIndexes of tableViewController.

Upvotes: 4

Related Questions