Home | History | Annotate | Download | only in cocoa
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #import "chrome/browser/ui/cocoa/hyperlink_text_view.h"
      6 
      7 #include "base/mac/scoped_nsobject.h"
      8 
      9 // The baseline shift for text in the NSTextView.
     10 const float kTextBaselineShift = -1.0;
     11 
     12 @interface HyperlinkTextView(Private)
     13 // Initialize the NSTextView properties for this subclass.
     14 - (void)configureTextView;
     15 
     16 // Change the current IBeamCursor to an arrowCursor.
     17 - (void)fixupCursor;
     18 @end
     19 
     20 @implementation HyperlinkTextView
     21 
     22 - (id)initWithCoder:(NSCoder*)decoder {
     23   if ((self = [super initWithCoder:decoder]))
     24     [self configureTextView];
     25   return self;
     26 }
     27 
     28 - (id)initWithFrame:(NSRect)frameRect {
     29   if ((self = [super initWithFrame:frameRect]))
     30     [self configureTextView];
     31   return self;
     32 }
     33 
     34 // Never draw the insertion point (otherwise, it shows up without any user
     35 // action if full keyboard accessibility is enabled).
     36 - (BOOL)shouldDrawInsertionPoint {
     37   return NO;
     38 }
     39 
     40 - (NSRange)selectionRangeForProposedRange:(NSRange)proposedSelRange
     41                               granularity:(NSSelectionGranularity)granularity {
     42   // Do not allow selections.
     43   return NSMakeRange(0, 0);
     44 }
     45 
     46 // Convince NSTextView to not show an I-Beam cursor when the cursor is over the
     47 // text view but not over actual text.
     48 //
     49 // http://www.mail-archive.com/cocoa-dev@lists.apple.com/msg10791.html
     50 // "NSTextView sets the cursor over itself dynamically, based on considerations
     51 // including the text under the cursor. It does so in -mouseEntered:,
     52 // -mouseMoved:, and -cursorUpdate:, so those would be points to consider
     53 // overriding."
     54 - (void)mouseMoved:(NSEvent*)e {
     55   [super mouseMoved:e];
     56   [self fixupCursor];
     57 }
     58 
     59 - (void)mouseEntered:(NSEvent*)e {
     60   [super mouseEntered:e];
     61   [self fixupCursor];
     62 }
     63 
     64 - (void)cursorUpdate:(NSEvent*)e {
     65   [super cursorUpdate:e];
     66   [self fixupCursor];
     67 }
     68 
     69 - (void)configureTextView {
     70   [self setEditable:NO];
     71   [self setDrawsBackground:NO];
     72   [self setHorizontallyResizable:NO];
     73   [self setVerticallyResizable:NO];
     74 
     75   // When text is rendered, linkTextAttributes override anything set via
     76   // addAttributes for text that has NSLinkAttributeName. Set to nil to allow
     77   // custom attributes to take precendence.
     78   [self setLinkTextAttributes:nil];
     79 }
     80 
     81 - (void)fixupCursor {
     82   if ([[NSCursor currentCursor] isEqual:[NSCursor IBeamCursor]])
     83     [[NSCursor arrowCursor] set];
     84 }
     85 
     86 - (void)setMessageAndLink:(NSString*)message
     87                  withLink:(NSString*)link
     88                  atOffset:(NSUInteger)linkOffset
     89                      font:(NSFont*)font
     90              messageColor:(NSColor*)messageColor
     91                 linkColor:(NSColor*)linkColor {
     92   NSMutableString* finalMessage = [NSMutableString stringWithString:message];
     93   [finalMessage insertString:link atIndex:linkOffset];
     94   [self setMessage:finalMessage withFont:font messageColor:messageColor];
     95   if ([link length] != 0) {
     96     [self addLinkRange:NSMakeRange(linkOffset, [link length])
     97               withName:@""
     98              linkColor:linkColor];
     99   }
    100 }
    101 
    102 - (void)setMessage:(NSString*)message
    103           withFont:(NSFont*)font
    104       messageColor:(NSColor*)messageColor {
    105   // Create an attributes dictionary for the message and link.
    106   NSDictionary* attributes = @{
    107     NSForegroundColorAttributeName : messageColor,
    108     NSCursorAttributeName : [NSCursor arrowCursor],
    109     NSFontAttributeName : font,
    110     NSBaselineOffsetAttributeName : @(kTextBaselineShift)
    111   };
    112 
    113   // Create the attributed string for the message.
    114   base::scoped_nsobject<NSAttributedString> attributedMessage(
    115       [[NSMutableAttributedString alloc] initWithString:message
    116                                              attributes:attributes]);
    117 
    118   // Update the text view with the new text.
    119   [[self textStorage] setAttributedString:attributedMessage];
    120 }
    121 
    122 - (void)addLinkRange:(NSRange)range
    123             withName:(id)name
    124            linkColor:(NSColor*)linkColor {
    125   NSDictionary* attributes = @{
    126     NSForegroundColorAttributeName : linkColor,
    127     NSUnderlineStyleAttributeName : @(YES),
    128     NSCursorAttributeName : [NSCursor pointingHandCursor],
    129     NSLinkAttributeName : name,
    130     NSUnderlineStyleAttributeName : @(NSSingleUnderlineStyle)
    131   };
    132 
    133   [[self textStorage] addAttributes:attributes range:range];
    134 }
    135 
    136 @end
    137