mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-21 17:59:34 +00:00
145802 - session history in Go menu for Chimera, 145803 - urlbar autocomplete for chimera
This commit is contained in:
parent
c58b0f7441
commit
d8e9c91f64
9
camino/BrowserWindow.nib/classes.nib
generated
9
camino/BrowserWindow.nib/classes.nib
generated
@ -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;
|
||||
|
8
camino/BrowserWindow.nib/info.nib
generated
8
camino/BrowserWindow.nib/info.nib
generated
@ -22,10 +22,8 @@
|
||||
<string>22 500 93 162 0 0 1152 746 </string>
|
||||
<key>463</key>
|
||||
<string>7 444 200 252 0 0 1152 746 </string>
|
||||
<key>475</key>
|
||||
<string>493 338 207 230 0 0 1152 746 </string>
|
||||
<key>56</key>
|
||||
<string>340 478 343 68 0 0 1024 746 </string>
|
||||
<string>378 463 343 68 0 0 1152 746 </string>
|
||||
</dict>
|
||||
<key>IBFramework Version</key>
|
||||
<string>248.0</string>
|
||||
@ -43,6 +41,10 @@
|
||||
<array>
|
||||
<integer>497</integer>
|
||||
</array>
|
||||
<key>IBOpenObjects</key>
|
||||
<array>
|
||||
<integer>56</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
<string>5Q125</string>
|
||||
</dict>
|
||||
|
BIN
camino/BrowserWindow.nib/objects.nib
generated
BIN
camino/BrowserWindow.nib/objects.nib
generated
Binary file not shown.
@ -21,13 +21,30 @@
|
||||
* David Hyatt <hyatt@netscape.com> (Original Author)
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#include "nsIAutoCompleteSession.h"
|
||||
#import <AppKit/AppKit.h>
|
||||
#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
|
||||
|
@ -19,41 +19,106 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* David Hyatt <hyatt@netscape.com> (Original Author)
|
||||
*
|
||||
*/
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#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<nsIAutoCompleteSession> 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<nsISupportsArray> 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<nsISupportsArray> items;
|
||||
mResults->GetItems(getter_AddRefs(items));
|
||||
|
||||
nsCOMPtr<nsISupports> itemSupports = dont_AddRef(items->ElementAt(aRow));
|
||||
nsCOMPtr<nsIAutoCompleteItem> 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
|
||||
|
@ -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 <hyatt@netscape.com> (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
|
76
camino/CHAutoCompleteTextField.h
Normal file
76
camino/CHAutoCompleteTextField.h
Normal file
@ -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 <hewitt@netscape.com> (Original Author)
|
||||
*/
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import "CHAutoCompleteDataSource.h"
|
||||
#include "nsIAutoCompleteSession.h"
|
||||
#include "nsIAutoCompleteResults.h"
|
||||
#include "nsIAutoCompleteListener.h"
|
||||
|
||||
@class CHAutoCompleteDataSource, CHPageProxyIcon;
|
||||
|
||||
@interface CHAutoCompleteTextField : NSTextField
|
||||
{
|
||||
IBOutlet CHPageProxyIcon *mProxyIcon;
|
||||
NSWindow *mPopupWin;
|
||||
NSTableView *mTableView;
|
||||
|
||||
CHAutoCompleteDataSource *mDataSource;
|
||||
|
||||
nsIAutoCompleteSession *mSession;
|
||||
nsIAutoCompleteResults *mResults;
|
||||
nsIAutoCompleteListener *mListener;
|
||||
|
||||
NSString* mSearchString;
|
||||
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
|
447
camino/CHAutoCompleteTextField.mm
Normal file
447
camino/CHAutoCompleteTextField.mm
Normal file
@ -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 <hewitt@netscape.com> (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<nsIAutoCompleteSession> session =
|
||||
do_GetService("@mozilla.org/autocompleteSession;1?type=history");
|
||||
mSession = session;
|
||||
NS_IF_ADDREF(mSession);
|
||||
}
|
||||
|
||||
- (NSString *) session
|
||||
{
|
||||
// XXX return session name
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSTableView *) tableView
|
||||
{
|
||||
return mTableView;
|
||||
}
|
||||
|
||||
- (int) visibleRows
|
||||
{
|
||||
int minRows = [mDataSource rowCount];
|
||||
return minRows < kMaxRows ? minRows : kMaxRows;
|
||||
}
|
||||
|
||||
// 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
|
@ -18,19 +18,19 @@
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* David Hyatt <hyatt@netscape.com> (Original Author)
|
||||
* Joe Hewitt <hewitt@netscape.com> (Original Author)
|
||||
*/
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import "BrowserWindowController.h"
|
||||
#import "CHAutoCompleteDataSource.h"
|
||||
#import <Appkit/Appkit.h>
|
||||
|
||||
@interface CHGoMenu : NSMenu {
|
||||
|
||||
@interface CHAutoCompleteTableView : NSTableView {
|
||||
IBOutlet NSTextField* mURLBar;
|
||||
IBOutlet BrowserWindowController* mWindowController;
|
||||
CHAutoCompleteDataSource* mDataSource;
|
||||
}
|
||||
|
||||
- (BOOL)isShowing;
|
||||
- (void) emptyHistoryItems;
|
||||
- (void) addHistoryItems;
|
||||
|
||||
// NSMenu
|
||||
- (void) update;
|
||||
|
||||
@end
|
147
camino/CHGoMenu.mm
Normal file
147
camino/CHGoMenu.mm
Normal file
@ -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 <hewitt@netscape.com> (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<nsIWebBrowser> webBrowser = [view getWebBrowser];
|
||||
if (!webBrowser) return nsnull;
|
||||
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(webBrowser));
|
||||
return webNav.get();
|
||||
}
|
||||
|
||||
- (void) historyItemAction:(id)sender
|
||||
{
|
||||
// get web navigation for current browser
|
||||
nsCOMPtr<nsIWebNavigation> 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<nsIWebNavigation> webNav = [self currentWebNavigation];
|
||||
if (!webNav) return;
|
||||
nsCOMPtr<nsISHistory> 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<nsIHistoryEntry> 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
|
@ -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 = {
|
||||
|
@ -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;
|
||||
|
8
camino/English.lproj/BrowserWindow.nib/info.nib
generated
8
camino/English.lproj/BrowserWindow.nib/info.nib
generated
@ -22,10 +22,8 @@
|
||||
<string>22 500 93 162 0 0 1152 746 </string>
|
||||
<key>463</key>
|
||||
<string>7 444 200 252 0 0 1152 746 </string>
|
||||
<key>475</key>
|
||||
<string>493 338 207 230 0 0 1152 746 </string>
|
||||
<key>56</key>
|
||||
<string>340 478 343 68 0 0 1024 746 </string>
|
||||
<string>378 463 343 68 0 0 1152 746 </string>
|
||||
</dict>
|
||||
<key>IBFramework Version</key>
|
||||
<string>248.0</string>
|
||||
@ -43,6 +41,10 @@
|
||||
<array>
|
||||
<integer>497</integer>
|
||||
</array>
|
||||
<key>IBOpenObjects</key>
|
||||
<array>
|
||||
<integer>56</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
<string>5Q125</string>
|
||||
</dict>
|
||||
|
BIN
camino/English.lproj/BrowserWindow.nib/objects.nib
generated
BIN
camino/English.lproj/BrowserWindow.nib/objects.nib
generated
Binary file not shown.
1
camino/English.lproj/MainMenu.nib/classes.nib
generated
1
camino/English.lproj/MainMenu.nib/classes.nib
generated
@ -5,6 +5,7 @@
|
||||
LANGUAGE = ObjC;
|
||||
SUPERCLASS = ToolbarController;
|
||||
},
|
||||
{CLASS = CHGoMenu; LANGUAGE = ObjC; SUPERCLASS = NSMenu; },
|
||||
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
|
||||
{
|
||||
ACTIONS = {
|
||||
|
BIN
camino/English.lproj/MainMenu.nib/objects.nib
generated
BIN
camino/English.lproj/MainMenu.nib/objects.nib
generated
Binary file not shown.
1
camino/MainMenu.nib/classes.nib
generated
1
camino/MainMenu.nib/classes.nib
generated
@ -5,6 +5,7 @@
|
||||
LANGUAGE = ObjC;
|
||||
SUPERCLASS = ToolbarController;
|
||||
},
|
||||
{CLASS = CHGoMenu; LANGUAGE = ObjC; SUPERCLASS = NSMenu; },
|
||||
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
|
||||
{
|
||||
ACTIONS = {
|
||||
|
BIN
camino/MainMenu.nib/objects.nib
generated
BIN
camino/MainMenu.nib/objects.nib
generated
Binary file not shown.
@ -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 = {
|
||||
|
@ -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;
|
||||
|
@ -22,10 +22,8 @@
|
||||
<string>22 500 93 162 0 0 1152 746 </string>
|
||||
<key>463</key>
|
||||
<string>7 444 200 252 0 0 1152 746 </string>
|
||||
<key>475</key>
|
||||
<string>493 338 207 230 0 0 1152 746 </string>
|
||||
<key>56</key>
|
||||
<string>340 478 343 68 0 0 1024 746 </string>
|
||||
<string>378 463 343 68 0 0 1152 746 </string>
|
||||
</dict>
|
||||
<key>IBFramework Version</key>
|
||||
<string>248.0</string>
|
||||
@ -43,6 +41,10 @@
|
||||
<array>
|
||||
<integer>497</integer>
|
||||
</array>
|
||||
<key>IBOpenObjects</key>
|
||||
<array>
|
||||
<integer>56</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
<string>5Q125</string>
|
||||
</dict>
|
||||
|
Binary file not shown.
@ -5,6 +5,7 @@
|
||||
LANGUAGE = ObjC;
|
||||
SUPERCLASS = ToolbarController;
|
||||
},
|
||||
{CLASS = CHGoMenu; LANGUAGE = ObjC; SUPERCLASS = NSMenu; },
|
||||
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
|
||||
{
|
||||
ACTIONS = {
|
||||
|
Binary file not shown.
@ -21,13 +21,30 @@
|
||||
* David Hyatt <hyatt@netscape.com> (Original Author)
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#include "nsIAutoCompleteSession.h"
|
||||
#import <AppKit/AppKit.h>
|
||||
#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
|
||||
|
@ -19,41 +19,106 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* David Hyatt <hyatt@netscape.com> (Original Author)
|
||||
*
|
||||
*/
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#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<nsIAutoCompleteSession> 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<nsISupportsArray> 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<nsISupportsArray> items;
|
||||
mResults->GetItems(getter_AddRefs(items));
|
||||
|
||||
nsCOMPtr<nsISupports> itemSupports = dont_AddRef(items->ElementAt(aRow));
|
||||
nsCOMPtr<nsIAutoCompleteItem> 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
|
||||
|
76
camino/src/browser/AutoCompleteTextField.h
Normal file
76
camino/src/browser/AutoCompleteTextField.h
Normal file
@ -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 <hewitt@netscape.com> (Original Author)
|
||||
*/
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import "CHAutoCompleteDataSource.h"
|
||||
#include "nsIAutoCompleteSession.h"
|
||||
#include "nsIAutoCompleteResults.h"
|
||||
#include "nsIAutoCompleteListener.h"
|
||||
|
||||
@class CHAutoCompleteDataSource, CHPageProxyIcon;
|
||||
|
||||
@interface CHAutoCompleteTextField : NSTextField
|
||||
{
|
||||
IBOutlet CHPageProxyIcon *mProxyIcon;
|
||||
NSWindow *mPopupWin;
|
||||
NSTableView *mTableView;
|
||||
|
||||
CHAutoCompleteDataSource *mDataSource;
|
||||
|
||||
nsIAutoCompleteSession *mSession;
|
||||
nsIAutoCompleteResults *mResults;
|
||||
nsIAutoCompleteListener *mListener;
|
||||
|
||||
NSString* mSearchString;
|
||||
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
|
447
camino/src/browser/AutoCompleteTextField.mm
Normal file
447
camino/src/browser/AutoCompleteTextField.mm
Normal file
@ -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 <hewitt@netscape.com> (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<nsIAutoCompleteSession> session =
|
||||
do_GetService("@mozilla.org/autocompleteSession;1?type=history");
|
||||
mSession = session;
|
||||
NS_IF_ADDREF(mSession);
|
||||
}
|
||||
|
||||
- (NSString *) session
|
||||
{
|
||||
// XXX return session name
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSTableView *) tableView
|
||||
{
|
||||
return mTableView;
|
||||
}
|
||||
|
||||
- (int) visibleRows
|
||||
{
|
||||
int minRows = [mDataSource rowCount];
|
||||
return minRows < kMaxRows ? minRows : kMaxRows;
|
||||
}
|
||||
|
||||
// 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
|
@ -18,19 +18,19 @@
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* David Hyatt <hyatt@netscape.com> (Original Author)
|
||||
* Joe Hewitt <hewitt@netscape.com> (Original Author)
|
||||
*/
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import "BrowserWindowController.h"
|
||||
#import "CHAutoCompleteDataSource.h"
|
||||
#import <Appkit/Appkit.h>
|
||||
|
||||
@interface CHGoMenu : NSMenu {
|
||||
|
||||
@interface CHAutoCompleteTableView : NSTableView {
|
||||
IBOutlet NSTextField* mURLBar;
|
||||
IBOutlet BrowserWindowController* mWindowController;
|
||||
CHAutoCompleteDataSource* mDataSource;
|
||||
}
|
||||
|
||||
- (BOOL)isShowing;
|
||||
- (void) emptyHistoryItems;
|
||||
- (void) addHistoryItems;
|
||||
|
||||
// NSMenu
|
||||
- (void) update;
|
||||
|
||||
@end
|
147
camino/src/browser/GoMenu.mm
Normal file
147
camino/src/browser/GoMenu.mm
Normal file
@ -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 <hewitt@netscape.com> (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<nsIWebBrowser> webBrowser = [view getWebBrowser];
|
||||
if (!webBrowser) return nsnull;
|
||||
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(webBrowser));
|
||||
return webNav.get();
|
||||
}
|
||||
|
||||
- (void) historyItemAction:(id)sender
|
||||
{
|
||||
// get web navigation for current browser
|
||||
nsCOMPtr<nsIWebNavigation> 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<nsIWebNavigation> webNav = [self currentWebNavigation];
|
||||
if (!webNav) return;
|
||||
nsCOMPtr<nsISHistory> 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<nsIHistoryEntry> 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
|
9
chimera/BrowserWindow.nib/classes.nib
generated
9
chimera/BrowserWindow.nib/classes.nib
generated
@ -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;
|
||||
|
8
chimera/BrowserWindow.nib/info.nib
generated
8
chimera/BrowserWindow.nib/info.nib
generated
@ -22,10 +22,8 @@
|
||||
<string>22 500 93 162 0 0 1152 746 </string>
|
||||
<key>463</key>
|
||||
<string>7 444 200 252 0 0 1152 746 </string>
|
||||
<key>475</key>
|
||||
<string>493 338 207 230 0 0 1152 746 </string>
|
||||
<key>56</key>
|
||||
<string>340 478 343 68 0 0 1024 746 </string>
|
||||
<string>378 463 343 68 0 0 1152 746 </string>
|
||||
</dict>
|
||||
<key>IBFramework Version</key>
|
||||
<string>248.0</string>
|
||||
@ -43,6 +41,10 @@
|
||||
<array>
|
||||
<integer>497</integer>
|
||||
</array>
|
||||
<key>IBOpenObjects</key>
|
||||
<array>
|
||||
<integer>56</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
<string>5Q125</string>
|
||||
</dict>
|
||||
|
BIN
chimera/BrowserWindow.nib/objects.nib
generated
BIN
chimera/BrowserWindow.nib/objects.nib
generated
Binary file not shown.
@ -21,13 +21,30 @@
|
||||
* David Hyatt <hyatt@netscape.com> (Original Author)
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#include "nsIAutoCompleteSession.h"
|
||||
#import <AppKit/AppKit.h>
|
||||
#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
|
||||
|
@ -19,41 +19,106 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* David Hyatt <hyatt@netscape.com> (Original Author)
|
||||
*
|
||||
*/
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#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<nsIAutoCompleteSession> 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<nsISupportsArray> 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<nsISupportsArray> items;
|
||||
mResults->GetItems(getter_AddRefs(items));
|
||||
|
||||
nsCOMPtr<nsISupports> itemSupports = dont_AddRef(items->ElementAt(aRow));
|
||||
nsCOMPtr<nsIAutoCompleteItem> 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
|
||||
|
@ -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 <hyatt@netscape.com> (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
|
76
chimera/CHAutoCompleteTextField.h
Normal file
76
chimera/CHAutoCompleteTextField.h
Normal file
@ -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 <hewitt@netscape.com> (Original Author)
|
||||
*/
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import "CHAutoCompleteDataSource.h"
|
||||
#include "nsIAutoCompleteSession.h"
|
||||
#include "nsIAutoCompleteResults.h"
|
||||
#include "nsIAutoCompleteListener.h"
|
||||
|
||||
@class CHAutoCompleteDataSource, CHPageProxyIcon;
|
||||
|
||||
@interface CHAutoCompleteTextField : NSTextField
|
||||
{
|
||||
IBOutlet CHPageProxyIcon *mProxyIcon;
|
||||
NSWindow *mPopupWin;
|
||||
NSTableView *mTableView;
|
||||
|
||||
CHAutoCompleteDataSource *mDataSource;
|
||||
|
||||
nsIAutoCompleteSession *mSession;
|
||||
nsIAutoCompleteResults *mResults;
|
||||
nsIAutoCompleteListener *mListener;
|
||||
|
||||
NSString* mSearchString;
|
||||
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
|
447
chimera/CHAutoCompleteTextField.mm
Normal file
447
chimera/CHAutoCompleteTextField.mm
Normal file
@ -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 <hewitt@netscape.com> (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<nsIAutoCompleteSession> session =
|
||||
do_GetService("@mozilla.org/autocompleteSession;1?type=history");
|
||||
mSession = session;
|
||||
NS_IF_ADDREF(mSession);
|
||||
}
|
||||
|
||||
- (NSString *) session
|
||||
{
|
||||
// XXX return session name
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSTableView *) tableView
|
||||
{
|
||||
return mTableView;
|
||||
}
|
||||
|
||||
- (int) visibleRows
|
||||
{
|
||||
int minRows = [mDataSource rowCount];
|
||||
return minRows < kMaxRows ? minRows : kMaxRows;
|
||||
}
|
||||
|
||||
// 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
|
36
chimera/CHGoMenu.h
Normal file
36
chimera/CHGoMenu.h
Normal file
@ -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 <hewitt@netscape.com> (Original Author)
|
||||
*/
|
||||
|
||||
#import <Appkit/Appkit.h>
|
||||
|
||||
@interface CHGoMenu : NSMenu {
|
||||
|
||||
}
|
||||
|
||||
- (void) emptyHistoryItems;
|
||||
- (void) addHistoryItems;
|
||||
|
||||
// NSMenu
|
||||
- (void) update;
|
||||
|
||||
@end
|
147
chimera/CHGoMenu.mm
Normal file
147
chimera/CHGoMenu.mm
Normal file
@ -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 <hewitt@netscape.com> (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<nsIWebBrowser> webBrowser = [view getWebBrowser];
|
||||
if (!webBrowser) return nsnull;
|
||||
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(webBrowser));
|
||||
return webNav.get();
|
||||
}
|
||||
|
||||
- (void) historyItemAction:(id)sender
|
||||
{
|
||||
// get web navigation for current browser
|
||||
nsCOMPtr<nsIWebNavigation> 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<nsIWebNavigation> webNav = [self currentWebNavigation];
|
||||
if (!webNav) return;
|
||||
nsCOMPtr<nsISHistory> 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<nsIHistoryEntry> 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
|
@ -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 = {
|
||||
|
@ -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;
|
||||
|
8
chimera/English.lproj/BrowserWindow.nib/info.nib
generated
8
chimera/English.lproj/BrowserWindow.nib/info.nib
generated
@ -22,10 +22,8 @@
|
||||
<string>22 500 93 162 0 0 1152 746 </string>
|
||||
<key>463</key>
|
||||
<string>7 444 200 252 0 0 1152 746 </string>
|
||||
<key>475</key>
|
||||
<string>493 338 207 230 0 0 1152 746 </string>
|
||||
<key>56</key>
|
||||
<string>340 478 343 68 0 0 1024 746 </string>
|
||||
<string>378 463 343 68 0 0 1152 746 </string>
|
||||
</dict>
|
||||
<key>IBFramework Version</key>
|
||||
<string>248.0</string>
|
||||
@ -43,6 +41,10 @@
|
||||
<array>
|
||||
<integer>497</integer>
|
||||
</array>
|
||||
<key>IBOpenObjects</key>
|
||||
<array>
|
||||
<integer>56</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
<string>5Q125</string>
|
||||
</dict>
|
||||
|
BIN
chimera/English.lproj/BrowserWindow.nib/objects.nib
generated
BIN
chimera/English.lproj/BrowserWindow.nib/objects.nib
generated
Binary file not shown.
1
chimera/English.lproj/MainMenu.nib/classes.nib
generated
1
chimera/English.lproj/MainMenu.nib/classes.nib
generated
@ -5,6 +5,7 @@
|
||||
LANGUAGE = ObjC;
|
||||
SUPERCLASS = ToolbarController;
|
||||
},
|
||||
{CLASS = CHGoMenu; LANGUAGE = ObjC; SUPERCLASS = NSMenu; },
|
||||
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
|
||||
{
|
||||
ACTIONS = {
|
||||
|
BIN
chimera/English.lproj/MainMenu.nib/objects.nib
generated
BIN
chimera/English.lproj/MainMenu.nib/objects.nib
generated
Binary file not shown.
1
chimera/MainMenu.nib/classes.nib
generated
1
chimera/MainMenu.nib/classes.nib
generated
@ -5,6 +5,7 @@
|
||||
LANGUAGE = ObjC;
|
||||
SUPERCLASS = ToolbarController;
|
||||
},
|
||||
{CLASS = CHGoMenu; LANGUAGE = ObjC; SUPERCLASS = NSMenu; },
|
||||
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
|
||||
{
|
||||
ACTIONS = {
|
||||
|
BIN
chimera/MainMenu.nib/objects.nib
generated
BIN
chimera/MainMenu.nib/objects.nib
generated
Binary file not shown.
@ -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 = {
|
||||
|
@ -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;
|
||||
|
@ -22,10 +22,8 @@
|
||||
<string>22 500 93 162 0 0 1152 746 </string>
|
||||
<key>463</key>
|
||||
<string>7 444 200 252 0 0 1152 746 </string>
|
||||
<key>475</key>
|
||||
<string>493 338 207 230 0 0 1152 746 </string>
|
||||
<key>56</key>
|
||||
<string>340 478 343 68 0 0 1024 746 </string>
|
||||
<string>378 463 343 68 0 0 1152 746 </string>
|
||||
</dict>
|
||||
<key>IBFramework Version</key>
|
||||
<string>248.0</string>
|
||||
@ -43,6 +41,10 @@
|
||||
<array>
|
||||
<integer>497</integer>
|
||||
</array>
|
||||
<key>IBOpenObjects</key>
|
||||
<array>
|
||||
<integer>56</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
<string>5Q125</string>
|
||||
</dict>
|
||||
|
Binary file not shown.
@ -5,6 +5,7 @@
|
||||
LANGUAGE = ObjC;
|
||||
SUPERCLASS = ToolbarController;
|
||||
},
|
||||
{CLASS = CHGoMenu; LANGUAGE = ObjC; SUPERCLASS = NSMenu; },
|
||||
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
|
||||
{
|
||||
ACTIONS = {
|
||||
|
Binary file not shown.
@ -21,13 +21,30 @@
|
||||
* David Hyatt <hyatt@netscape.com> (Original Author)
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#include "nsIAutoCompleteSession.h"
|
||||
#import <AppKit/AppKit.h>
|
||||
#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
|
||||
|
@ -19,41 +19,106 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* David Hyatt <hyatt@netscape.com> (Original Author)
|
||||
*
|
||||
*/
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#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<nsIAutoCompleteSession> 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<nsISupportsArray> 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<nsISupportsArray> items;
|
||||
mResults->GetItems(getter_AddRefs(items));
|
||||
|
||||
nsCOMPtr<nsISupports> itemSupports = dont_AddRef(items->ElementAt(aRow));
|
||||
nsCOMPtr<nsIAutoCompleteItem> 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
|
||||
|
76
chimera/src/browser/AutoCompleteTextField.h
Normal file
76
chimera/src/browser/AutoCompleteTextField.h
Normal file
@ -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 <hewitt@netscape.com> (Original Author)
|
||||
*/
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import "CHAutoCompleteDataSource.h"
|
||||
#include "nsIAutoCompleteSession.h"
|
||||
#include "nsIAutoCompleteResults.h"
|
||||
#include "nsIAutoCompleteListener.h"
|
||||
|
||||
@class CHAutoCompleteDataSource, CHPageProxyIcon;
|
||||
|
||||
@interface CHAutoCompleteTextField : NSTextField
|
||||
{
|
||||
IBOutlet CHPageProxyIcon *mProxyIcon;
|
||||
NSWindow *mPopupWin;
|
||||
NSTableView *mTableView;
|
||||
|
||||
CHAutoCompleteDataSource *mDataSource;
|
||||
|
||||
nsIAutoCompleteSession *mSession;
|
||||
nsIAutoCompleteResults *mResults;
|
||||
nsIAutoCompleteListener *mListener;
|
||||
|
||||
NSString* mSearchString;
|
||||
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
|
447
chimera/src/browser/AutoCompleteTextField.mm
Normal file
447
chimera/src/browser/AutoCompleteTextField.mm
Normal file
@ -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 <hewitt@netscape.com> (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<nsIAutoCompleteSession> session =
|
||||
do_GetService("@mozilla.org/autocompleteSession;1?type=history");
|
||||
mSession = session;
|
||||
NS_IF_ADDREF(mSession);
|
||||
}
|
||||
|
||||
- (NSString *) session
|
||||
{
|
||||
// XXX return session name
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSTableView *) tableView
|
||||
{
|
||||
return mTableView;
|
||||
}
|
||||
|
||||
- (int) visibleRows
|
||||
{
|
||||
int minRows = [mDataSource rowCount];
|
||||
return minRows < kMaxRows ? minRows : kMaxRows;
|
||||
}
|
||||
|
||||
// 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
|
36
chimera/src/browser/GoMenu.h
Normal file
36
chimera/src/browser/GoMenu.h
Normal file
@ -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 <hewitt@netscape.com> (Original Author)
|
||||
*/
|
||||
|
||||
#import <Appkit/Appkit.h>
|
||||
|
||||
@interface CHGoMenu : NSMenu {
|
||||
|
||||
}
|
||||
|
||||
- (void) emptyHistoryItems;
|
||||
- (void) addHistoryItems;
|
||||
|
||||
// NSMenu
|
||||
- (void) update;
|
||||
|
||||
@end
|
147
chimera/src/browser/GoMenu.mm
Normal file
147
chimera/src/browser/GoMenu.mm
Normal file
@ -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 <hewitt@netscape.com> (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<nsIWebBrowser> webBrowser = [view getWebBrowser];
|
||||
if (!webBrowser) return nsnull;
|
||||
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(webBrowser));
|
||||
return webNav.get();
|
||||
}
|
||||
|
||||
- (void) historyItemAction:(id)sender
|
||||
{
|
||||
// get web navigation for current browser
|
||||
nsCOMPtr<nsIWebNavigation> 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<nsIWebNavigation> webNav = [self currentWebNavigation];
|
||||
if (!webNav) return;
|
||||
nsCOMPtr<nsISHistory> 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<nsIHistoryEntry> 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
|
Loading…
x
Reference in New Issue
Block a user