3306 lines
114 KiB
Plaintext
3306 lines
114 KiB
Plaintext
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Netscape 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/NPL/
|
|
*
|
|
* 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 mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 2002
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* 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 NPL, 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 NPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#import "NSString+Utils.h"
|
|
|
|
#import "BrowserWindowController.h"
|
|
#import "BrowserWindow.h"
|
|
|
|
#import "BookmarkToolbar.h"
|
|
#import "BookmarkViewController.h"
|
|
#import "BookmarkManager.h"
|
|
#import "ProgressDlgController.h"
|
|
|
|
#import "BrowserContentViews.h"
|
|
#import "BrowserWrapper.h"
|
|
#import "PreferenceManager.h"
|
|
#import "HistoryDataSource.h"
|
|
#import "BrowserTabView.h"
|
|
#import "UserDefaults.h"
|
|
#import "PageProxyIcon.h"
|
|
#import "AutoCompleteTextField.h"
|
|
#import "SearchTextField.h"
|
|
#import "SearchTextFieldCell.h"
|
|
#import "STFPopUpButtonCell.h"
|
|
#import "MainController.h"
|
|
#import "DraggableImageAndTextCell.h"
|
|
|
|
#include "nsIWebNavigation.h"
|
|
#include "nsISHistory.h"
|
|
#include "nsIHistoryEntry.h"
|
|
#include "nsIHistoryItems.h"
|
|
#include "nsIDOMDocument.h"
|
|
#include "nsIDOMNSDocument.h"
|
|
#include "nsIDOMLocation.h"
|
|
#include "nsIDOMElement.h"
|
|
#include "nsIDOMEvent.h"
|
|
#include "nsIPrefBranch.h"
|
|
#include "nsIContextMenuListener.h"
|
|
#include "nsIDOMWindow.h"
|
|
#include "CHBrowserService.h"
|
|
#include "nsString.h"
|
|
#include "nsCRT.h"
|
|
#include "GeckoUtils.h"
|
|
#include "nsIWebProgressListener.h"
|
|
#include "nsIWebBrowserChrome.h"
|
|
#include "nsNetUtil.h"
|
|
|
|
#include "nsIClipboardCommands.h"
|
|
#include "nsIWebBrowser.h"
|
|
#include "nsIInterfaceRequestorUtils.h"
|
|
#include "nsIPrefBranch.h"
|
|
#include "nsServiceManagerUtils.h"
|
|
#include "nsIURI.h"
|
|
#include "nsIURIFixup.h"
|
|
#include "nsIBrowserHistory.h"
|
|
#include "nsIPermissionManager.h"
|
|
#include "nsIWebPageDescriptor.h"
|
|
#include "nsPIDOMWindow.h"
|
|
#include "nsIDOMHTMLInputElement.h"
|
|
#include "nsIDOMHTMLTextAreaElement.h"
|
|
#include "nsIFocusController.h"
|
|
|
|
#include <QuickTime/QuickTime.h>
|
|
#include <AppKit/NSPasteboard.h>
|
|
#import <AddressBook/AddressBook.h>
|
|
#import "ABAddressBook+Utils.h"
|
|
|
|
#include "nsAppDirectoryServiceDefs.h"
|
|
|
|
static NSString *BrowserToolbarIdentifier = @"Browser Window Toolbar";
|
|
static NSString *BackToolbarItemIdentifier = @"Back Toolbar Item";
|
|
static NSString *ForwardToolbarItemIdentifier = @"Forward Toolbar Item";
|
|
static NSString *ReloadToolbarItemIdentifier = @"Reload Toolbar Item";
|
|
static NSString *StopToolbarItemIdentifier = @"Stop Toolbar Item";
|
|
static NSString *HomeToolbarItemIdentifier = @"Home Toolbar Item";
|
|
static NSString *LocationToolbarItemIdentifier = @"Location Toolbar Item";
|
|
static NSString *SidebarToolbarItemIdentifier = @"Sidebar Toolbar Item";
|
|
static NSString *PrintToolbarItemIdentifier = @"Print Toolbar Item";
|
|
static NSString *ThrobberToolbarItemIdentifier = @"Throbber Toolbar Item";
|
|
static NSString *SearchToolbarItemIdentifier = @"Search Toolbar Item";
|
|
static NSString *ViewSourceToolbarItemIdentifier = @"View Source Toolbar Item";
|
|
static NSString *BookmarkToolbarItemIdentifier = @"Bookmark Toolbar Item";
|
|
static NSString *TextBiggerToolbarItemIdentifier = @"Text Bigger Toolbar Item";
|
|
static NSString *TextSmallerToolbarItemIdentifier = @"Text Smaller Toolbar Item";
|
|
static NSString *NewTabToolbarItemIdentifier = @"New Tab Toolbar Item";
|
|
static NSString *CloseTabToolbarItemIdentifier = @"Close Tab Toolbar Item";
|
|
static NSString *SendURLToolbarItemIdentifier = @"Send URL Toolbar Item";
|
|
static NSString *DLManagerToolbarItemIdentifier = @"Download Manager Toolbar Item";
|
|
|
|
|
|
static NSString *NavigatorWindowFrameSaveName = @"NavigatorWindow";
|
|
|
|
// Cached toolbar defaults read in from a plist. If null, we'll use
|
|
// hardcoded defaults.
|
|
static NSArray* sToolbarDefaults = nil;
|
|
|
|
enum BWCOpenDest {
|
|
kDestinationNewWindow = 0,
|
|
kDestinationNewTab,
|
|
kDestinationCurrentView
|
|
};
|
|
|
|
//////////////////////////////////////
|
|
@interface AutoCompleteTextFieldEditor : NSTextView
|
|
{
|
|
NSFont* mDefaultFont; // will be needed if editing empty field
|
|
NSUndoManager *mUndoManager; //we handle our own undo to avoid stomping on bookmark undo
|
|
}
|
|
- (id)initWithFrame:(NSRect)bounds defaultFont:(NSFont*)defaultFont;
|
|
@end
|
|
|
|
@implementation AutoCompleteTextFieldEditor
|
|
|
|
// sets the defaultFont so that we don't paste in the wrong one
|
|
- (id)initWithFrame:(NSRect)bounds defaultFont:(NSFont*)defaultFont
|
|
{
|
|
if ((self = [super initWithFrame:bounds])) {
|
|
mDefaultFont = defaultFont;
|
|
mUndoManager = [[NSUndoManager alloc] init];
|
|
[self setDelegate:self];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
-(void) dealloc
|
|
{
|
|
[mUndoManager release];
|
|
[super dealloc];
|
|
}
|
|
|
|
-(void)paste:(id)sender
|
|
{
|
|
NSPasteboard *pboard = [NSPasteboard generalPasteboard];
|
|
NSEnumerator *dataTypes = [[pboard types] objectEnumerator];
|
|
NSString *aType;
|
|
while ((aType = [dataTypes nextObject])) {
|
|
if ([aType isEqualToString:NSStringPboardType]) {
|
|
NSString *oldText = [pboard stringForType:NSStringPboardType];
|
|
NSString *newText = [oldText stringByRemovingCharactersInSet:[NSCharacterSet controlCharacterSet]];
|
|
NSRange aRange = [self selectedRange];
|
|
if ([self shouldChangeTextInRange:aRange replacementString:newText]) {
|
|
[[self textStorage] replaceCharactersInRange:aRange withString:newText];
|
|
if (NSMaxRange(aRange) == 0 && mDefaultFont) // will only be true if the field is empty
|
|
[self setFont:mDefaultFont]; // wrong font will be used otherwise
|
|
[self didChangeText];
|
|
}
|
|
// after a paste, the insertion point should be after the pasted text
|
|
unsigned int newInsertionPoint = aRange.location + [newText length];
|
|
[self setSelectedRange:NSMakeRange(newInsertionPoint,0)];
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (NSUndoManager *)undoManagerForTextView:(NSTextView *)aTextView
|
|
{
|
|
if (aTextView == self)
|
|
return mUndoManager;
|
|
return nil;
|
|
}
|
|
|
|
@end
|
|
//////////////////////////////////////
|
|
|
|
#pragma mark -
|
|
|
|
//
|
|
// IconPopUpCell
|
|
//
|
|
// A popup cell that displays only an icon with no border, yet retains the
|
|
// behaviors of a popup menu. It's amazing you can't get this w/out having
|
|
// to subclass, but *shrug*.
|
|
//
|
|
@interface IconPopUpCell : NSPopUpButtonCell
|
|
{
|
|
@private
|
|
NSImage* fImage;
|
|
NSRect fSrcRect; // rect cached for drawing, same size as image
|
|
}
|
|
- (id)initWithImage:(NSImage *)inImage;
|
|
@end
|
|
|
|
@implementation IconPopUpCell
|
|
|
|
- (id)initWithImage:(NSImage *)inImage
|
|
{
|
|
if ( (self = [super initTextCell:@"" pullsDown:YES]) )
|
|
{
|
|
fImage = [inImage retain];
|
|
fSrcRect = NSMakeRect(0,0,0,0);
|
|
fSrcRect.size = [fImage size];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
[fImage release];
|
|
[super dealloc];
|
|
}
|
|
|
|
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
|
|
{
|
|
[fImage setFlipped:[controlView isFlipped]];
|
|
cellFrame.size = fSrcRect.size; // don't scale
|
|
[fImage drawInRect:cellFrame fromRect:fSrcRect operation:NSCompositeSourceOver fraction:1.0];
|
|
}
|
|
|
|
@end
|
|
|
|
#pragma mark -
|
|
|
|
//
|
|
// interface ToolbarViewItem
|
|
//
|
|
// NSToolbarItem, by default, doesn't do validation for view items. Override
|
|
// that behavior to call |-validateToolbarItem:| on the item's target.
|
|
//
|
|
@interface ToolbarViewItem : NSToolbarItem
|
|
{
|
|
}
|
|
@end
|
|
|
|
@implementation ToolbarViewItem
|
|
|
|
//
|
|
// -validate
|
|
//
|
|
// Override default behavior (which does nothing at all for a view item) to
|
|
// ask the target to handle it. The target must perform all the appropriate
|
|
// enabling/disabling within |-validateToolbarItem:| because we can't know
|
|
// all the details. The return value is ignored.
|
|
//
|
|
- (void)validate
|
|
{
|
|
id target = [self target];
|
|
if ([target respondsToSelector:@selector(validateToolbarItem:)])
|
|
[target validateToolbarItem:self];
|
|
}
|
|
|
|
@end
|
|
|
|
#pragma mark -
|
|
|
|
//
|
|
// interface ToolbarButton
|
|
//
|
|
// A subclass of NSButton that responds to |-setControlSize:| which
|
|
// comes from the toolbar when it changes sizes. Adjust the size
|
|
// of our associated NSToolbarItem when the call comes.
|
|
//
|
|
// Note that |-setControlSize:| is not part of NSView's api, but the
|
|
// toolbar code calls it anyway, without any documentation to that
|
|
// effect.
|
|
//
|
|
@interface ToolbarButton : NSButton
|
|
{
|
|
NSToolbarItem* mToolbarItem;
|
|
}
|
|
-(id)initWithFrame:(NSRect)inFrame item:(NSToolbarItem*)inItem;
|
|
@end
|
|
|
|
@implementation ToolbarButton
|
|
|
|
-(id)initWithFrame:(NSRect)inFrame item:(NSToolbarItem*)inItem
|
|
{
|
|
if ((self = [super initWithFrame:inFrame])) {
|
|
mToolbarItem = inItem;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
//
|
|
// -setControlSize:
|
|
//
|
|
// Called by the toolbar when the toolbar changes icon size. Adjust our
|
|
// toolbar item so that it can adjust larger or smaller.
|
|
//
|
|
- (void)setControlSize:(NSControlSize)size
|
|
{
|
|
NSSize s;
|
|
if (size == NSRegularControlSize) {
|
|
s = NSMakeSize(32., 32.);
|
|
[mToolbarItem setMinSize:s];
|
|
[mToolbarItem setMaxSize:s];
|
|
}
|
|
else {
|
|
s = NSMakeSize(24., 24.);
|
|
[mToolbarItem setMinSize:s];
|
|
[mToolbarItem setMaxSize:s];
|
|
}
|
|
[[self image] setSize:s];
|
|
}
|
|
|
|
//
|
|
// -controlSize
|
|
//
|
|
// The toolbar assumes this implemented whenever |-setControlSize:| is implemented,
|
|
// though I'm not sure why.
|
|
//
|
|
- (NSControlSize)controlSize
|
|
{
|
|
return [[self cell] controlSize];
|
|
}
|
|
|
|
@end
|
|
|
|
#pragma mark -
|
|
|
|
@interface BrowserWindowController(Private)
|
|
// open a new window or tab, but doesn't load anything into them. Must be matched
|
|
// with a call to do that.
|
|
- (BrowserWindowController*)openNewWindow:(BOOL)aLoadInBG;
|
|
- (BrowserTabViewItem*)openNewTab:(BOOL)aLoadInBG;
|
|
|
|
- (void)setupToolbar;
|
|
- (void)ensureBookmarkViewController;
|
|
- (NSString*)getContextMenuNodeDocumentURL;
|
|
- (void)loadSourceOfURL:(NSString*)urlStr;
|
|
- (void)transformFormatString:(NSMutableString*)inFormat domain:(NSString*)inDomain search:(NSString*)inSearch;
|
|
- (void)openNewWindowWithDescriptor:(nsISupports*)aDesc displayType:(PRUint32)aDisplayType loadInBackground:(BOOL)aLoadInBG;
|
|
- (void)openNewTabWithDescriptor:(nsISupports*)aDesc displayType:(PRUint32)aDisplayType loadInBackground:(BOOL)aLoadInBG;
|
|
- (BOOL)isPageTextFieldFocused;
|
|
- (void)performSearch:(SearchTextField *)inSearchField inView:(BWCOpenDest)inDest inBackground:(BOOL)inLoadInBG;
|
|
- (void)goToLocationFromToolbarURLField:(AutoCompleteTextField *)inURLField inView:(BWCOpenDest)inDest inBackground:(BOOL)inLoadInBG;
|
|
|
|
// create back/forward session history menus on toolbar button
|
|
- (IBAction)backMenu:(id)inSender;
|
|
- (IBAction)forwardMenu:(id)inSender;
|
|
@end
|
|
|
|
@implementation BrowserWindowController
|
|
|
|
- (id)initWithWindowNibName:(NSString *)windowNibName
|
|
{
|
|
if ( (self = [super initWithWindowNibName:(NSString *)windowNibName]) )
|
|
{
|
|
// we cannot rely on the OS to correctly cascade new windows (RADAR bug 2972893)
|
|
// so we turn off the cascading. We do it at the end of |windowDidLoad|
|
|
[self setShouldCascadeWindows:NO];
|
|
mInitialized = NO;
|
|
mMoveReentrant = NO;
|
|
mShouldAutosave = YES;
|
|
mShouldLoadHomePage = YES;
|
|
mChromeMask = 0;
|
|
mContextMenuFlags = 0;
|
|
mContextMenuEvent = nsnull;
|
|
mContextMenuNode = nsnull;
|
|
mThrobberImages = nil;
|
|
mThrobberHandler = nil;
|
|
mURLFieldEditor = nil;
|
|
mProgressSuperview = nil;
|
|
mBookmarkToolbarItem = nil;
|
|
mSidebarToolbarItem = nil;
|
|
mSavedTitle = nil;
|
|
|
|
// register for services
|
|
NSArray* sendTypes = [NSArray arrayWithObjects:NSStringPboardType, nil];
|
|
NSArray* returnTypes = [NSArray arrayWithObjects:NSStringPboardType, nil];
|
|
[NSApp registerServicesMenuSendTypes:sendTypes returnTypes:returnTypes];
|
|
|
|
nsCOMPtr<nsIBrowserHistory> globalHist = do_GetService("@mozilla.org/browser/global-history;2");
|
|
mGlobalHistory = globalHist;
|
|
if ( mGlobalHistory )
|
|
NS_ADDREF(mGlobalHistory);
|
|
nsCOMPtr<nsIURIFixup> fixer ( do_GetService("@mozilla.org/docshell/urifixup;1") );
|
|
mURIFixer = fixer;
|
|
if ( fixer )
|
|
NS_ADDREF(mURIFixer);
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (BOOL)isResponderGeckoView:(NSResponder*) responder
|
|
{
|
|
return ([responder isKindOfClass:[NSView class]] &&
|
|
[(NSView*)responder isDescendantOf:[mBrowserView getBrowserView]]);
|
|
}
|
|
|
|
- (void)windowDidBecomeKey:(NSNotification *)notification
|
|
{
|
|
BOOL windowWithMultipleTabs = ([mTabBrowser numberOfTabViewItems] > 1);
|
|
// When this window gets focus, fix the Close Window modifiers depending
|
|
// on whether we have multiple tabs
|
|
[[NSApp delegate] adjustCloseTabMenuItemKeyEquivalent:windowWithMultipleTabs];
|
|
[[NSApp delegate] adjustCloseWindowMenuItemKeyEquivalent:windowWithMultipleTabs];
|
|
|
|
if ([self isResponderGeckoView:[[self window] firstResponder]]) {
|
|
CHBrowserView* browserView = [mBrowserView getBrowserView];
|
|
if (browserView)
|
|
[browserView setActive:YES];
|
|
}
|
|
}
|
|
|
|
- (void)windowDidResignKey:(NSNotification *)notification
|
|
{
|
|
// when we are no longer the key window, set the Close shortcut back
|
|
// to Command-W, for other windows.
|
|
[[NSApp delegate] adjustCloseTabMenuItemKeyEquivalent:NO];
|
|
[[NSApp delegate] adjustCloseWindowMenuItemKeyEquivalent:NO];
|
|
|
|
if ([self isResponderGeckoView:[[self window] firstResponder]]) {
|
|
CHBrowserView* browserView = [mBrowserView getBrowserView];
|
|
if (browserView)
|
|
[browserView setActive:NO];
|
|
}
|
|
}
|
|
|
|
- (void)windowDidBecomeMain:(NSNotification *)notification
|
|
{
|
|
// we have to manually enable/disable the bookmarks menu items, because we
|
|
// turn autoenabling off for that menu
|
|
[[NSApp delegate] adjustBookmarksMenuItemsEnabling:YES];
|
|
}
|
|
|
|
- (void)windowDidResignMain:(NSNotification *)notification
|
|
{
|
|
// we have to manually enable/disable the bookmarks menu items, because we
|
|
// turn autoenabling off for that menu
|
|
[[NSApp delegate] adjustBookmarksMenuItemsEnabling:NO];
|
|
}
|
|
|
|
-(void)mouseMoved:(NSEvent*)aEvent
|
|
{
|
|
if (mMoveReentrant)
|
|
return;
|
|
|
|
mMoveReentrant = YES;
|
|
NSView* view = [[[self window] contentView] hitTest: [aEvent locationInWindow]];
|
|
[view mouseMoved: aEvent];
|
|
[super mouseMoved: aEvent];
|
|
mMoveReentrant = NO;
|
|
}
|
|
|
|
-(void)autosaveWindowFrame
|
|
{
|
|
if (mShouldAutosave)
|
|
[[self window] saveFrameUsingName: NavigatorWindowFrameSaveName];
|
|
}
|
|
|
|
-(void)disableAutosave
|
|
{
|
|
mShouldAutosave = NO;
|
|
}
|
|
|
|
-(void)disableLoadPage
|
|
{
|
|
mShouldLoadHomePage = NO;
|
|
}
|
|
|
|
- (void)windowWillClose:(NSNotification *)notification
|
|
{
|
|
mClosingWindow = YES;
|
|
|
|
#if DEBUG
|
|
NSLog(@"Window will close notification.");
|
|
#endif
|
|
[self autosaveWindowFrame];
|
|
|
|
// ensure that the URL auto-complete popup is closed before the mork
|
|
// database is shut down, or we crash
|
|
[mURLBar clearResults];
|
|
|
|
{ // scope...
|
|
nsCOMPtr<nsIHistoryItems> history(do_QueryInterface(mGlobalHistory));
|
|
if (history)
|
|
history->Flush();
|
|
NS_IF_RELEASE(mGlobalHistory);
|
|
NS_IF_RELEASE(mURIFixer);
|
|
} // matters
|
|
|
|
// Tell the BrowserTabView the window is closed
|
|
[mTabBrowser windowClosed];
|
|
|
|
// if the bookmark manager is visible when we close the window, all hell
|
|
// breaks loose in the autorelease pool and when we try to show another
|
|
// window. Honestly, I don't know why, but the easy fix is to simply
|
|
// ensure that the browser is visible when we close.
|
|
[self ensureBrowserVisible:self];
|
|
|
|
// we have to manually enable/disable the bookmarks menu items, because we
|
|
// turn autoenabling off for that menu
|
|
[[NSApp delegate] adjustBookmarksMenuItemsEnabling:NO];
|
|
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
|
|
// autorelease just in case we're here because of a window closing
|
|
// initiated from gecko, in which case this BWC would still be on the
|
|
// stack and may need to stay alive until it unwinds. We've already
|
|
// shut down gecko above, so we can safely go away at a later time.
|
|
[self autorelease];
|
|
}
|
|
|
|
//
|
|
// - stopAllPendingLoads
|
|
//
|
|
// For each tab, stop it from loading
|
|
//
|
|
- (void)stopAllPendingLoads
|
|
{
|
|
int numTabs = [mTabBrowser numberOfTabViewItems];
|
|
for (int i = 0; i < numTabs; i++) {
|
|
NSTabViewItem* item = [mTabBrowser tabViewItemAtIndex: i];
|
|
[[[item view] getBrowserView] stop: nsIWebNavigation::STOP_ALL];
|
|
}
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
#if DEBUG
|
|
NSLog(@"Browser controller died.");
|
|
#endif
|
|
|
|
// clear the window-level undo manager used by the edit field. Not sure
|
|
// why this isn't automatically done, but we'll leave objects hanging around in
|
|
// the undo/redo if we do not. We also cannot do this in the url bar's dealloc,
|
|
// it only works if it's here.
|
|
[[[self window] undoManager] removeAllActions];
|
|
|
|
// active Gecko connections have already been shut down in |windowWillClose|
|
|
// so we don't need to worry about that here. We only have to be careful
|
|
// not to access anything related to the document, as it's been destroyed. The
|
|
// superclass dealloc takes care of our child NSView's, which include the
|
|
// BrowserWrappers and their child CHBrowserViews.
|
|
|
|
//if (mSidebarBrowserView)
|
|
// [mSidebarBrowserView windowClosed];
|
|
|
|
[mSavedTitle release];
|
|
[mProgress release];
|
|
[mPopupBlocked release];
|
|
[mSearchBar release];
|
|
[self stopThrobber];
|
|
[mThrobberImages release];
|
|
[mURLFieldEditor release];
|
|
|
|
[mBookmarkViewController release];
|
|
|
|
[super dealloc];
|
|
}
|
|
|
|
//
|
|
// windowDidLoad
|
|
//
|
|
// setup all the things we can't do in the nib. Note that we defer the setup of
|
|
// the bookmarks view until the user actually displays it the first time.
|
|
//
|
|
- (void)windowDidLoad
|
|
{
|
|
[super windowDidLoad];
|
|
|
|
BOOL mustResizeChrome = NO;
|
|
|
|
// hide the resize control if specified by the chrome mask
|
|
if ( mChromeMask && !(mChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE) )
|
|
[[self window] setShowsResizeIndicator:NO];
|
|
|
|
if ( mChromeMask && !(mChromeMask & nsIWebBrowserChrome::CHROME_STATUSBAR) ) {
|
|
// remove the status bar at the bottom
|
|
[mStatusBar removeFromSuperview];
|
|
mustResizeChrome = YES;
|
|
|
|
// clear out everything in the status bar we were holding on to. This will cause us to
|
|
// pass nil for these status items into the CHBrowserwWrapper which is what we want. We'll
|
|
// crash if we give them things that have gone away.
|
|
mProgress = nil;
|
|
mStatus = nil;
|
|
mLock = nil;
|
|
mPopupBlocked = nil;
|
|
}
|
|
else {
|
|
// Retain with a single extra refcount. This allows us to remove
|
|
// the progress meter from its superview without having to worry
|
|
// about retaining and releasing it. Cache the superview of the
|
|
// progress. Dynamically fetch the superview so as not to burden
|
|
// someone rearranging the nib with this detail. Note that this
|
|
// needs to be in a subview from the status bar because if the
|
|
// window resizes while it is hidden, its position wouldn't get updated.
|
|
// Having it in a separate view that stays visible (and is thus
|
|
// involved in the layout process) solves this.
|
|
[mProgress retain];
|
|
mProgressSuperview = [mProgress superview];
|
|
|
|
// due to a cocoa issue with it updating the bounding box of two rects
|
|
// that both needing updating instead of just the two individual rects
|
|
// (radar 2194819), we need to make the text area opaque.
|
|
[mStatus setBackgroundColor:[NSColor windowBackgroundColor]];
|
|
[mStatus setDrawsBackground:YES];
|
|
|
|
// create a new cell for our popup blocker item that draws just an image
|
|
// yet still retains the functionality of a popdown menu. Like the progress
|
|
// meter above, we retain so we can hide with impunity and grab its superview.
|
|
// However, unlike the progress meter, this doesn't need to be in a subview from
|
|
// the status bar because it is in a fixed position on the LHS.
|
|
[mPopupBlocked retain];
|
|
NSFont* savedFont = [[mPopupBlocked cell] font];
|
|
NSMenu* savedMenu = [mPopupBlocked menu]; // must cache this before replacing cell
|
|
IconPopUpCell* iconCell = [[[IconPopUpCell alloc] initWithImage:[NSImage imageNamed:@"popup-blocked"]] autorelease];
|
|
[mPopupBlocked setCell:iconCell];
|
|
[iconCell setFont:savedFont];
|
|
[mPopupBlocked setToolTip:NSLocalizedString(@"A web popup was blocked", "Web Popup Toolitp")];
|
|
// [iconCell setPreferredEdge:NSMaxYEdge];
|
|
[iconCell setMenu:savedMenu];
|
|
[iconCell setBordered:NO];
|
|
mPopupBlockSuperview = [mPopupBlocked superview];
|
|
[self showPopupBlocked:NO];
|
|
|
|
// register for notifications so we can populate the popup blocker menu
|
|
// right before it's displayed.
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(buildPopupBlockerMenu:)
|
|
name:NSPopUpButtonCellWillPopUpNotification object:iconCell];
|
|
}
|
|
|
|
// Set up the toolbar's search text field
|
|
NSMutableArray *searchTitles =
|
|
[NSMutableArray arrayWithArray:[[[BrowserWindowController searchURLDictionary] allKeys] sortedArrayUsingSelector:@selector(compare:)]];
|
|
|
|
[searchTitles removeObject:@"PreferredSearchEngine"];
|
|
|
|
[mSearchBar addPopUpMenuItemsWithTitles:searchTitles];
|
|
[[[mSearchBar cell] popUpButtonCell] selectItemWithTitle:
|
|
[[BrowserWindowController searchURLDictionary] objectForKey:@"PreferredSearchEngine"]];
|
|
|
|
[mSearchBar retain];
|
|
[mSearchBar removeFromSuperview];
|
|
|
|
// Set the sheet's search text field
|
|
[mSearchSheetTextField addPopUpMenuItemsWithTitles:searchTitles];
|
|
[[[mSearchSheetTextField cell] popUpButtonCell] selectItemWithTitle:
|
|
[[BrowserWindowController searchURLDictionary] objectForKey:@"PreferredSearchEngine"]];
|
|
|
|
// Get our saved dimensions.
|
|
NSRect oldFrame = [[self window] frame];
|
|
[[self window] setFrameUsingName: NavigatorWindowFrameSaveName];
|
|
|
|
if (NSEqualSizes(oldFrame.size, [[self window] frame].size))
|
|
mustResizeChrome = YES;
|
|
|
|
mInitialized = YES;
|
|
|
|
[[self window] setAcceptsMouseMovedEvents: YES];
|
|
|
|
[self setupToolbar];
|
|
|
|
|
|
// 03/03/2002 mlj Changing strategy a bit here. The addTab: method was
|
|
// duplicating a lot of the code found here. I have moved it to that method.
|
|
// We now remove the IB tab, then add one of our own.
|
|
|
|
[mTabBrowser removeTabViewItem:[mTabBrowser tabViewItemAtIndex:0]];
|
|
|
|
// create ourselves a new tab and fill it with the appropriate content. If we
|
|
// have a URL pending to be opened here, don't load anything in it, otherwise,
|
|
// load the homepage if that's what the user wants (or about:blank).
|
|
[self createNewTab:(mPendingURL ? eNewTabEmpty : (mShouldLoadHomePage ? eNewTabHomepage : eNewTabAboutBlank))];
|
|
|
|
// we have a url "pending" from the "open new window with link" command. Deal
|
|
// with it now that everything is loaded.
|
|
if (mPendingURL) {
|
|
if (mShouldLoadHomePage)
|
|
[self loadURL:mPendingURL referrer:mPendingReferrer activate:mPendingActivate allowPopups:mPendingAllowPopups];
|
|
[mPendingURL release];
|
|
[mPendingReferrer release];
|
|
mPendingURL = mPendingReferrer = nil;
|
|
}
|
|
|
|
if ( mChromeMask && !(mChromeMask & nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR) ) {
|
|
// remove the personal toolbar and adjust the content area upwards. Removing it
|
|
// from the parent view releases it, so we have to clear out the member var.
|
|
//float height = [mPersonalToolbar frame].size.height;
|
|
[mPersonalToolbar removeFromSuperview];
|
|
mPersonalToolbar = nil;
|
|
mustResizeChrome = YES;
|
|
}
|
|
else
|
|
{
|
|
[mPersonalToolbar buildButtonList];
|
|
|
|
if (![self shouldShowBookmarkToolbar])
|
|
[mPersonalToolbar showBookmarksToolbar:NO];
|
|
}
|
|
|
|
if (mustResizeChrome)
|
|
[mContentView resizeSubviewsWithOldSize:[mContentView frame].size];
|
|
|
|
// stagger window from last browser, if there is one. we can't just use autoposition
|
|
// because it doesn't work on multiple monitors (radar bug 2972893). |getFrontmostBrowserWindow|
|
|
// only gets fully chromed windows, so this will do the right thing for popups (yay!).
|
|
const int kWindowStaggerOffset = 15;
|
|
NSWindow* lastBrowser = [[NSApp delegate] getFrontmostBrowserWindow];
|
|
if ( lastBrowser != [self window] ) {
|
|
NSRect screenRect = [[lastBrowser screen] visibleFrame];
|
|
NSRect testBrowserFrame = [lastBrowser frame];
|
|
NSPoint previousOrigin = testBrowserFrame.origin;
|
|
testBrowserFrame.origin.x += kWindowStaggerOffset;
|
|
testBrowserFrame.origin.y -= kWindowStaggerOffset;
|
|
|
|
// check if this new window position would overlap the dock or go off the screen. We test
|
|
// this by ensuring that it is contained by the visible screen rect (excluding dock). If
|
|
// not, the window juts out somewhere and needs to be repositioned.
|
|
if ( !NSContainsRect(screenRect, testBrowserFrame) ) {
|
|
// if a normal cascade fails, try shifting horizontally and reseting vertically
|
|
testBrowserFrame.origin.y = NSMaxY(screenRect) - testBrowserFrame.size.height;
|
|
if ( !NSContainsRect(screenRect, testBrowserFrame) ) {
|
|
// if shifting right also fails, try shifting vertically and reseting horizontally instead
|
|
testBrowserFrame.origin.x = NSMinX(screenRect);
|
|
testBrowserFrame.origin.y = previousOrigin.y - kWindowStaggerOffset;
|
|
if ( !NSContainsRect(screenRect, testBrowserFrame) ) {
|
|
// if all else fails, give up and reset to the upper left corner
|
|
testBrowserFrame.origin.x = NSMinX(screenRect);
|
|
testBrowserFrame.origin.y = NSMaxY(screenRect) - testBrowserFrame.size.height;
|
|
}
|
|
}
|
|
}
|
|
// actually move the window
|
|
[[self window] setFrameOrigin: testBrowserFrame.origin];
|
|
}
|
|
|
|
// if the search field is not on the toolbar, nil out the nextKeyView of the
|
|
// url bar so that we know to break off the toolbar when tabbing. If it is,
|
|
// and we're running on pre-panther, set the search bar as the tab view. We
|
|
// don't want to do this on panther because it will do it for us.
|
|
if (![mSearchBar window])
|
|
[mURLBar setNextKeyView:nil];
|
|
else {
|
|
const float kPantherAppKit = 743.0;
|
|
if (NSAppKitVersionNumber < kPantherAppKit)
|
|
[mURLBar setNextKeyView:mSearchBar];
|
|
}
|
|
|
|
// needed when full keyboard access is enabled
|
|
[mLock setRefusesFirstResponder:YES];
|
|
}
|
|
|
|
- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)proposedFrameSize
|
|
{
|
|
//if ( mChromeMask && !(mChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE) )
|
|
// return [[self window] frame].size;
|
|
return proposedFrameSize;
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
// -createToolbarPopupButton:
|
|
//
|
|
// Create a new instance of one of our special click-hold popup buttons that knows
|
|
// how to display a menu on click-hold. Associate it with the toolbar item |inItem|.
|
|
- (NSButton*)createToolbarPopupButton:(NSToolbarItem*)inItem
|
|
{
|
|
NSRect frame = NSMakeRect(0.,0.,32.,32.);
|
|
NSButton* button = [[[ToolbarButton alloc] initWithFrame:frame item:inItem] autorelease];
|
|
if (button) {
|
|
DraggableImageAndTextCell* newCell = [[[DraggableImageAndTextCell alloc] init] autorelease];
|
|
[newCell setDraggable:YES];
|
|
[newCell setClickHoldTimeout:0.75];
|
|
[button setCell:newCell];
|
|
|
|
[button setBezelStyle: NSRegularSquareBezelStyle];
|
|
[button setButtonType: NSMomentaryChangeButton];
|
|
[button setBordered: NO];
|
|
[button setImagePosition: NSImageOnly];
|
|
}
|
|
return button;
|
|
}
|
|
|
|
- (void)setupToolbar
|
|
{
|
|
if ( !mChromeMask || (mChromeMask & nsIWebBrowserChrome::CHROME_TOOLBAR) ) {
|
|
NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier:BrowserToolbarIdentifier] autorelease];
|
|
|
|
[toolbar setDisplayMode:NSToolbarDisplayModeDefault];
|
|
[toolbar setAllowsUserCustomization:YES];
|
|
[toolbar setAutosavesConfiguration:YES];
|
|
[toolbar setDelegate:self];
|
|
[[self window] setToolbar:toolbar];
|
|
}
|
|
}
|
|
|
|
// toolbarWillAddItem: (toolbar delegate method)
|
|
//
|
|
// Called when a button is about to be added to a toolbar. This is where we should
|
|
// cache items we may need later. For instance, we want to hold onto the sidebar
|
|
// toolbar item so we can change it when the drawer opens and closes.
|
|
- (void)toolbarWillAddItem:(NSNotification *)notification
|
|
{
|
|
NSToolbarItem* item = [[notification userInfo] objectForKey:@"item"];
|
|
if ( [[item itemIdentifier] isEqual:SidebarToolbarItemIdentifier] )
|
|
mSidebarToolbarItem = item;
|
|
else if ( [[item itemIdentifier] isEqual:BookmarkToolbarItemIdentifier] )
|
|
mBookmarkToolbarItem = item;
|
|
else if ( [[item itemIdentifier] isEqual:SearchToolbarItemIdentifier] ) {
|
|
// restore the next key view of the url bar to the search bar, but only
|
|
// if we're on jaguar. On panther, we really don't know that it should
|
|
// be the search toolbar (it could be another toolbar button if full keyboard
|
|
// access is enabled) but it will fix itself automatically.
|
|
const float kPantherAppKit = 743.0;
|
|
if (NSAppKitVersionNumber < kPantherAppKit)
|
|
[mURLBar setNextKeyView:mSearchBar];
|
|
}
|
|
}
|
|
|
|
//
|
|
// toolbarDidRemoveItem: (toolbar delegate method)
|
|
//
|
|
// Called when a button is about to be removed from a toolbar. This is where we should
|
|
// uncache items so we don't access them after they're gone. For instance, we want to
|
|
// clear our ref to the sidebar toolbar item.
|
|
//
|
|
- (void)toolbarDidRemoveItem:(NSNotification *)notification
|
|
{
|
|
NSToolbarItem* item = [[notification userInfo] objectForKey:@"item"];
|
|
if ( [[item itemIdentifier] isEqual:SidebarToolbarItemIdentifier] )
|
|
mSidebarToolbarItem = nil;
|
|
else if ( [[item itemIdentifier] isEqual:ThrobberToolbarItemIdentifier] )
|
|
[self stopThrobber];
|
|
else if ( [[item itemIdentifier] isEqual:BookmarkToolbarItemIdentifier] )
|
|
mBookmarkToolbarItem = nil;
|
|
else if ( [[item itemIdentifier] isEqual:SearchToolbarItemIdentifier] ) {
|
|
// search bar removed, set next key view of url bar to nil which tells
|
|
// it to break out of the toolbar tab ring on a tab.
|
|
[mURLBar setNextKeyView:nil];
|
|
}
|
|
|
|
}
|
|
|
|
- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
|
|
{
|
|
return [NSArray arrayWithObjects: BackToolbarItemIdentifier,
|
|
ForwardToolbarItemIdentifier,
|
|
ReloadToolbarItemIdentifier,
|
|
StopToolbarItemIdentifier,
|
|
HomeToolbarItemIdentifier,
|
|
LocationToolbarItemIdentifier,
|
|
SidebarToolbarItemIdentifier,
|
|
ThrobberToolbarItemIdentifier,
|
|
SearchToolbarItemIdentifier,
|
|
PrintToolbarItemIdentifier,
|
|
ViewSourceToolbarItemIdentifier,
|
|
BookmarkToolbarItemIdentifier,
|
|
NewTabToolbarItemIdentifier,
|
|
CloseTabToolbarItemIdentifier,
|
|
TextBiggerToolbarItemIdentifier,
|
|
TextSmallerToolbarItemIdentifier,
|
|
SendURLToolbarItemIdentifier,
|
|
NSToolbarCustomizeToolbarItemIdentifier,
|
|
NSToolbarFlexibleSpaceItemIdentifier,
|
|
NSToolbarSpaceItemIdentifier,
|
|
NSToolbarSeparatorItemIdentifier,
|
|
DLManagerToolbarItemIdentifier,
|
|
nil];
|
|
}
|
|
|
|
// + toolbarDefaults
|
|
//
|
|
// Parse a plist called "ToolbarDefaults.plist" in our Resources subfolder. This
|
|
// allows anyone to easily customize the default set w/out having to recompile. We
|
|
// hold onto the list for the duration of the app to avoid reparsing it every
|
|
// time.
|
|
+ (NSArray*) toolbarDefaults
|
|
{
|
|
if ( !sToolbarDefaults ) {
|
|
sToolbarDefaults = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"ToolbarDefaults" ofType:@"plist"]];
|
|
[sToolbarDefaults retain];
|
|
}
|
|
return sToolbarDefaults;
|
|
}
|
|
|
|
|
|
- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar
|
|
{
|
|
// try to get the defaults from the plist, but if not, hardcode something so
|
|
// the user always has a toolbar.
|
|
NSArray* defaults = [BrowserWindowController toolbarDefaults];
|
|
NS_ASSERTION(defaults, "Couldn't load toolbar defaults from plist");
|
|
return ( defaults ? defaults : [NSArray arrayWithObjects: BackToolbarItemIdentifier,
|
|
ForwardToolbarItemIdentifier,
|
|
ReloadToolbarItemIdentifier,
|
|
StopToolbarItemIdentifier,
|
|
LocationToolbarItemIdentifier,
|
|
SearchToolbarItemIdentifier,
|
|
SidebarToolbarItemIdentifier,
|
|
nil] );
|
|
}
|
|
|
|
// XXX use a dictionary to speed up the following?
|
|
|
|
- (NSToolbarItem *) toolbar:(NSToolbar *)toolbar
|
|
itemForItemIdentifier:(NSString *)itemIdent
|
|
willBeInsertedIntoToolbar:(BOOL)willBeInserted
|
|
{
|
|
NSToolbarItem *toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier:itemIdent] autorelease];
|
|
if ( [itemIdent isEqual:BackToolbarItemIdentifier] && willBeInserted ) {
|
|
// create a new toolbar item that knows how to do validation
|
|
toolbarItem = [[[ToolbarViewItem alloc] initWithItemIdentifier:itemIdent] autorelease];
|
|
|
|
NSButton* button = [self createToolbarPopupButton:toolbarItem];
|
|
[toolbarItem setLabel:NSLocalizedString(@"Back", @"Back")];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"Go Back", @"Go Back")];
|
|
[toolbarItem setToolTip:NSLocalizedString(@"BackToolTip", @"Go back one page")];
|
|
|
|
NSSize size = NSMakeSize(32., 32.);
|
|
NSImage* icon = [NSImage imageNamed:@"back"];
|
|
[icon setScalesWhenResized:YES];
|
|
[button setImage:icon];
|
|
|
|
[toolbarItem setView:button];
|
|
[toolbarItem setMinSize:size];
|
|
[toolbarItem setMaxSize:size];
|
|
|
|
[button setTarget:self];
|
|
[button setAction:@selector(back:)];
|
|
[toolbarItem setTarget:self];
|
|
[toolbarItem setAction:@selector(back:)]; // so validateToolbarItem: works correctly
|
|
[[button cell] setClickHoldAction:@selector(backMenu:)];
|
|
|
|
NSMenuItem *menuFormRep = [[[NSMenuItem alloc] init] autorelease];
|
|
[menuFormRep setTarget:self];
|
|
[menuFormRep setAction:@selector(back:)];
|
|
[menuFormRep setTitle:[toolbarItem label]];
|
|
|
|
[toolbarItem setMenuFormRepresentation:menuFormRep];
|
|
}
|
|
else if ([itemIdent isEqual:BackToolbarItemIdentifier]) {
|
|
// not going onto the toolbar, don't need to go through the gynmastics above
|
|
// and create a separate view
|
|
[toolbarItem setLabel:NSLocalizedString(@"Back", @"Back")];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"Go Back", @"Go Back")];
|
|
[toolbarItem setImage:[NSImage imageNamed:@"back"]];
|
|
}
|
|
else if ( [itemIdent isEqual:ForwardToolbarItemIdentifier] && willBeInserted ) {
|
|
// create a new toolbar item that knows how to do validation
|
|
toolbarItem = [[[ToolbarViewItem alloc] initWithItemIdentifier:itemIdent] autorelease];
|
|
|
|
NSButton* button = [self createToolbarPopupButton:toolbarItem];
|
|
[toolbarItem setLabel:NSLocalizedString(@"Forward", @"Forward")];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"Go Forward", @"Go Forward")];
|
|
[toolbarItem setToolTip:NSLocalizedString(@"ForwardToolTip", @"Go forward one page")];
|
|
|
|
NSSize size = NSMakeSize(32., 32.);
|
|
NSImage* icon = [NSImage imageNamed:@"forward"];
|
|
[icon setScalesWhenResized:YES];
|
|
[button setImage:icon];
|
|
|
|
[toolbarItem setView:button];
|
|
[toolbarItem setMinSize:size];
|
|
[toolbarItem setMaxSize:size];
|
|
|
|
[button setTarget:self];
|
|
[button setAction:@selector(forward:)];
|
|
[toolbarItem setTarget:self];
|
|
[toolbarItem setAction:@selector(forward:)]; // so validateToolbarItem: works correctly
|
|
[[button cell] setClickHoldAction:@selector(forwardMenu:)];
|
|
|
|
NSMenuItem *menuFormRep = [[[NSMenuItem alloc] init] autorelease];
|
|
[menuFormRep setTarget:self];
|
|
[menuFormRep setAction:@selector(forward:)];
|
|
[menuFormRep setTitle:[toolbarItem label]];
|
|
|
|
[toolbarItem setMenuFormRepresentation:menuFormRep];
|
|
}
|
|
else if ([itemIdent isEqual:ForwardToolbarItemIdentifier]) {
|
|
// not going onto the toolbar, don't need to go through the gynmastics above
|
|
// and create a separate view
|
|
[toolbarItem setLabel:NSLocalizedString(@"Forward", @"Forward")];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"Go Forward", @"Go Forward")];
|
|
[toolbarItem setImage:[NSImage imageNamed:@"forward"]];
|
|
}
|
|
else if ([itemIdent isEqual:ReloadToolbarItemIdentifier]) {
|
|
[toolbarItem setLabel:NSLocalizedString(@"Reload", @"Reload")];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"Reload Page", @"Reload Page")];
|
|
[toolbarItem setToolTip:NSLocalizedString(@"ReloadToolTip", @"Reload current page")];
|
|
[toolbarItem setImage:[NSImage imageNamed:@"reload"]];
|
|
[toolbarItem setTarget:self];
|
|
[toolbarItem setAction:@selector(reload:)];
|
|
}
|
|
else if ([itemIdent isEqual:StopToolbarItemIdentifier]) {
|
|
[toolbarItem setLabel:NSLocalizedString(@"Stop", @"Stop")];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"Stop Loading", @"Stop Loading")];
|
|
[toolbarItem setToolTip:NSLocalizedString(@"StopToolTip", @"Stop loading this page")];
|
|
[toolbarItem setImage:[NSImage imageNamed:@"stop"]];
|
|
[toolbarItem setTarget:self];
|
|
[toolbarItem setAction:@selector(stop:)];
|
|
}
|
|
else if ([itemIdent isEqual:HomeToolbarItemIdentifier]) {
|
|
[toolbarItem setLabel:NSLocalizedString(@"Home", @"Home")];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"Go Home", @"Go Home")];
|
|
[toolbarItem setToolTip:NSLocalizedString(@"HomeToolTip", @"Go to home page")];
|
|
[toolbarItem setImage:[NSImage imageNamed:@"home"]];
|
|
[toolbarItem setTarget:self];
|
|
[toolbarItem setAction:@selector(home:)];
|
|
}
|
|
else if ([itemIdent isEqual:SidebarToolbarItemIdentifier]) {
|
|
[toolbarItem setLabel:NSLocalizedString(@"ToggleBookmarks", @"Manage Bookmarks label")];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"Manage Bookmarks", @"Manage Bookmarks palette")];
|
|
[toolbarItem setToolTip:NSLocalizedString(@"BookmarkMgrToolTip", @"Show or hide all bookmarks")];
|
|
[toolbarItem setImage:[NSImage imageNamed:@"manager"]];
|
|
[toolbarItem setTarget:self];
|
|
[toolbarItem setAction:@selector(toggleSidebar:)];
|
|
}
|
|
else if ( [itemIdent isEqual:SearchToolbarItemIdentifier] ) {
|
|
NSMenuItem *menuFormRep = [[[NSMenuItem alloc] init] autorelease];
|
|
|
|
[toolbarItem setLabel:NSLocalizedString(@"Search", @"Search")];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"Search", @"Search")];
|
|
[toolbarItem setToolTip:NSLocalizedString(@"SearchToolTip", @"Search the Internet")];
|
|
[toolbarItem setView:mSearchBar];
|
|
[toolbarItem setMinSize:NSMakeSize(128, NSHeight([mSearchBar frame]))];
|
|
[toolbarItem setMaxSize:NSMakeSize(150, NSHeight([mSearchBar frame]))];
|
|
[toolbarItem setTarget:self];
|
|
[toolbarItem setAction:@selector(performSearch:)];
|
|
|
|
[menuFormRep setTarget:self];
|
|
[menuFormRep setAction:@selector(beginSearchSheet)];
|
|
[menuFormRep setTitle:[toolbarItem label]];
|
|
|
|
[toolbarItem setMenuFormRepresentation:menuFormRep];
|
|
}
|
|
else if ([itemIdent isEqual:ThrobberToolbarItemIdentifier]) {
|
|
[toolbarItem setLabel:@""];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"Progress", @"Progress")];
|
|
[toolbarItem setToolTip:NSLocalizedStringFromTable(@"ThrobberPageDefault", @"WebsiteDefaults", nil)];
|
|
[toolbarItem setImage:[NSImage imageNamed:@"throbber-01"]];
|
|
[toolbarItem setTarget:self];
|
|
[toolbarItem setTag:'Thrb'];
|
|
[toolbarItem setAction:@selector(clickThrobber:)];
|
|
}
|
|
else if ([itemIdent isEqual:LocationToolbarItemIdentifier]) {
|
|
NSMenuItem *menuFormRep = [[[NSMenuItem alloc] init] autorelease];
|
|
|
|
[toolbarItem setLabel:NSLocalizedString(@"Location", @"Location")];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"Location", @"Location")];
|
|
[toolbarItem setView:mLocationToolbarView];
|
|
[toolbarItem setMinSize:NSMakeSize(128, NSHeight([mLocationToolbarView frame]))];
|
|
[toolbarItem setMaxSize:NSMakeSize(2560, NSHeight([mLocationToolbarView frame]))];
|
|
|
|
[menuFormRep setTarget:self];
|
|
[menuFormRep setAction:@selector(performAppropriateLocationAction)];
|
|
[menuFormRep setTitle:[toolbarItem label]];
|
|
|
|
[toolbarItem setMenuFormRepresentation:menuFormRep];
|
|
}
|
|
else if ([itemIdent isEqual:PrintToolbarItemIdentifier]) {
|
|
[toolbarItem setLabel:NSLocalizedString(@"Print", @"Print")];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"Print", @"Print")];
|
|
[toolbarItem setToolTip:NSLocalizedString(@"PrintToolTip", @"Print this page")];
|
|
[toolbarItem setImage:[NSImage imageNamed:@"print"]];
|
|
[toolbarItem setTarget:self];
|
|
[toolbarItem setAction:@selector(printDocument:)];
|
|
}
|
|
else if ([itemIdent isEqual:ViewSourceToolbarItemIdentifier]) {
|
|
[toolbarItem setLabel:NSLocalizedString(@"View Source", @"View Source")];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"View Page Source", @"View Page Source")];
|
|
[toolbarItem setToolTip:NSLocalizedString(@"ViewSourceToolTip", @"Display the HTML source of this page")];
|
|
[toolbarItem setImage:[NSImage imageNamed:@"showsource"]];
|
|
[toolbarItem setTarget:self];
|
|
[toolbarItem setAction:@selector(viewSource:)];
|
|
}
|
|
else if ([itemIdent isEqual:BookmarkToolbarItemIdentifier]) {
|
|
[toolbarItem setLabel:NSLocalizedString(@"Bookmark", @"Bookmark")];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"Bookmark Page", @"Bookmark Page")];
|
|
[toolbarItem setToolTip:NSLocalizedString(@"BookmarkToolTip", @"Add this page to your bookmarks")];
|
|
[toolbarItem setImage:[NSImage imageNamed:@"add_to_bookmark.tif"]];
|
|
[toolbarItem setTarget:self];
|
|
[toolbarItem setAction:@selector(bookmarkPage:)];
|
|
}
|
|
else if ([itemIdent isEqual:TextBiggerToolbarItemIdentifier]) {
|
|
[toolbarItem setLabel:NSLocalizedString(@"BigText", @"Enlarge Text")];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"BigText", @"Enlarge Text")];
|
|
[toolbarItem setToolTip:NSLocalizedString(@"BigTextToolTip", @"Enlarge the text on this page")];
|
|
[toolbarItem setImage:[NSImage imageNamed:@"textBigger.tif"]];
|
|
[toolbarItem setTarget:self];
|
|
[toolbarItem setAction:@selector(biggerTextSize:)];
|
|
}
|
|
else if ([itemIdent isEqual:TextSmallerToolbarItemIdentifier]) {
|
|
[toolbarItem setLabel:NSLocalizedString(@"SmallText", @"Shrink Text")];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"SmallText", @"Shrink Text")];
|
|
[toolbarItem setToolTip:NSLocalizedString(@"SmallTextToolTip", @"Shrink the text on this page")];
|
|
[toolbarItem setImage:[NSImage imageNamed:@"textSmaller.tif"]];
|
|
[toolbarItem setTarget:self];
|
|
[toolbarItem setAction:@selector(smallerTextSize:)];
|
|
}
|
|
else if ([itemIdent isEqual:NewTabToolbarItemIdentifier]) {
|
|
[toolbarItem setLabel:NSLocalizedString(@"NewTab", @"New Tab")];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"NewTab", @"New Tab")];
|
|
[toolbarItem setToolTip:NSLocalizedString(@"NewTabToolTip", @"Create a new tab")];
|
|
[toolbarItem setImage:[NSImage imageNamed:@"newTab.tif"]];
|
|
[toolbarItem setTarget:self];
|
|
[toolbarItem setAction:@selector(newTab:)];
|
|
}
|
|
else if ([itemIdent isEqual:CloseTabToolbarItemIdentifier]) {
|
|
[toolbarItem setLabel:NSLocalizedString(@"CloseTab", @"Close Tab")];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"CloseTab", @"Close Tab")];
|
|
[toolbarItem setToolTip:NSLocalizedString(@"CloseTabToolTip", @"Close the current tab")];
|
|
[toolbarItem setImage:[NSImage imageNamed:@"closeTab.tif"]];
|
|
[toolbarItem setTarget:self];
|
|
[toolbarItem setAction:@selector(closeCurrentTab:)];
|
|
}
|
|
else if ([itemIdent isEqual:SendURLToolbarItemIdentifier]) {
|
|
[toolbarItem setLabel:NSLocalizedString(@"SendLink", @"Send Link")];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"SendLink", @"Send Link")];
|
|
[toolbarItem setToolTip:NSLocalizedString(@"SendLinkToolTip", @"Send current URL")];
|
|
[toolbarItem setImage:[NSImage imageNamed:@"sendLink.tif"]];
|
|
[toolbarItem setTarget:self];
|
|
[toolbarItem setAction:@selector(sendURL:)];
|
|
}
|
|
else if ([itemIdent isEqual:DLManagerToolbarItemIdentifier]) {
|
|
[toolbarItem setLabel:NSLocalizedString(@"Downloads", @"Downloads")];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"Downloads", @"Downloads")];
|
|
[toolbarItem setToolTip:NSLocalizedString(@"DownloadsToolTip", @"Show the download manager")];
|
|
[toolbarItem setImage:[NSImage imageNamed:@"dl_manager.tif"]];
|
|
[toolbarItem setTarget:[ProgressDlgController sharedDownloadController]];
|
|
[toolbarItem setAction:@selector(showWindow:)];
|
|
}
|
|
else {
|
|
toolbarItem = nil;
|
|
}
|
|
|
|
return toolbarItem;
|
|
}
|
|
|
|
// This method handles the enabling/disabling of the toolbar buttons.
|
|
- (BOOL)validateToolbarItem:(NSToolbarItem *)theItem
|
|
{
|
|
// Check the action and see if it matches.
|
|
SEL action = [theItem action];
|
|
// NSLog(@"Validating toolbar item %@ with selector %s", [theItem label], action);
|
|
if (action == @selector(back:)) {
|
|
// if the bookmark manager is showing, we enable the back button so that
|
|
// they can click back to return to the webpage they were viewing.
|
|
BOOL enable = NO;
|
|
if ( [mContentView isBookmarkManagerVisible] )
|
|
enable = YES;
|
|
else
|
|
enable = [[mBrowserView getBrowserView] canGoBack];
|
|
|
|
// we have to handle all the enabling/disabling ourselves because this
|
|
// toolbar button is a view item. Note the return value is ignored.
|
|
[(NSButton*)[theItem view] setEnabled:enable];
|
|
return enable;
|
|
}
|
|
else if (action == @selector(forward:)) {
|
|
// we have to handle all the enabling/disabling ourselves because this
|
|
// toolbar button is a view item. Note the return value is ignored.
|
|
BOOL enable = [[mBrowserView getBrowserView] canGoForward];
|
|
[(NSButton*)[theItem view] setEnabled:enable];
|
|
return enable;
|
|
}
|
|
else if (action == @selector(reload:))
|
|
return [mBrowserView isBusy] == NO;
|
|
else if (action == @selector(stop:))
|
|
return [mBrowserView isBusy];
|
|
else if (action == @selector(bookmarkPage:))
|
|
return ![mBrowserView isEmpty];
|
|
else if (action == @selector(biggerTextSize:))
|
|
return ![mBrowserView isEmpty] && [[mBrowserView getBrowserView] canMakeTextBigger];
|
|
else if ( action == @selector(smallerTextSize:))
|
|
return ![mBrowserView isEmpty] && [[mBrowserView getBrowserView] canMakeTextSmaller];
|
|
else if (action == @selector(newTab:))
|
|
return YES;
|
|
else if (action == @selector(closeCurrentTab:))
|
|
return ([mTabBrowser numberOfTabViewItems] > 1);
|
|
else if (action == @selector(sendURL:))
|
|
{
|
|
NSString* curURL = [[self getBrowserWrapper] getCurrentURLSpec];
|
|
return ![MainController isBlankURL:curURL];
|
|
}
|
|
else if (action == @selector(viewSource:))
|
|
return ![mContentView isBookmarkManagerVisible];
|
|
else
|
|
return YES;
|
|
}
|
|
|
|
- (void)ensureBookmarkViewController
|
|
{
|
|
if (!mBookmarkViewController) {
|
|
mBookmarkViewController = [[BookmarkViewController alloc] initWithBrowserWindowController:self];
|
|
}
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)loadingStarted
|
|
{
|
|
[self startThrobber];
|
|
}
|
|
|
|
- (void)loadingDone
|
|
{
|
|
[self stopThrobber];
|
|
}
|
|
|
|
- (void)performAppropriateLocationAction
|
|
{
|
|
NSToolbar *toolbar = [[self window] toolbar];
|
|
if ( [toolbar isVisible] )
|
|
{
|
|
if ( ([[[self window] toolbar] displayMode] == NSToolbarDisplayModeIconAndLabel) ||
|
|
([[[self window] toolbar] displayMode] == NSToolbarDisplayModeIconOnly) )
|
|
{
|
|
NSArray *itemsWeCanSee = [toolbar visibleItems];
|
|
|
|
for (unsigned int i = 0; i < [itemsWeCanSee count]; i++)
|
|
{
|
|
if ([[[itemsWeCanSee objectAtIndex:i] itemIdentifier] isEqual:LocationToolbarItemIdentifier])
|
|
{
|
|
[self focusURLBar];
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[self beginLocationSheet];
|
|
}
|
|
|
|
- (void)focusURLBar
|
|
{
|
|
[[mBrowserView getBrowserView] setActive:NO];
|
|
[mURLBar selectText: self];
|
|
}
|
|
|
|
- (void)beginLocationSheet
|
|
{
|
|
[NSApp beginSheet: mLocationSheetWindow
|
|
modalForWindow: [self window]
|
|
modalDelegate: nil
|
|
didEndSelector: nil
|
|
contextInfo: nil];
|
|
}
|
|
|
|
- (IBAction)endLocationSheet:(id)sender
|
|
{
|
|
[mLocationSheetWindow orderOut:self];
|
|
[NSApp endSheet:mLocationSheetWindow returnCode:1];
|
|
[self loadURL:[mLocationSheetURLField stringValue] referrer:nil activate:YES allowPopups:NO];
|
|
}
|
|
|
|
- (IBAction)cancelLocationSheet:(id)sender
|
|
{
|
|
[mLocationSheetWindow orderOut:self];
|
|
[NSApp endSheet:mLocationSheetWindow returnCode:0];
|
|
}
|
|
|
|
- (void)performAppropriateSearchAction
|
|
{
|
|
NSToolbar *toolbar = [[self window] toolbar];
|
|
if ( [toolbar isVisible] )
|
|
{
|
|
if ( ([[[self window] toolbar] displayMode] == NSToolbarDisplayModeIconAndLabel) ||
|
|
([[[self window] toolbar] displayMode] == NSToolbarDisplayModeIconOnly) )
|
|
{
|
|
NSArray *itemsWeCanSee = [toolbar visibleItems];
|
|
|
|
for (unsigned int i = 0; i < [itemsWeCanSee count]; i++)
|
|
{
|
|
if ([[[itemsWeCanSee objectAtIndex:i] itemIdentifier] isEqual:SearchToolbarItemIdentifier])
|
|
{
|
|
[self focusSearchBar];
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[self beginSearchSheet];
|
|
}
|
|
|
|
- (void)focusSearchBar
|
|
{
|
|
[[mBrowserView getBrowserView] setActive:NO];
|
|
|
|
[mSearchBar selectText:self];
|
|
}
|
|
|
|
- (void)beginSearchSheet
|
|
{
|
|
[NSApp beginSheet: mSearchSheetWindow
|
|
modalForWindow: [self window]
|
|
modalDelegate: nil
|
|
didEndSelector: nil
|
|
contextInfo: nil];
|
|
}
|
|
|
|
- (IBAction)endSearchSheet:(id)sender
|
|
{
|
|
[mSearchSheetWindow orderOut:self];
|
|
[NSApp endSheet:mSearchSheetWindow returnCode:1];
|
|
[self performSearch:mSearchSheetTextField];
|
|
}
|
|
|
|
- (IBAction)cancelSearchSheet:(id)sender
|
|
{
|
|
[mSearchSheetWindow orderOut:self];
|
|
[NSApp endSheet:mSearchSheetWindow returnCode:0];
|
|
}
|
|
|
|
-(IBAction)cancelAddBookmarkSheet:(id)sender
|
|
{
|
|
[mAddBookmarkSheetWindow orderOut:self];
|
|
[NSApp endSheet:mAddBookmarkSheetWindow returnCode:0];
|
|
[mCachedBMVC endAddBookmark: 0];
|
|
}
|
|
|
|
-(IBAction)endAddBookmarkSheet:(id)sender
|
|
{
|
|
[mAddBookmarkSheetWindow orderOut:self];
|
|
[NSApp endSheet:mAddBookmarkSheetWindow returnCode:0];
|
|
[mCachedBMVC endAddBookmark: 1];
|
|
}
|
|
|
|
- (void)cacheBookmarkVC:(BookmarkViewController *)aVC
|
|
{
|
|
mCachedBMVC = aVC;
|
|
}
|
|
|
|
//
|
|
// - manageBookmarks:
|
|
//
|
|
// Toggle the bookmark manager in all cases. This is what users
|
|
// expect to happen. When the manager is displayed, retain the
|
|
// last selected collection, regardless of what it is.
|
|
//
|
|
-(IBAction)manageBookmarks: (id)aSender
|
|
{
|
|
[self toggleBookmarkManager: self];
|
|
}
|
|
|
|
//
|
|
// -manageHistory:
|
|
//
|
|
// History is a slightly different beast from bookmarks. Unlike
|
|
// bookmarks, which acts as a toggle, history ensures the manager
|
|
// is visible and selects the history collection. If the manager
|
|
// is already visible, selects the history collection.
|
|
//
|
|
// An alternate solution would be to have it select history when
|
|
// it wasn't the selected container, and hide when history was
|
|
// the selected collection (toggling in that one case). This makes
|
|
// me feel dirty as the command does two different things depending
|
|
// on the (possibly undiscoverable to the user) context in which it is
|
|
// invoked. For that reason, I've chosen to not have history be a
|
|
// toggle and see the fallout.
|
|
//
|
|
-(IBAction)manageHistory: (id)aSender
|
|
{
|
|
if ( ![mContentView isBookmarkManagerVisible] )
|
|
[self toggleBookmarkManager: self];
|
|
|
|
[mBookmarkViewController selectContainer:kHistoryContainerIndex];
|
|
}
|
|
|
|
- (IBAction)goToLocationFromToolbarURLField:(id)sender
|
|
{
|
|
if ([sender isKindOfClass:[AutoCompleteTextField class]])
|
|
[self goToLocationFromToolbarURLField:(AutoCompleteTextField *)sender
|
|
inView:kDestinationCurrentView inBackground:NO];
|
|
}
|
|
|
|
- (void)goToLocationFromToolbarURLField:(AutoCompleteTextField *)inURLField
|
|
inView:(BWCOpenDest)inDest inBackground:(BOOL)inLoadInBG
|
|
{
|
|
// trim off any whitespace around url
|
|
NSString *theURL = [[inURLField stringValue] stringByTrimmingWhitespace];
|
|
|
|
// look for bookmarks keywords match
|
|
NSArray *resolvedURLs = [[BookmarkManager sharedBookmarkManager] resolveBookmarksKeyword:theURL];
|
|
|
|
NSString* resolvedURL = nil;
|
|
if ([resolvedURLs count] == 1) {
|
|
resolvedURL = [resolvedURLs lastObject];
|
|
if (inDest == kDestinationNewTab)
|
|
[self openNewTabWithURL:resolvedURL referrer:nil loadInBackground:inLoadInBG allowPopups:NO];
|
|
else if (inDest == kDestinationNewWindow)
|
|
[self openNewWindowWithURL:resolvedURL referrer:nil loadInBackground:inLoadInBG allowPopups:NO];
|
|
else // if it's not a new window or a new tab, load into the current view
|
|
[self loadURL:resolvedURL referrer:nil activate:YES allowPopups:NO];
|
|
} else {
|
|
if (inDest == kDestinationNewTab || inDest == kDestinationNewWindow)
|
|
[self openURLArray:resolvedURLs replaceExistingTabs:NO allowPopups:NO];
|
|
else
|
|
[self openURLArray:resolvedURLs replaceExistingTabs:YES allowPopups:NO];
|
|
}
|
|
|
|
// global history needs to know the user typed this url so it can present it
|
|
// in autocomplete. We use the URI fixup service to strip whitespace and remove
|
|
// invalid protocols, etc. Don't save keyword-expanded urls.
|
|
if (resolvedURL && [theURL isEqualToString:resolvedURL] && mGlobalHistory && mURIFixer && [theURL length] > 0) {
|
|
nsAutoString url;
|
|
[theURL assignTo_nsAString:url];
|
|
NS_ConvertUCS2toUTF8 utf8URL(url);
|
|
|
|
nsCOMPtr<nsIURI> fixedURI;
|
|
mURIFixer->CreateFixupURI(utf8URL, 0, getter_AddRefs(fixedURI));
|
|
if (fixedURI)
|
|
mGlobalHistory->MarkPageAsTyped(fixedURI);
|
|
}
|
|
}
|
|
- (void)saveDocument:(BOOL)focusedFrame filterView:(NSView*)aFilterView
|
|
{
|
|
[[mBrowserView getBrowserView] saveDocument:focusedFrame filterView:aFilterView];
|
|
}
|
|
|
|
- (void)saveURL: (NSView*)aFilterView url: (NSString*)aURLSpec suggestedFilename: (NSString*)aFilename
|
|
{
|
|
[[mBrowserView getBrowserView] saveURL: aFilterView url: aURLSpec suggestedFilename: aFilename];
|
|
}
|
|
|
|
- (void)loadSourceOfURL:(NSString*)urlStr
|
|
{
|
|
// first attempt to get the source that's already loaded
|
|
PRBool loadInBackground;
|
|
nsCOMPtr<nsIPrefBranch> pref(do_GetService("@mozilla.org/preferences-service;1"));
|
|
pref->GetBoolPref("browser.tabs.loadInBackground", &loadInBackground);
|
|
|
|
nsCOMPtr<nsISupports> desc = [[mBrowserView getBrowserView] getPageDescriptor];
|
|
if (desc) {
|
|
// make sure we're not trying to load a subframe by checking |urlStr| against the url in
|
|
// the desc (which is a history entry). We can only use the desc if it's the toplevel page.
|
|
nsCOMPtr<nsIHistoryEntry> entry(do_QueryInterface(desc));
|
|
if (entry) {
|
|
nsCOMPtr<nsIURI> uri;
|
|
entry->GetURI(getter_AddRefs(uri));
|
|
nsCAutoString spec;
|
|
uri->GetSpec(spec);
|
|
if ([urlStr isEqualToString:[NSString stringWithUTF8String:spec.get()]]) {
|
|
[self openNewTabWithDescriptor:desc displayType:nsIWebPageDescriptor::DISPLAY_AS_SOURCE loadInBackground:loadInBackground];
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
//otherwise reload it from the server
|
|
NSString* viewSource = [@"view-source:" stringByAppendingString: urlStr];
|
|
[self openNewTabWithURL: viewSource referrer:nil loadInBackground: loadInBackground allowPopups:NO];
|
|
}
|
|
|
|
- (IBAction)viewSource:(id)aSender
|
|
{
|
|
NSString* urlStr = [[mBrowserView getBrowserView] getFocusedURLString];
|
|
[self loadSourceOfURL:urlStr];
|
|
}
|
|
|
|
- (IBAction)viewPageSource:(id)aSender
|
|
{
|
|
NSString* urlStr = [[mBrowserView getBrowserView] getCurrentURLSpec];
|
|
[self loadSourceOfURL:urlStr];
|
|
}
|
|
|
|
- (IBAction)printDocument:(id)aSender
|
|
{
|
|
[[mBrowserView getBrowserView] printDocument];
|
|
}
|
|
|
|
- (IBAction)pageSetup:(id)aSender
|
|
{
|
|
[[mBrowserView getBrowserView] pageSetup];
|
|
}
|
|
|
|
- (IBAction)performSearch:(id)aSender
|
|
{
|
|
// If we have a valid SearchTextField, perform a search using its contents
|
|
if ([aSender isKindOfClass:[SearchTextField class]])
|
|
[self performSearch:(SearchTextField *)aSender inView:kDestinationCurrentView inBackground:NO];
|
|
}
|
|
|
|
//
|
|
// - performSearch:inView:inBackground
|
|
//
|
|
// performs a search using searchField and opens either in the current view, a new tab, or a new
|
|
// window. If it's a new tab or window, loadInBG determines whether the window/tab is opened in the background
|
|
//
|
|
-(void)performSearch:(SearchTextField *)inSearchField inView:(BWCOpenDest)inDest inBackground:(BOOL)inLoadInBG
|
|
{
|
|
// Get the search URL from our dictionary of sites and search urls
|
|
NSMutableString *searchURL = [NSMutableString stringWithString:
|
|
[[BrowserWindowController searchURLDictionary] objectForKey:
|
|
[inSearchField titleOfSelectedPopUpItem]]];
|
|
NSString *currentURL = [[self getBrowserWrapper] getCurrentURLSpec];
|
|
NSString *searchString = [inSearchField stringValue];
|
|
|
|
const char *aURLSpec = [currentURL lossyCString];
|
|
NSString *aDomain = @"";
|
|
nsIURI *aURI = nil;
|
|
|
|
// If we have an about: type URL, remove " site:%d" from the search string
|
|
// This is a fix to deal with Google's Search this Site feature
|
|
// If other sites use %d to search the site, we'll have to have specific rules
|
|
// for those sites.
|
|
|
|
if ([currentURL hasPrefix:@"about:"]) {
|
|
NSRange domainStringRange = [searchURL rangeOfString:@" site:%d"
|
|
options:NSBackwardsSearch];
|
|
|
|
NSRange notFoundRange = NSMakeRange(NSNotFound, 0);
|
|
if (NSEqualRanges(domainStringRange, notFoundRange) == NO)
|
|
[searchURL deleteCharactersInRange:domainStringRange];
|
|
}
|
|
|
|
// If they didn't type anything in the search field, visit the domain of
|
|
// the search site, i.e. www.google.com for the Google site
|
|
if ([[inSearchField stringValue] isEqualToString:@""]) {
|
|
aURLSpec = [searchURL lossyCString];
|
|
|
|
if (NS_NewURI(&aURI, aURLSpec, nsnull, nsnull) == NS_OK) {
|
|
nsCAutoString spec;
|
|
aURI->GetHost(spec);
|
|
|
|
aDomain = [NSString stringWithUTF8String:spec.get()];
|
|
|
|
if (inDest == kDestinationNewTab)
|
|
[self openNewTabWithURL:aDomain referrer:nil loadInBackground:inLoadInBG allowPopups:NO];
|
|
else if (inDest == kDestinationNewWindow)
|
|
[self openNewWindowWithURL:aDomain referrer:nil loadInBackground:inLoadInBG allowPopups:NO];
|
|
else // if it's not a new window or a new tab, load into the current view
|
|
[self loadURL:aDomain referrer:nil activate:NO allowPopups:NO];
|
|
|
|
}
|
|
} else {
|
|
aURLSpec = [[[self getBrowserWrapper] getCurrentURLSpec] lossyCString];
|
|
|
|
// Get the domain so that we can replace %d in our searchURL
|
|
if (NS_NewURI(&aURI, aURLSpec, nsnull, nsnull) == NS_OK) {
|
|
nsCAutoString spec;
|
|
aURI->GetHost(spec);
|
|
|
|
aDomain = [NSString stringWithUTF8String:spec.get()];
|
|
}
|
|
|
|
// Escape the search string so the user can search for strings with
|
|
// special characters ("&", "+", etc.) List from RFC2396.
|
|
NSString *escapedSearchString = (NSString *) CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)searchString, NULL, CFSTR(";/?:@&=+$,"), kCFStringEncodingUTF8);
|
|
|
|
// replace the conversion specifiers (%d, %s) in the search string
|
|
[self transformFormatString:searchURL domain:aDomain search:escapedSearchString];
|
|
[escapedSearchString release];
|
|
|
|
if (inDest == kDestinationNewTab)
|
|
[self openNewTabWithURL:searchURL referrer:nil loadInBackground:inLoadInBG allowPopups:NO];
|
|
else if (inDest == kDestinationNewWindow)
|
|
[self openNewWindowWithURL:searchURL referrer:nil loadInBackground:inLoadInBG allowPopups:NO];
|
|
else // if it's not a new window or a new tab, load into the current view
|
|
[self loadURL:searchURL referrer:nil activate:NO allowPopups:NO];
|
|
}
|
|
}
|
|
|
|
// - transformFormatString:domain:search
|
|
//
|
|
// Replaces all occurances of %d in |inFormat| with |inDomain| and all occurances of
|
|
// %s with |inSearch|.
|
|
- (void) transformFormatString:(NSMutableString*)inFormat domain:(NSString*)inDomain search:(NSString*)inSearch
|
|
{
|
|
// Replace any occurence of %d with the current domain
|
|
[inFormat replaceOccurrencesOfString:@"%d" withString:inDomain options:NSBackwardsSearch
|
|
range:NSMakeRange(0, [inFormat length])];
|
|
|
|
// Replace any occurence of %s with the contents of the search text field
|
|
[inFormat replaceOccurrencesOfString:@"%s" withString:inSearch options:NSBackwardsSearch
|
|
range:NSMakeRange(0, [inFormat length])];
|
|
}
|
|
|
|
- (IBAction)sendURL:(id)aSender
|
|
{
|
|
NSString* titleString = nil;
|
|
NSString* urlString = nil;
|
|
|
|
[[self getBrowserWrapper] getTitle:&titleString andHref:&urlString];
|
|
|
|
if (!titleString) titleString = @"";
|
|
if (!urlString) urlString = @"";
|
|
|
|
// we need to encode entities in the title and url strings first. For some reason
|
|
// CFURLCreateStringByAddingPercentEscapes is only happy with UTF-8 strings.
|
|
CFStringRef urlUTF8String = CFStringCreateWithCString(kCFAllocatorDefault, [urlString UTF8String], kCFStringEncodingUTF8);
|
|
CFStringRef titleUTF8String = CFStringCreateWithCString(kCFAllocatorDefault, [titleString UTF8String], kCFStringEncodingUTF8);
|
|
|
|
CFStringRef escapedURL = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, urlUTF8String, NULL, CFSTR("&?="), kCFStringEncodingUTF8);
|
|
CFStringRef escapedTitle = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, titleUTF8String, NULL, CFSTR("&?="), kCFStringEncodingUTF8);
|
|
|
|
NSString* mailtoURLString = [NSString stringWithFormat:@"mailto:?subject=%@&body=%@", (NSString*)escapedTitle, (NSString*)escapedURL];
|
|
|
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:mailtoURLString]];
|
|
|
|
CFRelease(urlUTF8String);
|
|
CFRelease(titleUTF8String);
|
|
|
|
CFRelease(escapedURL);
|
|
CFRelease(escapedTitle);
|
|
}
|
|
|
|
- (NSToolbarItem*)throbberItem
|
|
{
|
|
// find our throbber toolbar item.
|
|
NSToolbar* toolbar = [[self window] toolbar];
|
|
NSArray* items = [toolbar visibleItems];
|
|
unsigned count = [items count];
|
|
for (unsigned i = 0; i < count; ++i) {
|
|
NSToolbarItem* item = [items objectAtIndex: i];
|
|
if ([item tag] == 'Thrb') {
|
|
return item;
|
|
}
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
- (NSArray*)throbberImages
|
|
{
|
|
// Simply load an array of NSImage objects from the files "throbber-NN.tif". I used "Quicktime Player" to
|
|
// save all of the frames of the animated gif as individual .tif files for simplicity of implementation.
|
|
if (mThrobberImages == nil)
|
|
{
|
|
NSImage* images[64];
|
|
int i;
|
|
for (i = 0;; ++i) {
|
|
NSString* imageName = [NSString stringWithFormat: @"throbber-%02d", i + 1];
|
|
images[i] = [NSImage imageNamed: imageName];
|
|
if (images[i] == nil)
|
|
break;
|
|
}
|
|
mThrobberImages = [[NSArray alloc] initWithObjects: images count: i];
|
|
}
|
|
return mThrobberImages;
|
|
}
|
|
|
|
|
|
- (void)clickThrobber:(id)aSender
|
|
{
|
|
NSString *pageToLoad = NSLocalizedStringFromTable(@"ThrobberPageDefault", @"WebsiteDefaults", nil);
|
|
if (![pageToLoad isEqualToString:@"ThrobberPageDefault"])
|
|
[self loadURL:pageToLoad referrer:nil activate:YES allowPopups:NO];
|
|
}
|
|
|
|
- (void)startThrobber
|
|
{
|
|
// optimization: only throb if the throbber toolbar item is visible.
|
|
NSToolbarItem* throbberItem = [self throbberItem];
|
|
if (throbberItem) {
|
|
[self stopThrobber];
|
|
mThrobberHandler = [[ThrobberHandler alloc] initWithToolbarItem:throbberItem
|
|
images:[self throbberImages]];
|
|
}
|
|
}
|
|
|
|
- (void)stopThrobber
|
|
{
|
|
[mThrobberHandler stopThrobber];
|
|
[mThrobberHandler release];
|
|
mThrobberHandler = nil;
|
|
[[self throbberItem] setImage: [[self throbberImages] objectAtIndex: 0]];
|
|
}
|
|
|
|
|
|
- (BOOL)findInPageWithPattern:(NSString*)text caseSensitive:(BOOL)inCaseSensitive
|
|
wrap:(BOOL)inWrap backwards:(BOOL)inBackwards
|
|
{
|
|
return [[mBrowserView getBrowserView] findInPageWithPattern:text caseSensitive:inCaseSensitive
|
|
wrap:inWrap backwards:inBackwards];
|
|
}
|
|
|
|
- (BOOL)findInPage:(BOOL)inBackwards
|
|
{
|
|
return [[mBrowserView getBrowserView] findInPage:inBackwards];
|
|
}
|
|
|
|
- (NSString*)lastFindText
|
|
{
|
|
return [[mBrowserView getBrowserView] lastFindText];
|
|
}
|
|
|
|
- (void)addBookmarkExtended:(BOOL)aIsFolder URL:(NSString*)aURL title:(NSString*)aTitle
|
|
{
|
|
// why doesn't this talk to the data source?
|
|
[self ensureBookmarkViewController];
|
|
[mBookmarkViewController ensureBookmarks];
|
|
[mBookmarkViewController addItem: self isFolder: aIsFolder URL:aURL title:aTitle];
|
|
}
|
|
|
|
- (BOOL)bookmarkManagerIsVisible
|
|
{
|
|
return [mContentView isBookmarkManagerVisible];
|
|
}
|
|
|
|
- (BOOL)singleBookmarkIsSelected
|
|
{
|
|
if (![mContentView isBookmarkManagerVisible]) return NO;
|
|
return ([mBookmarkViewController numberOfSelectedRows] == 1);
|
|
}
|
|
|
|
- (IBAction)bookmarkPage: (id)aSender
|
|
{
|
|
[self addBookmarkExtended:NO URL:nil title:nil];
|
|
}
|
|
|
|
|
|
- (IBAction)bookmarkLink: (id)aSender
|
|
{
|
|
nsCOMPtr<nsIDOMElement> linkContent;
|
|
nsAutoString href;
|
|
GeckoUtils::GetEnclosingLinkElementAndHref(mContextMenuNode, getter_AddRefs(linkContent), href);
|
|
nsAutoString linkText;
|
|
GeckoUtils::GatherTextUnder(linkContent, linkText);
|
|
NSString* urlStr = [NSString stringWith_nsAString:href];
|
|
NSString* titleStr = [NSString stringWith_nsAString:linkText];
|
|
[self addBookmarkExtended:NO URL:urlStr title:titleStr];
|
|
}
|
|
|
|
//
|
|
// -currentWebNavigation
|
|
//
|
|
// return a weak reference to the current web navigation object. Callers should
|
|
// not hold onto this for longer than the current call unless they addref it.
|
|
//
|
|
- (nsIWebNavigation*) currentWebNavigation
|
|
{
|
|
BrowserWrapper* wrapper = [self getBrowserWrapper];
|
|
if (!wrapper) return nsnull;
|
|
CHBrowserView* view = [wrapper getBrowserView];
|
|
if (!view) return nsnull;
|
|
nsCOMPtr<nsIWebBrowser> webBrowser = getter_AddRefs([view getWebBrowser]);
|
|
if (!webBrowser) return nsnull;
|
|
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(webBrowser));
|
|
return webNav.get();
|
|
}
|
|
|
|
//
|
|
// -sessionHistory
|
|
//
|
|
// Return a weak reference to the current session history object. Callers
|
|
// should not hold onto this for longer than the current call unless they addref.
|
|
//
|
|
- (nsISHistory*) sessionHistory
|
|
{
|
|
nsIWebNavigation* webNav = [self currentWebNavigation];
|
|
if (!webNav) return nil;
|
|
nsCOMPtr<nsISHistory> sessionHistory;
|
|
webNav->GetSessionHistory(getter_AddRefs(sessionHistory));
|
|
return sessionHistory.get();
|
|
}
|
|
|
|
- (void)historyItemAction:(id)inSender
|
|
{
|
|
// get web navigation for current browser
|
|
nsIWebNavigation* webNav = [self currentWebNavigation];
|
|
if (!webNav) return;
|
|
|
|
// browse to the history entry for the menuitem that was selected
|
|
PRInt32 historyIndex = [inSender tag];
|
|
webNav->GotoIndex(historyIndex);
|
|
}
|
|
|
|
//
|
|
// -populateSessionHistoryMenu:shist:from:to:
|
|
//
|
|
// Adds to the given popup menu the items of the session history from index |inFrom| to
|
|
// |inTo|. Sets the tag on the item to the index in the session history. When an item
|
|
// is selected, calls |-historyItemAction:|. Correctly handles iterating in the
|
|
// correct direction based on relative indices of from/to.
|
|
//
|
|
- (void)populateSessionHistoryMenu:(NSMenu*)inPopup shist:(nsISHistory*)inHistory from:(unsigned long)inFrom to:(unsigned long)inTo
|
|
{
|
|
// max number of characters in a menu title before cropping it
|
|
const unsigned int kMaxTitleLength = 80;
|
|
|
|
// go forwards if |inFrom| < |inTo| and backwards if |inFrom| > |inTo|
|
|
int direction = -1;
|
|
if (inFrom <= inTo)
|
|
direction = 1;
|
|
|
|
// create a menu item for each item in the session history. Instead of simply going
|
|
// from |inFrom| to |inTo|, we use |count| to take the directionality out of the loop
|
|
// control so we can go fwd or backwards with the same loop control.
|
|
const int numIterations = abs(inFrom - inTo) + 1;
|
|
for (PRInt32 i = inFrom, count = 0; count < numIterations; i += direction, ++count) {
|
|
nsCOMPtr<nsIHistoryEntry> entry;
|
|
inHistory->GetEntryAtIndex(i, PR_FALSE, getter_AddRefs(entry));
|
|
if (entry) {
|
|
nsXPIDLString textStr;
|
|
entry->GetTitle(getter_Copies(textStr));
|
|
NSString* title = [[NSString stringWith_nsAString: textStr] stringByTruncatingTo:kMaxTitleLength at:kTruncateAtMiddle];
|
|
NSMenuItem *newItem = [inPopup addItemWithTitle:title action:@selector(historyItemAction:) keyEquivalent:@""];
|
|
[newItem setTarget:self];
|
|
[newItem setTag:i];
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// -forwardMenu:
|
|
//
|
|
// Create a menu off the fwd button (the sender) that contains the session history
|
|
// from the current position forward to the most recent in the session history.
|
|
//
|
|
- (IBAction)forwardMenu:(id)inSender
|
|
{
|
|
NSMenu* popupMenu = [[[NSMenu alloc] init] autorelease];
|
|
[popupMenu addItemWithTitle:@"" action:NULL keyEquivalent:@""]; // dummy first item
|
|
|
|
// figure out what indices of the history to build in the menu. Item 0
|
|
// in the shared history is the least recent (beginning of history) page.
|
|
nsISHistory* sessionHistory = [self sessionHistory];
|
|
PRInt32 currentIndex;
|
|
sessionHistory->GetIndex(¤tIndex);
|
|
PRInt32 count;
|
|
sessionHistory->GetCount(&count);
|
|
|
|
// builds forwards from the item after the current to the end (|count|)
|
|
[self populateSessionHistoryMenu:popupMenu shist:sessionHistory from:currentIndex+1 to:count-1];
|
|
|
|
// use a temporary NSPopUpButtonCell to display the menu.
|
|
NSPopUpButtonCell *popupCell = [[[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:YES] autorelease];
|
|
[popupCell setMenu: popupMenu];
|
|
[popupCell trackMouse:[NSApp currentEvent] inRect:[inSender bounds] ofView:inSender untilMouseUp:YES];
|
|
}
|
|
|
|
//
|
|
// -backMenu:
|
|
//
|
|
// Create a menu off the back button (the sender) that contains the session history
|
|
// from the current position backward to the first item in the session history.
|
|
//
|
|
- (IBAction)backMenu:(id)inSender
|
|
{
|
|
// do nothing on click-hold if the bm manager is visible
|
|
if ( [mContentView isBookmarkManagerVisible] )
|
|
return;
|
|
|
|
NSMenu* popupMenu = [[[NSMenu alloc] init] autorelease];
|
|
[popupMenu addItemWithTitle:@"" action:NULL keyEquivalent:@""]; // dummy first item
|
|
|
|
// figure out what indices of the history to build in the menu. Item 0
|
|
// in the shared history is the least recent (beginning of history) page.
|
|
nsISHistory* sessionHistory = [self sessionHistory];
|
|
PRInt32 currentIndex;
|
|
sessionHistory->GetIndex(¤tIndex);
|
|
|
|
// builds backwards from the item before the current item to 0, the first item in the list
|
|
[self populateSessionHistoryMenu:popupMenu shist:sessionHistory from:currentIndex-1 to:0];
|
|
|
|
// use a temporary NSPopUpButtonCell to display the menu.
|
|
NSPopUpButtonCell *popupCell = [[[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:YES] autorelease];
|
|
[popupCell setMenu: popupMenu];
|
|
[popupCell trackMouse:[NSApp currentEvent] inRect:[inSender bounds] ofView:inSender untilMouseUp:YES];
|
|
}
|
|
|
|
- (IBAction)back:(id)aSender
|
|
{
|
|
// if the bookmark manager is visible, hitting the back button will restore
|
|
// the browser views, not actually go back.
|
|
if ( [mContentView isBookmarkManagerVisible] )
|
|
[self toggleBookmarkManager:self];
|
|
else
|
|
[[mBrowserView getBrowserView] goBack];
|
|
}
|
|
|
|
- (IBAction)forward:(id)aSender
|
|
{
|
|
[[mBrowserView getBrowserView] goForward];
|
|
}
|
|
|
|
- (IBAction)reload:(id)aSender
|
|
{
|
|
unsigned int reloadFlags = NSLoadFlagsNone;
|
|
|
|
if (([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask) != 0)
|
|
reloadFlags = NSLoadFlagsBypassCacheAndProxy;
|
|
|
|
[[mBrowserView getBrowserView] reload: reloadFlags];
|
|
}
|
|
|
|
- (IBAction)stop:(id)aSender
|
|
{
|
|
[[mBrowserView getBrowserView] stop: nsIWebNavigation::STOP_ALL];
|
|
}
|
|
|
|
- (IBAction)home:(id)aSender
|
|
{
|
|
[mBrowserView loadURI:[[PreferenceManager sharedInstance] homePage:NO] referrer: nil flags:NSLoadFlagsNone activate:NO allowPopups:NO];
|
|
}
|
|
|
|
- (NSString*)getContextMenuNodeDocumentURL
|
|
{
|
|
if (!mContextMenuNode) return @"";
|
|
|
|
nsCOMPtr<nsIDOMDocument> ownerDoc;
|
|
mContextMenuNode->GetOwnerDocument(getter_AddRefs(ownerDoc));
|
|
|
|
nsCOMPtr<nsIDOMNSDocument> nsDoc = do_QueryInterface(ownerDoc);
|
|
if (!nsDoc) return @"";
|
|
|
|
nsCOMPtr<nsIDOMLocation> location;
|
|
nsDoc->GetLocation(getter_AddRefs(location));
|
|
if (!location) return @"";
|
|
|
|
nsAutoString urlStr;
|
|
location->GetHref(urlStr);
|
|
return [NSString stringWith_nsAString:urlStr];
|
|
}
|
|
|
|
- (IBAction)frameToNewWindow:(id)sender
|
|
{
|
|
// assumes mContextMenuNode has been set
|
|
NSString* frameURL = [self getContextMenuNodeDocumentURL];
|
|
if ([frameURL length] > 0)
|
|
[self openNewWindowWithURL:frameURL referrer:nil loadInBackground:NO allowPopups:NO]; // follow the pref?
|
|
}
|
|
|
|
- (IBAction)frameToNewTab:(id)sender
|
|
{
|
|
// assumes mContextMenuNode has been set
|
|
NSString* frameURL = [self getContextMenuNodeDocumentURL];
|
|
if ([frameURL length] > 0)
|
|
[self openNewTabWithURL:frameURL referrer:nil loadInBackground:NO allowPopups:NO]; // follow the pref?
|
|
}
|
|
|
|
- (IBAction)frameToThisWindow:(id)sender
|
|
{
|
|
// assumes mContextMenuNode has been set
|
|
NSString* frameURL = [self getContextMenuNodeDocumentURL];
|
|
if ([frameURL length] > 0)
|
|
[self loadURL:frameURL referrer:nil activate:YES allowPopups:NO];
|
|
}
|
|
|
|
|
|
- (IBAction)toggleSidebar:(id)aSender
|
|
{
|
|
[self toggleBookmarkManager:self];
|
|
}
|
|
|
|
// map command-left arrow to 'back'
|
|
- (void)moveToBeginningOfLine:(id)sender
|
|
{
|
|
[self back:sender];
|
|
}
|
|
|
|
// map command-right arrow to 'forward'
|
|
- (void)moveToEndOfLine:(id)sender
|
|
{
|
|
[self forward:sender];
|
|
}
|
|
|
|
//
|
|
// isPageTextFieldFocused
|
|
//
|
|
// Determine if a text field in the content area has focus. Returns YES if the
|
|
// focus is in a <input type="text"> or <textarea>
|
|
//
|
|
- (BOOL)isPageTextFieldFocused
|
|
{
|
|
#define ENSURE_TRUE(x) if (!x) return NO;
|
|
BOOL isFocused = NO;
|
|
|
|
nsCOMPtr<nsIWebBrowser> webBrizzle = dont_AddRef([[[self getBrowserWrapper] getBrowserView] getWebBrowser]);
|
|
ENSURE_TRUE(webBrizzle);
|
|
nsCOMPtr<nsIDOMWindow> domWindow;
|
|
webBrizzle->GetContentDOMWindow(getter_AddRefs(domWindow));
|
|
nsCOMPtr<nsPIDOMWindow> privateWindow = do_QueryInterface(domWindow);
|
|
ENSURE_TRUE(privateWindow);
|
|
nsIFocusController *controller = privateWindow->GetRootFocusController();
|
|
ENSURE_TRUE(controller);
|
|
nsCOMPtr<nsIDOMElement> focusedItem;
|
|
controller->GetFocusedElement(getter_AddRefs(focusedItem));
|
|
|
|
// we got it, now check if it's what we care about
|
|
nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(focusedItem);
|
|
nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea = do_QueryInterface(focusedItem);
|
|
if (input) {
|
|
nsAutoString type;
|
|
input->GetType(type);
|
|
if (type == NS_LITERAL_STRING("text"))
|
|
isFocused = YES;
|
|
}
|
|
else if (textArea)
|
|
isFocused = YES;
|
|
|
|
return isFocused;
|
|
}
|
|
|
|
// map delete key to Back
|
|
- (void)deleteBackward:(id)sender
|
|
{
|
|
// there are times when backspaces can seep through from IME gone wrong. As a
|
|
// workaround until we can get them all fixed, ignore backspace when the
|
|
// focused widget is a text field (<input type="text"> or <textarea>
|
|
if ([self isPageTextFieldFocused])
|
|
return;
|
|
|
|
if ([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask)
|
|
[self forward:sender];
|
|
else
|
|
[self back:sender];
|
|
}
|
|
|
|
-(void)loadURL:(NSString*)aURLSpec referrer:(NSString*)aReferrer activate:(BOOL)activate allowPopups:(BOOL)inAllowPopups
|
|
{
|
|
if (mInitialized) {
|
|
[mBrowserView loadURI:aURLSpec referrer:aReferrer flags:NSLoadFlagsNone activate:activate allowPopups:inAllowPopups];
|
|
}
|
|
else {
|
|
// we haven't yet initialized all the browser machinery, stash the url and referrer
|
|
// until we're ready in windowDidLoad:
|
|
mPendingURL = aURLSpec;
|
|
[mPendingURL retain];
|
|
mPendingReferrer = aReferrer;
|
|
[mPendingReferrer retain];
|
|
mPendingActivate = activate;
|
|
mPendingAllowPopups = inAllowPopups;
|
|
}
|
|
}
|
|
|
|
- (void)updateLocationFields:(NSString *)locationString
|
|
{
|
|
if ( [locationString isEqual:@"about:blank"] )
|
|
locationString = @""; // return;
|
|
|
|
[mURLBar setURI:locationString];
|
|
[mLocationSheetURLField setStringValue:locationString];
|
|
|
|
// don't call [window display] here, no matter how much you might want
|
|
// to, because it forces a redraw of every view in the window and with a lot
|
|
// of tabs, it's dog slow.
|
|
// [[self window] display];
|
|
}
|
|
|
|
- (void)updateSiteIcons:(NSImage *)siteIconImage
|
|
{
|
|
if (siteIconImage == nil)
|
|
siteIconImage = [NSImage imageNamed:@"globe_ico"];
|
|
[mProxyIcon setImage:siteIconImage];
|
|
}
|
|
|
|
//
|
|
// closeBrowserWindow:
|
|
//
|
|
// Some gecko view in this window wants to close the window. If we have
|
|
// a bunch of tabs, only close the relevant tab, otherwise close the
|
|
// window as a whole.
|
|
//
|
|
- (void)closeBrowserWindow:(BrowserWrapper*)inBrowser
|
|
{
|
|
if ( [mTabBrowser numberOfTabViewItems] > 1 ) {
|
|
// close the appropriate browser (it may not be frontmost) and
|
|
// remove it from the tab UI
|
|
[inBrowser windowClosed];
|
|
[mTabBrowser removeTabViewItem:[inBrowser tab]];
|
|
}
|
|
else
|
|
{
|
|
// if a window unload handler calls window.close(), we
|
|
// can get here while the window is already being closed,
|
|
// so we don't want to close it again (and recurse).
|
|
if (!mClosingWindow)
|
|
[[self window] close];
|
|
}
|
|
}
|
|
|
|
- (void)createNewTab:(ENewTabContents)contents;
|
|
{
|
|
// ensureBrowserVisible needs to be called prior to createNewTabItem or the new view won't draw
|
|
// if the bookmarks manager was visible.
|
|
[self ensureBrowserVisible:self];
|
|
|
|
BrowserTabViewItem* newTab = [self createNewTabItem];
|
|
BrowserWrapper* newView = [newTab view];
|
|
|
|
BOOL loadHomepage = NO;
|
|
if (contents == eNewTabHomepage)
|
|
{
|
|
nsCOMPtr<nsIPrefBranch> pref(do_GetService("@mozilla.org/preferences-service;1"));
|
|
PRInt32 newTabPage = 0; // 0=about:blank, 1=home page, 2=last page visited
|
|
pref->GetIntPref("browser.tabs.startPage", &newTabPage);
|
|
loadHomepage = (newTabPage == 1);
|
|
}
|
|
|
|
[newTab setLabel: (loadHomepage ? NSLocalizedString(@"TabLoading", @"") : NSLocalizedString(@"UntitledPageTitle", @""))];
|
|
[mTabBrowser addTabViewItem: newTab];
|
|
|
|
BOOL focusURLBar = NO;
|
|
if (contents != eNewTabEmpty)
|
|
{
|
|
// Focus the URL bar if we're opening a blank tab and the URL bar is visible.
|
|
NSToolbar* toolbar = [[self window] toolbar];
|
|
BOOL locationBarVisible = [toolbar isVisible] &&
|
|
([toolbar displayMode] == NSToolbarDisplayModeIconAndLabel ||
|
|
[toolbar displayMode] == NSToolbarDisplayModeIconOnly);
|
|
|
|
NSString* urlToLoad = @"about:blank";
|
|
if (loadHomepage)
|
|
urlToLoad = [[PreferenceManager sharedInstance] homePage: NO];
|
|
|
|
focusURLBar = locationBarVisible && [MainController isBlankURL:urlToLoad];
|
|
|
|
[newView loadURI:urlToLoad referrer:nil flags:NSLoadFlagsNone activate:!focusURLBar allowPopups:NO];
|
|
}
|
|
|
|
[mTabBrowser selectLastTabViewItem: self];
|
|
|
|
if (focusURLBar)
|
|
[self focusURLBar];
|
|
}
|
|
|
|
- (IBAction)newTab:(id)sender
|
|
{
|
|
[self createNewTab:eNewTabHomepage]; // we'll look at the pref to decide whether to load the home page
|
|
}
|
|
|
|
-(IBAction)closeCurrentTab:(id)sender
|
|
{
|
|
if ( [mTabBrowser numberOfTabViewItems] > 1 ) {
|
|
[[[mTabBrowser selectedTabViewItem] view] windowClosed];
|
|
[mTabBrowser removeTabViewItem:[mTabBrowser selectedTabViewItem]];
|
|
}
|
|
}
|
|
|
|
- (IBAction)previousTab:(id)sender
|
|
{
|
|
if ([mTabBrowser indexOfTabViewItem:[mTabBrowser selectedTabViewItem]] == 0)
|
|
[mTabBrowser selectLastTabViewItem:sender];
|
|
else
|
|
[mTabBrowser selectPreviousTabViewItem:sender];
|
|
}
|
|
|
|
- (IBAction)nextTab:(id)sender
|
|
{
|
|
if ([mTabBrowser indexOfTabViewItem:[mTabBrowser selectedTabViewItem]] == [mTabBrowser numberOfTabViewItems] - 1)
|
|
[mTabBrowser selectFirstTabViewItem:sender];
|
|
else
|
|
[mTabBrowser selectNextTabViewItem:sender];
|
|
}
|
|
|
|
- (IBAction)closeSendersTab:(id)sender
|
|
{
|
|
if ([sender isMemberOfClass:[NSMenuItem class]])
|
|
{
|
|
BrowserTabViewItem* tabViewItem = [mTabBrowser itemWithTag:[sender tag]];
|
|
if (tabViewItem)
|
|
{
|
|
[[tabViewItem view] windowClosed];
|
|
[mTabBrowser removeTabViewItem:tabViewItem];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (IBAction)closeOtherTabs:(id)sender
|
|
{
|
|
if ([sender isMemberOfClass:[NSMenuItem class]])
|
|
{
|
|
BrowserTabViewItem* tabViewItem = [mTabBrowser itemWithTag:[sender tag]];
|
|
if (tabViewItem)
|
|
{
|
|
while ([mTabBrowser numberOfTabViewItems] > 1)
|
|
{
|
|
NSTabViewItem* doomedItem = nil;
|
|
if ([mTabBrowser indexOfTabViewItem:tabViewItem] == 0)
|
|
doomedItem = [mTabBrowser tabViewItemAtIndex:1];
|
|
else
|
|
doomedItem = [mTabBrowser tabViewItemAtIndex:0];
|
|
|
|
[[doomedItem view] windowClosed];
|
|
[mTabBrowser removeTabViewItem:doomedItem];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- (IBAction)reloadSendersTab:(id)sender
|
|
{
|
|
if ([sender isMemberOfClass:[NSMenuItem class]])
|
|
{
|
|
BrowserTabViewItem* tabViewItem = [mTabBrowser itemWithTag:[sender tag]];
|
|
if (tabViewItem)
|
|
{
|
|
[[[tabViewItem view] getBrowserView] reload: NSLoadFlagsNone];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (IBAction)moveTabToNewWindow:(id)sender
|
|
{
|
|
if ([sender isMemberOfClass:[NSMenuItem class]])
|
|
{
|
|
BrowserTabViewItem* tabViewItem = [mTabBrowser itemWithTag:[sender tag]];
|
|
if (tabViewItem)
|
|
{
|
|
NSString* url = [[tabViewItem view] getCurrentURLSpec];
|
|
|
|
PRBool backgroundLoad = PR_FALSE;
|
|
nsCOMPtr<nsIPrefBranch> pref(do_GetService("@mozilla.org/preferences-service;1"));
|
|
if (pref)
|
|
pref->GetBoolPref("browser.tabs.loadInBackground", &backgroundLoad);
|
|
|
|
[self openNewWindowWithURL:url referrer:nil loadInBackground:backgroundLoad allowPopups:NO];
|
|
|
|
[[tabViewItem view] windowClosed];
|
|
[mTabBrowser removeTabViewItem:tabViewItem];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)tabView:(NSTabView *)aTabView didSelectTabViewItem:(NSTabViewItem *)aTabViewItem
|
|
{
|
|
// we'll get called for the sidebar tabs as well. ignore any calls coming from
|
|
// there, we're only interested in the browser tabs.
|
|
if (aTabView != mTabBrowser)
|
|
return;
|
|
|
|
// Disconnect the old view, if one has been designated.
|
|
// If the window has just been opened, none has been.
|
|
if ( mBrowserView )
|
|
[mBrowserView disconnectView];
|
|
|
|
// Connect up the new view
|
|
mBrowserView = [aTabViewItem view];
|
|
[mTabBrowser refreshTabBar:YES];
|
|
|
|
// Make the new view the primary content area.
|
|
[mBrowserView makePrimaryBrowserView: mURLBar status: mStatus windowController: self];
|
|
}
|
|
|
|
- (void)tabView:(NSTabView *)aTabView willSelectTabViewItem:(NSTabViewItem *)aTabViewItem
|
|
{
|
|
// we'll get called for the sidebar tabs as well. ignore any calls coming from
|
|
// there, we're only interested in the browser tabs.
|
|
if (aTabView != mTabBrowser)
|
|
return;
|
|
if ([aTabView isKindOfClass:[BrowserTabView class]] && [aTabViewItem isKindOfClass:[BrowserTabViewItem class]]) {
|
|
[(BrowserTabViewItem *)[aTabView selectedTabViewItem] willDeselect];
|
|
[(BrowserTabViewItem *)aTabViewItem willSelect];
|
|
}
|
|
}
|
|
|
|
- (void)tabViewDidChangeNumberOfTabViewItems:(NSTabView *)aTabView
|
|
{
|
|
[[NSApp delegate] fixCloseMenuItemKeyEquivalents];
|
|
[mTabBrowser refreshTabBar:YES];
|
|
}
|
|
|
|
-(id)getTabBrowser
|
|
{
|
|
return mTabBrowser;
|
|
}
|
|
|
|
-(BrowserWrapper*)getBrowserWrapper
|
|
{
|
|
return mBrowserView;
|
|
}
|
|
|
|
-(void)openNewWindowWithURL:(NSString*)aURLSpec referrer:(NSString*)aReferrer loadInBackground:(BOOL)aLoadInBG allowPopups:(BOOL)inAllowPopups
|
|
{
|
|
BrowserWindowController* browser = [self openNewWindow:aLoadInBG];
|
|
[browser loadURL: aURLSpec referrer:aReferrer activate:!aLoadInBG allowPopups:inAllowPopups];
|
|
}
|
|
|
|
//
|
|
// -openNewWindow:
|
|
//
|
|
// open a new window, but doesn't load anything into it. Must be matched
|
|
// with a call to do that.
|
|
//
|
|
- (BrowserWindowController*)openNewWindow:(BOOL)aLoadInBG
|
|
{
|
|
// Autosave our dimensions before we open a new window. That ensures the size ends up matching.
|
|
[self autosaveWindowFrame];
|
|
|
|
BrowserWindowController* browser = [[BrowserWindowController alloc] initWithWindowNibName: @"BrowserWindow"];
|
|
if (aLoadInBG)
|
|
{
|
|
BrowserWindow* browserWin = [browser window];
|
|
[browserWin setSuppressMakeKeyFront:YES]; // prevent gecko focus bringing the window to the front
|
|
[browserWin orderWindow: NSWindowBelow relativeTo: [[self window] windowNumber]];
|
|
[browserWin setSuppressMakeKeyFront:NO];
|
|
}
|
|
else
|
|
[browser showWindow:self];
|
|
|
|
return browser;
|
|
}
|
|
|
|
-(void)openNewTabWithURL:(NSString*)aURLSpec referrer:(NSString*)aReferrer loadInBackground:(BOOL)aLoadInBG allowPopups:(BOOL)inAllowPopups
|
|
{
|
|
BrowserTabViewItem* newTab = [self openNewTab:aLoadInBG];
|
|
[[newTab view] loadURI:aURLSpec referrer:aReferrer flags:NSLoadFlagsNone activate:!aLoadInBG allowPopups:inAllowPopups];
|
|
}
|
|
|
|
//
|
|
// -openNewTab:
|
|
//
|
|
// open a new tab, but doesn't load anything into it. Must be matched
|
|
// with a call to do that.
|
|
//
|
|
- (BrowserTabViewItem*)openNewTab:(BOOL)aLoadInBG;
|
|
{
|
|
// ensureBrowserVisible needs to be called prior to createNewTabItem or the new view won't draw
|
|
// if the bookmarks manager was visible.
|
|
[self ensureBrowserVisible:self];
|
|
|
|
BrowserTabViewItem* newTab = [self createNewTabItem];
|
|
|
|
|
|
// hyatt originally made new tabs open on the far right and tabs opened from a content
|
|
// link open to the right of the current tab. The idea was to keep the new tab
|
|
// close to the tab that spawned it, since they are related. Users, however, got confused
|
|
// as to why tabs appeared in different places, so now all tabs go on the far right.
|
|
#ifdef OPEN_TAB_TO_RIGHT_OF_SELECTED
|
|
NSTabViewItem* selectedTab = [mTabBrowser selectedTabViewItem];
|
|
int index = [mTabBrowser indexOfTabViewItem: selectedTab];
|
|
[mTabBrowser insertTabViewItem: newTab atIndex: index+1];
|
|
#else
|
|
[mTabBrowser addTabViewItem: newTab];
|
|
#endif
|
|
|
|
[newTab setLabel: NSLocalizedString(@"TabLoading", @"")];
|
|
|
|
// unless we're told to load this tab in the bg, select the tab
|
|
// before we load so that it's the primary and will push the url into
|
|
// the url bar immediately rather than waiting for the server.
|
|
if (!aLoadInBG)
|
|
[mTabBrowser selectTabViewItem: newTab];
|
|
|
|
return newTab;
|
|
}
|
|
|
|
-(void)openNewWindowWithDescriptor:(nsISupports*)aDesc displayType:(PRUint32)aDisplayType loadInBackground:(BOOL)aLoadInBG;
|
|
{
|
|
BrowserWindowController* browser = [self openNewWindow:aLoadInBG];
|
|
[[[browser getBrowserWrapper] getBrowserView] setPageDescriptor:aDesc displayType:aDisplayType];
|
|
}
|
|
|
|
-(void)openNewTabWithDescriptor:(nsISupports*)aDesc displayType:(PRUint32)aDisplayType loadInBackground:(BOOL)aLoadInBG;
|
|
{
|
|
BrowserTabViewItem* newTab = [self openNewTab:aLoadInBG];
|
|
[[[newTab view] getBrowserView] setPageDescriptor:aDesc displayType:aDisplayType];
|
|
}
|
|
|
|
- (void)openURLArray:(NSArray*)urlArray replaceExistingTabs:(BOOL)replaceExisting allowPopups:(BOOL)inAllowPopups
|
|
{
|
|
// ensure the content area is visible. We can't rely on normal url loading
|
|
// to do this because for the new tabs we create below, they won't be connected
|
|
// to their controller until much later, so the call to ensure visibility fails.
|
|
[self ensureBrowserVisible:self];
|
|
|
|
int curNumTabs = [mTabBrowser numberOfTabViewItems];
|
|
int numItems = (int)[urlArray count];
|
|
|
|
for (int i = 0; i < numItems; i++)
|
|
{
|
|
NSString* thisURL = [urlArray objectAtIndex:i];
|
|
BrowserTabViewItem* tabViewItem;
|
|
|
|
if (replaceExisting && i < curNumTabs)
|
|
{
|
|
tabViewItem = [mTabBrowser tabViewItemAtIndex:i];
|
|
}
|
|
else
|
|
{
|
|
tabViewItem = [self createNewTabItem];
|
|
[tabViewItem setLabel: NSLocalizedString(@"UntitledPageTitle", @"")];
|
|
[mTabBrowser addTabViewItem: tabViewItem];
|
|
}
|
|
|
|
[[tabViewItem view] loadURI: thisURL referrer:nil
|
|
flags: NSLoadFlagsNone activate:(i == 0) allowPopups:inAllowPopups];
|
|
|
|
}
|
|
|
|
// Select the first tab.
|
|
[mTabBrowser selectTabViewItemAtIndex:replaceExisting ? 0 : curNumTabs];
|
|
}
|
|
|
|
-(void) openURLArrayReplacingTabs:(NSArray*)urlArray closeExtraTabs:(BOOL)closeExtra allowPopups:(BOOL)inAllowPopups
|
|
{
|
|
[self openURLArray:urlArray replaceExistingTabs:YES allowPopups:inAllowPopups];
|
|
if (closeExtra) {
|
|
int closeIndex = [urlArray count];
|
|
int closeCount = [mTabBrowser numberOfTabViewItems] - closeIndex;
|
|
for (int i = 0; i < closeCount; i++) {
|
|
[[mTabBrowser tabViewItemAtIndex:closeIndex] closeTab];
|
|
}
|
|
}
|
|
}
|
|
|
|
-(BrowserTabViewItem*)createNewTabItem
|
|
{
|
|
BrowserTabViewItem* newTab = [BrowserTabView makeNewTabItem];
|
|
BrowserWrapper* newView = [[[BrowserWrapper alloc] initWithTab: newTab andWindow: [mTabBrowser window]] autorelease];
|
|
|
|
[newTab setView: newView];
|
|
|
|
// we have to copy the context menu for each tag, because
|
|
// the menu gets the tab view item's tag.
|
|
NSMenu* contextMenu = [mTabMenu copy];
|
|
[[newTab tabItemContentsView] setMenu:contextMenu];
|
|
[contextMenu release];
|
|
|
|
return newTab;
|
|
}
|
|
|
|
-(void)setChromeMask:(unsigned int)aMask
|
|
{
|
|
mChromeMask = aMask;
|
|
}
|
|
|
|
-(unsigned int)chromeMask
|
|
{
|
|
return mChromeMask;
|
|
}
|
|
|
|
- (IBAction)biggerTextSize:(id)aSender
|
|
{
|
|
[[mBrowserView getBrowserView] biggerTextSize];
|
|
}
|
|
|
|
- (IBAction)smallerTextSize:(id)aSender
|
|
{
|
|
[[mBrowserView getBrowserView] smallerTextSize];
|
|
}
|
|
|
|
- (void)getInfo:(id)sender
|
|
{
|
|
[self ensureBookmarkViewController];
|
|
[mBookmarkViewController ensureBookmarks];
|
|
[mBookmarkViewController showBookmarkInfo:sender];
|
|
}
|
|
|
|
- (BOOL)canGetInfo
|
|
{
|
|
return [self singleBookmarkIsSelected];
|
|
}
|
|
|
|
- (BOOL)shouldShowBookmarkToolbar
|
|
{
|
|
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
|
|
if ([defaults integerForKey:USER_DEFAULTS_HIDE_PERS_TOOLBAR_KEY] == 1)
|
|
return NO;
|
|
|
|
return YES;
|
|
}
|
|
|
|
-(id)getAddBookmarkSheetWindow
|
|
{
|
|
return mAddBookmarkSheetWindow;
|
|
}
|
|
|
|
-(id)getAddBookmarkTitle
|
|
{
|
|
return mAddBookmarkTitleField;
|
|
}
|
|
|
|
-(id)getAddBookmarkFolder
|
|
{
|
|
return mAddBookmarkFolderField;
|
|
}
|
|
|
|
-(id)getAddBookmarkCheckbox
|
|
{
|
|
return mAddBookmarkCheckbox;
|
|
}
|
|
|
|
// Called when a context menu should be shown.
|
|
- (void)onShowContextMenu:(int)flags domEvent:(nsIDOMEvent*)aEvent domNode:(nsIDOMNode*)aNode
|
|
{
|
|
mContextMenuFlags = flags;
|
|
mContextMenuNode = aNode;
|
|
mContextMenuEvent = aEvent;
|
|
}
|
|
|
|
// Returns the text of the href attribute for the link the context menu is
|
|
// currently on. Returns an empty string if the context menu is not on a
|
|
// link or we couldn't work out the href for some other reason.
|
|
- (NSString*)getContextMenuNodeHrefText
|
|
{
|
|
if (mContextMenuNode) {
|
|
nsCOMPtr<nsIDOMElement> linkContent;
|
|
nsAutoString href;
|
|
GeckoUtils::GetEnclosingLinkElementAndHref(mContextMenuNode, getter_AddRefs(linkContent), href);
|
|
|
|
// XXXdwh Handle simple XLINKs if we want to be compatible with Mozilla, but who
|
|
// really uses these anyway? :)
|
|
if (linkContent && !href.IsEmpty())
|
|
return [NSString stringWith_nsAString:href];
|
|
}
|
|
|
|
// Not on a link or a link we don't understand
|
|
return @"";
|
|
}
|
|
|
|
// Determine if the node the context menu has been invoked for is an <a> node
|
|
// indicating a mailto: link. If so return the indicated e-mail address
|
|
// otherwise return nil
|
|
- (NSString*)getMailAddressFromContextMenuLinkNode
|
|
{
|
|
NSString* hrefStr = [self getContextMenuNodeHrefText];
|
|
|
|
if ([hrefStr hasPrefix:@"mailto:"]) {
|
|
NSString* linkTargetText = [hrefStr substringFromIndex:7];
|
|
|
|
// mailto: links can contain arguments (after '?') and/or multiple e-mail
|
|
// addresses (comma separated). We want just the first e-mail address.
|
|
NSRange separatorRange = [linkTargetText rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@",?"]];
|
|
|
|
if (separatorRange.length != 0)
|
|
linkTargetText = [linkTargetText substringToIndex:separatorRange.location];
|
|
|
|
return linkTargetText;
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
// Add the e-mail address from the mailto: link of the context menu node
|
|
// to the user's address book. If the address already exists we just
|
|
// open the address book at the record containing it.
|
|
- (IBAction)addToAddressBook:(id)aSender
|
|
{
|
|
NSString* emailAddress = [self getMailAddressFromContextMenuLinkNode];
|
|
if (emailAddress) {
|
|
ABAddressBook* abook = [ABAddressBook sharedAddressBook];
|
|
if ([abook emailAddressExistsInAddressBook:emailAddress] )
|
|
[abook openAddressBookForRecordWithEmail:emailAddress];
|
|
else
|
|
[abook addNewPersonFromEmail:emailAddress];
|
|
}
|
|
}
|
|
|
|
// Copy the e-mail address from the mailto: link of the context menu node
|
|
// onto the clipboard.
|
|
- (IBAction)copyAddressToClipboard:(id)aSender
|
|
{
|
|
NSString* emailAddress = [self getMailAddressFromContextMenuLinkNode];
|
|
|
|
if (emailAddress) {
|
|
NSPasteboard* clipboard = [NSPasteboard generalPasteboard];
|
|
|
|
NSArray* types = [NSArray arrayWithObject:NSStringPboardType];
|
|
|
|
[clipboard declareTypes:types owner:nil];
|
|
[clipboard setString:emailAddress forType:NSStringPboardType];
|
|
}
|
|
}
|
|
|
|
- (void)prepareAddToAddressBookMenuItem:(NSMenuItem*)addToAddressBookItem address:(NSString*)emailAddress
|
|
{
|
|
if ([[ABAddressBook sharedAddressBook] emailAddressExistsInAddressBook:emailAddress]) {
|
|
NSString* realName = [[ABAddressBook sharedAddressBook] getRealNameForEmailAddress:[self getMailAddressFromContextMenuLinkNode]];
|
|
[addToAddressBookItem setTitle:[NSString stringWithFormat:NSLocalizedString(@"Open %@ in Address Book", @"Open %@ in Address Book"), realName != nil ? realName : @""]];
|
|
[addToAddressBookItem setEnabled:YES];
|
|
} else {
|
|
[addToAddressBookItem setTitle:NSLocalizedString(@"Add to Address Book", @"Add to Address Book")];
|
|
[addToAddressBookItem setEnabled:([emailAddress length] > 0) ];
|
|
}
|
|
}
|
|
|
|
- (NSMenu*)getContextMenu
|
|
{
|
|
BOOL showFrameItems = NO;
|
|
|
|
NSMenu* menuPrototype = nil;
|
|
if ((mContextMenuFlags & nsIContextMenuListener::CONTEXT_LINK) != 0)
|
|
{
|
|
NSString* emailAddress = [self getMailAddressFromContextMenuLinkNode];
|
|
|
|
if ((mContextMenuFlags & nsIContextMenuListener::CONTEXT_IMAGE) != 0) {
|
|
if (emailAddress) {
|
|
[self prepareAddToAddressBookMenuItem:mAddToAddressBook2 address:emailAddress];
|
|
menuPrototype = mImageMailToLinkMenu;
|
|
}
|
|
else
|
|
menuPrototype = mImageLinkMenu;
|
|
}
|
|
else {
|
|
if (emailAddress) {
|
|
[self prepareAddToAddressBookMenuItem:mAddToAddressBook address:emailAddress];
|
|
menuPrototype = mMailToLinkMenu;
|
|
}
|
|
else
|
|
menuPrototype = mLinkMenu;
|
|
}
|
|
}
|
|
else if ((mContextMenuFlags & nsIContextMenuListener::CONTEXT_INPUT) != 0 ||
|
|
(mContextMenuFlags & nsIContextMenuListener::CONTEXT_TEXT) != 0) {
|
|
menuPrototype = mInputMenu;
|
|
}
|
|
else if ((mContextMenuFlags & nsIContextMenuListener::CONTEXT_IMAGE) != 0) {
|
|
menuPrototype = mImageMenu;
|
|
}
|
|
else if (!mContextMenuFlags || (mContextMenuFlags & nsIContextMenuListener::CONTEXT_DOCUMENT) != 0) {
|
|
// if there aren't any flags or we're in the background of a page,
|
|
// show the document menu. This prevents us from failing to find a case
|
|
// and not showing the context menu.
|
|
menuPrototype = mPageMenu;
|
|
[mBackItem setEnabled: [[mBrowserView getBrowserView] canGoBack]];
|
|
[mForwardItem setEnabled: [[mBrowserView getBrowserView] canGoForward]];
|
|
[mCopyItem setEnabled: [[mBrowserView getBrowserView] canCopy]];
|
|
}
|
|
|
|
if (mContextMenuNode) {
|
|
nsCOMPtr<nsIDOMDocument> ownerDoc;
|
|
mContextMenuNode->GetOwnerDocument(getter_AddRefs(ownerDoc));
|
|
|
|
nsCOMPtr<nsIDOMWindow> contentWindow = getter_AddRefs([[mBrowserView getBrowserView] getContentWindow]);
|
|
|
|
nsCOMPtr<nsIDOMDocument> contentDoc;
|
|
if (contentWindow)
|
|
contentWindow->GetDocument(getter_AddRefs(contentDoc));
|
|
|
|
showFrameItems = (contentDoc != ownerDoc);
|
|
}
|
|
|
|
// we have to clone the menu and return that, so that we don't change
|
|
// our only copy of the menu
|
|
NSMenu* result = [[menuPrototype copy] autorelease];
|
|
|
|
const int kFrameRelatedItemsTag = 100;
|
|
const int kFrameInapplicableItemsTag = 101;
|
|
|
|
if (showFrameItems) {
|
|
NSMenuItem* frameItem;
|
|
while ((frameItem = [result itemWithTag:kFrameInapplicableItemsTag]) != nil)
|
|
[result removeItem:frameItem];
|
|
}
|
|
else {
|
|
NSMenuItem* frameItem;
|
|
while ((frameItem = [result itemWithTag:kFrameRelatedItemsTag]) != nil)
|
|
[result removeItem:frameItem];
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Context menu methods
|
|
- (IBAction)openLinkInNewWindow:(id)aSender
|
|
{
|
|
[self openLinkInNewWindowOrTab: YES];
|
|
}
|
|
|
|
- (IBAction)openLinkInNewTab:(id)aSender
|
|
{
|
|
[self openLinkInNewWindowOrTab: NO];
|
|
}
|
|
|
|
-(void)openLinkInNewWindowOrTab: (BOOL)aUseWindow
|
|
{
|
|
NSString* hrefStr = [self getContextMenuNodeHrefText];
|
|
|
|
if ([hrefStr length] == 0)
|
|
return;
|
|
|
|
nsCOMPtr<nsIPrefBranch> pref(do_GetService("@mozilla.org/preferences-service;1"));
|
|
if (!pref)
|
|
return; // Something bad happened if we can't get prefs.
|
|
|
|
PRBool loadInBackground;
|
|
pref->GetBoolPref("browser.tabs.loadInBackground", &loadInBackground);
|
|
|
|
NSString* referrer = [[mBrowserView getBrowserView] getFocusedURLString];
|
|
|
|
if (aUseWindow)
|
|
[self openNewWindowWithURL: hrefStr referrer:referrer loadInBackground: loadInBackground allowPopups:NO];
|
|
else
|
|
[self openNewTabWithURL: hrefStr referrer:referrer loadInBackground: loadInBackground allowPopups:NO];
|
|
}
|
|
|
|
- (IBAction)savePageAs:(id)aSender
|
|
{
|
|
NSView* accessoryView = [[NSApp delegate] getSavePanelView];
|
|
[self saveDocument:NO filterView:accessoryView];
|
|
}
|
|
|
|
- (IBAction)saveFrameAs:(id)aSender
|
|
{
|
|
NSView* accessoryView = [[NSApp delegate] getSavePanelView];
|
|
[self saveDocument:YES filterView:accessoryView];
|
|
}
|
|
|
|
- (IBAction)saveLinkAs:(id)aSender
|
|
{
|
|
NSString* hrefStr = [self getContextMenuNodeHrefText];
|
|
|
|
if ([hrefStr length] == 0)
|
|
return;
|
|
|
|
// The user wants to save this link.
|
|
nsAutoString text;
|
|
GeckoUtils::GatherTextUnder(mContextMenuNode, text);
|
|
|
|
[self saveURL:nil url:hrefStr suggestedFilename:[NSString stringWith_nsAString:text]];
|
|
}
|
|
|
|
- (IBAction)saveImageAs:(id)aSender
|
|
{
|
|
nsCOMPtr<nsIDOMHTMLImageElement> imgElement(do_QueryInterface(mContextMenuNode));
|
|
if (imgElement) {
|
|
nsAutoString text;
|
|
imgElement->GetAttribute(NS_LITERAL_STRING("src"), text);
|
|
nsAutoString url;
|
|
imgElement->GetSrc(url);
|
|
|
|
NSString* hrefStr = [NSString stringWith_nsAString: url];
|
|
|
|
[self saveURL:nil url:hrefStr suggestedFilename: [NSString stringWith_nsAString: text]];
|
|
}
|
|
}
|
|
|
|
- (IBAction)copyImage:(id)sender
|
|
{
|
|
nsCOMPtr<nsIWebBrowser> webBrowser = getter_AddRefs([[[self getBrowserWrapper] getBrowserView] getWebBrowser]);
|
|
nsCOMPtr<nsIClipboardCommands> clipboard(do_GetInterface(webBrowser));
|
|
if (clipboard)
|
|
clipboard->CopyImageContents();
|
|
}
|
|
|
|
- (IBAction)copyImageLocation:(id)sender
|
|
{
|
|
nsCOMPtr<nsIWebBrowser> webBrowser = getter_AddRefs([[[self getBrowserWrapper] getBrowserView] getWebBrowser]);
|
|
nsCOMPtr<nsIClipboardCommands> clipboard(do_GetInterface(webBrowser));
|
|
if (clipboard)
|
|
clipboard->CopyImageLocation();
|
|
}
|
|
|
|
- (IBAction)copyLinkLocation:(id)aSender
|
|
{
|
|
nsCOMPtr<nsIWebBrowser> webBrowser = getter_AddRefs([[[self getBrowserWrapper] getBrowserView] getWebBrowser]);
|
|
nsCOMPtr<nsIClipboardCommands> clipboard(do_GetInterface(webBrowser));
|
|
if (clipboard)
|
|
clipboard->CopyLinkLocation();
|
|
}
|
|
|
|
- (IBAction)viewOnlyThisImage:(id)aSender
|
|
{
|
|
nsCOMPtr<nsIDOMHTMLImageElement> imgElement(do_QueryInterface(mContextMenuNode));
|
|
if (imgElement) {
|
|
nsAutoString url;
|
|
imgElement->GetSrc(url);
|
|
|
|
NSString* urlStr = [NSString stringWith_nsAString: url];
|
|
NSString* referrer = [[mBrowserView getBrowserView] getFocusedURLString];
|
|
|
|
[self loadURL: urlStr referrer:referrer activate:YES allowPopups:NO];
|
|
}
|
|
}
|
|
|
|
- (BookmarkToolbar*) bookmarkToolbar
|
|
{
|
|
return mPersonalToolbar;
|
|
}
|
|
|
|
- (NSProgressIndicator*)progressIndicator
|
|
{
|
|
return mProgress;
|
|
}
|
|
|
|
- (void)showProgressIndicator
|
|
{
|
|
// note we do nothing to check if the progress indicator is already there.
|
|
[mProgressSuperview addSubview:mProgress];
|
|
}
|
|
|
|
- (void)hideProgressIndicator
|
|
{
|
|
[mProgress removeFromSuperview];
|
|
}
|
|
|
|
//
|
|
// - showPopupBlocked:
|
|
//
|
|
// Show/hide the image of the blocked-popup indicator
|
|
//
|
|
- (void)showPopupBlocked:(BOOL)inBlocked
|
|
{
|
|
if (inBlocked && ![mPopupBlocked window]) { // told to show, currently hidden
|
|
[mPopupBlockSuperview addSubview:mPopupBlocked];
|
|
}
|
|
else if (!inBlocked && [mPopupBlocked window]) { // told to hide, currently visible
|
|
[mPopupBlocked removeFromSuperview];
|
|
}
|
|
}
|
|
|
|
//
|
|
// buildPopupBlockerMenu:
|
|
//
|
|
// Called by the notification center right before the menu will be displayed. This
|
|
// allows us the opportunity to populate its contents from the list of sites
|
|
// in the block list.
|
|
//
|
|
- (void)buildPopupBlockerMenu:(NSNotification*)notifier
|
|
{
|
|
const long kSeparatorTag = -1;
|
|
NSPopUpButton* popup = [notifier object];
|
|
|
|
// clear out existing menu. loop until we hit our special tag
|
|
int numItemsToDelete = [popup indexOfItemWithTag:kSeparatorTag];
|
|
for ( int i = 0; i < numItemsToDelete; ++i )
|
|
[popup removeItemAtIndex:0];
|
|
|
|
// the first item will get swallowed by the popup
|
|
[popup insertItemWithTitle:@"" atIndex:0];
|
|
|
|
// fill in new menu
|
|
nsCOMPtr<nsISupportsArray> blockedSites;
|
|
[[self getBrowserWrapper] getBlockedSites:getter_AddRefs(blockedSites)];
|
|
PRUint32 siteCount = 0;
|
|
blockedSites->Count(&siteCount);
|
|
for ( PRUint32 i = 0, insertAt = 1; i < siteCount; ++i ) {
|
|
nsCOMPtr<nsISupports> genericURI = dont_AddRef(blockedSites->ElementAt(i));
|
|
nsCOMPtr<nsIURI> uri = do_QueryInterface(genericURI);
|
|
if ( uri ) {
|
|
// extract the host
|
|
nsCAutoString host;
|
|
uri->GetHost(host);
|
|
NSString* hostString = [NSString stringWithCString:host.get()];
|
|
NSString* itemTitle = [NSString stringWithFormat:NSLocalizedString(@"Unblock %@", @"Unblock %@"), hostString];
|
|
|
|
// ensure that duplicate hosts aren't inserted
|
|
if ([popup indexOfItemWithTitle:itemTitle] == -1) {
|
|
// create a new menu item and set its tag to the position in the menu so
|
|
// the action can know which site we want to unblock. Insert it at |i+1|
|
|
// because we had to pad with one item above, but set the tag to |i| because
|
|
// that's the index in the array.
|
|
[popup insertItemWithTitle:itemTitle atIndex:insertAt];
|
|
NSMenuItem* currItem = [popup itemAtIndex:insertAt];
|
|
[currItem setAction:@selector(unblockSite:)];
|
|
[currItem setTarget:self];
|
|
[currItem setTag:i];
|
|
++insertAt; // only increment insert pos if we inserted something
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// unblockSite:
|
|
//
|
|
// Called in response to an item in the unblock popup menu being selected to
|
|
// add a particular site to the popup whitelist. We assume that the tag of
|
|
// the sender is the index into the blocked sites array stores in the browser
|
|
// wrapper to get the nsURI.
|
|
//
|
|
- (IBAction)unblockSite:(id)sender
|
|
{
|
|
nsCOMPtr<nsISupportsArray> blockedSites;
|
|
[[self getBrowserWrapper] getBlockedSites:getter_AddRefs(blockedSites)];
|
|
|
|
// get the tag from the sender and use that as the index into the list
|
|
long tag = [sender tag];
|
|
if ( tag >= 0 ) {
|
|
nsCOMPtr<nsISupports> genUri = dont_AddRef(blockedSites->ElementAt(tag));
|
|
nsCOMPtr<nsIURI> uri = do_QueryInterface(genUri);
|
|
|
|
nsCOMPtr<nsIPermissionManager> pm ( do_GetService(NS_PERMISSIONMANAGER_CONTRACTID) );
|
|
pm->Add(uri, "popup", nsIPermissionManager::ALLOW_ACTION);
|
|
}
|
|
}
|
|
|
|
//
|
|
// - unblockAllSites:
|
|
//
|
|
// Called in response to the menu item from the unblock popup. Loop over all
|
|
// the items in the blocked sites array in the browser wrapper and add them
|
|
// to the whitelist.
|
|
//
|
|
- (IBAction)unblockAllSites:(id)sender
|
|
{
|
|
nsCOMPtr<nsISupportsArray> blockedSites;
|
|
[[self getBrowserWrapper] getBlockedSites:getter_AddRefs(blockedSites)];
|
|
nsCOMPtr<nsIPermissionManager> pm ( do_GetService(NS_PERMISSIONMANAGER_CONTRACTID) );
|
|
|
|
PRUint32 count = 0;
|
|
blockedSites->Count(&count);
|
|
for ( PRUint32 i = 0; i < count; ++i ) {
|
|
nsCOMPtr<nsISupports> genUri = dont_AddRef(blockedSites->ElementAt(i));
|
|
nsCOMPtr<nsIURI> uri = do_QueryInterface(genUri);
|
|
pm->Add(uri, "popup", nsIPermissionManager::ALLOW_ACTION);
|
|
}
|
|
}
|
|
|
|
// -configurePopupBlocking
|
|
//
|
|
// Show the web features pref panel where the user can do things to configure
|
|
// popup blocking
|
|
- (IBAction)configurePopupBlocking:(id)sender
|
|
{
|
|
[[NSApp delegate] displayPreferencesWindow:self];
|
|
[[[NSApp delegate] preferencesController] selectPreferencePaneByIdentifier:@"org.mozilla.chimera.preference.webfeatures"];
|
|
}
|
|
|
|
// updateLock:
|
|
//
|
|
// Sets the lock icon in the status bar to the appropriate image and updates
|
|
// the url bar display of security state appropriately.
|
|
- (void)updateLock:(unsigned int)inSecurityState
|
|
{
|
|
unsigned char securityState = inSecurityState & 0x000000FF;
|
|
switch ( securityState ) {
|
|
case nsIWebProgressListener::STATE_IS_INSECURE:
|
|
[mLock setImage:[BrowserWindowController insecureIcon]];
|
|
break;
|
|
case nsIWebProgressListener::STATE_IS_SECURE:
|
|
[mLock setImage:[BrowserWindowController secureIcon]];;
|
|
break;
|
|
case nsIWebProgressListener::STATE_IS_BROKEN:
|
|
[mLock setImage:[BrowserWindowController brokenIcon]];
|
|
break;
|
|
}
|
|
[mURLBar setSecureState:securityState];
|
|
}
|
|
|
|
+ (NSImage*) insecureIcon
|
|
{
|
|
static NSImage* sInsecureIcon = nil;
|
|
if (!sInsecureIcon)
|
|
sInsecureIcon = [[NSImage imageNamed:@"globe_ico"] retain];
|
|
return sInsecureIcon;
|
|
}
|
|
|
|
+ (NSImage*) secureIcon;
|
|
{
|
|
static NSImage* sSecureIcon = nil;
|
|
if (!sSecureIcon)
|
|
sSecureIcon = [[NSImage imageNamed:@"security_lock"] retain];
|
|
return sSecureIcon;
|
|
}
|
|
|
|
+ (NSImage*) brokenIcon;
|
|
{
|
|
static NSImage* sBrokenIcon = nil;
|
|
if (!sBrokenIcon)
|
|
sBrokenIcon = [[NSImage imageNamed:@"security_broken"] retain];
|
|
return sBrokenIcon;
|
|
}
|
|
|
|
// return the window's saved title
|
|
- (NSString *)savedTitle
|
|
{
|
|
return mSavedTitle;
|
|
}
|
|
|
|
// save the window title before showing
|
|
// bookmark manager or History manager
|
|
- (void)setSavedTitle:(NSString *)aTitle
|
|
{
|
|
[mSavedTitle autorelease];
|
|
mSavedTitle = [aTitle retain];
|
|
}
|
|
|
|
+ (NSDictionary *)searchURLDictionary
|
|
{
|
|
static NSDictionary *searchURLDictionary = nil;
|
|
if (searchURLDictionary)
|
|
return searchURLDictionary;
|
|
|
|
NSString *defaultSearchEngineList = [[NSBundle mainBundle] pathForResource:@"SearchURLList" ofType:@"plist"];
|
|
|
|
//
|
|
// We haven't read the search engine list yet attempt to read from user's profile directory
|
|
//
|
|
nsCOMPtr<nsIFile> aDir;
|
|
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(aDir));
|
|
if (aDir) {
|
|
nsCAutoString aDirPath;
|
|
nsresult rv = aDir->GetNativePath(aDirPath);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
NSString *profileDir = [NSString stringWithUTF8String:aDirPath.get()];
|
|
|
|
//
|
|
// If the file exists we read it from the profile directory
|
|
// If it doesn't we attempt to copy it there from our app bundle first
|
|
// (so that the user has something to edit in future)
|
|
//
|
|
NSString *searchEngineListPath = [profileDir stringByAppendingPathComponent:@"SearchURLList.plist"];
|
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
if ( [fileManager isReadableFileAtPath:searchEngineListPath] ||
|
|
[fileManager copyPath:defaultSearchEngineList toPath:searchEngineListPath handler:nil] )
|
|
searchURLDictionary = [[NSDictionary alloc] initWithContentsOfFile:searchEngineListPath];
|
|
else {
|
|
#if DEBUG
|
|
NSLog(@"Unable to copy search engine list to user profile directory");
|
|
#endif
|
|
}
|
|
}
|
|
else {
|
|
#if DEBUG
|
|
NSLog(@"Unable to get profile directory");
|
|
#endif
|
|
}
|
|
}
|
|
else {
|
|
#if DEBUG
|
|
NSLog(@"Unable to determine profile directory");
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// If reading from the profile directory failed for any reason
|
|
// then read the default search engine list from our application bundle directly
|
|
//
|
|
if (!searchURLDictionary)
|
|
searchURLDictionary = [[NSDictionary alloc] initWithContentsOfFile:defaultSearchEngineList];
|
|
|
|
return searchURLDictionary;
|
|
}
|
|
|
|
|
|
|
|
- (void) focusChangedFrom:(NSResponder*) oldResponder to:(NSResponder*) newResponder
|
|
{
|
|
BOOL oldResponderIsGecko = [self isResponderGeckoView:oldResponder];
|
|
BOOL newResponderIsGecko = [self isResponderGeckoView:newResponder];
|
|
|
|
if (oldResponderIsGecko != newResponderIsGecko && [[self window] isKeyWindow])
|
|
[[mBrowserView getBrowserView] setActive:newResponderIsGecko];
|
|
}
|
|
|
|
|
|
- (PageProxyIcon *)proxyIconView
|
|
{
|
|
return mProxyIcon;
|
|
}
|
|
|
|
- (BookmarkViewController *)bookmarkViewController
|
|
{
|
|
[self ensureBookmarkViewController];
|
|
return mBookmarkViewController;
|
|
}
|
|
|
|
- (id)windowWillReturnFieldEditor:(NSWindow *)aWindow toObject:(id)anObject
|
|
{
|
|
if ([anObject isEqual:mURLBar]) {
|
|
if (!mURLFieldEditor) {
|
|
mURLFieldEditor = [[AutoCompleteTextFieldEditor alloc] initWithFrame:[anObject bounds]
|
|
defaultFont:[mURLBar font]];
|
|
[mURLFieldEditor setFieldEditor:YES];
|
|
[mURLFieldEditor setAllowsUndo:YES];
|
|
}
|
|
return mURLFieldEditor;
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)sender
|
|
{
|
|
return [[BookmarkManager sharedBookmarkManager] undoManager];
|
|
}
|
|
|
|
- (IBAction)reloadWithNewCharset:(NSString*)charset
|
|
{
|
|
[mBrowserView reloadWithNewCharset:charset];
|
|
}
|
|
|
|
- (NSString*)currentCharset
|
|
{
|
|
return [mBrowserView currentCharset];
|
|
}
|
|
|
|
|
|
//
|
|
// -toggleBookmarkManager
|
|
//
|
|
// switch between a gecko content view and the in-window bookmark manager.
|
|
// This changes the current focus and forces it into the content area.
|
|
//
|
|
- (void)toggleBookmarkManager:(id)sender
|
|
{
|
|
// lazily init the setup of the view's controller
|
|
[self ensureBookmarkViewController];
|
|
|
|
// deactivate any gecko view that might think it has focus
|
|
if ([self isResponderGeckoView:[[self window] firstResponder]]) {
|
|
// inform the tab view that it will be hidden so that it can perform any necessary cleanup
|
|
[mTabBrowser setVisible:NO];
|
|
CHBrowserView* browserView = [mBrowserView getBrowserView];
|
|
if (browserView)
|
|
[browserView setActive:NO];
|
|
}
|
|
|
|
// swap out between content and bookmarks.
|
|
[mContentView setBookmarkManagerView:[mBookmarkViewController bookmarksEditingView]];
|
|
[mContentView toggleBookmarkManager:sender];
|
|
|
|
// if we're now showing the bm manager, force it to have focus,
|
|
// otherwise give focus back to gecko.
|
|
if ( [mContentView isBookmarkManagerVisible] ) {
|
|
// cancel all pending loads. safari does this, i think we should too
|
|
[self stopAllPendingLoads];
|
|
|
|
// save window title
|
|
[self setSavedTitle:[[self window] title]];
|
|
[[self window] setTitle:NSLocalizedString(@"Bookmark Manager",@"Bookmark Manager")];
|
|
[mBookmarkViewController selectLastContainer];
|
|
|
|
// set focus to appropriate area of bm manager
|
|
[mBookmarkViewController focus];
|
|
}
|
|
else {
|
|
[[self window] setTitle:[self savedTitle]];
|
|
CHBrowserView* browserView = [mBrowserView getBrowserView];
|
|
if (browserView)
|
|
[browserView setActive:YES];
|
|
// inform the tab view that it will be visible, so that it can adjust to any changes that occurred
|
|
// when it was out of the hierarchy
|
|
[mTabBrowser setVisible:YES];
|
|
}
|
|
|
|
// we have to manually update the bookmarks menu items, because we
|
|
// turn autoenabling off for that menu
|
|
[[NSApp delegate] adjustBookmarksMenuItemsEnabling:[[self window] isMainWindow]];
|
|
}
|
|
|
|
//
|
|
// - ensureBrowserVisible:
|
|
//
|
|
// Make sure that the browser is showing, not the bookmarks manager
|
|
//
|
|
- (void)ensureBrowserVisible:(id)sender
|
|
{
|
|
if ( [mContentView isBookmarkManagerVisible] )
|
|
[self toggleBookmarkManager:self];
|
|
}
|
|
|
|
//
|
|
// - handleCommandReturn:
|
|
//
|
|
// handle command-return in location or search field, opening a new tab or window as appropriate
|
|
//
|
|
- (BOOL) handleCommandReturn
|
|
{
|
|
BOOL handled = NO;
|
|
|
|
// determine whether to load in background
|
|
PRBool loadInBG;
|
|
nsCOMPtr<nsIPrefBranch> pref(do_GetService("@mozilla.org/preferences-service;1"));
|
|
pref->GetBoolPref("browser.tabs.loadInBackground", &loadInBG);
|
|
|
|
// determine whether to load in tab or window
|
|
PRBool loadInTab;
|
|
pref->GetBoolPref("browser.tabs.opentabfor.middleclick",&loadInTab);
|
|
|
|
BWCOpenDest destination = loadInTab ? kDestinationNewTab : kDestinationNewWindow;
|
|
|
|
// see if command-return came in the url bar
|
|
if ([mURLBar fieldEditor] && [[self window] firstResponder] == [mURLBar fieldEditor]) {
|
|
handled = YES;
|
|
[self goToLocationFromToolbarURLField:mURLBar inView:destination inBackground:loadInBG];
|
|
// kill any autocomplete that was in progress
|
|
[mURLBar revertText];
|
|
// set the text in the URL bar back to the current URL
|
|
[self updateLocationFields:[mBrowserView getCurrentURLSpec]];
|
|
|
|
// see if command-return came in the search field
|
|
} else if ([mSearchBar isFirstResponder]) {
|
|
handled = YES;
|
|
[self performSearch:mSearchBar inView:destination inBackground:loadInBG];
|
|
}
|
|
return handled;
|
|
}
|
|
|
|
|
|
@end
|
|
|
|
#pragma mark -
|
|
|
|
@implementation ThrobberHandler
|
|
|
|
-(id)initWithToolbarItem:(NSToolbarItem*)inButton images:(NSArray*)inImages
|
|
{
|
|
if ( (self = [super init]) ) {
|
|
mImages = [inImages retain];
|
|
mTimer = [[NSTimer scheduledTimerWithTimeInterval: 0.2
|
|
target: self selector: @selector(pulseThrobber:)
|
|
userInfo: inButton repeats: YES] retain];
|
|
mFrame = 0;
|
|
[self startThrobber];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
-(void)dealloc
|
|
{
|
|
[self stopThrobber];
|
|
[mImages release];
|
|
[super dealloc];
|
|
}
|
|
|
|
|
|
// Called by an NSTimer.
|
|
|
|
- (void)pulseThrobber:(id)aSender
|
|
{
|
|
// advance to next frame.
|
|
if (++mFrame >= [mImages count])
|
|
mFrame = 0;
|
|
NSToolbarItem* toolbarItem = (NSToolbarItem*) [aSender userInfo];
|
|
[toolbarItem setImage: [mImages objectAtIndex: mFrame]];
|
|
}
|
|
|
|
#define QUICKTIME_THROBBER 0
|
|
|
|
#if QUICKTIME_THROBBER
|
|
static Boolean movieControllerFilter(MovieController mc, short action, void *params, long refCon)
|
|
{
|
|
if (action == mcActionMovieClick || action == mcActionMouseDown) {
|
|
EventRecord* event = (EventRecord*) params;
|
|
event->what = nullEvent;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
- (void)startThrobber
|
|
{
|
|
#if QUICKTIME_THROBBER
|
|
// Use Quicktime to draw the frames from a single Animated GIF. This works fine for the animation, but
|
|
// when the frames stop, the poster frame disappears.
|
|
NSToolbarItem* throbberItem = [self throbberItem];
|
|
if (throbberItem != nil && [throbberItem view] == nil) {
|
|
NSSize minSize = [throbberItem minSize];
|
|
NSLog(@"Origin minSize = %f X %f", minSize.width, minSize.height);
|
|
NSSize maxSize = [throbberItem maxSize];
|
|
NSLog(@"Origin maxSize = %f X %f", maxSize.width, maxSize.height);
|
|
|
|
NSURL* throbberURL = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:@"throbber" ofType:@"gif"]];
|
|
NSLog(@"throbberURL = %@", throbberURL);
|
|
NSMovie* throbberMovie = [[[NSMovie alloc] initWithURL: throbberURL byReference: YES] autorelease];
|
|
NSLog(@"throbberMovie = %@", throbberMovie);
|
|
|
|
if ([throbberMovie QTMovie] != nil) {
|
|
NSMovieView* throbberView = [[[NSMovieView alloc] init] autorelease];
|
|
[throbberView setMovie: throbberMovie];
|
|
[throbberView showController: NO adjustingSize: NO];
|
|
[throbberView setLoopMode: NSQTMovieLoopingPlayback];
|
|
[throbberItem setView: throbberView];
|
|
NSSize size = NSMakeSize(32, 32);
|
|
[throbberItem setMinSize: size];
|
|
[throbberItem setMaxSize: size];
|
|
[throbberView gotoPosterFrame: self];
|
|
[throbberView start: self];
|
|
|
|
// experiment, veto mouse clicks in the movie controller by using an action filter.
|
|
MCSetActionFilterWithRefCon((MovieController) [throbberView movieController],
|
|
NewMCActionFilterWithRefConUPP(movieControllerFilter),
|
|
0);
|
|
}
|
|
}
|
|
#else
|
|
#endif
|
|
}
|
|
|
|
- (void)stopThrobber
|
|
{
|
|
#if QUICKTIME_THROBBER
|
|
// Stop the quicktime animation.
|
|
NSToolbarItem* throbberItem = [self throbberItem];
|
|
if (throbberItem != nil) {
|
|
NSMovieView* throbberView = [throbberItem view];
|
|
if ([throbberView isPlaying]) {
|
|
[throbberView stop: self];
|
|
[throbberView gotoPosterFrame: self];
|
|
} else {
|
|
[throbberView start: self];
|
|
}
|
|
}
|
|
#else
|
|
if (mTimer) {
|
|
[mTimer invalidate];
|
|
[mTimer release];
|
|
mTimer = nil;
|
|
|
|
mFrame = 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
@end
|