Chapter 27 Challenge


#1

Well, I must say that none of the developer documentation on this seems to be overly helpful and there is no example I could find on the Apple Developer site. In any case below is my additional method (over ride the default) to print a page number at the bottom of the page but to be honest I am somewhat at a loss if I wanted to print at the top of the page what I would do. Note that the code, in the text, doesn’t seem to allow for much of a margin area so my invocation of this method actually seems to intrude on the printing rectangle area defined in the chapter.

[code]- (void)drawPageBorderWithSize:(NSSize)borderSize {
// Hold on to the current frame
NSRect currentFrame = [self frame];
// Get a new frame and set it
NSRect newFrame= NSMakeRect(0, 0, borderSize.width, borderSize.height);
[self setFrame];

// Get the font size from the attributes
NSFont *font = [attributes objectForKey:NSFontAttributeName];
float capHeight = [font capHeight];

// Construct the page number string for printing then get its length
// and figure where it goes on the page to center it.
NSString *string = [ NSString stringWithFormat:@"Page %d", currentPage + 1];
float strStartPt = (borderSize.width - (float)[string length]) / 2.0;

// Draw the string on the page...
//  Had to increase the spacing to keep it from printing off the page
//  this acuatlly causes it to intrude a little on the printing Rect
[self lockFocus];
[string drawAtPoint:NSMakePoint(strStartPt, borderSize.height - (3.4 * capHeight)) // 2 times the line spacing
     withAttributes:attributes];
[self unlockFocus];

// Restore the orig frame
[self setFrame:currentFrame];

}
[/code]

The above is based on what I could make out of the skimpy explanation found in the “Providing a Custom Pagination Scheme” area of the documentation and plenty of oops on the way. It works but it does not seem very elegant.


#2

Unfortunately I don’t think there are any easy answers for arranging the page. I do have one suggestion, though: to horizontally center the page number text, have a look at NSParagraphStyle. You can use it to set the text to be centered, and then provide a rect to draw the string in.


#3

Hi,

I’m really unstatisfied.
The challenge says “Add page number” and nothing more.
Nothing about top or bottom, center or not, and so on…
With the tools I have at the end of the chapter, we can only add it at the top.
This is what I have done.
But the solution…

This book is for learning (…), if the challenge is to write the page number at bottom page, please, say it and give at least the name of the tools (NSDivideRect, NSMutableParagraphStyle).
Looking is good to learn, even on other things that the one we are looking for, but I can’t guess NSDivideRect exists…
And this is why, I bought this book. I want to know what I have to look for.

This was my 2 cents for the next version.


#4

Based on the solution that comes with the book, I think that linesPerPage should be adjusted, in order to avoid the page number being on top of the last line, like this:

// How many lines per page? 
linesPerPage = pageRect.size.height / lineHeight -1;// -1 to give space to page number

Possibly it is not the best solution, but it seems to work.


#5

Indeed this is the best solution. In this way you’ll spare one line for printing the page number stamp (either before or after the for loop in the drawRect: method which draws the people records).
The tricky part for me was to get really centered the text for the print stamp. I have first tried to calculate the rect it was going to be drawn in, but I then resorted making two helper methods, one which provides the rect and one which provides the attributes for the page number stamp string:

#pragma mark - helpers
- (NSRect)rectForPageStamp {
    NSRect rectForPageStamp;
    rectForPageStamp.size.width = _pageRect.size.width;
    rectForPageStamp.size.height = _pageRect.size.height - _lineHeight;
    rectForPageStamp.origin.x = _pageRect.origin.x;
    rectForPageStamp.origin.y = _pageRect.origin.y + _pageRect.size.height - _lineHeight;
    return rectForPageStamp;
}

- (NSDictionary *)attributesForPageStampString {
    NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
    [attributes setObject:[_attributes objectForKey:NSFontAttributeName]  forKey:NSFontAttributeName];
    NSMutableParagraphStyle *pStyle = [[NSMutableParagraphStyle alloc] init];
    [pStyle setAlignment:NSTextAlignmentCenter];
    [attributes setObject:pStyle forKey:NSParagraphStyleAttributeName];
    return attributes;
}

Then to draw the page number stamp I’ve added this after the for loop in the drawRect: method:

//Page number stamp
    NSString *pageNumberStampString = [NSString stringWithFormat:@"Page: %ld", _currentPage + 1];
    [pageNumberStampString drawInRect:[self rectForPageStamp]withAttributes:[self attributesForPageStampString]];

My only doubt is about the helper method which returns the attributes for the new string: I’m assuming in it that the _attributes property of the view is set and contains already an object for the key NSFontAttributeName, which it always should since it is initialized with that in both initWithFrame: and awakeFromNib methods in my subclass.
Anyway, in order to avoid any possible runtime error maybe it would be better to add an extra checking for it before using it in the new attributes dictionary returned by the method.