conflicting_module_view_win.cc revision 868fa2fe829687343ffae624259930155e16dbd8
1// Copyright (c) 2013 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#include "chrome/browser/ui/views/conflicting_module_view_win.h" 6 7#include "base/metrics/histogram.h" 8#include "chrome/browser/enumerate_modules_model_win.h" 9#include "chrome/browser/profiles/profile.h" 10#include "chrome/browser/ui/browser.h" 11#include "chrome/common/chrome_notification_types.h" 12#include "chrome/common/pref_names.h" 13#include "content/public/browser/notification_service.h" 14#include "content/public/browser/user_metrics.h" 15#include "grit/chromium_strings.h" 16#include "grit/generated_resources.h" 17#include "grit/locale_settings.h" 18#include "grit/theme_resources.h" 19#include "ui/base/accessibility/accessible_view_state.h" 20#include "ui/base/l10n/l10n_util.h" 21#include "ui/base/resource/resource_bundle.h" 22#include "ui/views/controls/button/label_button.h" 23#include "ui/views/controls/image_view.h" 24#include "ui/views/controls/label.h" 25#include "ui/views/layout/grid_layout.h" 26#include "ui/views/layout/layout_constants.h" 27#include "ui/views/widget/widget.h" 28 29using content::UserMetricsAction; 30 31namespace { 32 33// Layout constants. 34const int kInsetBottomRight = 13; 35const int kInsetLeft = 14; 36const int kInsetTop = 9; 37const int kHeadlineMessagePadding = 4; 38const int kMessageBubblePadding = 11; 39 40// How often to show this bubble. 41const int kShowConflictingModuleBubbleMax = 3; 42 43} // namespace 44 45//////////////////////////////////////////////////////////////////////////////// 46// ConflictingModuleView 47 48ConflictingModuleView::ConflictingModuleView( 49 views::View* anchor_view, 50 Browser* browser, 51 const GURL& help_center_url) 52 : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT), 53 browser_(browser), 54 explanation_(NULL), 55 learn_more_button_(NULL), 56 not_now_button_(NULL), 57 help_center_url_(help_center_url) { 58 set_close_on_deactivate(false); 59 set_move_with_anchor(true); 60 set_close_on_esc(true); 61 62 // Compensate for built-in vertical padding in the anchor view's image. 63 set_anchor_view_insets(gfx::Insets(5, 0, 5, 0)); 64 65 registrar_.Add(this, chrome::NOTIFICATION_MODULE_INCOMPATIBILITY_BADGE_CHANGE, 66 content::NotificationService::AllSources()); 67} 68 69// static 70void ConflictingModuleView::MaybeShow(Browser* browser, 71 views::View* anchor_view) { 72 static bool done_checking = false; 73 if (done_checking) 74 return; // Only show the bubble once per launch. 75 76 EnumerateModulesModel* model = EnumerateModulesModel::GetInstance(); 77 GURL url = model->GetFirstNotableConflict(); 78 if (!url.is_valid()) { 79 done_checking = true; 80 return; 81 } 82 83 // A pref that counts how often the Sideload Wipeout bubble has been shown. 84 IntegerPrefMember bubble_shown; 85 bubble_shown.Init(prefs::kModuleConflictBubbleShown, 86 browser->profile()->GetPrefs()); 87 if (bubble_shown.GetValue() >= kShowConflictingModuleBubbleMax) { 88 done_checking = true; 89 return; 90 } 91 92 ConflictingModuleView* bubble_delegate = 93 new ConflictingModuleView(anchor_view, browser, url); 94 views::BubbleDelegateView::CreateBubble(bubble_delegate); 95 bubble_delegate->ShowBubble(); 96 97 done_checking = true; 98} 99 100//////////////////////////////////////////////////////////////////////////////// 101// ConflictingModuleView - private. 102 103ConflictingModuleView::~ConflictingModuleView() { 104} 105 106void ConflictingModuleView::ShowBubble() { 107 StartFade(true); 108 109 IntegerPrefMember bubble_shown; 110 bubble_shown.Init( 111 prefs::kModuleConflictBubbleShown, 112 browser_->profile()->GetPrefs()); 113 bubble_shown.SetValue(bubble_shown.GetValue() + 1); 114} 115 116void ConflictingModuleView::DismissBubble() { 117 GetWidget()->Close(); 118 119 content::RecordAction( 120 UserMetricsAction("ConflictingModuleNotificationDismissed")); 121} 122 123void ConflictingModuleView::Init() { 124 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 125 126 views::GridLayout* layout = views::GridLayout::CreatePanel(this); 127 layout->SetInsets(kInsetTop, kInsetLeft, 128 kInsetBottomRight, kInsetBottomRight); 129 SetLayoutManager(layout); 130 131 views::ImageView* icon = new views::ImageView(); 132 icon->SetImage(rb.GetNativeImageNamed(IDR_INPUT_ALERT_MENU).ToImageSkia()); 133 gfx::Size icon_size = icon->GetPreferredSize(); 134 135 const int text_column_set_id = 0; 136 views::ColumnSet* upper_columns = layout->AddColumnSet(text_column_set_id); 137 upper_columns->AddColumn( 138 views::GridLayout::LEADING, views::GridLayout::LEADING, 139 0, views::GridLayout::FIXED, icon_size.width(), icon_size.height()); 140 upper_columns->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing); 141 upper_columns->AddColumn( 142 views::GridLayout::LEADING, views::GridLayout::LEADING, 143 0, views::GridLayout::USE_PREF, 0, 0); 144 145 layout->StartRowWithPadding( 146 0, text_column_set_id, 0, kHeadlineMessagePadding); 147 layout->AddView(icon); 148 explanation_ = new views::Label(); 149 explanation_->SetMultiLine(true); 150 explanation_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 151 explanation_->SetText(l10n_util::GetStringUTF16( 152 IDS_OPTIONS_CONFLICTING_MODULE)); 153 explanation_->SizeToFit(views::Widget::GetLocalizedContentsWidth( 154 IDS_CONFLICTING_MODULE_BUBBLE_WIDTH_CHARS)); 155 layout->AddView(explanation_); 156 157 const int action_row_column_set_id = 1; 158 views::ColumnSet* bottom_columns = 159 layout->AddColumnSet(action_row_column_set_id); 160 bottom_columns->AddPaddingColumn(1, 0); 161 bottom_columns->AddColumn(views::GridLayout::TRAILING, 162 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0); 163 bottom_columns->AddPaddingColumn(0, views::kRelatedButtonHSpacing); 164 bottom_columns->AddColumn(views::GridLayout::TRAILING, 165 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0); 166 layout->AddPaddingRow(0, 7); 167 168 layout->StartRowWithPadding(0, action_row_column_set_id, 169 0, kMessageBubblePadding); 170 learn_more_button_ = new views::LabelButton(this, 171 l10n_util::GetStringUTF16(IDS_CONFLICTS_LEARN_MORE)); 172 learn_more_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON); 173 layout->AddView(learn_more_button_); 174 not_now_button_ = new views::LabelButton(this, 175 l10n_util::GetStringUTF16(IDS_CONFLICTS_NOT_NOW)); 176 not_now_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON); 177 layout->AddView(not_now_button_); 178 179 content::RecordAction( 180 UserMetricsAction("ConflictingModuleNotificationShown")); 181 182 UMA_HISTOGRAM_ENUMERATION("ConflictingModule.UserSelection", 183 EnumerateModulesModel::ACTION_BUBBLE_SHOWN, 184 EnumerateModulesModel::ACTION_BOUNDARY); 185} 186 187void ConflictingModuleView::ButtonPressed(views::Button* sender, 188 const ui::Event& event) { 189 if (sender == learn_more_button_) { 190 EnumerateModulesModel::RecordLearnMoreStat(false); 191 browser_->OpenURL( 192 content::OpenURLParams(help_center_url_, 193 content::Referrer(), 194 NEW_FOREGROUND_TAB, 195 content::PAGE_TRANSITION_LINK, 196 false)); 197 198 EnumerateModulesModel* model = EnumerateModulesModel::GetInstance(); 199 model->AcknowledgeConflictNotification(); 200 DismissBubble(); 201 } else if (sender == not_now_button_) { 202 DismissBubble(); 203 } 204} 205 206void ConflictingModuleView::GetAccessibleState( 207 ui::AccessibleViewState* state) { 208 state->role = ui::AccessibilityTypes::ROLE_ALERT; 209} 210 211void ConflictingModuleView::ViewHierarchyChanged( 212 const ViewHierarchyChangedDetails& details) { 213 if (details.is_add && details.child == this) 214 NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_ALERT, true); 215} 216 217void ConflictingModuleView::Observe( 218 int type, 219 const content::NotificationSource& source, 220 const content::NotificationDetails& details) { 221 DCHECK(type == chrome::NOTIFICATION_MODULE_INCOMPATIBILITY_BADGE_CHANGE); 222 EnumerateModulesModel* model = EnumerateModulesModel::GetInstance(); 223 if (!model->ShouldShowConflictWarning()) 224 GetWidget()->Close(); 225} 226