<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="http://commons.oreilly.com/wiki/skins/common/feed.css?97"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://commons.oreilly.com/wiki/index.php?title=Learning_Cocoa_with_Objective-C/Document-Based_Applications/Rich-Text_Handling&amp;action=history&amp;feed=atom</id>
		<title>Learning Cocoa with Objective-C/Document-Based Applications/Rich-Text Handling - Revision history</title>
		<link rel="self" type="application/atom+xml" href="http://commons.oreilly.com/wiki/index.php?title=Learning_Cocoa_with_Objective-C/Document-Based_Applications/Rich-Text_Handling&amp;action=history&amp;feed=atom"/>
		<link rel="alternate" type="text/html" href="http://commons.oreilly.com/wiki/index.php?title=Learning_Cocoa_with_Objective-C/Document-Based_Applications/Rich-Text_Handling&amp;action=history"/>
		<updated>2013-05-19T05:09:09Z</updated>
		<subtitle>Revision history for this page on the wiki</subtitle>
		<generator>MediaWiki 1.11.0</generator>

	<entry>
		<id>http://commons.oreilly.com/wiki/index.php?title=Learning_Cocoa_with_Objective-C/Document-Based_Applications/Rich-Text_Handling&amp;diff=6272&amp;oldid=prev</id>
		<title>Docbook2Wiki: Initial conversion from Docbook</title>
		<link rel="alternate" type="text/html" href="http://commons.oreilly.com/wiki/index.php?title=Learning_Cocoa_with_Objective-C/Document-Based_Applications/Rich-Text_Handling&amp;diff=6272&amp;oldid=prev"/>
				<updated>2008-03-07T12:56:06Z</updated>
		
		<summary type="html">&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{Learning Cocoa with Objective-C/TOC}}&lt;br /&gt;
