Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get NSTextFinder to show up

I have a mac cocoa app with a webview that contains some text. I would like to search through that text using the default find bar provided by NSTextFinder. As easy as this may seem reading through the NSTextFinder class reference, I cannot get the find bar to show up. What am I missing?

As a sidenote:
- Yes, I tried setting findBarContainer to a different view, same thing. I reverted back to the scroll view to eliminate complexity in debugging
- performTextFinderAction is called to perform the find operation

**App Delegate:**

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{

    self.textFinderController = [[NSTextFinder alloc] init];

    self.webView = [[STEWebView alloc] initWithFrame:CGRectMake(0, 0,  self.window.frame.size.width, 200)];
    [[self.window contentView] addSubview:self.webView];

    [self.textFinderController setClient:self.webView];
    [self.textFinderController setFindBarContainer:self.webView.enclosingScrollView];


    [[self.webView mainFrame] loadHTMLString:@"sample string" baseURL:NULL];

}

- (IBAction)performTextFinderAction:(id)sender {
    [self.textFinderController performAction:[sender tag]];
}

**STEWebView**

@interface STEWebView : WebView <NSTextFinderClient>

@end


@implementation STEWebView

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {

    }

    return self;
}

- (void)drawRect:(NSRect)dirtyRect
{
    // Drawing code here.
}


- (NSUInteger) stringLength {
    return [[self stringByEvaluatingJavaScriptFromString:@"document.documentElement.textContent"] length];
}

- (NSString *)string {
    return [self stringByEvaluatingJavaScriptFromString:@"document.documentElement.textContent"];
}
like image 468
Lukasz Avatar asked May 07 '12 22:05

Lukasz


3 Answers

In my tests, WebView.enclosingScrollView was null.

// [self.textFinderController setFindBarContainer:self.webView.enclosingScrollView];
NSLog(@"%@", self.webView.enclosingScrollView);

Using the following category on NSView, it is possible to find the nested subview that extends NSScrollView, and set that as the container, allowing the NSTextFinder to display beautifully within a WebView

@interface NSView (ScrollView)

- (NSScrollView *) scrollView;

@end

@implementation NSView (ScrollView)

- (NSScrollView *) scrollView {
    if ([self isKindOfClass:[NSScrollView class]]) {
        return (NSScrollView *)self;
    }

    if ([self.subviews count] == 0) {
        return nil;
    }

    for (NSView *subview in self.subviews) {
        NSView *scrollView = [subview scrollView];
        if (scrollView != nil) {
            return (NSScrollView *)scrollView;
        }
    }
    return nil;
}

@end

And in your applicationDidFinishLaunching:aNotification:

[self.textFinderController setFindBarContainer:[self scrollView]];
like image 171
Michael Robinson Avatar answered Nov 11 '22 14:11

Michael Robinson


To get the Find Bar to appear (as opposed to the default Find Panel), you simply have to use the setUsesFindBar: method.

In your case, you'll want to do (in your applicationDidFinishLaunching:aNotification method):

[textFinderController setUsesFindBar:YES];
//Optionally, incremental searching is a nice feature
[textFinderController setIncrementalSearchingEnabled:YES];
like image 22
varkor Avatar answered Nov 11 '22 12:11

varkor


Finally got this to show up.

First set your NSTextFinder instances' client to a class implementing the <NSTextFinderClient> protocol:

self.textFinder.client = self.textFinderController;

Next, make sure your NSTextFinder has a findBarContainer set to the webView category described by Michael Robinson, or get the scrollview within the webView yourself:

self.textFinder.findBarContainer = [self.webView scrollView];

Set the find bar position above the content (or wherever you wish):

[self.webView scrollView].findBarPosition = NSScrollViewFindBarPositionAboveContent;

Finally, tell it to show up:

[self.textFinder performAction:NSTextFinderActionShowFindInterface];

It should show up in your webView:

Also, not sure if it makes a difference, but I have the NSTextFinder in the XIB, with a referencing outlet:

@property (strong) IBOutlet NSTextFinder *textFinder;

You may also be able to get it by simply initing it like normal: self.textFinder = [[NSTextFinder alloc] init];

like image 31
Joel Fischer Avatar answered Nov 11 '22 12:11

Joel Fischer