Backing out bug 178607 because I forgot to test before committing, and I'm seeing peristent crashes and hangs locally.

This commit is contained in:
alqahira%ardisson.org 2008-01-21 21:58:48 +00:00
Родитель 408fb87bd4
Коммит 7cd758b8f6
8 изменённых файлов: 0 добавлений и 1416 удалений

Просмотреть файл

@ -1,83 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* 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 Camino code.
*
* The Initial Developer of the Original Code is
* Bryan Atwood
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bryan Atwood <bryan.h.atwood@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import <Cocoa/Cocoa.h>
// AutoCompleteResults
//
// Container object for generic auto complete.
// Holds the search string, array of matched objects and the default item.
//
@interface AutoCompleteResults : NSObject
{
NSString* mSearchString; // strong
NSArray* mMatches; // strong
int mDefaultIndex;
}
- (NSString*)searchString;
- (void)setSearchString:(NSString*)string;
- (NSArray*)matches;
- (void)setMatches:(NSArray*)matches;
- (int)defaultIndex;
- (void)setDefaultIndex:(int)defaultIndex;
@end
// AutoCompleteListener
//
// This defines the protocol methods for the object that listens for auto complete
// results. |onAutoComplete| is called by the object that searches the data and
// the results are returned to the originating caller as AutoCompleteResults.
//
@protocol AutoCompleteListener
- (void)autoCompleteFoundResults:(AutoCompleteResults*)results;
@end
// AutoCompleteSession
//
// An AutoCompleteSession object listens for search requests and searches a set of data
// |startAutoCompleteWithSearch| initiates the process. Previous results are passed in
// as well as the listener object for when the search is complete.
//
@protocol AutoCompleteSession
- (void)startAutoCompleteWithSearch:(NSString*)searchString
previousResults:(AutoCompleteResults*)previousSearchResults
listener:(id<AutoCompleteListener>)listener;
@end

Просмотреть файл

@ -1,87 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* 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 Camino code.
*
* The Initial Developer of the Original Code is
* Bryan Atwood
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bryan Atwood <bryan.h.atwood@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import "AutoCompleteUtils.h"
@implementation AutoCompleteResults
- (void)dealloc
{
[mSearchString release];
[mMatches release];
[super dealloc];
}
- (NSString*)searchString
{
return mSearchString;
}
- (void)setSearchString:(NSString*)string
{
[mSearchString release];
// The caller might change the string, so keep a copy.
mSearchString = [string copy];
}
- (NSArray*)matches
{
return mMatches;
}
- (void)setMatches:(NSArray*)matches
{
if (mMatches != matches) {
[mMatches release];
mMatches = [matches retain];
}
}
- (int)defaultIndex
{
return mDefaultIndex;
}
- (void)setDefaultIndex:(int)index
{
mDefaultIndex = index;
}
@end

Просмотреть файл

@ -1,100 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* 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 Camino code.
*
* The Initial Developer of the Original Code is
* Bryan Atwood
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bryan Atwood <bryan.h.atwood@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import <Cocoa/Cocoa.h>
#import "AutoCompleteUtils.h"
#include "nsIDOMEventListener.h"
extern const int kFormFillMaxRows;
@class KeychainAutoCompleteSession;
@class CHBrowserView;
@class FormFillPopup;
@class FormFillController;
class nsIDOMHTMLInputElement;
// FormFillListener
//
// The FormFillListener object listens for DOM events and the corresponding
// methods in the FormFillController are called for handling.
//
class FormFillListener : public nsIDOMEventListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMEVENTLISTENER
FormFillListener(FormFillController* aController);
protected:
FormFillController* mController; // weak
};
// FormFillController
//
// Manages the FormFillPopup windows that contain search results
// as well as sending search requests to the KeychainAutoCompleteSession
// and listening for search results. This can be extended to send
// search requests to a form history session as well.
@interface FormFillController : NSObject <AutoCompleteListener>
{
KeychainAutoCompleteSession* mKeychainSession; // strong
AutoCompleteResults* mResults; // strong
FormFillListener* mListener; // strong
FormFillPopup* mPopupWindow; // strong
CHBrowserView* mBrowserView; // weak
nsIDOMHTMLInputElement* mFocusedInputElement; // weak
// mCompleteResult determines if the current search should complete the default
// result when ready. This prevents backspace/delete from autocompleting.
BOOL mCompleteResult;
// mUsernameFillEnabled determines whether we send searches to the Keychain
// Service. Form fill history value can be added here as well.
BOOL mUsernameFillEnabled;
}
- (void)attachToBrowser:(CHBrowserView*)browser;
// Callback function for when a row in the focused popup window is clicked.
- (void)popupSelected;
@end

