How to show NSTextView-like context menu - macos

I want to present NSTextView-like context menu for a certain NSString object (say, "text") each time -rightMouseDown-method of my custom NSResponder-subclass get called.
Where can I obtain these items for some NSString?
UPD
Created NSTextView instance and used its -menuForEvent:-method. Some of items was disabled (like 'copy' and so on), I reset its target value to custom object with overridden selectors (like -copy: and others).

NSTextView is an NSView subclass, which provides a class method +defaultMenu. So you can ask for NSMenu * menu = [NSTextView defaultMenu]; to get your very own copy to do with as you please. You may have to walk its structure and customize individual NSMenuItem instances to adjust their target/action but most (all?) should work just fine with nil-target (sends action to first responder) and their default action.
I must admit, however, I'm not sure what you mean by "Where can I obtain these items for some NSString?" The context menu is opened from some UI control (like a text view) and sends its action (like -checkSpelling...) to some target (like the first responder; which should be something like a text view, which acts as the view for a string or attributed string) to act upon.

Related

How to get notified of clicks in a view-based NSTableView

I have a view-based NSTableView containing a list of words. When the user double-clicks on a word, I would like to take an action. The words are not editable or selectable. How do I do this?
I have tried setting the target and action of the table view in IB, but it only calls the action method when the user clicks in the header of the table, not in one of the words.
I have tried setting the target and action of the NSTextField that the table cell view keeps in IB. This results in this error message being repeated in the console:
2018-01-02 14:14:32.080347-0800 WordExplorer[7089:21457459] Could not connect action, target class NSObject does not respond to -relatedWordClick:
However the target class does respond to the selector. (I connected it in IB directly, so clearly, it does!) It is also not a simple NSObject, so I'm guessing that something else is going wrong there.
I have tried manually calling -setTarget: and -setAction: on the NSTextField contained in the table cell view in my delegate's -tableView:viewForTableColumn:row: method. This has no effect, and the debugger shows that despite calling those methods, they do not set the text field's action or target method. (Though, given this is Xcode we're talking about, it's likely that's just a debugger display issue.) I get no errors in the console like when I make the connection in IB, but it also does not call the appropriate method.
Do I need to make custom view class and use that for the table cell view? Or is there a simpler way to get clicks (and preferably double-clicks) on words in my list?
Simply create an IBAction on the object you have as the NSTableView's target, and then set the NSTableView's doubleAction property to the selector for that IBAction, and you can handle double-click events easily.

Trying to see the delegate of an NSTextView of an NSCell

I am having a devil of a time trying to figure out how to get the address of the Text Field Editor (NSTextView) of an NSCell—NSFormCell and NSTextFieldCell in particular? NSCell does not have a property to access it. I did figure out the editor is not allocated until one is actually editing the field.
I want to set the delegate so I can capture keystrokes for auto-completion.
By default, there's a single field editor for each window. Even if a control or cell uses a custom field editor, it's still vended by the window. You would call -[NSWindow fieldEditor:forObject:] to obtain the field editor for a given control.
However, the delegate of the field editor is always set to the control on whose behalf it is working. Setting the delegate to something else is likely to break things. So, you would typically use a custom subclass of the control and implement your delegate methods there.
Finally, controlling completions is normally done using -textView:completions:forPartialWordRange:indexOfSelectedItem: in the text view delegate, not by capturing keystrokes.

How to programmatically add new NSToolbarItem to existing toolbar?

I'm looking for a method called addNewItem:(NSToolbarItem *)item or something like this that lets me add a programmatically created item to my toolbar, but I haven't found any. I would like to add an item that shows a popover when the user clicks on it, like in Safari when the user downloads something.
You need to have a class that conforms to the NSToolbarDelegate protocol and have an instance of that class be the delegate of your toolbar. This delegate would, for example, implement -toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar:, which returns an NSToolbarItem instance for a given identifier, potentially creating that item on demand. By doing this, you’re preparing your delegate to return a toolbar item when the toolbar asks it for the item corresponding to an identifier.
Having done that, you can programatically add a new toolbar item to the toolbar by sending -[NSToolbar insertItemWithItemIdentifier:atIndex] to the toolbar instance. The identifier string argument should match the one used in the paragraph above. If you need to remove an item, send -[NSToolbar removeItemAtIndex:] to the toolbar.
This is described with examples in the Adding and Removing Toolbar Items section of the Toolbar Programming Topics for Cocoa document.

NSTextFinder action on NSTextView

I'm trying to capture all the NSTextFinderClient calls on my custom NSTextView subclass.
The show action is called on my -(void)performTextFinderAction:(id)sender override, but for find next, find previous, etc. it's not called.
Any ideas?
Thanks!
Edit:
If you create a new project and drag an NSTextView from interface builder, command-g and command-shift-g (find next and find previous) don't work when the find bar is first responder.
Why is this?
I need a custom subclass of NSTextView to respond to the find bar for every event.
I searched in the Apple's TextEdit source code because with TextEdit, the standard search bar within the Text View works fine for command-G (and other shortcuts) even the search field is the first responder.
I found the solution.
Go to your nib for the main menu, and select the "Find" (and related) menu items. They should be bound to the default action called "performFindPanelAction:." Now unbind them and bind to "performTextFinderAction:" of the First Responder instead.
You may not find that action in the First Responder's action list. So you need to add it by yourself in the First Responder's attributes inspector pane.
This was meant by the document below saying
Before OS X v10.7, the default action for these menu items was performFindPanelAction:. Whenever possible which you should update your implementation to use this new action.
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSResponder_Class/#//apple_ref/occ/instm/NSResponder/performTextFinderAction:
The find bar communicates privately with the client's NSTextFinder instead of calling NSResponder's -performTextFinderAction:. This is necessary to allow find to work when something besides the client has key focus.
What are you trying to accomplish?

Accessing objects on one nib file from another nib file

I have two nib files - Main.nib and Preference.nib
In Main.nib file I have an instance of NSView class. Its window has a NSPopUpButton which on clicking shows a menu. In the menu I have show Preferences menu item.
Menu item on clicking shows a preferences panel containing a color well item.
On clicking color well a color panel is displayed to choose the color.
The problem is how to apply that color to main application window.
My preference panel window is in Preference.nib file.
So problem is accessing NSView from another Nib Window.
Is there a way so that I can make connection between preference panel and my main application window(NSView)
You're thinking about this at the wrong level. NSView and NSWindow are view objects in the Model-View-Controller pattern and shouldn't be used for holding application data. The color you select in your preference panel is application data and should be stored in an appropriate model object.
You could, for example, use bindings to bind the color well to the NSUserDefaultsController object to store that data (assuming this is an application-wide setting). You didn't say exactly what the color is used for in your main window, but if the object that uses it is bindings aware, you can bind that object to the same value on the NSUserDefaultsController and you're done.
Otherwise, you can respond to the color well's action message to store the color in an appropriate place and then send a notification using NSNotificationCenter to tell other objects that the color has changed. You'll need to sign up any object that needs to take action when the value changes for your notification message.
Here are some resources:
Here's an overview of the model-view-controller pattern that explains how Cocoa programs are structured
This is a high level explanation of how Cocoa bindings work
Here's a bunch of documents about using notifications

Resources