/* -*- 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 #include #import #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 globalHist = do_GetService("@mozilla.org/browser/global-history;2"); mGlobalHistory = globalHist; if ( mGlobalHistory ) NS_ADDREF(mGlobalHistory); nsCOMPtr 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 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 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 pref(do_GetService("@mozilla.org/preferences-service;1")); pref->GetBoolPref("browser.tabs.loadInBackground", &loadInBackground); nsCOMPtr 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 entry(do_QueryInterface(desc)); if (entry) { nsCOMPtr 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 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 webBrowser = getter_AddRefs([view getWebBrowser]); if (!webBrowser) return nsnull; nsCOMPtr 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 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 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 ownerDoc; mContextMenuNode->GetOwnerDocument(getter_AddRefs(ownerDoc)); nsCOMPtr nsDoc = do_QueryInterface(ownerDoc); if (!nsDoc) return @""; nsCOMPtr 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 or