WKPagePreviewViewController.mm   [plain text]


/*
 * Copyright (C) 2014 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

#import "config.h"
#import "WKPagePreviewViewController.h"

#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000

static const CGFloat previewViewInset = 3;
static const CGFloat previewViewTitleHeight = 34;

@implementation WKPagePreviewViewController

- (instancetype)initWithPageURL:(NSURL *)URL mainViewSize:(NSSize)size popoverToViewScale:(CGFloat)scale
{
    if (!(self = [super init]))
        return nil;

    _url = URL;
    _mainViewSize = size;
    _popoverToViewScale = scale;

    return self;
}

- (NSString *)previewTitle
{
    return _previewTitle.get();
}

- (void)setPreviewTitle:(NSString *)previewTitle
{
    if ([_previewTitle isEqualToString:previewTitle])
        return;

    // Keep a separate copy around in case this is received before the view hierarchy is created.
    _previewTitle = adoptNS([previewTitle copy]);
    [_titleTextField setStringValue:previewTitle ? previewTitle : @""];
}

+ (NSSize)previewPadding
{
    return NSMakeSize(2 * previewViewInset, previewViewTitleHeight + 2 * previewViewInset);
}

- (void)setLoading:(BOOL)loading
{
    if (_loading == loading)
        return;

    _loading = loading;

    [_previewView setHidden:loading];

    if (_loading)
        [_spinner startAnimation:nil];
    else
        [_spinner stopAnimation:nil];
}

- (BOOL)isLoading
{
    return _loading;
}

- (void)loadView
{
    NSRect defaultFrame = NSMakeRect(0, 0, _mainViewSize.width, _mainViewSize.height);
    _previewView = [_delegate pagePreviewViewController:self viewForPreviewingURL:_url.get() initialFrameSize:defaultFrame.size];
    ASSERT(_previewView);

    RetainPtr<NSClickGestureRecognizer> clickRecognizer = adoptNS([[NSClickGestureRecognizer alloc] initWithTarget:self action:@selector(_clickRecognized:)]);
    [_previewView addGestureRecognizer:clickRecognizer.get()];

    NSRect previewFrame = [_previewView frame];
    NSRect containerFrame = previewFrame;
    NSSize totalPadding = [[self class] previewPadding];
    containerFrame.size.width += totalPadding.width;
    containerFrame.size.height += totalPadding.height;
    previewFrame = NSOffsetRect(previewFrame, previewViewInset, previewViewInset);

    RetainPtr<NSView> containerView = adoptNS([[NSView alloc] initWithFrame:containerFrame]);
    [containerView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
    [containerView addSubview:_previewView.get()];
    [_previewView setFrame:previewFrame];
    [_previewView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
    [_previewView setHidden:YES];

    _titleTextField = adoptNS([[NSTextField alloc] init]);
    [_titleTextField setWantsLayer:YES];
    [_titleTextField setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin];
    [_titleTextField setEditable:NO];
    [_titleTextField setBezeled:NO];
    [_titleTextField setDrawsBackground:NO];
    [_titleTextField setAlignment:NSCenterTextAlignment];
    [_titleTextField setUsesSingleLineMode:YES];
    [_titleTextField setLineBreakMode:NSLineBreakByTruncatingTail];
    [_titleTextField setTextColor:[NSColor labelColor]];

    NSString *title = _previewTitle.get();
    if (!title)
        title = [_delegate pagePreviewViewController:self titleForPreviewOfURL:_url.get()];
    if (!title)
        title = [_url absoluteString];

    [_titleTextField setStringValue:title ? title : @""];

    [_titleTextField sizeToFit];
    NSSize titleFittingSize = [_titleTextField frame].size;
    CGFloat textFieldCenteringOffset = (NSMaxY(containerFrame) - NSMaxY(previewFrame) - titleFittingSize.height) / 2;

    NSRect titleFrame = previewFrame;
    titleFrame.size.height = titleFittingSize.height;
    titleFrame.origin.y = NSMaxY(previewFrame) + textFieldCenteringOffset;
    [_titleTextField setFrame:titleFrame];
    [containerView addSubview:_titleTextField.get()];

    NSSize spinnerSize = NSMakeSize(48, 48);
    NSRect spinnerFrame = NSMakeRect(NSMidX(containerFrame), NSMidY(containerFrame), 0, 0);
    spinnerFrame = NSInsetRect(spinnerFrame, -spinnerSize.width * 0.5, -spinnerSize.height * 0.5);
    spinnerFrame.origin.x = floor(spinnerFrame.origin.x);
    spinnerFrame.origin.y = floor(spinnerFrame.origin.y);

    _spinner = adoptNS([[NSProgressIndicator alloc] initWithFrame:spinnerFrame]);
    [_spinner setStyle:NSProgressIndicatorSpinningStyle];
    [_spinner setDisplayedWhenStopped:NO];
    [_spinner setAutoresizingMask:NSViewMinXMargin | NSViewMaxXMargin | NSViewMinYMargin | NSViewMaxYMargin];
    [_spinner setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameAqua]];
    if (_loading)
        [_spinner startAnimation:nil];

    [containerView addSubview:_spinner.get()];

    // Setting the webView bounds will scale it to 75% of the _mainViewSize.
    [_previewView setBounds:NSMakeRect(0, 0, _mainViewSize.width / _popoverToViewScale, _mainViewSize.height / _popoverToViewScale)];

    self.view = containerView.get();
}

- (void)replacePreviewWithImage:(NSImage *)image atSize:(NSSize)size
{
    RetainPtr<NSClickGestureRecognizer> clickRecognizer = adoptNS([[NSClickGestureRecognizer alloc] initWithTarget:self action:@selector(_clickRecognized:)]);
    RetainPtr<NSImageView> imageView = adoptNS([[NSImageView alloc] initWithFrame:NSMakeRect(0, 0, size.width, size.height)]);
    [imageView setImage:image];
    [imageView addGestureRecognizer:clickRecognizer.get()];
    self.view = imageView.get();
}

- (void)_clickRecognized:(NSGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer.state == NSGestureRecognizerStateBegan)
        [_delegate pagePreviewViewControllerWasClicked:self];
}

@end

#endif // PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000