In [[Learning Cocoa with Objective-C/Document-Based Applications/Multiple Document Architecture|Chapter 10]], we showed how Cocoa's multiple-document architecture takes care of many of the tasks involved in building a document-centric application, and we used a simple text editor as an example. Cocoa's text-handling ability goes much further by supporting multiple fonts, various paragraph styles, embedded images, undo, drag-and-drop, and even spell checking. It can handle differences in text directionality and provides sophisticated typesetting capabilities, such as the ability to control kerning between characters.&lt;br /&gt;
&lt;br /&gt;
In this chapter, we are going to examine the functionality of &amp;lt;tt&amp;gt;NSTextView&amp;lt;/tt&amp;gt; and the other classes that compose the text system. We'll then dive into code and add the following functionality, one step at a time, to a rich-text editor:&lt;br /&gt;
&lt;br /&gt;
* Enable the font menu&lt;br /&gt;
* Work with attributed text&lt;br /&gt;
* Register undo actions&lt;br /&gt;
* Enable the text menu&lt;br /&gt;
* Handle embedded images&lt;br /&gt;
* Add a special feature that we'll save for last&lt;br /&gt;
&lt;br /&gt;
That's a lot of ground to cover, so let's get going!&lt;br /&gt;
&lt;br /&gt;
== Cocoa's Text System ==&lt;br /&gt;
&lt;br /&gt;
Cocoa's text system, which underlies the functionality we worked with in [[Learning Cocoa with Objective-C/Document-Based Applications/Multiple Document Architecture|Chapter 10]], consists of three API layers, as shown in [[Learning Cocoa with Objective-C/Document-Based Applications/Rich-Text Handling#learncocoa2-CHP-11-FIG-1|Figure 11-1]]. You can see the same Model-View-Controller (MVC) paradigm we've talked about previously in the design of the text system. At the top layer is the &amp;lt;tt&amp;gt;NSTextView&amp;lt;/tt&amp;gt; that provides the on-screen view of text.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;learncocoa2-CHP-11-FIG-1&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 11-1. Three layers of the Cocoa text system'''&lt;br /&gt;
&lt;br /&gt;
[[Image:Learning Cocoa with Objective-C_I_2_tt394.png|Three layers of the Cocoa text system]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At the bottom layer, the &amp;lt;tt&amp;gt;NSTextStorage&amp;lt;/tt&amp;gt; class gives programmatic access to the text. This allows you to search for text and manipulate paragraph and character styles without incurring the overhead of laying out the text for display.&lt;br /&gt;
&lt;br /&gt;
In the middle layer are the &amp;lt;tt&amp;gt;NSLayoutManager&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;NSTextContainer&amp;lt;/tt&amp;gt; classes, which control the way text is laid out on-screen or on the printed page. An &amp;lt;tt&amp;gt;NSTextContainer&amp;lt;/tt&amp;gt; object defines a region where text can be laid out. Typically, this is a rectangular region, but subclasses can support other shapes. If a container's area is inset from the text view's bounds, a margin appears around the text. An instance of the &amp;lt;tt&amp;gt;NSLayoutManager&amp;lt;/tt&amp;gt; class displays the text contained in an &amp;lt;tt&amp;gt;NSTextStorage&amp;lt;/tt&amp;gt; object, rendering text in an &amp;lt;tt&amp;gt;NSTextView&amp;lt;/tt&amp;gt;'s display according to the areas defined by &amp;lt;tt&amp;gt;NSTextContainer&amp;lt;/tt&amp;gt; objects.&lt;br /&gt;
&lt;br /&gt;
For most uses, the API provided by the &amp;lt;tt&amp;gt;NSTextView&amp;lt;/tt&amp;gt; class is all that you need to learn to enable rich-text functionality in your applications.&lt;br /&gt;
&lt;br /&gt;
=== Supported Text Data Types ===&lt;br /&gt;
&lt;br /&gt;
Cocoa's text system supports the following types of data that can be read, displayed, and saved:&lt;br /&gt;
&lt;br /&gt;
;A simple string&lt;br /&gt;
: As we saw in [[Learning Cocoa with Objective-C/Document-Based Applications/Multiple Document Architecture|Chapter 10]], you can set and read the contents of a text view to and from an &amp;lt;tt&amp;gt;NSString&amp;lt;/tt&amp;gt; instance. This is the easiest way to deal with plain text files.&lt;br /&gt;
;Data as rich text&lt;br /&gt;
: The Rich Text Format (RTF) is a standard created by Microsoft for representing text with multiple fonts and colors. RTF is supported by many word processors (including the TextEdit application that comes with Mac OS X) as an interchange format, but serves quite well as a primary document format. Files saved in RTF format will be assigned an ''.rtf''extension.&lt;br /&gt;
;Data as rich text with images&lt;br /&gt;
: Standard RTF files can also contain attachments, such as images, audio clips, and even QuickTime movies, which are embedded in the file. These files, known as RTFD (the &amp;quot;D&amp;quot; stands for ''directory'') use a type of package format, or directory, in which the embedded files of the RTF document are stored. The package will contain the RTF file (e.g., ''text.rtf''), along with any associated attachments (e.g., ''fuzzball.tiff''). When the file is saved, it will be assigned an ''.rtfd''extension.&lt;br /&gt;
&lt;br /&gt;
=== Working with File Wrappers ===&lt;br /&gt;
&lt;br /&gt;
Because RTFD files are not simple files, but are composed of many files in a directory structure, the &amp;lt;tt&amp;gt;dataRepresentationOfType:&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;loadDataRepresentation:ofType:&amp;lt;/tt&amp;gt; methods will not read them. To handle complex file types that consist of bundled directories, Cocoa provides ''file wrappers'' . File wrappers can be of three distinct types:&lt;br /&gt;
&lt;br /&gt;
* A directory wrapper that holds a directory and all the files and subdirectories within it&lt;br /&gt;
* A regular file wrapper that holds the contents of a single file&lt;br /&gt;
* A link wrapper that represents a symbolic link, or alias, in the filesystem&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;NSDocument&amp;lt;/tt&amp;gt; class provides the following methods for loading data from, and saving data to, file wrappers:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;- (BOOL)loadFileWrapperRepresentation:(NSFileWrapper *)wrapper ofType:(NSString *)type&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Loads the document data contained by the given file wrapper into the receiving &amp;lt;tt&amp;gt;NSDocument&amp;lt;/tt&amp;gt; object&lt;br /&gt;
;&amp;lt;tt&amp;gt;- (NSFileWrapper *)fileWrapperRepresentationOfType:(NSString *)type&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Returns a file wrapper object that represents the contents of the document for a given document type&lt;br /&gt;
&lt;br /&gt;
In fact, the &amp;lt;tt&amp;gt;NSDocument&amp;lt;/tt&amp;gt; implementation of these methods actually calls the &amp;lt;tt&amp;gt;dataRepresentationOfType:&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;loadDataRepresentation:ofType:&amp;lt;/tt&amp;gt; methods that we used in the Simple Text Edit application in [[Learning Cocoa with Objective-C/Document-Based Applications/Multiple Document Architecture|Chapter 10]]. By overloading the file wrapper load and save methods, we can support RTFD.&lt;br /&gt;
&lt;br /&gt;
== Creating a Rich-Text Editor ==&lt;br /&gt;
&lt;br /&gt;
To show how to work with rich text, we're going to create a new project similar to the Simple Text Edit application. The big difference is that the application we'll build in this chapter will work with rich-text files instead of just plain text. We'll make a few changes to the recipe along the way; but not too much has changed, so we'll zip through the parts that we've already covered. Refer back to [[Learning Cocoa with Objective-C/Document-Based Applications/Multiple Document Architecture|Chapter 10]] if you need help with any of the steps.&lt;br /&gt;
&lt;br /&gt;
To get started:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Launch Project Builder, and choose New Project from the File menu (File → New Project).&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;From the New Project window, select Application → Cocoa Document-based Application.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Name the project &amp;quot;RTF Edit&amp;quot;, and save it into your ''~/LearningCocoa''folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Compose the UI by opening the ''MyDocument.nib''file in Interface Builder and performing the following steps:&lt;br /&gt;
&lt;br /&gt;
# Remove the default text field.&lt;br /&gt;
# Drag an &amp;lt;tt&amp;gt;NSTextView&amp;lt;/tt&amp;gt; from the Views palette to the application's window.&lt;br /&gt;
# Resize the text view so that it occupies the entire window.&lt;br /&gt;
# Change the Autosizing options so that the view will follow changes in the window's size.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;In Project Builder, open ''MyDocument.h''from the Classes directory, and add a declaration for the text view's outlet.&lt;br /&gt;
&lt;br /&gt;
 #import &amp;lt;Cocoa/Cocoa.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 @interface MyDocument : NSDocument&lt;br /&gt;
 {&lt;br /&gt;
 '''    IBOutlet NSTextView * textView;'''&lt;br /&gt;
 }&lt;br /&gt;
 @end&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Save (File → Save, or [[Image:Learning Cocoa with Objective-C_I_2_tt396.png|]] -S) ''MyDocument.h'', and then drag it onto Interface Builder's ''MyDocument.nib''window so that Interface Builder can pick up the change to the file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Control-drag a connection from the File's Owner object (remember, this is a proxy for the &amp;lt;tt&amp;gt;MyDocument&amp;lt;/tt&amp;gt; instance at runtime) to the &amp;lt;tt&amp;gt;NSTextView&amp;lt;/tt&amp;gt; we added in step 4, and connect it to the &amp;lt;tt&amp;gt;textView&amp;lt;/tt&amp;gt; outlet.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Save (File → Save, or [[Image:Learning Cocoa with Objective-C_I_2_tt397.png|]] -S) the nib file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;In Project Builder, open the active target (Project → Edit Active Target, or Option-[[Image:Learning Cocoa with Objective-C_I_2_tt398.png|]]-E), and select the Info.plist Entries → Simple View → Document Types item in the outline.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Modify the default document type entry as shown in [[Learning Cocoa with Objective-C/Document-Based Applications/Rich-Text Handling#learncocoa2-CHP-11-FIG-12|Figure 11-12]]. Simply click on the &amp;quot;DocumentType&amp;quot; entry to select it, rename &amp;quot;DocumentType&amp;quot; to &amp;quot;Rich Text&amp;quot;, enter the values (''rtf'' for Extension and ''RTF''for OS types) into the Document Type Information area, and click Change to apply these settings.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Open ''MyDocument.h'', and add the &amp;lt;tt&amp;gt;dataFromFile&amp;lt;/tt&amp;gt; instance variable to hold the raw RTF data loaded from a file.&lt;br /&gt;
&lt;br /&gt;
 #import &amp;lt;Cocoa/Cocoa.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 @interface MyDocument : NSDocument&lt;br /&gt;
 {&lt;br /&gt;
     IBOutlet NSTextView * textView;&lt;br /&gt;
 '''    NSAttributedString * rtfData;'''&lt;br /&gt;
 }&lt;br /&gt;
 @end       &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;learncocoa2-CHP-11-FIG-2&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 11-2. Setting the application settings for RTF Edit. Don't forget to hit the Change button!'''&lt;br /&gt;
