// Copyright 1997-1999 Omni Development, Inc.  All rights reserved.
//
// This software may only be used and reproduced according to the
// terms in the file OmniSourceLicense.html, which should be
// distributed with this project and can also be found at
// http://www.omnigroup.com/DeveloperResources/OmniSourceLicense.html.

#import "OAScrollView.h"

#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#import <OmniBase/OmniBase.h>
#import <OmniFoundation/OmniFoundation.h>

#import "NSImage-OAExtensions.h"
#import "OAPageSelectableDocumentProtocol.h"
#import "OAZoomableViewProtocol.h"
#import "ps.h"

RCS_ID("$Header: /Network/Developer/Source/CVS/OmniGroup/OmniAppKit/Widgets.subproj/OAScrollView.m,v 1.14 1999/04/06 23:36:18 len Exp $")

@interface OAScrollView (Private)
- (void)processKeyDown:(NSEvent *)theEvent;
- (void)scrollDownByPercentage:(float)percentage;
- (void)pageUp:(id)sender;
- (void)pageDown:(id)sender;
- (void)zoomIn:(id)sender;
- (void)zoomOut:(id)sender;
- (void)addOrRemoveScrollersIfNeeded;
- (void)autoScrollTile;
- (NSSize)contentSizeForHorizontalScroller:(BOOL)hasHorizontalScroller verticalScroller:(BOOL)hasVerticalScroller;
@end

@implementation OAScrollView

#if defined(RHAPSODY) || defined(WIN32)
#define SCROLLERS_ON_RIGHT
#endif

static int startingScales[] = {50, 75, 100, 125, 150, 200, 400, 0};
static NSFont *smallSystemFont;

+ (void)initialize;
{
    static BOOL initialized = NO;

    [super initialize];

    if (initialized)
        return;

    initialized = YES;

    smallSystemFont = [NSFont systemFontOfSize:10.0];
}

- initWithFrame:(NSRect)theFrame
{
    NSRect widgetFrame = NSMakeRect(0.0, 0.0, 0.0, 0.0);
#ifndef RHAPSODY
    NSRect dummyFrame = NSMakeRect(0.0, 0.0, 1.0, 1.0);
#endif
    
    [super initWithFrame:theFrame];

    [[self contentView] setAutoresizesSubviews:YES];
    scrollBehavior = AUTO_SCROLL;
    [self setHasHorizontalScroller:YES];
    [self setHasVerticalScroller:YES];

    horizontalWidgetsBox = [[NSView alloc] initWithFrame:widgetFrame];
    [self addSubview:horizontalWidgetsBox];

#ifndef RHAPSODY
    // Skip buttons in scroller on Mac interface, since clicking below thumb pages down.
    // create page up/down buttons
    pageUpButton = [[NSButton alloc] initWithFrame:dummyFrame];
    [pageUpButton setImage:[NSImage imageNamed:@"OAPageUp" inBundleForClass:[OAScrollView class]]]; // Note we use OAScrollView and not self intentionally
    [pageUpButton setAlternateImage:[NSImage imageNamed:@"OAPageUpAlt" inBundleForClass:[OAScrollView class]]];
    [pageUpButton setTag:OMNI_PAGE_UP_TAG];
    [pageUpButton setTarget:self];
    [pageUpButton setAction:@selector(pageUp:)];
    [pageUpButton setKeyEquivalent:@""];
    [pageUpButton setEnabled:YES];
    [pageUpButton setRefusesFirstResponder:YES];
    [self addSubview:pageUpButton];

    pageDownButton = [[NSButton alloc] initWithFrame:dummyFrame];
    [pageDownButton setImage:[NSImage imageNamed:@"OAPageDown" inBundleForClass:[OAScrollView class]]];
    [pageDownButton setAlternateImage:[NSImage imageNamed:@"OAPageDownAlt" inBundleForClass:[OAScrollView class]]];
    [pageDownButton setTag:OMNI_PAGE_DOWN_TAG];
    [pageDownButton setTarget:self];
    [pageDownButton setAction:@selector(pageDown:)];
    [pageDownButton setKeyEquivalent:@""];
    [pageDownButton setEnabled:YES];
    [pageDownButton setRefusesFirstResponder:YES];
    [self addSubview:pageDownButton];
#endif    
    return self;
}

