Cocoa Text Architecture Guide
Cocoa Text Architecture Guide
Guide
Contents
Text Attributes 35
Character Attributes 35
Contents
Font Handling 39
The Font Panel 39
Creating a Font Panel 39
Using the Font Panel 40
Working with Font Objects 40
Font Descriptors 41
Querying Font Metrics 42
Querying Standard Font Variations 43
Characters, Glyphs, and the Layout Manager 44
Getting the View Coordinates of a Glyph 45
Working with the Font Manager 45
Creating a Font Manager 45
Handling Font Changes 46
Converting Fonts Manually 47
Setting Font Styles and Traits 48
Examining Fonts 49
Customizing the Font Conversion System 49
Text Editing 51
The Editing Environment 51
The Key-Input Message Sequence 52
Intercepting Key Events 54
Text View Delegation 55
Text View Delegate Messages and Notifications 56
Text Field Delegation 57
Synchronizing Editing 57
Batch-Editing Mode 58
Forcing the End of Editing 59
Setting Focus and Selection Programmatically 60
Subclassing NSTextView 61
Updating State 62
Custom Import Types 62
Altering Selection Behavior 63
Contents
Typographical Concepts 12
Figure 2-1
Figure 2-2
Figure 2-3
Figure 2-4
Figure 2-5
Figure 2-6
Figure 2-7
A text field 32
A text view 33
The field editor 34
Text Attributes 35
Figure 5-1
Font Handling 39
Figure 6-1
Table 6-1
Table 6-2
Table 6-3
Table 6-4
Listing 6-1
Font metrics 42
Font metrics and related NSFont methods 43
Standard font methods 43
Font conversion methods 47
Font menu item actions and tags 50
Font family name matching 41
Text Editing 51
Figure 7-1
Figure 7-2
Figure 7-3
Table 7-1
Table 7-2
Table 7-3
Table 7-4
Table 7-5
Table 7-6
Listing 7-1
Listing 7-2
Listing 7-3
Listing 7-4
Key-event processing 52
Input context key binding and interpretation 53
Delegate of an NSTextView object 56
NSWindow field editorrelated methods 70
NSTextFieldCell field editorrelated method 71
NSCell field editorrelated methods 71
NSControl field editorrelated methods 72
NSResponder field editorrelated methods 72
NSText field editorrelated methods 73
Forcing layout 58
Forcing the end of editing 59
Forcing the field editor to enter a newline character 68
Substituting a custom field editor 70
The Cocoa text system is the primary text-handling system in OS X, responsible for the processing and display
of all visible text in Cocoa. It provides a complete set of high-quality typographical services through the
text-related AppKit classes, which enable applications to create, edit, display, and store text with all the
characteristics of fine typesetting, such as kerning, ligatures, line-breaking, and justification.
At a Glance
The Cocoa text system provides text editing and layout for most applications. The object-oriented design of
the system provides flexibility and ease of use.
Font Objects, the Font Panel, and the Font Manager Provide Typeface Handling
The Font panel, also called the Fonts window , is a user interface object that displays a list of available font
families and styles, letting the user preview them and change the font used to display text. Text views work
with NSFontPanel and NSFontManager objects to implement the font-handling system. You can create font
objects using the NSFont class and query them for font metrics and detailed glyph layout information.
Related Chapter: Font Handling (page 39)
Prerequisites
To understand the information in this document, you should understand the material in Text System User
Interface Layer Programming Guide . In addition, you should have a general knowledge of Cocoa programming
paradigms and, to understand the code examples, familiarity with the Objective-C language.
See Also
The following documents describe other aspects of the Cocoa text system:
Text System User Interface Layer Programming Guide describes the high-level interface to the Cocoa text system,
which is sufficient for most applications.
Text System Storage Layer Overview discusses the lower-level facilities that the Cocoa text system uses to store
text.
Text Layout Programming Guide describes how the Cocoa text system lays out text on a page, suitable for
display and printing.
The following sample code projects illustrate how to use many of the APIs of the Cocoa text system:
CircleView is a small application with a demonstration subclass of NSView that draws text in a circle.
NSFontAttributeExplorer demonstrates how to gather and display various metric information for installed fonts
using NSFont.
TextInputView demonstrates how a view can implement the NSTextInputClient protocol.
TextViewDelegate demonstrates using a text view's delegate to control selection and user input.
10
The Macintosh operating system has provided sophisticated text handling and typesetting capabilities from
its beginning. In fact, these features sparked the desktop publishing revolution. Over the years, the text handling
facilities of the platform have continued to evolve to become more advanced, more efficient, and easier to
use. OS X provides modern text handling capabilities that are available to all applications through the classes
of the Cocoa text system and the opaque types and functions of Core Text.
The text-handling component of any application presents one of the greatest challenges to software designers.
Even the most basic text-handling system must be relatively sophisticated, allowing for text input, layout,
display, editing, copying and pasting, and many other features. But developers and users expect even more
than these basic features, expecting even simple editors to support multiple fonts, various paragraph styles,
embedded images, spell checking, and other features.
The Cocoa text system provides all these basic and advanced text-handling features, and it also satisfies
additional requirements from the ever-more-interconnected computing world: support for the character sets
of all of the worlds living languages, powerful layout capabilities to handle various text directionality and
nonrectangular text containers, and sophisticated typesetting capabilities such as control of kerning and
ligatures. Cocoas object-oriented text system is designed to provide all these capabilities without requiring
you to learn about or interact with more of the system than is necessary to meet the needs of your application.
Underlying the Cocoa text system is Core Text, which provides low-level, basic text layout and font-handling
capabilities to higher-level engines such as AppKit, WebKit, and others. Core Text provides the implementation
for many Cocoa text technologies. Application developers typically have no need to use Core Text directly.
However, the Core Text API is accessible to developers who must use it directly, such as those writing applications
with their own layout engine and those porting ATSUI- or QuickDraw-based codebases to the modern world.
To decide which OS X text technology is right for your application, apply the following guidelines:
If possible, use Cocoa text. The NSTextView class is the most advanced full-featured, flexible text view in
OS X. For small amounts of text, use NSTextField. For more information about text views, see Text System
User Interface Layer Programming Guide .
To display web content in your application, use WebKit. For more information about WebKit, see WebKit
Objective-C Programming Guide .
If you have your own page layout engine, you can use Core Text to generate the glyphs and position them
relative to each other. For more information about Core Text, see Core Text Programming Guide .
11
Typographical Concepts
This chapter defines some important typographical concepts relevant to the text system. If you are already
familiar with typography, you can skip this chapter.
12
Typographical Concepts
Typefaces and Fonts
Characters and glyphs do not have a one-to-one correspondence. In some cases a character may be represented
by multiple glyphs, such as an which may be an e glyph combined with an acute accent glyph . In other
cases, a single glyph may represent multiple characters, as in the case of a ligature, or joined letter. Figure 2-2
shows individual characters and the single-glyph ligature often used when they are adjacent.
Figure 2-2
Ligatures
A ligature is an example of a contextual form in which the glyph used to represent a character changes
depending on the characters next to it. Other contextual forms include alternate glyphs for characters beginning
or ending a word.
Computers store characters as numbers mapped by encoding tables to their corresponding characters. The
encoding scheme native to OS X is called Unicode. The Unicode standard provides a unique number for every
character in every modern written language in the world, independent of the platform, program, and
programming language being used. This universal standard solves a longstanding problem of different computer
systems using hundreds of conflicting encoding schemes. It also has features that simplify handling bidirectional
text and contextual forms.
Glyphs are also represented by numeric codes called glyph codes. The glyphs used to depict characters are
selected by the Cocoa layout manager during composition and layout processing. The layout manager
determines which glyphs to use and where to place them in the display, or view. The layout manager caches
the glyph codes in use and provides methods to convert between characters and glyphs and between characters
and view coordinates. (See Text Layout (page 14) for more information about the layout process.)
13
Typographical Concepts
Text Layout
A typestyle, or simply style, is a distinguishing visual characteristic of a typeface. For example, roman typestyle
is characterized by upright letters having serifs and stems thicker than horizontal lines. In italic typestyle, the
letters slant to the right and are rounded, similar to cursive or handwritten letter shapes. A typeface usually
has several associated typestyles.
A font is a series of glyphs depicting the characters in a consistent size, typeface, and typestyle. A font is
intended for use in a specific display environment. Fonts contain glyphs for all the contextual forms, such as
ligatures, as well as the normal character forms.
A font family is a group of fonts that share a typeface but differ in typestyle. So, for example, Times is the name
of a font family (as well as the name of its typeface). Times Roman and Times Italic are the names of two
individual fonts belonging to the Times family. Figure 2-3 shows several of the fonts in the Times font family.
Figure 2-3
Styles, also called traits , that are available in Cocoa include variations such as bold, italic, condensed, expanded,
narrow, small caps, poster fonts, and fixed pitch. Font descriptors in the Cocoa text system provide a
font-matching capability, so that you can partially describe a font by creating a font descriptor with, for example,
just a family name or weight, and you can then find all the fonts on the system that match the given trait.
Text Layout
Text layout is the process of arranging glyphs on a display device, in an area called a text view , which represents
an area similar to a page in traditional typesetting. The order in which glyphs are laid out relative to each other
is called text direction. In English and other languages derived from Latin, glyphs are placed side by side to
form words that are separated by spaces. Words are laid out in lines beginning at the top left of the text view
proceeding from left to right until the text reaches the right side of the view. Text then begins a new line at
the left side of the view under the beginning of the previous line, and layout proceeds in the same manner to
the bottom of the text view.
14
Typographical Concepts
Text Layout
In other languages, glyph layout can be quite different. For example, some languages lay out glyphs from right
to left or vertically instead of horizontally. It is common, especially in technical writing, to mix languages with
differing text direction, such as English and Hebrew, in the same line. Some writing systems even alternate
layout direction in every other line (an arrangement called boustrophedonic writing). Some languages do not
group glyphs into words separated by spaces. Moreover, some applications call for arbitrary arrangements of
glyphs; for example, in a graphic design context, a layout may require glyphs to be arranged on a nonlinear
path.
To create lines from a string of glyphs, the layout engine must perform line breaking by finding a point at
which to end one line and begin the next. In the Cocoa text system, you can specify line breaking at either
word or glyph boundaries. In Roman text, a word broken between glyphs requires insertion of a hyphen glyph
at the breakpoint.
The Cocoa layout manager lays out glyphs along an invisible line called the baseline. In Roman text, the baseline
is horizontal, and the bottom edge of most of the glyphs rest on it. Some glyphs extend below the baseline,
including those for characters like g that have descenders, or tails, and large rounded characters like O
that must extend slightly below the baseline to compensate for optical effects. Other writing systems place
glyphs below or centered on the baseline. Every glyph includes an origin point that the layout manager uses
to align it properly with the baseline.
Glyph designers provide a set of measurements with a font, called metrics, which describe the spacing around
each glyph in the font. The layout manager uses these metrics to determining glyph placement. In horizontal
text, the glyph has a metric called the advance width, which measures the distance along the baseline to the
origin point of the next glyph. Typically there is some space between the origin point and the left side of the
glyph, which is called the left-side bearing. There may also be space between the right side of the glyph and
the point described by the advance width, which is called the right-side bearing. The vertical dimension of
the glyph is provided by two metrics called the ascent and the descent. The ascent is the distance from the
15
Typographical Concepts
Text Layout
origin (on the baseline) to the top of the tallest glyphs in the font. The descent, which is the distance below
the baseline to the bottom of the fonts deepest descender. The rectangle enclosing the visible parts of the
glyph is called the bounding rectangle or bounding box. Figure 2-4 illustrates these metrics.
Figure 2-4
Glyph metrics
By default, in horizontal text, typesetters place glyphs side-by-side using the advance width, resulting in a
standard interglyph space. However, in some combinations, text is made more readable by kerning, which is
shrinking or stretching the space between two glyphs. A very common example of kerning occurs between
an uppercase W and uppercase A, as shown in Figure 2-5. Type designers include kerning information in the
metrics for a font. The Cocoa text system provides methods to turn kerning off, use the default settings provided
with the font, or tighten or loosen the kerning throughout a selection of text.
Figure 2-5
Kerning
16
Typographical Concepts
Text Layout
Type systems usually measure font metrics in units called points, which in OS X measure exactly 72 per inch.
Adding the distance of the ascent and the descent of a font provides the fonts point size.
Space added during typesetting between lines of type is called leading, after the slugs of lead used for that
purpose in traditional metal-type page layout. (Leading is sometimes also called linegap .) The total amount
of ascent plus descent plus leading provides a fonts line height.
Although the preceding typographic concepts of type design may be somewhat esoteric, most people who
have created documents on a computer or typewriter are familiar with the elements of text layout on a page.
For example, the margins are the areas of white space between the edges of the page and the text area where
the layout engine places glyphs. Alignment describes the way text lines are placed relative to the margins.
For example, horizontal text can be aligned right, left, or centered, as shown in Figure 2-6.
Figure 2-6
17
Typographical Concepts
Text Layout
Lines of text can also be justified; for horizontal text the lines are aligned on both right and left margin by
varying interword and interglyph spacing, as shown in Figure 2-7. The system performs alignment and
justification, if requested, after the text stream has been broken into lines and hyphens added and other glyph
substitutions made.
Figure 2-7
Justified text
18
The Cocoa text system is abstracted into a set of classes that interact to provide all of the text-handling features
of the system. The classes represent specific functional areas with well-defined interfaces that enable application
programs to modify the behavior of the system or even to replace parts with custom subclasses. The Cocoa
text system is designed so that you dont need to learn about or interact with more of the system than is
necessary to meet the needs of your application.
For most developers, the general-purpose programmatic interface of the NSTextView class is all you need to
learn. NSTextView provides the user interface to the text system. See NSTextView Class Reference for detailed
information about NSTextView.
If you need more flexible, programmatic access to the text, youll need to learn about the storage layer and
the NSTextStorage class. And, of course, to access all the available features, you can interact with any of the
classes that support the text system.
19
The text classes exceed most other classes in the AppKit in the richness and complexity of their interface. One
of their design goals is to provide a comprehensive set of text-handling features so that you rarely need to
create a subclass. Among other things, a text object such as NSTextView can:
Control the font and layout characteristics of its text by working with the Font menu and Font panel (also
called the Fonts window ).
20
Write text to or read text from files in the form of RTFDRich Text Format files that contain TIFF or EPS
images, or attached files.
Let the user copy and paste text within and between applications.
Let the user copy and paste font and format information between NSTextView objects.
Graphical user-interface building tools (such as Interface Builder) may give you access to text objects in several
different configurations, such as those found in the NSTextField, NSForm, and NSScrollView objects. These
classes configure a text object for their own specific purposes. Additionally, all NSTextField, NSForm, or
NSButton objects within the same windowin short, all objects that access a text object through associated
cellsshare the same text object, called the field editor . Thus, its generally best to use one of these classes
whenever it meets your needs, rather than create text objects yourself. But if one of these classes doesnt
provide enough flexibility for your purposes, you can create text objects programmatically.
Text objects typically work closely with various other objects. Some of thesesuch as the delegate or an
embedded graphic objectrequire some programming on your part. Otherssuch as the Font panel, spell
checker, or rulertake no effort other than deciding whether the service should be enabled or disabled.
To control layout of text on the screen or printed page, you work with the objects that link the NSTextStorage
repository to the NSTextView that displays its contents. These objects are of the NSLayoutManager and
NSTextContainer classes.
An NSTextContainer object defines a region where text can be laid out. Typically, a text container defines
a rectangular area, but by creating a subclass of NSTextContainer you can create other shapes: circles,
pentagons, or irregular shapes, for example. NSTextContainer isnt a user-interface object, so it cant display
anything or receive events from the keyboard or mouse. It simply describes an area that can be filled with text,
and its not tied to any particular coordinate system. Nor does an NSTextContainer object store textthats
the job of an NSTextStorage object.
A layout manager object, of the NSLayoutManager class, orchestrates the operation of the other text handling
objects. It intercedes in operations that convert the data in an NSTextStorage object to rendered text in an
NSTextView objects display. It also oversees the layout of text within the areas defined by NSTextContainer
objects.
21
22
Figure 3-2
23
Using only an NSTextStorage object, you can search text for specific characters, strings, paragraph styles,
and so on.
Using only an NSTextStorage object, you can programmatically operate on the text without incurring
the overhead of laying it out for display.
Using all the components of the text system except for an NSTextView object, you can calculate layout
information, determine where line breaks occur, figure the total number of pages, and so forth.
The layering of the text system reduces the amount you have to learn to accomplish common text-handling
tasks. In fact, many applications interact with the system solely through the API of the NSTextView class.
24
To create the text view object in Interface Builder, drag a Text View from the Object library onto your app
window. When your app launches and its nib file is loaded, it instantiates an NSTextView object and embeds
it in a scroll view. Behind the scenes, the text view object automatically instantiates and manages
NSTextContainer, NSLayoutManager, and NSTextStorage objects.
To create the text view object programmatically and let it create and own the other objects, use the NSTextView
initialization method initWithFrame:.
The text view ownership technique is the easiest and cleanest way to set up the text system object web.
However, it creates a single flow of text which does not support pagination or complex layouts, as described
in Common Configurations (page 27). For other configurations you must create the objects explicitly.
Create an NSTextStorage object in the normal way using the alloc and init messages.
When you create the text system explicitly, you need to keep a reference only to this NSTextStorage
object. The other objects of the system are owned by the text storage object, and they are released
automatically by the system.
textStorage = [[NSTextStorage alloc]
initWithString:@"Here's to the ones who see things
different."];
2.
25
3.
Create an NSTextContainer object, initialize it with a size, and connect it to the layout manager.
The size of the text container is the size of the view in which it is displayedin this case self.windowView
is the content view of the apps main window. Once youve created the text container, you add it to the
list of containers that the layout manager owns. If your app has multiple text containers, you can create
them and add them in this step, or you can create them lazily as needed.
NSTextContainer *textContainer;
textContainer = [[NSTextContainer alloc]
initWithContainerSize:self.windowView.frame.size];
[layoutManager addTextContainer:textContainer];
4.
Create an NSTextView object, initialize it with a frame, and connect it to the text container.
When you create the text systems object web explicitly, you must use the
initWithFrame:textContainer: method to initialize the text view. This initialization method does
nothing more than initialize the receiver and set its text container (unlike initWithFrame:, which not
only initializes the receiver, but automatically creates and interconnects its own web of text system objects).
Each text view in the system is connected to its own text container.
NSTextView *textView;
textView = [[NSTextView alloc]
initWithFrame:self.windowView.frame
textContainer:textContainer];
Once the NSTextView object has been initialized, you make it the content view of the window, which is
then displayed. The makeFirstResponder: message makes the text view key, so that it accepts keystroke
events.
[self.window setContentView:textView];
[self.window makeKeyAndOrderFront:nil];
[self.window makeFirstResponder:textView];
For simplicity, this code puts the text view directly into the windows content view. More commonly, text
views are placed inside scroll views, as described in Putting an NSTextView Object in an NSScrollView in
Text System User Interface Layer Programming Guide .
26
Common Configurations
The following diagrams give you an idea of how you can configure objects of the four primary text system
classesNSTextStorage, NSLayoutManager, NSTextContainer, and NSTextViewto accomplish different
text-handling goals.
To display a single flow of text, arrange the objects as shown in Figure 3-3.
Figure 3-3
The NSTextView object provides the view that displays the glyphs, and the NSTextContainer object defines
an area within that view where the glyphs are laid out. Typically in this configuration, the NSTextContainer
objects vertical dimension is declared to be some extremely large value so that the container can accommodate
any amount of text, while the NSTextView object is set to size itself around the text using the
setVerticallyResizable: method defined by NSText, and given a maximum height equal to the
NSTextContainer objects height. Then, with the text view embedded in an NSScrollView object, the user
can scroll to see any portion of this text.
If the text containers area is inset from the text views bounds, a margin appears around the text. The
NSLayoutManager object, and other objects not pictured here, work together to generate glyphs from the
NSTextStorage objects data and lay them out within the area defined by the NSTextContainer object.
This configuration is limited by having only one NSTextContainer-NSTextView pair. In such an arrangement,
the text flows uninterrupted within the area defined by the NSTextContainer. Page breaks, multicolumn
layout, and more complex layouts cant be accommodated by this arrangement.
27
By using multiple NSTextContainer-NSTextView pairs, more complex layout arrangements are possible.
For example, to support page breaks, an application can configure the text objects as shown in Figure 3-4.
Figure 3-4
Each NSTextContainer-NSTextView pair corresponds to a page of the document. The blue rectangle in
Figure 3-4 represents a custom view object that your application provides as a background for the NSTextView
objects. This custom view can be embedded in an NSScrollView object to enable the user to scroll through
the documents pages.
28
Instead of having one NSTextView-NSTextContainer pair correspond to a single page, there are now two
pairsone for each column on the page. Each NSTextContainer-NSTextView pair controls a portion of the
document. As the text is displayed, glyphs are first laid out in the top-left view. When there is no more room
in that view, the NSLayoutManager object informs its delegate that it has finished filling the container. The
delegate can check whether theres more text that needs to be laid out and add another NSTextContainer
and NSTextView if necessary. The NSLayoutManager object proceeds to lay out text in the next container,
notifies the delegate when finished, and so on. Again, a custom view (depicted as a blue rectangle) provides
a canvas for these text columns.
29
Not only can you have multiple NSTextContainer-NSTextView pairs, you can also have multiple
NSLayoutManager objects accessing the same text storage. Figure 3-6 illustrates the simplest arrangement
with multiple layout managers.
Figure 3-6
The effect of this arrangement is to give multiple views on the same text. If the user alters the text in the top
view, the change is immediately reflected in the bottom view (assuming the location of the change is within
the bottom views bounds).
30
Finally, complex page layout requirements, such as permitting text to wrap around embedded graphics, can
be achieved by a configuration that uses a custom subclass of NSTextContainer. This subclass defines a
region that adapts its shape to accommodate the graphic image and uses the object configuration shown in
Figure 3-7.
Figure 3-7
See Text Layout Programming Guide for information about how the text system lays out text.
31
Text fields, text views, and the field editor are important objects in the Cocoa text system because they are
central to the users interaction with the system. They provide text entry, manipulation, and display. If your
application deals in any way with user-entered text, you should understand these objects.
Text Fields
A text field is a user interface control object instantiated from the NSTextField class. Figure 4-1 shows a text
field. Text fields display small amounts of text, typically (although not necessarily) a single line. Text fields
provide places for users to enter text responses, such as search parameters. Like all controls, a text field has a
target and an action, and it performs validation on its value when edited. If the value isnt valid, it sends a
special error action message to its target.
Figure 4-1
A text field
A text field is implemented by two classes: NSTextFieldCell, the cell which does most of the work, and
NSTextField, the control that contains that cell. Every method in NSTextFieldCell has a cover in
NSTextField. (A cover is a method of the same name that calls the original method.) An NSTextField object
can have a delegate that responds to such delegate methods as textShouldEndEditing:.
By default, text fields send their action message when editing endsthat is, when the user presses Return or
moves focus to another control. You can control a text fields shape and layout, the font and color of its text,
background color, whether the text is editable or read-only, whether it is selectable or not (if read-only), and
whether the text scrolls or wraps when the text exceeds the text fields visible area.
32
To create a secure text field for password entry, use NSSecureTextField, a subclass of NSTextField. Secure
text fields display bullets in place of characters entered by the user, and they do not allow cutting or copying
of their contents. You can get the text fields value using the stringValue method, but users have no access
to the value. See Why Use a Custom Field Editor? (page 69) for information about the implementation of
secure text fields.
The usual way to instantiate a text field is to drag an NSTextField or NSSecureTextField object from the
Interface Builder objects library and place it in a window of your applications user interface. You can link text
fields together in their windows key view loop by setting each fields nextKeyView outlet in the Connections
pane of the Inspector window, so that users can press Tab to move keyboard focus from one field to the next
in the order you specify.
Text Views
Text views are user interface objects instantiated from the NSTextView class. Figure 4-2 shows a text view.
Text views typically display multiple lines of text laid out in paragraphs with all the characteristics of sophisticated
typesetting. A text view is the main user interface to the Cocoa text-editing system. It handles user events to
provide text entry and modification, and to display any font, including those of non-English languages, with
arbitrary colors, styles, and other attributes.
Figure 4-2
A text view
The Cocoa text system supports text views with many other underlying objects providing text storage, layout,
font and attribute manipulation, spell checking, undo and redo, copy and paste, drag and drop, saving of text
to files, and other features. NSTextView is a subclass of NSText, which is a separate class for historical reasons.
33
You dont instantiate NSText, although it declares many of the methods you use with NSTextView. When
you put an NSTextView object in an NSWindow object, you have a full-featured text editor whose capabilities
are provided for free by the Cocoa text system.
Because only one of the text fields in a window can be active at a time, the system needs only one NSTextView
instance per window to be the field editor. However, you can substitute custom field editors, in which case
there could be more than one field editor. Among its other duties, the field editor maintains the selection.
Therefore, a text field that's not being edited typically does not have a selection at all.
For more information about the field editor, see Working with the Field Editor (page 67).
34
Text Attributes
The Cocoa text system handles five kinds of text attributes: character attributes, temporary attributes, paragraph
attributes, glyph attributes, and document attributes. Character attributes include traits such as font, color,
and subscript, which can be associated with an individual character or a range of characters. Temporary
attributes are character attributes that apply only to a particular layout and are not persistent. Paragraph
attributes are traits such as indentation, tabs, and line spacing. Glyph attributes affect the way the layout
manager renders glyphs and include traits such as overstriking the previous glyph. Document attributes include
document-wide traits such as paper size, margins, and view zoom percentage.
This chapter provides a brief introduction to the various types of text attributes with cross-references to more
detailed documentation.
Character Attributes
The text system stores character attributes persistently in attributed strings along with the characters to which
they apply. The text systems predefined character attributes control the appearance of characters (font,
foreground color, background color, and ligature handling) and their placement (superscript, baseline offset,
and kerning).
Two special character attributes pertain to links and attachments. A link attribute points to a URL (encapsulated
in an NSURL object) or any other object of your choice. An attachment attribute is associated with a special
attachment character and points to an NSFileWrapper object containing the attached file or in-memory
data.
The predefined character attribute NSCharacterShapeAttributeName enables you to set a value for the
character shape feature used in font rendering by Apple Type Services. This feature is currently used to specify
traditional shapes in Chinese and Japanese scripts, but font developers could use it for other scripts as well.
The predefined character attribute NSGlyphInfoAttributeName points to an NSGlyphInfo object that
provides a means to override the standard glyph generation process and substitute a specified glyph over the
attributes range.
35
Text Attributes
Character Attributes
Conceptually, each character in an attributed string has an associated dictionary of attributes. Typically, however,
an attribute dictionary applies to a longer range of characters. The NSAttributedString class provides
methods that take a character index and return the associated attribute dictionary and the range to which its
attribute values apply. See Accessing Attributes in Attributed String Programming Guide for more information
about using these methods.
In addition to the predefined attributes, you can assign any attribute key-value pair you wish to a range of
characters. You add the attributes to the appropriate character range in the NSTextStorage object using the
NSMutableAttributedString method addAttribute:value:range:. You can also create an
NSDictionary object containing the names and values of a set of custom attributes and add them to the
character range in a single step using the addAttributes:range: method. To make use of your custom
attributes, you need a custom subclass of NSLayoutManager that understands what to do with them. Your
subclass should override the drawGlyphsForGlyphRange:atPoint: method first to call the superclass to
draw the glyph range, then draw your own attributes on top, or else draw the glyphs entirely your own way.
Attribute Fixing
Editing attributed strings can cause inconsistencies that must be cleaned up by attribute fixing. The AppKit
extensions to NSMutableAttributedString define fix... methods to fix inconsistencies among attachment,
font, and paragraph attributes. These methods ensure that attachments dont remain after their attachment
characters are deleted, that font attributes apply only to characters available in that font, and that paragraph
attributes are consistent throughout paragraphs.
See Attributed String Programming Guide for more details about character attributes and attribute fixing.
36
Text Attributes
Temporary Attributes
Temporary Attributes
Temporary attributes are character attributes that are not stored with an attributed string. Rather, the layout
manager assigns temporary attributes during the layout process and uses them only when drawing the text.
For example, you can use temporary attributes to underline misspelled words or color key words in a
programming language.
Temporary attributes affect only the appearance of text, not the way in which it is laid out. You store temporary
attributes in an NSDictionary object using the same keys as regular character attributes, or using custom
attribute names (if you have an NSLayoutManager subclass that can handle them). Then you add the attributes
using an NSLayoutManager method such as addTemporaryAttributes:forCharacterRange:. By default,
the only temporary attributes recognized are those affecting color and underlines. During layout, temporary
attributes supersede regular character attributes. So, for example, if a character has a stored
NSForegroundColorAttributeName value specifying blue and a temporary attribute of the same identifier
specifying red, then the character is rendered in red.
For more information on temporary attributes, see NSLayoutManager Class Reference .
Paragraph Attributes
Paragraph attributes affect the way the layout manager arranges lines of text into paragraphs on a page. The
text system encapsulates paragraph attributes in objects of the NSParagraphStyle class. The value of one
of the predefined character attributes, NSParagraphStyleAttributeName, points to an NSParagraphStyle
object containing the paragraph attributes for that character range. Attribute fixing ensures that only one
NSParagraphStyle object pertains to the characters throughout each paragraph.
Paragraph attributes include traits such as alignment, tab stops, line-breaking mode, and line spacing (also
known as leading). Users of text applications control paragraph attributes through ruler views, defined by the
NSRulerView class.
See Ruler and Paragraph Style Programming Topics for more details about paragraph attributes.
Glyph Attributes
Glyphs are the concrete representations of characters that the text system actually draws on a display. Glyph
attributes are not complex data structures like character attributes but are simply integer values that the layout
manager uses to denote special handling for particular glyphs during rendering.
37
Text Attributes
Document Attributes
The text system uses glyph attributes rarely, and applications should have little reason to be concerned with
them. Nonetheless, NSLayoutManager provides public methods that handle glyph attributes, so you can use
subclasses to extend the mechanism to handle custom glyph attributes if necessary.
The glyph generator sets built-in glyph attributes as required on glyphs during typesetting. They are maintained
in the layout managers glyph cache during that process, but they are not stored persistently. Two examples
of glyph attributes are the elastic attribute for spaces, used to lay out fully justified text, and the attribute
NSGlyphAttributeInscribe, which is used for situations such as drawing an umlaut over a character when
the font does not include a built-in character-with-umlaut.
For more information about glyph attributes, see the description of the
setIntAttribute:value:forGlyphAtIndex: method in NSLayoutManager Class Reference .
Document Attributes
Document attributes pertain to a document as a whole. Document attributes include traits such as paper size,
margins, and view zoom percentage. Although the text system has no built-in mechanism to store document
attributes, initialization methods such as initWithRTF:documentAttributes: can populate an
NSDictionary object that you provide with document attributes derived from a stream of RTF or HTML data.
Conversely, methods that write RTF data, such as RTFFromRange:documentAttributes:, write document
attributes if you pass a reference to an NSDictionary object containing them with the message.
See RTF Files and Attributed Strings in Attributed String Programming Guide and NSAttributedString AppKit
Additions Reference for more information.
38
Font Handling
This chapter explains how the Cocoa text system deals with fonts. It explains how to use the Font panel in your
application, how to work directly with font objects, and how to work with the font manager.
or typeface. The font manager receives the messages from the Font panel and sends messages up the responder
chain for action on the text objects.
Normally, an applications Font panel displays all the standard fonts available on the system. If this isnt
appropriate for your applicationfor example, if only fixed-pitch fonts should be usedyou can assign a
delegate to the NSFontPanel object to filter the available fonts. Before the NSFontPanel object adds a
particular font family or face to its list, the NSFontPanel object asks its delegate to confirm the addition by
sending the delegate a fontManager:willIncludeFont: message. If the delegate returns TRUE (or doesnt
implement this method), the font is added. If the delegate returns FALSE, the font isnt added. This method
must be invoked before the loading of the main nib file.
39
Font Handling
Working with Font Objects
You can add a custom view object to an NSFontPanel object using setAccessoryView:, allowing you to
add custom controls to the Font panel. You can also limit the fonts displayed (by default, all fonts are displayed)
by assigning a delegate to the applications font manager object.
If you want the NSFontManager object to instantiate the Font panel from some class other than NSFontPanel,
use the NSFontManager class method setFontPanelFactory:. See Converting Fonts Manually for more
information on using the font conversion system.
If multiple fonts are selected, changeFont: must send conversion messages for each selected font. This is
useful for objects such as table views, which do not inherently respond to messages from the Font panel.
40
Font Handling
Working with Font Objects
instance provides access to the fonts characteristics and glyphs. The text system combines character information
with font information to choose the glyphs used during text layout. You use font objects by passing them to
methods that accept them as a parameter. Font objects are immutable, so it is safe to use them from multiple
threads in your app.
You dont create font objects using the alloc and init methods; instead, you use methods such as
fontWithName:matrix: or fontWithName:size: to look up an available font and alter its size or matrix
to your needs. These methods check for an existing font object with the specified characteristics, returning it
if there is one. Otherwise, they look up the font data requested and create the appropriate object. You can
also use font descriptors to create fonts. See Font Descriptors (page 41).
NSFont also defines a number of methods for specifying standard system fonts, such as systemFontOfSize:,
userFontOfSize:, and messageFontOfSize:. To request the default size for these standard fonts, pass 0
or a negative number as the font size. The standard system font methods are listed in Querying Standard Font
Variations (page 43).
Font Descriptors
Font descriptors, instantiated from the NSFontDescriptor class, provide a way to describe a font with a
dictionary of attributes. The font descriptor can then be used to create or modify an NSFont object. In particular,
you can make an NSFont object from a font descriptor, you can get a descriptor from an NSFont object, and
you can change a descriptor and use it to make a new font object. You can also use a font descriptor to specify
custom fonts provided by an app.
Font descriptors provide a font matching capability by which you can partially describe a font by creating a
font descriptor with, for example, just a family name. You can then find all the available fonts on the system
with a matching family name using matchingFontDescriptorsWithMandatoryKeys:.
Font descriptors can be archived, which is preferrable to archiving a font object because a font object is
immutable and provides access to a particular font installed on a particular system. A font descriptor, on the
other hand, describes a font in terms of its characteristics, its attributes, and provides access at runtime to the
fonts currently available that match those attributes.
That is, you can use font descriptors to query the system for available fonts that match particular attributes,
and then create instances of NSFont matching those attributes, such as names, traits, languages, and other
features. For example, you can use a font descriptor to retrieve all the fonts matching a given font family name,
using the PostScript family names (as defined by the CSS standard) as shown in Listing 6-1.
Listing 6-1
NSFontDescriptor *helveticaNeueFamily =
[NSFontDescriptor fontDescriptorWithFontAttributes:
41
Font Handling
Working with Font Objects
Font metrics
42
Font Handling
Working with Font Objects
Table 6-1
Font metric
Methods
Advancement
advancementForGlyph:, maximumAdvancement
X-height
xHeight
Ascent
ascender
Bounding rectangle
boundingRectForFont, boundingRectForGlyph:
Cap height
capHeight
Line height
Descent
descender
Italic angle
italicAngle
Font
Methods
System font
[NSFont systemFontOfSize:[NSFont
smallSystemFontSize]]
[NSFont boldSystemFontOfSize:[NSFont
smallSystemFontSize]]
[NSFont systemFontSizeForControlSize:
NSMiniControlSize]
[NSFont boldSystemFontOfSize:[NSFont
systemFontSizeForControlSize: NSMiniControlSize]]
43
Font Handling
Working with Font Objects
Font
Methods
Application font
[NSFont userFontOfSize:-1.0]
[NSFont userFixedPitchFontOfSize:-1.0]
Label Font
44
Font Handling
Working with the Font Manager
45
Font Handling
Working with the Font Manager
You can then add the Font menu to your applications menus. Once the Font menu is installed, your application
automatically gains the functionality of both the Font menu and the Font panel.
The first three cause the font manager to query the sender of the message in order to determine which trait
to add or remove, or how to modify the font. The last causes the font manager to use the settings in the Font
panel to modify the font. The font manager records this information and uses it in later requests to convert
fonts.
When the font manager receives an addFontTrait: or removeFontTrait: message, it queries the sender
with a tag message, interpreting the return value as a trait mask for use with convertFont:toHaveTrait:
or convertFont:toNotHaveTrait:, as described in Converting Fonts Manually (page 47). The Font menu
commands Italic and Bold, for example, have trait mask values of NSItalicFontMask and NSBoldFontMask,
respectively. See the Constants section in NSFontManager Class Reference for a list of trait mask values.
When the font manager receives a modifyFont: message, it queries the sender with a tag message and
interprets the return value as a particular kind of conversion to perform, via the various conversion methods
described in Converting Fonts Manually (page 47). For example, a button whose tag value is
SizeUpFontAction causes the font managers convertFont: method to increase the size of the NSFont
object passed as the parameter. See the NSFontManager method modifyFont: for a list of conversion tag
values.
For modifyFontViaPanel:, the font manager sends the applications Font panel a panelConvertFont:
message. The Font panel in turn uses the font manager to convert the font provided according to the users
choices. For example, if the user selects only the font family in the Font panel (perhaps Helvetica), then for
whatever fonts are provided to panelConvertFont:, only the family is changed: Courier Medium 10.0 point
becomes Helvetica Medium 10.0 point, and Times Italic 12.0 point becomes Helvetica Oblique 12.0 point.
46
Font Handling
Working with the Font Manager
The font manager responds to a font-changing action method by sending a changeFont: action message
up the responder chain. A text-bearing object that receives this message should have the font manager convert
the fonts in its selection by invoking convertFont: for each font and using the NSFont object returned. The
convertFont: method uses the information recorded by the font-changing action method, such as
addFontTrait:, modifying the font provided appropriately. (Theres no way to explicitly set the font-changing
action or trait; instead, you use the methods described in Converting Fonts Manually (page 47).)
This simple example assumes theres only one font in the selection:
- (void)changeFont:(id)sender
{
NSFont *oldFont = [self selectionFont];
NSFont *newFont = [sender convertFont:oldFont];
[self setSelectionFont:newFont];
return;
}
Most text-bearing objects have to scan the selection for ranges with different fonts and invoke convertFont:
for each one.
Methods
Behavior
convertFont:toFace:
Alters the basic design of the font provided. Requires a fully specified
typeface name, such as Times-Roman or Helvetica-BoldOblique.
convertFont: toFamily:
Alters the basic design of the font provided. Requires only a family
name, such as Times or Helvetica.
convertFont:
toHaveTrait:
Uses a trait mask to add a single trait such as Italic, Bold, Condensed,
or Extended.
convertFont:
toNotHaveTrait:
47
Font Handling
Working with the Font Manager
Methods
Behavior
convertFont:toSize:
Returns a font of the requested size, with all other characteristics the
same as those of the original font.
convertWeight: ofFont:
Each method returns a transformed version of the font provided, or the original font if it cant be converted.
The default implementation of font conversion is very conservative, making a change only if no other trait or
aspect is affected. For example, if you try to convert Helvetica Oblique 12.0 point by adding the Bold trait, and
only Helvetica Bold is available, the font isnt converted. You can create a subclass of NSFontManager and
override the conversion methods to perform less conservative conversion, perhaps using Helvetica Bold in this
case and losing the Oblique trait.
In addition to the font-conversion methods, NSFontManager defines
fontWithFamily:traits:weight:size: to construct a font with a given set of characteristics. If you dont
care to make a subclass of NSFontManager, you can use this method to perform approximate font conversions
yourself.
48
Font Handling
Working with the Font Manager
Unlike underlining, bold and italic are traits of the font, so you need to use a font manager instance to convert
the font to have the desired trait, then add the font attribute to the mutable attributed string. For a mutable
attributed string named attributedString, use the following technique:
NSFontManager *fontManager = [NSFontManager sharedFontManager];
unsigned idx = range.location;
NSRange fontRange;
NSFont *font;
If your mutable attributed string is actually an NSTextStorage object, place this code between beginEditing
and endEditing calls.
Examining Fonts
In addition to converting fonts, NSFontManager provides information on which fonts are available to the
application and on the characteristics of any given font. The availableFonts method returns an array of
the names of all fonts available. The availableFontNamesWithTraits: method filters the available fonts
based on a font trait mask.
There are three methods for examining individual fonts. The fontNamed:hasTraits: method returns true
if the font matches the trait mask provided. The traitsOfFont: method returns a trait mask for a given font.
The weightOfFont: method returns an approximate ranking of a fonts weight on a scale of 015, where 0
is the lightest possible weight, 5 is Normal or Book weight, 9 is the equivalent of Bold, and 15 is the heaviest
possible (often called Black or Ultra Black).
49
Font Handling
Working with the Font Manager
requested. You may be able to avoid using subclasses if all you need is to add some custom controls to the
Font panel. In this case, you can invoke the NSFontPanel method setAccessoryView: to add an NSView
object below its font browser.
If you provide your own Font menu, you should register it with the font manager using the setFontMenu:
method. The font manager is responsible for validating Font menu items and changing their titles and tags
according to the selected font. For example, when the selected font is Italic, the font manager adds a check
mark to the Italic Font menu item and changes its tag to UnitalicMask. Your Font menus items should use
the appropriate action methods and tags, as shown in Table 6-4.
Table 6-4
Action
Tag
Italic
addFontTrait:
ItalicMask
Bold
addFontTrait:
BoldMask
Heavier
modifyFont:
HeavierFontAction
Larger
modifyFont:
SizeUpFontAction
See also the following documents: Attributed String Programming Guide describes NSAttributedString
objects, which manage sets of attributes, such as font and kerning, that are associated with character strings
or individual characters. Text Layout Programming Guide describes how the Cocoa text system converts strings
of text characters, font information, and page specifications into lines of glyphs placed at specific locations on
a page, suitable for display and printing.
50
Text Editing
This chapter describes ways in which you can control the behavior of the Cocoa text system as it performs text
editing. Text editing is the modification of text characters or attributes by interacting with text objects. Usually,
editing is performed by direct user action with a text view, but it can also be accomplished by programmatic
interaction with a text storage object. This document also discusses the text input system that translates
keyboard events into commands and text input.
The Cocoa text system implements a sophisticated editing mechanism that enables input and modification of
complex text character and style information. It is important to understand this mechanism if your code needs
to hook into it to modify that behavior.
The text system provides a number of control points where you can customize the editing behavior:
Text system classes provide methods to control many of the ways in which they perform editing.
You can implement more control through the Cocoa mechanisms of notification and delegation.
In extreme cases where the capabilities of the text system are not suitable, you can replace the text view
with a custom subclass.
and setEditable: methods. NSTextView also implements the distinction between plain and rich text
defined by NSText with its setRichText: and setImportsGraphics: methods. See Text System User
InterfaceLayerProgrammingGuide ,NSTextViewClassReference ,andNSTextClassReference formoreinformation.
An editable text view can operate in either of two distinct editing modes: as a normal text editor or as a field
editor. A field editor is a single text view instance shared by many text fields belonging to a window in an
application. This sharing results in a performance gain. When a text field becomes the first responder, the
51
Text Editing
The Key-Input Message Sequence
window inserts the field editor in its place in the responder chain. A normal text editor accepts Tab and Return
characters as input, whereas a field editor interprets Tab and Return as cues to end editing. The NSTextView
method setFieldEditor: controls this behavior.
See Working with the Field Editor (page 67) for more information about the field editor.
Key-event processing
If the first responder is a text view, the key event enters the text system. The key window sends the text view
a keyDown: message with the event as its argument. The keyDown: method passes the event to
handleEvent:, which sends the character input to the input context for key binding and interpretation. In
52
Text Editing
The Key-Input Message Sequence
The text input system uses a dictionary property list, called a key-bindings dictionary, to interpret keyboard
events before passing them to the Input Method Kit framework for mapping to characters.
During the processing of a keyboard event, the event passes through the NSMenu object, then to the first
responder via the keyDown: method. The default implementation of the method provided by the NSResponder
class propagates the message up the responder chain until an overridden keyDown: implementation stops
the propagation. Typically, an NSResponder subclass can choose to process certain keys and ignore others
(for example, in a game) or to send the handleEvent: message to its input context.
The input context checks the event to see if it matches any of the keystrokes in the users key-bindings dictionary.
A key-bindings dictionary maps a keystroke (including its modifier keys) to a method name. For example, the
default key-bindings dictionary maps ^d (Control-D) to the method name deleteForward:. If the keyboard
event is in the dictionary, then the input context calls the text views doCommandBySelector: method with
the selector associated with the dictionary entry.
If the input context cannot match the keyboard event to an entry in the key-bindings dictionary, it passes the
event to the Input Method Kit for mapping to characters.
53
Text Editing
Intercepting Key Events
can override the standard dictionary entirely by providing a dictionary file at the path
~/Library/KeyBindings/DefaultKeyBinding.dict. However, defining custom key bindings dynamically
(that is, while the application is running) is not supported.
For more information about text-input key event processing, see Text System Defaults and Key Bindings in
Cocoa Event Handling Guide in Cocoa Event Handling Guide .
When the text view has enough information to specify an actual change to its text, it sends an editing message
to its NSTextStorage object to effect the change. The methods that change character and attribute information
in the text storage object are declared in the NSTextStorage superclass NSMutableAttributedString,
and they depend on the two primitive methods replaceCharactersInRange:withString: and
setAttributes:range:. The text storage object then informs its layout managers of the change to initiate
glyph generation and layout when necessary, and it posts notifications and sends delegate messages before
and after processing the edits. For more information about the interaction of text view, text storage, and layout
manager objects, see Text Layout Programming Guide .
54
Text Editing
Text View Delegation
associated text storage object. The message sequence invoked when a text view receives key events is described
in more detail in The Key-Input Message Sequence (page 52).
With the standard key bindings, an Enter or Return character causes the text view to receive
doCommandBySelector: with a selector of insertNewline:, which can have one of two results. If the text
view is not a field editor, the text views insertText:replacementRange: method inserts a line-break
character. If the text view is a field editor, as when the user is editing a text field, the text view ends editing
instead. You can cause a text view to behave in either way by calling setFieldEditor:.
Although you could alter the text views behavior by subclassing the text view and overriding
insertText:replacementRange: and doCommandBySelector:, a better solution is to handle the event
in the text views delegate. The delegate can take control over user changes to text by implementing the
textView:shouldChangeTextInRange:replacementString: method.
To handle keystrokes that dont insert text, the delegate can implement the
textView:doCommandBySelector: method.
To distinguish between Enter and Return, for example, the delegate can test the selector passed with
doCommandBySelector:. If it is @selector(insertNewline:), you can send currentEvent to the NSApp
object to make sure the event is a key event and, if so, which key was pressed.
55
Text Editing
Text View Delegate Messages and Notifications
NSTextDelegate Protocol Reference and NSTextViewDelegate Protocol Reference describe the delegate messages
the delegate can receive. The delegating object sends a message only if the delegate implements the method.
All NSTextView objects attached to the same NSLayoutManager share the same delegate. Setting the
delegate of one such text view sets the delegate for all the others. Delegate messages pass the id of the sender
as an argument.
Note: For multiple NSTextView objects attached to the same NSLayoutManager object, the
argument id is that of the notifying text view, which is the first NSTextView object for the shared
NSLayoutManager object. This NSTextView object is responsible for posting notifications at the
appropriate times.
56
Text Editing
Text Field Delegation
It is particularly important for observers to register for the last of these notifications. If a new NSTextView
object is added at the beginning of a series of connected NSTextView objects, it becomes the new notifying
text view. It doesnt have access to which objects are observing its group of text objects, so it posts an
NSTextViewWillChangeNotifyingTextViewNotification, which allows all those observers to unregister
themselves from the old notifying text view and reregister themselves with the new one. For more information,
see the description for this notification in NSTextView Class Reference .
Synchronizing Editing
The editing process involves careful synchronization of the complex interaction of various objects. The text
system coordinates event processing, data modification, responder chain management, glyph generation, and
layout to maintain consistency in the text data model.
The system provides a rich set of notifications to delegates and observers to enable your code to interact with
this logic, as described in Text View Delegate Messages and Notifications (page 56).
57
Text Editing
Synchronizing Editing
Batch-Editing Mode
If your code needs to modify the text backing store directly, you should use batch-editing mode; that is, bracket
the changes between the NSMutableAttributedString methods beginEditing and endEditing.
Although this bracketing is not strictly necessary, its good practice, and its important for efficiency if youre
making multiple changes in succession. NSTextView uses the beginEditing and endEditing methods to
synchronize its editing activity, and you can use the methods directly to control the timing of notifications to
delegates, observers, and associated layout managers. When the NSTextStorage object is in batch-editing
mode, it refrains from informing its layout managers of any editing changes until it receives the endEditing
message.
The beginning of editing means that a series of modifications to the text backing store (NSTextStorage
for text views and cell values for cells) is about to occur. Bracketing editing between beginEditing and
endEditing locks down the text storage to ensure that text modifications are atomic transactions.
The end of editing means that the backing store is in a consistent state after modification. In cells (such as
NSTextFieldCell objects, which control text editing in text fields), the end of editing coincides with the
field editor resigning first responder status, which triggers synchronization of the contents of the field editor
and its parent cell.
In addition, the text view sends NSTextDidEndEditingNotification when it completes modifying its
backing store, regardless of its first responder status. For example, it sends out this notification when the
Replace All button is clicked in the Find window, even if the text view is not the first responder.
Important: Calling any of the layout managers layout-causing methods between beginEditing and
endEditing messages raises an exception. NSLayoutManager Class Reference and the NSLayoutManager.h
header file indicate which methods cause layout.
Listing 7-1 illustrates a situation in which the NSText method scrollRangeToVisible: forces layout to
occur and raises an exception.
Listing 7-1
Forcing layout
58
Text Editing
Synchronizing Editing
Scrolling a character range into visibility requires layout to be complete through that range so the text view
can know where the range is located. But in Listing 7-1, the text storage is in batch-editing mode. It is in an
inconsistent state, so the layout manager has no way to do layout at this time. Moving the
scrollRangeToVisible: call after endEditing would solve the problem.
There are additional actions that you should take if you implement new user actions in a text view, such as a
menu action or key binding method that changes the text. For example, you can modify the selected range
of characters using the NSTextView method setSelectedRange:, depending on the type of change
performed by the command, using the results of the NSTextView methods rangeForUserTextChange,
rangeForUserCharacterAttributeChange, or rangeForUserParagraphAttributeChange. For
example, rangeForUserParagraphAttributeChange returns the entire paragraph containing the original
selectionthat is the range affected if your action modifies paragraph attributes. Also, you should call
textView:shouldChangeTextInRange:replacementString: before you make the change and
didChangeText afterwards. These actions ensure that the correct text gets changed and the system sends
the correct notifications and delegate messages to the text views delegate. See Subclassing NSTextView (page
61) for more information.
- (void)textDidEndEditing:(NSNotification *)notification {
if([[[notification userInfo] valueForKey:@"NSTextMovement"] intValue] ==
NSReturnTextMovement) {
59
Text Editing
Synchronizing Editing
NSMutableDictionary *newUserInfo;
newUserInfo = [[NSMutableDictionary alloc]
initWithDictionary:[notification userInfo]];
[newUserInfo setObject:[NSNumber numberWithInt:NSIllegalTextMovement]
forKey:@"NSTextMovement"];
notification = [NSNotification notificationWithName:[notification name]
object:[notification object]
userInfo:newUserInfo];
[super textDidEndEditing:notification];
[[self window] makeFirstResponder:self];
} else {
[super textDidEndEditing:notification];
}
}
When an object conforming to the NSTextInputClient protocol becomes the first responder in the key
window, its NSTextInputContext object becomes active and bound to the active text input sources, such
as character palette, keyboards, and input methods.
60
Text Editing
Subclassing NSTextView
Whether the selection was set programmatically or by the user, you can get the range of characters currently
selected using the selectedRange method. NSTextView indicates its selection by applying a special set of
attributes to it. The selectedTextAttributes method returns these attributes, and
setSelectedTextAttributes: sets them.
While changing the selection in response to user input, an NSTextView object invokes its own
setSelectedRange:affinity:stillSelecting: method. The first parameter is the range to select. The
second, called the selection affinity, determines which glyph the insertion point displays near when the two
glyphs defining the selected range are not adjacent. Its typically used where the selected lines wrap to place
the insertion point at the end of one line or the beginning of the following line. You can get the selection
affinity currently in effect using the selectionAffinity method. The last parameter indicates whether the
selection is still in the process of changing; the delegate and any observers arent notified of the change in the
selection until the method is invoked with NO for this argument.
Another factor affecting selection behavior is the selection granularity: whether characters, words, or whole
paragraphs are being selected. This is usually determined by the number of initial mouse clicks; for example,
a double click initiates word-level selection. NSTextView decides how much to change the selection during
input tracking using its selectionRangeForProposedRange:granularity: method.
An additional aspect of selection, related to input management, is the range of marked text. As the input
context interprets keyboard input, it can mark incomplete input in a special way. The text view displays this
marked text differently from the selection, using temporary attributes that affect only display, not layout or
storage. For example, NSTextView uses marked text to display a combination key, such as Option-E, which
places an acute accent character above the character entered next. When the user types Option-E, the text
view displays an acute accent in a yellow highlight box, indicating that it is marked text, rather than final input.
When the user types the next character, the text view displays it as a single accented character, and the marked
text highlight disappears. The markedRange method returns the range of any marked text, and
markedTextAttributes returns the attributes used to highlight the marked text. You can change these
attributes using setMarkedTextAttributes:.
Subclassing NSTextView
Using NSTextView directly is the easiest way to interact with the text system, and its delegate mechanism
provides an extremely flexible way to modify its behavior. In cases where delegation does not provide required
behavior, you can subclass NSTextView.
61
Text Editing
Subclassing NSTextView
Note: To modify editing behavior, your first resort should be to notification or delegation, rather
than subclassing. It may be tempting to start by subclassing NSTextView and overriding keyDown:,
but thats usually not appropriate, unless you really need to deal with raw key events before input
management or key binding. In most cases its more appropriate to work with one of the text view
delegate methods or with text view notifications, as described in Text View Delegate Messages and
Notifications (page 56).
The text system requires NSTextView subclasses to abide by certain rules of behavior, and NSTextView
provides many methods to help subclasses do so. Some of these methods are meant to be overridden to add
information and behavior into the basic infrastructure. Some are meant to be invoked as part of that
infrastructure when the subclass defines its own behavior.
Updating State
NSTextView automatically updates the Fonts window and ruler as its selection changes. If you add any new
font or paragraph attributes to your subclass of NSTextView, youll need to override the methods that perform
this updating to account for the added information. The updateFontPanel method makes the Fonts window
display the font of the first character in the selection. You could override this method to update the display of
an accessory view in the Fonts window. Similarly, updateRuler causes the ruler to display the paragraph
attributes for the first paragraph in the selection. You can also override this method to customize display of
items in the ruler. Be sure to invoke the super implementation in your override to have the basic updating
performed as well.
the ability of your subclass to handle pasteboard operations for new data types, you should override the
readablePasteboardTypes and writablePasteboardTypes methods to reflect those types. Similarly,
to support new types of data for dragging operations, you should override the acceptableDragTypes
method. Your implementation of these methods should invoke the superclass implementation, add the new
data types to the array returned from super, and return the modified array.
To read and write custom pasteboard types, you must override the readSelectionFromPasteboard:type:
and writeSelectionToPasteboard:type: methods. In your implementation of these methods, you should
read the new data types your subclass supports and let the superclass handle any other types.
62
Text Editing
Subclassing NSTextView
For dragging operations, if your subclasss ability to accept your custom dragging types varies over time, you
can override updateDragTypeRegistration to register or unregister the custom types according to the
text views current status. By default this method enables dragging of all acceptable types if the receiver is
editable and a rich text view.
63
Text Editing
Creating a Custom Text View
should disallow the change. If the delegate returns YES, the text view posts an
NSTextDidBeginEditingNotification, and shouldChangeTextInRange:replacementString: in
turn returns YES. In this case you can make your changes to the text, and follow up by invoking didChangeText.
This method concludes the changes by posting an NSTextDidChangeNotification, which results in the
delegate receiving a textDidChange: message.
The textShouldBeginEditing: and textDidBeginEditing: messages are sent only once during an
editing session. More precisely, theyre sent upon the first user input since the NSTextView became the first
responder. Thereafter, these messagesand the NSTextDidBeginEditingNotificationare skipped in
the sequence. The textView:shouldChangeTextInRange:replacementString: method, however, must
be invoked for each individual change.
punctuation are preserved after a change. Smart insertion and deletion typically applies when the user has
selected whole words or other significant units of text. A smart deletion of a word before a comma, for example,
also deletes the space that would otherwise be left before the comma (though not placing it on the pasteboard
in a Cut operation). A smart insertion of a word between another word and a comma adds a space between
the two words to protect that boundary. NSTextView automatically uses smart insertion and deletion by
default; you can turn this behavior off using setSmartInsertDeleteEnabled:. Doing so causes only the
selected text to be deleted, and inserted text to be added, with no addition of white space.
If your subclass of NSTextView defines any methods that insert or delete text, you can make them smart by
taking advantage of two NSTextView methods. The smartDeleteRangeForProposedRange: method
expands a proposed deletion range to include any white space that should also be deleted. If you need to save
the deleted text, however, its typically best to save only the text from the original range. For smart insertion,
smartInsertForString:replacingRange:beforeString:afterString: returns by reference two
strings that you can insert before and after a given string to preserve spacing and punctuation. See the method
descriptions for more information.
64
Text Editing
Creating a Custom Text View
2.
3.
In the first level of support, the keyDown: method recognizes a limited set of events and ignores others. This
level of support is typical of games. (When overriding keyDown:, you must also override
acceptsFirstResponder to make your custom view respond to key events, as described in Event Handling
Basics in Cocoa Event Handling Guide in Cocoa Event Handling Guide .)
In the second level of support, you can override keyDown: and use the handleEvent: method to receive
key-binding support without implementing the NSTextInputClient protocol. Because the NSView method
inputContext does not instantiate NSTextInputContext automatically if the view does not conform to
NSTextInputClient, the custom view must instantiate it manually. You then implement the standard
key-binding methods that your view wants to support, such as moveForward: or deleteForward:. (The full
list of key-binding methods can be found in NSResponder.h.)
If you are writing your own text view from scratch, you should use the third level of support and implement
the NSTextInputClient protocol in addition to overriding keyDown: and using handleEvent:. NSTextView
and its subclasses are the only classes provided in Cocoa that implement NSTextInputClient, and if your
application needs more complex behavior than NSTextView can provide, as a word processor might, you
may need to implement a text view from the ground up. To do this, you must subclass NSView and implement
the NSTextInputClient protocol. (A class implementing this protocolby inheriting from NSTextView or
by implementing the protocol directlyis called a text view .)
If you are implementing the NSTextInputClient protocol, your view needs to manage marked text and
communicate with the text input context to support the text input system. These tasks are described in the
next two sections.
65
Text Editing
Creating a Custom Text View
A common example of marked text appears when a user enters a character with multiple keystrokes, such as
, in an NSTextView object. To enter this character, the user needs to type Option-E followed by the E key.
After pressing Option-E, the accent mark appears in a highlighted box, indicating that the text is marked (not
final). After the final E is pressed, the character appears and the highlight disappears.
66
Text Editing
Working with the Field Editor
67
Text Editing
Working with the Field Editor
want pressing Return to end editing but not select the next control, you can implement the
textDidEndEditing: delegate method in the text field. The field editor automatically calls this method if
the delegate implements it, and passes NSTextDidEndEditingNotification. The implementation can
examine this notification to discover the event that ended editing and respond appropriately.
68
Text Editing
Working with the Field Editor
This method returns YES to indicate that it handles this particular command and NO for other commands that
it doesnt handle. This approach has the advantage that it doesnt change the setup of the field editor but
handles just the special case of interest. Because the delegate message includes a reference to the control
being edited, you could add a check to restrict the behavior to a particular class, such as NSTextField, or an
individual subclass.
69
Text Editing
Working with the Field Editor
Listing 7-4
If the requesting object is not a custom text field or subclass, the delegate method returns nil and the window
uses its default field editor. This arrangement has the advantage that it does not instantiate the custom field
editor unless it is needed.
In OS X v10.6 and later, another way of providing a custom field editor is to override the NSCell method
fieldEditorForView:. This method, rather than the window delegate method, is more suitable for custom
cell subclasses.
You can find more information about subclassing NSTextView in Subclassing NSTextView (page 61).
Method
Description
fieldEditor: forObject:
endEditingFor:
Forces the field editor to give up its first responder status and
prepares it for its next assignment.
70
Text Editing
Working with the Field Editor
Method
Description
windowWillReturnFieldEditor:
toObject:
The NSTextFieldCell method related to the field editor is listed in Table 7-2.
Table 7-2
Method
Description
setUpFieldEditorAttributes:
The NSCell methods related to the field editor are listed in Table 7-3.
Table 7-3
Method
Description
fieldEditorForView:
selectWithFrame:
inView:editor: delegate:start:
length:
Uses the field editor passed with the message to select text
in a range.
editWithFrame: inView:editor:
delegate:event:
endEditing:
Ends any editing of text, using the field editor passed with
the message, begun with either of the other two NSCell
field editorrelated methods.
The NSControl methods related to the field editor are listed in Table 7-4. The NSControl delegate methods
listed in Table 7-4 are control-specific versions of the delegate methods and notifications defined by NSText.
The field editor, derived from NSText, initiates sending the delegate messages and notifications through its
editing actions.
71
Text Editing
Working with the Field Editor
Table 7-4
Method
Description
abortEditing
currentEditor
If the receiver is being edited, this method returns the field editor;
otherwise, it returns nil.
validateEditing
Sets the object value of the text in a cell of the receiving control to
the current contents of the cells field editor.
control:
textShouldBeginEditing:
Sent directly to the delegate when the user tries to enter a character
in a cell of the control passed with the message.
control:
textShouldEndEditing:
Sent directly to the delegate when the insertion point tries to leave
a cell of the control that has been edited.
controlTextDidBeginEditing:
controlTextDidChange:
controlTextDidEndEditing:
The NSResponder methods related to the field editor are listed in Table 7-5.
Table 7-5
Method
Description
insertBacktab:
insertNewlineIgnoringFieldEditor:
insertTabIgnoringFieldEditor:
72
Text Editing
Working with the Field Editor
The NSText and NSTextDelegate methods related to the field editor are listed in Table 7-6.
Table 7-6
Method
Description
isFieldEditor
Returns YES if the receiver interprets Tab, Shift-Tab, and Return (Enter)
as cues to end editing and possibly to change the first responder; NO if
it accepts them as text input.
setFieldEditor:
Controls whether the receiver interprets Tab, Shift-Tab, and Return (Enter)
as cues to end editing and possibly to change the first responder.
textDidBeginEditing:
Informs the delegate that the user has begun changing text, passing
NSTextDidBeginEditingNotification.
textDidChange:
Informs the delegate that the text object has changed its characters or
formatting attributes, passing NSTextDidChangeNotification.
textDidEndEditing:
Informs the delegate that the text object has finished editing (that it has
resigned first responder status), passing NSTextDidEndEditingNotification.
textShouldBeginEditing:
textShouldEndEditing:
73
Date
Notes
2014-02-11
2013-04-23
2012-09-19
2012-07-23
2012-04-27
2010-05-04
2010-03-23
New document that explains how the objects of the Cocoa text system
interact. This document contains content previously published in the
following documents, which remain in the legacy area of the ADC library:
Text System Overview, Text Attributes, Text Editing Programming Guide
for Cocoa, and Text Input and Output.
74
Apple Inc.
Copyright 2014 Apple Inc.
All rights reserved.
No part of this publication may be reproduced,
stored in a retrieval system, or transmitted, in any
form or by any means, mechanical, electronic,
photocopying, recording, or otherwise, without
prior written permission of Apple Inc., with the
following exceptions: Any person is hereby
authorized to store documentation on a single
computer or device for personal use only and to
print copies of documentation for personal use
provided that the documentation contains
Apples copyright notice.
No licenses, express or implied, are granted with
respect to any of the technology described in this
document. Apple retains all intellectual property
rights associated with the technology described
in this document. This document is intended to
assist application developers to develop
applications only for Apple-branded products.
Apple Inc.
1 Infinite Loop
Cupertino, CA 95014
408-996-1010
Apple, the Apple logo, Cocoa, Mac, Macintosh,
Objective-C, OS X, QuickDraw, TrueType, and
Xcode are trademarks of Apple Inc., registered in
the U.S. and other countries.
Helvetica and Times are registered trademarks of
Heidelberger Druckmaschinen AG, available from
Linotype Library GmbH.
Smalltalk-80 is a trademark of ParcPlace Systems.
APPLE MAKES NO WARRANTY OR REPRESENTATION,
EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS
DOCUMENT, ITS QUALITY, ACCURACY,
MERCHANTABILITY, OR FITNESS FOR A PARTICULAR
PURPOSE. AS A RESULT, THIS DOCUMENT IS PROVIDED
AS IS, AND YOU, THE READER, ARE ASSUMING THE
ENTIRE RISK AS TO ITS QUALITY AND ACCURACY.
IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT,
INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES RESULTING FROM ANY DEFECT, ERROR OR
INACCURACY IN THIS DOCUMENT, even if advised of
the possibility of such damages.
Some jurisdictions do not allow the exclusion of
implied warranties or liability, so the above exclusion
may not apply to you.