&lt;br /&gt;
[[Image:Learning Cocoa with Objective-C_I_2_tt400.png|Setting the application settings for RTF Edit. Don't forget to hit the Change button!]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Open ''MyDocument.m'', and remove the &amp;lt;tt&amp;gt;loadDataRepresentation:ofType:&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;dataRepresentationOfType:&amp;lt;/tt&amp;gt; methods. We are removing them now because later on we will load RTFD data from a directory, and we will need the functionality that the file wrapper version of these methods will give us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Implement the &amp;lt;tt&amp;gt;loadFileWrapperRepresentation:ofType:&amp;lt;/tt&amp;gt;.method:&lt;br /&gt;
&lt;br /&gt;
                      '''- (BOOL)loadFileWrapperRepresentation:(NSFileWrapper *)wrapper''' &lt;br /&gt;
                      '''                               ofType:(NSString *)type'''&lt;br /&gt;
                      '''{'''&lt;br /&gt;
                      '''&amp;lt;nowiki&amp;gt;    rtfData = [[NSAttributedString alloc]&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
                      '''        initWithRTF:[wrapper regularFileContents] documentAttributes:nil];   // a'''&lt;br /&gt;
                      '''    if (textView) {                                                          // b'''&lt;br /&gt;
                      '''&amp;lt;nowiki&amp;gt;        [[textView textStorage]&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
                      '''&amp;lt;nowiki&amp;gt;            replaceCharactersInRange:NSMakeRange(0, [[textView string] length])];&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
                      '''                withAttributedString:rtfData];'''&lt;br /&gt;
                      '''        [rtfData release];''' &lt;br /&gt;
                      '''     }'''&lt;br /&gt;
                      '''     return YES;'''&lt;br /&gt;
                      '''}'''&lt;br /&gt;
                   &lt;br /&gt;