- (void)dealloc;
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];

    [self removeFromSuperview];
    [horizontalWidgetsBox removeFromSuperview];
    [horizontalWidgetsBox release];
    [pageUpButton removeFromSuperview];
    [pageUpButton release];
    [pageDownButton removeFromSuperview];
    [pageDownButton release];
    [scalePopUpButton removeFromSuperview];
    [scalePopUpButton release];
    [pagePromptTextField removeFromSuperview];
    [pagePromptTextField release];
    [pageNumberTextField removeFromSuperview];
    [pageNumberTextField release];
    [pagesCountTextField removeFromSuperview];
    [pagesCountTextField release];

    [super dealloc];
}

- (void)zoomToScale:(double)newZoomFactor;
{
    if (newZoomFactor == zoomFactor)
        return;

    zoomFactor = newZoomFactor;
    [[self documentView] zoomTo:newZoomFactor];
    [[self documentView] displayIfNeeded];
}

- (void)zoomFromSender:(NSMenuItem *)sender;
{
    double newZoomFactor;

    // This hack is needed under 4.2.  Maybe Rhapsody is better.
    if ([sender isKindOfClass:[NSMatrix class]])
        sender = [(NSMatrix *)sender selectedCell];

    newZoomFactor = [sender tag] / 100.0;
    [self zoomToScale:newZoomFactor];
}

- (float)zoomFactor;
{
    return zoomFactor;
}

- (void)setDelegate:(id)newDelegate;
{
    delegate = newDelegate;

    if ([delegate conformsToProtocol:@protocol(OAPageSelectableDocument)]) {
	NSRect                      textRect;

	textRect = [[self horizontalScroller] frame];

        pagePromptTextField = [[NSTextField alloc] initWithFrame:textRect];
	[pagePromptTextField setFont:smallSystemFont];
	[pagePromptTextField setStringValue:@"Page"];
	[pagePromptTextField setAlignment:NSRightTextAlignment];
	[pagePromptTextField setBackgroundColor:[NSColor controlColor]];
        [pagePromptTextField setBezeled:NO];
	[pagePromptTextField setEditable:NO];
	[pagePromptTextField setSelectable:NO];
	[horizontalWidgetsBox addSubview:pagePromptTextField];
	
        pageNumberTextField = [[NSTextField alloc] initWithFrame:textRect];
	[pageNumberTextField setFont:smallSystemFont];
	[pageNumberTextField setAlignment:NSCenterTextAlignment];
        [pageNumberTextField setBezeled:NO];
        [pageNumberTextField setBordered:YES];
	[pageNumberTextField setTarget:self];
	[pageNumberTextField setAction:@selector(gotoPage:)];
	[pageNumberTextField setNextResponder:delegate];
        [pageNumberTextField setRefusesFirstResponder:YES];
	[horizontalWidgetsBox addSubview:pageNumberTextField];

        pagesCountTextField = [[NSTextField alloc] initWithFrame:textRect];
	[pagesCountTextField setFont:smallSystemFont];
	[pagesCountTextField setAlignment:NSLeftTextAlignment];
        [pagesCountTextField setBackgroundColor:[NSColor controlColor]];
	[pagesCountTextField setBezeled:NO];
	[pagesCountTextField setEditable:NO];
	[pagesCountTextField setSelectable:NO];
	[horizontalWidgetsBox addSubview:pagesCountTextField];
    } else {
	[pagePromptTextField removeFromSuperview];
	[pagePromptTextField release];
	pagePromptTextField = nil;
	[pageNumberTextField removeFromSuperview];
	[pageNumberTextField release];
	pageNumberTextField = nil;
	[pagesCountTextField removeFromSuperview];
	[pagesCountTextField release];
	pagesCountTextField = nil;
    }

    [self tile];
}

- (void)setScrollBehavior:(ScrollingBehavior)behavior;
{
    scrollBehavior = behavior;
    switch (scrollBehavior) {
        case YES_SCROLL:
            [self setHasHorizontalScroller:YES];
            [self setHasVerticalScroller:YES];
            break;
        case NO_SCROLL:
            [self setHasHorizontalScroller:NO];
            [self setHasVerticalScroller:NO];
            break;
        case AUTO_SCROLL:
            break;
    }
}

