From d8e9c91f642ab8b1da73257d0de610b19cecb149 Mon Sep 17 00:00:00 2001 From: "hewitt%netscape.com" Date: Tue, 28 May 2002 09:07:53 +0000 Subject: [PATCH] 145802 - session history in Go menu for Chimera, 145803 - urlbar autocomplete for chimera --- camino/BrowserWindow.nib/classes.nib | 9 +- camino/BrowserWindow.nib/info.nib | 8 +- camino/BrowserWindow.nib/objects.nib | Bin 16892 -> 16669 bytes camino/CHAutoCompleteDataSource.h | 27 +- camino/CHAutoCompleteDataSource.mm | 93 +++- camino/CHAutoCompleteTableView.mm | 68 --- camino/CHAutoCompleteTextField.h | 76 +++ camino/CHAutoCompleteTextField.mm | 447 ++++++++++++++++++ .../{CHAutoCompleteTableView.h => CHGoMenu.h} | 18 +- camino/CHGoMenu.mm | 147 ++++++ camino/Chimera.pbproj/project.pbxproj | 30 +- .../BrowserWindow.nib/classes.nib | 9 +- .../English.lproj/BrowserWindow.nib/info.nib | 8 +- .../BrowserWindow.nib/objects.nib | Bin 16892 -> 16669 bytes camino/English.lproj/MainMenu.nib/classes.nib | 1 + camino/English.lproj/MainMenu.nib/objects.nib | Bin 9279 -> 9317 bytes camino/MainMenu.nib/classes.nib | 1 + camino/MainMenu.nib/objects.nib | Bin 9279 -> 9317 bytes .../projects/Chimera.pbproj/project.pbxproj | 30 +- .../BrowserWindow.nib/classes.nib | 9 +- .../English.lproj/BrowserWindow.nib/info.nib | 8 +- .../BrowserWindow.nib/objects.nib | Bin 16892 -> 16669 bytes .../English.lproj/MainMenu.nib/classes.nib | 1 + .../English.lproj/MainMenu.nib/objects.nib | Bin 9279 -> 9317 bytes camino/src/browser/AutoCompleteDataSource.h | 27 +- camino/src/browser/AutoCompleteDataSource.mm | 93 +++- camino/src/browser/AutoCompleteTextField.h | 76 +++ camino/src/browser/AutoCompleteTextField.mm | 447 ++++++++++++++++++ .../src/browser/GoMenu.h | 18 +- camino/src/browser/GoMenu.mm | 147 ++++++ chimera/BrowserWindow.nib/classes.nib | 9 +- chimera/BrowserWindow.nib/info.nib | 8 +- chimera/BrowserWindow.nib/objects.nib | Bin 16892 -> 16669 bytes chimera/CHAutoCompleteDataSource.h | 27 +- chimera/CHAutoCompleteDataSource.mm | 93 +++- chimera/CHAutoCompleteTableView.mm | 68 --- chimera/CHAutoCompleteTextField.h | 76 +++ chimera/CHAutoCompleteTextField.mm | 447 ++++++++++++++++++ chimera/CHGoMenu.h | 36 ++ chimera/CHGoMenu.mm | 147 ++++++ chimera/Chimera.pbproj/project.pbxproj | 30 +- .../BrowserWindow.nib/classes.nib | 9 +- .../English.lproj/BrowserWindow.nib/info.nib | 8 +- .../BrowserWindow.nib/objects.nib | Bin 16892 -> 16669 bytes .../English.lproj/MainMenu.nib/classes.nib | 1 + .../English.lproj/MainMenu.nib/objects.nib | Bin 9279 -> 9317 bytes chimera/MainMenu.nib/classes.nib | 1 + chimera/MainMenu.nib/objects.nib | Bin 9279 -> 9317 bytes .../projects/Chimera.pbproj/project.pbxproj | 30 +- .../BrowserWindow.nib/classes.nib | 9 +- .../English.lproj/BrowserWindow.nib/info.nib | 8 +- .../BrowserWindow.nib/objects.nib | Bin 16892 -> 16669 bytes .../English.lproj/MainMenu.nib/classes.nib | 1 + .../English.lproj/MainMenu.nib/objects.nib | Bin 9279 -> 9317 bytes chimera/src/browser/AutoCompleteDataSource.h | 27 +- chimera/src/browser/AutoCompleteDataSource.mm | 93 +++- chimera/src/browser/AutoCompleteTextField.h | 76 +++ chimera/src/browser/AutoCompleteTextField.mm | 447 ++++++++++++++++++ chimera/src/browser/GoMenu.h | 36 ++ chimera/src/browser/GoMenu.mm | 147 ++++++ 60 files changed, 3352 insertions(+), 280 deletions(-) delete mode 100644 camino/CHAutoCompleteTableView.mm create mode 100644 camino/CHAutoCompleteTextField.h create mode 100644 camino/CHAutoCompleteTextField.mm rename camino/{CHAutoCompleteTableView.h => CHGoMenu.h} (70%) create mode 100644 camino/CHGoMenu.mm create mode 100644 camino/src/browser/AutoCompleteTextField.h create mode 100644 camino/src/browser/AutoCompleteTextField.mm rename chimera/CHAutoCompleteTableView.h => camino/src/browser/GoMenu.h (70%) create mode 100644 camino/src/browser/GoMenu.mm delete mode 100644 chimera/CHAutoCompleteTableView.mm create mode 100644 chimera/CHAutoCompleteTextField.h create mode 100644 chimera/CHAutoCompleteTextField.mm create mode 100644 chimera/CHGoMenu.h create mode 100644 chimera/CHGoMenu.mm create mode 100644 chimera/src/browser/AutoCompleteTextField.h create mode 100644 chimera/src/browser/AutoCompleteTextField.mm create mode 100644 chimera/src/browser/GoMenu.h create mode 100644 chimera/src/browser/GoMenu.mm diff --git a/camino/BrowserWindow.nib/classes.nib b/camino/BrowserWindow.nib/classes.nib index 1ebea82c405d..1ad29253dc41 100644 --- a/camino/BrowserWindow.nib/classes.nib +++ b/camino/BrowserWindow.nib/classes.nib @@ -67,13 +67,14 @@ }; SUPERCLASS = NSWindowController; }, + {CLASS = CHAutoCompleteDataSource; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { - CLASS = CHAutoCompleteTableView; + ACTIONS = {onBlur = id; onResize = id; }; + CLASS = CHAutoCompleteTextField; LANGUAGE = ObjC; - OUTLETS = {mURLBar = NSTextField; mWindowController = BrowserWindowController; }; - SUPERCLASS = NSTableView; + OUTLETS = {mProxyIcon = CHPageProxyIcon; }; + SUPERCLASS = NSTextField; }, - {CLASS = CHAutoCompleteTextField; LANGUAGE = ObjC; SUPERCLASS = NSTextField; }, { CLASS = CHBookmarksOutlineView; LANGUAGE = ObjC; diff --git a/camino/BrowserWindow.nib/info.nib b/camino/BrowserWindow.nib/info.nib index 49c53f48dec3..69c87221fbef 100644 --- a/camino/BrowserWindow.nib/info.nib +++ b/camino/BrowserWindow.nib/info.nib @@ -22,10 +22,8 @@ 22 500 93 162 0 0 1152 746 463 7 444 200 252 0 0 1152 746 - 475 - 493 338 207 230 0 0 1152 746 56 - 340 478 343 68 0 0 1024 746 + 378 463 343 68 0 0 1152 746 IBFramework Version 248.0 @@ -43,6 +41,10 @@ 497 + IBOpenObjects + + 56 + IBSystem Version 5Q125 diff --git a/camino/BrowserWindow.nib/objects.nib b/camino/BrowserWindow.nib/objects.nib index b8b3f58e4615a20976e9b50b6d5fcb78e93ce507..07d94ae0dd20589257aec14d11a8a233d9b68ff2 100644 GIT binary patch literal 16669 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 literal 16892 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 (Original Author) */ -#import -#include "nsIAutoCompleteSession.h" +#import +#import "CHAutoCompleteTextField.h" +#include "nsIAutoCompleteResults.h" -@interface CHAutoCompleteDataSource : NSObject { - nsIAutoCompleteSession* mAutoComplete; +@class CHAutoCompleteTextField; + +@interface CHAutoCompleteDataSource : NSObject +{ + CHAutoCompleteTextField *mTextField; + NSImage *mIconImage; + + NSString* mErrorMessage; + nsIAutoCompleteResults *mResults; } --(void)initialize; +- (id) init; + +- (int) rowCount; +- (id) resultString:(int)aRow column:(NSString *)aColumn; + +- (void) setErrorMessage: (NSString*) error; +- (NSString*) errorMessage; + +- (void) setResults: (nsIAutoCompleteResults*) results; +- (nsIAutoCompleteResults*) results; @end diff --git a/camino/CHAutoCompleteDataSource.mm b/camino/CHAutoCompleteDataSource.mm index 8a57b887b486..eab2a47ed9ad 100644 --- a/camino/CHAutoCompleteDataSource.mm +++ b/camino/CHAutoCompleteDataSource.mm @@ -19,41 +19,106 @@ * * Contributor(s): * David Hyatt (Original Author) +* */ #import -#import "CHAutoCompleteDataSource.h" -#include "nsIServiceManager.h" +#import "CHAutoCompleteTextField.h" +#include "nsString.h" +#include "nsCRT.h" @implementation CHAutoCompleteDataSource -(id)init { if ((self = [super init])) { - mAutoComplete = nsnull; + mResults = nil; + mIconImage = [[NSImage imageNamed:@"globe_ico"] autorelease]; } return self; } --(void)initialize +-(void)dealloc { - if (!mAutoComplete) { - nsCOMPtr session = - do_GetService("@mozilla.org/autocompleteSession;1?type=history"); - mAutoComplete = session; - if (!mAutoComplete) - printf("Could not find autocomplete!\n"); - } + NS_IF_RELEASE(mResults); } --(int)numberOfRowsInTableView:(NSTableView*)aTableView +- (void) setErrorMessage: (NSString*) error { - return 0; + [self setResults:nsnull]; + mErrorMessage = error; +} + +- (NSString*) errorMessage +{ + return mErrorMessage; +} + +- (void) setResults:(nsIAutoCompleteResults*)aResults +{ + NS_IF_RELEASE(mResults); + + mErrorMessage = nil; + mResults = aResults; + NS_IF_ADDREF(mResults); +} + +- (nsIAutoCompleteResults *) results +{ + return mResults; +} + +- (int) rowCount +{ + if (!mResults) + return 0; + + nsCOMPtr items; + mResults->GetItems(getter_AddRefs(items)); + PRUint32 count; + items->Count(&count); + + return count; +} + +- (id) resultString:(int)aRow column:(NSString *)aColumn +{ + NSString *result = @""; + + if (!mResults) + return result; + + nsCOMPtr items; + mResults->GetItems(getter_AddRefs(items)); + + nsCOMPtr itemSupports = dont_AddRef(items->ElementAt(aRow)); + nsCOMPtr item = do_QueryInterface(itemSupports); + if (!item) + return result; + + if ([aColumn isEqualToString:@"icon"]) { + return mIconImage; + } else if ([aColumn isEqualToString:@"col1"]) { + nsAutoString value; + item->GetValue(value); + result = [NSString stringWithCharacters:value.get() length:value.Length()]; + } else if ([aColumn isEqualToString:@"col2"]) { + PRUnichar *comment; + item->GetComment(&comment); + result = [NSString stringWithCharacters:comment length:nsCRT::strlen(comment)]; + } + + return result; +} + +-(int) numberOfRowsInTableView:(NSTableView*)aTableView +{ + return [self rowCount]; } -(id)tableView:(NSTableView*)aTableView objectValueForTableColumn:(NSTableColumn*)aTableColumn row:(int)aRowIndex { - return @""; + return [self resultString:aRowIndex column:[aTableColumn identifier]]; } @end diff --git a/camino/CHAutoCompleteTableView.mm b/camino/CHAutoCompleteTableView.mm deleted file mode 100644 index 4f49a60d31e4..000000000000 --- a/camino/CHAutoCompleteTableView.mm +++ /dev/null @@ -1,68 +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): -* David Hyatt (Original Author) -*/ - -#import "CHAutoCompleteTableView.h" -#import "CHAutoCompleteDataSource.h" - -@implementation CHAutoCompleteTableView - --(id)initWithFrame:(NSRect)aRect -{ - if ((self = [super initWithFrame: aRect])) { - // Create our data source. - mDataSource = [[CHAutoCompleteDataSource alloc] init]; - [self setDataSource: mDataSource]; - - // Create the URL column. - NSTableColumn* urlColumn = [[[NSTableColumn alloc] initWithIdentifier:@"URL"] autorelease]; - [self addTableColumn: urlColumn]; - NSTableColumn* titleColumn = [[[NSTableColumn alloc] initWithIdentifier:@"Title"] autorelease]; - [self addTableColumn: titleColumn]; - } - return self; -} - --(void)dealloc -{ - [mDataSource release]; - [super dealloc]; -} - --(BOOL)isShowing -{ - return ([self superview] != nil); -} - --(void)controlTextDidChange:(NSNotification*)aNotification -{ - // Ensure that our data source is initialized. - [mDataSource initialize]; - -// [[[[mWindowController window] contentView] superview] addSubview: self]; -} - --(void)controlTextDidEndEditing:(NSNotification*)aNotification -{ -} - -@end diff --git a/camino/CHAutoCompleteTextField.h b/camino/CHAutoCompleteTextField.h new file mode 100644 index 000000000000..bcd888353ac9 --- /dev/null +++ b/camino/CHAutoCompleteTextField.h @@ -0,0 +1,76 @@ +/* -*- 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 (Original Author) +*/ + +#import +#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; + BOOL mBackspaced; + + NSTimer *mOpenTimer; +} + +- (void) setSession:(NSString *)aSession; +- (NSString *) session; + +- (NSTableView *) tableView; +- (int) visibleRows; + +- (void) startSearch:(NSString*)aString; +- (void) performSearch; +- (void) dataReady:(nsIAutoCompleteResults*)aResults status:(AutoCompleteStatus)aStatus; +- (void) searchTimer:(NSTimer *)aTimer; + +- (void) completeDefaultResult; +- (void) completeResult:(int)aRow; +- (void) enterResult:(int)aRow; + +- (void) selectRowAt:(int)aRow; +- (void) selectRowBy:(int)aRows; + +- (void) openPopup; +- (void) closePopup; +- (void) resizePopup; +- (BOOL) isOpen; + +- (void) onBlur:(id)sender; +- (void) onResize:(id)sender; + +@end diff --git a/camino/CHAutoCompleteTextField.mm b/camino/CHAutoCompleteTextField.mm new file mode 100644 index 000000000000..79f71118efb3 --- /dev/null +++ b/camino/CHAutoCompleteTextField.mm @@ -0,0 +1,447 @@ +/* -*- 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 (Original Author) +*/ + +#import "CHAutoCompleteTextField.h" +#import "CHPageProxyIcon.h" +#include "nsIServiceManager.h" +#include "nsMemory.h" +#include "nsString.h" + +static const int kMaxRows = 6; +static const int kFrameMargin = 1; + +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; + 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 = [[NSWindow alloc] initWithContentRect:NSMakeRect(0,0,0,0) + styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; + [mPopupWin setReleasedWhenClosed:NO]; + [mPopupWin setLevel:NSPopUpMenuWindowLevel]; + [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)]; + + // Create the icon column if we have a proxy icon + if (mProxyIcon != nil) { + 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] retain]; + [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]; +} + +- (void) dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + if (mSearchString) + [mSearchString release]; + + [mDataSource release]; + + NS_IF_RELEASE(mSession); + NS_IF_RELEASE(mResults); + NS_IF_RELEASE(mListener); +} + +- (void) setSession:(NSString *)aSession +{ + NS_IF_RELEASE(mSession); + + // XXX add aSession to contract id + nsCOMPtr 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; +} + +// searching //////////////////////////// + +- (void) startSearch:(NSString*)aString +{ + if (mSearchString) + [mSearchString release]; + mSearchString = [aString retain]; + + 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]; + + // 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; + } +} + +- (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]; +} + +// 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; + + // 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 (mBackspaced) { + [self selectRowAt:-1]; + mBackspaced = NO; + } else { + [self selectRowAt:defaultRow]; + [self completeResult:defaultRow]; + } +} + + +- (void) completeResult:(int)aRow +{ + NSRange matchRange; + NSText *text; + NSString *result1; + + if (aRow < 0) { + [self setStringValue:mSearchString]; + } else { + if ([mDataSource rowCount] <= 0) + return; + + result1 = [mDataSource resultString:aRow column:@"col1"]; + matchRange = [result1 rangeOfString:mSearchString]; + if (matchRange.length > 0) { + // cut off everything in the result string before the search string + result1 = [result1 substringWithRange:NSMakeRange(matchRange.location, [result1 length]-matchRange.location)]; + + // fill in the textfield with the matching string + [self setStringValue:result1]; + + // select the text after the search string + text = [[self window] fieldEditor:NO forObject:self]; + [text setSelectedRange:NSMakeRange([mSearchString length], [result1 length]-[mSearchString length])]; + } + } +} + +- (void) enterResult:(int)aRow +{ + if ([self isOpen] && aRow >= 0) { + [self setStringValue: [mDataSource resultString:[mTableView selectedRow] column:@"col1"]]; + } +} + +// selecting rows ///////////////////////////////////////// + +- (void) selectRowAt:(int)aRow +{ + [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) onBlur:(id)sender +{ + [self closePopup]; +} + +- (void) onResize:(id)sender +{ + [self resizePopup]; +} + +// NSTextField //////////////////////////////////////////// + +- (void)controlTextDidChange:(NSNotification *)aNotification +{ + [self startSearch:[self stringValue]]; +} + +- (void)controlTextDidEndEditing:(NSNotification *)aNotification +{ + [self closePopup]; +} + +// NSTextField delegate ////////////////////////////////// + +- (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]; + return YES; + } else if (command == @selector(moveDown:)) { + [self selectRowBy:1]; + return YES; + } else if (command == @selector(scrollPageUp:)) { + [self selectRowBy:-kMaxRows]; + } else if (command == @selector(scrollPageDown:)) { + [self selectRowBy:kMaxRows]; + } else if (command == @selector(moveToBeginningOfDocument:)) { + [self selectRowAt:0]; + } else if (command == @selector(moveToEndOfDocument:)) { + [self selectRowAt:[mTableView numberOfRows]-1]; + } else if (command == @selector(insertTab:) || command == @selector(insertNewline:)) { + [self closePopup]; + } 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 ([[self stringValue] length] > 1) + mBackspaced = YES; + } + + return NO; +} + +@end diff --git a/camino/CHAutoCompleteTableView.h b/camino/CHGoMenu.h similarity index 70% rename from camino/CHAutoCompleteTableView.h rename to camino/CHGoMenu.h index d8a86ae298bc..17e614302d80 100644 --- a/camino/CHAutoCompleteTableView.h +++ b/camino/CHGoMenu.h @@ -18,19 +18,19 @@ * Rights Reserved. * * Contributor(s): -* David Hyatt (Original Author) +* Joe Hewitt (Original Author) */ -#import -#import "BrowserWindowController.h" -#import "CHAutoCompleteDataSource.h" +#import + +@interface CHGoMenu : NSMenu { -@interface CHAutoCompleteTableView : NSTableView { - IBOutlet NSTextField* mURLBar; - IBOutlet BrowserWindowController* mWindowController; - CHAutoCompleteDataSource* mDataSource; } -- (BOOL)isShowing; +- (void) emptyHistoryItems; +- (void) addHistoryItems; + +// NSMenu +- (void) update; @end diff --git a/camino/CHGoMenu.mm b/camino/CHGoMenu.mm new file mode 100644 index 000000000000..487b84d7193e --- /dev/null +++ b/camino/CHGoMenu.mm @@ -0,0 +1,147 @@ +/* -*- 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 (Original Author) +*/ + +#import "CHGoMenu.h" +#import "BrowserWindowController.h" +#import "CHBrowserWrapper.h" +#import "CHBrowserView.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "nsIWebBrowser.h" +#include "nsISHistory.h" +#include "nsIWebNavigation.h" +#include "nsIHistoryEntry.h" +#include "nsCRT.h" + +// the tag of the separator after which to insert history menu items +static const int kDividerTag = 4000; +// the maximum number of history entry menuitems to display +static const int kMaxItems = 15; +// the maximum number of characters in a menu title before cropping it +static const int kMaxTitleLength = 20; + +@implementation CHGoMenu + +- (void) update +{ + [self emptyHistoryItems]; + [self addHistoryItems]; + + [super update]; +} + +- (nsIWebNavigation*) currentWebNavigation +{ + // get controller for current window + BrowserWindowController *controller; + controller = (BrowserWindowController*)[[NSApp mainWindow] windowController]; + if (!controller) return nsnull; + + // get web navigation for current browser + CHBrowserWrapper* wrapper = [controller getBrowserWrapper]; + if (!wrapper) return nsnull; + CHBrowserView* view = [wrapper getBrowserView]; + if (!view) return nsnull; + nsCOMPtr webBrowser = [view getWebBrowser]; + if (!webBrowser) return nsnull; + nsCOMPtr webNav(do_QueryInterface(webBrowser)); + return webNav.get(); +} + +- (void) historyItemAction:(id)sender +{ + // get web navigation for current browser + nsCOMPtr webNav = [self currentWebNavigation]; + if (!webNav) return; + + // browse to the history entry for the menuitem that was selected + PRInt32 historyIndex = ([sender tag] - 1) - kDividerTag; + webNav->GotoIndex(historyIndex); +} + +- (void) emptyHistoryItems +{ + // remove every history item after the insertion point + int insertionIndex = [self indexOfItemWithTag:kDividerTag]; + for (int i = [self numberOfItems]-1; i > insertionIndex ; --i) { + [self removeItemAtIndex:i]; + } +} + +- (void) addHistoryItems +{ + // get session history for current browser + nsCOMPtr webNav = [self currentWebNavigation]; + if (!webNav) return; + nsCOMPtr sessionHistory; + webNav->GetSessionHistory(getter_AddRefs(sessionHistory)); + + PRInt32 count; + sessionHistory->GetCount(&count); + PRInt32 currentIndex; + sessionHistory->GetIndex(¤tIndex); + + // determine the range of items to display + int rangeStart, rangeEnd; + int above = kMaxItems/2; + int below = (kMaxItems-above)-1; + if (count <= kMaxItems) { + // if the whole history fits within our menu, fit range to show all + rangeStart = count-1; + rangeEnd = 0; + } else { + // if the whole history is too large for menu, try to put current index as close to + // the middle of the list as possible, so the user can see both back and forward in session + rangeStart = currentIndex + above; + rangeEnd = currentIndex - below; + if (rangeStart >= count-1) { + rangeEnd -= (rangeStart-count)+1; // shift overflow to the end + rangeStart = count-1; + } else if (rangeEnd < 0) { + rangeStart -= rangeEnd; // shift overflow to the start + rangeEnd = 0; + } + } + + // create a new menu item for each history entry (up to MAX_MENUITEM entries) + for (PRInt32 i = rangeStart; i >= rangeEnd; --i) { + nsCOMPtr entry; + sessionHistory->GetEntryAtIndex(i, PR_FALSE, getter_AddRefs(entry)); + + PRUnichar *text; + entry->GetTitle(&text); + NSString* title = [NSString stringWithCharacters: text length: nsCRT::strlen(text)]; + + if ([title length] > kMaxTitleLength) { + + } + + NSMenuItem *newItem = [self addItemWithTitle:title action:@selector(historyItemAction:) keyEquivalent:@""]; + [newItem setTarget:self]; + [newItem setTag:kDividerTag+1+i]; + if (currentIndex == i) + [newItem setState:NSOnState]; + } +} + +@end diff --git a/camino/Chimera.pbproj/project.pbxproj b/camino/Chimera.pbproj/project.pbxproj index 873e19dd1d5d..4ebab3b0d650 100644 --- a/camino/Chimera.pbproj/project.pbxproj +++ b/camino/Chimera.pbproj/project.pbxproj @@ -27,6 +27,7 @@ F52D5CD4027A88C601A80166, F52F87CD027D75C301A80165, F52F87CE027D75C301A80165, + 2E748B73029A448D4B000102, ); isa = PBXGroup; name = Classes; @@ -409,6 +410,7 @@ F52F87D0027D75C301A80165, 2E293A01027F33604B000102, 2EEC3E63028138724B000102, + 2E748B74029A448D4B000102, ); isa = PBXHeadersBuildPhase; name = Headers; @@ -510,6 +512,7 @@ F52F87D2027D75C301A80165, 2E293A02027F33604B000102, 2EEC3E64028138724B000102, + 2E748B75029A448D4B000102, ); isa = PBXSourcesBuildPhase; name = Sources; @@ -569,6 +572,28 @@ settings = { }; }; + 2E748B72029A448D4B000102 = { + isa = PBXFileReference; + path = CHGoMenu.h; + refType = 4; + }; + 2E748B73029A448D4B000102 = { + isa = PBXFileReference; + path = CHGoMenu.mm; + refType = 4; + }; + 2E748B74029A448D4B000102 = { + fileRef = 2E748B72029A448D4B000102; + isa = PBXBuildFile; + settings = { + }; + }; + 2E748B75029A448D4B000102 = { + fileRef = 2E748B73029A448D4B000102; + isa = PBXBuildFile; + settings = { + }; + }; 2EEC3E6002810B184B000102 = { indentWidth = 2; isa = PBXFileReference; @@ -1009,6 +1034,7 @@ F52D5CD3027A88C601A80166, F52F87CB027D75C301A80165, F52F87CC027D75C301A80165, + 2E748B72029A448D4B000102, ); isa = PBXGroup; name = Headers; @@ -1483,12 +1509,12 @@ }; F52D5CCF027A887001A80166 = { isa = PBXFileReference; - path = CHAutoCompleteTableView.h; + path = CHAutoCompleteTextField.h; refType = 4; }; F52D5CD0027A887001A80166 = { isa = PBXFileReference; - path = CHAutoCompleteTableView.mm; + path = CHAutoCompleteTextField.mm; refType = 4; }; F52D5CD1027A887001A80166 = { diff --git a/camino/English.lproj/BrowserWindow.nib/classes.nib b/camino/English.lproj/BrowserWindow.nib/classes.nib index 1ebea82c405d..1ad29253dc41 100644 --- a/camino/English.lproj/BrowserWindow.nib/classes.nib +++ b/camino/English.lproj/BrowserWindow.nib/classes.nib @@ -67,13 +67,14 @@ }; SUPERCLASS = NSWindowController; }, + {CLASS = CHAutoCompleteDataSource; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { - CLASS = CHAutoCompleteTableView; + ACTIONS = {onBlur = id; onResize = id; }; + CLASS = CHAutoCompleteTextField; LANGUAGE = ObjC; - OUTLETS = {mURLBar = NSTextField; mWindowController = BrowserWindowController; }; - SUPERCLASS = NSTableView; + OUTLETS = {mProxyIcon = CHPageProxyIcon; }; + SUPERCLASS = NSTextField; }, - {CLASS = CHAutoCompleteTextField; LANGUAGE = ObjC; SUPERCLASS = NSTextField; }, { CLASS = CHBookmarksOutlineView; LANGUAGE = ObjC; diff --git a/camino/English.lproj/BrowserWindow.nib/info.nib b/camino/English.lproj/BrowserWindow.nib/info.nib index 49c53f48dec3..69c87221fbef 100644 --- a/camino/English.lproj/BrowserWindow.nib/info.nib +++ b/camino/English.lproj/BrowserWindow.nib/info.nib @@ -22,10 +22,8 @@ 22 500 93 162 0 0 1152 746 463 7 444 200 252 0 0 1152 746 - 475 - 493 338 207 230 0 0 1152 746 56 - 340 478 343 68 0 0 1024 746 + 378 463 343 68 0 0 1152 746 IBFramework Version 248.0 @@ -43,6 +41,10 @@ 497 + IBOpenObjects + + 56 + IBSystem Version 5Q125 diff --git a/camino/English.lproj/BrowserWindow.nib/objects.nib b/camino/English.lproj/BrowserWindow.nib/objects.nib index b8b3f58e4615a20976e9b50b6d5fcb78e93ce507..07d94ae0dd20589257aec14d11a8a233d9b68ff2 100644 GIT binary patch literal 16669 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 literal 16892 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 I)}ibEKfnvFQ~&?~ literal 9279 zcmb_h4QyQ1mA=YI8jqjtM`q?t z=O@9GYH$D z$YbspYhrBdn^&)1WktwsibRcR`>m{#&%~{pj!V!%cuz7mY!MGx30=EKtoWg1EOW?p zi-n)cp8*4A!tAjhwg#iQSk3|p9>f1!tCmrr}VuM(>a9_z(zG;Sk=GCiyzm))6nJ2S2&$Vh) z-(?RETbb|y>){-^owqM8mwX$FCS!?2km=8tW~z@S9Va(Zp6I~<4=)Cdo+vM4BSoS% zI^2^QaiE)()0Y7bha&ADbFqY|-#D ziZyp52j#4A1U}vABnGXF`{aT`%`Pf4M6Glz6U#aC^H7#KJq{-kTkQp3kzJSPsMnG<|My`o)bYs}b6pwo+lzkAi>{ zaTXU$E6|{sdY#e{KwOE%xvo{6x@hdM74FP>%0&M-VjCzKhND(4pY|m8EiReNtm(r6 znDZFYi!&@?;afU>AT)HJlQ|ULJ2aHAQ`Wp2WJn%jE$!z8dGs_(*yXEI6SXpjZHSz6m_4pH zh2Fd;PnF4F38R2paWE3~ckCO?JXCn~%wdH!C%*{SQ1QHJNLEx~U-D-Gg>+j%WOp_Y$|LaUkLUgSWX zc^+BFd_%mnXN|zh?z|~B9$s9Ywy)bskLtaeX{8Qd19f-8LV-Hlcfn{e z`qo9Q1PXN>TO>QSxa@0n!-}0aT*9ahDEE0uY-n-W4L0xLI+*tle6M#IC7l?@};SU1gagBKD3hyLsQ4!!7(uOfv@n{$_y zNY9a0c530|sVYqZ=W=3;Xy-Qi$3@s+5pz2hGM98Bhtwnc_&EfX5J1aH)yw>P|RWD_H&y{tz6 zTBE;Li;XU=L`?)&Ag_3<{IAJlV7bn}w9cxzOHRT$eb{#LxF(vK4{T$Lvt6tH*LBg= zo-z)V$~!YoYHsrOJVUGBh}Abv&z6qp7WvGi{9sDcBth zAE0Zo6CPQ0eB#DJ^#faPjem6+@N4kjr&n1o%dFCuag&~&JcqCPNE9uMw3EVJis^<5 zY%{F~O(B>VFHVeAllCFfeyH>hKChtu3k1;Bd#7zB23HIAt#QGQO|a*S`1i^6cQ!M2 zXETAQyD?rwhbA8HU>y2T7szKMXSI($HCDypDb~T*&k+%|r9!=}&izKQ_>3;`1nRlU zI5l~6C#TykK8$8;tOIMsDa-e_+W z>^ZD3{VjXsAK;9Ym%xc_8X$pP zHG?`WTTV!;U%oRX-?$*Rx5^EzvbRNkGA+B>W$mN9_p7HTjlg>8Jd>6Tjc5%`Cz|%Z%RHpDPNeBzqu&ax601;KiCb} zvNIe8pXky^u=Cm{b-HQ~>r-y_HVU4IEjSU4&+l^L`6PVros3iRvc7r!L94T{TL1h< zQ>$rO9_*JFcgv|YvSM1kI4KAE<+@gRWlFAXk!{fZ?~e zay>?zh@Pyi5Y`M()fW77*s18YA1Qlf|nSH$pElp3~r zQo4d|qwA<(S6;eI$i_@QMK|Bx*eF_LK5if3YP0C&(A~!eH&blX!F@?Pg&wvK51oKP zEhA_!>54Y+@RjvxYKf+rXnatkX3M7th$4FqTcL2hwsvnmhcY;5tYH81(g|z;h^!ez zUjSV{%d_ik1FuV2M@%tp=HpeUlb)d&L&?BQ9@izqRqLS9OTq6e`9TShMaz{uTW24u{w@Mjt|;Mpk--l*Z8na8WyLfj1SvPu)3`7zhIqw z`1X>XG@I^(_?QPNepaTf3~GZUT}WfOd0wHzi3#ZYNoGSyroMXmLeCQFPY~;+2T|`~Qa{f2#SmQq7wj+^EFX5Lzv9by zwget@=mF6OKWD(TgN}I}^bzkFL<2>XR}lEfs|LAx(9Wh4vC%-UIT*9prCp_2haGCt z`22SpaNV#|YRCAP0fVWHQ||y*VjuBNNfP!&5IkbQp>*jQ9mH7%SCc|n8H9gg;0=@@ zbZ@=OdDx$4J^8vS9>^x^2vVI#1JfsZ!AMv!pkF>Iy+?!L@uERDWz8e!9Q=8MZ#H|+ zylN7WFaOn&fTVsU^uxu+zi#k#h%)mC=VRV5m6O}>Vn{ZrQQ?#YpPYSr_>vQpHlY=e!qHN z@P4&fuwST;1^Xv;Q1Cm|CBZ8p@tELsYQ5lN5Zfkr7Q>x_=P_&(d{AB9gRff!x70kDoUP{#k|1_a44$1pA%p9fnYZ;5Yywz|`G>+xWgw@Y~c2f`3PW z><8*W!MB6(_kw*#P3=>OYBed?CDkeTu&PC6p#}s$q^blXy$%R|TD>FqD86xjeMJ3I z@V{2OF^_st@b9YCw?Wit!TwgY3HGkqF8F$t#`J)GbRT%WBKQ-kOYjkOUhuzEpR@sX z9sUnIyzS!G2Ep&aum*m|P={4gj^HcRK1V$+_>TemQ^7x{T0W~zaD_$qt%5xTbyl$d zfDl*kdJMn&y!s8Cs5amV2M(C{6AYO5FEDVyPN^Qj{tw@Mg8vZoNHZt#>n_2+iD9SU z0>G1kH{sXU1pldeRqzu4ef$Uj`vsS3`gYYM*a;PRNWCujN%f}S<7$&&PlDij#2kh& zR8_ADPM}Rt0z;)>m({A3_*x4*h9<$AF?>Pr-3m$wwM+1a6f*0ydRp+mQOKJAsX~JN zP$A!6Rqb%2xe^w+u}RCQ+S-X@Mrwj0NCl-(qM|?tXi=arU;+l>!i8E@fZZQm zYN$!9esAV>c@lLb4TQFCXW#$4_h#nJ+uG*b@w6Sw<}$XG6g8I$yr)now1y&sefx)= zv7@<%t(+y;zZ41$p@@O7;-n$z&u4Q^(g5$8Dy-@u)-|EXzI@IaO4yNHCY~DMnzKBf zD)8TH2}OF-=|ntg<>F4tExH9Bk4bPgfzwXq2Xl5(@T*g#q~3r8`-iDQZM>(ahZSC( zsoiZS(ylR~tg1JYv5vDsVKrpy;nXajoF&;U;2Inx)}9@4u+Pl2hODFU5i93pf=1BH z41dU-U~P;|oVa%F8Y@C{TPR{?cfig%`ApQlYf6F_@&}XFi0xub6NS0`qjvO2(#jlh z-D2TQ`5j=uOqhM~V|FZ(vvM|2a2oz|Ps+k;lZDq`r+GB(&yCudgK>L2>lRMU)=UC5 zcZy7G+5PCgy}^DbnNHZ?282}@$ct|j-zv0!HSMGyOOv;HqvXjQCNAxvNSF|P`CQIP z_1lSrSkN!`#*gqEvfly?D>LLAZL=i>1_CAez5!!fsqR{&Zn`mH+6>7 zz)9sgre-%4>YnVrH+r}p_|M|sC)e0smS<5GXEA26T`Ys&6vj6A`EW~tN7-q9nw_q7 zi$#bh<8@jgJ1Wda;C1>KGZElM#045NPU0@Dp1g-qb0~s9rJYpF&M=)hn41Zprudu5 z;_O5n*&ZO=a%MHZsMC{g|OrD=*KPuwy*Xtf^XY9fD$@3Ju$s$rP z8tq{mc2Ju8Eaaq}KYDATmcv7=hq3P=VvP~&s2%Lh?r3s?m*N`Qq#DFzdv15ST#KS!b5kzJ;z;ouRo_i)>bAXOBP6f z!a(D~T)v~|PM(E>i;M}*?=in-E|W!x6hr{YKcuqKg|1unz|K~|{tEG=U(X9ah68@+ z78a}5%itAC1xzn zVnM_-j7_z(vs23+t}6RoFS<>duXhCLpjk$$vCRAXEdpy&{nTs=#j2zO8;FcLEK?+is9hYKGC!5tTwxac{Cre z6JT55$t=yYQj41V;v*w=#;iHY*PTntrF;!Ul2#&7$+Ts8rshb}adM*zik_*Yw* z1S$FHiM{x7tOW;q@u}Iy$#oRk4xOTF_Qg~2BxRgOfG{MhS+c;_e8_Q<9#7Q_)oPY^ zrZJ_lKjCDN`PPtj$MNNjXb54m_84mZ^W+O)xy3KEZg9O(5(sDPqj4t>?-@N{n^>A{ zrS{*_M-?e;V!@mf9LV61tr{AdVe3~z5##hM6;G}?S^~xk710>4=7eL}_^h?r3<`i19`Jp6~FBEyGlTbizg@|Sn(QUG%cgV@-g4G38=6Lt1 z9ip$mD&)oGe_ePxoEmSHFcmVkQc}>R}>bgxe*YL*F?lM zE?BAN*4^=#UEw9jS=v1s^fo|eiT0?TS*@wSWH z()7!R(3la}pSDv$vd=3RoTUX*L|Qb{UZ;HNBnKvz=31#aP31b@GbZwz5!*r)Q7~fX z@@Y?UcxlNx@xs{Pavno^X@-@~Fz~pOITGAIJe-K9kUHKixnlFi@#ju%p|B&#esN>Y zo8&6#m1>f3)h?%63hJ9`f5OUUBjZ*&ZD;PL#=`F)U=97dcR4zru{)%ZnsuabOs8h; zZYOzj(+th>2Siy;pA|i#&$cI*@|_`GJ>X=K@&c%Znqqb7_-2O0y!o;_v2br=ub_O!w>NbSKdpz)c>T zzh7vWlEvI&kj^by)tgBtI_6SXdqj%h9mh(Jh@$ zd2wDo&@H!jOFJxAmE`kd@@h#Y!t(YGIoK^b1e=z7x@AjA?tDPr)**jB4=23{KgkQ{ zP_#);CWRCMSMLXZo>4i6U`?P zu5!JKX?JzXzHWJWUe=W4rFnTcEW;tWkxZZNluw6cs#88UCJ%*ZPVZ|8o_23*qo}~@G2FrjYQFa)OQG9j8^|lwXKaZa9+Mo+4D`xmH935 zojJLwLq@`~z9jGK2I3_`Jkl-OO7e-Y{8dSgIdbl-%#X=Z3TPKw3LfHwyjGIO#$@NT z{AgaDJugpm%5B{;)F}&+TGXwy^vXR_T*9Gw8f-5R_orRh)zkCueq-r*ep;TyDuRhq zWa5YO^30sH!g!}`T^yu7nR?&_Z1Eax!AM%^La8_(ukX~9Uo-IcSt?I<@2 z_Kz}5KQ;epj9+iLfwdzCO4zR+f0_ zdeSera+EOly7J8R7>GR!$o0*7S3V8cs;w~XHX4xf2=PPZ2aEXMC6a9*xr{+YIJ)j} zWhb~6?#l8Ik>1~hLr{OC@IEiuIdszN=t7ud_^>pHela$pZA8@(iiF}rCVylmSg}ZZe)iq2a?HnZ`WUkD?UP7s-l`U|FB0k7(+M#s}@vZ21%caiv_u zRw%5~v)!N1;cHRlWCi=hxoKnxL^j0Gzr{x{+nZO!z?)L`xVh39eZ2M@5Tr4XtkC3f z9Wq>v4z6I7;=YmiL`Z5Hv-s#ip7Ie1gSaK@;qR91ByGB1?PE4j_N>JX2M17+dVE$cpFx|? zC%BD72Fe7~%=0mNKPP_&tXRye)D6}+09z@rtw|48E(c6XuOqoFWx2YSv8)Gw9rZ3f;#TZHb<^*P6UJ@1pRYoitW$$JE;%cBeI6V(_A zYld_ip3a6yWs1}rbX(SR+!x^+4Zhv1KGR|+B456)M<|oplKS4~Crkwes#~IHLav$n zQUwl&G~rr+^Djm|`eT~UTBEz1P;@m+`2<%C_h$@=ue(g^lj)LM8yVNPLZ8s5XfuME zkD}Rc`t?BJ^Wm&uvuGd04-5VkwMy`VO7I_;VO@!DiIEg8weYza@B3Jumn(YL{RV0MKm5W3%9U zAP4%sg||MzpI7e)zE<5SIGO$1f`1;5KM*{p9>A`kVD^gu{J!8%;_;N=Z-V=k5&XO? z_^YZ$@NcONg5L+g$B(O@3tmu92tJ0_mjr(Wk104v-68nb6qcTV3}oPcs}BV`1LT`u z1K_imqgsYAod7e#N!Ks$M9%^OYwM6 z@Vx4UQ5ZJ}c13k=#OU*a_dpAFidWSKxaMK}O~I$t4p@ir&jkA~H80rr)K0-B0J!=r zm<|XIf3epD?^U-!GC*4ekE(ToKY=k~Mt;8q|ErVFD1_&Tn&#?~U~i}~I6-x6P>}O!E{uTik7 zalzqgJ|MVIi1cxc?-ks}1J7+t`@TAYQ&Gi`5xiCKMzseevbrkRzpJ;AfDnA;PUQ&pzv`l3 za|#>rf2hrMDka!OaI6>nGkAPiaGJ_q!CzAKg8vb?T)`(5ynY$uNx^5-3Cu?w6MR(N zhYC}LB0zjY@IL|H-GYA+Z_{fr#+UzRRg2({&kFwCSuV%2lQ`1a2K)M*sACOetfW1T I)}ibEKfnvFQ~&?~ literal 9279 zcmb_h4QyQ1mA=YI8jqjtM`q?t z=O@9GYH$D z$YbspYhrBdn^&)1WktwsibRcR`>m{#&%~{pj!V!%cuz7mY!MGx30=EKtoWg1EOW?p zi-n)cp8*4A!tAjhwg#iQSk3|p9>f1!tCmrr}VuM(>a9_z(zG;Sk=GCiyzm))6nJ2S2&$Vh) z-(?RETbb|y>){-^owqM8mwX$FCS!?2km=8tW~z@S9Va(Zp6I~<4=)Cdo+vM4BSoS% zI^2^QaiE)()0Y7bha&ADbFqY|-#D ziZyp52j#4A1U}vABnGXF`{aT`%`Pf4M6Glz6U#aC^H7#KJq{-kTkQp3kzJSPsMnG<|My`o)bYs}b6pwo+lzkAi>{ zaTXU$E6|{sdY#e{KwOE%xvo{6x@hdM74FP>%0&M-VjCzKhND(4pY|m8EiReNtm(r6 znDZFYi!&@?;afU>AT)HJlQ|ULJ2aHAQ`Wp2WJn%jE$!z8dGs_(*yXEI6SXpjZHSz6m_4pH zh2Fd;PnF4F38R2paWE3~ckCO?JXCn~%wdH!C%*{SQ1QHJNLEx~U-D-Gg>+j%WOp_Y$|LaUkLUgSWX zc^+BFd_%mnXN|zh?z|~B9$s9Ywy)bskLtaeX{8Qd19f-8LV-Hlcfn{e z`qo9Q1PXN>TO>QSxa@0n!-}0aT*9ahDEE0uY-n-W4L0xLI+*tle6M#IC7l?@};SU1gagBKD3hyLsQ4!!7(uOfv@n{$_y zNY9a0c530|sVYqZ=W=3;Xy-Qi$3@s+5pz2hGM98Bhtwnc_&EfX5J1aH)yw>P|RWD_H&y{tz6 zTBE;Li;XU=L`?)&Ag_3<{IAJlV7bn}w9cxzOHRT$eb{#LxF(vK4{T$Lvt6tH*LBg= zo-z)V$~!YoYHsrOJVUGBh}Abv&z6qp7WvGi{9sDcBth zAE0Zo6CPQ0eB#DJ^#faPjem6+@N4kjr&n1o%dFCuag&~&JcqCPNE9uMw3EVJis^<5 zY%{F~O(B>VFHVeAllCFfeyH>hKChtu3k1;Bd#7zB23HIAt#QGQO|a*S`1i^6cQ!M2 zXETAQyD?rwhbA8HU>y2T7szKMXSI($HCDypDb~T*&k+%|r9!=}&izKQ_>3;`1nRlU zI5l~6C#TykK8$8;tOIMsDa-e_+W z>^ZD3{VjXsAK;9Ym%xc_8X$pP zHG?`WTTV!;U%oRX-?$*Rx5^EzvbRNkGA+B>W$mN9_p7HTjlg>8Jd>6Tjc5%`Cz|%Z%RHpDPNeBzqu&ax601;KiCb} zvNIe8pXky^u=Cm{b-HQ~>r-y_HVU4IEjSU4&+l^L`6PVros3iRvc7r!L94T{TL1h< zQ>$rO9_*JFcgv|YvSM1kI4KAE<+@gRWlFAXk!{fZ?~e zay>?zh@Pyi5Y`M()fW77*s18YA1Qlf|nSH$pElp3~r zQo4d|qwA<(S6;eI$i_@QMK|Bx*eF_LK5if3YP0C&(A~!eH&blX!F@?Pg&wvK51oKP zEhA_!>54Y+@RjvxYKf+rXnatkX3M7th$4FqTcL2hwsvnmhcY;5tYH81(g|z;h^!ez zUjSV{%d_ik1FuV2M@%tp=HpeUlb)d&L&?BQ9@izqRqLS9OTq6e`9TShMaz{uTW24u{w@Mjt|;Mpk--l*Z8na8WyLfj1SvPu)3`7zhIqw z`1X>XG@I^(_?QPNepaTf3~GZUT}WfOd0wHzi3#ZYNoGSyroMXmLeCQFPY~;+2T|`~Qa{f2#SmQq7wj+^EFX5Lzv9by zwget@=mF6OKWD(TgN}I}^bzkFL<2>XR}lEfs|LAx(9Wh4vC%-UIT*9prCp_2haGCt z`22SpaNV#|YRCAP0fVWHQ||y*VjuBNNfP!&5IkbQp>*jQ9mH7%SCc|n8H9gg;0=@@ zbZ@=OdDx$4J^8vS9>^x^2vVI#1JfsZ!AMv!pkF>Iy+?!L@uERDWz8e!9Q=8MZ#H|+ zylN7WFaOn&fTVsU^uxu+zi#k#h%)mC=VRV5m6O}>Vn{ZrQQ?#YpPYSr_>vQpHlY=e!qHN z@P4&fuwST;1^Xv;Q1Cm|CBZ8p@tELsYQ5lN5Zfkr7Q>x_=P_&(d{AB9gRff!x70kDoUP{#k|1_a44$1pA%p9fnYZ;5Yywz|`G>+xWgw@Y~c2f`3PW z><8*W!MB6(_kw*#P3=>OYBed?CDkeTu&PC6p#}s$q^blXy$%R|TD>FqD86xjeMJ3I z@V{2OF^_st@b9YCw?Wit!TwgY3HGkqF8F$t#`J)GbRT%WBKQ-kOYjkOUhuzEpR@sX z9sUnIyzS!G2Ep&aum*m|P={4gj^HcRK1V$+_>TemQ^7x{T0W~zaD_$qt%5xTbyl$d zfDl*kdJMn&y!s8Cs5amV2M(C{6AYO5FEDVyPN^Qj{tw@Mg8vZoNHZt#>n_2+iD9SU z0>G1kH{sXU1pldeRqzu4ef$Uj`vsS3`gYYM*a;PRNWCujN%f}S<7$&&PlDij#2kh& zR8_ADPM}Rt0z;)>m({A3_*x4*h9<$AF?>Pr-3m$wwM+1a6f*0ydRp+mQOKJAsX~JN zP$A!6Rqb%2x22 500 93 162 0 0 1152 746 463 7 444 200 252 0 0 1152 746 - 475 - 493 338 207 230 0 0 1152 746 56 - 340 478 343 68 0 0 1024 746 + 378 463 343 68 0 0 1152 746 IBFramework Version 248.0 @@ -43,6 +41,10 @@ 497 + IBOpenObjects + + 56 + IBSystem Version 5Q125 diff --git a/camino/resources/localized/English.lproj/BrowserWindow.nib/objects.nib b/camino/resources/localized/English.lproj/BrowserWindow.nib/objects.nib index b8b3f58e4615a20976e9b50b6d5fcb78e93ce507..07d94ae0dd20589257aec14d11a8a233d9b68ff2 100644 GIT binary patch literal 16669 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 literal 16892 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 I)}ibEKfnvFQ~&?~ literal 9279 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 (Original Author) */ -#import -#include "nsIAutoCompleteSession.h" +#import +#import "CHAutoCompleteTextField.h" +#include "nsIAutoCompleteResults.h" -@interface CHAutoCompleteDataSource : NSObject { - nsIAutoCompleteSession* mAutoComplete; +@class CHAutoCompleteTextField; + +@interface CHAutoCompleteDataSource : NSObject +{ + CHAutoCompleteTextField *mTextField; + NSImage *mIconImage; + + NSString* mErrorMessage; + nsIAutoCompleteResults *mResults; } --(void)initialize; +- (id) init; + +- (int) rowCount; +- (id) resultString:(int)aRow column:(NSString *)aColumn; + +- (void) setErrorMessage: (NSString*) error; +- (NSString*) errorMessage; + +- (void) setResults: (nsIAutoCompleteResults*) results; +- (nsIAutoCompleteResults*) results; @end diff --git a/camino/src/browser/AutoCompleteDataSource.mm b/camino/src/browser/AutoCompleteDataSource.mm index 8a57b887b486..eab2a47ed9ad 100644 --- a/camino/src/browser/AutoCompleteDataSource.mm +++ b/camino/src/browser/AutoCompleteDataSource.mm @@ -19,41 +19,106 @@ * * Contributor(s): * David Hyatt (Original Author) +* */ #import -#import "CHAutoCompleteDataSource.h" -#include "nsIServiceManager.h" +#import "CHAutoCompleteTextField.h" +#include "nsString.h" +#include "nsCRT.h" @implementation CHAutoCompleteDataSource -(id)init { if ((self = [super init])) { - mAutoComplete = nsnull; + mResults = nil; + mIconImage = [[NSImage imageNamed:@"globe_ico"] autorelease]; } return self; } --(void)initialize +-(void)dealloc { - if (!mAutoComplete) { - nsCOMPtr session = - do_GetService("@mozilla.org/autocompleteSession;1?type=history"); - mAutoComplete = session; - if (!mAutoComplete) - printf("Could not find autocomplete!\n"); - } + NS_IF_RELEASE(mResults); } --(int)numberOfRowsInTableView:(NSTableView*)aTableView +- (void) setErrorMessage: (NSString*) error { - return 0; + [self setResults:nsnull]; + mErrorMessage = error; +} + +- (NSString*) errorMessage +{ + return mErrorMessage; +} + +- (void) setResults:(nsIAutoCompleteResults*)aResults +{ + NS_IF_RELEASE(mResults); + + mErrorMessage = nil; + mResults = aResults; + NS_IF_ADDREF(mResults); +} + +- (nsIAutoCompleteResults *) results +{ + return mResults; +} + +- (int) rowCount +{ + if (!mResults) + return 0; + + nsCOMPtr items; + mResults->GetItems(getter_AddRefs(items)); + PRUint32 count; + items->Count(&count); + + return count; +} + +- (id) resultString:(int)aRow column:(NSString *)aColumn +{ + NSString *result = @""; + + if (!mResults) + return result; + + nsCOMPtr items; + mResults->GetItems(getter_AddRefs(items)); + + nsCOMPtr itemSupports = dont_AddRef(items->ElementAt(aRow)); + nsCOMPtr item = do_QueryInterface(itemSupports); + if (!item) + return result; + + if ([aColumn isEqualToString:@"icon"]) { + return mIconImage; + } else if ([aColumn isEqualToString:@"col1"]) { + nsAutoString value; + item->GetValue(value); + result = [NSString stringWithCharacters:value.get() length:value.Length()]; + } else if ([aColumn isEqualToString:@"col2"]) { + PRUnichar *comment; + item->GetComment(&comment); + result = [NSString stringWithCharacters:comment length:nsCRT::strlen(comment)]; + } + + return result; +} + +-(int) numberOfRowsInTableView:(NSTableView*)aTableView +{ + return [self rowCount]; } -(id)tableView:(NSTableView*)aTableView objectValueForTableColumn:(NSTableColumn*)aTableColumn row:(int)aRowIndex { - return @""; + return [self resultString:aRowIndex column:[aTableColumn identifier]]; } @end diff --git a/camino/src/browser/AutoCompleteTextField.h b/camino/src/browser/AutoCompleteTextField.h new file mode 100644 index 000000000000..bcd888353ac9 --- /dev/null +++ b/camino/src/browser/AutoCompleteTextField.h @@ -0,0 +1,76 @@ +/* -*- 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 (Original Author) +*/ + +#import +#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; + BOOL mBackspaced; + + NSTimer *mOpenTimer; +} + +- (void) setSession:(NSString *)aSession; +- (NSString *) session; + +- (NSTableView *) tableView; +- (int) visibleRows; + +- (void) startSearch:(NSString*)aString; +- (void) performSearch; +- (void) dataReady:(nsIAutoCompleteResults*)aResults status:(AutoCompleteStatus)aStatus; +- (void) searchTimer:(NSTimer *)aTimer; + +- (void) completeDefaultResult; +- (void) completeResult:(int)aRow; +- (void) enterResult:(int)aRow; + +- (void) selectRowAt:(int)aRow; +- (void) selectRowBy:(int)aRows; + +- (void) openPopup; +- (void) closePopup; +- (void) resizePopup; +- (BOOL) isOpen; + +- (void) onBlur:(id)sender; +- (void) onResize:(id)sender; + +@end diff --git a/camino/src/browser/AutoCompleteTextField.mm b/camino/src/browser/AutoCompleteTextField.mm new file mode 100644 index 000000000000..79f71118efb3 --- /dev/null +++ b/camino/src/browser/AutoCompleteTextField.mm @@ -0,0 +1,447 @@ +/* -*- 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 (Original Author) +*/ + +#import "CHAutoCompleteTextField.h" +#import "CHPageProxyIcon.h" +#include "nsIServiceManager.h" +#include "nsMemory.h" +#include "nsString.h" + +static const int kMaxRows = 6; +static const int kFrameMargin = 1; + +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; + 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 = [[NSWindow alloc] initWithContentRect:NSMakeRect(0,0,0,0) + styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; + [mPopupWin setReleasedWhenClosed:NO]; + [mPopupWin setLevel:NSPopUpMenuWindowLevel]; + [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)]; + + // Create the icon column if we have a proxy icon + if (mProxyIcon != nil) { + 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] retain]; + [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]; +} + +- (void) dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + if (mSearchString) + [mSearchString release]; + + [mDataSource release]; + + NS_IF_RELEASE(mSession); + NS_IF_RELEASE(mResults); + NS_IF_RELEASE(mListener); +} + +- (void) setSession:(NSString *)aSession +{ + NS_IF_RELEASE(mSession); + + // XXX add aSession to contract id + nsCOMPtr 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; +} + +// searching //////////////////////////// + +- (void) startSearch:(NSString*)aString +{ + if (mSearchString) + [mSearchString release]; + mSearchString = [aString retain]; + + 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]; + + // 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; + } +} + +- (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]; +} + +// 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; + + // 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 (mBackspaced) { + [self selectRowAt:-1]; + mBackspaced = NO; + } else { + [self selectRowAt:defaultRow]; + [self completeResult:defaultRow]; + } +} + + +- (void) completeResult:(int)aRow +{ + NSRange matchRange; + NSText *text; + NSString *result1; + + if (aRow < 0) { + [self setStringValue:mSearchString]; + } else { + if ([mDataSource rowCount] <= 0) + return; + + result1 = [mDataSource resultString:aRow column:@"col1"]; + matchRange = [result1 rangeOfString:mSearchString]; + if (matchRange.length > 0) { + // cut off everything in the result string before the search string + result1 = [result1 substringWithRange:NSMakeRange(matchRange.location, [result1 length]-matchRange.location)]; + + // fill in the textfield with the matching string + [self setStringValue:result1]; + + // select the text after the search string + text = [[self window] fieldEditor:NO forObject:self]; + [text setSelectedRange:NSMakeRange([mSearchString length], [result1 length]-[mSearchString length])]; + } + } +} + +- (void) enterResult:(int)aRow +{ + if ([self isOpen] && aRow >= 0) { + [self setStringValue: [mDataSource resultString:[mTableView selectedRow] column:@"col1"]]; + } +} + +// selecting rows ///////////////////////////////////////// + +- (void) selectRowAt:(int)aRow +{ + [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) onBlur:(id)sender +{ + [self closePopup]; +} + +- (void) onResize:(id)sender +{ + [self resizePopup]; +} + +// NSTextField //////////////////////////////////////////// + +- (void)controlTextDidChange:(NSNotification *)aNotification +{ + [self startSearch:[self stringValue]]; +} + +- (void)controlTextDidEndEditing:(NSNotification *)aNotification +{ + [self closePopup]; +} + +// NSTextField delegate ////////////////////////////////// + +- (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]; + return YES; + } else if (command == @selector(moveDown:)) { + [self selectRowBy:1]; + return YES; + } else if (command == @selector(scrollPageUp:)) { + [self selectRowBy:-kMaxRows]; + } else if (command == @selector(scrollPageDown:)) { + [self selectRowBy:kMaxRows]; + } else if (command == @selector(moveToBeginningOfDocument:)) { + [self selectRowAt:0]; + } else if (command == @selector(moveToEndOfDocument:)) { + [self selectRowAt:[mTableView numberOfRows]-1]; + } else if (command == @selector(insertTab:) || command == @selector(insertNewline:)) { + [self closePopup]; + } 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 ([[self stringValue] length] > 1) + mBackspaced = YES; + } + + return NO; +} + +@end diff --git a/chimera/CHAutoCompleteTableView.h b/camino/src/browser/GoMenu.h similarity index 70% rename from chimera/CHAutoCompleteTableView.h rename to camino/src/browser/GoMenu.h index d8a86ae298bc..17e614302d80 100644 --- a/chimera/CHAutoCompleteTableView.h +++ b/camino/src/browser/GoMenu.h @@ -18,19 +18,19 @@ * Rights Reserved. * * Contributor(s): -* David Hyatt (Original Author) +* Joe Hewitt (Original Author) */ -#import -#import "BrowserWindowController.h" -#import "CHAutoCompleteDataSource.h" +#import + +@interface CHGoMenu : NSMenu { -@interface CHAutoCompleteTableView : NSTableView { - IBOutlet NSTextField* mURLBar; - IBOutlet BrowserWindowController* mWindowController; - CHAutoCompleteDataSource* mDataSource; } -- (BOOL)isShowing; +- (void) emptyHistoryItems; +- (void) addHistoryItems; + +// NSMenu +- (void) update; @end diff --git a/camino/src/browser/GoMenu.mm b/camino/src/browser/GoMenu.mm new file mode 100644 index 000000000000..487b84d7193e --- /dev/null +++ b/camino/src/browser/GoMenu.mm @@ -0,0 +1,147 @@ +/* -*- 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 (Original Author) +*/ + +#import "CHGoMenu.h" +#import "BrowserWindowController.h" +#import "CHBrowserWrapper.h" +#import "CHBrowserView.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "nsIWebBrowser.h" +#include "nsISHistory.h" +#include "nsIWebNavigation.h" +#include "nsIHistoryEntry.h" +#include "nsCRT.h" + +// the tag of the separator after which to insert history menu items +static const int kDividerTag = 4000; +// the maximum number of history entry menuitems to display +static const int kMaxItems = 15; +// the maximum number of characters in a menu title before cropping it +static const int kMaxTitleLength = 20; + +@implementation CHGoMenu + +- (void) update +{ + [self emptyHistoryItems]; + [self addHistoryItems]; + + [super update]; +} + +- (nsIWebNavigation*) currentWebNavigation +{ + // get controller for current window + BrowserWindowController *controller; + controller = (BrowserWindowController*)[[NSApp mainWindow] windowController]; + if (!controller) return nsnull; + + // get web navigation for current browser + CHBrowserWrapper* wrapper = [controller getBrowserWrapper]; + if (!wrapper) return nsnull; + CHBrowserView* view = [wrapper getBrowserView]; + if (!view) return nsnull; + nsCOMPtr webBrowser = [view getWebBrowser]; + if (!webBrowser) return nsnull; + nsCOMPtr webNav(do_QueryInterface(webBrowser)); + return webNav.get(); +} + +- (void) historyItemAction:(id)sender +{ + // get web navigation for current browser + nsCOMPtr webNav = [self currentWebNavigation]; + if (!webNav) return; + + // browse to the history entry for the menuitem that was selected + PRInt32 historyIndex = ([sender tag] - 1) - kDividerTag; + webNav->GotoIndex(historyIndex); +} + +- (void) emptyHistoryItems +{ + // remove every history item after the insertion point + int insertionIndex = [self indexOfItemWithTag:kDividerTag]; + for (int i = [self numberOfItems]-1; i > insertionIndex ; --i) { + [self removeItemAtIndex:i]; + } +} + +- (void) addHistoryItems +{ + // get session history for current browser + nsCOMPtr webNav = [self currentWebNavigation]; + if (!webNav) return; + nsCOMPtr sessionHistory; + webNav->GetSessionHistory(getter_AddRefs(sessionHistory)); + + PRInt32 count; + sessionHistory->GetCount(&count); + PRInt32 currentIndex; + sessionHistory->GetIndex(¤tIndex); + + // determine the range of items to display + int rangeStart, rangeEnd; + int above = kMaxItems/2; + int below = (kMaxItems-above)-1; + if (count <= kMaxItems) { + // if the whole history fits within our menu, fit range to show all + rangeStart = count-1; + rangeEnd = 0; + } else { + // if the whole history is too large for menu, try to put current index as close to + // the middle of the list as possible, so the user can see both back and forward in session + rangeStart = currentIndex + above; + rangeEnd = currentIndex - below; + if (rangeStart >= count-1) { + rangeEnd -= (rangeStart-count)+1; // shift overflow to the end + rangeStart = count-1; + } else if (rangeEnd < 0) { + rangeStart -= rangeEnd; // shift overflow to the start + rangeEnd = 0; + } + } + + // create a new menu item for each history entry (up to MAX_MENUITEM entries) + for (PRInt32 i = rangeStart; i >= rangeEnd; --i) { + nsCOMPtr entry; + sessionHistory->GetEntryAtIndex(i, PR_FALSE, getter_AddRefs(entry)); + + PRUnichar *text; + entry->GetTitle(&text); + NSString* title = [NSString stringWithCharacters: text length: nsCRT::strlen(text)]; + + if ([title length] > kMaxTitleLength) { + + } + + NSMenuItem *newItem = [self addItemWithTitle:title action:@selector(historyItemAction:) keyEquivalent:@""]; + [newItem setTarget:self]; + [newItem setTag:kDividerTag+1+i]; + if (currentIndex == i) + [newItem setState:NSOnState]; + } +} + +@end diff --git a/chimera/BrowserWindow.nib/classes.nib b/chimera/BrowserWindow.nib/classes.nib index 1ebea82c405d..1ad29253dc41 100644 --- a/chimera/BrowserWindow.nib/classes.nib +++ b/chimera/BrowserWindow.nib/classes.nib @@ -67,13 +67,14 @@ }; SUPERCLASS = NSWindowController; }, + {CLASS = CHAutoCompleteDataSource; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { - CLASS = CHAutoCompleteTableView; + ACTIONS = {onBlur = id; onResize = id; }; + CLASS = CHAutoCompleteTextField; LANGUAGE = ObjC; - OUTLETS = {mURLBar = NSTextField; mWindowController = BrowserWindowController; }; - SUPERCLASS = NSTableView; + OUTLETS = {mProxyIcon = CHPageProxyIcon; }; + SUPERCLASS = NSTextField; }, - {CLASS = CHAutoCompleteTextField; LANGUAGE = ObjC; SUPERCLASS = NSTextField; }, { CLASS = CHBookmarksOutlineView; LANGUAGE = ObjC; diff --git a/chimera/BrowserWindow.nib/info.nib b/chimera/BrowserWindow.nib/info.nib index 49c53f48dec3..69c87221fbef 100644 --- a/chimera/BrowserWindow.nib/info.nib +++ b/chimera/BrowserWindow.nib/info.nib @@ -22,10 +22,8 @@ 22 500 93 162 0 0 1152 746 463 7 444 200 252 0 0 1152 746 - 475 - 493 338 207 230 0 0 1152 746 56 - 340 478 343 68 0 0 1024 746 + 378 463 343 68 0 0 1152 746 IBFramework Version 248.0 @@ -43,6 +41,10 @@ 497 + IBOpenObjects + + 56 + IBSystem Version 5Q125 diff --git a/chimera/BrowserWindow.nib/objects.nib b/chimera/BrowserWindow.nib/objects.nib index b8b3f58e4615a20976e9b50b6d5fcb78e93ce507..07d94ae0dd20589257aec14d11a8a233d9b68ff2 100644 GIT binary patch literal 16669 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 literal 16892 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 (Original Author) */ -#import -#include "nsIAutoCompleteSession.h" +#import +#import "CHAutoCompleteTextField.h" +#include "nsIAutoCompleteResults.h" -@interface CHAutoCompleteDataSource : NSObject { - nsIAutoCompleteSession* mAutoComplete; +@class CHAutoCompleteTextField; + +@interface CHAutoCompleteDataSource : NSObject +{ + CHAutoCompleteTextField *mTextField; + NSImage *mIconImage; + + NSString* mErrorMessage; + nsIAutoCompleteResults *mResults; } --(void)initialize; +- (id) init; + +- (int) rowCount; +- (id) resultString:(int)aRow column:(NSString *)aColumn; + +- (void) setErrorMessage: (NSString*) error; +- (NSString*) errorMessage; + +- (void) setResults: (nsIAutoCompleteResults*) results; +- (nsIAutoCompleteResults*) results; @end diff --git a/chimera/CHAutoCompleteDataSource.mm b/chimera/CHAutoCompleteDataSource.mm index 8a57b887b486..eab2a47ed9ad 100644 --- a/chimera/CHAutoCompleteDataSource.mm +++ b/chimera/CHAutoCompleteDataSource.mm @@ -19,41 +19,106 @@ * * Contributor(s): * David Hyatt (Original Author) +* */ #import -#import "CHAutoCompleteDataSource.h" -#include "nsIServiceManager.h" +#import "CHAutoCompleteTextField.h" +#include "nsString.h" +#include "nsCRT.h" @implementation CHAutoCompleteDataSource -(id)init { if ((self = [super init])) { - mAutoComplete = nsnull; + mResults = nil; + mIconImage = [[NSImage imageNamed:@"globe_ico"] autorelease]; } return self; } --(void)initialize +-(void)dealloc { - if (!mAutoComplete) { - nsCOMPtr session = - do_GetService("@mozilla.org/autocompleteSession;1?type=history"); - mAutoComplete = session; - if (!mAutoComplete) - printf("Could not find autocomplete!\n"); - } + NS_IF_RELEASE(mResults); } --(int)numberOfRowsInTableView:(NSTableView*)aTableView +- (void) setErrorMessage: (NSString*) error { - return 0; + [self setResults:nsnull]; + mErrorMessage = error; +} + +- (NSString*) errorMessage +{ + return mErrorMessage; +} + +- (void) setResults:(nsIAutoCompleteResults*)aResults +{ + NS_IF_RELEASE(mResults); + + mErrorMessage = nil; + mResults = aResults; + NS_IF_ADDREF(mResults); +} + +- (nsIAutoCompleteResults *) results +{ + return mResults; +} + +- (int) rowCount +{ + if (!mResults) + return 0; + + nsCOMPtr items; + mResults->GetItems(getter_AddRefs(items)); + PRUint32 count; + items->Count(&count); + + return count; +} + +- (id) resultString:(int)aRow column:(NSString *)aColumn +{ + NSString *result = @""; + + if (!mResults) + return result; + + nsCOMPtr items; + mResults->GetItems(getter_AddRefs(items)); + + nsCOMPtr itemSupports = dont_AddRef(items->ElementAt(aRow)); + nsCOMPtr item = do_QueryInterface(itemSupports); + if (!item) + return result; + + if ([aColumn isEqualToString:@"icon"]) { + return mIconImage; + } else if ([aColumn isEqualToString:@"col1"]) { + nsAutoString value; + item->GetValue(value); + result = [NSString stringWithCharacters:value.get() length:value.Length()]; + } else if ([aColumn isEqualToString:@"col2"]) { + PRUnichar *comment; + item->GetComment(&comment); + result = [NSString stringWithCharacters:comment length:nsCRT::strlen(comment)]; + } + + return result; +} + +-(int) numberOfRowsInTableView:(NSTableView*)aTableView +{ + return [self rowCount]; } -(id)tableView:(NSTableView*)aTableView objectValueForTableColumn:(NSTableColumn*)aTableColumn row:(int)aRowIndex { - return @""; + return [self resultString:aRowIndex column:[aTableColumn identifier]]; } @end diff --git a/chimera/CHAutoCompleteTableView.mm b/chimera/CHAutoCompleteTableView.mm deleted file mode 100644 index 4f49a60d31e4..000000000000 --- a/chimera/CHAutoCompleteTableView.mm +++ /dev/null @@ -1,68 +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): -* David Hyatt (Original Author) -*/ - -#import "CHAutoCompleteTableView.h" -#import "CHAutoCompleteDataSource.h" - -@implementation CHAutoCompleteTableView - --(id)initWithFrame:(NSRect)aRect -{ - if ((self = [super initWithFrame: aRect])) { - // Create our data source. - mDataSource = [[CHAutoCompleteDataSource alloc] init]; - [self setDataSource: mDataSource]; - - // Create the URL column. - NSTableColumn* urlColumn = [[[NSTableColumn alloc] initWithIdentifier:@"URL"] autorelease]; - [self addTableColumn: urlColumn]; - NSTableColumn* titleColumn = [[[NSTableColumn alloc] initWithIdentifier:@"Title"] autorelease]; - [self addTableColumn: titleColumn]; - } - return self; -} - --(void)dealloc -{ - [mDataSource release]; - [super dealloc]; -} - --(BOOL)isShowing -{ - return ([self superview] != nil); -} - --(void)controlTextDidChange:(NSNotification*)aNotification -{ - // Ensure that our data source is initialized. - [mDataSource initialize]; - -// [[[[mWindowController window] contentView] superview] addSubview: self]; -} - --(void)controlTextDidEndEditing:(NSNotification*)aNotification -{ -} - -@end diff --git a/chimera/CHAutoCompleteTextField.h b/chimera/CHAutoCompleteTextField.h new file mode 100644 index 000000000000..bcd888353ac9 --- /dev/null +++ b/chimera/CHAutoCompleteTextField.h @@ -0,0 +1,76 @@ +/* -*- 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 (Original Author) +*/ + +#import +#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; + BOOL mBackspaced; + + NSTimer *mOpenTimer; +} + +- (void) setSession:(NSString *)aSession; +- (NSString *) session; + +- (NSTableView *) tableView; +- (int) visibleRows; + +- (void) startSearch:(NSString*)aString; +- (void) performSearch; +- (void) dataReady:(nsIAutoCompleteResults*)aResults status:(AutoCompleteStatus)aStatus; +- (void) searchTimer:(NSTimer *)aTimer; + +- (void) completeDefaultResult; +- (void) completeResult:(int)aRow; +- (void) enterResult:(int)aRow; + +- (void) selectRowAt:(int)aRow; +- (void) selectRowBy:(int)aRows; + +- (void) openPopup; +- (void) closePopup; +- (void) resizePopup; +- (BOOL) isOpen; + +- (void) onBlur:(id)sender; +- (void) onResize:(id)sender; + +@end diff --git a/chimera/CHAutoCompleteTextField.mm b/chimera/CHAutoCompleteTextField.mm new file mode 100644 index 000000000000..79f71118efb3 --- /dev/null +++ b/chimera/CHAutoCompleteTextField.mm @@ -0,0 +1,447 @@ +/* -*- 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 (Original Author) +*/ + +#import "CHAutoCompleteTextField.h" +#import "CHPageProxyIcon.h" +#include "nsIServiceManager.h" +#include "nsMemory.h" +#include "nsString.h" + +static const int kMaxRows = 6; +static const int kFrameMargin = 1; + +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; + 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 = [[NSWindow alloc] initWithContentRect:NSMakeRect(0,0,0,0) + styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; + [mPopupWin setReleasedWhenClosed:NO]; + [mPopupWin setLevel:NSPopUpMenuWindowLevel]; + [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)]; + + // Create the icon column if we have a proxy icon + if (mProxyIcon != nil) { + 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] retain]; + [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]; +} + +- (void) dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + if (mSearchString) + [mSearchString release]; + + [mDataSource release]; + + NS_IF_RELEASE(mSession); + NS_IF_RELEASE(mResults); + NS_IF_RELEASE(mListener); +} + +- (void) setSession:(NSString *)aSession +{ + NS_IF_RELEASE(mSession); + + // XXX add aSession to contract id + nsCOMPtr 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; +} + +// searching //////////////////////////// + +- (void) startSearch:(NSString*)aString +{ + if (mSearchString) + [mSearchString release]; + mSearchString = [aString retain]; + + 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]; + + // 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; + } +} + +- (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]; +} + +// 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; + + // 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 (mBackspaced) { + [self selectRowAt:-1]; + mBackspaced = NO; + } else { + [self selectRowAt:defaultRow]; + [self completeResult:defaultRow]; + } +} + + +- (void) completeResult:(int)aRow +{ + NSRange matchRange; + NSText *text; + NSString *result1; + + if (aRow < 0) { + [self setStringValue:mSearchString]; + } else { + if ([mDataSource rowCount] <= 0) + return; + + result1 = [mDataSource resultString:aRow column:@"col1"]; + matchRange = [result1 rangeOfString:mSearchString]; + if (matchRange.length > 0) { + // cut off everything in the result string before the search string + result1 = [result1 substringWithRange:NSMakeRange(matchRange.location, [result1 length]-matchRange.location)]; + + // fill in the textfield with the matching string + [self setStringValue:result1]; + + // select the text after the search string + text = [[self window] fieldEditor:NO forObject:self]; + [text setSelectedRange:NSMakeRange([mSearchString length], [result1 length]-[mSearchString length])]; + } + } +} + +- (void) enterResult:(int)aRow +{ + if ([self isOpen] && aRow >= 0) { + [self setStringValue: [mDataSource resultString:[mTableView selectedRow] column:@"col1"]]; + } +} + +// selecting rows ///////////////////////////////////////// + +- (void) selectRowAt:(int)aRow +{ + [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) onBlur:(id)sender +{ + [self closePopup]; +} + +- (void) onResize:(id)sender +{ + [self resizePopup]; +} + +// NSTextField //////////////////////////////////////////// + +- (void)controlTextDidChange:(NSNotification *)aNotification +{ + [self startSearch:[self stringValue]]; +} + +- (void)controlTextDidEndEditing:(NSNotification *)aNotification +{ + [self closePopup]; +} + +// NSTextField delegate ////////////////////////////////// + +- (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]; + return YES; + } else if (command == @selector(moveDown:)) { + [self selectRowBy:1]; + return YES; + } else if (command == @selector(scrollPageUp:)) { + [self selectRowBy:-kMaxRows]; + } else if (command == @selector(scrollPageDown:)) { + [self selectRowBy:kMaxRows]; + } else if (command == @selector(moveToBeginningOfDocument:)) { + [self selectRowAt:0]; + } else if (command == @selector(moveToEndOfDocument:)) { + [self selectRowAt:[mTableView numberOfRows]-1]; + } else if (command == @selector(insertTab:) || command == @selector(insertNewline:)) { + [self closePopup]; + } 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 ([[self stringValue] length] > 1) + mBackspaced = YES; + } + + return NO; +} + +@end diff --git a/chimera/CHGoMenu.h b/chimera/CHGoMenu.h new file mode 100644 index 000000000000..17e614302d80 --- /dev/null +++ b/chimera/CHGoMenu.h @@ -0,0 +1,36 @@ +/* -*- 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 (Original Author) +*/ + +#import + +@interface CHGoMenu : NSMenu { + +} + +- (void) emptyHistoryItems; +- (void) addHistoryItems; + +// NSMenu +- (void) update; + +@end diff --git a/chimera/CHGoMenu.mm b/chimera/CHGoMenu.mm new file mode 100644 index 000000000000..487b84d7193e --- /dev/null +++ b/chimera/CHGoMenu.mm @@ -0,0 +1,147 @@ +/* -*- 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 (Original Author) +*/ + +#import "CHGoMenu.h" +#import "BrowserWindowController.h" +#import "CHBrowserWrapper.h" +#import "CHBrowserView.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "nsIWebBrowser.h" +#include "nsISHistory.h" +#include "nsIWebNavigation.h" +#include "nsIHistoryEntry.h" +#include "nsCRT.h" + +// the tag of the separator after which to insert history menu items +static const int kDividerTag = 4000; +// the maximum number of history entry menuitems to display +static const int kMaxItems = 15; +// the maximum number of characters in a menu title before cropping it +static const int kMaxTitleLength = 20; + +@implementation CHGoMenu + +- (void) update +{ + [self emptyHistoryItems]; + [self addHistoryItems]; + + [super update]; +} + +- (nsIWebNavigation*) currentWebNavigation +{ + // get controller for current window + BrowserWindowController *controller; + controller = (BrowserWindowController*)[[NSApp mainWindow] windowController]; + if (!controller) return nsnull; + + // get web navigation for current browser + CHBrowserWrapper* wrapper = [controller getBrowserWrapper]; + if (!wrapper) return nsnull; + CHBrowserView* view = [wrapper getBrowserView]; + if (!view) return nsnull; + nsCOMPtr webBrowser = [view getWebBrowser]; + if (!webBrowser) return nsnull; + nsCOMPtr webNav(do_QueryInterface(webBrowser)); + return webNav.get(); +} + +- (void) historyItemAction:(id)sender +{ + // get web navigation for current browser + nsCOMPtr webNav = [self currentWebNavigation]; + if (!webNav) return; + + // browse to the history entry for the menuitem that was selected + PRInt32 historyIndex = ([sender tag] - 1) - kDividerTag; + webNav->GotoIndex(historyIndex); +} + +- (void) emptyHistoryItems +{ + // remove every history item after the insertion point + int insertionIndex = [self indexOfItemWithTag:kDividerTag]; + for (int i = [self numberOfItems]-1; i > insertionIndex ; --i) { + [self removeItemAtIndex:i]; + } +} + +- (void) addHistoryItems +{ + // get session history for current browser + nsCOMPtr webNav = [self currentWebNavigation]; + if (!webNav) return; + nsCOMPtr sessionHistory; + webNav->GetSessionHistory(getter_AddRefs(sessionHistory)); + + PRInt32 count; + sessionHistory->GetCount(&count); + PRInt32 currentIndex; + sessionHistory->GetIndex(¤tIndex); + + // determine the range of items to display + int rangeStart, rangeEnd; + int above = kMaxItems/2; + int below = (kMaxItems-above)-1; + if (count <= kMaxItems) { + // if the whole history fits within our menu, fit range to show all + rangeStart = count-1; + rangeEnd = 0; + } else { + // if the whole history is too large for menu, try to put current index as close to + // the middle of the list as possible, so the user can see both back and forward in session + rangeStart = currentIndex + above; + rangeEnd = currentIndex - below; + if (rangeStart >= count-1) { + rangeEnd -= (rangeStart-count)+1; // shift overflow to the end + rangeStart = count-1; + } else if (rangeEnd < 0) { + rangeStart -= rangeEnd; // shift overflow to the start + rangeEnd = 0; + } + } + + // create a new menu item for each history entry (up to MAX_MENUITEM entries) + for (PRInt32 i = rangeStart; i >= rangeEnd; --i) { + nsCOMPtr entry; + sessionHistory->GetEntryAtIndex(i, PR_FALSE, getter_AddRefs(entry)); + + PRUnichar *text; + entry->GetTitle(&text); + NSString* title = [NSString stringWithCharacters: text length: nsCRT::strlen(text)]; + + if ([title length] > kMaxTitleLength) { + + } + + NSMenuItem *newItem = [self addItemWithTitle:title action:@selector(historyItemAction:) keyEquivalent:@""]; + [newItem setTarget:self]; + [newItem setTag:kDividerTag+1+i]; + if (currentIndex == i) + [newItem setState:NSOnState]; + } +} + +@end diff --git a/chimera/Chimera.pbproj/project.pbxproj b/chimera/Chimera.pbproj/project.pbxproj index 873e19dd1d5d..4ebab3b0d650 100644 --- a/chimera/Chimera.pbproj/project.pbxproj +++ b/chimera/Chimera.pbproj/project.pbxproj @@ -27,6 +27,7 @@ F52D5CD4027A88C601A80166, F52F87CD027D75C301A80165, F52F87CE027D75C301A80165, + 2E748B73029A448D4B000102, ); isa = PBXGroup; name = Classes; @@ -409,6 +410,7 @@ F52F87D0027D75C301A80165, 2E293A01027F33604B000102, 2EEC3E63028138724B000102, + 2E748B74029A448D4B000102, ); isa = PBXHeadersBuildPhase; name = Headers; @@ -510,6 +512,7 @@ F52F87D2027D75C301A80165, 2E293A02027F33604B000102, 2EEC3E64028138724B000102, + 2E748B75029A448D4B000102, ); isa = PBXSourcesBuildPhase; name = Sources; @@ -569,6 +572,28 @@ settings = { }; }; + 2E748B72029A448D4B000102 = { + isa = PBXFileReference; + path = CHGoMenu.h; + refType = 4; + }; + 2E748B73029A448D4B000102 = { + isa = PBXFileReference; + path = CHGoMenu.mm; + refType = 4; + }; + 2E748B74029A448D4B000102 = { + fileRef = 2E748B72029A448D4B000102; + isa = PBXBuildFile; + settings = { + }; + }; + 2E748B75029A448D4B000102 = { + fileRef = 2E748B73029A448D4B000102; + isa = PBXBuildFile; + settings = { + }; + }; 2EEC3E6002810B184B000102 = { indentWidth = 2; isa = PBXFileReference; @@ -1009,6 +1034,7 @@ F52D5CD3027A88C601A80166, F52F87CB027D75C301A80165, F52F87CC027D75C301A80165, + 2E748B72029A448D4B000102, ); isa = PBXGroup; name = Headers; @@ -1483,12 +1509,12 @@ }; F52D5CCF027A887001A80166 = { isa = PBXFileReference; - path = CHAutoCompleteTableView.h; + path = CHAutoCompleteTextField.h; refType = 4; }; F52D5CD0027A887001A80166 = { isa = PBXFileReference; - path = CHAutoCompleteTableView.mm; + path = CHAutoCompleteTextField.mm; refType = 4; }; F52D5CD1027A887001A80166 = { diff --git a/chimera/English.lproj/BrowserWindow.nib/classes.nib b/chimera/English.lproj/BrowserWindow.nib/classes.nib index 1ebea82c405d..1ad29253dc41 100644 --- a/chimera/English.lproj/BrowserWindow.nib/classes.nib +++ b/chimera/English.lproj/BrowserWindow.nib/classes.nib @@ -67,13 +67,14 @@ }; SUPERCLASS = NSWindowController; }, + {CLASS = CHAutoCompleteDataSource; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { - CLASS = CHAutoCompleteTableView; + ACTIONS = {onBlur = id; onResize = id; }; + CLASS = CHAutoCompleteTextField; LANGUAGE = ObjC; - OUTLETS = {mURLBar = NSTextField; mWindowController = BrowserWindowController; }; - SUPERCLASS = NSTableView; + OUTLETS = {mProxyIcon = CHPageProxyIcon; }; + SUPERCLASS = NSTextField; }, - {CLASS = CHAutoCompleteTextField; LANGUAGE = ObjC; SUPERCLASS = NSTextField; }, { CLASS = CHBookmarksOutlineView; LANGUAGE = ObjC; diff --git a/chimera/English.lproj/BrowserWindow.nib/info.nib b/chimera/English.lproj/BrowserWindow.nib/info.nib index 49c53f48dec3..69c87221fbef 100644 --- a/chimera/English.lproj/BrowserWindow.nib/info.nib +++ b/chimera/English.lproj/BrowserWindow.nib/info.nib @@ -22,10 +22,8 @@ 22 500 93 162 0 0 1152 746 463 7 444 200 252 0 0 1152 746 - 475 - 493 338 207 230 0 0 1152 746 56 - 340 478 343 68 0 0 1024 746 + 378 463 343 68 0 0 1152 746 IBFramework Version 248.0 @@ -43,6 +41,10 @@ 497 + IBOpenObjects + + 56 + IBSystem Version 5Q125 diff --git a/chimera/English.lproj/BrowserWindow.nib/objects.nib b/chimera/English.lproj/BrowserWindow.nib/objects.nib index b8b3f58e4615a20976e9b50b6d5fcb78e93ce507..07d94ae0dd20589257aec14d11a8a233d9b68ff2 100644 GIT binary patch literal 16669 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 literal 16892 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 I)}ibEKfnvFQ~&?~ literal 9279 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 I)}ibEKfnvFQ~&?~ literal 9279 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 500 93 162 0 0 1152 746 463 7 444 200 252 0 0 1152 746 - 475 - 493 338 207 230 0 0 1152 746 56 - 340 478 343 68 0 0 1024 746 + 378 463 343 68 0 0 1152 746 IBFramework Version 248.0 @@ -43,6 +41,10 @@ 497 + IBOpenObjects + + 56 + IBSystem Version 5Q125 diff --git a/chimera/resources/localized/English.lproj/BrowserWindow.nib/objects.nib b/chimera/resources/localized/English.lproj/BrowserWindow.nib/objects.nib index b8b3f58e4615a20976e9b50b6d5fcb78e93ce507..07d94ae0dd20589257aec14d11a8a233d9b68ff2 100644 GIT binary patch literal 16669 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 literal 16892 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 I)}ibEKfnvFQ~&?~ literal 9279 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 (Original Author) */ -#import -#include "nsIAutoCompleteSession.h" +#import +#import "CHAutoCompleteTextField.h" +#include "nsIAutoCompleteResults.h" -@interface CHAutoCompleteDataSource : NSObject { - nsIAutoCompleteSession* mAutoComplete; +@class CHAutoCompleteTextField; + +@interface CHAutoCompleteDataSource : NSObject +{ + CHAutoCompleteTextField *mTextField; + NSImage *mIconImage; + + NSString* mErrorMessage; + nsIAutoCompleteResults *mResults; } --(void)initialize; +- (id) init; + +- (int) rowCount; +- (id) resultString:(int)aRow column:(NSString *)aColumn; + +- (void) setErrorMessage: (NSString*) error; +- (NSString*) errorMessage; + +- (void) setResults: (nsIAutoCompleteResults*) results; +- (nsIAutoCompleteResults*) results; @end diff --git a/chimera/src/browser/AutoCompleteDataSource.mm b/chimera/src/browser/AutoCompleteDataSource.mm index 8a57b887b486..eab2a47ed9ad 100644 --- a/chimera/src/browser/AutoCompleteDataSource.mm +++ b/chimera/src/browser/AutoCompleteDataSource.mm @@ -19,41 +19,106 @@ * * Contributor(s): * David Hyatt (Original Author) +* */ #import -#import "CHAutoCompleteDataSource.h" -#include "nsIServiceManager.h" +#import "CHAutoCompleteTextField.h" +#include "nsString.h" +#include "nsCRT.h" @implementation CHAutoCompleteDataSource -(id)init { if ((self = [super init])) { - mAutoComplete = nsnull; + mResults = nil; + mIconImage = [[NSImage imageNamed:@"globe_ico"] autorelease]; } return self; } --(void)initialize +-(void)dealloc { - if (!mAutoComplete) { - nsCOMPtr session = - do_GetService("@mozilla.org/autocompleteSession;1?type=history"); - mAutoComplete = session; - if (!mAutoComplete) - printf("Could not find autocomplete!\n"); - } + NS_IF_RELEASE(mResults); } --(int)numberOfRowsInTableView:(NSTableView*)aTableView +- (void) setErrorMessage: (NSString*) error { - return 0; + [self setResults:nsnull]; + mErrorMessage = error; +} + +- (NSString*) errorMessage +{ + return mErrorMessage; +} + +- (void) setResults:(nsIAutoCompleteResults*)aResults +{ + NS_IF_RELEASE(mResults); + + mErrorMessage = nil; + mResults = aResults; + NS_IF_ADDREF(mResults); +} + +- (nsIAutoCompleteResults *) results +{ + return mResults; +} + +- (int) rowCount +{ + if (!mResults) + return 0; + + nsCOMPtr items; + mResults->GetItems(getter_AddRefs(items)); + PRUint32 count; + items->Count(&count); + + return count; +} + +- (id) resultString:(int)aRow column:(NSString *)aColumn +{ + NSString *result = @""; + + if (!mResults) + return result; + + nsCOMPtr items; + mResults->GetItems(getter_AddRefs(items)); + + nsCOMPtr itemSupports = dont_AddRef(items->ElementAt(aRow)); + nsCOMPtr item = do_QueryInterface(itemSupports); + if (!item) + return result; + + if ([aColumn isEqualToString:@"icon"]) { + return mIconImage; + } else if ([aColumn isEqualToString:@"col1"]) { + nsAutoString value; + item->GetValue(value); + result = [NSString stringWithCharacters:value.get() length:value.Length()]; + } else if ([aColumn isEqualToString:@"col2"]) { + PRUnichar *comment; + item->GetComment(&comment); + result = [NSString stringWithCharacters:comment length:nsCRT::strlen(comment)]; + } + + return result; +} + +-(int) numberOfRowsInTableView:(NSTableView*)aTableView +{ + return [self rowCount]; } -(id)tableView:(NSTableView*)aTableView objectValueForTableColumn:(NSTableColumn*)aTableColumn row:(int)aRowIndex { - return @""; + return [self resultString:aRowIndex column:[aTableColumn identifier]]; } @end diff --git a/chimera/src/browser/AutoCompleteTextField.h b/chimera/src/browser/AutoCompleteTextField.h new file mode 100644 index 000000000000..bcd888353ac9 --- /dev/null +++ b/chimera/src/browser/AutoCompleteTextField.h @@ -0,0 +1,76 @@ +/* -*- 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 (Original Author) +*/ + +#import +#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; + BOOL mBackspaced; + + NSTimer *mOpenTimer; +} + +- (void) setSession:(NSString *)aSession; +- (NSString *) session; + +- (NSTableView *) tableView; +- (int) visibleRows; + +- (void) startSearch:(NSString*)aString; +- (void) performSearch; +- (void) dataReady:(nsIAutoCompleteResults*)aResults status:(AutoCompleteStatus)aStatus; +- (void) searchTimer:(NSTimer *)aTimer; + +- (void) completeDefaultResult; +- (void) completeResult:(int)aRow; +- (void) enterResult:(int)aRow; + +- (void) selectRowAt:(int)aRow; +- (void) selectRowBy:(int)aRows; + +- (void) openPopup; +- (void) closePopup; +- (void) resizePopup; +- (BOOL) isOpen; + +- (void) onBlur:(id)sender; +- (void) onResize:(id)sender; + +@end diff --git a/chimera/src/browser/AutoCompleteTextField.mm b/chimera/src/browser/AutoCompleteTextField.mm new file mode 100644 index 000000000000..79f71118efb3 --- /dev/null +++ b/chimera/src/browser/AutoCompleteTextField.mm @@ -0,0 +1,447 @@ +/* -*- 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 (Original Author) +*/ + +#import "CHAutoCompleteTextField.h" +#import "CHPageProxyIcon.h" +#include "nsIServiceManager.h" +#include "nsMemory.h" +#include "nsString.h" + +static const int kMaxRows = 6; +static const int kFrameMargin = 1; + +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; + 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 = [[NSWindow alloc] initWithContentRect:NSMakeRect(0,0,0,0) + styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; + [mPopupWin setReleasedWhenClosed:NO]; + [mPopupWin setLevel:NSPopUpMenuWindowLevel]; + [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)]; + + // Create the icon column if we have a proxy icon + if (mProxyIcon != nil) { + 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] retain]; + [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]; +} + +- (void) dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + if (mSearchString) + [mSearchString release]; + + [mDataSource release]; + + NS_IF_RELEASE(mSession); + NS_IF_RELEASE(mResults); + NS_IF_RELEASE(mListener); +} + +- (void) setSession:(NSString *)aSession +{ + NS_IF_RELEASE(mSession); + + // XXX add aSession to contract id + nsCOMPtr 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; +} + +// searching //////////////////////////// + +- (void) startSearch:(NSString*)aString +{ + if (mSearchString) + [mSearchString release]; + mSearchString = [aString retain]; + + 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]; + + // 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; + } +} + +- (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]; +} + +// 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; + + // 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 (mBackspaced) { + [self selectRowAt:-1]; + mBackspaced = NO; + } else { + [self selectRowAt:defaultRow]; + [self completeResult:defaultRow]; + } +} + + +- (void) completeResult:(int)aRow +{ + NSRange matchRange; + NSText *text; + NSString *result1; + + if (aRow < 0) { + [self setStringValue:mSearchString]; + } else { + if ([mDataSource rowCount] <= 0) + return; + + result1 = [mDataSource resultString:aRow column:@"col1"]; + matchRange = [result1 rangeOfString:mSearchString]; + if (matchRange.length > 0) { + // cut off everything in the result string before the search string + result1 = [result1 substringWithRange:NSMakeRange(matchRange.location, [result1 length]-matchRange.location)]; + + // fill in the textfield with the matching string + [self setStringValue:result1]; + + // select the text after the search string + text = [[self window] fieldEditor:NO forObject:self]; + [text setSelectedRange:NSMakeRange([mSearchString length], [result1 length]-[mSearchString length])]; + } + } +} + +- (void) enterResult:(int)aRow +{ + if ([self isOpen] && aRow >= 0) { + [self setStringValue: [mDataSource resultString:[mTableView selectedRow] column:@"col1"]]; + } +} + +// selecting rows ///////////////////////////////////////// + +- (void) selectRowAt:(int)aRow +{ + [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) onBlur:(id)sender +{ + [self closePopup]; +} + +- (void) onResize:(id)sender +{ + [self resizePopup]; +} + +// NSTextField //////////////////////////////////////////// + +- (void)controlTextDidChange:(NSNotification *)aNotification +{ + [self startSearch:[self stringValue]]; +} + +- (void)controlTextDidEndEditing:(NSNotification *)aNotification +{ + [self closePopup]; +} + +// NSTextField delegate ////////////////////////////////// + +- (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]; + return YES; + } else if (command == @selector(moveDown:)) { + [self selectRowBy:1]; + return YES; + } else if (command == @selector(scrollPageUp:)) { + [self selectRowBy:-kMaxRows]; + } else if (command == @selector(scrollPageDown:)) { + [self selectRowBy:kMaxRows]; + } else if (command == @selector(moveToBeginningOfDocument:)) { + [self selectRowAt:0]; + } else if (command == @selector(moveToEndOfDocument:)) { + [self selectRowAt:[mTableView numberOfRows]-1]; + } else if (command == @selector(insertTab:) || command == @selector(insertNewline:)) { + [self closePopup]; + } 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 ([[self stringValue] length] > 1) + mBackspaced = YES; + } + + return NO; +} + +@end diff --git a/chimera/src/browser/GoMenu.h b/chimera/src/browser/GoMenu.h new file mode 100644 index 000000000000..17e614302d80 --- /dev/null +++ b/chimera/src/browser/GoMenu.h @@ -0,0 +1,36 @@ +/* -*- 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 (Original Author) +*/ + +#import + +@interface CHGoMenu : NSMenu { + +} + +- (void) emptyHistoryItems; +- (void) addHistoryItems; + +// NSMenu +- (void) update; + +@end diff --git a/chimera/src/browser/GoMenu.mm b/chimera/src/browser/GoMenu.mm new file mode 100644 index 000000000000..487b84d7193e --- /dev/null +++ b/chimera/src/browser/GoMenu.mm @@ -0,0 +1,147 @@ +/* -*- 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 (Original Author) +*/ + +#import "CHGoMenu.h" +#import "BrowserWindowController.h" +#import "CHBrowserWrapper.h" +#import "CHBrowserView.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "nsIWebBrowser.h" +#include "nsISHistory.h" +#include "nsIWebNavigation.h" +#include "nsIHistoryEntry.h" +#include "nsCRT.h" + +// the tag of the separator after which to insert history menu items +static const int kDividerTag = 4000; +// the maximum number of history entry menuitems to display +static const int kMaxItems = 15; +// the maximum number of characters in a menu title before cropping it +static const int kMaxTitleLength = 20; + +@implementation CHGoMenu + +- (void) update +{ + [self emptyHistoryItems]; + [self addHistoryItems]; + + [super update]; +} + +- (nsIWebNavigation*) currentWebNavigation +{ + // get controller for current window + BrowserWindowController *controller; + controller = (BrowserWindowController*)[[NSApp mainWindow] windowController]; + if (!controller) return nsnull; + + // get web navigation for current browser + CHBrowserWrapper* wrapper = [controller getBrowserWrapper]; + if (!wrapper) return nsnull; + CHBrowserView* view = [wrapper getBrowserView]; + if (!view) return nsnull; + nsCOMPtr webBrowser = [view getWebBrowser]; + if (!webBrowser) return nsnull; + nsCOMPtr webNav(do_QueryInterface(webBrowser)); + return webNav.get(); +} + +- (void) historyItemAction:(id)sender +{ + // get web navigation for current browser + nsCOMPtr webNav = [self currentWebNavigation]; + if (!webNav) return; + + // browse to the history entry for the menuitem that was selected + PRInt32 historyIndex = ([sender tag] - 1) - kDividerTag; + webNav->GotoIndex(historyIndex); +} + +- (void) emptyHistoryItems +{ + // remove every history item after the insertion point + int insertionIndex = [self indexOfItemWithTag:kDividerTag]; + for (int i = [self numberOfItems]-1; i > insertionIndex ; --i) { + [self removeItemAtIndex:i]; + } +} + +- (void) addHistoryItems +{ + // get session history for current browser + nsCOMPtr webNav = [self currentWebNavigation]; + if (!webNav) return; + nsCOMPtr sessionHistory; + webNav->GetSessionHistory(getter_AddRefs(sessionHistory)); + + PRInt32 count; + sessionHistory->GetCount(&count); + PRInt32 currentIndex; + sessionHistory->GetIndex(¤tIndex); + + // determine the range of items to display + int rangeStart, rangeEnd; + int above = kMaxItems/2; + int below = (kMaxItems-above)-1; + if (count <= kMaxItems) { + // if the whole history fits within our menu, fit range to show all + rangeStart = count-1; + rangeEnd = 0; + } else { + // if the whole history is too large for menu, try to put current index as close to + // the middle of the list as possible, so the user can see both back and forward in session + rangeStart = currentIndex + above; + rangeEnd = currentIndex - below; + if (rangeStart >= count-1) { + rangeEnd -= (rangeStart-count)+1; // shift overflow to the end + rangeStart = count-1; + } else if (rangeEnd < 0) { + rangeStart -= rangeEnd; // shift overflow to the start + rangeEnd = 0; + } + } + + // create a new menu item for each history entry (up to MAX_MENUITEM entries) + for (PRInt32 i = rangeStart; i >= rangeEnd; --i) { + nsCOMPtr entry; + sessionHistory->GetEntryAtIndex(i, PR_FALSE, getter_AddRefs(entry)); + + PRUnichar *text; + entry->GetTitle(&text); + NSString* title = [NSString stringWithCharacters: text length: nsCRT::strlen(text)]; + + if ([title length] > kMaxTitleLength) { + + } + + NSMenuItem *newItem = [self addItemWithTitle:title action:@selector(historyItemAction:) keyEquivalent:@""]; + [newItem setTarget:self]; + [newItem setTag:kDividerTag+1+i]; + if (currentIndex == i) + [newItem setState:NSOnState]; + } +} + +@end