зеркало из https://github.com/mozilla/pjs.git
Register for undo/redo notifications so we can hide the suggestions
list. Fixes the urlbar font size. (bug 159606)
This commit is contained in:
Родитель
9069418c32
Коммит
640d1ca539
|
@ -1,92 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
||||||
*
|
|
||||||
* The contents of this file are subject to the Mozilla Public
|
|
||||||
* License Version 1.1 (the "License"); you may not use this file
|
|
||||||
* except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at http://www.mozilla.org/MPL/
|
|
||||||
*
|
|
||||||
* Software distributed under the License is distributed on an "AS
|
|
||||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
||||||
* implied. See the License for the specific language governing
|
|
||||||
* rights and limitations under the License.
|
|
||||||
*
|
|
||||||
* The Original Code is the Mozilla browser.
|
|
||||||
*
|
|
||||||
* The Initial Developer of the Original Code is Netscape
|
|
||||||
* Communications Corporation. Portions created by Netscape are
|
|
||||||
* Copyright (C) 2002 Netscape Communications Corporation. All
|
|
||||||
* Rights Reserved.
|
|
||||||
*
|
|
||||||
* Contributor(s):
|
|
||||||
* Joe Hewitt <hewitt@netscape.com> (Original Author)
|
|
||||||
* David Haas <haasd@cae.wisc.edu>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <AppKit/AppKit.h>
|
|
||||||
#import "CHAutoCompleteDataSource.h"
|
|
||||||
#include "nsIAutoCompleteSession.h"
|
|
||||||
#include "nsIAutoCompleteResults.h"
|
|
||||||
#include "nsIAutoCompleteListener.h"
|
|
||||||
|
|
||||||
@class CHAutoCompleteDataSource, CHPageProxyIcon;
|
|
||||||
|
|
||||||
@interface CHAutoCompleteTextField : NSTextField
|
|
||||||
{
|
|
||||||
IBOutlet CHPageProxyIcon *mProxyIcon;
|
|
||||||
NSWindow *mPopupWin;
|
|
||||||
NSTableView *mTableView;
|
|
||||||
|
|
||||||
CHAutoCompleteDataSource *mDataSource;
|
|
||||||
|
|
||||||
nsIAutoCompleteSession *mSession;
|
|
||||||
nsIAutoCompleteResults *mResults;
|
|
||||||
nsIAutoCompleteListener *mListener;
|
|
||||||
|
|
||||||
NSString *mSearchString;
|
|
||||||
|
|
||||||
// used to remember if backspace was pressed in complete: so we can check this in controlTextDidChange
|
|
||||||
BOOL mBackspaced;
|
|
||||||
// determines if the search currently pending should complete the default result when it is ready
|
|
||||||
BOOL mCompleteResult;
|
|
||||||
// should the autocomplete fill in the default completion into the text field? The default
|
|
||||||
// is no, but this can be set with a user default pref.
|
|
||||||
BOOL mCompleteWhileTyping;
|
|
||||||
|
|
||||||
NSTimer *mOpenTimer;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) setSession:(NSString *)aSession;
|
|
||||||
- (NSString *) session;
|
|
||||||
- (void) setPageProxyIcon:(NSImage *)aImage;
|
|
||||||
|
|
||||||
- (NSTableView *) tableView;
|
|
||||||
- (int) visibleRows;
|
|
||||||
|
|
||||||
- (void) startSearch:(NSString*)aString complete:(BOOL)aComplete;
|
|
||||||
- (void) performSearch;
|
|
||||||
- (void) dataReady:(nsIAutoCompleteResults*)aResults status:(AutoCompleteStatus)aStatus;
|
|
||||||
- (void) searchTimer:(NSTimer *)aTimer;
|
|
||||||
- (void) clearResults;
|
|
||||||
|
|
||||||
- (void) completeDefaultResult;
|
|
||||||
- (void) completeSelectedResult;
|
|
||||||
- (void) completeResult:(int)aRow;
|
|
||||||
- (void) enterResult:(int)aRow;
|
|
||||||
- (void) revertText;
|
|
||||||
|
|
||||||
- (void) selectRowAt:(int)aRow;
|
|
||||||
- (void) selectRowBy:(int)aRows;
|
|
||||||
|
|
||||||
- (void) openPopup;
|
|
||||||
- (void) closePopup;
|
|
||||||
- (void) resizePopup;
|
|
||||||
- (BOOL) isOpen;
|
|
||||||
|
|
||||||
- (void) onRowClicked:(NSNotification *)aNote;
|
|
||||||
- (void) onBlur:(NSNotification *)aNote;
|
|
||||||
- (void) onResize:(NSNotification *)aNote;
|
|
||||||
|
|
||||||
- (void) setStringUndoably:(NSString*)aString fromLocation:(unsigned int)aLocation;
|
|
||||||
- (id) fieldEditor;
|
|
||||||
|
|
||||||
@end
|
|
|
@ -1,574 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
||||||
*
|
|
||||||
* The contents of this file are subject to the Mozilla Public
|
|
||||||
* License Version 1.1 (the "License"); you may not use this file
|
|
||||||
* except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at http://www.mozilla.org/MPL/
|
|
||||||
*
|
|
||||||
* Software distributed under the License is distributed on an "AS
|
|
||||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
||||||
* implied. See the License for the specific language governing
|
|
||||||
* rights and limitations under the License.
|
|
||||||
*
|
|
||||||
* The Original Code is the Mozilla browser.
|
|
||||||
*
|
|
||||||
* The Initial Developer of the Original Code is Netscape
|
|
||||||
* Communications Corporation. Portions created by Netscape are
|
|
||||||
* Copyright (C) 2002 Netscape Communications Corporation. All
|
|
||||||
* Rights Reserved.
|
|
||||||
*
|
|
||||||
* Contributor(s):
|
|
||||||
* Joe Hewitt <hewitt@netscape.com> (Original Author)
|
|
||||||
* David Haas <haasd@cae.wisc.edu>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "CHAutoCompleteTextField.h"
|
|
||||||
#import "BrowserWindowController.h"
|
|
||||||
#import "CHPageProxyIcon.h"
|
|
||||||
#include "nsIServiceManager.h"
|
|
||||||
#include "nsMemory.h"
|
|
||||||
#include "nsString.h"
|
|
||||||
#include "CHUserDefaults.h"
|
|
||||||
|
|
||||||
static const int kMaxRows = 6;
|
|
||||||
static const int kFrameMargin = 1;
|
|
||||||
|
|
||||||
@interface AutoCompleteWindow : NSWindow
|
|
||||||
- (BOOL)isKeyWindow;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation AutoCompleteWindow
|
|
||||||
- (BOOL)isKeyWindow
|
|
||||||
{
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
class AutoCompleteListener : public nsIAutoCompleteListener
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AutoCompleteListener(CHAutoCompleteTextField* aTextField)
|
|
||||||
{
|
|
||||||
NS_INIT_REFCNT();
|
|
||||||
mTextField = aTextField;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
|
||||||
|
|
||||||
NS_IMETHODIMP OnStatus(const PRUnichar* aText) { return NS_OK; }
|
|
||||||
NS_IMETHODIMP SetParam(nsISupports *aParam) { return NS_OK; }
|
|
||||||
NS_IMETHODIMP GetParam(nsISupports **aParam) { return NS_OK; }
|
|
||||||
|
|
||||||
NS_IMETHODIMP OnAutoComplete(nsIAutoCompleteResults *aResults, AutoCompleteStatus aStatus)
|
|
||||||
{
|
|
||||||
[mTextField dataReady:aResults status:aStatus];
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
CHAutoCompleteTextField *mTextField;
|
|
||||||
};
|
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener)
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@implementation CHAutoCompleteTextField
|
|
||||||
|
|
||||||
- (void) awakeFromNib
|
|
||||||
{
|
|
||||||
NSTableColumn *column;
|
|
||||||
NSScrollView *scrollView;
|
|
||||||
NSCell *dataCell;
|
|
||||||
|
|
||||||
mSearchString = nil;
|
|
||||||
mBackspaced = NO;
|
|
||||||
mCompleteResult = NO;
|
|
||||||
mOpenTimer = nil;
|
|
||||||
|
|
||||||
mSession = nsnull;
|
|
||||||
mResults = nsnull;
|
|
||||||
mListener = (nsIAutoCompleteListener *)new AutoCompleteListener(self);
|
|
||||||
NS_IF_ADDREF(mListener);
|
|
||||||
|
|
||||||
[self setDelegate: self];
|
|
||||||
|
|
||||||
// XXX the owner of the textfield should set this
|
|
||||||
[self setSession:@"history"];
|
|
||||||
|
|
||||||
// construct and configure the popup window
|
|
||||||
mPopupWin = [[AutoCompleteWindow alloc] initWithContentRect:NSMakeRect(0,0,0,0)
|
|
||||||
styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
|
|
||||||
[mPopupWin setReleasedWhenClosed:NO];
|
|
||||||
[mPopupWin setLevel:NSFloatingWindowLevel];
|
|
||||||
[mPopupWin setHasShadow:YES];
|
|
||||||
[mPopupWin setAlphaValue:0.9];
|
|
||||||
|
|
||||||
// construct and configure the view
|
|
||||||
mTableView = [[[NSTableView alloc] initWithFrame:NSMakeRect(0,0,0,0)] autorelease];
|
|
||||||
[mTableView setIntercellSpacing:NSMakeSize(1, 2)];
|
|
||||||
[mTableView setTarget:self];
|
|
||||||
[mTableView setAction:@selector(onRowClicked:)];
|
|
||||||
|
|
||||||
// Create the icon column if we have a proxy icon
|
|
||||||
if (mProxyIcon) {
|
|
||||||
column = [[[NSTableColumn alloc] initWithIdentifier:@"icon"] autorelease];
|
|
||||||
[column setWidth:[mProxyIcon frame].origin.x + [mProxyIcon frame].size.width];
|
|
||||||
dataCell = [[[NSImageCell alloc] initImageCell:nil] autorelease];
|
|
||||||
[column setDataCell:dataCell];
|
|
||||||
[mTableView addTableColumn: column];
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the text columns
|
|
||||||
column = [[[NSTableColumn alloc] initWithIdentifier:@"col1"] autorelease];
|
|
||||||
[mTableView addTableColumn: column];
|
|
||||||
column = [[[NSTableColumn alloc] initWithIdentifier:@"col2"] autorelease];
|
|
||||||
[[column dataCell] setTextColor:[NSColor darkGrayColor]];
|
|
||||||
[mTableView addTableColumn: column];
|
|
||||||
|
|
||||||
// hide the table header
|
|
||||||
[mTableView setHeaderView:nil];
|
|
||||||
|
|
||||||
// construct the scroll view that contains the table view
|
|
||||||
scrollView = [[[NSScrollView alloc] initWithFrame:NSMakeRect(0,0,0,0)] autorelease];
|
|
||||||
[scrollView setHasVerticalScroller:YES];
|
|
||||||
[[scrollView verticalScroller] setControlSize:NSSmallControlSize];
|
|
||||||
[scrollView setDocumentView: mTableView];
|
|
||||||
|
|
||||||
// construct the datasource
|
|
||||||
mDataSource = [[CHAutoCompleteDataSource alloc] init];
|
|
||||||
[mTableView setDataSource: mDataSource];
|
|
||||||
|
|
||||||
[mPopupWin setContentView:scrollView];
|
|
||||||
|
|
||||||
// listen for when window resigns from key handling
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onBlur:)
|
|
||||||
name:NSWindowDidResignKeyNotification object:nil];
|
|
||||||
|
|
||||||
// listen for when window is about to be moved or resized
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onBlur:)
|
|
||||||
name:NSWindowWillMoveNotification object:nil];
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResize:)
|
|
||||||
name:NSWindowDidResizeNotification object:nil];
|
|
||||||
|
|
||||||
// read the user default on if we should auto-complete the text field as the user
|
|
||||||
// types or make them pick something from a list (a-la mozilla).
|
|
||||||
mCompleteWhileTyping = [[NSUserDefaults standardUserDefaults] boolForKey:USER_DEFAULTS_AUTOCOMPLETE_WHILE_TYPING];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) dealloc
|
|
||||||
{
|
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
||||||
|
|
||||||
if (mSearchString)
|
|
||||||
[mSearchString release];
|
|
||||||
|
|
||||||
[mPopupWin release];
|
|
||||||
[mDataSource release];
|
|
||||||
|
|
||||||
NS_IF_RELEASE(mSession);
|
|
||||||
NS_IF_RELEASE(mResults);
|
|
||||||
NS_IF_RELEASE(mListener);
|
|
||||||
|
|
||||||
[super dealloc];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) setSession:(NSString *)aSession
|
|
||||||
{
|
|
||||||
NS_IF_RELEASE(mSession);
|
|
||||||
|
|
||||||
// XXX add aSession to contract id
|
|
||||||
nsCOMPtr<nsIAutoCompleteSession> session =
|
|
||||||
do_GetService("@mozilla.org/autocompleteSession;1?type=history");
|
|
||||||
mSession = session;
|
|
||||||
NS_IF_ADDREF(mSession);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *) session
|
|
||||||
{
|
|
||||||
// XXX return session name
|
|
||||||
return @"";
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSTableView *) tableView
|
|
||||||
{
|
|
||||||
return mTableView;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (int) visibleRows
|
|
||||||
{
|
|
||||||
int minRows = [mDataSource rowCount];
|
|
||||||
return minRows < kMaxRows ? minRows : kMaxRows;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) setPageProxyIcon:(NSImage *)aImage
|
|
||||||
{
|
|
||||||
[mProxyIcon setImage:aImage];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(id) fieldEditor
|
|
||||||
{
|
|
||||||
return [[self window] fieldEditor:NO forObject:self];
|
|
||||||
}
|
|
||||||
// searching ////////////////////////////
|
|
||||||
|
|
||||||
- (void) startSearch:(NSString*)aString complete:(BOOL)aComplete
|
|
||||||
{
|
|
||||||
if (mSearchString)
|
|
||||||
[mSearchString release];
|
|
||||||
mSearchString = [aString retain];
|
|
||||||
|
|
||||||
mCompleteResult = aComplete;
|
|
||||||
|
|
||||||
if ([self isOpen]) {
|
|
||||||
[self performSearch];
|
|
||||||
} else {
|
|
||||||
// delay the search when the popup is not yet opened so that users
|
|
||||||
// don't see a jerky flashing popup when they start typing for the first time
|
|
||||||
if (mOpenTimer) {
|
|
||||||
[mOpenTimer invalidate];
|
|
||||||
[mOpenTimer release];
|
|
||||||
}
|
|
||||||
|
|
||||||
mOpenTimer = [[NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(searchTimer:)
|
|
||||||
userInfo:nil repeats:NO] retain];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) performSearch
|
|
||||||
{
|
|
||||||
PRUnichar* chars = nsMemory::Alloc(([mSearchString length]+1) * sizeof(PRUnichar));
|
|
||||||
[mSearchString getCharacters:chars];
|
|
||||||
chars[[mSearchString length]] = 0; // I shouldn't have to do this
|
|
||||||
nsresult rv = mSession->OnStartLookup(chars, mResults, mListener);
|
|
||||||
nsMemory::Free(chars);
|
|
||||||
|
|
||||||
if (NS_FAILED(rv))
|
|
||||||
NSLog(@"Unable to perform autocomplete lookup");
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) dataReady:(nsIAutoCompleteResults*)aResults status:(AutoCompleteStatus)aStatus
|
|
||||||
{
|
|
||||||
NS_IF_RELEASE(mResults);
|
|
||||||
mResults = nsnull;
|
|
||||||
|
|
||||||
if (aStatus == nsIAutoCompleteStatus::failed) {
|
|
||||||
[mDataSource setErrorMessage:@""];
|
|
||||||
} else if (aStatus == nsIAutoCompleteStatus::ignored) {
|
|
||||||
[mDataSource setErrorMessage:@""];
|
|
||||||
} else if (aStatus == nsIAutoCompleteStatus::noMatch) {
|
|
||||||
[mDataSource setErrorMessage:@""];
|
|
||||||
} else if (aStatus == nsIAutoCompleteStatus::matchFound) {
|
|
||||||
mResults = aResults;
|
|
||||||
NS_IF_ADDREF(mResults);
|
|
||||||
[mDataSource setResults:aResults];
|
|
||||||
[self completeDefaultResult];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([mDataSource rowCount] > 0) {
|
|
||||||
[mTableView noteNumberOfRowsChanged];
|
|
||||||
[self openPopup];
|
|
||||||
} else {
|
|
||||||
[self closePopup];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) searchTimer:(NSTimer *)aTimer
|
|
||||||
{
|
|
||||||
[mOpenTimer release];
|
|
||||||
mOpenTimer = nil;
|
|
||||||
|
|
||||||
[self performSearch];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) clearResults
|
|
||||||
{
|
|
||||||
// clear out search data
|
|
||||||
if (mSearchString)
|
|
||||||
[mSearchString release];
|
|
||||||
mSearchString = nil;
|
|
||||||
NS_IF_RELEASE(mResults);
|
|
||||||
mResults = nsnull;
|
|
||||||
|
|
||||||
[mDataSource setResults:nil];
|
|
||||||
|
|
||||||
[self closePopup];
|
|
||||||
}
|
|
||||||
|
|
||||||
// handling the popup /////////////////////////////////
|
|
||||||
|
|
||||||
- (void) openPopup
|
|
||||||
{
|
|
||||||
[self resizePopup];
|
|
||||||
|
|
||||||
// show the popup
|
|
||||||
if ([mPopupWin isVisible] == NO)
|
|
||||||
[mPopupWin orderFront:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) resizePopup
|
|
||||||
{
|
|
||||||
NSRect locationFrame, winFrame;
|
|
||||||
NSPoint locationOrigin;
|
|
||||||
int tableHeight;
|
|
||||||
|
|
||||||
if ([self visibleRows] == 0) {
|
|
||||||
[self closePopup];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the origin of the location bar in coordinates of the root view
|
|
||||||
locationFrame = [[self superview] frame];
|
|
||||||
locationOrigin = [[[self superview] superview] convertPoint:locationFrame.origin
|
|
||||||
toView:[[[self window] contentView] superview]];
|
|
||||||
|
|
||||||
// get the height of the table view
|
|
||||||
winFrame = [[self window] frame];
|
|
||||||
tableHeight = (int)([mTableView rowHeight]+[mTableView intercellSpacing].height)*[self visibleRows];
|
|
||||||
|
|
||||||
// make the columns split the width of the popup
|
|
||||||
[[mTableView tableColumnWithIdentifier:@"col1"] setWidth:locationFrame.size.width/2];
|
|
||||||
|
|
||||||
// position the popup anchored to bottom/left of location bar (
|
|
||||||
[mPopupWin setFrame:NSMakeRect(winFrame.origin.x + locationOrigin.x + kFrameMargin,
|
|
||||||
((winFrame.origin.y + locationOrigin.y) - tableHeight) - kFrameMargin,
|
|
||||||
locationFrame.size.width - (2*kFrameMargin),
|
|
||||||
tableHeight) display:NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) closePopup
|
|
||||||
{
|
|
||||||
[mPopupWin close];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL) isOpen
|
|
||||||
{
|
|
||||||
return [mPopupWin isVisible];
|
|
||||||
}
|
|
||||||
|
|
||||||
// url completion ////////////////////////////
|
|
||||||
|
|
||||||
- (void) completeDefaultResult
|
|
||||||
{
|
|
||||||
PRInt32 defaultRow;
|
|
||||||
mResults->GetDefaultItemIndex(&defaultRow);
|
|
||||||
|
|
||||||
if (mCompleteResult && mCompleteWhileTyping) {
|
|
||||||
[self selectRowAt:defaultRow];
|
|
||||||
[self completeResult:defaultRow];
|
|
||||||
} else {
|
|
||||||
[self selectRowAt:-1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) completeSelectedResult
|
|
||||||
{
|
|
||||||
[self completeResult:[mTableView selectedRow]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) completeResult:(int)aRow
|
|
||||||
{
|
|
||||||
if (aRow < 0 && mSearchString) {
|
|
||||||
// reset to the original search string with the insertion point at the end. Note
|
|
||||||
// we have to make our range before we call setStringUndoably: because it calls
|
|
||||||
// clearResults() which destroys |mSearchString|.
|
|
||||||
NSRange selectAtEnd = NSMakeRange([mSearchString length],0);
|
|
||||||
[self setStringUndoably:mSearchString fromLocation:0];
|
|
||||||
[[self fieldEditor] setSelectedRange:selectAtEnd];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ([mDataSource rowCount] <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Fill in the suggestion from the list, but change only the text
|
|
||||||
// after what is typed and select just that part. This allows the
|
|
||||||
// user to see what they have typed and what change the autocomplete
|
|
||||||
// makes while allowing them to continue typing w/out having to
|
|
||||||
// reset the insertion point.
|
|
||||||
NSString *result = [mDataSource resultString:aRow column:@"col1"];
|
|
||||||
NSRange matchRange = [result rangeOfString:mSearchString];
|
|
||||||
if (matchRange.length > 0 && matchRange.location != NSNotFound) {
|
|
||||||
unsigned int location = matchRange.location + matchRange.length;
|
|
||||||
result = [result substringWithRange:NSMakeRange(location, [result length]-location)];
|
|
||||||
[self setStringUndoably:result fromLocation:[mSearchString length]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) enterResult:(int)aRow
|
|
||||||
{
|
|
||||||
if (aRow >= 0 && [mDataSource rowCount] > 0) {
|
|
||||||
[self setStringUndoably:[mDataSource resultString:[mTableView selectedRow] column:@"col1"] fromLocation:0];
|
|
||||||
[self closePopup];
|
|
||||||
} else if (mOpenTimer) {
|
|
||||||
// if there was a search timer going when we hit enter, cancel it
|
|
||||||
[mOpenTimer invalidate];
|
|
||||||
[mOpenTimer release];
|
|
||||||
mOpenTimer = nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) revertText
|
|
||||||
{
|
|
||||||
BrowserWindowController *controller = (BrowserWindowController *)[[self window] windowController];
|
|
||||||
NSString *url = [[controller getBrowserWrapper] getCurrentURLSpec];
|
|
||||||
if (url) {
|
|
||||||
[self clearResults];
|
|
||||||
NSTextView *fieldEditor = [self fieldEditor];
|
|
||||||
[[fieldEditor undoManager] removeAllActions];
|
|
||||||
[fieldEditor setString:url];
|
|
||||||
[fieldEditor selectAll:self];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) setStringUndoably:(NSString *)aString fromLocation:(unsigned int)aLocation
|
|
||||||
{
|
|
||||||
NSTextView *fieldEditor = [self fieldEditor];
|
|
||||||
NSRange aRange = NSMakeRange(aLocation,[[fieldEditor string] length] - aLocation);
|
|
||||||
if ([fieldEditor shouldChangeTextInRange:aRange replacementString:aString]) {
|
|
||||||
[[fieldEditor textStorage] replaceCharactersInRange:aRange withString:aString];
|
|
||||||
// Whenever we send [self didChangeText], we trigger the
|
|
||||||
// textDidChange method, which will begin a new search with
|
|
||||||
// a new search string (which we just inserted) if the selection
|
|
||||||
// is at the end of the string. So, we "select" the first character
|
|
||||||
// to prevent that badness from happening.
|
|
||||||
[fieldEditor setSelectedRange:NSMakeRange(0,0)];
|
|
||||||
[fieldEditor didChangeText];
|
|
||||||
}
|
|
||||||
aRange = NSMakeRange(aLocation,[[fieldEditor string] length] - aLocation);
|
|
||||||
[fieldEditor setSelectedRange:aRange];
|
|
||||||
}
|
|
||||||
|
|
||||||
// selecting rows /////////////////////////////////////////
|
|
||||||
|
|
||||||
- (void) selectRowAt:(int)aRow
|
|
||||||
{
|
|
||||||
if (aRow >= -1 && [mDataSource rowCount] > 0) {
|
|
||||||
// show the popup
|
|
||||||
if ([mPopupWin isVisible] == NO)
|
|
||||||
[mPopupWin orderFront:nil];
|
|
||||||
|
|
||||||
[mTableView selectRow:aRow byExtendingSelection:NO];
|
|
||||||
[mTableView scrollRowToVisible: aRow];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) selectRowBy:(int)aRows
|
|
||||||
{
|
|
||||||
int row = [mTableView selectedRow];
|
|
||||||
|
|
||||||
if (row == -1 && aRows < 0) {
|
|
||||||
// if nothing is selected and you scroll up, go to last row
|
|
||||||
row = [mTableView numberOfRows]-1;
|
|
||||||
} else if (row == [mTableView numberOfRows]-1 && aRows == 1) {
|
|
||||||
// if the last row is selected and you scroll down, go to first row
|
|
||||||
row = 0;
|
|
||||||
} else if (aRows+row < 0) {
|
|
||||||
// if you scroll up beyond first row...
|
|
||||||
if (row == 0)
|
|
||||||
row = -1; // ...and first row is selected, select nothing
|
|
||||||
else
|
|
||||||
row = 0; // ...else, go to first row
|
|
||||||
} else if (aRows+row >= [mTableView numberOfRows]) {
|
|
||||||
// if you scroll down beyond the last row...
|
|
||||||
if (row == [mTableView numberOfRows]-1)
|
|
||||||
row = 0; // and last row is selected, select first row
|
|
||||||
else
|
|
||||||
row = [mTableView numberOfRows]-1; // else, go to last row
|
|
||||||
} else {
|
|
||||||
// no special case, just increment current row
|
|
||||||
row += aRows;
|
|
||||||
}
|
|
||||||
|
|
||||||
[self selectRowAt:row];
|
|
||||||
}
|
|
||||||
|
|
||||||
// event handlers ////////////////////////////////////////////
|
|
||||||
|
|
||||||
- (void) onRowClicked:(NSNotification *)aNote
|
|
||||||
{
|
|
||||||
[self enterResult:[mTableView clickedRow]];
|
|
||||||
[[[self window] windowController] goToLocationFromToolbarURLField:self];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) onBlur:(NSNotification *)aNote
|
|
||||||
{
|
|
||||||
[self closePopup];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) onResize:(NSNotification *)aNote
|
|
||||||
{
|
|
||||||
[self resizePopup];
|
|
||||||
}
|
|
||||||
|
|
||||||
// NSTextField delegate //////////////////////////////////
|
|
||||||
- (void)controlTextDidChange:(NSNotification *)aNote
|
|
||||||
{
|
|
||||||
NSTextView *fieldEditor = [[aNote userInfo] objectForKey:@"NSFieldEditor"];
|
|
||||||
NSRange range = [fieldEditor selectedRange];
|
|
||||||
// make sure we're typing at the end of the string
|
|
||||||
if (range.location == [[fieldEditor string] length]) {
|
|
||||||
// when we ask for a NSTextView string, Cocoa returns
|
|
||||||
// a pointer to the view's backing store. So, the value
|
|
||||||
// of the string continually changes as we edit the text view.
|
|
||||||
// Since we'll edit the text view as we add in autocomplete results,
|
|
||||||
// we've got to make a copy of the string as it currently stands
|
|
||||||
// to know what we were searching for in the first place.
|
|
||||||
NSString *searchString = [[fieldEditor string] copyWithZone:nil];
|
|
||||||
[self startSearch:searchString complete:!mBackspaced];
|
|
||||||
[searchString release];
|
|
||||||
}
|
|
||||||
else if (([mTableView selectedRow] == -1) || mBackspaced)
|
|
||||||
[self clearResults];
|
|
||||||
|
|
||||||
mBackspaced = NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)controlTextDidEndEditing:(NSNotification *)aNote
|
|
||||||
{
|
|
||||||
[self closePopup];
|
|
||||||
[[[[aNote userInfo] objectForKey:@"NSFieldEditor"] undoManager] removeAllActions];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command
|
|
||||||
{
|
|
||||||
if (command == @selector(insertNewline:)) {
|
|
||||||
[self enterResult:[mTableView selectedRow]];
|
|
||||||
} else if (command == @selector(moveUp:)) {
|
|
||||||
[self selectRowBy:-1];
|
|
||||||
[self completeSelectedResult];
|
|
||||||
return YES;
|
|
||||||
} else if (command == @selector(moveDown:)) {
|
|
||||||
[self selectRowBy:1];
|
|
||||||
[self completeSelectedResult];
|
|
||||||
return YES;
|
|
||||||
} else if (command == @selector(scrollPageUp:)) {
|
|
||||||
[self selectRowBy:-kMaxRows];
|
|
||||||
[self completeSelectedResult];
|
|
||||||
} else if (command == @selector(scrollPageDown:)) {
|
|
||||||
[self selectRowBy:kMaxRows];
|
|
||||||
[self completeSelectedResult];
|
|
||||||
} else if (command == @selector(moveToBeginningOfDocument:)) {
|
|
||||||
[self selectRowAt:0];
|
|
||||||
[self completeSelectedResult];
|
|
||||||
} else if (command == @selector(moveToEndOfDocument:)) {
|
|
||||||
[self selectRowAt:[mTableView numberOfRows]-1];
|
|
||||||
[self completeSelectedResult];
|
|
||||||
} else if (command == @selector(insertTab:)) {
|
|
||||||
if ([mPopupWin isVisible]) {
|
|
||||||
[self selectRowBy:1];
|
|
||||||
[self completeSelectedResult];
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
} else if (command == @selector(deleteBackward:) ||
|
|
||||||
command == @selector(deleteForward:)) {
|
|
||||||
// if the user deletes characters, we need to know so that
|
|
||||||
// we can prevent autocompletion later when search results come in
|
|
||||||
if ([[textView string] length] > 1)
|
|
||||||
mBackspaced = YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
|
@ -85,6 +85,7 @@
|
||||||
- (void) onRowClicked:(NSNotification *)aNote;
|
- (void) onRowClicked:(NSNotification *)aNote;
|
||||||
- (void) onBlur:(NSNotification *)aNote;
|
- (void) onBlur:(NSNotification *)aNote;
|
||||||
- (void) onResize:(NSNotification *)aNote;
|
- (void) onResize:(NSNotification *)aNote;
|
||||||
|
- (void) onUndoOrRedo:(NSNotification *)aNote;
|
||||||
|
|
||||||
- (void) setStringUndoably:(NSString*)aString fromLocation:(unsigned int)aLocation;
|
- (void) setStringUndoably:(NSString*)aString fromLocation:(unsigned int)aLocation;
|
||||||
- (id) fieldEditor;
|
- (id) fieldEditor;
|
||||||
|
|
|
@ -91,6 +91,7 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener)
|
||||||
mListener = (nsIAutoCompleteListener *)new AutoCompleteListener(self);
|
mListener = (nsIAutoCompleteListener *)new AutoCompleteListener(self);
|
||||||
NS_IF_ADDREF(mListener);
|
NS_IF_ADDREF(mListener);
|
||||||
|
|
||||||
|
[self setFont:[NSFont controlContentFontOfSize:0]];
|
||||||
[self setDelegate: self];
|
[self setDelegate: self];
|
||||||
|
|
||||||
// XXX the owner of the textfield should set this
|
// XXX the owner of the textfield should set this
|
||||||
|
@ -151,6 +152,14 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener)
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResize:)
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResize:)
|
||||||
name:NSWindowDidResizeNotification object:nil];
|
name:NSWindowDidResizeNotification object:nil];
|
||||||
|
|
||||||
|
// listen for Undo/Redo to make sure autocomplete doesn't get horked.
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onUndoOrRedo:)
|
||||||
|
name:NSUndoManagerDidRedoChangeNotification
|
||||||
|
object:[[self fieldEditor] undoManager]];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onUndoOrRedo:)
|
||||||
|
name:NSUndoManagerDidUndoChangeNotification
|
||||||
|
object:[[self fieldEditor] undoManager]];
|
||||||
|
|
||||||
// read the user default on if we should auto-complete the text field as the user
|
// read the user default on if we should auto-complete the text field as the user
|
||||||
// types or make them pick something from a list (a-la mozilla).
|
// types or make them pick something from a list (a-la mozilla).
|
||||||
mCompleteWhileTyping = [[NSUserDefaults standardUserDefaults] boolForKey:USER_DEFAULTS_AUTOCOMPLETE_WHILE_TYPING];
|
mCompleteWhileTyping = [[NSUserDefaults standardUserDefaults] boolForKey:USER_DEFAULTS_AUTOCOMPLETE_WHILE_TYPING];
|
||||||
|
@ -501,6 +510,11 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener)
|
||||||
[self resizePopup];
|
[self resizePopup];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) onUndoOrRedo:(NSNotification *)aNote
|
||||||
|
{
|
||||||
|
[self clearResults];
|
||||||
|
}
|
||||||
|
|
||||||
// NSTextField delegate //////////////////////////////////
|
// NSTextField delegate //////////////////////////////////
|
||||||
- (void)controlTextDidChange:(NSNotification *)aNote
|
- (void)controlTextDidChange:(NSNotification *)aNote
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,92 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
||||||
*
|
|
||||||
* The contents of this file are subject to the Mozilla Public
|
|
||||||
* License Version 1.1 (the "License"); you may not use this file
|
|
||||||
* except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at http://www.mozilla.org/MPL/
|
|
||||||
*
|
|
||||||
* Software distributed under the License is distributed on an "AS
|
|
||||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
||||||
* implied. See the License for the specific language governing
|
|
||||||
* rights and limitations under the License.
|
|
||||||
*
|
|
||||||
* The Original Code is the Mozilla browser.
|
|
||||||
*
|
|
||||||
* The Initial Developer of the Original Code is Netscape
|
|
||||||
* Communications Corporation. Portions created by Netscape are
|
|
||||||
* Copyright (C) 2002 Netscape Communications Corporation. All
|
|
||||||
* Rights Reserved.
|
|
||||||
*
|
|
||||||
* Contributor(s):
|
|
||||||
* Joe Hewitt <hewitt@netscape.com> (Original Author)
|
|
||||||
* David Haas <haasd@cae.wisc.edu>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <AppKit/AppKit.h>
|
|
||||||
#import "CHAutoCompleteDataSource.h"
|
|
||||||
#include "nsIAutoCompleteSession.h"
|
|
||||||
#include "nsIAutoCompleteResults.h"
|
|
||||||
#include "nsIAutoCompleteListener.h"
|
|
||||||
|
|
||||||
@class CHAutoCompleteDataSource, CHPageProxyIcon;
|
|
||||||
|
|
||||||
@interface CHAutoCompleteTextField : NSTextField
|
|
||||||
{
|
|
||||||
IBOutlet CHPageProxyIcon *mProxyIcon;
|
|
||||||
NSWindow *mPopupWin;
|
|
||||||
NSTableView *mTableView;
|
|
||||||
|
|
||||||
CHAutoCompleteDataSource *mDataSource;
|
|
||||||
|
|
||||||
nsIAutoCompleteSession *mSession;
|
|
||||||
nsIAutoCompleteResults *mResults;
|
|
||||||
nsIAutoCompleteListener *mListener;
|
|
||||||
|
|
||||||
NSString *mSearchString;
|
|
||||||
|
|
||||||
// used to remember if backspace was pressed in complete: so we can check this in controlTextDidChange
|
|
||||||
BOOL mBackspaced;
|
|
||||||
// determines if the search currently pending should complete the default result when it is ready
|
|
||||||
BOOL mCompleteResult;
|
|
||||||
// should the autocomplete fill in the default completion into the text field? The default
|
|
||||||
// is no, but this can be set with a user default pref.
|
|
||||||
BOOL mCompleteWhileTyping;
|
|
||||||
|
|
||||||
NSTimer *mOpenTimer;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) setSession:(NSString *)aSession;
|
|
||||||
- (NSString *) session;
|
|
||||||
- (void) setPageProxyIcon:(NSImage *)aImage;
|
|
||||||
|
|
||||||
- (NSTableView *) tableView;
|
|
||||||
- (int) visibleRows;
|
|
||||||
|
|
||||||
- (void) startSearch:(NSString*)aString complete:(BOOL)aComplete;
|
|
||||||
- (void) performSearch;
|
|
||||||
- (void) dataReady:(nsIAutoCompleteResults*)aResults status:(AutoCompleteStatus)aStatus;
|
|
||||||
- (void) searchTimer:(NSTimer *)aTimer;
|
|
||||||
- (void) clearResults;
|
|
||||||
|
|
||||||
- (void) completeDefaultResult;
|
|
||||||
- (void) completeSelectedResult;
|
|
||||||
- (void) completeResult:(int)aRow;
|
|
||||||
- (void) enterResult:(int)aRow;
|
|
||||||
- (void) revertText;
|
|
||||||
|
|
||||||
- (void) selectRowAt:(int)aRow;
|
|
||||||
- (void) selectRowBy:(int)aRows;
|
|
||||||
|
|
||||||
- (void) openPopup;
|
|
||||||
- (void) closePopup;
|
|
||||||
- (void) resizePopup;
|
|
||||||
- (BOOL) isOpen;
|
|
||||||
|
|
||||||
- (void) onRowClicked:(NSNotification *)aNote;
|
|
||||||
- (void) onBlur:(NSNotification *)aNote;
|
|
||||||
- (void) onResize:(NSNotification *)aNote;
|
|
||||||
|
|
||||||
- (void) setStringUndoably:(NSString*)aString fromLocation:(unsigned int)aLocation;
|
|
||||||
- (id) fieldEditor;
|
|
||||||
|
|
||||||
@end
|
|
|
@ -1,574 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
||||||
*
|
|
||||||
* The contents of this file are subject to the Mozilla Public
|
|
||||||
* License Version 1.1 (the "License"); you may not use this file
|
|
||||||
* except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at http://www.mozilla.org/MPL/
|
|
||||||
*
|
|
||||||
* Software distributed under the License is distributed on an "AS
|
|
||||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
||||||
* implied. See the License for the specific language governing
|
|
||||||
* rights and limitations under the License.
|
|
||||||
*
|
|
||||||
* The Original Code is the Mozilla browser.
|
|
||||||
*
|
|
||||||
* The Initial Developer of the Original Code is Netscape
|
|
||||||
* Communications Corporation. Portions created by Netscape are
|
|
||||||
* Copyright (C) 2002 Netscape Communications Corporation. All
|
|
||||||
* Rights Reserved.
|
|
||||||
*
|
|
||||||
* Contributor(s):
|
|
||||||
* Joe Hewitt <hewitt@netscape.com> (Original Author)
|
|
||||||
* David Haas <haasd@cae.wisc.edu>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "CHAutoCompleteTextField.h"
|
|
||||||
#import "BrowserWindowController.h"
|
|
||||||
#import "CHPageProxyIcon.h"
|
|
||||||
#include "nsIServiceManager.h"
|
|
||||||
#include "nsMemory.h"
|
|
||||||
#include "nsString.h"
|
|
||||||
#include "CHUserDefaults.h"
|
|
||||||
|
|
||||||
static const int kMaxRows = 6;
|
|
||||||
static const int kFrameMargin = 1;
|
|
||||||
|
|
||||||
@interface AutoCompleteWindow : NSWindow
|
|
||||||
- (BOOL)isKeyWindow;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation AutoCompleteWindow
|
|
||||||
- (BOOL)isKeyWindow
|
|
||||||
{
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
class AutoCompleteListener : public nsIAutoCompleteListener
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AutoCompleteListener(CHAutoCompleteTextField* aTextField)
|
|
||||||
{
|
|
||||||
NS_INIT_REFCNT();
|
|
||||||
mTextField = aTextField;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
|
||||||
|
|
||||||
NS_IMETHODIMP OnStatus(const PRUnichar* aText) { return NS_OK; }
|
|
||||||
NS_IMETHODIMP SetParam(nsISupports *aParam) { return NS_OK; }
|
|
||||||
NS_IMETHODIMP GetParam(nsISupports **aParam) { return NS_OK; }
|
|
||||||
|
|
||||||
NS_IMETHODIMP OnAutoComplete(nsIAutoCompleteResults *aResults, AutoCompleteStatus aStatus)
|
|
||||||
{
|
|
||||||
[mTextField dataReady:aResults status:aStatus];
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
CHAutoCompleteTextField *mTextField;
|
|
||||||
};
|
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener)
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@implementation CHAutoCompleteTextField
|
|
||||||
|
|
||||||
- (void) awakeFromNib
|
|
||||||
{
|
|
||||||
NSTableColumn *column;
|
|
||||||
NSScrollView *scrollView;
|
|
||||||
NSCell *dataCell;
|
|
||||||
|
|
||||||
mSearchString = nil;
|
|
||||||
mBackspaced = NO;
|
|
||||||
mCompleteResult = NO;
|
|
||||||
mOpenTimer = nil;
|
|
||||||
|
|
||||||
mSession = nsnull;
|
|
||||||
mResults = nsnull;
|
|
||||||
mListener = (nsIAutoCompleteListener *)new AutoCompleteListener(self);
|
|
||||||
NS_IF_ADDREF(mListener);
|
|
||||||
|
|
||||||
[self setDelegate: self];
|
|
||||||
|
|
||||||
// XXX the owner of the textfield should set this
|
|
||||||
[self setSession:@"history"];
|
|
||||||
|
|
||||||
// construct and configure the popup window
|
|
||||||
mPopupWin = [[AutoCompleteWindow alloc] initWithContentRect:NSMakeRect(0,0,0,0)
|
|
||||||
styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
|
|
||||||
[mPopupWin setReleasedWhenClosed:NO];
|
|
||||||
[mPopupWin setLevel:NSFloatingWindowLevel];
|
|
||||||
[mPopupWin setHasShadow:YES];
|
|
||||||
[mPopupWin setAlphaValue:0.9];
|
|
||||||
|
|
||||||
// construct and configure the view
|
|
||||||
mTableView = [[[NSTableView alloc] initWithFrame:NSMakeRect(0,0,0,0)] autorelease];
|
|
||||||
[mTableView setIntercellSpacing:NSMakeSize(1, 2)];
|
|
||||||
[mTableView setTarget:self];
|
|
||||||
[mTableView setAction:@selector(onRowClicked:)];
|
|
||||||
|
|
||||||
// Create the icon column if we have a proxy icon
|
|
||||||
if (mProxyIcon) {
|
|
||||||
column = [[[NSTableColumn alloc] initWithIdentifier:@"icon"] autorelease];
|
|
||||||
[column setWidth:[mProxyIcon frame].origin.x + [mProxyIcon frame].size.width];
|
|
||||||
dataCell = [[[NSImageCell alloc] initImageCell:nil] autorelease];
|
|
||||||
[column setDataCell:dataCell];
|
|
||||||
[mTableView addTableColumn: column];
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the text columns
|
|
||||||
column = [[[NSTableColumn alloc] initWithIdentifier:@"col1"] autorelease];
|
|
||||||
[mTableView addTableColumn: column];
|
|
||||||
column = [[[NSTableColumn alloc] initWithIdentifier:@"col2"] autorelease];
|
|
||||||
[[column dataCell] setTextColor:[NSColor darkGrayColor]];
|
|
||||||
[mTableView addTableColumn: column];
|
|
||||||
|
|
||||||
// hide the table header
|
|
||||||
[mTableView setHeaderView:nil];
|
|
||||||
|
|
||||||
// construct the scroll view that contains the table view
|
|
||||||
scrollView = [[[NSScrollView alloc] initWithFrame:NSMakeRect(0,0,0,0)] autorelease];
|
|
||||||
[scrollView setHasVerticalScroller:YES];
|
|
||||||
[[scrollView verticalScroller] setControlSize:NSSmallControlSize];
|
|
||||||
[scrollView setDocumentView: mTableView];
|
|
||||||
|
|
||||||
// construct the datasource
|
|
||||||
mDataSource = [[CHAutoCompleteDataSource alloc] init];
|
|
||||||
[mTableView setDataSource: mDataSource];
|
|
||||||
|
|
||||||
[mPopupWin setContentView:scrollView];
|
|
||||||
|
|
||||||
// listen for when window resigns from key handling
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onBlur:)
|
|
||||||
name:NSWindowDidResignKeyNotification object:nil];
|
|
||||||
|
|
||||||
// listen for when window is about to be moved or resized
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onBlur:)
|
|
||||||
name:NSWindowWillMoveNotification object:nil];
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResize:)
|
|
||||||
name:NSWindowDidResizeNotification object:nil];
|
|
||||||
|
|
||||||
// read the user default on if we should auto-complete the text field as the user
|
|
||||||
// types or make them pick something from a list (a-la mozilla).
|
|
||||||
mCompleteWhileTyping = [[NSUserDefaults standardUserDefaults] boolForKey:USER_DEFAULTS_AUTOCOMPLETE_WHILE_TYPING];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) dealloc
|
|
||||||
{
|
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
||||||
|
|
||||||
if (mSearchString)
|
|
||||||
[mSearchString release];
|
|
||||||
|
|
||||||
[mPopupWin release];
|
|
||||||
[mDataSource release];
|
|
||||||
|
|
||||||
NS_IF_RELEASE(mSession);
|
|
||||||
NS_IF_RELEASE(mResults);
|
|
||||||
NS_IF_RELEASE(mListener);
|
|
||||||
|
|
||||||
[super dealloc];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) setSession:(NSString *)aSession
|
|
||||||
{
|
|
||||||
NS_IF_RELEASE(mSession);
|
|
||||||
|
|
||||||
// XXX add aSession to contract id
|
|
||||||
nsCOMPtr<nsIAutoCompleteSession> session =
|
|
||||||
do_GetService("@mozilla.org/autocompleteSession;1?type=history");
|
|
||||||
mSession = session;
|
|
||||||
NS_IF_ADDREF(mSession);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *) session
|
|
||||||
{
|
|
||||||
// XXX return session name
|
|
||||||
return @"";
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSTableView *) tableView
|
|
||||||
{
|
|
||||||
return mTableView;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (int) visibleRows
|
|
||||||
{
|
|
||||||
int minRows = [mDataSource rowCount];
|
|
||||||
return minRows < kMaxRows ? minRows : kMaxRows;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) setPageProxyIcon:(NSImage *)aImage
|
|
||||||
{
|
|
||||||
[mProxyIcon setImage:aImage];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(id) fieldEditor
|
|
||||||
{
|
|
||||||
return [[self window] fieldEditor:NO forObject:self];
|
|
||||||
}
|
|
||||||
// searching ////////////////////////////
|
|
||||||
|
|
||||||
- (void) startSearch:(NSString*)aString complete:(BOOL)aComplete
|
|
||||||
{
|
|
||||||
if (mSearchString)
|
|
||||||
[mSearchString release];
|
|
||||||
mSearchString = [aString retain];
|
|
||||||
|
|
||||||
mCompleteResult = aComplete;
|
|
||||||
|
|
||||||
if ([self isOpen]) {
|
|
||||||
[self performSearch];
|
|
||||||
} else {
|
|
||||||
// delay the search when the popup is not yet opened so that users
|
|
||||||
// don't see a jerky flashing popup when they start typing for the first time
|
|
||||||
if (mOpenTimer) {
|
|
||||||
[mOpenTimer invalidate];
|
|
||||||
[mOpenTimer release];
|
|
||||||
}
|
|
||||||
|
|
||||||
mOpenTimer = [[NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(searchTimer:)
|
|
||||||
userInfo:nil repeats:NO] retain];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) performSearch
|
|
||||||
{
|
|
||||||
PRUnichar* chars = nsMemory::Alloc(([mSearchString length]+1) * sizeof(PRUnichar));
|
|
||||||
[mSearchString getCharacters:chars];
|
|
||||||
chars[[mSearchString length]] = 0; // I shouldn't have to do this
|
|
||||||
nsresult rv = mSession->OnStartLookup(chars, mResults, mListener);
|
|
||||||
nsMemory::Free(chars);
|
|
||||||
|
|
||||||
if (NS_FAILED(rv))
|
|
||||||
NSLog(@"Unable to perform autocomplete lookup");
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) dataReady:(nsIAutoCompleteResults*)aResults status:(AutoCompleteStatus)aStatus
|
|
||||||
{
|
|
||||||
NS_IF_RELEASE(mResults);
|
|
||||||
mResults = nsnull;
|
|
||||||
|
|
||||||
if (aStatus == nsIAutoCompleteStatus::failed) {
|
|
||||||
[mDataSource setErrorMessage:@""];
|
|
||||||
} else if (aStatus == nsIAutoCompleteStatus::ignored) {
|
|
||||||
[mDataSource setErrorMessage:@""];
|
|
||||||
} else if (aStatus == nsIAutoCompleteStatus::noMatch) {
|
|
||||||
[mDataSource setErrorMessage:@""];
|
|
||||||
} else if (aStatus == nsIAutoCompleteStatus::matchFound) {
|
|
||||||
mResults = aResults;
|
|
||||||
NS_IF_ADDREF(mResults);
|
|
||||||
[mDataSource setResults:aResults];
|
|
||||||
[self completeDefaultResult];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([mDataSource rowCount] > 0) {
|
|
||||||
[mTableView noteNumberOfRowsChanged];
|
|
||||||
[self openPopup];
|
|
||||||
} else {
|
|
||||||
[self closePopup];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) searchTimer:(NSTimer *)aTimer
|
|
||||||
{
|
|
||||||
[mOpenTimer release];
|
|
||||||
mOpenTimer = nil;
|
|
||||||
|
|
||||||
[self performSearch];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) clearResults
|
|
||||||
{
|
|
||||||
// clear out search data
|
|
||||||
if (mSearchString)
|
|
||||||
[mSearchString release];
|
|
||||||
mSearchString = nil;
|
|
||||||
NS_IF_RELEASE(mResults);
|
|
||||||
mResults = nsnull;
|
|
||||||
|
|
||||||
[mDataSource setResults:nil];
|
|
||||||
|
|
||||||
[self closePopup];
|
|
||||||
}
|
|
||||||
|
|
||||||
// handling the popup /////////////////////////////////
|
|
||||||
|
|
||||||
- (void) openPopup
|
|
||||||
{
|
|
||||||
[self resizePopup];
|
|
||||||
|
|
||||||
// show the popup
|
|
||||||
if ([mPopupWin isVisible] == NO)
|
|
||||||
[mPopupWin orderFront:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) resizePopup
|
|
||||||
{
|
|
||||||
NSRect locationFrame, winFrame;
|
|
||||||
NSPoint locationOrigin;
|
|
||||||
int tableHeight;
|
|
||||||
|
|
||||||
if ([self visibleRows] == 0) {
|
|
||||||
[self closePopup];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the origin of the location bar in coordinates of the root view
|
|
||||||
locationFrame = [[self superview] frame];
|
|
||||||
locationOrigin = [[[self superview] superview] convertPoint:locationFrame.origin
|
|
||||||
toView:[[[self window] contentView] superview]];
|
|
||||||
|
|
||||||
// get the height of the table view
|
|
||||||
winFrame = [[self window] frame];
|
|
||||||
tableHeight = (int)([mTableView rowHeight]+[mTableView intercellSpacing].height)*[self visibleRows];
|
|
||||||
|
|
||||||
// make the columns split the width of the popup
|
|
||||||
[[mTableView tableColumnWithIdentifier:@"col1"] setWidth:locationFrame.size.width/2];
|
|
||||||
|
|
||||||
// position the popup anchored to bottom/left of location bar (
|
|
||||||
[mPopupWin setFrame:NSMakeRect(winFrame.origin.x + locationOrigin.x + kFrameMargin,
|
|
||||||
((winFrame.origin.y + locationOrigin.y) - tableHeight) - kFrameMargin,
|
|
||||||
locationFrame.size.width - (2*kFrameMargin),
|
|
||||||
tableHeight) display:NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) closePopup
|
|
||||||
{
|
|
||||||
[mPopupWin close];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL) isOpen
|
|
||||||
{
|
|
||||||
return [mPopupWin isVisible];
|
|
||||||
}
|
|
||||||
|
|
||||||
// url completion ////////////////////////////
|
|
||||||
|
|
||||||
- (void) completeDefaultResult
|
|
||||||
{
|
|
||||||
PRInt32 defaultRow;
|
|
||||||
mResults->GetDefaultItemIndex(&defaultRow);
|
|
||||||
|
|
||||||
if (mCompleteResult && mCompleteWhileTyping) {
|
|
||||||
[self selectRowAt:defaultRow];
|
|
||||||
[self completeResult:defaultRow];
|
|
||||||
} else {
|
|
||||||
[self selectRowAt:-1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) completeSelectedResult
|
|
||||||
{
|
|
||||||
[self completeResult:[mTableView selectedRow]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) completeResult:(int)aRow
|
|
||||||
{
|
|
||||||
if (aRow < 0 && mSearchString) {
|
|
||||||
// reset to the original search string with the insertion point at the end. Note
|
|
||||||
// we have to make our range before we call setStringUndoably: because it calls
|
|
||||||
// clearResults() which destroys |mSearchString|.
|
|
||||||
NSRange selectAtEnd = NSMakeRange([mSearchString length],0);
|
|
||||||
[self setStringUndoably:mSearchString fromLocation:0];
|
|
||||||
[[self fieldEditor] setSelectedRange:selectAtEnd];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ([mDataSource rowCount] <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Fill in the suggestion from the list, but change only the text
|
|
||||||
// after what is typed and select just that part. This allows the
|
|
||||||
// user to see what they have typed and what change the autocomplete
|
|
||||||
// makes while allowing them to continue typing w/out having to
|
|
||||||
// reset the insertion point.
|
|
||||||
NSString *result = [mDataSource resultString:aRow column:@"col1"];
|
|
||||||
NSRange matchRange = [result rangeOfString:mSearchString];
|
|
||||||
if (matchRange.length > 0 && matchRange.location != NSNotFound) {
|
|
||||||
unsigned int location = matchRange.location + matchRange.length;
|
|
||||||
result = [result substringWithRange:NSMakeRange(location, [result length]-location)];
|
|
||||||
[self setStringUndoably:result fromLocation:[mSearchString length]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) enterResult:(int)aRow
|
|
||||||
{
|
|
||||||
if (aRow >= 0 && [mDataSource rowCount] > 0) {
|
|
||||||
[self setStringUndoably:[mDataSource resultString:[mTableView selectedRow] column:@"col1"] fromLocation:0];
|
|
||||||
[self closePopup];
|
|
||||||
} else if (mOpenTimer) {
|
|
||||||
// if there was a search timer going when we hit enter, cancel it
|
|
||||||
[mOpenTimer invalidate];
|
|
||||||
[mOpenTimer release];
|
|
||||||
mOpenTimer = nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) revertText
|
|
||||||
{
|
|
||||||
BrowserWindowController *controller = (BrowserWindowController *)[[self window] windowController];
|
|
||||||
NSString *url = [[controller getBrowserWrapper] getCurrentURLSpec];
|
|
||||||
if (url) {
|
|
||||||
[self clearResults];
|
|
||||||
NSTextView *fieldEditor = [self fieldEditor];
|
|
||||||
[[fieldEditor undoManager] removeAllActions];
|
|
||||||
[fieldEditor setString:url];
|
|
||||||
[fieldEditor selectAll:self];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) setStringUndoably:(NSString *)aString fromLocation:(unsigned int)aLocation
|
|
||||||
{
|
|
||||||
NSTextView *fieldEditor = [self fieldEditor];
|
|
||||||
NSRange aRange = NSMakeRange(aLocation,[[fieldEditor string] length] - aLocation);
|
|
||||||
if ([fieldEditor shouldChangeTextInRange:aRange replacementString:aString]) {
|
|
||||||
[[fieldEditor textStorage] replaceCharactersInRange:aRange withString:aString];
|
|
||||||
// Whenever we send [self didChangeText], we trigger the
|
|
||||||
// textDidChange method, which will begin a new search with
|
|
||||||
// a new search string (which we just inserted) if the selection
|
|
||||||
// is at the end of the string. So, we "select" the first character
|
|
||||||
// to prevent that badness from happening.
|
|
||||||
[fieldEditor setSelectedRange:NSMakeRange(0,0)];
|
|
||||||
[fieldEditor didChangeText];
|
|
||||||
}
|
|
||||||
aRange = NSMakeRange(aLocation,[[fieldEditor string] length] - aLocation);
|
|
||||||
[fieldEditor setSelectedRange:aRange];
|
|
||||||
}
|
|
||||||
|
|
||||||
// selecting rows /////////////////////////////////////////
|
|
||||||
|
|
||||||
- (void) selectRowAt:(int)aRow
|
|
||||||
{
|
|
||||||
if (aRow >= -1 && [mDataSource rowCount] > 0) {
|
|
||||||
// show the popup
|
|
||||||
if ([mPopupWin isVisible] == NO)
|
|
||||||
[mPopupWin orderFront:nil];
|
|
||||||
|
|
||||||
[mTableView selectRow:aRow byExtendingSelection:NO];
|
|
||||||
[mTableView scrollRowToVisible: aRow];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) selectRowBy:(int)aRows
|
|
||||||
{
|
|
||||||
int row = [mTableView selectedRow];
|
|
||||||
|
|
||||||
if (row == -1 && aRows < 0) {
|
|
||||||
// if nothing is selected and you scroll up, go to last row
|
|
||||||
row = [mTableView numberOfRows]-1;
|
|
||||||
} else if (row == [mTableView numberOfRows]-1 && aRows == 1) {
|
|
||||||
// if the last row is selected and you scroll down, go to first row
|
|
||||||
row = 0;
|
|
||||||
} else if (aRows+row < 0) {
|
|
||||||
// if you scroll up beyond first row...
|
|
||||||
if (row == 0)
|
|
||||||
row = -1; // ...and first row is selected, select nothing
|
|
||||||
else
|
|
||||||
row = 0; // ...else, go to first row
|
|
||||||
} else if (aRows+row >= [mTableView numberOfRows]) {
|
|
||||||
// if you scroll down beyond the last row...
|
|
||||||
if (row == [mTableView numberOfRows]-1)
|
|
||||||
row = 0; // and last row is selected, select first row
|
|
||||||
else
|
|
||||||
row = [mTableView numberOfRows]-1; // else, go to last row
|
|
||||||
} else {
|
|
||||||
// no special case, just increment current row
|
|
||||||
row += aRows;
|
|
||||||
}
|
|
||||||
|
|
||||||
[self selectRowAt:row];
|
|
||||||
}
|
|
||||||
|
|
||||||
// event handlers ////////////////////////////////////////////
|
|
||||||
|
|
||||||
- (void) onRowClicked:(NSNotification *)aNote
|
|
||||||
{
|
|
||||||
[self enterResult:[mTableView clickedRow]];
|
|
||||||
[[[self window] windowController] goToLocationFromToolbarURLField:self];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) onBlur:(NSNotification *)aNote
|
|
||||||
{
|
|
||||||
[self closePopup];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) onResize:(NSNotification *)aNote
|
|
||||||
{
|
|
||||||
[self resizePopup];
|
|
||||||
}
|
|
||||||
|
|
||||||
// NSTextField delegate //////////////////////////////////
|
|
||||||
- (void)controlTextDidChange:(NSNotification *)aNote
|
|
||||||
{
|
|
||||||
NSTextView *fieldEditor = [[aNote userInfo] objectForKey:@"NSFieldEditor"];
|
|
||||||
NSRange range = [fieldEditor selectedRange];
|
|
||||||
// make sure we're typing at the end of the string
|
|
||||||
if (range.location == [[fieldEditor string] length]) {
|
|
||||||
// when we ask for a NSTextView string, Cocoa returns
|
|
||||||
// a pointer to the view's backing store. So, the value
|
|
||||||
// of the string continually changes as we edit the text view.
|
|
||||||
// Since we'll edit the text view as we add in autocomplete results,
|
|
||||||
// we've got to make a copy of the string as it currently stands
|
|
||||||
// to know what we were searching for in the first place.
|
|
||||||
NSString *searchString = [[fieldEditor string] copyWithZone:nil];
|
|
||||||
[self startSearch:searchString complete:!mBackspaced];
|
|
||||||
[searchString release];
|
|
||||||
}
|
|
||||||
else if (([mTableView selectedRow] == -1) || mBackspaced)
|
|
||||||
[self clearResults];
|
|
||||||
|
|
||||||
mBackspaced = NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)controlTextDidEndEditing:(NSNotification *)aNote
|
|
||||||
{
|
|
||||||
[self closePopup];
|
|
||||||
[[[[aNote userInfo] objectForKey:@"NSFieldEditor"] undoManager] removeAllActions];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command
|
|
||||||
{
|
|
||||||
if (command == @selector(insertNewline:)) {
|
|
||||||
[self enterResult:[mTableView selectedRow]];
|
|
||||||
} else if (command == @selector(moveUp:)) {
|
|
||||||
[self selectRowBy:-1];
|
|
||||||
[self completeSelectedResult];
|
|
||||||
return YES;
|
|
||||||
} else if (command == @selector(moveDown:)) {
|
|
||||||
[self selectRowBy:1];
|
|
||||||
[self completeSelectedResult];
|
|
||||||
return YES;
|
|
||||||
} else if (command == @selector(scrollPageUp:)) {
|
|
||||||
[self selectRowBy:-kMaxRows];
|
|
||||||
[self completeSelectedResult];
|
|
||||||
} else if (command == @selector(scrollPageDown:)) {
|
|
||||||
[self selectRowBy:kMaxRows];
|
|
||||||
[self completeSelectedResult];
|
|
||||||
} else if (command == @selector(moveToBeginningOfDocument:)) {
|
|
||||||
[self selectRowAt:0];
|
|
||||||
[self completeSelectedResult];
|
|
||||||
} else if (command == @selector(moveToEndOfDocument:)) {
|
|
||||||
[self selectRowAt:[mTableView numberOfRows]-1];
|
|
||||||
[self completeSelectedResult];
|
|
||||||
} else if (command == @selector(insertTab:)) {
|
|
||||||
if ([mPopupWin isVisible]) {
|
|
||||||
[self selectRowBy:1];
|
|
||||||
[self completeSelectedResult];
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
} else if (command == @selector(deleteBackward:) ||
|
|
||||||
command == @selector(deleteForward:)) {
|
|
||||||
// if the user deletes characters, we need to know so that
|
|
||||||
// we can prevent autocompletion later when search results come in
|
|
||||||
if ([[textView string] length] > 1)
|
|
||||||
mBackspaced = YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
|
@ -85,6 +85,7 @@
|
||||||
- (void) onRowClicked:(NSNotification *)aNote;
|
- (void) onRowClicked:(NSNotification *)aNote;
|
||||||
- (void) onBlur:(NSNotification *)aNote;
|
- (void) onBlur:(NSNotification *)aNote;
|
||||||
- (void) onResize:(NSNotification *)aNote;
|
- (void) onResize:(NSNotification *)aNote;
|
||||||
|
- (void) onUndoOrRedo:(NSNotification *)aNote;
|
||||||
|
|
||||||
- (void) setStringUndoably:(NSString*)aString fromLocation:(unsigned int)aLocation;
|
- (void) setStringUndoably:(NSString*)aString fromLocation:(unsigned int)aLocation;
|
||||||
- (id) fieldEditor;
|
- (id) fieldEditor;
|
||||||
|
|
|
@ -91,6 +91,7 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener)
|
||||||
mListener = (nsIAutoCompleteListener *)new AutoCompleteListener(self);
|
mListener = (nsIAutoCompleteListener *)new AutoCompleteListener(self);
|
||||||
NS_IF_ADDREF(mListener);
|
NS_IF_ADDREF(mListener);
|
||||||
|
|
||||||
|
[self setFont:[NSFont controlContentFontOfSize:0]];
|
||||||
[self setDelegate: self];
|
[self setDelegate: self];
|
||||||
|
|
||||||
// XXX the owner of the textfield should set this
|
// XXX the owner of the textfield should set this
|
||||||
|
@ -151,6 +152,14 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener)
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResize:)
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResize:)
|
||||||
name:NSWindowDidResizeNotification object:nil];
|
name:NSWindowDidResizeNotification object:nil];
|
||||||
|
|
||||||
|
// listen for Undo/Redo to make sure autocomplete doesn't get horked.
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onUndoOrRedo:)
|
||||||
|
name:NSUndoManagerDidRedoChangeNotification
|
||||||
|
object:[[self fieldEditor] undoManager]];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onUndoOrRedo:)
|
||||||
|
name:NSUndoManagerDidUndoChangeNotification
|
||||||
|
object:[[self fieldEditor] undoManager]];
|
||||||
|
|
||||||
// read the user default on if we should auto-complete the text field as the user
|
// read the user default on if we should auto-complete the text field as the user
|
||||||
// types or make them pick something from a list (a-la mozilla).
|
// types or make them pick something from a list (a-la mozilla).
|
||||||
mCompleteWhileTyping = [[NSUserDefaults standardUserDefaults] boolForKey:USER_DEFAULTS_AUTOCOMPLETE_WHILE_TYPING];
|
mCompleteWhileTyping = [[NSUserDefaults standardUserDefaults] boolForKey:USER_DEFAULTS_AUTOCOMPLETE_WHILE_TYPING];
|
||||||
|
@ -501,6 +510,11 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener)
|
||||||
[self resizePopup];
|
[self resizePopup];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) onUndoOrRedo:(NSNotification *)aNote
|
||||||
|
{
|
||||||
|
[self clearResults];
|
||||||
|
}
|
||||||
|
|
||||||
// NSTextField delegate //////////////////////////////////
|
// NSTextField delegate //////////////////////////////////
|
||||||
- (void)controlTextDidChange:(NSNotification *)aNote
|
- (void)controlTextDidChange:(NSNotification *)aNote
|
||||||
{
|
{
|
||||||
|
|
Загрузка…
Ссылка в новой задаче