- (void)showingPageNumber:(int)pageNumber of:(unsigned int)pagesCount;
{
    if (pageNumber < 0)
        [pageNumberTextField setStringValue:@""];
    else
        [pageNumberTextField setIntValue:pageNumber + 1];
    [pagesCountTextField setStringValue:[NSString stringWithFormat:@"of %d", pagesCount]];
    [pageNumberTextField setNextResponder:[self documentView]];
}

- (void)gotoPage:(id)sender;
{
    [delegate displayPageNumber:[sender intValue] - 1];
    [pageNumberTextField setNextResponder:[self documentView]];
}

// NSScrollView subclass

- (void)setDocumentView:(NSView *)aView
{
    if ([aView conformsToProtocol:@protocol(OAZoomableView)]) {
	unsigned int scaleIndex;

	/* create scale scalePopUpButton */
	scalePopUpButton = [[NSPopUpButton alloc] init];
	for (scaleIndex = 0; startingScales[scaleIndex] != 0; scaleIndex++) {
	    NSString *title;
	    NSMenuItem *scaleCell;

	    title = [NSString stringWithFormat:@"%d%%", startingScales[scaleIndex]];
	    [scalePopUpButton addItemWithTitle:title];
            scaleCell = [scalePopUpButton itemWithTitle:title];
	    [scaleCell setTag:startingScales[scaleIndex]];
	    [scaleCell setTarget:self];
	    [scaleCell setAction:@selector(zoomFromSender:)];
	}

	zoomFactor = 1.0;
	[scalePopUpButton selectItemWithTitle:@"100%"];
        [scalePopUpButton setRefusesFirstResponder:YES];
	[horizontalWidgetsBox addSubview:scalePopUpButton];
    } else {
	[scalePopUpButton removeFromSuperview];
	[scalePopUpButton release];
	scalePopUpButton = nil;
    }

    [super setDocumentView:aView];
    [self addOrRemoveScrollersIfNeeded];
}

- (void)tile;
{
    NSRect scrollerRect, widgetRect;
    NSRect widgetsAreaRect, widgetsBoxRect;
    BOOL hasMultiplePages;
    NSClipView *clipView;
    NSView *docView;

    if (flags.tiling)
        return;
    flags.tiling = YES;

    clipView = [self contentView];
    docView = [clipView documentView];

    if (scrollBehavior == AUTO_SCROLL)
        [self autoScrollTile];
    else
        [super tile];

    // Set up widgets in horizontal scroller
    hasMultiplePages = NSHeight([docView frame]) > [self contentSize].height || [delegate conformsToProtocol:@protocol(OAPageSelectableDocument)];
    if (![self hasHorizontalScroller]) {
        [horizontalWidgetsBox removeFromSuperview];
    } else {
        if (![horizontalWidgetsBox superview])
            [self addSubview:horizontalWidgetsBox];
        scrollerRect = [[self horizontalScroller] frame];
        widgetsBoxRect = scrollerRect;
        widgetsAreaRect = NSMakeRect(0, 0, scrollerRect.size.width, scrollerRect.size.height);

        if (scalePopUpButton) {
            NSDivideRect(widgetsAreaRect, &widgetRect, &widgetsAreaRect, 80.0, NSMinXEdge);
#ifndef RHAPSODY
            widgetRect = NSInsetRect(widgetRect, 1.0, 1.0);
#else
            widgetRect = NSInsetRect(widgetRect, 1.0, -1.0);
#endif
            [scalePopUpButton setFrame:widgetRect];
        }

        if (pagePromptTextField && hasMultiplePages) {
            NSDivideRect(widgetsAreaRect, &widgetRect, &widgetsAreaRect, 39, NSMinXEdge);
            widgetRect = NSInsetRect(widgetRect, 1.0, 0.0);
#ifndef RHAPSODY
            widgetRect.origin.y -= 3.0;
#else
            widgetRect.origin.y -= 1.0;
#endif
            [pagePromptTextField setFrame:widgetRect];

            NSDivideRect(widgetsAreaRect, &widgetRect, &widgetsAreaRect, 37, NSMinXEdge);
            widgetRect = NSInsetRect(widgetRect, 1.0, 0.0);
#ifndef RHAPSODY
            widgetRect.origin.y += 1.0;
            widgetRect.size.height -= 1.0;
#else
            widgetRect.origin.y -= 1.0;
            widgetRect.size.height += 2.0;
#endif
            [pageNumberTextField setFrame:widgetRect];

            NSDivideRect(widgetsAreaRect, &widgetRect, &widgetsAreaRect, 40, NSMinXEdge);
            widgetRect = NSInsetRect(widgetRect, 1.0, 0.0);
#ifndef RHAPSODY
            widgetRect.origin.y -= 3.0;
#else
            widgetRect.origin.y -= 1.0;
#endif
            [pagesCountTextField setFrame:widgetRect];
        }

        scrollerRect.size.width -= NSMinX(widgetsAreaRect);
        [[self horizontalScroller] setFrame:scrollerRect];

        widgetsBoxRect.size.width = NSMinX(widgetsAreaRect);
        widgetsBoxRect.origin.x = NSMaxX(scrollerRect);
        [horizontalWidgetsBox setFrame:widgetsBoxRect];
    }

    // Set up widgets in vertical scroller

    if (![self hasVerticalScroller] || !pageUpButton || !hasMultiplePages) {
        [pageDownButton removeFromSuperview];
        [pageUpButton removeFromSuperview];
    } else {
        NSSize widgetSize;

        widgetSize = NSMakeSize(16.0, 16.0);

        if (![pageUpButton superview])
            [self addSubview:pageUpButton];
        if (![pageDownButton superview])
            [self addSubview:pageDownButton];

        scrollerRect = [[self verticalScroller] frame];

        // lop off the size we want, plus a pixel for spacing below
        NSDivideRect(scrollerRect, &widgetRect, &scrollerRect, widgetSize.height + 1.0, NSMaxYEdge);
        widgetRect.size = widgetSize;
        widgetRect = NSOffsetRect(widgetRect, 1.0, 0.0);
        [pageDownButton setFrame:widgetRect];

        NSDivideRect(scrollerRect, &widgetRect, &scrollerRect, widgetSize.height + 1.0, NSMaxYEdge);
        widgetRect.size = widgetSize;
        widgetRect = NSOffsetRect(widgetRect, 1.0, 0.0);
        [pageUpButton setFrame:widgetRect];

        [[self verticalScroller] setFrame:scrollerRect];
    }

    [self setNeedsDisplay:YES];
    flags.tiling = NO;
}

