OverSight/MainApp/3rdParty/HyperlinkTextField.m

154 lines
5.0 KiB
Objective-C
Executable File

//
// HyperlinkTextField.m
// NSTextFieldHyperlinks
//
// Created by Toomas Vahter on 25.12.12.
// Copyright (c) 2012 Toomas Vahter. All rights reserved.
//
// This content is released under the MIT License (http://www.opensource.org/licenses/mit-license.php).
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "HyperlinkTextField.h"
@interface HyperlinkTextField ()
@property (nonatomic, readonly) NSArray *hyperlinkInfos;
@property (nonatomic, readonly) NSTextView *textView;
- (void)_resetHyperlinkCursorRects;
@end
#define kHyperlinkInfoCharacterRangeKey @"range"
#define kHyperlinkInfoURLKey @"url"
#define kHyperlinkInfoRectKey @"rect"
@implementation HyperlinkTextField
- (void)_hyperlinkTextFieldInit
{
[self setEditable:NO];
[self setSelectable:NO];
}
- (id)initWithFrame:(NSRect)frame
{
if ((self = [super initWithFrame:frame]))
{
[self _hyperlinkTextFieldInit];
}
return self;
}
- (id)initWithCoder:(NSCoder *)coder
{
if ((self = [super initWithCoder:coder]))
{
[self _hyperlinkTextFieldInit];
}
return self;
}
- (void)resetCursorRects
{
[super resetCursorRects];
[self _resetHyperlinkCursorRects];
}
- (void)_resetHyperlinkCursorRects
{
for (NSDictionary *info in self.hyperlinkInfos)
{
[self addCursorRect:[[info objectForKey:kHyperlinkInfoRectKey] rectValue] cursor:[NSCursor pointingHandCursor]];
}
}
#pragma mark -
#pragma mark Accessors
- (NSArray *)hyperlinkInfos
{
NSMutableArray *hyperlinkInfos = [[NSMutableArray alloc] init];
NSRange stringRange = NSMakeRange(0, [self.attributedStringValue length]);
__block NSTextView *textView = self.textView;
[self.attributedStringValue enumerateAttribute:NSLinkAttributeName inRange:stringRange options:0 usingBlock:^(id value, NSRange range, BOOL *stop)
{
if (value)
{
NSUInteger rectCount = 0;
NSRectArray rectArray = [textView.layoutManager rectArrayForCharacterRange:range withinSelectedCharacterRange:range inTextContainer:textView.textContainer rectCount:&rectCount];
for (NSUInteger i = 0; i < rectCount; i++)
{
[hyperlinkInfos addObject:@{kHyperlinkInfoCharacterRangeKey : [NSValue valueWithRange:range], kHyperlinkInfoURLKey : value, kHyperlinkInfoRectKey : [NSValue valueWithRect:rectArray[i]]}];
}
}
}];
return [hyperlinkInfos count] ? hyperlinkInfos : nil;
}
- (NSTextView *)textView
{
// Font used for displaying and frame calculations must match
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedStringValue];
NSFont *font = [attributedString attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL];
if (!font)
[attributedString addAttribute:NSFontAttributeName value:self.font range:NSMakeRange(0, [attributedString length])];
NSRect textViewFrame = [self.cell titleRectForBounds:self.bounds];
NSTextView *textView = [[NSTextView alloc] initWithFrame:textViewFrame];
[textView.textStorage setAttributedString:attributedString];
return textView;
}
#pragma mark -
#pragma mark Mouse Events
- (void)mouseUp:(NSEvent *)theEvent
{
NSTextView *textView = self.textView;
NSPoint localPoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
NSUInteger index = [textView.layoutManager characterIndexForPoint:localPoint inTextContainer:textView.textContainer fractionOfDistanceBetweenInsertionPoints:NULL];
if (index != NSNotFound)
{
for (NSDictionary *info in self.hyperlinkInfos)
{
NSRange range = [[info objectForKey:kHyperlinkInfoCharacterRangeKey] rangeValue];
if (NSLocationInRange(index, range))
{
NSURL *url = [info objectForKey:kHyperlinkInfoURLKey];
[[NSWorkspace sharedWorkspace] openURL:url];
}
}
}
}
@end