diff --git a/camino/resources/localized/English.lproj/BrowserWindow.nib/classes.nib b/camino/resources/localized/English.lproj/BrowserWindow.nib/classes.nib index 7ba20ff3498..7cc02cd2599 100644 --- a/camino/resources/localized/English.lproj/BrowserWindow.nib/classes.nib +++ b/camino/resources/localized/English.lproj/BrowserWindow.nib/classes.nib @@ -137,6 +137,7 @@ saveImageAs = id; saveLinkAs = id; savePageAs = id; + searchForSelection = id; sendURL = id; sendURLFromLink = id; showBookmarksInfo = id; @@ -164,7 +165,7 @@ mLinkMenu = NSMenu; mLocationSheetURLField = NSTextField; mLocationSheetWindow = NSWindow; - mLocationToolbarView = NSSplitView; + mLocationToolbarView = ExtendedSplitView; mMailToLinkMenu = NSMenu; mPageMenu = NSMenu; mPersonalToolbar = BookmarkToolbar; @@ -188,6 +189,7 @@ SUPERCLASS = NSView; }, {CLASS = ExtendedOutlineView; LANGUAGE = ObjC; SUPERCLASS = NSOutlineView; }, + {CLASS = ExtendedSplitView; LANGUAGE = ObjC; SUPERCLASS = NSSplitView; }, {CLASS = ExtendedTableView; LANGUAGE = ObjC; SUPERCLASS = NSTableView; }, { ACTIONS = {addBookmark = id; addBookmarkFolder = id; addBookmarkSeparator = id; }; diff --git a/camino/resources/localized/English.lproj/BrowserWindow.nib/info.nib b/camino/resources/localized/English.lproj/BrowserWindow.nib/info.nib index 3eb4a3e10c8..6e429d44042 100644 --- a/camino/resources/localized/English.lproj/BrowserWindow.nib/info.nib +++ b/camino/resources/localized/English.lproj/BrowserWindow.nib/info.nib @@ -13,19 +13,19 @@ 1058 318 439 135 80 0 0 1600 1002 1066 - 775 752 600 85 0 0 1920 1178 + 775 772 370 64 0 0 1920 1178 297 - 558 586 213 306 0 0 1600 1002 + 688 734 226 306 0 0 1920 1178 314 306 574 213 156 0 0 1600 1002 336 159 679 226 206 0 0 1600 1002 365 - 123 707 98 168 0 0 1600 1002 + 149 856 98 168 0 0 1920 1178 463 348 489 213 275 0 0 1600 1002 56 - 951 593 314 64 0 0 1920 1178 + 803 772 314 64 0 0 1920 1178 654 620 416 210 149 0 0 1600 1002 801 diff --git a/camino/resources/localized/English.lproj/BrowserWindow.nib/keyedobjects.nib b/camino/resources/localized/English.lproj/BrowserWindow.nib/keyedobjects.nib index 6b01a3dfd9b..679f9eff50e 100644 Binary files a/camino/resources/localized/English.lproj/BrowserWindow.nib/keyedobjects.nib and b/camino/resources/localized/English.lproj/BrowserWindow.nib/keyedobjects.nib differ diff --git a/camino/src/browser/BrowserWindowController.h b/camino/src/browser/BrowserWindowController.h index 8a1b6d8d908..41d14b65e79 100644 --- a/camino/src/browser/BrowserWindowController.h +++ b/camino/src/browser/BrowserWindowController.h @@ -104,11 +104,13 @@ typedef enum @class BrowserTabViewItem; @class AutoCompleteTextField; @class SearchTextField; +@class ExtendedSplitView; + @interface BrowserWindowController : NSWindowController { IBOutlet BrowserTabView* mTabBrowser; - IBOutlet NSSplitView* mLocationToolbarView; // parent splitter of location and search + IBOutlet ExtendedSplitView* mLocationToolbarView; // parent splitter of location and search, strong IBOutlet AutoCompleteTextField* mURLBar; IBOutlet NSTextField* mStatus; IBOutlet NSProgressIndicator* mProgress; // STRONG reference @@ -211,6 +213,7 @@ typedef enum - (IBAction)printDocument:(id)aSender; - (IBAction)pageSetup:(id)aSender; - (IBAction)performSearch:(id)aSender; +- (IBAction)searchForSelection:(id)aSender; - (IBAction)sendURL:(id)aSender; - (IBAction)sendURLFromLink:(id)aSender; diff --git a/camino/src/browser/BrowserWindowController.mm b/camino/src/browser/BrowserWindowController.mm index 8f8081a4a01..5b3f2f3ef89 100644 --- a/camino/src/browser/BrowserWindowController.mm +++ b/camino/src/browser/BrowserWindowController.mm @@ -66,6 +66,7 @@ #import "DraggableImageAndTextCell.h" #import "MVPreferencesController.h" #import "ViewCertificateDialogController.h" +#import "ExtendedSplitView.h" #import "wallet.h" #include "nsString.h" @@ -142,6 +143,7 @@ const float kMininumURLAndSearchBarWidth = 128.0; static NSString* const NavigatorWindowFrameSaveName = @"NavigatorWindow"; static NSString* const NavigatorWindowSearchBarWidth = @"SearchBarWidth"; +static NSString* const NavigatorWindowSearchBarHidden = @"SearchBarHidden"; static NSString* const kViewSourceProtocolString = @"view-source:"; const unsigned long kNoToolbarsChromeMask = (nsIWebBrowserChrome::CHROME_ALL & ~(nsIWebBrowserChrome::CHROME_TOOLBAR | @@ -588,10 +590,12 @@ enum BWCOpenDest { if (mShouldAutosave) { [[self window] saveFrameUsingName: NavigatorWindowFrameSaveName]; - // save the width of the search bar so it's consistent regardless of the + // save the width and visibility of the search bar so it's consistent regardless of the // size of the next window we create const float searchBarWidth = [mSearchBar frame].size.width; [[NSUserDefaults standardUserDefaults] setFloat:searchBarWidth forKey:NavigatorWindowSearchBarWidth]; + BOOL isCollapsed = [mLocationToolbarView isSubviewCollapsed:mSearchBar]; + [[NSUserDefaults standardUserDefaults] setBool:isCollapsed forKey:NavigatorWindowSearchBarHidden]; } } @@ -714,6 +718,7 @@ enum BWCOpenDest { [self stopThrobber]; [mThrobberImages release]; [mURLFieldEditor release]; + [mLocationToolbarView release]; delete mDataOwner; // paranoia; should have been deleted in -windowWillClose @@ -730,6 +735,15 @@ enum BWCOpenDest { { [super windowDidLoad]; + // we shouldn't have to do this, yet for some reason removing it from + // the toolbar destroys the view. However, this also helps us by ensuring + // that we always have a search bar alive to do things with, like redirect + // context menu searches to. + [mLocationToolbarView retain]; + // explicitly don't save the splitter position, we want to save it oursevles + // since we want a different behavior. + [mLocationToolbarView setAutosaveSplitterPosition:NO]; + BOOL mustResizeChrome = NO; // hide the resize control if specified by the chrome mask @@ -805,17 +819,23 @@ enum BWCOpenDest { [self setupToolbar]; - // set the size of the search bar to the width it was last time - float searchBarWidth = [[NSUserDefaults standardUserDefaults] floatForKey:NavigatorWindowSearchBarWidth]; - if (searchBarWidth <= 0) - searchBarWidth = kMininumURLAndSearchBarWidth; - const float currentWidth = [mLocationToolbarView frame].size.width; - float newDividerPosition = currentWidth - searchBarWidth - [mLocationToolbarView dividerThickness]; - if (newDividerPosition < kMininumURLAndSearchBarWidth) - newDividerPosition = kMininumURLAndSearchBarWidth; - [mLocationToolbarView setLeftWidth:newDividerPosition]; - [mLocationToolbarView adjustSubviews]; - + // set the size of the search bar to the width it was last time and hide it + // programmatically if it wasn't visible + BOOL searchBarHidden = [[NSUserDefaults standardUserDefaults] boolForKey:NavigatorWindowSearchBarHidden]; + if (searchBarHidden) + [mLocationToolbarView collapseSubviewAtIndex:1]; + else { + float searchBarWidth = [[NSUserDefaults standardUserDefaults] floatForKey:NavigatorWindowSearchBarWidth]; + if (searchBarWidth <= 0) + searchBarWidth = kMininumURLAndSearchBarWidth; + const float currentWidth = [mLocationToolbarView frame].size.width; + float newDividerPosition = currentWidth - searchBarWidth - [mLocationToolbarView dividerThickness]; + if (newDividerPosition < kMininumURLAndSearchBarWidth) + newDividerPosition = kMininumURLAndSearchBarWidth; + [mLocationToolbarView setLeftWidth:newDividerPosition]; + [mLocationToolbarView adjustSubviews]; + } + // 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 @@ -1379,12 +1399,12 @@ enum BWCOpenDest { // -splitView:canCollapseSubview: // NSSplitView delegate // -// We don't want to allow the user to collapse either the url bar or the search bar +// Allow the user (read: smokey) to collapse the search bar but not the url bar. // - (BOOL)splitView:(NSSplitView *)sender canCollapseSubview:(NSView *)subview { if (sender == mLocationToolbarView) - return NO; + return (subview == mSearchBar); return YES; } @@ -1768,26 +1788,10 @@ enum BWCOpenDest { // - (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:CombinedLocationToolbarItemIdentifier]) - { - [self focusSearchBar]; - return; - } - } - } - } - - [self beginSearchSheet]; + if ([mSearchBar window] && ![mLocationToolbarView isSubviewCollapsed:mSearchBar]) + [self focusSearchBar]; + else + [self beginSearchSheet]; } - (void)focusSearchBar @@ -2003,6 +2007,22 @@ enum BWCOpenDest { [self performSearch:(SearchTextField *)aSender inView:kDestinationCurrentView inBackground:NO]; } +// +// -searchForSelection: +// +// Get the selection, stick it into the search bar, and do a search with the +// currently selected search engine in the search bar. If there is no search +// bar in the toolbar, that's still ok because we've guaranteed that we always +// have a search bar even if it's not on a toolbar. +// +- (IBAction)searchForSelection:(id)aSender +{ + NSString* selection = [[mBrowserView getBrowserView] getSelection]; + [mSearchBar becomeFirstResponder]; + [mSearchBar setStringValue:selection]; + [self performSearch:mSearchBar]; +} + // // - performSearch:inView:inBackground // @@ -3259,7 +3279,9 @@ enum BWCOpenDest { NSMenu* menuPrototype = nil; int contextMenuFlags = mDataOwner->mContextMenuFlags; - + + BOOL hasSelection = [[mBrowserView getBrowserView] canCopy]; + if ((contextMenuFlags & nsIContextMenuListener::CONTEXT_LINK) != 0) { NSString* emailAddress = [self getMailAddressFromContextMenuLinkNode]; @@ -3295,9 +3317,9 @@ enum BWCOpenDest { menuPrototype = mPageMenu; [mBackItem setEnabled: [[mBrowserView getBrowserView] canGoBack]]; [mForwardItem setEnabled: [[mBrowserView getBrowserView] canGoForward]]; - [mCopyItem setEnabled: [[mBrowserView getBrowserView] canCopy]]; + [mCopyItem setEnabled:hasSelection]; } - + if (mDataOwner->mContextMenuNode) { nsCOMPtr ownerDoc; mDataOwner->mContextMenuNode->GetOwnerDocument(getter_AddRefs(ownerDoc)); @@ -3315,8 +3337,17 @@ enum BWCOpenDest { // our only copy of the menu NSMenu* result = [[menuPrototype copy] autorelease]; - const int kFrameRelatedItemsTag = 100; + const int kFrameRelatedItemsTag = 100; const int kFrameInapplicableItemsTag = 101; + const int kSelectionRelatedItemsTag = 102; + + // if there's no selection or no search bar in the toolbar, hide the search item. + // We need a search item to know what the user's preferred search is. + if (!hasSelection) { + NSMenuItem* selectionItem; + while ((selectionItem = [result itemWithTag:kSelectionRelatedItemsTag]) != nil) + [result removeItem:selectionItem]; + } if (showFrameItems) { NSMenuItem* frameItem; diff --git a/camino/src/browser/SearchTextField.m b/camino/src/browser/SearchTextField.m index 7f80a6ddcbc..1b9d0728f8f 100644 --- a/camino/src/browser/SearchTextField.m +++ b/camino/src/browser/SearchTextField.m @@ -153,6 +153,22 @@ [super textDidChange: aNotification]; } +// +// -setStringValue: +// +// Override to display the clear (x) when setting the search bar's text +// programmatically. +// +- (void)setStringValue:(NSString*)inValue +{ + [super setStringValue:inValue]; + + // force the (x) to display when string changed programmatically. This + // has to come after our call to super otherwise the cell won't have the + // new value yet. + [[self cell] searchSubmittedFromView:self]; +} + - (NSString *)titleOfSelectedPopUpItem { return [[[self cell] popUpButtonCell] titleOfSelectedItem]; diff --git a/camino/src/embedding/CHBrowserView.h b/camino/src/embedding/CHBrowserView.h index 53eaab5b0e6..1e8081e921e 100644 --- a/camino/src/embedding/CHBrowserView.h +++ b/camino/src/embedding/CHBrowserView.h @@ -225,6 +225,9 @@ typedef enum { -(BOOL)canDelete; -(IBAction)selectAll:(id)aSender; +// Returns the currently selected text as a NSString. +- (NSString*)getSelection; + -(IBAction)undo:(id)aSender; -(IBAction)redo:(id)aSender; diff --git a/camino/src/extensions/ExtendedSplitView.h b/camino/src/extensions/ExtendedSplitView.h index 0ff25c68ad3..85ff585c4ac 100644 --- a/camino/src/extensions/ExtendedSplitView.h +++ b/camino/src/extensions/ExtendedSplitView.h @@ -41,8 +41,9 @@ @interface ExtendedSplitView : NSSplitView { - NSString* mAutosaveName; // owned + NSString* mAutosaveName; // owned BOOL mAutosaveSplitterPosition; + NSMutableDictionary* mCollapsedSubviews; // owned } - (void)setAutosaveName:(NSString *)name; @@ -51,4 +52,6 @@ - (BOOL)autosaveSplitterPosition; - (void)setAutosaveSplitterPosition:(BOOL)inAutosave; +- (void)collapseSubviewAtIndex:(int)inIndex; + @end diff --git a/camino/src/extensions/ExtendedSplitView.m b/camino/src/extensions/ExtendedSplitView.m index 2f504a8c6ea..8ea3be8ccde 100644 --- a/camino/src/extensions/ExtendedSplitView.m +++ b/camino/src/extensions/ExtendedSplitView.m @@ -60,6 +60,7 @@ { // we'll default to saving (if we have an autosaveName) mAutosaveSplitterPosition = YES; + mCollapsedSubviews = [[NSMutableDictionary alloc] init]; } return self; } @@ -67,6 +68,7 @@ - (void)dealloc { [mAutosaveName release]; + [mCollapsedSubviews release]; [super dealloc]; } @@ -191,5 +193,81 @@ } } +// +// -collapseSubviewAtIndex: +// +// Called to programmatically collapse the given subview. Removes it from the +// view and we will manage it ourselves when it comes time to re-insert it into +// the split view. Replaces it with a temporary view so we know what to look for. +// +- (void)collapseSubviewAtIndex:(int)inIndex +{ + // be lazy with the allocation, we generally will never need it + if (!mCollapsedSubviews) + mCollapsedSubviews = [[NSMutableDictionary alloc] init]; + + NSView* viewToCollapse = [[self subviews] objectAtIndex:inIndex]; + NSView* placeholder = [[[NSView alloc] initWithFrame:NSZeroRect] autorelease]; + [mCollapsedSubviews setObject:viewToCollapse forKey:[NSValue valueWithPointer:placeholder]]; + [self replaceSubview:viewToCollapse with:placeholder]; + [self adjustSubviews]; +} + +// +// -drawDividerInRect: +// +// Watches for changes to the size of one of our temporary views that have +// been hidden programmatically. When we notice one changing size, swap the +// associated real view back in in its place. +// +- (void)drawDividerInRect:(NSRect)inRect +{ + if ([mCollapsedSubviews count]) { + // loop over all the the keys (the placeholder views) to see if they've changed size. + // if they have, swap back in the object at that key (the real view). + NSEnumerator* e = [mCollapsedSubviews keyEnumerator]; + NSValue* key = nil; + while ((key = (NSValue*)[e nextObject])) { + NSView* placeholderView = (NSView*)[key pointerValue]; + NSSize viewSize = [placeholderView frame].size; + BOOL isVertical = [self isVertical]; + if ((isVertical && viewSize.width > 0) || (!isVertical && viewSize.height > 0)) { + // swap out the temp view if size changed with the view we cached + // in the collapse function + NSView* realView = [mCollapsedSubviews objectForKey:key]; + [realView setFrameSize:viewSize]; + [self replaceSubview:placeholderView with:realView]; + [self adjustSubviews]; + [mCollapsedSubviews removeObjectForKey:key]; + } + } + } + [super drawDividerInRect:inRect]; +} + +// +// -isSubviewCollapsed: +// +// Overridden to check our list of programmatically collapsed subviews if the base +// class didn't find it as hidden already. +// +- (BOOL)isSubviewCollapsed:(NSView*)inView +{ + BOOL isCollapsed = [super isSubviewCollapsed:inView]; + if (!isCollapsed) { + // check our list of hidden views to see if it's in that list + if ([mCollapsedSubviews count]) { + NSEnumerator* e = [mCollapsedSubviews objectEnumerator]; + NSView* view = nil; + while ((view = (NSView*)[e nextObject])) { + if (view == inView) { + isCollapsed = YES; + break; + } + } + } + } + return isCollapsed; +} @end // ExtendedSplitView