- (void)reflectScrolledClipView:(NSClipView *)aClipView;
{
    [super reflectScrolledClipView:aClipView];
    [self addOrRemoveScrollersIfNeeded];
}

// NSResponder subclass

- (BOOL)acceptsFirstResponder;
{
    return YES;
}

- (void)keyDown:(NSEvent *)theEvent;
{
    if (pageNumberTextField) {
        NSString *characters;

        characters = [theEvent characters];
        if ([characters length] > 0) {
            unichar keyDownCharacter;

            keyDownCharacter = [[theEvent characters] characterAtIndex:0];
            if (keyDownCharacter >= '0' && keyDownCharacter <= '9') {
                [pageNumberTextField selectText:self];
                [[[self window] firstResponder] keyDown:theEvent];
                return;
            }
        }
    }

    [self processKeyDown:theEvent];

    while (YES) {
        // Peek at the next event
        theEvent = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:NO];
        // Break the loop if there is no next event
        if (!theEvent)
            break;
        // Skip over key-up events
        else if ([theEvent type] == NSKeyUp) {
            [super keyUp:[[self window] nextEventMatchingMask:NSKeyUpMask]];
            continue;
        }
        // Respond only to key-down events
        else if ([theEvent type] == NSKeyDown) {
            [self processKeyDown:theEvent];
            [[self window] nextEventMatchingMask:NSKeyDownMask];
        }
        // Break the loop on all other event types
        else
            break;
    }

    [self displayIfNeeded];
    PSWait();
}

// NSView subclass

- (BOOL)isOpaque;
{
    return YES;
}