&lt;br /&gt;
The code we added does the following things:&lt;br /&gt;
&lt;br /&gt;
# Creates a new &amp;lt;tt&amp;gt;NSAttributedString&amp;lt;/tt&amp;gt; based on the RTF contents of the file wrapper.&lt;br /&gt;
# If there is a &amp;lt;tt&amp;gt;textView&amp;lt;/tt&amp;gt; instead, we will load the RTF straight into it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Next, implement the &amp;lt;tt&amp;gt;fileWrapperRepresentationOfType:&amp;lt;/tt&amp;gt; method so that the document can save its contents.&lt;br /&gt;
&lt;br /&gt;
                      '''- (NSFileWrapper *)fileWrapperRepresentationOfType:(NSString *)type'''&lt;br /&gt;
                      '''{'''&lt;br /&gt;
                      '''&amp;lt;nowiki&amp;gt;    NSRange range = NSMakeRange(0,[[textView string] length];&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
                      '''&amp;lt;nowiki&amp;gt;    NSFileWrapper * wrapper = [[NSFileWrapper alloc]&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
                      '''&amp;lt;nowiki&amp;gt;        initRegularFileWithContents:[textView RTFFromRange:range]];&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
                      '''    return [wrapper autorelease];'''&lt;br /&gt;
                      ''' }'''&lt;br /&gt;
                   &lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Finally, implement the &amp;lt;tt&amp;gt;windowControllerDidLoadNib:&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
 - (void)windowControllerDidLoadNib:(NSWindowController *) aController&lt;br /&gt;
 {&lt;br /&gt;
     [super windowControllerDidLoadNib:aController];&lt;br /&gt;
 '''    if (rtfData) {                                                           // a'''&lt;br /&gt;
                      '''&amp;lt;nowiki&amp;gt;        [[textView textStorage]&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
                      '''&amp;lt;nowiki&amp;gt;            replaceCharactersInRange:NSMakeRange(0, [[textView string] length]);&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
                      '''                withAttributedString:rtfData];'''&lt;br /&gt;
                      '''        [rtfData release];'''&lt;br /&gt;
                      '''    }'''&lt;br /&gt;
                      '''    [textView setAllowsUndo:YES];                                            // b'''&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The code we added does the following things:&lt;br /&gt;
&lt;br /&gt;
# If there is RTF data waiting, it is loaded into the text view.&lt;br /&gt;
# Sets the text view to allow for undo actions to be performed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Save the project (File → Save, or [[Image:Learning Cocoa with Objective-C_I_2_tt404.png|]]-S).&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Build and run (Build → Build and Run, or [[Image:Learning Cocoa with Objective-C_I_2_tt405.png|]]-R) the application. You should see the text editor as shown in [[Learning Cocoa with Objective-C/Document-Based Applications/Rich-Text Handling#learncocoa2-CHP-11-FIG-3|Figure 11-3]]. You should be able to save and open rich-text files with it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;learncocoa2-CHP-11-FIG-3&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 11-3. RTF Edit in action'''&lt;br /&gt;
&lt;br /&gt;
[[Image:Learning Cocoa with Objective-C_I_2_tt406.png|RTF Edit in&lt;br /&gt;
 action&lt;br /&gt;
]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Enabling the Font Menu ==&lt;br /&gt;
&lt;br /&gt;
Text views are already wired to work with the AppKit's font system, which is defined by the &amp;lt;tt&amp;gt;NSFontPanel&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;NSFontManager&amp;lt;/tt&amp;gt; classes. The font manager keeps track of the currently selected font, while the font panel lets users change the current font. When a user enters text into a text view, the view stores the text into the underlying text-storage object with attributes matching the current font.&lt;br /&gt;
&lt;br /&gt;
The font manager, font panel, and an associated Font menu are set up using Interface Builder. To add font-handling functionality to our RTF Edit application, perform the following tasks:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Open ''MainMenu.nib''in Interface Builder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Open the Cocoa-Menus palette, and drag a Font menu to the MainMenu menu bar. Drop it between the Edit and Window menus, as shown in [[Learning Cocoa with Objective-C/Document-Based Applications/Rich-Text Handling#learncocoa2-CHP-11-FIG-4|Figure 11-4]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;learncocoa2-CHP-11-FIG-4&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 11-4. Adding the Font menu to RTF Edit'''&lt;br /&gt;
&lt;br /&gt;
[[Image:Learning Cocoa with Objective-C_I_2_tt407.png|Adding the Font menu to RTF Edit]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice that when you drop it, a Font Manager object is added to the nib. This is a reference to the Font Manager so that you can connect it to other objects in your application if needed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Save (File → Save, or [[Image:Learning Cocoa with Objective-C_I_2_tt408.png|]] -S) the nib file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Return to Project Builder, and Build and Run ([[Image:Learning Cocoa with Objective-C_I_2_tt409.png|]]-R) the project. Try the following tasks:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Type some text into the document, and select it. Open up the Font Panel (Font → Show Fonts, or [[Image:Learning Cocoa with Objective-C_I_2_tt410.png|]]-T), and change the font. Watch the selected text change, similar to what is shown in [[Learning Cocoa with Objective-C/Document-Based Applications/Rich-Text Handling#learncocoa2-CHP-11-FIG-5|Figure 11-5]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;learncocoa2-CHP-11-FIG-5&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 11-5. Using the Font Panel'''&lt;br /&gt;
&lt;br /&gt;
[[Image:Learning Cocoa with Objective-C_I_2_tt411.png|Using the Font Panel]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;From the Extras pop-up menu at the bottom of the Font Panel, select the Color item. Change the text to a different color by selecting a color and clicking the Apply button.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Close the Color and Font panels by clicking on their close window buttons.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Save your file, and then open it in Text Edit to see your changes work in various applications.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Text Storage and Attributed Text ==&lt;br /&gt;
&lt;br /&gt;
The text-storage object, an instance of &amp;lt;tt&amp;gt;NSTextStorage&amp;lt;/tt&amp;gt; , serves as the data repository for the contents of a text view. Conceptually, each character of text in the text-storage object has an associated dictionary of keys and values that describe the characteristics, or ''attributes --'' such as font, color, and paragraph style—of that character. [[Learning Cocoa with Objective-C/Single-Window Applications/Custom Views|Chapter 7]]'s String View application first introduced the notion of using attributes when drawing text. To make our text string show up in red, we set the following attribute in a dictionary (that we used when we drew the text):&lt;br /&gt;
&lt;br /&gt;
 [attribs setObject:[NSColor redColor]&lt;br /&gt;
             forKey:NSForegroundColorAttributeName];&lt;br /&gt;
&lt;br /&gt;
You can associate any attribute you want with text; however, the attributes that Cocoa's text system pays attention to are listed in [[Learning Cocoa with Objective-C/Document-Based Applications/Rich-Text Handling#learncocoa2-CHP-11-TABLE-1|Table 11-1]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;learncocoa2-CHP-11-TABLE-1&amp;quot;&amp;gt;&lt;br /&gt;
'''Table 11-1. Standard Cocoa text attributes'''&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; &lt;br /&gt;
|-&lt;br /&gt;
! Attribute identifier !! Class of value !! Default value&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSAttachmentAttributeName&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSTextAttachment&lt;br /&gt;
| None&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSBackgroundColorAttributeName&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSColor&lt;br /&gt;
| None&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSBaselineOffsetAttributeName&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSNumber ''(float)''&lt;br /&gt;
| 0.0&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSFontAttributeName&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSFont&lt;br /&gt;
| Helvetica, 12pt&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSForegroundColorAttributeName&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSColor&lt;br /&gt;
| Black&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSKernAttributeName&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSNumber ''(float)''&lt;br /&gt;
| 0.0&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSLigatureAttributeName&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSNumber ''(int)''&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSLinkAttributeName&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 id&lt;br /&gt;
| None&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSParagraphStyleName&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSParagraphStyle&lt;br /&gt;
| Default paragraph style&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSSuperScriptAttributeName&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSNumber ''(int)''&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSUnderlineStyleAttributeName&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 NSNumber ''(int)''&lt;br /&gt;
| None&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In [[Learning Cocoa with Objective-C/Document-Based Applications/Rich-Text Handling#learncocoa2-CHP-11-TABLE-1|Table 11-1]], we refer to &amp;lt;tt&amp;gt;NSNumber&amp;lt;/tt&amp;gt; ''(int)'' and &amp;lt;tt&amp;gt;NSNumber&amp;lt;/tt&amp;gt; ''(float)''. This means that the attribute should be set to an &amp;lt;tt&amp;gt;NSNumber&amp;lt;/tt&amp;gt; object that was created with the type specified.&lt;br /&gt;
&lt;br /&gt;
=== Working with Attributed Text ===&lt;br /&gt;
&lt;br /&gt;
The text-storage class provides methods to access the various attributes of the text it contains. To show how to work with text attributes, we'll add an analyzer to RTF Edit. Our analysis will count the number of characters in the document and give the number of font changes. To do so, follow these steps:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;In Project Builder, edit the ''MyDocument.h''file, and add the following action:&lt;br /&gt;
&lt;br /&gt;
 #import &amp;lt;Cocoa/Cocoa.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 @interface MyDocument : NSDocument&lt;br /&gt;
 {&lt;br /&gt;
     IBOutlet NSTextView * textView;&lt;br /&gt;
     NSAttributedString * rtfData;&lt;br /&gt;
 }&lt;br /&gt;
 '''- (IBAction)analyzeText:(id)sender;'''&lt;br /&gt;
 @end&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Save the ''MyDocument.h''file, then open ''MyDocument.nib''in Interface Builder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Reparse the ''MyDocument.h''file in Interface Builder. To do this, drag the ''MyDocument.h''file to the ''MyDocument.nib''window.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Add a button to our document interface, and name it Analyze, as shown in [[Learning Cocoa with Objective-C/Document-Based Applications/Rich-Text Handling#learncocoa2-CHP-11-FIG-6|Figure 11-6]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;learncocoa2-CHP-11-FIG-6&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 11-6. Adding an Analyze button to our interface'''&lt;br /&gt;
&lt;br /&gt;
[[Image:Learning Cocoa with Objective-C_I_2_tt436.png|Adding an Analyze button to our interface]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Control-drag a connection from the Analyze button to the File's Owner object, and connect the button to the &amp;lt;tt&amp;gt;analyzeText:&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Save ([[Image:Learning Cocoa with Objective-C_I_2_tt437.png|]]-S) the nib file, and return to Project Builder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Edit the ''MyDocument.m''file, and add the &amp;lt;tt&amp;gt;analyzeText:&amp;lt;/tt&amp;gt; method as shown.&lt;br /&gt;
&lt;br /&gt;
                         '''- (IBAction)analyzeText:(id)sender'''&lt;br /&gt;
                         '''{'''&lt;br /&gt;
                         '''    int count = 0;                                                       // a'''&lt;br /&gt;
                         '''    int fontChanges = -1;                                                // b'''&lt;br /&gt;
                         '''    id lastAttribute = nil;                                              // c'''&lt;br /&gt;
                         '''    NSTextStorage * storage = [textView textStorage];                    // d'''&lt;br /&gt;
 &lt;br /&gt;
                         '''    while (count &amp;lt; [storage length]) {                                   // e'''&lt;br /&gt;
                         '''        id attributeValue = [storage attribute:NSFontAttributeName'''&lt;br /&gt;
                         '''                                    atIndex:count'''&lt;br /&gt;
                         '''                             effectiveRange:nil];'''&lt;br /&gt;
                         '''        if (attributeValue != lastAttribute) {                           // f'''&lt;br /&gt;
                         '''            fontChanges++;'''&lt;br /&gt;
                         '''        }'''&lt;br /&gt;
                         '''        lastAttribute = attributeValue;                                  // g'''&lt;br /&gt;
                         '''        count++;                                                         // h'''&lt;br /&gt;
                         '''    }'''&lt;br /&gt;
 &lt;br /&gt;
                         '''    NSBeginAlertSheet(@&amp;quot;Analysis&amp;quot;,         // title                      // i'''&lt;br /&gt;
                         '''                      @&amp;quot;OK&amp;quot;,               // default button label'''&lt;br /&gt;
                         '''                      nil,                 // cancel button label'''&lt;br /&gt;
                         '''                      nil,                 // other button label'''&lt;br /&gt;
                         '''                      [textView window],   // document window'''&lt;br /&gt;
                         '''                      nil,                 // modal delegate'''&lt;br /&gt;
                         '''                      NULL,                // selector to method'''&lt;br /&gt;
                         '''                      NULL,                // dismiss selector'''&lt;br /&gt;
                         '''                      nil,                 // context info'''&lt;br /&gt;
                         '''                      @&amp;quot;Font Changes %i&amp;quot;,'''&lt;br /&gt;
                         '''                      fontChanges);'''&lt;br /&gt;
                         '''}'''&lt;br /&gt;
                      &lt;br /&gt;
&lt;br /&gt;
The code we added performs the following tasks:&lt;br /&gt;
&lt;br /&gt;
# Sets up a counter to loop through all the characters in the document. This will allow us to examine the characters and notice font changes as we loop through the document.&lt;br /&gt;
# Sets up a counter that will be used to keep track of the number of font changes that are found in the document.&lt;br /&gt;
# Acts as a holder for the text-attribute object that was examined during a previous iteration of our loop.&lt;br /&gt;
# Gets a reference to the text-storage object behind the text view.&lt;br /&gt;
# Sets up a loop that will continue until we have examined every character in the document. Each time the loop is executed, the attribute value for the current character is obtained.&lt;br /&gt;
# Checks to see if the font attribute of the current character is the same as the last character. If not, we record the change in font.&lt;br /&gt;
# Stores this font attribute so that we can compare it to the font attribute we'll see the next time through the loop.&lt;br /&gt;
# Increments our counter.&lt;br /&gt;
# Creates our message and displays it to the user on a sheet attached to the window. We can pass in &amp;lt;tt&amp;gt;nil&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;NULL&amp;lt;/tt&amp;gt; to most of the arguments since the sheet is for informative purposes only.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Save the project (File → Save, or [[Image:Learning Cocoa with Objective-C_I_2_tt439.png|]]-S).&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Build and run ([[Image:Learning Cocoa with Objective-C_I_2_tt440.png|]]-R) the application. Type some text, change the fonts, and then hit the Analyze button. You should see something like [[Learning Cocoa with Objective-C/Document-Based Applications/Rich-Text Handling#learncocoa2-CHP-11-FIG-7|Figure 11-7]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;learncocoa2-CHP-11-FIG-7&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 11-7. RTF Edit analyzing its text'''&lt;br /&gt;
&lt;br /&gt;
[[Image:Learning Cocoa with Objective-C_I_2_tt441.png|RTF Edit analyzing its text]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Our next set of additions to the code will change the formatting of the text in our document.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;In Project Builder, edit the ''MyDocument.h''file, and add the following action:&lt;br /&gt;
&lt;br /&gt;
 #import &amp;lt;Cocoa/Cocoa.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 @interface MyDocument : NSDocument&lt;br /&gt;
 {&lt;br /&gt;
     IBOutlet NSTextView * textView;&lt;br /&gt;
     NSData * dataFromFile;&lt;br /&gt;
 }&lt;br /&gt;
 - (IBAction)analyzeText:(id)sender;&lt;br /&gt;
 '''- (IBAction)clearFormatting:(id)sender;'''&lt;br /&gt;
 @end&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Save the ''MyDocument.h'' file; then open ''MyDocument.nib''in Interface Builder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Reparse the ''MyDocument.h''file in Interface Builder. To do this, drag the ''MyDocument.h''file to the ''MyDocument.nib''window.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Add a button to our document interface, and name it Remove Formatting, as shown in [[Learning Cocoa with Objective-C/Document-Based Applications/Rich-Text Handling#learncocoa2-CHP-11-FIG-8|Figure 11-8]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;learncocoa2-CHP-11-FIG-8&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 11-8. Adding a Remove Formatting button to RTF Edit'''&lt;br /&gt;
&lt;br /&gt;
[[Image:Learning Cocoa with Objective-C_I_2_tt443.png|Adding a Remove Formatting button to RTF Edit]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Control-drag a connection from the Remove Formatting button to the File's Owner object, and connect the button to the &amp;lt;tt&amp;gt;clearFormatting:&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Save ([[Image:Learning Cocoa with Objective-C_I_2_tt444.png|]]-S) the nib file, and return to Project Builder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Edit the ''MyDocument.m''file, and add the &amp;lt;tt&amp;gt;clearFormatting:&amp;lt;/tt&amp;gt; method as shown.&lt;br /&gt;
&lt;br /&gt;
                         '''- (IBAction)clearFormatting:(id)sender'''&lt;br /&gt;
                         '''{'''&lt;br /&gt;
                         '''    NSTextStorage * storage = [textView textStorage];                     // a'''&lt;br /&gt;
                         '''    NSRange range = NSMakeRange(0, [storage length]);                     // b'''&lt;br /&gt;
                         '''    NSMutableDictionary * attribs = [NSMutableDictionary dictionary];     // c'''&lt;br /&gt;
                         '''    [attribs setObject:[NSFont fontWithName:@&amp;quot;Helvetica&amp;quot; size:12]         // d'''&lt;br /&gt;
                         '''                forKey:NSFontAttributeName];'''&lt;br /&gt;
                         '''    [storage setAttributes:attribs range:range];                          // e'''&lt;br /&gt;
                         '''}'''&lt;br /&gt;
                      &lt;br /&gt;
&lt;br /&gt;
The code that we added performs the following tasks:&lt;br /&gt;
&lt;br /&gt;
# Gets a reference to the text-storage object behind the text view&lt;br /&gt;
# Creates a range structure that will encompass all of the text in the storage object&lt;br /&gt;
# Creates a new mutable dictionary for the attributes to which we will set the text&lt;br /&gt;
# Adds an attribute to the dictionary to format the text with the Helvetica font in size 12&lt;br /&gt;
# Tells the storage to apply the new attributes to all characters&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Save the project (File → Save, or [[Image:Learning Cocoa with Objective-C_I_2_tt446.png|]]-S).&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Build and run ([[Image:Learning Cocoa with Objective-C_I_2_tt447.png|]]-R) the application. Type some text, change the fonts, and then hit the Remove Formatting button. You should see all of your changes disappear.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Registering Undo Actions ===&lt;br /&gt;
&lt;br /&gt;
There's one small problem with our method to remove formatting. When you make changes after removing the formatting and then want to undo changes to a point in time before you cleared the formatting, things don't work as expected. This is because we need to register the change with the ''undo manager'' .&lt;br /&gt;
&lt;br /&gt;
The undo manager, implemented by the &amp;lt;tt&amp;gt;NSUndoManager&amp;lt;/tt&amp;gt; class, is a general-purpose recorder of operations that can be undone or redone. An undoable operation is registered with the undo manager by specifying an object and a method to call on that object, along with an argument to pass to that method.&lt;br /&gt;
&lt;br /&gt;
To allow the RTF Edit application to undo the removal of formatting, perform the following steps:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Edit the &amp;lt;tt&amp;gt;removeFormatting:&amp;lt;/tt&amp;gt; method in ''MyDocuments.m'', adding the code indicated in boldface:&lt;br /&gt;
&lt;br /&gt;
 - (IBAction)clearFormatting:(id)sender&lt;br /&gt;
 {&lt;br /&gt;
     NSTextStorage * storage = [textView textStorage];                     &lt;br /&gt;
     NSRange range = NSMakeRange(0, [storage length]);                     &lt;br /&gt;
     NSMutableDictionary * attribs = [NSMutableDictionary dictionary];  &lt;br /&gt;
 '''    NSUndoManager * undoManager = [self undoManager];                     // a'''&lt;br /&gt;
                         '''    [undoManager registerUndoWithTarget:storage                           // b'''&lt;br /&gt;
                         '''                               selector:@selector(setAttributedString:)'''&lt;br /&gt;
                         '''&amp;lt;nowiki&amp;gt;                                 object:[storage copy]];&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
   &lt;br /&gt;
     [attribs setObject:[NSFont fontWithName:@&amp;quot;Helvetica&amp;quot;                  &lt;br /&gt;
                                        size:12]&lt;br /&gt;
                 forKey:NSFontAttributeName];&lt;br /&gt;
     [storage setAttributes:attribs range:range];&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The code we added performs the following tasks:&lt;br /&gt;
&lt;br /&gt;
# Gets the &amp;lt;tt&amp;gt;undoManager&amp;lt;/tt&amp;gt; from the document. Each document has an associated &amp;lt;tt&amp;gt;undoManager&amp;lt;/tt&amp;gt;.&lt;br /&gt;
# Registers an undo action with the &amp;lt;tt&amp;gt;undoManager&amp;lt;/tt&amp;gt;. This action calls the underlying text-storage object's &amp;lt;tt&amp;gt;setAttributedString:&amp;lt;/tt&amp;gt; method with a copy of the current storage—effectively resetting the contents of the storage to the same state as before the change.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Save the project (File → Save, [[Image:Learning Cocoa with Objective-C_I_2_tt449.png|]]-S).&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Build and run ([[Image:Learning Cocoa with Objective-C_I_2_tt450.png|]]-R) the application. Undo should now work correctly.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Enabling the Text Menu ==&lt;br /&gt;
&lt;br /&gt;
Not only do text views come wired to work with the AppKit's font system, they are also prewired to work with paragraph-formatting rulers. These rulers let a user specify paragraph formatting for his documents. The easiest way to enable this functionality is to use Interface Builder. Perform the following steps:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Open ''MainMenu.nib''in Interface Builder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Open the Cocoa Menus palette, and drag a Text menu to the MainMenu menu bar. Drop it between the Font and Window menus, as shown in [[Learning Cocoa with Objective-C/Document-Based Applications/Rich-Text Handling#learncocoa2-CHP-11-FIG-9|Figure 11-9]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;learncocoa2-CHP-11-FIG-9&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 11-9. Adding the Text Menu to RTF Edit's main menu bar'''&lt;br /&gt;
&lt;br /&gt;
[[Image:Learning Cocoa with Objective-C_I_2_tt451.png|Adding the Text Menu to RTF Edit's main menu bar]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Save (File → Save, or [[Image:Learning Cocoa with Objective-C_I_2_tt452.png|]] -S) the nib file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Return to Project Builder, and Build and run ([[Image:Learning Cocoa with Objective-C_I_2_tt453.png|]]-R) the project. Try the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Select the Show Ruler menu item (Text → Show Ruler). A ruler will appear on the text view, as shown in [[Learning Cocoa with Objective-C/Document-Based Applications/Rich-Text Handling#learncocoa2-CHP-11-FIG-10|Figure 11-10]]. The ruler displays margin and tab markers similar to those used in full-blown word processors.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;learncocoa2-CHP-11-FIG-10&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 11-10. RTF Edit sporting a ruler'''&lt;br /&gt;
&lt;br /&gt;
[[Image:Learning Cocoa with Objective-C_I_2_tt454.png|RTF Edit sporting a ruler]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Type some text, and change the paragraph alignment using the four buttons along the top-left hand side of the ruler.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Create another paragraph, and change its indentation settings using the controls provided by the ruler.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Handling Embedded Images ==&lt;br /&gt;
&lt;br /&gt;
The next piece of functionality we will add to RTF Edit is the ability to handle embedded images. To do this, we tell the text view that we want it place graphics into documents, and we add methods to support the loading and saving of RTFD files.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;In Project Builder, open the RTF Edit target (Project → Edit Active Target, or Option-[[Image:Learning Cocoa with Objective-C_I_2_tt455.png|]]-E), and select the Application Settings tab.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Add a new document type entry as shown in [[Learning Cocoa with Objective-C/Document-Based Applications/Rich-Text Handling#learncocoa2-CHP-11-FIG-11|Figure 11-11]]. Fill out the Document Type Information fields with the fields shown, and click Add. Don't forget to set the Document Class field to &amp;lt;tt&amp;gt;MyDocument&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;learncocoa2-CHP-11-FIG-11&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 11-11. Adding the rtfd file type to the RTF Edit application'''&lt;br /&gt;
&lt;br /&gt;
[[Image:Learning Cocoa with Objective-C_I_2_tt456.png|Adding the rtfd file type to the RTF Edit application]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Open ''MyDocument.m'', and change the &amp;lt;tt&amp;gt;loadFileWrapperRepresentation:ofType:&amp;lt;/tt&amp;gt; method as shown. This will allow RTF edit to open either RTF or RTFD files. Note that we use the name of the document type we set previously in step 2.&lt;br /&gt;
&lt;br /&gt;
 - (BOOL)loadFileWrapperRepresentation:(NSFileWrapper *) ofType:(NSString *)type&lt;br /&gt;
 {&lt;br /&gt;
 '''    if ([type isEqualToString:@&amp;quot;Rich Text with Attachments&amp;quot;]) {'''&lt;br /&gt;
                      '''&amp;lt;nowiki&amp;gt;        rtfData = [[NSAttributedString alloc]&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
                      '''            initWithRTFDFileWrapper:wrapper documentAttributes:nil];'''&lt;br /&gt;
                      '''    } else {'''&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        rtfData = [[NSAttributedString alloc]&lt;br /&gt;
            initWithRTF:[wrapper regularFileContents] documentAttributes:nil]; &lt;br /&gt;
&amp;lt;/nowiki&amp;gt;'''    }'''&amp;lt;nowiki&amp;gt;        &lt;br /&gt;
    if (textView) {                                                                &lt;br /&gt;
        [[textView textStorage]&lt;br /&gt;
            replaceCharactersInRange:NSMakeRange(0, [[textView string] length]);&lt;br /&gt;
                withAttributedString:rtfData];&lt;br /&gt;
        [rtfData release];                                                         &lt;br /&gt;
     }&lt;br /&gt;
     return YES;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Next, change the &amp;lt;tt&amp;gt;fileWrapperRepresentationOfType:&amp;lt;/tt&amp;gt; method so that the document can save its contents according to the type of data requested.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;- (NSFileWrapper *)fileWrapperRepresentationOfType:(NSString *)type&lt;br /&gt;
{&lt;br /&gt;
    NSRange range = NSMakeRange(0, [[textView string] length]);&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;'''    if ([type isEqualToString:@&amp;quot;Rich Text with Attachments&amp;quot;]) {'''&lt;br /&gt;
                      '''&amp;lt;nowiki&amp;gt;        return [[textView textStorage] RTFDFileWrapperFromRange:range&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
                      '''                                             documentAttributes:nil];'''&lt;br /&gt;
                      '''    } else {'''&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        NSFileWrapper * wrapper = [[NSFileWrapper alloc]&lt;br /&gt;
            initRegularFileWithContents:[textView RTFFromRange:range]];&lt;br /&gt;
        return [wrapper autorelease];&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;'''    }'''&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Finally, change the &amp;lt;tt&amp;gt;windowControllerDidLoadNib:&amp;lt;/tt&amp;gt; method so that graphics can be added to the documents.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;- (void)windowControllerDidLoadNib:(NSWindowController *) aController&lt;br /&gt;
{&lt;br /&gt;
    [super windowControllerDidLoadNib:aController];&lt;br /&gt;
    if (rtfData) {                                                              &lt;br /&gt;
        [[textView textStorage]&lt;br /&gt;
            replaceCharactersInRange:NSMakeRange(0, [[textView string] length]);&lt;br /&gt;
                withAttributedString:rtfData];&lt;br /&gt;
        [rtfData release];&lt;br /&gt;
    }&lt;br /&gt;
    [textView setAllowsUndo:YES];   &lt;br /&gt;
&amp;lt;/nowiki&amp;gt;'''    [textView setImportsGraphics:YES];'''                                           &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Save the project (File → Save, or [[Image:Learning Cocoa with Objective-C_I_2_tt460.png|]]-S).&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Clean the project (Build → Clean, or Shift-[[Image:Learning Cocoa with Objective-C_I_2_tt461.png|]]-K).&amp;lt;ref&amp;gt;In some of the versions of Project Builder that we worked with while writing this book, there was a problem with adding document types unless you forced this cleaning step.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Build and run ([[Image:Learning Cocoa with Objective-C_I_2_tt462.png|]]-R) the application. Create a document, and drag an image into it. When you save the document, the Save panel will have a pull-down menu to select what kind of file you are saving, as shown in [[Learning Cocoa with Objective-C/Document-Based Applications/Rich-Text Handling#learncocoa2-CHP-11-FIG-12|Figure 11-12]]. Be sure to select Rich Text with Attachments in order to save your image information .&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The Spoken Word ===&lt;br /&gt;
&lt;br /&gt;
The last thing we will add to our application has very little to do with rich text, but it's fun and shows off one of the ways that Cocoa is integrated with other Mac OS X technologies. We'll add a button that, when pressed, will speak the contents of a document to us using Mac OS X's built-in Text-To-Speech engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;In Project Builder, edit ''MyDocument.h'', and add the following action declaration:&lt;br /&gt;
&lt;br /&gt;
 #import &amp;lt;Cocoa/Cocoa.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 @interface MyDocument : NSDocument&lt;br /&gt;
 {&lt;br /&gt;
     IBOutlet NSTextView * textView;&lt;br /&gt;
     NSData * dataFromFile;&lt;br /&gt;
     NSString * dataType;&lt;br /&gt;
 }&lt;br /&gt;
 - (IBAction)analyzeText:(id)sender;&lt;br /&gt;
 - (IBAction)removeFormatting:(id)sender;&lt;br /&gt;
 '''- (IBAction)speakText:(id)sender;'''&lt;br /&gt;
 @end&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Save the ''MyDocument.h''file; then open ''MyDocument.nib''in Interface Builder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Reparse the ''MyDocument.h''file by dragging the ''MyDocument.h''file from Project Builder to Interface Builder's ''MyDocument.nib''window.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Add a button to our document interface, and name it Speak, as shown in [[Learning Cocoa with Objective-C/Document-Based Applications/Rich-Text Handling#learncocoa2-CHP-11-FIG-13|Figure 11-13]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;learncocoa2-CHP-11-FIG-12&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 11-12. Saving a file with attachments'''&lt;br /&gt;
&lt;br /&gt;
[[Image:Learning Cocoa with Objective-C_I_2_tt464.png|Saving a file with attachments]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;learncocoa2-CHP-11-FIG-13&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 11-13. Adding the Speak button to RTF Edit'''&lt;br /&gt;
&lt;br /&gt;
[[Image:Learning Cocoa with Objective-C_I_2_tt465.png|Adding the Speak button to RTF Edit]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Control-drag a connection from the Speak button to the File's Owner object, and connect it to the &amp;lt;tt&amp;gt;speakText:&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Save ([[Image:Learning Cocoa with Objective-C_I_2_tt466.png|]]-S) the nib file, and return to Project Builder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;In Project Builder, edit the ''MyDocument.m''file, and add the &amp;lt;tt&amp;gt;speakText:&amp;lt;/tt&amp;gt; method as shown:&lt;br /&gt;
&lt;br /&gt;
                         '''- (IBAction)speakText:(id)sender'''&lt;br /&gt;
                         '''{'''&lt;br /&gt;
                         '''    [textView startSpeaking:sender];'''&lt;br /&gt;
                         '''}'''&lt;br /&gt;
                      &lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Save the project (File → Save, or [[Image:Learning Cocoa with Objective-C_I_2_tt468.png|]]-S).&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Build and run ([[Image:Learning Cocoa with Objective-C_I_2_tt469.png|]]-R) the application. Type some text, then click on the Speak button. The built-in Text-to-Speech engine will start reading off what you typed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Exercises ==&lt;br /&gt;
&lt;br /&gt;
# Using Interface Builder, turn on image attachments and undo by removing the two lines of code in the &amp;lt;tt&amp;gt;awakeFromNib&amp;lt;/tt&amp;gt; method that perform this duty.&lt;br /&gt;
# Set the ruler to appear automatically when a document window opens.&lt;br /&gt;
# Replace the Speak buttons with menu items.&lt;br /&gt;
# Add a number of characters line to the Analyze sheet.&lt;br /&gt;
== Notes ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Docbook2Wiki</name></author>	</entry>

	</feed>