Disable Text Replacement in Mac Application - objective-c

What's the procedure to disable Text Replacement inside a Mac OSX application written in Objective-C?
The application I'm currently debugging is using lots of NSTextFields and
from what I've found out NSTextFields doesn't seem to have the same methods as NSTextViews for disabling this:
setAutomaticQuoteSubstitutionEnabled:NO
setAutomaticTextReplacementEnabled:NO
This is although what I'm trying to achieve for all text fields within the application so what's the procedure in order to get this working?
Note that the user shouldn't be able to enable this at any point and it should also override the global settings in System Preferences -> Keyboard -> Text.

When a text field has the keyboard focus (when it is the first responder of the window), a text view is added to the window on top of the text field and handles editing for it. This text view is called the field editor.
There are various places where you can customize the field editor. Since you have many text fields, you may want to use the window delegate method -windowWillReturnFieldEditor:toObject:. It can just create an NSTextView, set its fieldEditor property to true, set automaticTextReplacementEnabled to false, and return that. It should probably only create this object once, the first time it's requested, and then return it for all calls, for efficiency.
Other approaches include using a custom NSWindow subclass which overrides -fieldEditor:forObject: or using a custom NSTextFieldCell class for your text fields, which overrides -setUpFieldEditorAttributes:

Related

Cocoa text menu and modifying fonts in NSOutlineView

The system supplied text menu works by sending a number of messages like changeFont: modifyFont: and addFontTrait: up the first responder chain until it reaches an NSTextView for example.
I'd like to extend this to control row styles in my NSOutlineView but I have only been able to override changeFont: in my window controller and intercept the message (maybe a better place to do this but it works for now). This works for changing fonts but the other menu items like Bold, Bigger, Smaller which use modifyFont: and addFontTrait: aren't ever getting called in the window controller so I can't modify their behavior to work on the outline view. Interestingly they appear selectable in the menu but only changeFont: is called and as I understand it I need to get a tag value from the NSMenuItem which is the sender of the methods modifyFont: and addFontTrait:.
Does anyone know how to implement this functionality by getting those other methods to be called anywhere? Thanks!
This is documented in the Cocoa Text Architecture Guide: Font Handling – Handling Font Changes. The -addFontTrait: and -modifyFont: messages are not sent up the responder chain. They are sent directly to the font manager. The font manager makes a note of the requested modifications and sends -changeFont: up the responder chain.
You should only need to implement -changeFont: as you have.
You do not get the tag from the menu item. The font manager does that. That's the source of the information that the font manager records internally.
Your -changeFont: method should call -convertFont: on the font manager, passing the current font. That method will return a new font modified as per the recorded change request. You would do that for all the fonts which should be affected. (For example, you might have a selection with multiple fonts in it.)
You do not normally have direct access to the requested modifications, such as "add the Bold trait" or "make the font bigger".
You can customize the font manager by subclassing NSFontManager and passing your subclass to +[NSFontManager setFontManagerFactory:] very early in app start-up. In your custom font manager, you can separately track the changes requested by the various action messages like -addFontTrait:. Here is where you would check the tag of the sender. Then, in your outline view you could query the properties of your the sender of -changeFont:, after verifying that it's an instance of your subclass, to determine what change(s) were requested.
Remember, though, that your custom subclass will be used throughout your app, not just for your outline view. So, your customizations should be in addition to the normal behavior of NSFontManager, not instead of, so it doesn't break stuff.

NSTextField Key Interface Control (KIC) behaviour

Background: I have a custom derivation of NSTextField that I am trying to use as a cell in a grid similar to a spreadsheet.
I have set the nextKeyView of my NSTextField and am confused between two states that the NSTextField can have BOTH of which involve it having the blue focus-ring drawn around it:
the cursor is blinking in it => in this case the TAB key behaves as expected and moves to the nextKeyView and it is in a "text accepting" mode
it has not quite "entered" the text field for the purposes of text editing => the TAB key does not respond with KIC behaviour and move to the nextKeyView and trying to enter any text just in fact results in the following:
-[NSEvent key]: unrecognized selector sent to instance 0x60800012bf40
From background reading and a bit of debugging it appears that the first state corresponds to control/focus being handed off to the window's shared text editor and the custom NSTextField actually loses firstResponder status in this process.
What's interesting is how this differs from the behaviour of two standard NSTextField controls dragged onto an NSView in Interface Builder. Running such a simple app only the first state above is present at all as you tab from one NSTextField to the other! I am glad to have the intermediate second state in my app (because I need it) but I don't understand why it is happening...
Summary: two related questions
How do I programmatically control the NSTextField entering these two states of effectively accepting text and not while it has the focus [I do not know how to achieve this at all so this is my main problem...]
How can I get the KIC behaviour in the situation where the NSTextField has the focus but is not in "text editing" mode since this is the behaviour I am trying to get. [My current conclusion is that KIC does not work in this situation and that standard practise would be to resort to the regular overriding of keyDown for the set of keys that would normally be associated with KIC.]