Просмотреть файл

@ -1,748 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* 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 Camino code.
*
* The Initial Developer of the Original Code is
* Bryan Atwood
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bryan Atwood <bryan.h.atwood@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import "FormFillController.h"
#import "CHBrowserView.h"
#import "FormFillPopup.h"
#import "KeychainAutoCompleteSession.h"
#import "PreferenceManager.h"
#import "NSString+Gecko.h"
#import "NSArray+Utils.h"
#include "GeckoUtils.h"
#include "nsString.h"
#include "nsPIDOMWindow.h"
#include "nsIDOMWindow.h"
#include "nsIDOMDocumentEvent.h"
#include "nsIPrivateDOMEvent.h"
#include "nsIDOMEventTarget.h"
#include "nsIDOMEvent.h"
#include "nsIDOMHTMLFormElement.h"
#include "nsIDOMHTMLInputElement.h"
#include "nsIDOMNSHTMLInputElement.h"
#include "nsIDOMKeyEvent.h"
const int kFormFillMaxRows = 10;
@interface FormFillController(Private)
// Listener and autocomplete initialization and cleanup
- (void)browserResized:(NSNotification*)notification;
- (void)addResizeObserver:(NSWindow*)browserWindow;
- (void)removeResizeObserver:(NSWindow*)browserWindow;
- (void)addWindowListeners:(nsIDOMWindow*)aWindow;
- (void)removeWindowListeners:(nsIDOMWindow*)aWindow;
- (void)startControllingInputElement:(nsIDOMHTMLInputElement*)aInputElement;
- (void)stopControllingInputElement;
// Popup window management
- (BOOL)isPopupOpen;
- (void)openPopup;
- (void)closePopup;
- (void)shiftRowSelectionBy:(int)aRows;
// Autocomplete methods
- (void)startSearch:(NSString*)searchString;
- (void)dataReady;
- (void)autoCompleteFieldText;
- (void)filledAutoCompleteFieldText;
// Event handlers
- (void)focus:(nsIDOMEvent*)aEvent;
- (void)blur:(nsIDOMEvent*)aEvent;
- (void)unload:(nsIDOMEvent*)aEvent;
- (void)submit:(nsIDOMEvent*)aEvent;
- (void)input:(nsIDOMEvent*)aEvent;
- (void)keyPress:(nsIDOMEvent*)aEvent;
- (BOOL)handleKeyNavigation:(int)aKey;
// Utility methods
- (BOOL)IsCaretAtEndOfLine;
@end
NS_IMPL_ISUPPORTS1(FormFillListener, nsIDOMEventListener)
FormFillListener::FormFillListener(FormFillController* aController)
: mController(aController)
{
}
NS_IMETHODIMP FormFillListener::HandleEvent(nsIDOMEvent* aEvent)
{
nsAutoString type;
aEvent->GetType(type);
if (type.Equals(NS_LITERAL_STRING("focus")))
[mController focus:aEvent];
else if (type.Equals(NS_LITERAL_STRING("blur")))
[mController blur:aEvent];
else if (type.Equals(NS_LITERAL_STRING("unload")))
[mController unload:aEvent];
else if (type.Equals(NS_LITERAL_STRING("submit")))
[mController submit:aEvent];
else if (type.Equals(NS_LITERAL_STRING("input")))
[mController input:aEvent];
else if (type.Equals(NS_LITERAL_STRING("keypress")))
[mController keyPress:aEvent];
return NS_OK;
}
@implementation FormFillController
- (id)init
{
if ((self = [super init])) {
// mListener captures DOM and auto complete events.
mListener = new FormFillListener(self);
NS_ADDREF(mListener);
// Initialize the password fill session.
// History form fill session can also be added when someone writes it.
mKeychainSession = [[KeychainAutoCompleteSession alloc] init];
}
return self;
}
- (void)dealloc
{
// Remove ourselves as a focus listener from cached view.
nsCOMPtr<nsIDOMWindow> domWindow = [mBrowserView contentWindow];
if (domWindow)
[self removeWindowListeners:domWindow];
[self removeResizeObserver:[mBrowserView nativeWindow]];
[mResults release];
[mKeychainSession release];
[mPopupWindow release];
NS_IF_RELEASE(mListener);
[super dealloc];
}
- (void)attachToBrowser:(CHBrowserView*)browser
{
if (!browser)
return;
mBrowserView = browser;
// Listen for focus events on the domWindow of the browser view.
nsCOMPtr<nsIDOMWindow> domWindow = [mBrowserView contentWindow];
if (domWindow)
[self addWindowListeners:domWindow];
}
- (void)browserResized:(NSNotification*)notification
{
[self closePopup];
}
- (void)addResizeObserver:(NSWindow*)browserWindow
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(browserResized:)
name:NSWindowDidResizeNotification
object:browserWindow];
}
- (void)removeResizeObserver:(NSWindow*)browserWindow
{
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSWindowDidResizeNotification
object:browserWindow];
}
- (void)addWindowListeners:(nsIDOMWindow*)aWindow
{
nsCOMPtr<nsPIDOMWindow> privateDOMWindow = do_QueryInterface(aWindow);
if (!privateDOMWindow)
return;
nsPIDOMEventTarget* chromeEventHandler = privateDOMWindow->GetChromeEventHandler();
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(chromeEventHandler);
if (!target)
return;
target->AddEventListener(NS_LITERAL_STRING("focus"),
static_cast<nsIDOMEventListener*>(mListener),
PR_TRUE);
target->AddEventListener(NS_LITERAL_STRING("blur"),
static_cast<nsIDOMEventListener*>(mListener),
PR_TRUE);
target->AddEventListener(NS_LITERAL_STRING("unload"),
static_cast<nsIDOMEventListener*>(mListener),
PR_TRUE);
target->AddEventListener(NS_LITERAL_STRING("submit"),
static_cast<nsIDOMEventListener*>(mListener),
PR_TRUE);
target->AddEventListener(NS_LITERAL_STRING("input"),
static_cast<nsIDOMEventListener*>(mListener),
PR_TRUE);
target->AddEventListener(NS_LITERAL_STRING("keypress"),
static_cast<nsIDOMEventListener*>(mListener),
PR_TRUE);
}
- (void)removeWindowListeners:(nsIDOMWindow*)aWindow
{
[self stopControllingInputElement];
nsCOMPtr<nsPIDOMWindow> privateDOMWindow = do_QueryInterface(aWindow);
if (!privateDOMWindow)
return;
nsPIDOMEventTarget* chromeEventHandler = privateDOMWindow->GetChromeEventHandler();
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(chromeEventHandler);
if (!target)
return;
target->RemoveEventListener(NS_LITERAL_STRING("focus"),
static_cast<nsIDOMEventListener*>(mListener),
PR_TRUE);
target->RemoveEventListener(NS_LITERAL_STRING("blur"),
static_cast<nsIDOMEventListener*>(mListener),
PR_TRUE);
target->RemoveEventListener(NS_LITERAL_STRING("unload"),
static_cast<nsIDOMEventListener*>(mListener),
PR_TRUE);
target->RemoveEventListener(NS_LITERAL_STRING("submit"),
static_cast<nsIDOMEventListener*>(mListener),
PR_TRUE);
target->RemoveEventListener(NS_LITERAL_STRING("input"),
static_cast<nsIDOMEventListener*>(mListener),
PR_TRUE);
target->RemoveEventListener(NS_LITERAL_STRING("keypress"),
static_cast<nsIDOMEventListener*>(mListener),
PR_TRUE);
}
- (void)startControllingInputElement:(nsIDOMHTMLInputElement*)aInputElement
{
// Make sure we're not still attached to an input element.
[self stopControllingInputElement];
// Set the autocomplete session for this input. Currently, only password autocomplete
// but other sessions like form fill history can be added here.
mUsernameFillEnabled = [mKeychainSession attachToInput:aInputElement];
// If this is not a valid auto-complete input, we can return now.
if (!mUsernameFillEnabled)
return;
// Cache the input element.
mFocusedInputElement = aInputElement;
// Create the popup window if it doesn't exist.
if (!mPopupWindow) {
mPopupWindow = [[FormFillPopup alloc] init];
[mPopupWindow attachToController:self];
}
}
- (void)stopControllingInputElement
{
if (mPopupWindow) {
[self closePopup];
[mPopupWindow setItems:nil];
}
mFocusedInputElement = nsnull;
// Stop sending search requests to auto-form fill.
mUsernameFillEnabled = NO;
[mResults release];
mResults = nil;
}
-(void)autoCompleteFoundResults:(AutoCompleteResults*)results
{
[mResults release];
mResults = nil;
if ([[results matches] count] > 0) {
mResults = [results retain];
[self dataReady];
}
else {
[mPopupWindow setItems:nil];
[self closePopup];
}
}
- (BOOL)isPopupOpen
{
return mPopupWindow ? [mPopupWindow isPopupOpen] : NO;
}
- (void)openPopup
{
// Only open popup if it's not already open.
if ([self isPopupOpen])
return;
// Make sure input field is visible before showing popup.
GeckoUtils::ScrollElementIntoView(mFocusedInputElement);
nsIntRect inputIntRect;
if (!(GeckoUtils::GetFrameInScreenCoordinates(mFocusedInputElement, &inputIntRect)))
return;
NSRect inputElementFrame = NSMakeRect(inputIntRect.x, inputIntRect.y, inputIntRect.width, inputIntRect.height);
NSScreen* mainScreen = [[NSScreen screens] firstObject]; // NSArray category method
if (!mainScreen)
return;
NSPoint origin = inputElementFrame.origin;
float width = NSWidth(inputElementFrame);
// y-flip and subtract the control height to convert to cocoa coords
origin.y = NSMaxY([mainScreen frame]) - inputElementFrame.origin.y - inputElementFrame.size.height;
// To account for the text box border, shift rectangle position to the right by 2 pixels
// and reduce the width by 3 pixels.
// TODO: check shift here, still not aligned sometimes.
origin.x += 2.0;
width -= 3.0;
[mPopupWindow openPopup:[mBrowserView nativeWindow] withOrigin:origin width:width];
// Listen for resize events to close the popup.
[self addResizeObserver:[mBrowserView nativeWindow]];
}
- (void)closePopup
{
if (mPopupWindow) {
// Deselecting the row prevents a flash when popup is opened and default is selected.
[mPopupWindow selectRow:-1];
[mPopupWindow closePopup];
[self removeResizeObserver:[mBrowserView nativeWindow]];
}
}
- (void)shiftRowSelectionBy:(int)aRows
{
int row = [mPopupWindow selectedRow] + aRows;
// pin result at top row
if (row < 0)
row = 0;
// pin result at bottom row
int numRows = [mPopupWindow rowCount];
if (row >= numRows)
row = numRows - 1;
[mPopupWindow selectRow:row];
}
//
// popupSelected
//
// Called when a new item in the popup window is selected, either by mouse click
// or keyboard movement. The form field is set to the value of the selected item
// and an autocomplete event is sent for any listeners
- (void)popupSelected
{
if (![self isPopupOpen] || !mResults)
return;
int row = [mPopupWindow selectedRow];
if (row < 0)
return;
nsAutoString value;
[[mPopupWindow resultForRow:row] assignTo_nsAString:value];
mFocusedInputElement->SetValue(value);
// Auto-fill the input so that untyped letters are selected.
nsCOMPtr<nsIDOMNSHTMLInputElement> nsInput = do_QueryInterface(mFocusedInputElement);
if (nsInput) {
int searchLength = [[mResults searchString] length];
nsInput->SetSelectionStart((PRInt32)searchLength);
}
// Send an autocomplete DOM event any time auto fill is done.
[self filledAutoCompleteFieldText];
}
- (void)startSearch:(NSString*)searchString;
{
// Check if password autocomplete is enabled.
// Form history autocomplete can be added here.
if (mUsernameFillEnabled) {
[mKeychainSession startAutoCompleteWithSearch:searchString
previousResults:mResults
listener:self];
}
}
- (void)dataReady
{
[mPopupWindow setItems:[mResults matches]];
// Open the popup if more than one result is returned.
// Also require mCompleteResult since it prevents a backspace from opening popup
// even though we want to search on a backspace to get the larger result set.
if ([mPopupWindow rowCount] > 1 && mCompleteResult)
[self openPopup];
else
[self closePopup];
// Prevents backspace from auto-completing the result we just erased.
if (mCompleteResult)
[self autoCompleteFieldText];
}
//
// autoCompleteFieldText
//
// Called when FormFillController should fill the text field with the default
// autocomplete result.
- (void)autoCompleteFieldText
{
if (!mResults)
return;
NSArray* matches = [mResults matches];
// Select the default if it's available.
// Otherwise, select the first username in the list.
int defaultIndex = [mResults defaultIndex];
nsAutoString value;
[[matches objectAtIndex:defaultIndex] assignTo_nsAString:value];
mFocusedInputElement->SetValue(value);
// Auto-fill the input such that untyped letters are selected.
nsCOMPtr<nsIDOMNSHTMLInputElement> nsInput = do_QueryInterface(mFocusedInputElement);
if (nsInput) {
int searchLength = [[mResults searchString] length];
nsInput->SetSelectionStart((PRInt32)searchLength);
}
// Select the default entry in the popup.
if ([self isPopupOpen])
[mPopupWindow selectRow:defaultIndex];
// Send a DOM event any time auto fill is done.
[self filledAutoCompleteFieldText];
}
//
// filledAutoCompleteFieldText
//
// Called whenever the form element is filled. It sends a DOM event
// "DOMAutoComplete" that can be listened for, e.g., to fill a password
// when a username element is completed.
//
- (void)filledAutoCompleteFieldText
{
if (!mFocusedInputElement)
return;
nsCOMPtr<nsIDOMDocument> domDoc;
mFocusedInputElement->GetOwnerDocument(getter_AddRefs(domDoc));
nsCOMPtr<nsIDOMDocumentEvent> doc = do_QueryInterface(domDoc);
if (!doc)
return;
nsCOMPtr<nsIDOMEvent> event;
doc->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event));
nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(event);
if (!privateEvent)
return;
event->InitEvent(NS_LITERAL_STRING("DOMAutoComplete"), PR_TRUE, PR_TRUE);
privateEvent->SetTrusted(PR_TRUE);
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mFocusedInputElement);
PRBool defaultActionEnabled;
target->DispatchEvent(event, &defaultActionEnabled);
}
//
// focus
//
// When a new element is selected, check whether we allow autocomplete.
// If autocomplete is allowed, start controlling the input to that element.
//
- (void)focus:(nsIDOMEvent*)aEvent
{
nsCOMPtr<nsIDOMEventTarget> target;
aEvent->GetTarget(getter_AddRefs(target));
nsCOMPtr<nsIDOMHTMLInputElement> inputElement = do_QueryInterface(target);
if (!inputElement)
return;
nsAutoString type;
inputElement->GetType(type);
if (!type.LowerCaseEqualsLiteral("text"))
return;
PRBool isReadOnly = PR_FALSE;
if (NS_FAILED(inputElement->GetReadOnly(&isReadOnly)) || isReadOnly)
return;
PRBool autoCompleteOverride = [[PreferenceManager sharedInstance] getBooleanPref:"wallet.crypto.autocompleteoverride" withSuccess:NULL];
if (!autoCompleteOverride) {
nsAutoString autocomplete;
inputElement->GetAttribute(NS_LITERAL_STRING("autocomplete"), autocomplete);
if (autocomplete.EqualsIgnoreCase("off"))
return;
nsCOMPtr<nsIDOMHTMLFormElement> form;
inputElement->GetForm(getter_AddRefs(form));
if (form) {
form->GetAttribute(NS_LITERAL_STRING("autocomplete"), autocomplete);
if (autocomplete.EqualsIgnoreCase("off"))
return;
}
}
[self startControllingInputElement:inputElement];
}
//
// blur
//
// Anytime focus moves from an element, stop autocompleting it until next
// input element is focused.
//
- (void)blur:(nsIDOMEvent*)aEvent
{
if (mFocusedInputElement)
[self stopControllingInputElement];
}
//
// unload
//
// Stop autocompleting on a page if it is unloaded.
//
- (void)unload:(nsIDOMEvent*)aEvent
{
if (mFocusedInputElement) {
nsCOMPtr<nsIDOMEventTarget> target;
aEvent->GetTarget(getter_AddRefs(target));
nsCOMPtr<nsIDOMDocument> eventDoc = do_QueryInterface(target);
nsCOMPtr<nsIDOMDocument> inputDoc;
mFocusedInputElement->GetOwnerDocument(getter_AddRefs(inputDoc));
if (eventDoc == inputDoc)
[self stopControllingInputElement];
}
}
//
// submit
//
// If a form is submitted, stop autocompleting.
//
- (void)submit:(nsIDOMEvent*)aEvent
{
if (mFocusedInputElement)
[self stopControllingInputElement];
}
//
// input
//
// If an HTML input box is being controlled, do a search when input occurs.
//
- (void)input:(nsIDOMEvent*)aEvent
{
nsCOMPtr<nsIDOMEventTarget> target;
aEvent->GetTarget(getter_AddRefs(target));
nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(target);
if (input && mFocusedInputElement == input) {
nsAutoString value;
mFocusedInputElement->GetValue(value);
[self startSearch:[NSString stringWith_nsAString:value]];
}
}
//
// keyPress
//
// This is triggered when a key is pressed but before an 'input' is triggered.
// It also handles non-input keys like arrow keys.
//
- (void)keyPress:(nsIDOMEvent*)aEvent
{
if (!mFocusedInputElement)
return;
nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aEvent);
if (!keyEvent)
return;
// By default, allow keystroke to continue to the next listener.
BOOL cancel = NO;
// By default, autocomplete on keystrokes that later trigger 'input' events.
mCompleteResult = YES;
PRUint32 k;
keyEvent->GetKeyCode(&k);
switch (k) {
case nsIDOMKeyEvent::DOM_VK_UP:
case nsIDOMKeyEvent::DOM_VK_DOWN:
case nsIDOMKeyEvent::DOM_VK_PAGE_UP:
case nsIDOMKeyEvent::DOM_VK_PAGE_DOWN:
cancel = [self handleKeyNavigation:k];
break;
case nsIDOMKeyEvent::DOM_VK_ESCAPE:
case nsIDOMKeyEvent::DOM_VK_RETURN:
cancel = [self isPopupOpen];
[self closePopup];
break;
case nsIDOMKeyEvent::DOM_VK_BACK_SPACE:
case nsIDOMKeyEvent::DOM_VK_DELETE:
// Don't allow autocomplete of 'input' event if it's due to a back space or
// delete.
mCompleteResult = NO;
break;
}
if (cancel) {
aEvent->StopPropagation();
aEvent->PreventDefault();
}
}
//
// handleKeyNavigation
//
// Handles key events that are for navigation of the popup window.
// Should return YES if the event should be cancelled and not propagated.
//
- (BOOL)handleKeyNavigation:(int)aKey
{
switch (aKey) {
case nsIDOMKeyEvent::DOM_VK_UP:
if ([self isPopupOpen]) {
[self shiftRowSelectionBy:-1];
[self popupSelected];
return YES;
}
break;
case nsIDOMKeyEvent::DOM_VK_DOWN:
if ([self isPopupOpen]) {
[self shiftRowSelectionBy:1];
[self popupSelected];
return YES;
}
else if ([self IsCaretAtEndOfLine]) {
nsAutoString value;
mFocusedInputElement->GetValue(value);
[self startSearch:[NSString stringWith_nsAString:value]];
return YES;
}
break;
case nsIDOMKeyEvent::DOM_VK_PAGE_UP:
if ([self isPopupOpen]) {
[self shiftRowSelectionBy:-kFormFillMaxRows];
[self popupSelected];
return YES;
}
break;
case nsIDOMKeyEvent::DOM_VK_PAGE_DOWN:
if ([self isPopupOpen]) {
[self shiftRowSelectionBy:kFormFillMaxRows];
[self popupSelected];
return YES;
}
else {
nsAutoString value;
mFocusedInputElement->GetValue(value);
[self startSearch:[NSString stringWith_nsAString:value]];
return YES;
}
break;
}
return NO;
}
- (BOOL)IsCaretAtEndOfLine
{
if (!mFocusedInputElement)
return NO;
nsCOMPtr<nsIDOMNSHTMLInputElement> nsInput = do_QueryInterface(mFocusedInputElement);
if (!nsInput)
return NO;
PRInt32 selectStart;
nsInput->GetSelectionStart(&selectStart);
PRInt32 textLength;
nsInput->GetTextLength(&textLength);
return (selectStart == textLength);
}
@end

