Next key view of NSTextView find bar - objective-c

Suppose there is a window which has two NSTextViews in it, and each of them uses the findBar.
The problem is that after closing one find bar (finishing the finding) the cursor jumps to the other textView, i.e. the focus does not return the the textView for which the find operation originated.
Please, does anyone know how to make it return to the original view?
This is a screenshot of one simple setup:

You can assign the nextKeyView property in StoryBoards (see image below) to assign where you want to the focus to "jump", otherwise, if you need to assign the nextKeyView property programmatically (when the view is initialized), you can do so using the nextKeyView property available via the NSView class. Both methods are hinted at below:
1. Assign the nextKeyView programmatically via this property
#property(assign) NSView *nextKeyView;
2. Or you can assign the nextKeyView in storyboards
Hope this helps!

Set the nextKeyView property of the text field back to the original view.

You can create the subclass of textview and mention the same inside your interface builder->Custom class and inside your custom textview class override the below method:-
-(BOOL)becomeFirstResponder
{
return YES;
}

Related

How to bind click action of NSButton in view based NSTableView

I have an NSTableView that is set to be 'view based', and within each NSTableCellView there is an NSButton and an NSTextField.
The text field is being populated correctly from an array controller. The buttons are appearing correctly but I'm having trouble working out how to hook up the click action.
I thought this would be possible by control-dragging from the NSButton in IB to a simple method like this one in my controller (in this case an NSDocument subclass):
- (IBAction)testAction:(NSButton *)sender {
NSLog(#"Test action");
}
It connects fine but never gets fired. Any ideas why this is or how to fix it?
I don't understand why this works, but I had the same problem and was able to get it working by assigning the table delegate and datasource to the file owner within IB, which is also the class of my click handlers. Only then did it seem to actually bind the click handlers for the buttons in my cell view. Previously I was setting the delegate and datasource in code after the view was loaded.
You have to subclass NSTableCellView class. put your onClick Action method in subclass files.
Let me know if i am not clear..

NSStepper in NSTableCellView has no effect

I’m using a regular (not subclassed) NSTableCellView in a view-based table view. It has the initial image and text field views. I added an NSStepper to the view.
The text field is bound to tableCellView.objectValue.quantity.
The stepper’s value is bound to tableCellView.objectValue.quantity too.
The problem is that when running the app, when I click the stepper it doesn’t seem to get the mouse event, neither arrow gets highlighted, the value is not incremented or decremented.
If I set the double action of the table view it gets triggered if I double-click the stepper as if it was transparent.
What am I missing?
Thanks!
You should look at the documentation but easiest is that you need to subclass NSTableView and override this method to validate the proposed first responder. As the document states NSTableViews disallow some controls to be used unless the row is first selected. Even then it still may discard some.
- (BOOL)validateProposedFirstResponder:(NSResponder *)responder forEvent:(NSEvent *)event {
return YES;
}
Further to the correct answer from Robert Payne, with Swift you could add an extension to NSTableView and not subclass it.
extension NSTableView {
override public func validateProposedFirstResponder(responder: NSResponder, forEvent event: NSEvent?) -> Bool {
return true
}
}
And I'd like to emphasis that it's the NSTableView not the NSTableViewCell.

Highlighting selected item in a NSCollectionView using NSBox

How do I make the NSCollectionView update to show the currently selected item using an NSBox? Displaying selection in a list seems like a basic thing, but I'm having all kinds of trouble with this.
I've read this question and also looked at the sample code from Apple. There seems to be several ways to do this.
Using a subclasses of NSCollectionViewItem and special "prototype view".
Using a NSBox.
I wish to use the NSBox way since it seems simples and is also used in the official code sample.
It's apparently done as described in the following quote by alternegro:
If a different background color will suffice as a highlight, you could
simply use an NSBox as the root item for you collection item view.
Fill the NSBox with the highlight color of your choice. Set the NSBox
to Custom so the fill will work. Set the NSBox to transparent.
Bind the transparency attribute of the NSBox to the selected attribute
of File Owner(Collection Item) Set the value transformer for the
transparent binding to NSNegateBoolean.
I'm stuck at the very first part: "use an NSBox as the root item for you (sic) collection item view". I've tried to change the "Custom Class" to a FoobarBox that inherits from NSBox, but it doesnt seems to help as I cannot change the background color to blue nor can I bind the transparency. Any pointers on how to make the selection display in my NSCollectionVuew would be appreciated.
First, create a class for your ListView that inherits from NSBox
#interface MyListViewBox : NSBox
#property (unsafe_unretained) IBOutlet NSCollectionViewItem *controller;
#end
Then, in Interface Builder, specify your class name as "Custom class" property as shown on my screenshot
Then you will realize IB does not show NSBox properties or binding in the GUI (at least with version 4.5.2), so I decided to change the properties programmatically.
Create an outlet for NSCollectionViewItem in your NSBox subclass (as seen above)
Use IB to link the outlet to your NSCollectionItemView
in -(void)awakeFromNib for your NSBox subclass, add the following code
-(void)awakeFromNib {
//properties are not showing up in XCode Inspector IB view
//configuring the box here :-(
self.boxType = NSBoxCustom;
self.borderType = NSLineBorder;
self.fillColor = [NSColor selectedControlColor];
//bind the "transparent" property of NSBox to the "selected" property of NSCollectionViewItem controller
//controller is bound as IBOutlet in IB
NSValueTransformer* transformer = [NSValueTransformer valueTransformerForName:NSNegateBooleanTransformerName];
[self bind:#"transparent"
toObject:self.controller
withKeyPath:#"selected"
options:[NSDictionary dictionaryWithObjectsAndKeys:transformer, NSValueTransformerBindingOption, nil]];
}
In XCode 4.5.2, you can just delete the NSView that comes automatically with the NSColletionView and drag in an NSBox (which will have all the appropriate bindings available). Make sure you re-bind the CollectionView to your new Box.

Getting NSArrayController item for right click in NSCollectionView

I'm trying to create a file explorer using nscollectionview and am currently implementing a right click menu for each item (i.e. copy/delete/rename/etc). I currently have:
An NSCollectionView linked with an NSArrayController which holds a custom object
A subclass of NSBox as the view for each item, this also tracks mouse events and passes them to the controller
The controller has an NSMenu outlet (rcMenu) and also an NSView outlet (itemView) for the NSBox subclass that should be where the menu popup
The code for calling the menu is:
[NSMenu popUpContextMenu:rcMenu withEvent:event forView:itemView];
Once run, this works in that the menu pops up when right clicking the item in the collection view, but on inspecting the event that's passed to the controller, there's not really anything I could use to find out which item was right clicked other than the x,y coordinates (which seem to be for the NSWindow rather than the item or NSCollectionView). What I really want is the object in the NSArrayController that had it's view right clicked.
Is this down to me setting it up incorrectly, is there an easy way to figure it out, or is it just that tough to work it out?
You might try setting the menu of each collection view item's view. Most likely, you'll do this by overriding +defaultMenu in your item view class. Once you do that, comment out the popUpContextMenu:withEvent:forView: message and see whether you can get away without it.
Furthermore, it would then not be too hard to serve up different menus for different kinds of items (e.g., folders vs. packages vs. files, and different types of files at that). You'd probably have to override -menuForEvent: instead of +defaultMenu.
I found an other solution that might help.
For this solution I made a subclass of NSCollectionViewItem and NSView, respectively (and for the ease of explaining) ItemViewController and ItemView.
I'm assuming you work with IB where you have already bound your NSCollectionView to the ContentArray of your NSArrayController (also bind the selectionIndexes).
Next add an ViewController object to the NIB and make sure its custom class is set to the ItemViewController. Now connect it to the itemPrototype outlet of your NSCollectionView.
Next add a Custom View object to the NIB and set its custom class to ItemView. Connect its outlet to the view property of your ItemViewController.
In the interface file of ItemView create a representedObject-like property. With this I mean something like:
#property (nonatomic, assign) id someRepresentedObjectPropertyName
This will be the property which will represent the item in your NSArrayController.
Now go to the implementation file of ItemViewController and override the -setRepresentedObject: method. In here we will first let the ItemViewController handle setting its representedObject, afterwards we assign the same representedObject to the property we made in ItemView. The override would look like:
-(void)setRepresentedObject:(id)representedObject {
[super setRepresentedObject:representedObject];
//Do some appropiate checking on the representedObject...
if (self.view != nil) {
[(ItemView *)self.view setSomeRepresentedObjectPropertyName:self.representedObject];
}
}
Now if you go back to the implementation of ItemView you can override the method -rightMouseUp: and build/set-up a NSMenu there and use the -popUpMenuPositioning...: method. The someRepresentedObjectPropertyName property of ItemView should be set to the correct item in your NSArrayController.
EDIT:
Instead of overriding -setRepresentedObject you could also bind the ItemView's someRepresentedObjectPropertyName to representedObject.someRepresentedObjectPropertyName

Can you set a navbar's edit button in Interface Builder?

It's easy enough to set up a table view to allow editing. Just add one line to your UITableViewController:
self.navigationItem.rightBarButtonItem = self.editButtonItem;
This line adds an edit button on the nav bar that will change the table to editing mode and change its button text to "Done" while editing.
Is it possible to set this up in Interface Builder? I see that you can add a UIBarButtonItem and can set its "Identifier" to "Edit", but I don't see the expected behavior.
BTW, what does the "Identifier" in the Attributes panel do?
Yes, you can add UIBarButtonItems in Interface Builder, and they should work.
The identifier lets you use a preset button (like Edit or Reload), or you can choose Custom and make your own button.
EDIT: I may be able to help further if you could explain how UIBarButtonItems added through IB don't work.
UPDATE: UIViewController.editButtonItem is a special method that returns a UIBarButtonItem that invokes the view's setEditing method. You can achieve the same effect by creating a method that does the same thing and connecting the selector to your UIBarButtonItem in IB.
In your header file:
- IBAction edit:(id)sender;
and in your implementation file:
- (IBAction) edit:(id)sender {
[self setEditing:YES animated:YES];
}
then connect the selector to the UIBarButtonItem.
However, you might not be able to create this connection in the default Navigation-Based Application template since the Table View is in a separate file.
Have a look here: http://blog.tmro.net/2009/05/uitabbarbuttonitem-did-not-change-its.html
If you want your button to be able to change its label dynamically make sure you use a custom identifier otherwise its title will be immutable.
We still can't seem to do this specifically in Interface Builder as of Xcode 9.4.1. It's very easy to do in code, though.
You don't need to set up the button in IB at all. Simply add this code in your viewDidLoad method:
navigationItem.leftBarButtonItem = editButtonItem
That automatically sets up the Edit button, which turns to Done so the user can end editing.
To do anything custom associated with the editing process, override the view controller's setEditing(_ editing: Bool, animated: Bool) method.
For example, if you have a table view whose editing needs to be turned on and off, you can do this:
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
tableView.setEditing(editing, animated: animated)
}
Make sure to call super.setEditing here.
Note: if you're using a UITableViewController, setEditing is already set up in the super class to handle the table view. You don't need to override it, unless you have other custom code you want to include when editing is enabled/disabled.