How to disable context menus with right mouse click in an NSTextField (Cocoa)?

I'm working on a Cocoa application that has editable text fields. These text fields need to accept values but don't need to be spell checked or use any of the other options given in the default context menu. I've read that the easiest way to remove the right click/ opt + click context menu is to override the function:
rightMouseDown:(NSEvent *)
I've done this in a custom NSTextfield class. This fix blocks the user from right clicking when the text box is enabled and unselected, but as soon as the user double clicks/enters the text field for editing the default right click functionality returns.
Is this because the firstResponder switches to a class in the inheritance chain upon trying to edit the field? Is this approach the right way to disable all context menu functionality for this NSTextField?
Thanks!
When a text field is editing, the actual first responder is the "field editor", an NSTextView supplied by the window. The field editor always uses the control on whose behalf it is acting as its delegate.
So, in order to influence its behavior with respect to the contextual menu, you need to use a custom subclass of NSTextField. (I guess you already are to override -rightMouseDown:.) Then, implement the text view delegate method -textView:menu:forEvent:atIndex: and return nil (i.e. no menu).

Modify multiple NSTextView with commands

I'm wondering if anyone knows if it is possible to modify multiple NSTextViews with a menu bar command. For example if the user selects "Bold" from the menu bar, the different NSTextViews that are selected update all their content to show bold.
Here is the set up I have:
#interface MyCustomTextField : NSView <NSTextViewDelegate>{
NSTextView *textView;
BOOL selected;
...
}
So basically I have my own custom class and within each custom class I have a NSTextView, a var determining whether or not this view is selected and some other stuff.
I'm able to select multiple fields however from what I've read on Apple documentation every NSTextView in the window shares one field editor. When a user edits a NSTextView they are actually sending commands to the field editor which processes it and routes it to NSTextView. If this is the case does that mean that I need to create my own custom field editor and route the commands to all my custom selected text classes instead?
==edit==
My CustomTextField classes have a variable named "selected" (see above) and by holding the shift or apple key down I'm able to "select" multiple CustomTextField instances (I put a mask in front of the NSTextView instances which catches the mouseDown message).
So by this selection, multiple instances have their "selected" attribute set to true. As far as the first responder for the window, it would be set to the mask that shows the blue halo around all the NSTextViews.
I'm wondering if I can tell the app to accept default NSTextView commands (such as bold, italicize, etc.) and that if I supply a custom field editor, it will pass all the appropriate messages to the selected CustomTextFields which will then pass it on to the NSTextViews.
In my head the message would be passed like this:
User Submits Text Toolbar Command > Custom Field Editor > MyCustomTextField > NSTextView
Hopefully my explanation made sense or maybe I'm in LaLa land now.

Objective-C & Interface Builder for Dummies: How do I bind the keyboard?

So, I've been reading through other questions on here and Xcode's documentation, but I'm still a bit confused. Here's the scenario: I have a login screen for my app which has 3 text fields and 1 button. Each text field is bound to have a Return Key in IB: Next, Next, Go.
Now, how do I bind these return keys to actual actions where field 1 moves to the next, then field 2 moves to the next, and last field 3 triggers the button?
Some answers for similar questions suggest the use of textFieldShouldReturn method, but I'm still fuzzy on it. Somehow I can't see how it auto-magically knows what to do without having some kind of binding...
What you need to do is use an IBAction to select the next field when the return key is pressed. To do this, first add a method like this to your UIViewController. Make sure to add the method declaration to your header.
- (IBAction)selectSecondField:(id)sender
{
//_secondField is the IBOutlet to the second field
[_secondField becomeFirstResponder];
}
Build and then go to Interface Builder. Select the first text field and open the connections inspector (⌘2) and drag from the dot next to "Did End On Exit" to your controller with the action. A menu of actions will pop up, select selectSecondField.
You will need an action for each field. Alternatively, you could have one action and use sender to see which field was returned.
There's a handle (in the connections panel) on each text field called "nextfield" or something along those lines? (I can't remember off the top of my head) But if you drag that to the next box, that's how it knows (manually). I think generally it guesses using the X/Y location, but when you need to manually do it, just drag that handle.