154 lines
5.0 KiB
Objective-C
Executable File
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
|