Build an eDoc Reader for your iPodby Matthew Russell
Apple's iPod has caught the world by storm and is emerging into a really handy gadget that does a lot more than play music. Although eBook reading isn't synonymous with iPod yet, it might be once you've completed this project.
This article is the first in a series that walks you through the process of developing a Cocoa application that allows you to read large text documents, PDF files, and other electronic books on your 3G iPod or newer. Following along with this series highlights a number of valuable concepts such as text wrangling, interfacing to the user defaults system, incorporating existing open source software as a part of your own project, and tackling the Cocoa-Java bridge.
The User Interface
For development, we'll use the latest version of Xcode--the IDE of choice for any Cocoa application. If you don't already have the latest version of Xcode, you can download it from Apple Developer Connection. You'll have to register, but it's free and worth the trouble. As with any other Cocoa project, open up Xcode, create a new project, and choose a new "Cocoa Application." Name the project "Pod Reader" and place it in whatever location you like. In Xcode, expand the "NIB files" folder at the very bottom of the leftmost pane to reveal "MainMenu.nib." Double click on "MainMenu.nib" to fire up IB (Interface Builder).
We'll follow the Model View Controller (MVC) paradigm for application design. MVC is the defacto design standard for Cocoa applications. The Model comprises custom classes that perform the bulk of the labor, the View encapsulates the GUI, and the Controller handles the flow of data between our model and our view. Normally, the best models and controls in the view are designed to be general and reusable. Controllers are typically application specific by necessity.
Using the IB panel with the controls on it, try and make your application look like the finished product shown below. First, resize the rather large window panel IB opens up for you to a more suitable size. Once it's resized, drag the appropriate AppKit framework controls onto the NSWindow panel. In all, you should need four NSTextFields (one of them is customized as a "System Font Text" label), three NSButtons, and an NSProgressIndicator.
The finished product. You specify a document and a destination directory (the iPod), designate a value to separate sections of a document on (such as "chapter" or "scene"), click on "Copy It," and the document is "intelligently" chunked into 4KB files you can read on your iPod. (Currently, the iPod will not display files larger than 4KB.)
The NSTextField that has the label "System Font Text" on it looks different from the other three, but it is actually the very same control. A few of its attributes are set to make it a label as a convenience to you. You can check it out for yourself and learn a lot more about the NSTextField by doing a comparison of the two. Select "Tools -> Show Info" from the menu and then select the "Attributes" menu at the top while the NSTextField is selected. You'll want to get familiar with this Info window and all that it has to offer you.
Drag controls onto your window using the controls palette. Controls are organized into groups designated by the topmost row. As you layout your design, use IB's guidelines for placing the widgets. IB does a nice job of helping you to line them up in accordance with human interface guidelines via its markup (dashed lines that appear) inside the window.
If you haven't worked in IB very much before, you might like to know that selecting and then clicking controls like NSButton a second time makes their label editable. You might also like to note that opening the Info on "Window" in the "Instances" tab of MainMenu.nib allows you to give the window a title and allows you to disable resizing by unchecking the "Resize" control.
Customizing the View
Your fingers are itching to write code at this point, but there's still a few things we can do first. As you recall, the controller handles data flow in the application. Its accomplishes this task through "outlets" and "actions." Outlets are nothing more than pointers to objects in the view. For example, we may want to modify the value of an NSTextField in our view, so we use its outlet in the controller to pass it a message. Actions are very similar; they are pointers to methods that are called in response to events that occur in the view, such as pressing an NSButton.
A few outlets we can take care of right away are ones that control the flow of tabbing. The NSTextFields directly above the "Source File" and "Destination" buttons should not be editable or selectable, so open their Info window and uncheck the "Editable" and "Selectable" options near the bottom. Also, uncheck "Enabled" for the "Copy It" button. We'll programmatically enable it in the application once certain conditions are met.
The NSTextField acting as a label as well as the NSTextFields just above the "Source File" and "Destination" buttons cannot be tabbed into, so that takes care of them. For the remaining controls, we'd like for the tabbing flow to proceed from top to bottom: from the "Source File" button, to the "Destination" button, to the text field we can type a "Separator" value into, and finally to the "Copy It" button.
To set the tabbing from "Source File" to "Destination," hold down the control button while the "Source File" button is selected, drag down to "Destination," and once "Destination" is marked up, release your mouse button. You should see a line drawn on your screen connecting them, and the Info window should open.
Select "nextKeyView" in the outlets tab and click "Connect." Repeat the same process to set the tabbing for the remaining controls, finishing up the loop by wrapping the "Copy It" button back up to the "Source File" button. To set the outlet that starts keyboard control with the "Source File" button as soon as the application starts, we'll designate the "Source File" button as the Initial First Responder. Setting this outlet is just like the others we set; control click from "Window" in the "Classes" tab of MainMenu.nib to the "Source File" button. Select "initialFirstResponder" once the Info window opens, and then click on "Connect."
Create outlets that handle the flow of tabbing and set the first responder status.
Creating the AppController Class
We're still not ready to write any code, but we are getting closer. In IB, click on the "Classes" tab of the MainMenu.nib palette. In the root of the browser, select "NSObject" and then choose "Classes -> Subclass NSObject" on the main menu. A new subclass of NSObject appears in the next pane of the browser; name it "AppController."
Create the AppController class by subclassing NSObject.
To specify the controller's "outlets" and "actions," select "AppController" in the MainMenu.nib palette, and then press "1" while holding down the Command key. The "AppController Class Info" window should appear. With the "Outlets" tab selected, click on the "Add" button to create an outlet. Name this outlet "copyButton," and change its corresponding popup button value from "id" to "NSButton." This change statically types "copyButton" as an NSButton. Statically typing objects can make debugging easier because it allows the compiler to provide better feedback. Repeat this process and create "destButton" and "sourceButton" outlets of type NSButton.
Next, create three outlets of type NSTextField and call them "destDir," "sourceFile," and "separatorValue." Finally, create a "progressIndicator" outlet of type NSProgressIndicator. You can go to "Help -> Documentation" in Xcode and type "NSProgressIndicator" in the search box to look up more information about NSProgressIndicator or any other class in this article. In the "Actions" tab, create two actions in an analogous manner to the outlets. Name the actions "copyIt" and "openFileDialog." Xcode inserts colons after their names for you. Your final actions and outlets should look like the ones below.
Outlets and Actions for AppController in IB.
Pages: 1, 2