- (void)drawRect:(NSRect)rect;
{
    NSRect aRect;
    BOOL somethingToDraw = NO;
    float border;

    switch ([self borderType]) {
    default:
    case NSNoBorder:
	border = 0.0;
        [[NSColor controlColor] set];
	NSRectFill(rect);
	break;
    case NSBezelBorder:
	border = 2.0;
	NSDrawDarkBezel([self bounds], rect);
	break;
    case NSLineBorder:
	border = 1.0;
        [[NSColor controlColor] set];
	NSRectFill(rect);
        [[NSColor controlDarkShadowColor] set];
	NSFrameRect([self bounds]);
	break;
    case NSGrooveBorder:
	border = 2.0;
	NSDrawGroove([self bounds], rect);
	break;
    }

    [super drawRect:rect];

    if ([self hasHorizontalScroller]) {
	aRect = [[self horizontalScroller] frame];
	if (!NSIsEmptyRect(NSIntersectionRect(aRect, rect))) {
	    somethingToDraw = YES;
	    PSmoveto(NSMinX(aRect) + border, NSMinY(aRect) - 1.0);
	    PSlineto(NSMaxX(aRect) - 2.0 * border, NSMinY(aRect) - 1.0);
	}
    }
    if ([self hasVerticalScroller]) {
	aRect = [[self verticalScroller] frame];
	if (!NSIsEmptyRect(NSIntersectionRect(aRect, rect))) {
	    somethingToDraw = YES;
#ifndef SCROLLERS_ON_RIGHT
            PSmoveto(NSMaxX(aRect) + 1.0, NSMinY(aRect) + border);
            PSlineto(NSMaxX(aRect) + 1.0, NSMaxY(aRect) - 2.0 * border);
#else
            PSmoveto(NSMinX(aRect) - 1.0, NSMinY(aRect) + border);
            PSlineto(NSMinX(aRect) - 1.0, NSMaxY(aRect) - 2.0 * border);
#endif
        }
    }
    if (somethingToDraw) {
        [[NSColor controlDarkShadowColor] set];
	PSstroke();
    }
}

@end

@implementation OAScrollView (Private)

enum {
    UnicharDeleteKey  = 0x007F,
    UnicharNonBreakingSpaceKey  = 0x00A0
};

- (void)processKeyDown:(NSEvent *)theEvent;
{
    int keyCode;

    [NSCursor setHiddenUntilMouseMoves:YES];
    keyCode = (int)[[theEvent characters] characterAtIndex:0];
    switch (keyCode) {
        case UnicharDeleteKey:
            // I don't think we need 128 anymore either
        case 128: // 128 (nonbreaking space) is what we get for Alt-Space
        case UnicharNonBreakingSpaceKey:
            [self scrollDownByPercentage:-0.9];
            break;
        case ' ':
            if (([theEvent modifierFlags] & NSAlternateKeyMask) ||
                ([theEvent modifierFlags] & NSShiftKeyMask))
                [self scrollDownByPercentage:-0.9];
            else
                [self scrollDownByPercentage:0.9];
            break;
        case 'u':
            [self scrollDownByPercentage:-0.4];
            break;
        case 'd':
            [self scrollDownByPercentage:0.4];
            break;
        case 'f':
            [self pageDown:self];
            break;
        case 'b':
            [self pageUp:self];
            break;
        case '[':
            [self zoomIn:self];
            break;
        case ']':
            [self zoomOut:self];
            break;
        default:
            [super keyDown:theEvent];
            break;
    }
}

- (void)scrollDownByPercentage:(float)percentage;
{
    NSRect beforeScrollVisibleRect, visibleRect;
    NSView *documentView;
    BOOL isScrollingDown = YES;

    documentView = [self documentView];
    isScrollingDown = ((percentage > 0.0) == YES);
    if (![documentView isFlipped])
        percentage = -percentage;
    beforeScrollVisibleRect = [self documentVisibleRect];
    visibleRect = beforeScrollVisibleRect;
    visibleRect.origin.y += percentage * NSHeight(visibleRect);
    [documentView scrollRectToVisible:visibleRect];

    if ([delegate conformsToProtocol:@protocol(OAPageSelectableDocument)]
        && NSEqualRects(beforeScrollVisibleRect, [self documentVisibleRect])) {
        NSWindow *documentWindow;
        NSRect bounds;

        documentWindow = [documentView window];
        [documentWindow disableFlushWindow];
        
        if (isScrollingDown) {
            [self pageDown:self];
        } else {
            [self pageUp:self];
        }
        bounds = [documentView bounds];
        if (isScrollingDown == ![documentView isFlipped]) {
            bounds.origin.y = NSHeight(bounds) - 1;
        } else {
            bounds.origin.y = 0;
        }
        bounds.size.height = 1;

        [documentView scrollRectToVisible:bounds];
        [documentWindow enableFlushWindow];
    }
}

