3671 lines
128 KiB
Plaintext
3671 lines
128 KiB
Plaintext
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is 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 MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#import <AddressBook/AddressBook.h>
|
|
#import "ABAddressBook+Utils.h"
|
|
|
|
#import "NSString+Utils.h"
|
|
|
|
#import "BrowserWindowController.h"
|
|
#import "BrowserWindow.h"
|
|
|
|
#import "BookmarkToolbar.h"
|
|
#import "BookmarkViewController.h"
|
|
#import "BookmarkManager.h"
|
|
#import "AddBookmarkDialogController.h"
|
|
#import "ProgressDlgController.h"
|
|
|
|
#import "BrowserContentViews.h"
|
|
#import "BrowserWrapper.h"
|
|
#import "PreferenceManager.h"
|
|
#import "BrowserTabView.h"
|
|
#import "BrowserTabViewItem.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"
|
|
#import "MVPreferencesController.h"
|
|
#import "wallet.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 "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 "nsIPref.h"
|
|
|
|
#include "nsIClipboardCommands.h"
|
|
#include "nsICommandManager.h"
|
|
#include "nsICommandParams.h"
|
|
#include "nsIContentViewerEdit.h"
|
|
#include "nsIWebBrowser.h"
|
|
#include "nsIInterfaceRequestorUtils.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 "nsIDOMHTMLEmbedElement.h"
|
|
#include "nsIDOMHTMLObjectElement.h"
|
|
#include "nsIDOMHTMLAppletElement.h"
|
|
#include "nsIFocusController.h"
|
|
|
|
|
|
#include "nsAppDirectoryServiceDefs.h"
|
|
|
|
static NSString* const BrowserToolbarIdentifier = @"Browser Window Toolbar";
|
|
static NSString* const BackToolbarItemIdentifier = @"Back Toolbar Item";
|
|
static NSString* const ForwardToolbarItemIdentifier = @"Forward Toolbar Item";
|
|
static NSString* const ReloadToolbarItemIdentifier = @"Reload Toolbar Item";
|
|
static NSString* const StopToolbarItemIdentifier = @"Stop Toolbar Item";
|
|
static NSString* const HomeToolbarItemIdentifier = @"Home Toolbar Item";
|
|
static NSString* const LocationToolbarItemIdentifier = @"Location Toolbar Item";
|
|
static NSString* const BookmarksToolbarItemIdentifier = @"Sidebar Toolbar Item"; // note legacy name
|
|
static NSString* const PrintToolbarItemIdentifier = @"Print Toolbar Item";
|
|
static NSString* const ThrobberToolbarItemIdentifier = @"Throbber Toolbar Item";
|
|
static NSString* const SearchToolbarItemIdentifier = @"Search Toolbar Item";
|
|
static NSString* const ViewSourceToolbarItemIdentifier = @"View Source Toolbar Item";
|
|
static NSString* const BookmarkToolbarItemIdentifier = @"Bookmark Toolbar Item";
|
|
static NSString* const TextBiggerToolbarItemIdentifier = @"Text Bigger Toolbar Item";
|
|
static NSString* const TextSmallerToolbarItemIdentifier = @"Text Smaller Toolbar Item";
|
|
static NSString* const NewTabToolbarItemIdentifier = @"New Tab Toolbar Item";
|
|
static NSString* const CloseTabToolbarItemIdentifier = @"Close Tab Toolbar Item";
|
|
static NSString* const SendURLToolbarItemIdentifier = @"Send URL Toolbar Item";
|
|
static NSString* const DLManagerToolbarItemIdentifier = @"Download Manager Toolbar Item";
|
|
static NSString* const FormFillToolbarItemIdentifier = @"Form Fill Toolbar Item";
|
|
static NSString* const HistoryToolbarItemIdentifier = @"History Toolbar Item";
|
|
|
|
int TabBarVisiblePrefChangedCallback(const char* pref, void* data);
|
|
static const char* const gTabBarVisiblePref = "camino.tab_bar_always_visible";
|
|
|
|
|
|
static NSString* const NavigatorWindowFrameSaveName = @"NavigatorWindow";
|
|
|
|
// Cached toolbar defaults read in from a plist. If null, we'll use
|
|
// hardcoded defaults.
|
|
static NSArray* sToolbarDefaults = nil;
|
|
|
|
#pragma mark -
|
|
|
|
// small class that owns C++ objects in behalf of BrowserWindowController.
|
|
// this just allows us to use nsCOMPtr rather than doing manual refcounting.
|
|
class BWCDataOwner
|
|
{
|
|
public:
|
|
|
|
BWCDataOwner()
|
|
: mContextMenuFlags(0)
|
|
{
|
|
mGlobalHistory = do_GetService("@mozilla.org/browser/global-history;2");
|
|
mURIFixer = do_GetService("@mozilla.org/docshell/urifixup;1");
|
|
}
|
|
|
|
nsCOMPtr<nsIURIFixup> mURIFixer;
|
|
nsCOMPtr<nsIBrowserHistory> mGlobalHistory;
|
|
|
|
int mContextMenuFlags;
|
|
nsCOMPtr<nsIDOMEvent> mContextMenuEvent;
|
|
nsCOMPtr<nsIDOMNode> mContextMenuNode;
|
|
};
|
|
|
|
|
|
#pragma mark -
|
|
|
|
// This little class exists so that we can clear up the context menu-related
|
|
// pointers in the mDataOwner at autorelease time. See the comments in -onShowContextMenu:
|
|
@interface ContextMenuDataClearer : NSObject
|
|
{
|
|
id mTarget; // retained
|
|
SEL mSelector;
|
|
}
|
|
|
|
- (id)initWithTarget:(id)inTarget selector:(SEL)inSelector;
|
|
|
|
@end
|
|
|
|
@implementation ContextMenuDataClearer
|
|
|
|
- (id)initWithTarget:(id)inTarget selector:(SEL)inSelector
|
|
{
|
|
if ((self = [super init]))
|
|
{
|
|
mTarget = [inTarget retain];
|
|
mSelector = inSelector;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
-(void)dealloc
|
|
{
|
|
[mTarget performSelector:mSelector]; // do our work
|
|
[mTarget release];
|
|
[super dealloc];
|
|
}
|
|
|
|
@end // ContextMenuDataClearer
|
|
|
|
#pragma mark -
|
|
|
|
//////////////////////////////////////
|
|
@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 -
|
|
|
|
enum BWCOpenDest {
|
|
kDestinationNewWindow = 0,
|
|
kDestinationNewTab,
|
|
kDestinationCurrentView
|
|
};
|
|
|
|
@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;
|
|
- (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;
|
|
|
|
- (BrowserTabViewItem*)tabForBrowser:(BrowserWrapper*)inWrapper;
|
|
- (BookmarkViewController*)bookmarkViewControllerForCurrentTab;
|
|
- (void)bookmarkableTitle:(NSString **)outTitle URL:(NSString**)outURLString forWrapper:(BrowserWrapper*)inWrapper;
|
|
|
|
- (void)clearContextMenuTarget;
|
|
|
|
// create back/forward session history menus on toolbar button
|
|
- (IBAction)backMenu:(id)inSender;
|
|
- (IBAction)forwardMenu:(id)inSender;
|
|
|
|
@end
|
|
|
|
#pragma mark -
|
|
|
|
@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;
|
|
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];
|
|
|
|
mDataOwner = new BWCDataOwner();
|
|
}
|
|
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 0
|
|
// the widget code (via -viewsWindowDidBecomeKey) takes care
|
|
// of sending focus and activate events to gecko
|
|
// on window activation, so no need to do this here:
|
|
if ([self isResponderGeckoView:[[self window] firstResponder]])
|
|
[mBrowserView setBrowserActive:YES];
|
|
#endif
|
|
}
|
|
|
|
- (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 0
|
|
// the widget code (via -viewsWindowDidResignKey) takes care
|
|
// of sending lost-focus and deactivate events to gecko
|
|
// on window activation, so no need to do this here:
|
|
if ([self isResponderGeckoView:[[self window] firstResponder]])
|
|
[mBrowserView setBrowserActive:NO];
|
|
#endif
|
|
}
|
|
|
|
- (void)windowDidBecomeMain:(NSNotification *)notification
|
|
{
|
|
// MainController listens for window layering notifications and updates bookmarks,
|
|
// so we don't need to do anything here
|
|
}
|
|
|
|
- (void)windowDidResignMain:(NSNotification *)notification
|
|
{
|
|
// MainController listens for window layering notifications and updates bookmarks,
|
|
// so we don't need to do anything here
|
|
}
|
|
|
|
-(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;
|
|
|
|
[self autosaveWindowFrame];
|
|
|
|
// ensure that the URL auto-complete popup is closed before the mork
|
|
// database is shut down, or we crash
|
|
[mURLBar clearResults];
|
|
|
|
if (mDataOwner)
|
|
{
|
|
nsCOMPtr<nsIHistoryItems> history(do_QueryInterface(mDataOwner->mGlobalHistory));
|
|
if (history)
|
|
history->Flush();
|
|
}
|
|
|
|
delete mDataOwner;
|
|
mDataOwner = NULL;
|
|
|
|
nsCOMPtr<nsIPref> pref(do_GetService(NS_PREF_CONTRACTID));
|
|
if ( pref )
|
|
pref->UnregisterCallback(gTabBarVisiblePref, TabBarVisiblePrefChangedCallback, self);
|
|
|
|
// Tell the BrowserTabView the window is closed
|
|
[mTabBrowser windowClosed];
|
|
|
|
[[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];
|
|
|
|
delete mDataOwner; // paranoia; should have been deleted in -windowWillClose
|
|
|
|
[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
|
|
// XXX we should just hide it and allow the user to show it again
|
|
[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;
|
|
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];
|
|
BOOL haveSavedFrame = [[self window] setFrameUsingName: NavigatorWindowFrameSaveName];
|
|
if (!haveSavedFrame)
|
|
{
|
|
NSRect mainScreenBounds = [[NSScreen mainScreen] visibleFrame];
|
|
NSRect windowBounds = NSInsetRect(mainScreenBounds, 4.0f, 4.0f);
|
|
const float kDefaultWindowWidth = 800.0f;
|
|
if (NSWidth(windowBounds) > kDefaultWindowWidth)
|
|
windowBounds.size.width = kDefaultWindowWidth;
|
|
[[self window] setFrame:windowBounds display:YES];
|
|
}
|
|
|
|
if (NSEqualSizes(oldFrame.size, [[self window] frame].size))
|
|
mustResizeChrome = YES;
|
|
|
|
mInitialized = YES;
|
|
|
|
[[self window] setAcceptsMouseMovedEvents: YES];
|
|
|
|
[self setupToolbar];
|
|
|
|
// set up autohide behavior on tab browser and register for changes on that pref. The
|
|
// default is for it to hide when only 1 tab is visible, so if no pref is found, it will
|
|
// be NO, and that works. However, if any of the JS chrome flags are set, we don't want
|
|
// to let the tab bar show so leave it off and don't register for the pref updates.
|
|
BOOL allowTabBar = YES;
|
|
if (mChromeMask && (!(mChromeMask & nsIWebBrowserChrome::CHROME_STATUSBAR) ||
|
|
!(mChromeMask & nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR)))
|
|
allowTabBar = NO;
|
|
if (allowTabBar) {
|
|
BOOL tabBarAlwaysVisible = [[PreferenceManager sharedInstance] getBooleanPref:gTabBarVisiblePref withSuccess:nil];
|
|
[mTabBrowser setBarAlwaysVisible:tabBarAlwaysVisible];
|
|
nsCOMPtr<nsIPref> pref(do_GetService(NS_PREF_CONTRACTID));
|
|
if (pref)
|
|
pref->RegisterCallback(gTabBarVisiblePref, TabBarVisiblePrefChangedCallback, self);
|
|
}
|
|
|
|
// remove the dummy tab view
|
|
[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;
|
|
}
|
|
|
|
[mPersonalToolbar buildButtonList];
|
|
|
|
BOOL chromeHidesToolbar = (mChromeMask != 0) && !(mChromeMask & nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR);
|
|
if (chromeHidesToolbar || ![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 = 22;
|
|
|
|
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];
|
|
}
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(newTab:)
|
|
name:kTabBarBackgroundDoubleClickedNotification object:mTabBrowser];
|
|
|
|
}
|
|
|
|
- (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.45];
|
|
[button setCell:newCell];
|
|
|
|
[button setBezelStyle: NSRegularSquareBezelStyle];
|
|
[button setButtonType: NSMomentaryChangeButton];
|
|
[button setBordered: NO];
|
|
[button setImagePosition: NSImageOnly];
|
|
}
|
|
return button;
|
|
}
|
|
|
|
- (void)setupToolbar
|
|
{
|
|
NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier:BrowserToolbarIdentifier] autorelease];
|
|
|
|
[toolbar setDisplayMode:NSToolbarDisplayModeDefault];
|
|
[toolbar setAllowsUserCustomization:YES];
|
|
[toolbar setAutosavesConfiguration:YES];
|
|
[toolbar setDelegate:self];
|
|
[[self window] setToolbar:toolbar];
|
|
|
|
// for a chromed window without the toolbar or locationbar flag, hide the toolbar (but allow the user to show it)
|
|
if (mChromeMask && (!(mChromeMask & nsIWebBrowserChrome::CHROME_TOOLBAR) &&
|
|
!(mChromeMask & nsIWebBrowserChrome::CHROME_LOCATIONBAR)))
|
|
{
|
|
[toolbar setAutosavesConfiguration:NO]; // make sure this hiding doesn't get saved
|
|
[toolbar setVisible:NO];
|
|
}
|
|
}
|
|
|
|
// 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:BookmarksToolbarItemIdentifier] )
|
|
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:BookmarksToolbarItemIdentifier] )
|
|
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,
|
|
BookmarksToolbarItemIdentifier,
|
|
ThrobberToolbarItemIdentifier,
|
|
SearchToolbarItemIdentifier,
|
|
PrintToolbarItemIdentifier,
|
|
ViewSourceToolbarItemIdentifier,
|
|
BookmarkToolbarItemIdentifier,
|
|
NewTabToolbarItemIdentifier,
|
|
CloseTabToolbarItemIdentifier,
|
|
TextBiggerToolbarItemIdentifier,
|
|
TextSmallerToolbarItemIdentifier,
|
|
SendURLToolbarItemIdentifier,
|
|
NSToolbarCustomizeToolbarItemIdentifier,
|
|
NSToolbarFlexibleSpaceItemIdentifier,
|
|
NSToolbarSpaceItemIdentifier,
|
|
NSToolbarSeparatorItemIdentifier,
|
|
DLManagerToolbarItemIdentifier,
|
|
FormFillToolbarItemIdentifier,
|
|
HistoryToolbarItemIdentifier,
|
|
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,
|
|
BookmarksToolbarItemIdentifier,
|
|
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:BookmarksToolbarItemIdentifier]) {
|
|
[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(manageBookmarks:)];
|
|
}
|
|
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(addBookmark:)];
|
|
}
|
|
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 if ([itemIdent isEqual:FormFillToolbarItemIdentifier]) {
|
|
[toolbarItem setLabel:NSLocalizedString(@"Fill Form", nil)];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"Fill Form", nil)];
|
|
[toolbarItem setToolTip:NSLocalizedString(@"FillFormToolTip", nil)];
|
|
[toolbarItem setImage:[NSImage imageNamed:@"autofill"]];
|
|
[toolbarItem setTarget:self];
|
|
[toolbarItem setAction:@selector(fillForm:)];
|
|
}
|
|
else if ([itemIdent isEqual:HistoryToolbarItemIdentifier]) {
|
|
[toolbarItem setLabel:NSLocalizedString(@"ShowHistory", nil)];
|
|
[toolbarItem setPaletteLabel:NSLocalizedString(@"ShowHistory", nil)];
|
|
[toolbarItem setToolTip:NSLocalizedString(@"ShowHistoryToolTip", nil)];
|
|
[toolbarItem setImage:[NSImage imageNamed:@"history"]];
|
|
[toolbarItem setTarget:self];
|
|
[toolbarItem setAction:@selector(manageHistory:)];
|
|
}
|
|
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 = [[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.
|
|
[theItem setEnabled:enable];
|
|
return enable;
|
|
}
|
|
else if (action == @selector(manageBookmarks:)) {
|
|
BOOL enable = [[mBrowserView getBrowserView] canGoBack];
|
|
if (!enable && ![self bookmarkManagerIsVisible])
|
|
enable = true;
|
|
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];
|
|
[theItem setEnabled:enable];
|
|
return enable;
|
|
}
|
|
else if (action == @selector(reload:))
|
|
return (![mBrowserView isBusy] && ![self bookmarkManagerIsVisible]);
|
|
else if (action == @selector(stop:))
|
|
return [mBrowserView isBusy];
|
|
else if (action == @selector(addBookmark:))
|
|
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] getCurrentURI];
|
|
return ![MainController isBlankURL:curURL];
|
|
}
|
|
else if (action == @selector(viewSource:))
|
|
return ![self bookmarkManagerIsVisible];
|
|
else
|
|
return YES;
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
|
|
-(BOOL)validateMenuItem: (NSMenuItem*)aMenuItem
|
|
{
|
|
SEL action = [aMenuItem action];
|
|
|
|
if (action == @selector(moveTabToNewWindow:) ||
|
|
action == @selector(closeCurrentTab:) ||
|
|
action == @selector(closeSendersTab:) ||
|
|
action == @selector(closeOtherTabs:))
|
|
return ([mTabBrowser numberOfTabViewItems] > 1);
|
|
|
|
return YES;
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
// BrowserUIDelegate methods (called from the frontmost tab's BrowserWrapper)
|
|
|
|
|
|
- (void)loadingStarted
|
|
{
|
|
}
|
|
|
|
- (void)loadingDone:(BOOL)activateContent
|
|
{
|
|
if (activateContent)
|
|
{
|
|
// if we're the front/key window, focus the content area. If we're not,
|
|
// set gecko as the first responder so that it will be activated when
|
|
// the window is focused. If the user is typing in the urlBar, however,
|
|
// don't mess with the focus at all.
|
|
if ([[self window] isKeyWindow])
|
|
{
|
|
if (![self userChangedLocationField])
|
|
[mBrowserView setBrowserActive:YES];
|
|
}
|
|
else
|
|
[[self window] makeFirstResponder:[mBrowserView getBrowserView]];
|
|
}
|
|
}
|
|
|
|
- (void)setLoadingActive:(BOOL)active
|
|
{
|
|
if (active)
|
|
{
|
|
[self startThrobber];
|
|
[mProgress setIndeterminate:YES];
|
|
[self showProgressIndicator];
|
|
[mProgress startAnimation:self];
|
|
}
|
|
else
|
|
{
|
|
[self stopThrobber];
|
|
[mProgress stopAnimation:self];
|
|
[self hideProgressIndicator];
|
|
[mProgress setIndeterminate:YES];
|
|
}
|
|
}
|
|
|
|
- (void)setLoadingProgress:(float)progress
|
|
{
|
|
if (progress > 0.0f)
|
|
{
|
|
[mProgress setIndeterminate:NO];
|
|
[mProgress setDoubleValue:progress];
|
|
}
|
|
else
|
|
{
|
|
[mProgress setIndeterminate:YES];
|
|
[mProgress startAnimation:self];
|
|
}
|
|
}
|
|
|
|
- (void)updateWindowTitle:(NSString*)title
|
|
{
|
|
[[self window] setTitle:title];
|
|
}
|
|
|
|
- (void)updateStatus:(NSString*)status
|
|
{
|
|
if (![[mStatus stringValue] isEqualToString:status])
|
|
[mStatus setStringValue:status];
|
|
}
|
|
|
|
- (void)updateLocationFields:(NSString*)url ignoreTyping:(BOOL)ignoreTyping
|
|
{
|
|
if (!ignoreTyping && [self userChangedLocationField])
|
|
return;
|
|
|
|
if ([url isEqual:@"about:blank"])
|
|
url = @""; // return;
|
|
|
|
[mURLBar setURI:url];
|
|
[mLocationSheetURLField setStringValue:url];
|
|
|
|
// 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*)icon ignoreTyping:(BOOL)ignoreTyping
|
|
{
|
|
if (!ignoreTyping && [self userChangedLocationField])
|
|
return;
|
|
|
|
if (icon == nil)
|
|
icon = [NSImage imageNamed:@"globe_ico"];
|
|
[mProxyIcon setImage:icon];
|
|
}
|
|
|
|
- (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];
|
|
}
|
|
}
|
|
|
|
- (void)showSecurityState:(unsigned long)state
|
|
{
|
|
[self updateLock:state];
|
|
}
|
|
|
|
- (BOOL)userChangedLocationField
|
|
{
|
|
return [mURLBar userHasTyped];
|
|
}
|
|
|
|
- (void)contentViewChangedTo:(NSView*)inView forURL:(NSString*)inURL
|
|
{
|
|
// update bookmarks menu
|
|
[[NSApp delegate] adjustBookmarksMenuItemsEnabling];
|
|
}
|
|
|
|
- (void)updateFromFrontmostTab
|
|
{
|
|
[[self window] setTitle: [mBrowserView windowTitle]];
|
|
[self setLoadingActive: [mBrowserView isBusy]];
|
|
[self setLoadingProgress: [mBrowserView loadingProgress]];
|
|
[self showPopupBlocked: [mBrowserView popupsBlocked]];
|
|
[self showSecurityState: [mBrowserView securityState]];
|
|
[self updateSiteIcons: [mBrowserView siteIcon] ignoreTyping:NO];
|
|
[self updateStatus: [mBrowserView statusString]];
|
|
[self updateLocationFields:[mBrowserView location] ignoreTyping:NO];
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (BrowserTabViewItem*)tabForBrowser:(BrowserWrapper*)inWrapper
|
|
{
|
|
NSEnumerator* tabsEnum = [[mTabBrowser tabViewItems] objectEnumerator];
|
|
id curTabItem;
|
|
while ((curTabItem = [tabsEnum nextObject]))
|
|
{
|
|
if ([curTabItem isKindOfClass:[BrowserTabViewItem class]] && ([(BrowserTabViewItem*)curTabItem view] == inWrapper))
|
|
return curTabItem;
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
- (BookmarkViewController*)bookmarkViewControllerForCurrentTab
|
|
{
|
|
id viewProvider = [mBrowserView contentViewProviderForURL:@"about:bookmarks"];
|
|
if ([viewProvider isKindOfClass:[BookmarkViewController class]])
|
|
return (BookmarkViewController*)viewProvider;
|
|
return nil;
|
|
}
|
|
|
|
// this gets the previous entry in session history if bookmarks are showing
|
|
- (void)bookmarkableTitle:(NSString **)outTitle URL:(NSString**)outURLString forWrapper:(BrowserWrapper*)inWrapper
|
|
{
|
|
*outTitle = nil;
|
|
*outURLString = nil;
|
|
|
|
NSString* curTitle = nil;
|
|
NSString* curURL = nil;
|
|
[inWrapper getTitle:&curTitle andHref:&curURL];
|
|
|
|
// if we're currently showing history or bookmarks, hand back the last URL.
|
|
if ([[curURL lowercaseString] isEqualToString:@"about:bookmarks"] ||
|
|
[[curURL lowercaseString] isEqualToString:@"about:history"])
|
|
{
|
|
nsCOMPtr<nsIWebBrowser> webBrowser = getter_AddRefs([[inWrapper getBrowserView] getWebBrowser]);
|
|
if (webBrowser)
|
|
{
|
|
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(webBrowser));
|
|
|
|
nsCOMPtr<nsISHistory> sessionHistory;
|
|
webNav->GetSessionHistory(getter_AddRefs(sessionHistory));
|
|
if (sessionHistory)
|
|
{
|
|
PRInt32 curEntryIndex;
|
|
sessionHistory->GetIndex(&curEntryIndex);
|
|
if (curEntryIndex > 0)
|
|
{
|
|
nsCOMPtr<nsIHistoryEntry> entry;
|
|
sessionHistory->GetEntryAtIndex(curEntryIndex - 1, PR_FALSE, getter_AddRefs(entry));
|
|
|
|
nsCAutoString uriSpec;
|
|
nsCOMPtr<nsIURI> entryURI;
|
|
entry->GetURI(getter_AddRefs(entryURI));
|
|
if (entryURI)
|
|
entryURI->GetSpec(uriSpec);
|
|
|
|
nsXPIDLString textStr;
|
|
entry->GetTitle(getter_Copies(textStr));
|
|
|
|
curTitle = [NSString stringWith_nsAString:textStr];
|
|
curURL = [NSString stringWithUTF8String:uriSpec.get()];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*outTitle = curTitle;
|
|
*outURLString = curURL;
|
|
}
|
|
|
|
- (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 setBrowserActive:NO];
|
|
[mURLBar selectText:self];
|
|
}
|
|
|
|
- (void)beginLocationSheet
|
|
{
|
|
[mLocationSheetURLField setStringValue:[mURLBar stringValue]];
|
|
[mLocationSheetURLField selectText:nil];
|
|
|
|
[NSApp beginSheet: mLocationSheetWindow
|
|
modalForWindow: [self window]
|
|
modalDelegate: nil
|
|
didEndSelector: nil
|
|
contextInfo: nil];
|
|
}
|
|
|
|
- (IBAction)endLocationSheet:(id)sender
|
|
{
|
|
[mLocationSheetWindow close]; // assumes it's not released on close
|
|
[NSApp endSheet:mLocationSheetWindow returnCode:1];
|
|
[self goToLocationFromToolbarURLField:mLocationSheetURLField];
|
|
}
|
|
|
|
- (IBAction)cancelLocationSheet:(id)sender
|
|
{
|
|
[mLocationSheetWindow close]; // assumes it's not released on close
|
|
[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 setBrowserActive: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];
|
|
}
|
|
|
|
//
|
|
// - manageBookmarks:
|
|
//
|
|
// Load the bookmarks in the frontmost tab or window.
|
|
//
|
|
-(IBAction)manageBookmarks:(id)aSender
|
|
{
|
|
if ([self bookmarkManagerIsVisible])
|
|
[self back:aSender];
|
|
else
|
|
[self loadURL:@"about:bookmarks" referrer:nil activate:YES allowPopups:NO];
|
|
|
|
[[NSApp delegate] adjustBookmarksMenuItemsEnabling];
|
|
}
|
|
|
|
//
|
|
// -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
|
|
{
|
|
[self loadURL:@"about:history" referrer:nil activate:YES allowPopups:YES];
|
|
|
|
// aSender could be a history menu item with a represented object of
|
|
// an item that we wish to reveal. However, it belongs to a different
|
|
// data source than the one we just created. need a way to find the one
|
|
// to reveal...
|
|
}
|
|
|
|
- (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];
|
|
|
|
if ([theURL length] == 0)
|
|
{
|
|
// re-focus the url bar if it's visible (might be in sheet?)
|
|
if ([inURLField window] == [self window])
|
|
[[self window] makeFirstResponder:inURLField];
|
|
|
|
return;
|
|
}
|
|
|
|
// 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 tabOpenPolicy:eAppendTabs allowPopups:NO];
|
|
else
|
|
[self openURLArray:resolvedURLs tabOpenPolicy:eReplaceTabs 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] &&
|
|
mDataOwner &&
|
|
mDataOwner->mGlobalHistory &&
|
|
mDataOwner->mURIFixer && [theURL length] > 0)
|
|
{
|
|
nsAutoString url;
|
|
[theURL assignTo_nsAString:url];
|
|
NS_ConvertUCS2toUTF8 utf8URL(url);
|
|
|
|
nsCOMPtr<nsIURI> fixedURI;
|
|
mDataOwner->mURIFixer->CreateFixupURI(utf8URL, 0, getter_AddRefs(fixedURI));
|
|
if (fixedURI)
|
|
mDataOwner->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
|
|
BOOL loadInBackground = [[PreferenceManager sharedInstance] getBooleanPref:"browser.tabs.loadInBackground" withSuccess:NULL];
|
|
|
|
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] getCurrentURI];
|
|
[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] getCurrentURI];
|
|
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] getCurrentURI] UTF8String];
|
|
|
|
// 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);
|
|
}
|
|
|
|
- (IBAction)sendURLFromLink:(id)aSender
|
|
{
|
|
if (!mDataOwner->mContextMenuNode)
|
|
return;
|
|
|
|
nsCOMPtr<nsIDOMElement> linkContent;
|
|
nsAutoString href;
|
|
GeckoUtils::GetEnclosingLinkElementAndHref(mDataOwner->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* urlString = [NSString stringWith_nsAString: href];
|
|
|
|
// 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 escapedURL = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, urlUTF8String, NULL, CFSTR("&?="), kCFStringEncodingUTF8);
|
|
|
|
NSString* mailtoURLString = [NSString stringWithFormat:@"mailto:?body=%@", (NSString*)escapedURL];
|
|
|
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:mailtoURLString]];
|
|
|
|
CFRelease(urlUTF8String);
|
|
CFRelease(escapedURL);
|
|
}
|
|
|
|
- (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;
|
|
NSToolbarItem* throbberItem = [self throbberItem];
|
|
if (throbberItem)
|
|
[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];
|
|
}
|
|
|
|
- (BOOL)bookmarkManagerIsVisible
|
|
{
|
|
NSString* currentURL = [[[self getBrowserWrapper] getCurrentURI] lowercaseString];
|
|
return [currentURL isEqualToString:@"about:bookmarks"] || [currentURL isEqualToString:@"about:history"];
|
|
}
|
|
|
|
- (BOOL)canHideBookmarks
|
|
{
|
|
return [self bookmarkManagerIsVisible] && [[mBrowserView getBrowserView] canGoBack];
|
|
}
|
|
|
|
- (BOOL)singleBookmarkIsSelected
|
|
{
|
|
if (![self bookmarkManagerIsVisible])
|
|
return NO;
|
|
|
|
BookmarkViewController* bookmarksController = [self bookmarkViewControllerForCurrentTab];
|
|
return ([bookmarksController numberOfSelectedRows] == 1);
|
|
}
|
|
|
|
- (IBAction)addBookmark:(id)aSender
|
|
{
|
|
int numTabs = [mTabBrowser numberOfTabViewItems];
|
|
NSMutableArray* itemsArray = [NSMutableArray arrayWithCapacity:numTabs];
|
|
for (int i = 0; i < numTabs; i++)
|
|
{
|
|
BrowserWrapper* browserWrapper = (BrowserWrapper*)[[mTabBrowser tabViewItemAtIndex:i] view];
|
|
NSString* curTitleString = nil;
|
|
NSString* hrefString = nil;
|
|
[self bookmarkableTitle:&curTitleString URL:&hrefString forWrapper:browserWrapper];
|
|
|
|
NSMutableDictionary* itemInfo = [NSMutableDictionary dictionaryWithObject:hrefString forKey:kAddBookmarkItemURLKey];
|
|
|
|
// title can be nil (e.g. for text files)
|
|
if (curTitleString)
|
|
[itemInfo setObject:curTitleString forKey:kAddBookmarkItemTitleKey];
|
|
|
|
if (browserWrapper == mBrowserView)
|
|
[itemInfo setObject:[NSNumber numberWithBool:YES] forKey:kAddBookmarkItemPrimaryTabKey];
|
|
|
|
[itemsArray addObject:itemInfo];
|
|
}
|
|
|
|
[[AddBookmarkDialogController sharedAddBookmarkDialogController] showDialogWithLocationsAndTitles:itemsArray isFolder:NO onWindow:[self window]];
|
|
}
|
|
|
|
- (IBAction)addBookmarkForLink:(id)aSender
|
|
{
|
|
if (!mDataOwner->mContextMenuNode)
|
|
return;
|
|
|
|
nsCOMPtr<nsIDOMElement> linkContent;
|
|
nsAutoString href;
|
|
GeckoUtils::GetEnclosingLinkElementAndHref(mDataOwner->mContextMenuNode, getter_AddRefs(linkContent), href);
|
|
nsAutoString linkText;
|
|
GeckoUtils::GatherTextUnder(linkContent, linkText);
|
|
NSString* urlStr = [NSString stringWith_nsAString:href];
|
|
NSString* titleStr = [NSString stringWith_nsAString:linkText];
|
|
|
|
NSDictionary* itemInfo = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
titleStr, kAddBookmarkItemTitleKey,
|
|
urlStr, kAddBookmarkItemURLKey,
|
|
nil];
|
|
NSArray* items = [NSArray arrayWithObject:itemInfo];
|
|
[[AddBookmarkDialogController sharedAddBookmarkDialogController] showDialogWithLocationsAndTitles:items isFolder:NO onWindow:[self window]];
|
|
}
|
|
|
|
- (IBAction)addBookmarkFolder:(id)aSender
|
|
{
|
|
if ([self bookmarkManagerIsVisible])
|
|
{
|
|
// if the bookmarks view controller is visible, delegate to it (so that it can use the
|
|
// selection to set the parent folder)
|
|
BookmarkViewController* bookmarksController = [self bookmarkViewControllerForCurrentTab];
|
|
[bookmarksController addBookmarkFolder:aSender];
|
|
}
|
|
|
|
[[AddBookmarkDialogController sharedAddBookmarkDialogController] showDialogWithLocationsAndTitles:nil isFolder:YES onWindow:[self window]];
|
|
}
|
|
|
|
- (IBAction)addBookmarkSeparator:(id)aSender
|
|
{
|
|
BookmarkViewController* bookmarksController = [self bookmarkViewControllerForCurrentTab];
|
|
[bookmarksController addBookmarkSeparator:aSender];
|
|
}
|
|
|
|
//
|
|
// -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
|
|
{
|
|
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
|
|
{
|
|
[[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 (!mDataOwner->mContextMenuNode) return @"";
|
|
|
|
nsCOMPtr<nsIDOMDocument> ownerDoc;
|
|
mDataOwner->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];
|
|
}
|
|
|
|
// 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];
|
|
}
|
|
|
|
//
|
|
// -focusedElement
|
|
//
|
|
// Returns the currently focused DOM element in the currently visible tab
|
|
//
|
|
- (void)focusedElement:(nsIDOMElement**)outElement
|
|
{
|
|
#define ENSURE_TRUE(x) if (!x) return;
|
|
if (!outElement)
|
|
return;
|
|
*outElement = nsnull;
|
|
|
|
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));
|
|
*outElement = focusedItem.get();
|
|
NS_IF_ADDREF(*outElement);
|
|
|
|
#undef ENSURE_TRUE
|
|
}
|
|
|
|
//
|
|
// -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
|
|
{
|
|
BOOL isFocused = NO;
|
|
|
|
nsCOMPtr<nsIDOMElement> focusedItem;
|
|
[self focusedElement: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;
|
|
}
|
|
|
|
//
|
|
// -isPagePluginFocused
|
|
//
|
|
// Determine if a plugin/applet in the content area has focus. Returns YES if the
|
|
// focus is in a <embed>, <object>, or <applet>
|
|
//
|
|
- (BOOL)isPagePluginFocused
|
|
{
|
|
BOOL isFocused = NO;
|
|
|
|
nsCOMPtr<nsIDOMElement> focusedItem;
|
|
[self focusedElement:getter_AddRefs(focusedItem)];
|
|
|
|
// we got it, now check if it's what we care about
|
|
nsCOMPtr<nsIDOMHTMLEmbedElement> embed = do_QueryInterface(focusedItem);
|
|
nsCOMPtr<nsIDOMHTMLObjectElement> object = do_QueryInterface(focusedItem);
|
|
nsCOMPtr<nsIDOMHTMLAppletElement> applet = do_QueryInterface(focusedItem);
|
|
if (embed || object || applet)
|
|
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] || [self isPagePluginFocused])
|
|
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;
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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)willShowPromptForBrowser:(BrowserWrapper*)inBrowser
|
|
{
|
|
// bring the tab to the front (for security reasons)
|
|
BrowserTabViewItem* tabItem = [self tabForBrowser:inBrowser];
|
|
[mTabBrowser selectTabViewItem:tabItem];
|
|
// force a display, so that the tab view redraws before the sheet is shown
|
|
[mTabBrowser display];
|
|
}
|
|
|
|
- (void)didDismissPromptForBrowser:(BrowserWrapper*)inBrowser
|
|
{
|
|
}
|
|
|
|
- (void)createNewTab:(ENewTabContents)contents
|
|
{
|
|
BrowserTabViewItem* newTab = [self createNewTabItem];
|
|
BrowserWrapper* newView = [newTab view];
|
|
|
|
BOOL loadHomepage = NO;
|
|
if (contents == eNewTabHomepage)
|
|
{
|
|
// 0 = about:blank, 1 = home page, 2 = last page visited
|
|
int newTabPage = [[PreferenceManager sharedInstance] getIntPref:"browser.tabs.startPage" withSuccess:NULL];
|
|
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];
|
|
|
|
[[NSApp delegate] adjustBookmarksMenuItemsEnabling];
|
|
}
|
|
|
|
- (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] getCurrentURI];
|
|
BOOL backgroundLoad = [[PreferenceManager sharedInstance] getBooleanPref:"browser.tabs.loadInBackground" withSuccess:NULL];
|
|
|
|
[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 willResignActiveBrowser];
|
|
[mBrowserView setDelegate:nil];
|
|
}
|
|
|
|
// Connect up the new view
|
|
mBrowserView = [aTabViewItem view];
|
|
[mTabBrowser refreshTabBar:YES];
|
|
|
|
// Make the new view the primary content area.
|
|
[mBrowserView setDelegate:self];
|
|
[mBrowserView didBecomeActiveBrowser];
|
|
[self updateFromFrontmostTab];
|
|
|
|
if (![self userChangedLocationField] && [[self window] isKeyWindow])
|
|
[mBrowserView setBrowserActive:YES];
|
|
|
|
[[NSApp delegate] adjustBookmarksMenuItemsEnabling];
|
|
}
|
|
|
|
- (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];
|
|
// paranoia, to avoid stale mBrowserView pointer (since we don't own it)
|
|
if ([aTabView numberOfTabViewItems] == 0)
|
|
mBrowserView = nil;
|
|
}
|
|
|
|
-(BrowserTabView*)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
|
|
{
|
|
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 tabOpenPolicy:(ETabOpenPolicy)tabPolicy allowPopups:(BOOL)inAllowPopups
|
|
{
|
|
int curNumTabs = [mTabBrowser numberOfTabViewItems];
|
|
int numItems = (int)[urlArray count];
|
|
int selectedTabIndex = [[mTabBrowser tabViewItems] indexOfObject:[mTabBrowser selectedTabViewItem]];
|
|
BrowserTabViewItem* tabViewToSelect = nil;
|
|
|
|
for (int i = 0; i < numItems; i++)
|
|
{
|
|
NSString* thisURL = [urlArray objectAtIndex:i];
|
|
BrowserTabViewItem* tabViewItem = nil;
|
|
|
|
if (tabPolicy == eReplaceTabs && i < curNumTabs)
|
|
tabViewItem = [mTabBrowser tabViewItemAtIndex: i];
|
|
else if (tabPolicy == eAppendFromCurrentTab && selectedTabIndex < curNumTabs)
|
|
tabViewItem = [mTabBrowser tabViewItemAtIndex: selectedTabIndex++];
|
|
else
|
|
{
|
|
tabViewItem = [self createNewTabItem];
|
|
[tabViewItem setLabel: NSLocalizedString(@"UntitledPageTitle", @"")];
|
|
[mTabBrowser addTabViewItem: tabViewItem];
|
|
}
|
|
|
|
if (!tabViewToSelect)
|
|
tabViewToSelect = tabViewItem;
|
|
|
|
[[tabViewItem view] loadURI: thisURL referrer:nil
|
|
flags: NSLoadFlagsNone activate:(i == 0) allowPopups:inAllowPopups];
|
|
}
|
|
|
|
// select the first tab that we changed
|
|
[mTabBrowser selectTabViewItem:tabViewToSelect];
|
|
}
|
|
|
|
-(void) openURLArrayReplacingTabs:(NSArray*)urlArray closeExtraTabs:(BOOL)closeExtra allowPopups:(BOOL)inAllowPopups
|
|
{
|
|
// if there are no urls to load (say, an empty tab group), just bail outright. otherwise we'd be
|
|
// left with no tabs at all and hell to pay when it came time to do menu/toolbar item validation.
|
|
if (![urlArray count])
|
|
return;
|
|
|
|
[self openURLArray:urlArray tabOpenPolicy:eReplaceTabs allowPopups:inAllowPopups];
|
|
if (closeExtra) {
|
|
int closeIndex = [urlArray count];
|
|
int closeCount = [mTabBrowser numberOfTabViewItems] - closeIndex;
|
|
for (int i = 0; i < closeCount; i++) {
|
|
[(BrowserTabViewItem*)[mTabBrowser tabViewItemAtIndex:closeIndex] closeTab:nil];
|
|
}
|
|
}
|
|
}
|
|
|
|
-(BrowserTabViewItem*)createNewTabItem
|
|
{
|
|
BrowserTabViewItem* newTab = [BrowserTabView makeNewTabItem];
|
|
BrowserWrapper* newView = [[BrowserWrapper alloc] initWithTab:newTab inWindow:[self window]];
|
|
|
|
// register the bookmarks as a custom view
|
|
BookmarkViewController* bmController = [[[BookmarkViewController alloc] initWithBrowserWindowController:self] autorelease];
|
|
[newView registerContentViewProvider:bmController forURL:@"about:bookmarks"];
|
|
[newView registerContentViewProvider:bmController forURL:@"about:history"];
|
|
|
|
// size the new browser view properly up-front, so that if the
|
|
// page is scrolled to a relative anchor, we don't mess with the
|
|
// scroll position by resizing it later
|
|
[newView setFrame:[mTabBrowser contentRect] resizingBrowserViewIfHidden:YES];
|
|
|
|
[newTab setView: newView]; // takes ownership
|
|
[newView release];
|
|
|
|
// 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
|
|
{
|
|
BookmarkViewController* bookmarksController = [self bookmarkViewControllerForCurrentTab];
|
|
[bookmarksController ensureBookmarks];
|
|
[bookmarksController 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;
|
|
}
|
|
|
|
// Called when a context menu should be shown.
|
|
- (void)onShowContextMenu:(int)flags domEvent:(nsIDOMEvent*)aEvent domNode:(nsIDOMNode*)aNode
|
|
{
|
|
if (mDataOwner)
|
|
{
|
|
mDataOwner->mContextMenuFlags = flags;
|
|
mDataOwner->mContextMenuNode = aNode;
|
|
mDataOwner->mContextMenuEvent = aEvent;
|
|
}
|
|
|
|
// There is no simple way of getting a callback when the context menu handling
|
|
// has finished, so we don't have a good place to clear mContextMenuNode etc.
|
|
// Cocoa doesn't provide any methods that can be overridden on the menu, view
|
|
// or window.
|
|
// The menu closes before the actions are dispatched, so that's too early.
|
|
// And we can't just use -performSelector:afterDelay:0 because that will fire
|
|
// while the menu is still up.
|
|
// So the best solution I've been able to come up with is relying on the
|
|
// autorelease of an object, which will happen when we get back to the
|
|
// main loop.
|
|
[[[ContextMenuDataClearer alloc] initWithTarget:self selector:@selector(clearContextMenuTarget)] autorelease];
|
|
}
|
|
|
|
- (void)clearContextMenuTarget
|
|
{
|
|
if (mDataOwner)
|
|
{
|
|
mDataOwner->mContextMenuFlags = 0;
|
|
mDataOwner->mContextMenuNode = nsnull;
|
|
mDataOwner->mContextMenuEvent = nsnull;
|
|
}
|
|
}
|
|
|
|
// 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 (!mDataOwner->mContextMenuNode)
|
|
return @"";
|
|
|
|
nsCOMPtr<nsIDOMElement> linkContent;
|
|
nsAutoString href;
|
|
GeckoUtils::GetEnclosingLinkElementAndHref(mDataOwner->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];
|
|
|
|
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", @""), realName != nil ? realName : @""]];
|
|
[addToAddressBookItem setEnabled:YES];
|
|
} else {
|
|
[addToAddressBookItem setTitle:NSLocalizedString(@"Add to Address Book", @"")];
|
|
[addToAddressBookItem setEnabled:([emailAddress length] > 0) ];
|
|
}
|
|
}
|
|
|
|
- (NSMenu*)getContextMenu
|
|
{
|
|
BOOL showFrameItems = NO;
|
|
|
|
NSMenu* menuPrototype = nil;
|
|
int contextMenuFlags = mDataOwner->mContextMenuFlags;
|
|
|
|
if ((contextMenuFlags & nsIContextMenuListener::CONTEXT_LINK) != 0)
|
|
{
|
|
NSString* emailAddress = [self getMailAddressFromContextMenuLinkNode];
|
|
|
|
if ((contextMenuFlags & 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 ((contextMenuFlags & nsIContextMenuListener::CONTEXT_INPUT) != 0 ||
|
|
(contextMenuFlags & nsIContextMenuListener::CONTEXT_TEXT) != 0) {
|
|
menuPrototype = mInputMenu;
|
|
}
|
|
else if ((contextMenuFlags & nsIContextMenuListener::CONTEXT_IMAGE) != 0) {
|
|
menuPrototype = mImageMenu;
|
|
}
|
|
else if (!contextMenuFlags || (contextMenuFlags & 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 (mDataOwner->mContextMenuNode) {
|
|
nsCOMPtr<nsIDOMDocument> ownerDoc;
|
|
mDataOwner->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;
|
|
|
|
BOOL loadInBackground = [[PreferenceManager sharedInstance] getBooleanPref:"browser.tabs.loadInBackground" withSuccess:NULL];
|
|
|
|
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(mDataOwner->mContextMenuNode, text);
|
|
|
|
[self saveURL:nil url:hrefStr suggestedFilename:[NSString stringWith_nsAString:text]];
|
|
}
|
|
|
|
- (IBAction)saveImageAs:(id)aSender
|
|
{
|
|
nsCOMPtr<nsIDOMHTMLImageElement> imgElement(do_QueryInterface(mDataOwner->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<nsICommandManager> commandMgr(do_GetInterface(webBrowser));
|
|
if (!commandMgr)
|
|
return;
|
|
|
|
(void)commandMgr->DoCommand("cmd_copyImageContents", nsnull, nsnull);
|
|
}
|
|
|
|
- (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(mDataOwner->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];
|
|
}
|
|
|
|
//
|
|
// 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
|
|
{
|
|
[[MVPreferencesController sharedInstance] showPreferences:nil];
|
|
[[MVPreferencesController sharedInstance] selectPreferencePaneByIdentifier:@"org.mozilla.chimera.preference.webfeatures"];
|
|
}
|
|
|
|
// updateLock:
|
|
//
|
|
// updates the url bar display of security state appropriately.
|
|
- (void)updateLock:(unsigned int)inSecurityState
|
|
{
|
|
unsigned char securityState = inSecurityState & 0x000000FF;
|
|
[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 setBrowserActive:newResponderIsGecko];
|
|
}
|
|
|
|
|
|
- (PageProxyIcon *)proxyIconView
|
|
{
|
|
return mProxyIcon;
|
|
}
|
|
|
|
// XXX this is only used to show bm after an import
|
|
- (BookmarkViewController *)bookmarkViewController
|
|
{
|
|
return [self bookmarkViewControllerForCurrentTab];
|
|
}
|
|
|
|
- (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];
|
|
}
|
|
|
|
//
|
|
// - handleCommandReturn:
|
|
//
|
|
// handle command-return in location or search field, opening a new tab or window as appropriate
|
|
//
|
|
- (BOOL) handleCommandReturn
|
|
{
|
|
// determine whether to load in background
|
|
BOOL loadInBG = [[PreferenceManager sharedInstance] getBooleanPref:"browser.tabs.loadInBackground" withSuccess:NULL];
|
|
// determine whether to load in tab or window
|
|
BOOL loadInTab = [[PreferenceManager sharedInstance] getBooleanPref:"browser.tabs.opentabfor.middleclick" withSuccess:NULL];
|
|
|
|
BWCOpenDest destination = loadInTab ? kDestinationNewTab : kDestinationNewWindow;
|
|
|
|
// see if command-return came in the url bar
|
|
BOOL handled = NO;
|
|
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 getCurrentURI] ignoreTyping:YES];
|
|
|
|
// see if command-return came in the search field
|
|
} else if ([mSearchBar isFirstResponder]) {
|
|
handled = YES;
|
|
[self performSearch:mSearchBar inView:destination inBackground:loadInBG];
|
|
}
|
|
return handled;
|
|
}
|
|
|
|
//
|
|
// -fillForm:
|
|
//
|
|
// Fills the form on the current web page using wallet
|
|
//
|
|
- (IBAction)fillForm:(id)sender
|
|
{
|
|
CHBrowserView* browser = [[self getBrowserWrapper] getBrowserView];
|
|
nsCOMPtr<nsIDOMWindow> domWindow = dont_AddRef([browser getContentWindow]);
|
|
nsCOMPtr<nsIDOMWindowInternal> internalDomWindow (do_QueryInterface(domWindow));
|
|
|
|
Wallet_Prefill(internalDomWindow);
|
|
}
|
|
|
|
@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
|
|
|
|
#include <QuickTime/QuickTime.h>
|
|
|
|
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);
|
|
}
|
|
}
|
|
#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
|
|
|
|
#pragma mark -
|
|
|
|
//
|
|
// TabBarVisiblePrefChangedCallback
|
|
//
|
|
// Pref callback to tell us when the pref values for the visibility of the tab
|
|
// view with just one tab open.
|
|
//
|
|
int TabBarVisiblePrefChangedCallback(const char* inPref, void* inBWC)
|
|
{
|
|
if (strcmp(inPref, gTabBarVisiblePref) == 0) {
|
|
BOOL newValue = [[PreferenceManager sharedInstance] getBooleanPref:gTabBarVisiblePref withSuccess:nil];
|
|
BrowserWindowController* bwc = (BrowserWindowController*)inBWC;
|
|
[[bwc getTabBrowser] setBarAlwaysVisible:newValue];
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|