Просмотреть файл

@ -1,83 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* 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 Camino code.
*
* The Initial Developer of the Original Code is
* Bryan Atwood
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bryan Atwood <bryan.h.atwood@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import <Cocoa/Cocoa.h>
@class FormFillController;
//
// FormFillPopupWindow
//
// The popup window needs to look like a "key" (activated) window even thought it's
// a child window. This subclass overrides |isKeyWindow| to return YES so that it is
// able to be a key window (and have activated scrollbars, etc) but not steal focus.
//
@interface FormFillPopupWindow : NSPanel
@end
// FormFillPopup
//
// Manages the display of the popup window and receives data from the FormFillController.
//
@interface FormFillPopup : NSObject
{
FormFillPopupWindow* mPopupWin; // strong
NSArray* mItems; // strong
NSTableView* mTableView; // weak
FormFillController* mController; // weak
}
- (void)attachToController:(FormFillController*)controller;
// openPopup expects an origin point in Cocoa coordinates and a width that
// should be equal to the text box.
- (void)openPopup:(NSWindow*)browserWindow withOrigin:(NSPoint)origin width:(float)width;
- (void)resizePopup;
- (void)closePopup;
- (BOOL)isPopupOpen;
- (int)visibleRows;
- (int)rowCount;
- (void)selectRow:(int)index;
- (int)selectedRow;
- (void)setItems:(NSArray*)items;
- (NSString*)resultForRow:(int)index;
@end

