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