bookmark_app_bubble_view.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
1// Copyright 2014 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/extensions/bookmark_app_bubble_view.h" 6 7#include "base/strings/string16.h" 8#include "base/strings/utf_string_conversions.h" 9#include "chrome/browser/extensions/app_icon_loader_impl.h" 10#include "chrome/browser/extensions/bookmark_app_helper.h" 11#include "chrome/browser/extensions/extension_service.h" 12#include "chrome/browser/extensions/launch_util.h" 13#include "chrome/browser/profiles/profile.h" 14#include "chrome/common/extensions/extension_constants.h" 15#include "extensions/browser/extension_prefs.h" 16#include "extensions/browser/extension_registry.h" 17#include "extensions/browser/extension_system.h" 18#include "extensions/browser/pref_names.h" 19#include "extensions/browser/uninstall_reason.h" 20#include "extensions/common/constants.h" 21#include "grit/generated_resources.h" 22#include "grit/theme_resources.h" 23#include "ui/base/l10n/l10n_util.h" 24#include "ui/base/resource/resource_bundle.h" 25#include "ui/events/keycodes/keyboard_codes.h" 26#include "ui/views/controls/button/checkbox.h" 27#include "ui/views/controls/button/label_button.h" 28#include "ui/views/controls/image_view.h" 29#include "ui/views/controls/label.h" 30#include "ui/views/controls/textfield/textfield.h" 31#include "ui/views/layout/grid_layout.h" 32#include "ui/views/layout/layout_constants.h" 33#include "ui/views/widget/widget.h" 34 35using views::ColumnSet; 36using views::GridLayout; 37 38namespace { 39 40// Minimum width of the the bubble. 41const int kMinBubbleWidth = 300; 42// Minimum width of the the textfield. 43const int kMinTextfieldWidth = 200; 44// Size of the icon. 45const int kIconSize = extension_misc::EXTENSION_ICON_MEDIUM; 46 47ExtensionService* GetExtensionService(Profile* profile) { 48 return extensions::ExtensionSystem::Get(profile)->extension_service(); 49} 50 51} // namespace 52 53BookmarkAppBubbleView* BookmarkAppBubbleView::bookmark_app_bubble_ = NULL; 54 55BookmarkAppBubbleView::~BookmarkAppBubbleView() { 56} 57 58// static 59void BookmarkAppBubbleView::ShowBubble(views::View* anchor_view, 60 Profile* profile, 61 const WebApplicationInfo& web_app_info, 62 const std::string& extension_id) { 63 if (bookmark_app_bubble_ != NULL) 64 return; 65 66 bookmark_app_bubble_ = new BookmarkAppBubbleView( 67 anchor_view, profile, web_app_info, extension_id); 68 views::BubbleDelegateView::CreateBubble(bookmark_app_bubble_)->Show(); 69 // Select the entire title textfield contents when the bubble is first shown. 70 bookmark_app_bubble_->title_tf_->SelectAll(true); 71 bookmark_app_bubble_->SetArrowPaintType(views::BubbleBorder::PAINT_NONE); 72} 73 74BookmarkAppBubbleView::BookmarkAppBubbleView( 75 views::View* anchor_view, 76 Profile* profile, 77 const WebApplicationInfo& web_app_info, 78 const std::string& extension_id) 79 : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT), 80 profile_(profile), 81 web_app_info_(web_app_info), 82 extension_id_(extension_id), 83 add_button_(NULL), 84 cancel_button_(NULL), 85 open_as_tab_checkbox_(NULL), 86 title_tf_(NULL), 87 remove_app_(true), 88 app_icon_loader_(new extensions::AppIconLoaderImpl(profile, 89 kIconSize, 90 this)) { 91 const SkColor background_color = GetNativeTheme()->GetSystemColor( 92 ui::NativeTheme::kColorId_DialogBackground); 93 set_arrow(views::BubbleBorder::TOP_CENTER); 94 set_color(background_color); 95 set_background(views::Background::CreateSolidBackground(background_color)); 96 set_margins(gfx::Insets(views::kPanelVertMargin, 0, 0, 0)); 97} 98 99void BookmarkAppBubbleView::Init() { 100 views::Label* title_label = new views::Label( 101 l10n_util::GetStringUTF16(IDS_BOOKMARK_APP_BUBBLE_TITLE)); 102 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 103 title_label->SetFontList(rb->GetFontList(ui::ResourceBundle::MediumFont)); 104 title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 105 106 add_button_ = 107 new views::LabelButton(this, l10n_util::GetStringUTF16(IDS_ADD)); 108 add_button_->SetStyle(views::Button::STYLE_BUTTON); 109 add_button_->SetIsDefault(true); 110 111 cancel_button_ = 112 new views::LabelButton(this, l10n_util::GetStringUTF16(IDS_CANCEL)); 113 cancel_button_->SetStyle(views::Button::STYLE_BUTTON); 114 115 GridLayout* layout = new GridLayout(this); 116 SetLayoutManager(layout); 117 118 // Column sets used in the layout of the bubble. 119 enum ColumnSetID { 120 TITLE_COLUMN_SET_ID, 121 TITLE_TEXT_COLUMN_SET_ID, 122 CONTENT_COLUMN_SET_ID 123 }; 124 125 // The column layout used for the title and checkbox. 126 ColumnSet* cs = layout->AddColumnSet(TITLE_COLUMN_SET_ID); 127 cs->AddPaddingColumn(0, views::kButtonHEdgeMarginNew); 128 cs->AddColumn( 129 GridLayout::LEADING, GridLayout::CENTER, 0, GridLayout::USE_PREF, 0, 0); 130 cs->AddPaddingColumn(0, views::kButtonHEdgeMarginNew); 131 132 // The column layout used for the icon and text box. 133 cs = layout->AddColumnSet(TITLE_TEXT_COLUMN_SET_ID); 134 cs->AddPaddingColumn(0, views::kButtonHEdgeMarginNew); 135 cs->AddColumn(GridLayout::LEADING, 136 GridLayout::CENTER, 137 0, 138 GridLayout::USE_PREF, 139 0, 140 0); 141 cs->AddPaddingColumn(0, views::kButtonHEdgeMarginNew); 142 cs->AddColumn(GridLayout::FILL, 143 GridLayout::CENTER, 144 1, 145 GridLayout::USE_PREF, 146 0, 147 kMinTextfieldWidth); 148 cs->AddPaddingColumn(0, views::kButtonHEdgeMarginNew); 149 150 // The column layout used for the row with buttons. 151 cs = layout->AddColumnSet(CONTENT_COLUMN_SET_ID); 152 cs->AddPaddingColumn(0, views::kButtonHEdgeMarginNew); 153 cs->AddColumn( 154 GridLayout::LEADING, GridLayout::CENTER, 0, GridLayout::USE_PREF, 0, 0); 155 cs->AddPaddingColumn(1, views::kUnrelatedControlHorizontalSpacing); 156 cs->AddColumn( 157 GridLayout::LEADING, GridLayout::CENTER, 0, GridLayout::USE_PREF, 0, 0); 158 cs->AddPaddingColumn(0, views::kRelatedButtonHSpacing); 159 cs->AddColumn( 160 GridLayout::LEADING, GridLayout::CENTER, 0, GridLayout::USE_PREF, 0, 0); 161 cs->AddPaddingColumn(0, views::kButtonHEdgeMarginNew); 162 163 layout->StartRow(0, TITLE_COLUMN_SET_ID); 164 layout->AddView(title_label); 165 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 166 167 const extensions::Extension* extension = 168 extensions::ExtensionRegistry::Get(profile_)->GetExtensionById( 169 extension_id_, extensions::ExtensionRegistry::EVERYTHING); 170 171 layout->StartRow(0, TITLE_TEXT_COLUMN_SET_ID); 172 icon_image_view_ = new views::ImageView(); 173 icon_image_view_->SetImageSize(gfx::Size(kIconSize, kIconSize)); 174 layout->AddView(icon_image_view_); 175 app_icon_loader_->FetchImage(extension_id_); 176 177 title_tf_ = new views::Textfield(); 178 title_tf_->SetText(extension ? base::UTF8ToUTF16(extension->name()) 179 : web_app_info_.title); 180 layout->AddView(title_tf_); 181 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 182 183 layout->StartRow(0, CONTENT_COLUMN_SET_ID); 184 open_as_tab_checkbox_ = new views::Checkbox( 185 l10n_util::GetStringUTF16(IDS_BOOKMARK_APP_BUBBLE_OPEN_AS_TAB)); 186 open_as_tab_checkbox_->SetChecked( 187 profile_->GetPrefs()->GetInteger( 188 extensions::pref_names::kBookmarkAppCreationLaunchType) == 189 extensions::LAUNCH_TYPE_REGULAR); 190 layout->AddView(open_as_tab_checkbox_); 191 layout->AddView(add_button_); 192 layout->AddView(cancel_button_); 193 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing); 194 195 AddAccelerator(ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE)); 196} 197 198views::View* BookmarkAppBubbleView::GetInitiallyFocusedView() { 199 return title_tf_; 200} 201 202void BookmarkAppBubbleView::WindowClosing() { 203 // We have to reset |bookmark_app_bubble_| here, not in our destructor, 204 // because we'll be destroyed asynchronously and the shown state will be 205 // checked before then. 206 DCHECK_EQ(bookmark_app_bubble_, this); 207 bookmark_app_bubble_ = NULL; 208 209 if (remove_app_) { 210 GetExtensionService(profile_) 211 ->UninstallExtension(extension_id_, 212 extensions::UNINSTALL_REASON_INSTALL_CANCELED, 213 base::Bind(&base::DoNothing), 214 NULL); 215 } else { 216 ApplyEdits(); 217 } 218} 219 220bool BookmarkAppBubbleView::AcceleratorPressed( 221 const ui::Accelerator& accelerator) { 222 if (accelerator.key_code() == ui::VKEY_RETURN) { 223 HandleButtonPressed(add_button_); 224 } 225 226 return BubbleDelegateView::AcceleratorPressed(accelerator); 227} 228 229gfx::Size BookmarkAppBubbleView::GetMinimumSize() const { 230 gfx::Size size(views::BubbleDelegateView::GetPreferredSize()); 231 size.SetToMax(gfx::Size(kMinBubbleWidth, 0)); 232 return size; 233} 234 235void BookmarkAppBubbleView::ButtonPressed(views::Button* sender, 236 const ui::Event& event) { 237 HandleButtonPressed(sender); 238} 239 240void BookmarkAppBubbleView::SetAppImage(const std::string& id, 241 const gfx::ImageSkia& image) { 242 DCHECK_EQ(extension_id_, id); 243 icon_image_view_->SetImage(image); 244} 245 246void BookmarkAppBubbleView::HandleButtonPressed(views::Button* sender) { 247 // Unset |remove_app_| so we don't delete the bookmark after the window 248 // closes. 249 if (sender == add_button_) 250 remove_app_ = false; 251 252 GetWidget()->Close(); 253} 254 255void BookmarkAppBubbleView::ApplyEdits() { 256 // Set the launch type based on the checkbox. 257 extensions::LaunchType launch_type = open_as_tab_checkbox_->checked() 258 ? extensions::LAUNCH_TYPE_REGULAR 259 : extensions::LAUNCH_TYPE_WINDOW; 260 profile_->GetPrefs()->SetInteger( 261 extensions::pref_names::kBookmarkAppCreationLaunchType, launch_type); 262 extensions::SetLaunchType(GetExtensionService(profile_), 263 extension_id_, 264 launch_type); 265 266 const extensions::Extension* extension = 267 extensions::ExtensionRegistry::Get(profile_)->GetExtensionById( 268 extension_id_, extensions::ExtensionRegistry::EVERYTHING); 269 if (extension && base::UTF8ToUTF16(extension->name()) == title_tf_->text()) 270 return; 271 272 // Reinstall the app with an updated name. 273 WebApplicationInfo install_info(web_app_info_); 274 install_info.title = title_tf_->text(); 275 276 extensions::CreateOrUpdateBookmarkApp(GetExtensionService(profile_), 277 install_info); 278} 279