1 // Copyright 2012 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 "base/bind.h" 8 #include "base/command_line.h" 9 #include "base/message_loop/message_loop.h" 10 #include "base/prefs/pref_service.h" 11 #include "base/stl_util.h" 12 #include "base/strings/string_util.h" 13 #include "base/strings/sys_string_conversions.h" 14 #include "base/strings/utf_string_conversions.h" 15 #include "chrome/app/chrome_command_ids.h" 16 #import "chrome/browser/app_controller_mac.h" 17 #include "chrome/browser/chrome_notification_types.h" 18 #include "chrome/browser/command_updater.h" 19 #include "chrome/browser/defaults.h" 20 #include "chrome/browser/extensions/api/omnibox/omnibox_api.h" 21 #include "chrome/browser/extensions/api/tabs/tabs_api.h" 22 #include "chrome/browser/extensions/extension_action.h" 23 #include "chrome/browser/extensions/extension_service.h" 24 #include "chrome/browser/extensions/location_bar_controller.h" 25 #include "chrome/browser/extensions/tab_helper.h" 26 #include "chrome/browser/profiles/profile.h" 27 #include "chrome/browser/search/instant_service.h" 28 #include "chrome/browser/search/instant_service_factory.h" 29 #include "chrome/browser/search/search.h" 30 #include "chrome/browser/search_engines/template_url.h" 31 #include "chrome/browser/search_engines/template_url_service.h" 32 #include "chrome/browser/search_engines/template_url_service_factory.h" 33 #include "chrome/browser/translate/chrome_translate_client.h" 34 #include "chrome/browser/translate/translate_service.h" 35 #include "chrome/browser/ui/browser_instant_controller.h" 36 #include "chrome/browser/ui/browser_list.h" 37 #import "chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.h" 38 #import "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h" 39 #import "chrome/browser/ui/cocoa/first_run_bubble_controller.h" 40 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h" 41 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h" 42 #import "chrome/browser/ui/cocoa/location_bar/content_setting_decoration.h" 43 #import "chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.h" 44 #import "chrome/browser/ui/cocoa/location_bar/generated_credit_card_decoration.h" 45 #import "chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h" 46 #import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h" 47 #import "chrome/browser/ui/cocoa/location_bar/mic_search_decoration.h" 48 #import "chrome/browser/ui/cocoa/location_bar/origin_chip_decoration.h" 49 #import "chrome/browser/ui/cocoa/location_bar/page_action_decoration.h" 50 #import "chrome/browser/ui/cocoa/location_bar/search_button_decoration.h" 51 #import "chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h" 52 #import "chrome/browser/ui/cocoa/location_bar/star_decoration.h" 53 #import "chrome/browser/ui/cocoa/location_bar/translate_decoration.h" 54 #import "chrome/browser/ui/cocoa/location_bar/zoom_decoration.h" 55 #import "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" 56 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h" 57 #include "chrome/browser/ui/content_settings/content_setting_image_model.h" 58 #include "chrome/browser/ui/omnibox/location_bar_util.h" 59 #import "chrome/browser/ui/omnibox/omnibox_popup_model.h" 60 #include "chrome/browser/ui/tabs/tab_strip_model.h" 61 #include "chrome/browser/ui/toolbar/toolbar_model.h" 62 #include "chrome/browser/ui/zoom/zoom_controller.h" 63 #include "chrome/common/chrome_switches.h" 64 #include "chrome/common/pref_names.h" 65 #include "components/translate/core/browser/language_state.h" 66 #include "content/public/browser/notification_service.h" 67 #include "content/public/browser/web_contents.h" 68 #include "extensions/browser/extension_system.h" 69 #include "extensions/common/extension.h" 70 #include "extensions/common/permissions/permissions_data.h" 71 #include "grit/generated_resources.h" 72 #include "grit/theme_resources.h" 73 #include "net/base/net_util.h" 74 #include "skia/ext/skia_utils_mac.h" 75 #import "ui/base/cocoa/cocoa_base_utils.h" 76 #include "ui/base/l10n/l10n_util_mac.h" 77 #include "ui/base/resource/resource_bundle.h" 78 #include "ui/gfx/image/image.h" 79 80 using content::WebContents; 81 82 namespace { 83 84 // Vertical space between the bottom edge of the location_bar and the first run 85 // bubble arrow point. 86 const static int kFirstRunBubbleYOffset = 1; 87 88 // Functor for moving BookmarkManagerPrivate page actions to the right via 89 // stable_partition. 90 class IsPageActionViewRightAligned { 91 public: 92 explicit IsPageActionViewRightAligned(ExtensionService* extension_service) 93 : extension_service_(extension_service) {} 94 95 bool operator()(PageActionDecoration* page_action_decoration) { 96 return extension_service_ 97 ->GetExtensionById( 98 page_action_decoration->page_action()->extension_id(), false) 99 ->permissions_data() 100 ->HasAPIPermission(extensions::APIPermission::kBookmarkManagerPrivate); 101 } 102 103 private: 104 ExtensionService* extension_service_; 105 106 // NOTE: Can't DISALLOW_COPY_AND_ASSIGN as we pass this object by value to 107 // std::stable_partition(). 108 }; 109 110 } 111 112 // TODO(shess): This code is mostly copied from the gtk 113 // implementation. Make sure it's all appropriate and flesh it out. 114 115 LocationBarViewMac::LocationBarViewMac(AutocompleteTextField* field, 116 CommandUpdater* command_updater, 117 Profile* profile, 118 Browser* browser) 119 : LocationBar(profile), 120 OmniboxEditController(command_updater), 121 omnibox_view_(new OmniboxViewMac(this, profile, command_updater, field)), 122 field_(field), 123 location_icon_decoration_(new LocationIconDecoration(this)), 124 selected_keyword_decoration_(new SelectedKeywordDecoration()), 125 ev_bubble_decoration_( 126 new EVBubbleDecoration(location_icon_decoration_.get())), 127 star_decoration_(new StarDecoration(command_updater)), 128 translate_decoration_(new TranslateDecoration(command_updater)), 129 zoom_decoration_(new ZoomDecoration(this)), 130 keyword_hint_decoration_(new KeywordHintDecoration()), 131 mic_search_decoration_(new MicSearchDecoration(command_updater)), 132 generated_credit_card_decoration_( 133 new GeneratedCreditCardDecoration(this)), 134 search_button_decoration_(new SearchButtonDecoration(this)), 135 browser_(browser), 136 weak_ptr_factory_(this) { 137 138 for (size_t i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) { 139 DCHECK_EQ(i, content_setting_decorations_.size()); 140 ContentSettingsType type = static_cast<ContentSettingsType>(i); 141 content_setting_decorations_.push_back( 142 new ContentSettingDecoration(type, this, profile)); 143 } 144 145 registrar_.Add( 146 this, chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED, 147 content::NotificationService::AllSources()); 148 content::Source<Profile> profile_source = content::Source<Profile>(profile); 149 registrar_.Add( 150 this, chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED, profile_source); 151 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED, 152 profile_source); 153 154 edit_bookmarks_enabled_.Init( 155 prefs::kEditBookmarksEnabled, profile->GetPrefs(), 156 base::Bind(&LocationBarViewMac::OnEditBookmarksEnabledChanged, 157 base::Unretained(this))); 158 159 browser_->search_model()->AddObserver(this); 160 161 [[field_ cell] setIsPopupMode: 162 !browser->SupportsWindowFeature(Browser::FEATURE_TABSTRIP)]; 163 164 if (chrome::ShouldDisplayOriginChip()) 165 origin_chip_decoration_.reset(new OriginChipDecoration( 166 this, location_icon_decoration_.get())); 167 } 168 169 LocationBarViewMac::~LocationBarViewMac() { 170 // Disconnect from cell in case it outlives us. 171 [[field_ cell] clearDecorations]; 172 173 browser_->search_model()->RemoveObserver(this); 174 } 175 176 void LocationBarViewMac::ShowFirstRunBubble() { 177 // We need the browser window to be shown before we can show the bubble, but 178 // we get called before that's happened. 179 base::MessageLoop::current()->PostTask( 180 FROM_HERE, base::Bind(&LocationBarViewMac::ShowFirstRunBubbleInternal, 181 weak_ptr_factory_.GetWeakPtr())); 182 } 183 184 GURL LocationBarViewMac::GetDestinationURL() const { 185 return destination_url(); 186 } 187 188 WindowOpenDisposition LocationBarViewMac::GetWindowOpenDisposition() const { 189 return disposition(); 190 } 191 192 content::PageTransition LocationBarViewMac::GetPageTransition() const { 193 return transition(); 194 } 195 196 void LocationBarViewMac::AcceptInput() { 197 WindowOpenDisposition disposition = 198 ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); 199 omnibox_view_->model()->AcceptInput(disposition, false); 200 } 201 202 void LocationBarViewMac::FocusLocation(bool select_all) { 203 omnibox_view_->FocusLocation(select_all); 204 } 205 206 void LocationBarViewMac::FocusSearch() { 207 omnibox_view_->SetForcedQuery(); 208 } 209 210 void LocationBarViewMac::UpdateContentSettingsIcons() { 211 if (RefreshContentSettingsDecorations()) 212 OnDecorationsChanged(); 213 } 214 215 void LocationBarViewMac::UpdatePageActions() { 216 size_t count_before = page_action_decorations_.size(); 217 RefreshPageActionDecorations(); 218 Layout(); 219 if (page_action_decorations_.size() != count_before) { 220 content::NotificationService::current()->Notify( 221 chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_COUNT_CHANGED, 222 content::Source<LocationBar>(this), 223 content::NotificationService::NoDetails()); 224 } 225 } 226 227 void LocationBarViewMac::InvalidatePageActions() { 228 size_t count_before = page_action_decorations_.size(); 229 DeletePageActionDecorations(); 230 Layout(); 231 if (page_action_decorations_.size() != count_before) { 232 content::NotificationService::current()->Notify( 233 chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_COUNT_CHANGED, 234 content::Source<LocationBar>(this), 235 content::NotificationService::NoDetails()); 236 } 237 } 238 239 void LocationBarViewMac::UpdateOpenPDFInReaderPrompt() { 240 // Not implemented on Mac. 241 } 242 243 void LocationBarViewMac::UpdateGeneratedCreditCardView() { 244 generated_credit_card_decoration_->Update(); 245 } 246 247 void LocationBarViewMac::SaveStateToContents(WebContents* contents) { 248 // TODO(shess): Why SaveStateToContents vs SaveStateToTab? 249 omnibox_view_->SaveStateToTab(contents); 250 } 251 252 void LocationBarViewMac::Revert() { 253 omnibox_view_->RevertAll(); 254 } 255 256 const OmniboxView* LocationBarViewMac::GetOmniboxView() const { 257 return omnibox_view_.get(); 258 } 259 260 OmniboxView* LocationBarViewMac::GetOmniboxView() { 261 return omnibox_view_.get(); 262 } 263 264 LocationBarTesting* LocationBarViewMac::GetLocationBarForTesting() { 265 return this; 266 } 267 268 // TODO(pamg): Change all these, here and for other platforms, to size_t. 269 int LocationBarViewMac::PageActionCount() { 270 return static_cast<int>(page_action_decorations_.size()); 271 } 272 273 int LocationBarViewMac::PageActionVisibleCount() { 274 int result = 0; 275 for (size_t i = 0; i < page_action_decorations_.size(); ++i) { 276 if (page_action_decorations_[i]->IsVisible()) 277 ++result; 278 } 279 return result; 280 } 281 282 ExtensionAction* LocationBarViewMac::GetPageAction(size_t index) { 283 if (index < page_action_decorations_.size()) 284 return page_action_decorations_[index]->page_action(); 285 NOTREACHED(); 286 return NULL; 287 } 288 289 ExtensionAction* LocationBarViewMac::GetVisiblePageAction(size_t index) { 290 size_t current = 0; 291 for (size_t i = 0; i < page_action_decorations_.size(); ++i) { 292 if (page_action_decorations_[i]->IsVisible()) { 293 if (current == index) 294 return page_action_decorations_[i]->page_action(); 295 296 ++current; 297 } 298 } 299 300 NOTREACHED(); 301 return NULL; 302 } 303 304 void LocationBarViewMac::TestPageActionPressed(size_t index) { 305 DCHECK_LT(index, page_action_decorations_.size()); 306 if (index < page_action_decorations_.size()) 307 page_action_decorations_[index]->OnMousePressed(NSZeroRect, NSZeroPoint); 308 } 309 310 bool LocationBarViewMac::GetBookmarkStarVisibility() { 311 DCHECK(star_decoration_.get()); 312 return star_decoration_->IsVisible(); 313 } 314 315 void LocationBarViewMac::SetEditable(bool editable) { 316 [field_ setEditable:editable ? YES : NO]; 317 UpdateStarDecorationVisibility(); 318 UpdateZoomDecoration(); 319 UpdatePageActions(); 320 Layout(); 321 } 322 323 bool LocationBarViewMac::IsEditable() { 324 return [field_ isEditable] ? true : false; 325 } 326 327 void LocationBarViewMac::SetStarred(bool starred) { 328 star_decoration_->SetStarred(starred); 329 UpdateStarDecorationVisibility(); 330 OnDecorationsChanged(); 331 } 332 333 void LocationBarViewMac::SetTranslateIconLit(bool on) { 334 translate_decoration_->SetLit(on); 335 OnDecorationsChanged(); 336 } 337 338 void LocationBarViewMac::ZoomChangedForActiveTab(bool can_show_bubble) { 339 UpdateZoomDecoration(); 340 OnDecorationsChanged(); 341 342 if (can_show_bubble && zoom_decoration_->IsVisible()) 343 zoom_decoration_->ShowBubble(YES); 344 } 345 346 bool LocationBarViewMac::IsStarEnabled() const { 347 return browser_defaults::bookmarks_enabled && 348 [field_ isEditable] && 349 !GetToolbarModel()->input_in_progress() && 350 edit_bookmarks_enabled_.GetValue() && 351 !IsBookmarkStarHiddenByExtension(); 352 } 353 354 NSPoint LocationBarViewMac::GetBookmarkBubblePoint() const { 355 DCHECK(IsStarEnabled()); 356 return [field_ bubblePointForDecoration:star_decoration_.get()]; 357 } 358 359 NSPoint LocationBarViewMac::GetTranslateBubblePoint() const { 360 return [field_ bubblePointForDecoration:translate_decoration_.get()]; 361 } 362 363 NSPoint LocationBarViewMac::GetPageInfoBubblePoint() const { 364 if (origin_chip_decoration_ && origin_chip_decoration_->IsVisible()) { 365 return [field_ bubblePointForDecoration:origin_chip_decoration_.get()]; 366 } else if (ev_bubble_decoration_->IsVisible()) { 367 return [field_ bubblePointForDecoration:ev_bubble_decoration_.get()]; 368 } else { 369 return [field_ bubblePointForDecoration:location_icon_decoration_.get()]; 370 } 371 } 372 373 NSPoint LocationBarViewMac::GetGeneratedCreditCardBubblePoint() const { 374 return 375 [field_ bubblePointForDecoration:generated_credit_card_decoration_.get()]; 376 } 377 378 void LocationBarViewMac::OnDecorationsChanged() { 379 // TODO(shess): The field-editor frame and cursor rects should not 380 // change, here. 381 [field_ updateMouseTracking]; 382 [field_ resetFieldEditorFrameIfNeeded]; 383 [field_ setNeedsDisplay:YES]; 384 } 385 386 // TODO(shess): This function should over time grow to closely match 387 // the views Layout() function. 388 void LocationBarViewMac::Layout() { 389 AutocompleteTextFieldCell* cell = [field_ cell]; 390 391 // Reset the left-hand decorations. 392 // TODO(shess): Shortly, this code will live somewhere else, like in 393 // the constructor. I am still wrestling with how best to deal with 394 // right-hand decorations, which are not a static set. 395 [cell clearDecorations]; 396 if (origin_chip_decoration_.get()) 397 [cell addLeftDecoration:origin_chip_decoration_.get()]; 398 [cell addLeftDecoration:location_icon_decoration_.get()]; 399 [cell addLeftDecoration:selected_keyword_decoration_.get()]; 400 if (!origin_chip_decoration_.get()) 401 [cell addLeftDecoration:ev_bubble_decoration_.get()]; 402 [cell addRightDecoration:search_button_decoration_.get()]; 403 [cell addRightDecoration:star_decoration_.get()]; 404 [cell addRightDecoration:translate_decoration_.get()]; 405 [cell addRightDecoration:zoom_decoration_.get()]; 406 [cell addRightDecoration:generated_credit_card_decoration_.get()]; 407 408 // Note that display order is right to left. 409 for (size_t i = 0; i < page_action_decorations_.size(); ++i) { 410 [cell addRightDecoration:page_action_decorations_[i]]; 411 } 412 413 for (ScopedVector<ContentSettingDecoration>::iterator i = 414 content_setting_decorations_.begin(); 415 i != content_setting_decorations_.end(); ++i) { 416 [cell addRightDecoration:*i]; 417 } 418 419 [cell addRightDecoration:keyword_hint_decoration_.get()]; 420 [cell addRightDecoration:mic_search_decoration_.get()]; 421 422 // By default only the location icon is visible. 423 location_icon_decoration_->SetVisible(!origin_chip_decoration_.get() || 424 !origin_chip_decoration_->IsVisible()); 425 selected_keyword_decoration_->SetVisible(false); 426 ev_bubble_decoration_->SetVisible(false); 427 keyword_hint_decoration_->SetVisible(false); 428 429 // Get the keyword to use for keyword-search and hinting. 430 const base::string16 keyword = omnibox_view_->model()->keyword(); 431 base::string16 short_name; 432 bool is_extension_keyword = false; 433 if (!keyword.empty()) { 434 short_name = TemplateURLServiceFactory::GetForProfile(profile())-> 435 GetKeywordShortName(keyword, &is_extension_keyword); 436 } 437 438 const bool is_keyword_hint = omnibox_view_->model()->is_keyword_hint(); 439 if (!keyword.empty() && !is_keyword_hint) { 440 // Switch from location icon to keyword mode. 441 location_icon_decoration_->SetVisible(false); 442 selected_keyword_decoration_->SetVisible(true); 443 selected_keyword_decoration_->SetKeyword(short_name, is_extension_keyword); 444 selected_keyword_decoration_->SetImage(GetKeywordImage(keyword)); 445 } else if ((GetToolbarModel()->GetSecurityLevel(false) == 446 ToolbarModel::EV_SECURE) && !origin_chip_decoration_.get()) { 447 // Switch from location icon to show the EV bubble instead. 448 location_icon_decoration_->SetVisible(false); 449 ev_bubble_decoration_->SetVisible(true); 450 451 base::string16 label(GetToolbarModel()->GetEVCertName()); 452 ev_bubble_decoration_->SetFullLabel(base::SysUTF16ToNSString(label)); 453 } else if (!keyword.empty() && is_keyword_hint) { 454 keyword_hint_decoration_->SetKeyword(short_name, 455 is_extension_keyword); 456 keyword_hint_decoration_->SetVisible(true); 457 } 458 459 // These need to change anytime the layout changes. 460 // TODO(shess): Anytime the field editor might have changed, the 461 // cursor rects almost certainly should have changed. The tooltips 462 // might change even when the rects don't change. 463 OnDecorationsChanged(); 464 } 465 466 void LocationBarViewMac::RedrawDecoration(LocationBarDecoration* decoration) { 467 AutocompleteTextFieldCell* cell = [field_ cell]; 468 NSRect frame = [cell frameForDecoration:decoration 469 inFrame:[field_ bounds]]; 470 if (!NSIsEmptyRect(frame)) 471 [field_ setNeedsDisplayInRect:frame]; 472 } 473 474 void LocationBarViewMac::SetPreviewEnabledPageAction( 475 ExtensionAction* page_action, bool preview_enabled) { 476 DCHECK(page_action); 477 WebContents* contents = GetWebContents(); 478 if (!contents) 479 return; 480 RefreshPageActionDecorations(); 481 Layout(); 482 483 PageActionDecoration* decoration = GetPageActionDecoration(page_action); 484 DCHECK(decoration); 485 if (!decoration) 486 return; 487 488 decoration->set_preview_enabled(preview_enabled); 489 decoration->UpdateVisibility(contents, GetToolbarModel()->GetURL()); 490 } 491 492 NSRect LocationBarViewMac::GetPageActionFrame(ExtensionAction* page_action) { 493 PageActionDecoration* decoration = GetPageActionDecoration(page_action); 494 if (!decoration) 495 return NSZeroRect; 496 497 AutocompleteTextFieldCell* cell = [field_ cell]; 498 NSRect frame = [cell frameForDecoration:decoration inFrame:[field_ bounds]]; 499 return frame; 500 } 501 502 NSPoint LocationBarViewMac::GetPageActionBubblePoint( 503 ExtensionAction* page_action) { 504 PageActionDecoration* decoration = GetPageActionDecoration(page_action); 505 if (!decoration) 506 return NSZeroPoint; 507 508 NSRect frame = GetPageActionFrame(page_action); 509 if (NSIsEmptyRect(frame)) { 510 // The bubble point positioning assumes that the page action is visible. If 511 // not, something else needs to be done otherwise the bubble will appear 512 // near the top left corner (unanchored). 513 NOTREACHED(); 514 return NSZeroPoint; 515 } 516 517 NSPoint bubble_point = decoration->GetBubblePointInFrame(frame); 518 return [field_ convertPoint:bubble_point toView:nil]; 519 } 520 521 void LocationBarViewMac::Update(const WebContents* contents) { 522 UpdateStarDecorationVisibility(); 523 UpdateTranslateDecoration(); 524 UpdateZoomDecoration(); 525 RefreshPageActionDecorations(); 526 RefreshContentSettingsDecorations(); 527 UpdateMicSearchDecorationVisibility(); 528 UpdateGeneratedCreditCardView(); 529 if (contents) 530 omnibox_view_->OnTabChanged(contents); 531 else 532 omnibox_view_->Update(); 533 OnChanged(); 534 } 535 536 void LocationBarViewMac::OnChanged() { 537 // Update the location-bar icon. 538 const int resource_id = omnibox_view_->GetIcon(); 539 NSImage* image = OmniboxViewMac::ImageForResource(resource_id); 540 location_icon_decoration_->SetImage(image); 541 ev_bubble_decoration_->SetImage(image); 542 543 if (origin_chip_decoration_.get()) 544 origin_chip_decoration_->Update(); 545 546 ToolbarModel* toolbar_model = GetToolbarModel(); 547 const chrome::DisplaySearchButtonConditions conditions = 548 chrome::GetDisplaySearchButtonConditions(); 549 const bool meets_conditions = 550 (conditions == chrome::DISPLAY_SEARCH_BUTTON_ALWAYS) || 551 ((conditions != chrome::DISPLAY_SEARCH_BUTTON_NEVER) && 552 (toolbar_model->WouldPerformSearchTermReplacement(true) || 553 ((conditions == chrome::DISPLAY_SEARCH_BUTTON_FOR_STR_OR_IIP) && 554 toolbar_model->input_in_progress()))); 555 search_button_decoration_->SetVisible( 556 ![[field_ cell] isPopupMode] && meets_conditions); 557 search_button_decoration_->SetIcon( 558 (resource_id == IDR_OMNIBOX_SEARCH) ? 559 IDR_OMNIBOX_SEARCH_BUTTON_LOUPE : IDR_OMNIBOX_SEARCH_BUTTON_ARROW); 560 561 Layout(); 562 563 InstantService* instant_service = 564 InstantServiceFactory::GetForProfile(profile()); 565 if (instant_service) { 566 gfx::Rect bounds(NSRectToCGRect([field_ frame])); 567 instant_service->OnOmniboxStartMarginChanged(bounds.x()); 568 } 569 } 570 571 void LocationBarViewMac::OnSetFocus() { 572 // Update the keyword and search hint states. 573 OnChanged(); 574 } 575 576 void LocationBarViewMac::ShowURL() { 577 omnibox_view_->ShowURL(); 578 } 579 580 void LocationBarViewMac::HideURL() { 581 omnibox_view_->HideURL(); 582 } 583 584 void LocationBarViewMac::EndOriginChipAnimations(bool cancel_fade) { 585 NOTIMPLEMENTED(); 586 } 587 588 InstantController* LocationBarViewMac::GetInstant() { 589 return browser_->instant_controller() ? 590 browser_->instant_controller()->instant() : NULL; 591 } 592 593 WebContents* LocationBarViewMac::GetWebContents() { 594 return browser_->tab_strip_model()->GetActiveWebContents(); 595 } 596 597 ToolbarModel* LocationBarViewMac::GetToolbarModel() { 598 return browser_->toolbar_model(); 599 } 600 601 const ToolbarModel* LocationBarViewMac::GetToolbarModel() const { 602 return browser_->toolbar_model(); 603 } 604 605 NSImage* LocationBarViewMac::GetKeywordImage(const base::string16& keyword) { 606 const TemplateURL* template_url = TemplateURLServiceFactory::GetForProfile( 607 profile())->GetTemplateURLForKeyword(keyword); 608 if (template_url && 609 (template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION)) { 610 return extensions::OmniboxAPI::Get(profile())-> 611 GetOmniboxIcon(template_url->GetExtensionId()).AsNSImage(); 612 } 613 614 return OmniboxViewMac::ImageForResource(IDR_OMNIBOX_SEARCH); 615 } 616 617 void LocationBarViewMac::Observe(int type, 618 const content::NotificationSource& source, 619 const content::NotificationDetails& details) { 620 switch (type) { 621 case chrome::NOTIFICATION_EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED: { 622 WebContents* contents = GetWebContents(); 623 if (content::Details<WebContents>(contents) != details) 624 return; 625 626 [field_ updateMouseTracking]; 627 [field_ setNeedsDisplay:YES]; 628 break; 629 } 630 631 case chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED: 632 case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: 633 Update(NULL); 634 break; 635 636 default: 637 NOTREACHED() << "Unexpected notification"; 638 break; 639 } 640 } 641 642 void LocationBarViewMac::ModelChanged(const SearchModel::State& old_state, 643 const SearchModel::State& new_state) { 644 if (UpdateMicSearchDecorationVisibility()) 645 Layout(); 646 } 647 648 void LocationBarViewMac::ActivatePageAction(const std::string& extension_id) { 649 for (size_t i = 0; i < page_action_decorations_.size(); ++i) { 650 if (page_action_decorations_[i]->page_action()->extension_id() == 651 extension_id) { 652 page_action_decorations_[i]->ActivatePageAction(); 653 return; 654 } 655 } 656 } 657 658 void LocationBarViewMac::PostNotification(NSString* notification) { 659 [[NSNotificationCenter defaultCenter] postNotificationName:notification 660 object:[NSValue valueWithPointer:this]]; 661 } 662 663 PageActionDecoration* LocationBarViewMac::GetPageActionDecoration( 664 ExtensionAction* page_action) { 665 DCHECK(page_action); 666 for (size_t i = 0; i < page_action_decorations_.size(); ++i) { 667 if (page_action_decorations_[i]->page_action() == page_action) 668 return page_action_decorations_[i]; 669 } 670 // If |page_action| is the browser action of an extension, no element in 671 // |page_action_decorations_| will match. 672 NOTREACHED(); 673 return NULL; 674 } 675 676 677 void LocationBarViewMac::DeletePageActionDecorations() { 678 // TODO(shess): Deleting these decorations could result in the cell 679 // refering to them before things are laid out again. Meanwhile, at 680 // least fail safe. 681 [[field_ cell] clearDecorations]; 682 683 page_action_decorations_.clear(); 684 } 685 686 void LocationBarViewMac::OnEditBookmarksEnabledChanged() { 687 UpdateStarDecorationVisibility(); 688 OnChanged(); 689 } 690 691 void LocationBarViewMac::RefreshPageActionDecorations() { 692 if (!IsEditable()) { 693 DeletePageActionDecorations(); 694 return; 695 } 696 697 WebContents* web_contents = GetWebContents(); 698 if (!web_contents) { 699 DeletePageActionDecorations(); // Necessary? 700 return; 701 } 702 703 std::vector<ExtensionAction*> new_page_actions = 704 extensions::TabHelper::FromWebContents(web_contents)-> 705 location_bar_controller()->GetCurrentActions(); 706 707 if (new_page_actions != page_actions_) { 708 page_actions_.swap(new_page_actions); 709 DeletePageActionDecorations(); 710 for (size_t i = 0; i < page_actions_.size(); ++i) { 711 page_action_decorations_.push_back( 712 new PageActionDecoration(this, browser_, page_actions_[i])); 713 } 714 715 // Move rightmost extensions to the start. 716 std::stable_partition( 717 page_action_decorations_.begin(), 718 page_action_decorations_.end(), 719 IsPageActionViewRightAligned( 720 extensions::ExtensionSystem::Get(profile())->extension_service())); 721 } 722 723 GURL url = GetToolbarModel()->GetURL(); 724 for (size_t i = 0; i < page_action_decorations_.size(); ++i) { 725 page_action_decorations_[i]->UpdateVisibility( 726 GetToolbarModel()->input_in_progress() ? NULL : web_contents, url); 727 } 728 } 729 730 bool LocationBarViewMac::RefreshContentSettingsDecorations() { 731 const bool input_in_progress = GetToolbarModel()->input_in_progress(); 732 WebContents* web_contents = input_in_progress ? 733 NULL : browser_->tab_strip_model()->GetActiveWebContents(); 734 bool icons_updated = false; 735 for (size_t i = 0; i < content_setting_decorations_.size(); ++i) { 736 icons_updated |= 737 content_setting_decorations_[i]->UpdateFromWebContents(web_contents); 738 } 739 return icons_updated; 740 } 741 742 void LocationBarViewMac::ShowFirstRunBubbleInternal() { 743 if (!field_ || ![field_ window]) 744 return; 745 746 // The first run bubble's left edge should line up with the left edge of the 747 // omnibox. This is different from other bubbles, which line up at a point 748 // set by their top arrow. Because the BaseBubbleController adjusts the 749 // window origin left to account for the arrow spacing, the first run bubble 750 // moves the window origin right by this spacing, so that the 751 // BaseBubbleController will move it back to the correct position. 752 const NSPoint kOffset = NSMakePoint( 753 info_bubble::kBubbleArrowXOffset + info_bubble::kBubbleArrowWidth/2.0, 754 kFirstRunBubbleYOffset); 755 [FirstRunBubbleController showForView:field_ 756 offset:kOffset 757 browser:browser_ 758 profile:profile()]; 759 } 760 761 void LocationBarViewMac::UpdateTranslateDecoration() { 762 if (!TranslateService::IsTranslateBubbleEnabled()) 763 return; 764 765 WebContents* web_contents = GetWebContents(); 766 if (!web_contents) 767 return; 768 LanguageState& language_state = 769 ChromeTranslateClient::FromWebContents(web_contents)->GetLanguageState(); 770 bool enabled = language_state.translate_enabled(); 771 command_updater()->UpdateCommandEnabled(IDC_TRANSLATE_PAGE, enabled); 772 translate_decoration_->SetVisible(enabled); 773 translate_decoration_->SetLit(language_state.IsPageTranslated()); 774 } 775 776 void LocationBarViewMac::UpdateZoomDecoration() { 777 WebContents* web_contents = GetWebContents(); 778 if (!web_contents) 779 return; 780 781 zoom_decoration_->Update(ZoomController::FromWebContents(web_contents)); 782 } 783 784 void LocationBarViewMac::UpdateStarDecorationVisibility() { 785 star_decoration_->SetVisible(IsStarEnabled()); 786 } 787 788 bool LocationBarViewMac::UpdateMicSearchDecorationVisibility() { 789 bool is_visible = !GetToolbarModel()->input_in_progress() && 790 browser_->search_model()->voice_search_supported(); 791 if (mic_search_decoration_->IsVisible() == is_visible) 792 return false; 793 mic_search_decoration_->SetVisible(is_visible); 794 return true; 795 } 796