- (void)pageUp:(id)sender;
{
    if ([delegate conformsToProtocol:@protocol(OAPageSelectableDocument)])
        [delegate pageUp];
    else
        [self scrollDownByPercentage:-0.9];
}

- (void)pageDown:(id)sender;
{
    if ([delegate conformsToProtocol:@protocol(OAPageSelectableDocument)])
        [delegate pageDown];
    else
        [self scrollDownByPercentage:0.9];
}

- (void)zoomIn:(id)sender;
{
    unsigned int zoomIndex;

    if (!scalePopUpButton)
        return;

    for (zoomIndex = 0; startingScales[zoomIndex] > 0; zoomIndex++) {
        if (zoomFactor * 100.0 < startingScales[zoomIndex]) {
            [scalePopUpButton selectItemWithTitle:[NSString stringWithFormat:@"%d%%", startingScales[zoomIndex]]];
            [self zoomToScale:startingScales[zoomIndex] / 100.0];
            break;
        }
    }
}

- (void)zoomOut:(id)sender;
{
    unsigned int zoomIndex;

    if (!scalePopUpButton)
        return;

    for (zoomIndex = 1; startingScales[zoomIndex] > 0; zoomIndex++) {
        if (zoomFactor * 100.0 <= startingScales[zoomIndex]) {
            [scalePopUpButton selectItemWithTitle:[NSString stringWithFormat:@"%d%%", startingScales[zoomIndex - 1]]];
            [self zoomToScale:startingScales[zoomIndex - 1] / 100.0];
            break;
        }
    }
}

- (void)addOrRemoveScrollersIfNeeded;
{
    if (scrollBehavior == AUTO_SCROLL) {
        NSRect docViewFrame;
        NSSize potentialContentSize;
        BOOL needsVerticalScroller, needsHorizontalScroller;

        docViewFrame = [[self documentView] frame];
        potentialContentSize = [self contentSizeForHorizontalScroller:NO verticalScroller:YES];
        needsVerticalScroller = NSHeight(docViewFrame) > potentialContentSize.height;
        if (!needsVerticalScroller) {
            potentialContentSize = [self contentSizeForHorizontalScroller:NO verticalScroller:NO];
        }
        needsHorizontalScroller = NSWidth(docViewFrame) > potentialContentSize.width;
        if ([self hasVerticalScroller] != needsVerticalScroller ||
            [self hasHorizontalScroller] != needsHorizontalScroller) {
            [self tile];
            [self setNeedsDisplayInRect:[self bounds]];
        }
    }
}

- (void)autoScrollTile;
{
    BOOL needsVerticalScroller, needsHorizontalScroller;
    NSClipView *clipView;
    NSView *docView;

    clipView = [self contentView];
    docView = [clipView documentView];

    if (!docView) {
        if ([self hasVerticalScroller])
            [self setHasVerticalScroller:NO];
        if ([self hasHorizontalScroller])
            [self setHasHorizontalScroller:NO];
        [super tile];
        return;
    }
    
    [super tile];

    needsVerticalScroller = NSHeight([docView frame]) > [self contentSizeForHorizontalScroller:NO verticalScroller:YES].height;
    if (needsVerticalScroller != [self hasVerticalScroller]) {
#if 0
        NSLog(@"%@ needsVerticalScroller? %.1f > %.1f = %d", OBShortObjectDescription(self), NSHeight([docView frame]), [self contentSizeForHorizontalScroller:NO verticalScroller:YES].height, needsVerticalScroller);
#endif
        [self setHasVerticalScroller:needsVerticalScroller];
        [super tile];
    }

    needsHorizontalScroller = NSWidth([docView frame]) > [self contentSize].width;
    if (needsHorizontalScroller != [self hasHorizontalScroller]) {
#if 0
        NSLog(@"%@ needsHorizontalScroller? %.1f > %.1f = %d", OBShortObjectDescription(self), NSWidth([docView frame]), [self contentSize].width, needsHorizontalScroller);
#endif
        [self setHasHorizontalScroller:needsHorizontalScroller];
        [super tile];
    }
}

- (NSSize)contentSizeForHorizontalScroller:(BOOL)hasHorizontalScroller verticalScroller:(BOOL)hasVerticalScroller;
{
    return [isa contentSizeForFrameSize:[self frame].size hasHorizontalScroller:hasHorizontalScroller hasVerticalScroller:hasVerticalScroller borderType:[self borderType]];
}

@end
