location_bar_view_mac.mm revision 3f50c38dc070f4bb515c1b64450dae14f316474e
1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" 6 7#include "app/l10n_util_mac.h" 8#include "app/resource_bundle.h" 9#include "base/stl_util-inl.h" 10#include "base/string_util.h" 11#include "base/sys_string_conversions.h" 12#include "base/utf_string_conversions.h" 13#include "chrome/app/chrome_command_ids.h" 14#include "chrome/browser/alternate_nav_url_fetcher.h" 15#import "chrome/browser/app_controller_mac.h" 16#import "chrome/browser/autocomplete/autocomplete_edit_view_mac.h" 17#import "chrome/browser/autocomplete/autocomplete_popup_model.h" 18#include "chrome/browser/browser_list.h" 19#include "chrome/browser/command_updater.h" 20#include "chrome/browser/content_setting_image_model.h" 21#include "chrome/browser/content_setting_bubble_model.h" 22#include "chrome/browser/defaults.h" 23#include "chrome/browser/extensions/extension_browser_event_router.h" 24#include "chrome/browser/extensions/extension_service.h" 25#include "chrome/browser/extensions/extension_tabs_module.h" 26#include "chrome/browser/instant/instant_controller.h" 27#include "chrome/browser/profiles/profile.h" 28#include "chrome/browser/search_engines/template_url.h" 29#include "chrome/browser/search_engines/template_url_model.h" 30#include "chrome/browser/tab_contents/navigation_entry.h" 31#include "chrome/browser/tab_contents/tab_contents.h" 32#import "chrome/browser/ui/cocoa/content_setting_bubble_cocoa.h" 33#include "chrome/browser/ui/cocoa/event_utils.h" 34#import "chrome/browser/ui/cocoa/extensions/extension_action_context_menu.h" 35#import "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h" 36#import "chrome/browser/ui/cocoa/first_run_bubble_controller.h" 37#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h" 38#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h" 39#import "chrome/browser/ui/cocoa/location_bar/content_setting_decoration.h" 40#import "chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.h" 41#import "chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h" 42#import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h" 43#import "chrome/browser/ui/cocoa/location_bar/page_action_decoration.h" 44#import "chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h" 45#import "chrome/browser/ui/cocoa/location_bar/star_decoration.h" 46#include "chrome/browser/ui/omnibox/location_bar_util.h" 47#include "chrome/common/extensions/extension.h" 48#include "chrome/common/extensions/extension_action.h" 49#include "chrome/common/extensions/extension_resource.h" 50#include "chrome/common/notification_service.h" 51#include "chrome/common/pref_names.h" 52#include "net/base/net_util.h" 53#include "grit/generated_resources.h" 54#include "grit/theme_resources.h" 55#include "skia/ext/skia_utils_mac.h" 56#include "third_party/skia/include/core/SkBitmap.h" 57 58namespace { 59 60// Vertical space between the bottom edge of the location_bar and the first run 61// bubble arrow point. 62const static int kFirstRunBubbleYOffset = 1; 63 64} 65 66// TODO(shess): This code is mostly copied from the gtk 67// implementation. Make sure it's all appropriate and flesh it out. 68 69LocationBarViewMac::LocationBarViewMac( 70 AutocompleteTextField* field, 71 CommandUpdater* command_updater, 72 ToolbarModel* toolbar_model, 73 Profile* profile, 74 Browser* browser) 75 : edit_view_(new AutocompleteEditViewMac(this, toolbar_model, profile, 76 command_updater, field)), 77 command_updater_(command_updater), 78 field_(field), 79 disposition_(CURRENT_TAB), 80 location_icon_decoration_(new LocationIconDecoration(this)), 81 selected_keyword_decoration_( 82 new SelectedKeywordDecoration( 83 AutocompleteEditViewMac::GetFieldFont())), 84 ev_bubble_decoration_( 85 new EVBubbleDecoration(location_icon_decoration_.get(), 86 AutocompleteEditViewMac::GetFieldFont())), 87 star_decoration_(new StarDecoration(command_updater)), 88 keyword_hint_decoration_( 89 new KeywordHintDecoration(AutocompleteEditViewMac::GetFieldFont())), 90 profile_(profile), 91 browser_(browser), 92 toolbar_model_(toolbar_model), 93 update_instant_(true), 94 transition_(PageTransition::TYPED), 95 first_run_bubble_(this) { 96 for (size_t i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) { 97 DCHECK_EQ(i, content_setting_decorations_.size()); 98 ContentSettingsType type = static_cast<ContentSettingsType>(i); 99 content_setting_decorations_.push_back( 100 new ContentSettingDecoration(type, this, profile_)); 101 } 102 103 registrar_.Add(this, 104 NotificationType::EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED, 105 NotificationService::AllSources()); 106} 107 108LocationBarViewMac::~LocationBarViewMac() { 109 // Disconnect from cell in case it outlives us. 110 [[field_ cell] clearDecorations]; 111} 112 113void LocationBarViewMac::ShowFirstRunBubble(FirstRun::BubbleType bubble_type) { 114 // We need the browser window to be shown before we can show the bubble, but 115 // we get called before that's happened. 116 Task* task = first_run_bubble_.NewRunnableMethod( 117 &LocationBarViewMac::ShowFirstRunBubbleInternal, bubble_type); 118 MessageLoop::current()->PostTask(FROM_HERE, task); 119} 120 121void LocationBarViewMac::ShowFirstRunBubbleInternal( 122 FirstRun::BubbleType bubble_type) { 123 if (!field_ || ![field_ window]) 124 return; 125 126 // The first run bubble's left edge should line up with the left edge of the 127 // omnibox. This is different from other bubbles, which line up at a point 128 // set by their top arrow. Because the BaseBubbleController adjusts the 129 // window origin left to account for the arrow spacing, the first run bubble 130 // moves the window origin right by this spacing, so that the 131 // BaseBubbleController will move it back to the correct position. 132 const NSPoint kOffset = NSMakePoint( 133 info_bubble::kBubbleArrowXOffset + info_bubble::kBubbleArrowWidth/2.0, 134 kFirstRunBubbleYOffset); 135 [FirstRunBubbleController showForView:field_ offset:kOffset profile:profile_]; 136} 137 138std::wstring LocationBarViewMac::GetInputString() const { 139 return location_input_; 140} 141 142void LocationBarViewMac::SetSuggestedText(const string16& text) { 143 edit_view_->SetSuggestText( 144 edit_view_->model()->UseVerbatimInstant() ? string16() : text); 145} 146 147WindowOpenDisposition LocationBarViewMac::GetWindowOpenDisposition() const { 148 return disposition_; 149} 150 151PageTransition::Type LocationBarViewMac::GetPageTransition() const { 152 return transition_; 153} 154 155void LocationBarViewMac::AcceptInput() { 156 WindowOpenDisposition disposition = 157 event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); 158 edit_view_->model()->AcceptInput(disposition, false); 159} 160 161void LocationBarViewMac::FocusLocation(bool select_all) { 162 edit_view_->FocusLocation(select_all); 163} 164 165void LocationBarViewMac::FocusSearch() { 166 edit_view_->SetForcedQuery(); 167} 168 169void LocationBarViewMac::UpdateContentSettingsIcons() { 170 if (RefreshContentSettingsDecorations()) { 171 [field_ updateCursorAndToolTipRects]; 172 [field_ setNeedsDisplay:YES]; 173 } 174} 175 176void LocationBarViewMac::UpdatePageActions() { 177 size_t count_before = page_action_decorations_.size(); 178 RefreshPageActionDecorations(); 179 Layout(); 180 if (page_action_decorations_.size() != count_before) { 181 NotificationService::current()->Notify( 182 NotificationType::EXTENSION_PAGE_ACTION_COUNT_CHANGED, 183 Source<LocationBar>(this), 184 NotificationService::NoDetails()); 185 } 186} 187 188void LocationBarViewMac::InvalidatePageActions() { 189 size_t count_before = page_action_decorations_.size(); 190 DeletePageActionDecorations(); 191 Layout(); 192 if (page_action_decorations_.size() != count_before) { 193 NotificationService::current()->Notify( 194 NotificationType::EXTENSION_PAGE_ACTION_COUNT_CHANGED, 195 Source<LocationBar>(this), 196 NotificationService::NoDetails()); 197 } 198} 199 200void LocationBarViewMac::SaveStateToContents(TabContents* contents) { 201 // TODO(shess): Why SaveStateToContents vs SaveStateToTab? 202 edit_view_->SaveStateToTab(contents); 203} 204 205void LocationBarViewMac::Update(const TabContents* contents, 206 bool should_restore_state) { 207 bool star_enabled = browser_defaults::bookmarks_enabled && 208 [field_ isEditable] && !toolbar_model_->input_in_progress(); 209 command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE, star_enabled); 210 star_decoration_->SetVisible(star_enabled); 211 RefreshPageActionDecorations(); 212 RefreshContentSettingsDecorations(); 213 // AutocompleteEditView restores state if the tab is non-NULL. 214 edit_view_->Update(should_restore_state ? contents : NULL); 215 OnChanged(); 216} 217 218void LocationBarViewMac::OnAutocompleteWillClosePopup() { 219 if (!update_instant_) 220 return; 221 222 InstantController* controller = browser_->instant(); 223 if (controller && !controller->commit_on_mouse_up()) 224 controller->DestroyPreviewContents(); 225 SetSuggestedText(string16()); 226} 227 228void LocationBarViewMac::OnAutocompleteLosingFocus(gfx::NativeView unused) { 229 SetSuggestedText(string16()); 230 231 InstantController* instant = browser_->instant(); 232 if (!instant) 233 return; 234 235 // If |IsMouseDownFromActivate()| returns false, the RenderWidgetHostView did 236 // not receive a mouseDown event. Therefore, we should destroy the preview. 237 // Otherwise, the RWHV was clicked, so we commit the preview. 238 if (!instant->is_displayable() || !instant->GetPreviewContents() || 239 !instant->IsMouseDownFromActivate()) { 240 instant->DestroyPreviewContents(); 241 } else if (instant->IsShowingInstant()) { 242 instant->SetCommitOnMouseUp(); 243 } else { 244 instant->CommitCurrentPreview(INSTANT_COMMIT_FOCUS_LOST); 245 } 246} 247 248void LocationBarViewMac::OnAutocompleteWillAccept() { 249 update_instant_ = false; 250} 251 252bool LocationBarViewMac::OnCommitSuggestedText(const std::wstring& typed_text) { 253 return edit_view_->CommitSuggestText(); 254} 255 256bool LocationBarViewMac::AcceptCurrentInstantPreview() { 257 return InstantController::CommitIfCurrent(browser_->instant()); 258} 259 260void LocationBarViewMac::OnSetSuggestedSearchText( 261 const string16& suggested_text) { 262 SetSuggestedText(suggested_text); 263} 264 265void LocationBarViewMac::OnPopupBoundsChanged(const gfx::Rect& bounds) { 266 InstantController* instant = browser_->instant(); 267 if (instant) 268 instant->SetOmniboxBounds(bounds); 269} 270 271void LocationBarViewMac::OnAutocompleteAccept(const GURL& url, 272 WindowOpenDisposition disposition, 273 PageTransition::Type transition, 274 const GURL& alternate_nav_url) { 275 // WARNING: don't add an early return here. The calls after the if must 276 // happen. 277 if (url.is_valid()) { 278 location_input_ = UTF8ToWide(url.spec()); 279 disposition_ = disposition; 280 transition_ = transition; 281 282 if (command_updater_) { 283 if (!alternate_nav_url.is_valid()) { 284 command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL); 285 } else { 286 AlternateNavURLFetcher* fetcher = 287 new AlternateNavURLFetcher(alternate_nav_url); 288 // The AlternateNavURLFetcher will listen for the pending navigation 289 // notification that will be issued as a result of the "open URL." It 290 // will automatically install itself into that navigation controller. 291 command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL); 292 if (fetcher->state() == AlternateNavURLFetcher::NOT_STARTED) { 293 // I'm not sure this should be reachable, but I'm not also sure enough 294 // that it shouldn't to stick in a NOTREACHED(). In any case, this is 295 // harmless. 296 delete fetcher; 297 } else { 298 // The navigation controller will delete the fetcher. 299 } 300 } 301 } 302 } 303 304 if (browser_->instant() && !edit_view_->model()->popup_model()->IsOpen()) 305 browser_->instant()->DestroyPreviewContents(); 306 307 update_instant_ = true; 308} 309 310void LocationBarViewMac::OnChanged() { 311 // Update the location-bar icon. 312 const int resource_id = edit_view_->GetIcon(); 313 NSImage* image = AutocompleteEditViewMac::ImageForResource(resource_id); 314 location_icon_decoration_->SetImage(image); 315 ev_bubble_decoration_->SetImage(image); 316 Layout(); 317 318 InstantController* instant = browser_->instant(); 319 string16 suggested_text; 320 if (update_instant_ && instant && GetTabContents()) { 321 if (edit_view_->model()->user_input_in_progress() && 322 edit_view_->model()->popup_model()->IsOpen()) { 323 instant->Update 324 (browser_->GetSelectedTabContentsWrapper(), 325 edit_view_->model()->CurrentMatch(), 326 WideToUTF16(edit_view_->GetText()), 327 edit_view_->model()->UseVerbatimInstant(), 328 &suggested_text); 329 if (!instant->MightSupportInstant()) { 330 edit_view_->model()->FinalizeInstantQuery(std::wstring(), 331 std::wstring()); 332 } 333 } else { 334 instant->DestroyPreviewContents(); 335 edit_view_->model()->FinalizeInstantQuery(std::wstring(), 336 std::wstring()); 337 } 338 } 339 340 SetSuggestedText(suggested_text); 341} 342 343void LocationBarViewMac::OnSelectionBoundsChanged() { 344 NOTIMPLEMENTED(); 345} 346 347void LocationBarViewMac::OnInputInProgress(bool in_progress) { 348 toolbar_model_->set_input_in_progress(in_progress); 349 Update(NULL, false); 350} 351 352void LocationBarViewMac::OnSetFocus() { 353 // Update the keyword and search hint states. 354 OnChanged(); 355} 356 357void LocationBarViewMac::OnKillFocus() { 358 // Do nothing. 359} 360 361SkBitmap LocationBarViewMac::GetFavIcon() const { 362 NOTIMPLEMENTED(); 363 return SkBitmap(); 364} 365 366std::wstring LocationBarViewMac::GetTitle() const { 367 NOTIMPLEMENTED(); 368 return std::wstring(); 369} 370 371void LocationBarViewMac::Revert() { 372 edit_view_->RevertAll(); 373} 374 375// TODO(pamg): Change all these, here and for other platforms, to size_t. 376int LocationBarViewMac::PageActionCount() { 377 return static_cast<int>(page_action_decorations_.size()); 378} 379 380int LocationBarViewMac::PageActionVisibleCount() { 381 int result = 0; 382 for (size_t i = 0; i < page_action_decorations_.size(); ++i) { 383 if (page_action_decorations_[i]->IsVisible()) 384 ++result; 385 } 386 return result; 387} 388 389TabContents* LocationBarViewMac::GetTabContents() const { 390 return browser_->GetSelectedTabContents(); 391} 392 393PageActionDecoration* LocationBarViewMac::GetPageActionDecoration( 394 ExtensionAction* page_action) { 395 DCHECK(page_action); 396 for (size_t i = 0; i < page_action_decorations_.size(); ++i) { 397 if (page_action_decorations_[i]->page_action() == page_action) 398 return page_action_decorations_[i]; 399 } 400 // If |page_action| is the browser action of an extension, no element in 401 // |page_action_decorations_| will match. 402 NOTREACHED(); 403 return NULL; 404} 405 406void LocationBarViewMac::SetPreviewEnabledPageAction( 407 ExtensionAction* page_action, bool preview_enabled) { 408 DCHECK(page_action); 409 TabContents* contents = GetTabContents(); 410 if (!contents) 411 return; 412 RefreshPageActionDecorations(); 413 Layout(); 414 415 PageActionDecoration* decoration = GetPageActionDecoration(page_action); 416 DCHECK(decoration); 417 if (!decoration) 418 return; 419 420 decoration->set_preview_enabled(preview_enabled); 421 decoration->UpdateVisibility(contents, 422 GURL(WideToUTF8(toolbar_model_->GetText()))); 423} 424 425NSPoint LocationBarViewMac::GetPageActionBubblePoint( 426 ExtensionAction* page_action) { 427 PageActionDecoration* decoration = GetPageActionDecoration(page_action); 428 if (!decoration) 429 return NSZeroPoint; 430 431 AutocompleteTextFieldCell* cell = [field_ cell]; 432 NSRect frame = [cell frameForDecoration:decoration inFrame:[field_ bounds]]; 433 DCHECK(!NSIsEmptyRect(frame)); 434 if (NSIsEmptyRect(frame)) 435 return NSZeroPoint; 436 437 NSPoint bubble_point = decoration->GetBubblePointInFrame(frame); 438 return [field_ convertPoint:bubble_point toView:nil]; 439} 440 441NSRect LocationBarViewMac::GetBlockedPopupRect() const { 442 const size_t kPopupIndex = CONTENT_SETTINGS_TYPE_POPUPS; 443 const LocationBarDecoration* decoration = 444 content_setting_decorations_[kPopupIndex]; 445 if (!decoration || !decoration->IsVisible()) 446 return NSZeroRect; 447 448 AutocompleteTextFieldCell* cell = [field_ cell]; 449 const NSRect frame = [cell frameForDecoration:decoration 450 inFrame:[field_ bounds]]; 451 return [field_ convertRect:frame toView:nil]; 452} 453 454ExtensionAction* LocationBarViewMac::GetPageAction(size_t index) { 455 if (index < page_action_decorations_.size()) 456 return page_action_decorations_[index]->page_action(); 457 NOTREACHED(); 458 return NULL; 459} 460 461ExtensionAction* LocationBarViewMac::GetVisiblePageAction(size_t index) { 462 size_t current = 0; 463 for (size_t i = 0; i < page_action_decorations_.size(); ++i) { 464 if (page_action_decorations_[i]->IsVisible()) { 465 if (current == index) 466 return page_action_decorations_[i]->page_action(); 467 468 ++current; 469 } 470 } 471 472 NOTREACHED(); 473 return NULL; 474} 475 476void LocationBarViewMac::TestPageActionPressed(size_t index) { 477 DCHECK_LT(index, page_action_decorations_.size()); 478 if (index < page_action_decorations_.size()) 479 page_action_decorations_[index]->OnMousePressed(NSZeroRect); 480} 481 482void LocationBarViewMac::SetEditable(bool editable) { 483 [field_ setEditable:editable ? YES : NO]; 484 star_decoration_->SetVisible(browser_defaults::bookmarks_enabled && 485 editable && !toolbar_model_->input_in_progress()); 486 UpdatePageActions(); 487 Layout(); 488} 489 490bool LocationBarViewMac::IsEditable() { 491 return [field_ isEditable] ? true : false; 492} 493 494void LocationBarViewMac::SetStarred(bool starred) { 495 star_decoration_->SetStarred(starred); 496 497 // TODO(shess): The field-editor frame and cursor rects should not 498 // change, here. 499 [field_ updateCursorAndToolTipRects]; 500 [field_ resetFieldEditorFrameIfNeeded]; 501 [field_ setNeedsDisplay:YES]; 502} 503 504NSPoint LocationBarViewMac::GetBookmarkBubblePoint() const { 505 AutocompleteTextFieldCell* cell = [field_ cell]; 506 const NSRect frame = [cell frameForDecoration:star_decoration_.get() 507 inFrame:[field_ bounds]]; 508 const NSPoint point = star_decoration_->GetBubblePointInFrame(frame); 509 return [field_ convertPoint:point toView:nil]; 510} 511 512NSPoint LocationBarViewMac::GetPageInfoBubblePoint() const { 513 AutocompleteTextFieldCell* cell = [field_ cell]; 514 if (ev_bubble_decoration_->IsVisible()) { 515 const NSRect frame = [cell frameForDecoration:ev_bubble_decoration_.get() 516 inFrame:[field_ bounds]]; 517 const NSPoint point = ev_bubble_decoration_->GetBubblePointInFrame(frame); 518 return [field_ convertPoint:point toView:nil]; 519 } else { 520 const NSRect frame = 521 [cell frameForDecoration:location_icon_decoration_.get() 522 inFrame:[field_ bounds]]; 523 const NSPoint point = 524 location_icon_decoration_->GetBubblePointInFrame(frame); 525 return [field_ convertPoint:point toView:nil]; 526 } 527} 528 529NSImage* LocationBarViewMac::GetKeywordImage(const std::wstring& keyword) { 530 const TemplateURL* template_url = 531 profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword); 532 if (template_url && template_url->IsExtensionKeyword()) { 533 const SkBitmap& bitmap = profile_->GetExtensionService()-> 534 GetOmniboxIcon(template_url->GetExtensionId()); 535 return gfx::SkBitmapToNSImage(bitmap); 536 } 537 538 return AutocompleteEditViewMac::ImageForResource(IDR_OMNIBOX_SEARCH); 539} 540 541void LocationBarViewMac::Observe(NotificationType type, 542 const NotificationSource& source, 543 const NotificationDetails& details) { 544 switch (type.value) { 545 case NotificationType::EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED: { 546 TabContents* contents = GetTabContents(); 547 if (Details<TabContents>(contents) != details) 548 return; 549 550 [field_ updateCursorAndToolTipRects]; 551 [field_ setNeedsDisplay:YES]; 552 break; 553 } 554 default: 555 NOTREACHED() << "Unexpected notification"; 556 break; 557 } 558} 559 560void LocationBarViewMac::PostNotification(NSString* notification) { 561 [[NSNotificationCenter defaultCenter] postNotificationName:notification 562 object:[NSValue valueWithPointer:this]]; 563} 564 565bool LocationBarViewMac::RefreshContentSettingsDecorations() { 566 const bool input_in_progress = toolbar_model_->input_in_progress(); 567 TabContents* tab_contents = 568 input_in_progress ? NULL : browser_->GetSelectedTabContents(); 569 bool icons_updated = false; 570 for (size_t i = 0; i < content_setting_decorations_.size(); ++i) { 571 icons_updated |= 572 content_setting_decorations_[i]->UpdateFromTabContents(tab_contents); 573 } 574 return icons_updated; 575} 576 577void LocationBarViewMac::DeletePageActionDecorations() { 578 // TODO(shess): Deleting these decorations could result in the cell 579 // refering to them before things are laid out again. Meanwhile, at 580 // least fail safe. 581 [[field_ cell] clearDecorations]; 582 583 page_action_decorations_.reset(); 584} 585 586void LocationBarViewMac::RefreshPageActionDecorations() { 587 if (!IsEditable()) { 588 DeletePageActionDecorations(); 589 return; 590 } 591 592 ExtensionService* service = profile_->GetExtensionService(); 593 if (!service) 594 return; 595 596 std::vector<ExtensionAction*> page_actions; 597 for (size_t i = 0; i < service->extensions()->size(); ++i) { 598 if (service->extensions()->at(i)->page_action()) 599 page_actions.push_back(service->extensions()->at(i)->page_action()); 600 } 601 602 // On startup we sometimes haven't loaded any extensions. This makes sure 603 // we catch up when the extensions (and any Page Actions) load. 604 if (page_actions.size() != page_action_decorations_.size()) { 605 DeletePageActionDecorations(); // Delete the old views (if any). 606 607 for (size_t i = 0; i < page_actions.size(); ++i) { 608 page_action_decorations_.push_back( 609 new PageActionDecoration(this, profile_, page_actions[i])); 610 } 611 } 612 613 if (page_action_decorations_.empty()) 614 return; 615 616 TabContents* contents = GetTabContents(); 617 if (!contents) 618 return; 619 620 GURL url = GURL(WideToUTF8(toolbar_model_->GetText())); 621 for (size_t i = 0; i < page_action_decorations_.size(); ++i) { 622 page_action_decorations_[i]->UpdateVisibility( 623 toolbar_model_->input_in_progress() ? NULL : contents, url); 624 } 625} 626 627// TODO(shess): This function should over time grow to closely match 628// the views Layout() function. 629void LocationBarViewMac::Layout() { 630 AutocompleteTextFieldCell* cell = [field_ cell]; 631 632 // Reset the left-hand decorations. 633 // TODO(shess): Shortly, this code will live somewhere else, like in 634 // the constructor. I am still wrestling with how best to deal with 635 // right-hand decorations, which are not a static set. 636 [cell clearDecorations]; 637 [cell addLeftDecoration:location_icon_decoration_.get()]; 638 [cell addLeftDecoration:selected_keyword_decoration_.get()]; 639 [cell addLeftDecoration:ev_bubble_decoration_.get()]; 640 [cell addRightDecoration:star_decoration_.get()]; 641 642 // Note that display order is right to left. 643 for (size_t i = 0; i < page_action_decorations_.size(); ++i) { 644 [cell addRightDecoration:page_action_decorations_[i]]; 645 } 646 for (size_t i = 0; i < content_setting_decorations_.size(); ++i) { 647 [cell addRightDecoration:content_setting_decorations_[i]]; 648 } 649 650 [cell addRightDecoration:keyword_hint_decoration_.get()]; 651 652 // By default only the location icon is visible. 653 location_icon_decoration_->SetVisible(true); 654 selected_keyword_decoration_->SetVisible(false); 655 ev_bubble_decoration_->SetVisible(false); 656 keyword_hint_decoration_->SetVisible(false); 657 658 // Get the keyword to use for keyword-search and hinting. 659 const std::wstring keyword(edit_view_->model()->keyword()); 660 std::wstring short_name; 661 bool is_extension_keyword = false; 662 if (!keyword.empty()) { 663 short_name = profile_->GetTemplateURLModel()-> 664 GetKeywordShortName(keyword, &is_extension_keyword); 665 } 666 667 const bool is_keyword_hint = edit_view_->model()->is_keyword_hint(); 668 669 if (!keyword.empty() && !is_keyword_hint) { 670 // Switch from location icon to keyword mode. 671 location_icon_decoration_->SetVisible(false); 672 selected_keyword_decoration_->SetVisible(true); 673 selected_keyword_decoration_->SetKeyword(short_name, is_extension_keyword); 674 selected_keyword_decoration_->SetImage(GetKeywordImage(keyword)); 675 } else if (toolbar_model_->GetSecurityLevel() == ToolbarModel::EV_SECURE) { 676 // Switch from location icon to show the EV bubble instead. 677 location_icon_decoration_->SetVisible(false); 678 ev_bubble_decoration_->SetVisible(true); 679 680 std::wstring label(toolbar_model_->GetEVCertName()); 681 ev_bubble_decoration_->SetFullLabel(base::SysWideToNSString(label)); 682 } else if (!keyword.empty() && is_keyword_hint) { 683 keyword_hint_decoration_->SetKeyword(WideToUTF16Hack(short_name), 684 is_extension_keyword); 685 keyword_hint_decoration_->SetVisible(true); 686 } 687 688 // These need to change anytime the layout changes. 689 // TODO(shess): Anytime the field editor might have changed, the 690 // cursor rects almost certainly should have changed. The tooltips 691 // might change even when the rects don't change. 692 [field_ resetFieldEditorFrameIfNeeded]; 693 [field_ updateCursorAndToolTipRects]; 694 695 [field_ setNeedsDisplay:YES]; 696} 697