Просмотреть файл

@ -1,230 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* 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 Camino code.
*
* The Initial Developer of the Original Code is
* Bryan Atwood
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bryan Atwood <bryan.h.atwood@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import "FormFillPopup.h"
#import "FormFillController.h"
@implementation FormFillPopupWindow
- (BOOL)isKeyWindow
{
return YES;
}
@end
@interface FormFillPopup(Private)
- (void)onRowClicked:(NSNotification *)aNote;
@end
@implementation FormFillPopup
- (id)init
{
if ((self = [super init])) {
// Construct and configure the popup window.
mPopupWin = [[FormFillPopupWindow alloc] initWithContentRect:NSMakeRect(0,0,0,0)
styleMask:NSNonactivatingPanelMask
backing:NSBackingStoreBuffered
defer:NO];
[mPopupWin setReleasedWhenClosed:NO];
[mPopupWin setHasShadow:YES];
[mPopupWin setAlphaValue:0.9];
// Construct and configure the view.
mTableView = [[[NSTableView alloc] initWithFrame:NSMakeRect(0,0,0,0)] autorelease];
[mTableView setIntercellSpacing:NSMakeSize(1, 2)];
[mTableView setTarget:self];
[mTableView setAction:@selector(onRowClicked:)];
// Create the text column (only one).
NSTableColumn* column = [[[NSTableColumn alloc] initWithIdentifier:@"usernames"] autorelease];
[mTableView addTableColumn:column];
// Hide the table header.
[mTableView setHeaderView:nil];
[mTableView setDataSource:self];
NSScrollView *scrollView = [[[NSScrollView alloc] initWithFrame:NSMakeRect(0,0,0,0)] autorelease];
[scrollView setHasVerticalScroller:YES];
[scrollView setAutohidesScrollers:YES];
[[scrollView verticalScroller] setControlSize:NSSmallControlSize];
[scrollView setDocumentView:mTableView];
[mPopupWin setContentView:scrollView];
}
return self;
}
- (void)dealloc
{
[mPopupWin release];
[mItems release];
[super dealloc];
}
- (void)attachToController:(FormFillController*)controller
{
mController = controller;
}
- (BOOL)isPopupOpen
{
return [mPopupWin isVisible];
}
- (void)openPopup:(NSWindow*)browserWindow withOrigin:(NSPoint)origin width:(float)width
{
// Set the size of the popup window.
NSRect tableViewFrame = [mTableView frame];
tableViewFrame.size.width = width;
[mTableView setFrame:tableViewFrame];
// Size the panel correctly.
tableViewFrame.size.height = (int)([mTableView rowHeight] + [mTableView intercellSpacing].height) * [self visibleRows];
[mPopupWin setContentSize:tableViewFrame.size];
[mPopupWin setFrameTopLeftPoint:origin];
// Show the popup.
if (![mPopupWin isVisible]) {
[browserWindow addChildWindow:mPopupWin ordered:NSWindowAbove];
[mPopupWin orderFront:nil];
}
}
- (void)resizePopup
{
// Don't resize if popup isn't visible.
if (![mPopupWin isVisible])
return;
if ([self visibleRows] == 0) {
[self closePopup];
return;
}
NSRect popupWinFrame = [mPopupWin frame];
int tableHeight = (int)([mTableView rowHeight] + [mTableView intercellSpacing].height) * [self visibleRows];
popupWinFrame.origin.y += NSHeight(popupWinFrame) - tableHeight;
popupWinFrame.size.height = tableHeight;
[mPopupWin setFrame:popupWinFrame display:YES];
}
- (void)closePopup
{
// We can get -closePopup even if we didn't show it.
if ([mPopupWin isVisible]) {
[[mPopupWin parentWindow] removeChildWindow:mPopupWin];
[mPopupWin orderOut:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
}
- (void)onRowClicked:(NSNotification *)aNote
{
[mController popupSelected];
[self closePopup];
}
- (int)visibleRows
{
int minRows = [self rowCount];
return (minRows < kFormFillMaxRows) ? minRows : kFormFillMaxRows;
}
- (int)rowCount
{
if (!mItems)
return 0;
return [mItems count];
}
- (void)selectRow:(int)index
{
if (index == -1)
[mTableView deselectAll:self];
else {
[mTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:index] byExtendingSelection:NO];
[mTableView scrollRowToVisible:index];
}
}
- (int)selectedRow
{
return [mTableView selectedRow];
}
- (NSString*)resultForRow:(int)index
{
return [mItems objectAtIndex:index];
}
- (void)setItems:(NSArray*)items
{
if (items != mItems) {
[mItems release];
mItems = [items retain];
}
// Update the view any time we get new data
[mTableView noteNumberOfRowsChanged];
[self resizePopup];
}
// methods for table view interaction
-(int)numberOfRowsInTableView:(NSTableView*)aTableView
{
return [self rowCount];
}
-(id)tableView:(NSTableView*)aTableView objectValueForTableColumn:(NSTableColumn*)aTableColumn row:(int)aRowIndex
{
return [self resultForRow:aRowIndex];
}
@end

Просмотреть файл

@ -1,85 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* 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 Camino code.
*
* The Initial Developer of the Original Code is
* Bryan Atwood
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bryan Atwood <bryan.h.atwood@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import <Cocoa/Cocoa.h>
#import "AutoCompleteUtils.h"
#include "nsIDOMEventListener.h"
#include "nsCOMPtr.h"
class nsIDOMHTMLInputElement;
//
// KeychainAutoCompleteDOMListener
//
// Listens for password fill requests from the FormFillController when a
// username is entered.
class KeychainAutoCompleteDOMListener : public nsIDOMEventListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMEVENTLISTENER
void SetElements(nsIDOMHTMLInputElement* usernameElement,
nsIDOMHTMLInputElement* passwordElement);
protected:
// Fills the password with the keychain data from the cached username input
// element.
void FillPassword();
// Pointers to the login input elements so that the form doesn't need to
// be searched when the same input element is attached again.
nsCOMPtr<nsIDOMHTMLInputElement> mUsernameElement; // strong
nsCOMPtr<nsIDOMHTMLInputElement> mPasswordElement; // strong
};
@interface KeychainAutoCompleteSession : NSObject<AutoCompleteSession>
{
KeychainAutoCompleteDOMListener* mDOMListener; // strong
NSMutableArray* mUsernames; // strong
NSString* mDefaultUser; // strong
// Cache the username input element so that we don't reread the keychain for
// the same element.
nsIDOMHTMLInputElement* mUsernameElement; // weak
}
- (BOOL)attachToInput:(nsIDOMHTMLInputElement*)usernameElement;
@end

Просмотреть файл