diff --git a/camino/BrowserWindow.h b/camino/BrowserWindow.h new file mode 100644 index 000000000000..8eb4cd63f876 --- /dev/null +++ b/camino/BrowserWindow.h @@ -0,0 +1,9 @@ +/* BrowserWindow */ + +#import + +@interface BrowserWindow : NSWindow +{ + IBOutlet id mAutoCompleteTextField; +} +@end diff --git a/camino/BrowserWindow.mm b/camino/BrowserWindow.mm new file mode 100644 index 000000000000..18cc910af98b --- /dev/null +++ b/camino/BrowserWindow.mm @@ -0,0 +1,22 @@ +#import "BrowserWindow.h" +#import "CHAutoCompleteTextField.h" + +static const int kEscapeKeyCode = 53; + +@implementation BrowserWindow + +- (void)sendEvent:(NSEvent *)theEvent +{ + // We need this hack because NSWindow::sendEvent will eat the escape key + // and won't pass it down to the key handler of responders in the window. + // We have to override sendEvent for all of our escape key needs. + if ([theEvent keyCode] == kEscapeKeyCode && [theEvent type] == NSKeyDown) { + NSText *fieldEditor = [self fieldEditor:NO forObject:mAutoCompleteTextField]; + if (fieldEditor && [self firstResponder] == fieldEditor) { + [mAutoCompleteTextField revertText]; + } + } else + [super sendEvent:theEvent]; +} + +@end diff --git a/camino/BrowserWindow.nib/classes.nib b/camino/BrowserWindow.nib/classes.nib index b4abc1d9ac61..97dfc30f8721 100644 --- a/camino/BrowserWindow.nib/classes.nib +++ b/camino/BrowserWindow.nib/classes.nib @@ -16,7 +16,12 @@ SUPERCLASS = NSObject; }, {CLASS = BookmarksToolbar; LANGUAGE = ObjC; SUPERCLASS = NSView; }, - {CLASS = BrowserWindow; LANGUAGE = ObjC; SUPERCLASS = NSWindow; }, + { + CLASS = BrowserWindow; + LANGUAGE = ObjC; + OUTLETS = {mAutoCompleteTextField = id; }; + SUPERCLASS = NSWindow; + }, { ACTIONS = { back = id; diff --git a/camino/BrowserWindow.nib/info.nib b/camino/BrowserWindow.nib/info.nib index 98ae94ce8056..adea7e7f4098 100644 --- a/camino/BrowserWindow.nib/info.nib +++ b/camino/BrowserWindow.nib/info.nib @@ -19,11 +19,11 @@ 336 630 666 200 132 0 0 1152 848 365 - 22 587 93 162 0 0 1152 848 + 25 719 93 162 0 0 1280 1002 463 7 536 200 180 0 0 1152 848 56 - 404 546 343 68 0 0 1152 848 + 442 634 343 68 0 0 1280 1002 IBFramework Version 248.0 @@ -41,10 +41,6 @@ 497 - IBOpenObjects - - 365 - IBSystem Version 5S60 diff --git a/camino/BrowserWindow.nib/objects.nib b/camino/BrowserWindow.nib/objects.nib index 13992b6b03d4..7bf240f04769 100644 Binary files a/camino/BrowserWindow.nib/objects.nib and b/camino/BrowserWindow.nib/objects.nib differ diff --git a/camino/CHAutoCompleteTextField.h b/camino/CHAutoCompleteTextField.h index e81c818d1bb8..ac0b7da51ee7 100644 --- a/camino/CHAutoCompleteTextField.h +++ b/camino/CHAutoCompleteTextField.h @@ -41,8 +41,12 @@ nsIAutoCompleteResults *mResults; nsIAutoCompleteListener *mListener; - NSString* mSearchString; + 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; NSTimer *mOpenTimer; } @@ -53,15 +57,17 @@ - (NSTableView *) tableView; - (int) visibleRows; -- (void) startSearch:(NSString*)aString; +- (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; diff --git a/camino/CHAutoCompleteTextField.mm b/camino/CHAutoCompleteTextField.mm index 12519e285fef..97ccc75f6b36 100644 --- a/camino/CHAutoCompleteTextField.mm +++ b/camino/CHAutoCompleteTextField.mm @@ -22,6 +22,7 @@ */ #import "CHAutoCompleteTextField.h" +#import "BrowserWindowController.h" #import "CHPageProxyIcon.h" #include "nsIServiceManager.h" #include "nsMemory.h" @@ -69,6 +70,7 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) mSearchString = nil; mBackspaced = NO; + mCompleteResult = NO; mOpenTimer = nil; mSession = nsnull; @@ -143,7 +145,7 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) if (mSearchString) [mSearchString release]; - + [mPopupWin release]; [mDataSource release]; @@ -182,12 +184,14 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) // searching //////////////////////////// -- (void) startSearch:(NSString*)aString +- (void) startSearch:(NSString*)aString complete:(BOOL)aComplete { if (mSearchString) [mSearchString release]; mSearchString = [aString retain]; + mCompleteResult = aComplete; + if ([self isOpen]) { [self performSearch]; } else { @@ -200,11 +204,6 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) mOpenTimer = [[NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(searchTimer:) userInfo:nil repeats:NO] retain]; - - // we need to reset mBackspaced here, or else it might still be true if the user backspaces - // the textfield to be empty, then starts typing, because it is normally reset in selectRowAt - // which won't be called until perhaps after several keystrokes (due to the timer) - mBackspaced = NO; } } @@ -254,6 +253,17 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) [self performSearch]; } +- (void) clearResults +{ + // clear out search data + mSearchString = nil; + mResults = nil; + + [mDataSource setResults:nil]; + + [self closePopup]; +} + // handling the popup ///////////////////////////////// - (void) openPopup @@ -271,6 +281,11 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) 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 @@ -307,12 +322,11 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) PRInt32 defaultRow; mResults->GetDefaultItemIndex(&defaultRow); - if (mBackspaced) { - [self selectRowAt:-1]; - mBackspaced = NO; - } else { + if (mCompleteResult) { [self selectRowAt:defaultRow]; [self completeResult:defaultRow]; + } else { + [self selectRowAt:-1]; } } @@ -327,7 +341,7 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) NSText *text; NSString *result1; - if (aRow < 0) { + if (aRow < 0 && mSearchString) { [self setStringValue:mSearchString]; } else { if ([mDataSource rowCount] <= 0) @@ -351,10 +365,27 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) - (void) enterResult:(int)aRow { - if ([self isOpen] && aRow >= 0) { + if (aRow >= 0 && [mDataSource rowCount] > 0) { [self setStringValue: [mDataSource resultString:[mTableView selectedRow] column:@"col1"]]; [self selectText:self]; [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]; + + [self setStringValue:url]; + [self selectText:self]; } } @@ -362,8 +393,14 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) - (void) selectRowAt:(int)aRow { - [mTableView selectRow:aRow byExtendingSelection:NO]; - [mTableView scrollRowToVisible: 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 @@ -414,11 +451,20 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) [self resizePopup]; } -// NSTextField //////////////////////////////////////////// +// NSTextField delegate ////////////////////////////////// - (void)controlTextDidChange:(NSNotification *)aNotification { - [self startSearch:[self stringValue]]; + NSText *text = [[self window] fieldEditor:NO forObject:self]; + NSRange range = [text selectedRange]; + + // make sure we're typing at the end of the string + if (range.location == [[self stringValue] length]) + [self startSearch:[self stringValue] complete:!mBackspaced]; + else + [self clearResults]; + + mBackspaced = NO; } - (void)controlTextDidEndEditing:(NSNotification *)aNotification @@ -426,8 +472,6 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) [self closePopup]; } -// NSTextField delegate ////////////////////////////////// - - (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command { if (command == @selector(insertNewline:)) { diff --git a/camino/Chimera.pbproj/project.pbxproj b/camino/Chimera.pbproj/project.pbxproj index 4cde1a8b5622..92244868a6e5 100644 --- a/camino/Chimera.pbproj/project.pbxproj +++ b/camino/Chimera.pbproj/project.pbxproj @@ -11,6 +11,7 @@ F517395B020CE3740189DA0C, F528E21A020FD9620168DE43, F5DE10EA0209DC0601A967DF, + F632AF8402B9AEBB01000103, F5DE10EB0209DC0601A967DF, F51B70B7026EC98B01A80166, F5AE04BA0206A4FE01A967DF, @@ -447,6 +448,7 @@ 2E748B74029A448D4B000102, F53E012A02AEE91D01A967F3, F53E013302AEEA2901A967F3, + F632AF8502B9AEBB01000103, ); isa = PBXHeadersBuildPhase; name = Headers; @@ -560,6 +562,7 @@ 2EEC3E64028138724B000102, 2E748B75029A448D4B000102, F53E012D02AEE93701A967F3, + F632AF8602B9AEBC01000103, ); isa = PBXSourcesBuildPhase; name = Sources; @@ -1196,6 +1199,7 @@ F517395A020CE3740189DA0C, F528E218020FD8400168DE43, F5DE10E70209DC0601A967DF, + F632AF8302B9AEBB01000103, F5DE10E80209DC0601A967DF, F51B70B6026EC98B01A80166, F5125A110202064D01FAFD9F, @@ -2006,7 +2010,6 @@ isa = PBXFileReference; path = CHPreferenceManager.mm; refType = 4; - indentWidth = 2; }; F52D5CD9027D3D5001A80166 = { fileRef = F52D5CD7027D3D5001A80166; @@ -6575,6 +6578,28 @@ //F62 //F63 //F64 + F632AF8302B9AEBB01000103 = { + isa = PBXFileReference; + path = BrowserWindow.h; + refType = 4; + }; + F632AF8402B9AEBB01000103 = { + isa = PBXFileReference; + path = BrowserWindow.mm; + refType = 4; + }; + F632AF8502B9AEBB01000103 = { + fileRef = F632AF8302B9AEBB01000103; + isa = PBXBuildFile; + settings = { + }; + }; + F632AF8602B9AEBC01000103 = { + fileRef = F632AF8402B9AEBB01000103; + isa = PBXBuildFile; + settings = { + }; + }; F655020201B480F201A962F7 = { isa = PBXFileReference; name = libnkcache.dylib; diff --git a/camino/English.lproj/BrowserWindow.nib/classes.nib b/camino/English.lproj/BrowserWindow.nib/classes.nib index b4abc1d9ac61..97dfc30f8721 100644 --- a/camino/English.lproj/BrowserWindow.nib/classes.nib +++ b/camino/English.lproj/BrowserWindow.nib/classes.nib @@ -16,7 +16,12 @@ SUPERCLASS = NSObject; }, {CLASS = BookmarksToolbar; LANGUAGE = ObjC; SUPERCLASS = NSView; }, - {CLASS = BrowserWindow; LANGUAGE = ObjC; SUPERCLASS = NSWindow; }, + { + CLASS = BrowserWindow; + LANGUAGE = ObjC; + OUTLETS = {mAutoCompleteTextField = id; }; + SUPERCLASS = NSWindow; + }, { ACTIONS = { back = id; diff --git a/camino/English.lproj/BrowserWindow.nib/info.nib b/camino/English.lproj/BrowserWindow.nib/info.nib index 98ae94ce8056..adea7e7f4098 100644 --- a/camino/English.lproj/BrowserWindow.nib/info.nib +++ b/camino/English.lproj/BrowserWindow.nib/info.nib @@ -19,11 +19,11 @@ 336 630 666 200 132 0 0 1152 848 365 - 22 587 93 162 0 0 1152 848 + 25 719 93 162 0 0 1280 1002 463 7 536 200 180 0 0 1152 848 56 - 404 546 343 68 0 0 1152 848 + 442 634 343 68 0 0 1280 1002 IBFramework Version 248.0 @@ -41,10 +41,6 @@ 497 - IBOpenObjects - - 365 - IBSystem Version 5S60 diff --git a/camino/English.lproj/BrowserWindow.nib/objects.nib b/camino/English.lproj/BrowserWindow.nib/objects.nib index 13992b6b03d4..7bf240f04769 100644 Binary files a/camino/English.lproj/BrowserWindow.nib/objects.nib and b/camino/English.lproj/BrowserWindow.nib/objects.nib differ diff --git a/camino/projects/Chimera.pbproj/project.pbxproj b/camino/projects/Chimera.pbproj/project.pbxproj index 4cde1a8b5622..92244868a6e5 100644 --- a/camino/projects/Chimera.pbproj/project.pbxproj +++ b/camino/projects/Chimera.pbproj/project.pbxproj @@ -11,6 +11,7 @@ F517395B020CE3740189DA0C, F528E21A020FD9620168DE43, F5DE10EA0209DC0601A967DF, + F632AF8402B9AEBB01000103, F5DE10EB0209DC0601A967DF, F51B70B7026EC98B01A80166, F5AE04BA0206A4FE01A967DF, @@ -447,6 +448,7 @@ 2E748B74029A448D4B000102, F53E012A02AEE91D01A967F3, F53E013302AEEA2901A967F3, + F632AF8502B9AEBB01000103, ); isa = PBXHeadersBuildPhase; name = Headers; @@ -560,6 +562,7 @@ 2EEC3E64028138724B000102, 2E748B75029A448D4B000102, F53E012D02AEE93701A967F3, + F632AF8602B9AEBC01000103, ); isa = PBXSourcesBuildPhase; name = Sources; @@ -1196,6 +1199,7 @@ F517395A020CE3740189DA0C, F528E218020FD8400168DE43, F5DE10E70209DC0601A967DF, + F632AF8302B9AEBB01000103, F5DE10E80209DC0601A967DF, F51B70B6026EC98B01A80166, F5125A110202064D01FAFD9F, @@ -2006,7 +2010,6 @@ isa = PBXFileReference; path = CHPreferenceManager.mm; refType = 4; - indentWidth = 2; }; F52D5CD9027D3D5001A80166 = { fileRef = F52D5CD7027D3D5001A80166; @@ -6575,6 +6578,28 @@ //F62 //F63 //F64 + F632AF8302B9AEBB01000103 = { + isa = PBXFileReference; + path = BrowserWindow.h; + refType = 4; + }; + F632AF8402B9AEBB01000103 = { + isa = PBXFileReference; + path = BrowserWindow.mm; + refType = 4; + }; + F632AF8502B9AEBB01000103 = { + fileRef = F632AF8302B9AEBB01000103; + isa = PBXBuildFile; + settings = { + }; + }; + F632AF8602B9AEBC01000103 = { + fileRef = F632AF8402B9AEBB01000103; + isa = PBXBuildFile; + settings = { + }; + }; F655020201B480F201A962F7 = { isa = PBXFileReference; name = libnkcache.dylib; diff --git a/camino/resources/localized/English.lproj/BrowserWindow.nib/classes.nib b/camino/resources/localized/English.lproj/BrowserWindow.nib/classes.nib index b4abc1d9ac61..97dfc30f8721 100644 --- a/camino/resources/localized/English.lproj/BrowserWindow.nib/classes.nib +++ b/camino/resources/localized/English.lproj/BrowserWindow.nib/classes.nib @@ -16,7 +16,12 @@ SUPERCLASS = NSObject; }, {CLASS = BookmarksToolbar; LANGUAGE = ObjC; SUPERCLASS = NSView; }, - {CLASS = BrowserWindow; LANGUAGE = ObjC; SUPERCLASS = NSWindow; }, + { + CLASS = BrowserWindow; + LANGUAGE = ObjC; + OUTLETS = {mAutoCompleteTextField = id; }; + SUPERCLASS = NSWindow; + }, { ACTIONS = { back = id; diff --git a/camino/resources/localized/English.lproj/BrowserWindow.nib/info.nib b/camino/resources/localized/English.lproj/BrowserWindow.nib/info.nib index 98ae94ce8056..adea7e7f4098 100644 --- a/camino/resources/localized/English.lproj/BrowserWindow.nib/info.nib +++ b/camino/resources/localized/English.lproj/BrowserWindow.nib/info.nib @@ -19,11 +19,11 @@ 336 630 666 200 132 0 0 1152 848 365 - 22 587 93 162 0 0 1152 848 + 25 719 93 162 0 0 1280 1002 463 7 536 200 180 0 0 1152 848 56 - 404 546 343 68 0 0 1152 848 + 442 634 343 68 0 0 1280 1002 IBFramework Version 248.0 @@ -41,10 +41,6 @@ 497 - IBOpenObjects - - 365 - IBSystem Version 5S60 diff --git a/camino/resources/localized/English.lproj/BrowserWindow.nib/objects.nib b/camino/resources/localized/English.lproj/BrowserWindow.nib/objects.nib index 13992b6b03d4..7bf240f04769 100644 Binary files a/camino/resources/localized/English.lproj/BrowserWindow.nib/objects.nib and b/camino/resources/localized/English.lproj/BrowserWindow.nib/objects.nib differ diff --git a/camino/src/browser/AutoCompleteTextField.h b/camino/src/browser/AutoCompleteTextField.h index e81c818d1bb8..ac0b7da51ee7 100644 --- a/camino/src/browser/AutoCompleteTextField.h +++ b/camino/src/browser/AutoCompleteTextField.h @@ -41,8 +41,12 @@ nsIAutoCompleteResults *mResults; nsIAutoCompleteListener *mListener; - NSString* mSearchString; + 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; NSTimer *mOpenTimer; } @@ -53,15 +57,17 @@ - (NSTableView *) tableView; - (int) visibleRows; -- (void) startSearch:(NSString*)aString; +- (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; diff --git a/camino/src/browser/AutoCompleteTextField.mm b/camino/src/browser/AutoCompleteTextField.mm index 12519e285fef..97ccc75f6b36 100644 --- a/camino/src/browser/AutoCompleteTextField.mm +++ b/camino/src/browser/AutoCompleteTextField.mm @@ -22,6 +22,7 @@ */ #import "CHAutoCompleteTextField.h" +#import "BrowserWindowController.h" #import "CHPageProxyIcon.h" #include "nsIServiceManager.h" #include "nsMemory.h" @@ -69,6 +70,7 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) mSearchString = nil; mBackspaced = NO; + mCompleteResult = NO; mOpenTimer = nil; mSession = nsnull; @@ -143,7 +145,7 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) if (mSearchString) [mSearchString release]; - + [mPopupWin release]; [mDataSource release]; @@ -182,12 +184,14 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) // searching //////////////////////////// -- (void) startSearch:(NSString*)aString +- (void) startSearch:(NSString*)aString complete:(BOOL)aComplete { if (mSearchString) [mSearchString release]; mSearchString = [aString retain]; + mCompleteResult = aComplete; + if ([self isOpen]) { [self performSearch]; } else { @@ -200,11 +204,6 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) mOpenTimer = [[NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(searchTimer:) userInfo:nil repeats:NO] retain]; - - // we need to reset mBackspaced here, or else it might still be true if the user backspaces - // the textfield to be empty, then starts typing, because it is normally reset in selectRowAt - // which won't be called until perhaps after several keystrokes (due to the timer) - mBackspaced = NO; } } @@ -254,6 +253,17 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) [self performSearch]; } +- (void) clearResults +{ + // clear out search data + mSearchString = nil; + mResults = nil; + + [mDataSource setResults:nil]; + + [self closePopup]; +} + // handling the popup ///////////////////////////////// - (void) openPopup @@ -271,6 +281,11 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) 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 @@ -307,12 +322,11 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) PRInt32 defaultRow; mResults->GetDefaultItemIndex(&defaultRow); - if (mBackspaced) { - [self selectRowAt:-1]; - mBackspaced = NO; - } else { + if (mCompleteResult) { [self selectRowAt:defaultRow]; [self completeResult:defaultRow]; + } else { + [self selectRowAt:-1]; } } @@ -327,7 +341,7 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) NSText *text; NSString *result1; - if (aRow < 0) { + if (aRow < 0 && mSearchString) { [self setStringValue:mSearchString]; } else { if ([mDataSource rowCount] <= 0) @@ -351,10 +365,27 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) - (void) enterResult:(int)aRow { - if ([self isOpen] && aRow >= 0) { + if (aRow >= 0 && [mDataSource rowCount] > 0) { [self setStringValue: [mDataSource resultString:[mTableView selectedRow] column:@"col1"]]; [self selectText:self]; [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]; + + [self setStringValue:url]; + [self selectText:self]; } } @@ -362,8 +393,14 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) - (void) selectRowAt:(int)aRow { - [mTableView selectRow:aRow byExtendingSelection:NO]; - [mTableView scrollRowToVisible: 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 @@ -414,11 +451,20 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) [self resizePopup]; } -// NSTextField //////////////////////////////////////////// +// NSTextField delegate ////////////////////////////////// - (void)controlTextDidChange:(NSNotification *)aNotification { - [self startSearch:[self stringValue]]; + NSText *text = [[self window] fieldEditor:NO forObject:self]; + NSRange range = [text selectedRange]; + + // make sure we're typing at the end of the string + if (range.location == [[self stringValue] length]) + [self startSearch:[self stringValue] complete:!mBackspaced]; + else + [self clearResults]; + + mBackspaced = NO; } - (void)controlTextDidEndEditing:(NSNotification *)aNotification @@ -426,8 +472,6 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) [self closePopup]; } -// NSTextField delegate ////////////////////////////////// - - (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command { if (command == @selector(insertNewline:)) { diff --git a/camino/src/browser/BrowserWindow.h b/camino/src/browser/BrowserWindow.h new file mode 100644 index 000000000000..8eb4cd63f876 --- /dev/null +++ b/camino/src/browser/BrowserWindow.h @@ -0,0 +1,9 @@ +/* BrowserWindow */ + +#import + +@interface BrowserWindow : NSWindow +{ + IBOutlet id mAutoCompleteTextField; +} +@end diff --git a/camino/src/browser/BrowserWindow.mm b/camino/src/browser/BrowserWindow.mm new file mode 100644 index 000000000000..18cc910af98b --- /dev/null +++ b/camino/src/browser/BrowserWindow.mm @@ -0,0 +1,22 @@ +#import "BrowserWindow.h" +#import "CHAutoCompleteTextField.h" + +static const int kEscapeKeyCode = 53; + +@implementation BrowserWindow + +- (void)sendEvent:(NSEvent *)theEvent +{ + // We need this hack because NSWindow::sendEvent will eat the escape key + // and won't pass it down to the key handler of responders in the window. + // We have to override sendEvent for all of our escape key needs. + if ([theEvent keyCode] == kEscapeKeyCode && [theEvent type] == NSKeyDown) { + NSText *fieldEditor = [self fieldEditor:NO forObject:mAutoCompleteTextField]; + if (fieldEditor && [self firstResponder] == fieldEditor) { + [mAutoCompleteTextField revertText]; + } + } else + [super sendEvent:theEvent]; +} + +@end diff --git a/chimera/BrowserWindow.h b/chimera/BrowserWindow.h new file mode 100644 index 000000000000..8eb4cd63f876 --- /dev/null +++ b/chimera/BrowserWindow.h @@ -0,0 +1,9 @@ +/* BrowserWindow */ + +#import + +@interface BrowserWindow : NSWindow +{ + IBOutlet id mAutoCompleteTextField; +} +@end diff --git a/chimera/BrowserWindow.mm b/chimera/BrowserWindow.mm new file mode 100644 index 000000000000..18cc910af98b --- /dev/null +++ b/chimera/BrowserWindow.mm @@ -0,0 +1,22 @@ +#import "BrowserWindow.h" +#import "CHAutoCompleteTextField.h" + +static const int kEscapeKeyCode = 53; + +@implementation BrowserWindow + +- (void)sendEvent:(NSEvent *)theEvent +{ + // We need this hack because NSWindow::sendEvent will eat the escape key + // and won't pass it down to the key handler of responders in the window. + // We have to override sendEvent for all of our escape key needs. + if ([theEvent keyCode] == kEscapeKeyCode && [theEvent type] == NSKeyDown) { + NSText *fieldEditor = [self fieldEditor:NO forObject:mAutoCompleteTextField]; + if (fieldEditor && [self firstResponder] == fieldEditor) { + [mAutoCompleteTextField revertText]; + } + } else + [super sendEvent:theEvent]; +} + +@end diff --git a/chimera/BrowserWindow.nib/classes.nib b/chimera/BrowserWindow.nib/classes.nib index b4abc1d9ac61..97dfc30f8721 100644 --- a/chimera/BrowserWindow.nib/classes.nib +++ b/chimera/BrowserWindow.nib/classes.nib @@ -16,7 +16,12 @@ SUPERCLASS = NSObject; }, {CLASS = BookmarksToolbar; LANGUAGE = ObjC; SUPERCLASS = NSView; }, - {CLASS = BrowserWindow; LANGUAGE = ObjC; SUPERCLASS = NSWindow; }, + { + CLASS = BrowserWindow; + LANGUAGE = ObjC; + OUTLETS = {mAutoCompleteTextField = id; }; + SUPERCLASS = NSWindow; + }, { ACTIONS = { back = id; diff --git a/chimera/BrowserWindow.nib/info.nib b/chimera/BrowserWindow.nib/info.nib index 98ae94ce8056..adea7e7f4098 100644 --- a/chimera/BrowserWindow.nib/info.nib +++ b/chimera/BrowserWindow.nib/info.nib @@ -19,11 +19,11 @@ 336 630 666 200 132 0 0 1152 848 365 - 22 587 93 162 0 0 1152 848 + 25 719 93 162 0 0 1280 1002 463 7 536 200 180 0 0 1152 848 56 - 404 546 343 68 0 0 1152 848 + 442 634 343 68 0 0 1280 1002 IBFramework Version 248.0 @@ -41,10 +41,6 @@ 497 - IBOpenObjects - - 365 - IBSystem Version 5S60 diff --git a/chimera/BrowserWindow.nib/objects.nib b/chimera/BrowserWindow.nib/objects.nib index 13992b6b03d4..7bf240f04769 100644 Binary files a/chimera/BrowserWindow.nib/objects.nib and b/chimera/BrowserWindow.nib/objects.nib differ diff --git a/chimera/CHAutoCompleteTextField.h b/chimera/CHAutoCompleteTextField.h index e81c818d1bb8..ac0b7da51ee7 100644 --- a/chimera/CHAutoCompleteTextField.h +++ b/chimera/CHAutoCompleteTextField.h @@ -41,8 +41,12 @@ nsIAutoCompleteResults *mResults; nsIAutoCompleteListener *mListener; - NSString* mSearchString; + 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; NSTimer *mOpenTimer; } @@ -53,15 +57,17 @@ - (NSTableView *) tableView; - (int) visibleRows; -- (void) startSearch:(NSString*)aString; +- (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; diff --git a/chimera/CHAutoCompleteTextField.mm b/chimera/CHAutoCompleteTextField.mm index 12519e285fef..97ccc75f6b36 100644 --- a/chimera/CHAutoCompleteTextField.mm +++ b/chimera/CHAutoCompleteTextField.mm @@ -22,6 +22,7 @@ */ #import "CHAutoCompleteTextField.h" +#import "BrowserWindowController.h" #import "CHPageProxyIcon.h" #include "nsIServiceManager.h" #include "nsMemory.h" @@ -69,6 +70,7 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) mSearchString = nil; mBackspaced = NO; + mCompleteResult = NO; mOpenTimer = nil; mSession = nsnull; @@ -143,7 +145,7 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) if (mSearchString) [mSearchString release]; - + [mPopupWin release]; [mDataSource release]; @@ -182,12 +184,14 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) // searching //////////////////////////// -- (void) startSearch:(NSString*)aString +- (void) startSearch:(NSString*)aString complete:(BOOL)aComplete { if (mSearchString) [mSearchString release]; mSearchString = [aString retain]; + mCompleteResult = aComplete; + if ([self isOpen]) { [self performSearch]; } else { @@ -200,11 +204,6 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) mOpenTimer = [[NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(searchTimer:) userInfo:nil repeats:NO] retain]; - - // we need to reset mBackspaced here, or else it might still be true if the user backspaces - // the textfield to be empty, then starts typing, because it is normally reset in selectRowAt - // which won't be called until perhaps after several keystrokes (due to the timer) - mBackspaced = NO; } } @@ -254,6 +253,17 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) [self performSearch]; } +- (void) clearResults +{ + // clear out search data + mSearchString = nil; + mResults = nil; + + [mDataSource setResults:nil]; + + [self closePopup]; +} + // handling the popup ///////////////////////////////// - (void) openPopup @@ -271,6 +281,11 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) 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 @@ -307,12 +322,11 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) PRInt32 defaultRow; mResults->GetDefaultItemIndex(&defaultRow); - if (mBackspaced) { - [self selectRowAt:-1]; - mBackspaced = NO; - } else { + if (mCompleteResult) { [self selectRowAt:defaultRow]; [self completeResult:defaultRow]; + } else { + [self selectRowAt:-1]; } } @@ -327,7 +341,7 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) NSText *text; NSString *result1; - if (aRow < 0) { + if (aRow < 0 && mSearchString) { [self setStringValue:mSearchString]; } else { if ([mDataSource rowCount] <= 0) @@ -351,10 +365,27 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) - (void) enterResult:(int)aRow { - if ([self isOpen] && aRow >= 0) { + if (aRow >= 0 && [mDataSource rowCount] > 0) { [self setStringValue: [mDataSource resultString:[mTableView selectedRow] column:@"col1"]]; [self selectText:self]; [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]; + + [self setStringValue:url]; + [self selectText:self]; } } @@ -362,8 +393,14 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) - (void) selectRowAt:(int)aRow { - [mTableView selectRow:aRow byExtendingSelection:NO]; - [mTableView scrollRowToVisible: 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 @@ -414,11 +451,20 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) [self resizePopup]; } -// NSTextField //////////////////////////////////////////// +// NSTextField delegate ////////////////////////////////// - (void)controlTextDidChange:(NSNotification *)aNotification { - [self startSearch:[self stringValue]]; + NSText *text = [[self window] fieldEditor:NO forObject:self]; + NSRange range = [text selectedRange]; + + // make sure we're typing at the end of the string + if (range.location == [[self stringValue] length]) + [self startSearch:[self stringValue] complete:!mBackspaced]; + else + [self clearResults]; + + mBackspaced = NO; } - (void)controlTextDidEndEditing:(NSNotification *)aNotification @@ -426,8 +472,6 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) [self closePopup]; } -// NSTextField delegate ////////////////////////////////// - - (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command { if (command == @selector(insertNewline:)) { diff --git a/chimera/Chimera.pbproj/project.pbxproj b/chimera/Chimera.pbproj/project.pbxproj index 4cde1a8b5622..92244868a6e5 100644 --- a/chimera/Chimera.pbproj/project.pbxproj +++ b/chimera/Chimera.pbproj/project.pbxproj @@ -11,6 +11,7 @@ F517395B020CE3740189DA0C, F528E21A020FD9620168DE43, F5DE10EA0209DC0601A967DF, + F632AF8402B9AEBB01000103, F5DE10EB0209DC0601A967DF, F51B70B7026EC98B01A80166, F5AE04BA0206A4FE01A967DF, @@ -447,6 +448,7 @@ 2E748B74029A448D4B000102, F53E012A02AEE91D01A967F3, F53E013302AEEA2901A967F3, + F632AF8502B9AEBB01000103, ); isa = PBXHeadersBuildPhase; name = Headers; @@ -560,6 +562,7 @@ 2EEC3E64028138724B000102, 2E748B75029A448D4B000102, F53E012D02AEE93701A967F3, + F632AF8602B9AEBC01000103, ); isa = PBXSourcesBuildPhase; name = Sources; @@ -1196,6 +1199,7 @@ F517395A020CE3740189DA0C, F528E218020FD8400168DE43, F5DE10E70209DC0601A967DF, + F632AF8302B9AEBB01000103, F5DE10E80209DC0601A967DF, F51B70B6026EC98B01A80166, F5125A110202064D01FAFD9F, @@ -2006,7 +2010,6 @@ isa = PBXFileReference; path = CHPreferenceManager.mm; refType = 4; - indentWidth = 2; }; F52D5CD9027D3D5001A80166 = { fileRef = F52D5CD7027D3D5001A80166; @@ -6575,6 +6578,28 @@ //F62 //F63 //F64 + F632AF8302B9AEBB01000103 = { + isa = PBXFileReference; + path = BrowserWindow.h; + refType = 4; + }; + F632AF8402B9AEBB01000103 = { + isa = PBXFileReference; + path = BrowserWindow.mm; + refType = 4; + }; + F632AF8502B9AEBB01000103 = { + fileRef = F632AF8302B9AEBB01000103; + isa = PBXBuildFile; + settings = { + }; + }; + F632AF8602B9AEBC01000103 = { + fileRef = F632AF8402B9AEBB01000103; + isa = PBXBuildFile; + settings = { + }; + }; F655020201B480F201A962F7 = { isa = PBXFileReference; name = libnkcache.dylib; diff --git a/chimera/English.lproj/BrowserWindow.nib/classes.nib b/chimera/English.lproj/BrowserWindow.nib/classes.nib index b4abc1d9ac61..97dfc30f8721 100644 --- a/chimera/English.lproj/BrowserWindow.nib/classes.nib +++ b/chimera/English.lproj/BrowserWindow.nib/classes.nib @@ -16,7 +16,12 @@ SUPERCLASS = NSObject; }, {CLASS = BookmarksToolbar; LANGUAGE = ObjC; SUPERCLASS = NSView; }, - {CLASS = BrowserWindow; LANGUAGE = ObjC; SUPERCLASS = NSWindow; }, + { + CLASS = BrowserWindow; + LANGUAGE = ObjC; + OUTLETS = {mAutoCompleteTextField = id; }; + SUPERCLASS = NSWindow; + }, { ACTIONS = { back = id; diff --git a/chimera/English.lproj/BrowserWindow.nib/info.nib b/chimera/English.lproj/BrowserWindow.nib/info.nib index 98ae94ce8056..adea7e7f4098 100644 --- a/chimera/English.lproj/BrowserWindow.nib/info.nib +++ b/chimera/English.lproj/BrowserWindow.nib/info.nib @@ -19,11 +19,11 @@ 336 630 666 200 132 0 0 1152 848 365 - 22 587 93 162 0 0 1152 848 + 25 719 93 162 0 0 1280 1002 463 7 536 200 180 0 0 1152 848 56 - 404 546 343 68 0 0 1152 848 + 442 634 343 68 0 0 1280 1002 IBFramework Version 248.0 @@ -41,10 +41,6 @@ 497 - IBOpenObjects - - 365 - IBSystem Version 5S60 diff --git a/chimera/English.lproj/BrowserWindow.nib/objects.nib b/chimera/English.lproj/BrowserWindow.nib/objects.nib index 13992b6b03d4..7bf240f04769 100644 Binary files a/chimera/English.lproj/BrowserWindow.nib/objects.nib and b/chimera/English.lproj/BrowserWindow.nib/objects.nib differ diff --git a/chimera/projects/Chimera.pbproj/project.pbxproj b/chimera/projects/Chimera.pbproj/project.pbxproj index 4cde1a8b5622..92244868a6e5 100644 --- a/chimera/projects/Chimera.pbproj/project.pbxproj +++ b/chimera/projects/Chimera.pbproj/project.pbxproj @@ -11,6 +11,7 @@ F517395B020CE3740189DA0C, F528E21A020FD9620168DE43, F5DE10EA0209DC0601A967DF, + F632AF8402B9AEBB01000103, F5DE10EB0209DC0601A967DF, F51B70B7026EC98B01A80166, F5AE04BA0206A4FE01A967DF, @@ -447,6 +448,7 @@ 2E748B74029A448D4B000102, F53E012A02AEE91D01A967F3, F53E013302AEEA2901A967F3, + F632AF8502B9AEBB01000103, ); isa = PBXHeadersBuildPhase; name = Headers; @@ -560,6 +562,7 @@ 2EEC3E64028138724B000102, 2E748B75029A448D4B000102, F53E012D02AEE93701A967F3, + F632AF8602B9AEBC01000103, ); isa = PBXSourcesBuildPhase; name = Sources; @@ -1196,6 +1199,7 @@ F517395A020CE3740189DA0C, F528E218020FD8400168DE43, F5DE10E70209DC0601A967DF, + F632AF8302B9AEBB01000103, F5DE10E80209DC0601A967DF, F51B70B6026EC98B01A80166, F5125A110202064D01FAFD9F, @@ -2006,7 +2010,6 @@ isa = PBXFileReference; path = CHPreferenceManager.mm; refType = 4; - indentWidth = 2; }; F52D5CD9027D3D5001A80166 = { fileRef = F52D5CD7027D3D5001A80166; @@ -6575,6 +6578,28 @@ //F62 //F63 //F64 + F632AF8302B9AEBB01000103 = { + isa = PBXFileReference; + path = BrowserWindow.h; + refType = 4; + }; + F632AF8402B9AEBB01000103 = { + isa = PBXFileReference; + path = BrowserWindow.mm; + refType = 4; + }; + F632AF8502B9AEBB01000103 = { + fileRef = F632AF8302B9AEBB01000103; + isa = PBXBuildFile; + settings = { + }; + }; + F632AF8602B9AEBC01000103 = { + fileRef = F632AF8402B9AEBB01000103; + isa = PBXBuildFile; + settings = { + }; + }; F655020201B480F201A962F7 = { isa = PBXFileReference; name = libnkcache.dylib; diff --git a/chimera/resources/localized/English.lproj/BrowserWindow.nib/classes.nib b/chimera/resources/localized/English.lproj/BrowserWindow.nib/classes.nib index b4abc1d9ac61..97dfc30f8721 100644 --- a/chimera/resources/localized/English.lproj/BrowserWindow.nib/classes.nib +++ b/chimera/resources/localized/English.lproj/BrowserWindow.nib/classes.nib @@ -16,7 +16,12 @@ SUPERCLASS = NSObject; }, {CLASS = BookmarksToolbar; LANGUAGE = ObjC; SUPERCLASS = NSView; }, - {CLASS = BrowserWindow; LANGUAGE = ObjC; SUPERCLASS = NSWindow; }, + { + CLASS = BrowserWindow; + LANGUAGE = ObjC; + OUTLETS = {mAutoCompleteTextField = id; }; + SUPERCLASS = NSWindow; + }, { ACTIONS = { back = id; diff --git a/chimera/resources/localized/English.lproj/BrowserWindow.nib/info.nib b/chimera/resources/localized/English.lproj/BrowserWindow.nib/info.nib index 98ae94ce8056..adea7e7f4098 100644 --- a/chimera/resources/localized/English.lproj/BrowserWindow.nib/info.nib +++ b/chimera/resources/localized/English.lproj/BrowserWindow.nib/info.nib @@ -19,11 +19,11 @@ 336 630 666 200 132 0 0 1152 848 365 - 22 587 93 162 0 0 1152 848 + 25 719 93 162 0 0 1280 1002 463 7 536 200 180 0 0 1152 848 56 - 404 546 343 68 0 0 1152 848 + 442 634 343 68 0 0 1280 1002 IBFramework Version 248.0 @@ -41,10 +41,6 @@ 497 - IBOpenObjects - - 365 - IBSystem Version 5S60 diff --git a/chimera/resources/localized/English.lproj/BrowserWindow.nib/objects.nib b/chimera/resources/localized/English.lproj/BrowserWindow.nib/objects.nib index 13992b6b03d4..7bf240f04769 100644 Binary files a/chimera/resources/localized/English.lproj/BrowserWindow.nib/objects.nib and b/chimera/resources/localized/English.lproj/BrowserWindow.nib/objects.nib differ diff --git a/chimera/src/browser/AutoCompleteTextField.h b/chimera/src/browser/AutoCompleteTextField.h index e81c818d1bb8..ac0b7da51ee7 100644 --- a/chimera/src/browser/AutoCompleteTextField.h +++ b/chimera/src/browser/AutoCompleteTextField.h @@ -41,8 +41,12 @@ nsIAutoCompleteResults *mResults; nsIAutoCompleteListener *mListener; - NSString* mSearchString; + 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; NSTimer *mOpenTimer; } @@ -53,15 +57,17 @@ - (NSTableView *) tableView; - (int) visibleRows; -- (void) startSearch:(NSString*)aString; +- (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; diff --git a/chimera/src/browser/AutoCompleteTextField.mm b/chimera/src/browser/AutoCompleteTextField.mm index 12519e285fef..97ccc75f6b36 100644 --- a/chimera/src/browser/AutoCompleteTextField.mm +++ b/chimera/src/browser/AutoCompleteTextField.mm @@ -22,6 +22,7 @@ */ #import "CHAutoCompleteTextField.h" +#import "BrowserWindowController.h" #import "CHPageProxyIcon.h" #include "nsIServiceManager.h" #include "nsMemory.h" @@ -69,6 +70,7 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) mSearchString = nil; mBackspaced = NO; + mCompleteResult = NO; mOpenTimer = nil; mSession = nsnull; @@ -143,7 +145,7 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) if (mSearchString) [mSearchString release]; - + [mPopupWin release]; [mDataSource release]; @@ -182,12 +184,14 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) // searching //////////////////////////// -- (void) startSearch:(NSString*)aString +- (void) startSearch:(NSString*)aString complete:(BOOL)aComplete { if (mSearchString) [mSearchString release]; mSearchString = [aString retain]; + mCompleteResult = aComplete; + if ([self isOpen]) { [self performSearch]; } else { @@ -200,11 +204,6 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) mOpenTimer = [[NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(searchTimer:) userInfo:nil repeats:NO] retain]; - - // we need to reset mBackspaced here, or else it might still be true if the user backspaces - // the textfield to be empty, then starts typing, because it is normally reset in selectRowAt - // which won't be called until perhaps after several keystrokes (due to the timer) - mBackspaced = NO; } } @@ -254,6 +253,17 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) [self performSearch]; } +- (void) clearResults +{ + // clear out search data + mSearchString = nil; + mResults = nil; + + [mDataSource setResults:nil]; + + [self closePopup]; +} + // handling the popup ///////////////////////////////// - (void) openPopup @@ -271,6 +281,11 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) 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 @@ -307,12 +322,11 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) PRInt32 defaultRow; mResults->GetDefaultItemIndex(&defaultRow); - if (mBackspaced) { - [self selectRowAt:-1]; - mBackspaced = NO; - } else { + if (mCompleteResult) { [self selectRowAt:defaultRow]; [self completeResult:defaultRow]; + } else { + [self selectRowAt:-1]; } } @@ -327,7 +341,7 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) NSText *text; NSString *result1; - if (aRow < 0) { + if (aRow < 0 && mSearchString) { [self setStringValue:mSearchString]; } else { if ([mDataSource rowCount] <= 0) @@ -351,10 +365,27 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) - (void) enterResult:(int)aRow { - if ([self isOpen] && aRow >= 0) { + if (aRow >= 0 && [mDataSource rowCount] > 0) { [self setStringValue: [mDataSource resultString:[mTableView selectedRow] column:@"col1"]]; [self selectText:self]; [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]; + + [self setStringValue:url]; + [self selectText:self]; } } @@ -362,8 +393,14 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) - (void) selectRowAt:(int)aRow { - [mTableView selectRow:aRow byExtendingSelection:NO]; - [mTableView scrollRowToVisible: 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 @@ -414,11 +451,20 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) [self resizePopup]; } -// NSTextField //////////////////////////////////////////// +// NSTextField delegate ////////////////////////////////// - (void)controlTextDidChange:(NSNotification *)aNotification { - [self startSearch:[self stringValue]]; + NSText *text = [[self window] fieldEditor:NO forObject:self]; + NSRange range = [text selectedRange]; + + // make sure we're typing at the end of the string + if (range.location == [[self stringValue] length]) + [self startSearch:[self stringValue] complete:!mBackspaced]; + else + [self clearResults]; + + mBackspaced = NO; } - (void)controlTextDidEndEditing:(NSNotification *)aNotification @@ -426,8 +472,6 @@ NS_IMPL_ISUPPORTS1(AutoCompleteListener, nsIAutoCompleteListener) [self closePopup]; } -// NSTextField delegate ////////////////////////////////// - - (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command { if (command == @selector(insertNewline:)) { diff --git a/chimera/src/browser/BrowserWindow.h b/chimera/src/browser/BrowserWindow.h new file mode 100644 index 000000000000..8eb4cd63f876 --- /dev/null +++ b/chimera/src/browser/BrowserWindow.h @@ -0,0 +1,9 @@ +/* BrowserWindow */ + +#import + +@interface BrowserWindow : NSWindow +{ + IBOutlet id mAutoCompleteTextField; +} +@end diff --git a/chimera/src/browser/BrowserWindow.mm b/chimera/src/browser/BrowserWindow.mm new file mode 100644 index 000000000000..18cc910af98b --- /dev/null +++ b/chimera/src/browser/BrowserWindow.mm @@ -0,0 +1,22 @@ +#import "BrowserWindow.h" +#import "CHAutoCompleteTextField.h" + +static const int kEscapeKeyCode = 53; + +@implementation BrowserWindow + +- (void)sendEvent:(NSEvent *)theEvent +{ + // We need this hack because NSWindow::sendEvent will eat the escape key + // and won't pass it down to the key handler of responders in the window. + // We have to override sendEvent for all of our escape key needs. + if ([theEvent keyCode] == kEscapeKeyCode && [theEvent type] == NSKeyDown) { + NSText *fieldEditor = [self fieldEditor:NO forObject:mAutoCompleteTextField]; + if (fieldEditor && [self firstResponder] == fieldEditor) { + [mAutoCompleteTextField revertText]; + } + } else + [super sendEvent:theEvent]; +} + +@end