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