media_galleries_dialog_views.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
1// Copyright (c) 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#include "chrome/browser/ui/views/extensions/media_galleries_dialog_views.h" 6 7#include "base/strings/utf_string_conversions.h" 8#include "chrome/browser/ui/views/constrained_window_views.h" 9#include "components/web_modal/web_contents_modal_dialog_host.h" 10#include "components/web_modal/web_contents_modal_dialog_manager.h" 11#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" 12#include "content/public/browser/web_contents.h" 13#include "content/public/browser/web_contents_view.h" 14#include "grit/generated_resources.h" 15#include "grit/locale_settings.h" 16#include "third_party/skia/include/core/SkColor.h" 17#include "ui/base/l10n/l10n_util.h" 18#include "ui/base/resource/resource_bundle.h" 19#include "ui/native_theme/native_theme.h" 20#include "ui/views/controls/button/checkbox.h" 21#include "ui/views/controls/button/label_button.h" 22#include "ui/views/controls/label.h" 23#include "ui/views/controls/menu/menu_runner.h" 24#include "ui/views/controls/scroll_view.h" 25#include "ui/views/controls/separator.h" 26#include "ui/views/layout/box_layout.h" 27#include "ui/views/layout/grid_layout.h" 28#include "ui/views/layout/layout_constants.h" 29#include "ui/views/view.h" 30#include "ui/views/widget/widget.h" 31#include "ui/views/window/dialog_client_view.h" 32 33using web_modal::WebContentsModalDialogManager; 34using web_modal::WebContentsModalDialogManagerDelegate; 35 36namespace { 37 38// Equal to the #969696 color used in spec (note WebUI color is #999). 39const SkColor kDeemphasizedTextColor = SkColorSetRGB(159, 159, 159); 40 41const int kScrollAreaHeight = 192; 42 43// This container has the right Layout() impl to use within a ScrollView. 44class ScrollableView : public views::View { 45 public: 46 ScrollableView() {} 47 virtual ~ScrollableView() {} 48 49 virtual void Layout() OVERRIDE; 50 51 private: 52 DISALLOW_COPY_AND_ASSIGN(ScrollableView); 53}; 54 55void ScrollableView::Layout() { 56 gfx::Size pref = GetPreferredSize(); 57 int width = pref.width(); 58 int height = pref.height(); 59 if (parent()) { 60 width = std::max(parent()->width(), width); 61 height = std::max(parent()->height(), height); 62 } 63 SetBounds(x(), y(), width, height); 64 65 views::View::Layout(); 66} 67 68} // namespace 69 70typedef MediaGalleriesDialogController::GalleryPermissionsVector 71 GalleryPermissionsVector; 72 73MediaGalleriesDialogViews::MediaGalleriesDialogViews( 74 MediaGalleriesDialogController* controller) 75 : controller_(controller), 76 window_(NULL), 77 contents_(new views::View()), 78 add_gallery_button_(NULL), 79 confirm_available_(false), 80 accepted_(false) { 81 InitChildViews(); 82 83 // Ownership of |contents_| is handed off by this call. |window_| will take 84 // care of deleting itself after calling DeleteDelegate(). 85 WebContentsModalDialogManager* web_contents_modal_dialog_manager = 86 WebContentsModalDialogManager::FromWebContents( 87 controller->web_contents()); 88 DCHECK(web_contents_modal_dialog_manager); 89 WebContentsModalDialogManagerDelegate* modal_delegate = 90 web_contents_modal_dialog_manager->delegate(); 91 DCHECK(modal_delegate); 92 window_ = views::Widget::CreateWindowAsFramelessChild( 93 this, 94 controller->web_contents()->GetView()->GetNativeView(), 95 modal_delegate->GetWebContentsModalDialogHost()->GetHostView()); 96 web_contents_modal_dialog_manager->ShowDialog(window_->GetNativeView()); 97} 98 99MediaGalleriesDialogViews::~MediaGalleriesDialogViews() {} 100 101void MediaGalleriesDialogViews::InitChildViews() { 102 // Outer dialog layout. 103 contents_->RemoveAllChildViews(true); 104 int dialog_content_width = views::Widget::GetLocalizedContentsWidth( 105 IDS_MEDIA_GALLERIES_DIALOG_CONTENT_WIDTH_CHARS); 106 views::GridLayout* layout = views::GridLayout::CreatePanel(contents_); 107 contents_->SetLayoutManager(layout); 108 109 int column_set_id = 0; 110 views::ColumnSet* columns = layout->AddColumnSet(column_set_id); 111 columns->AddColumn(views::GridLayout::LEADING, 112 views::GridLayout::LEADING, 113 1, 114 views::GridLayout::FIXED, 115 dialog_content_width, 116 0); 117 118 if (!DialogDelegate::UseNewStyle()) { 119 // Header text. 120 views::Label* header = new views::Label(controller_->GetHeader()); 121 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 122 header->SetFont(rb.GetFont(ui::ResourceBundle::MediumFont)); 123 header->SetHorizontalAlignment(gfx::ALIGN_LEFT); 124 layout->StartRow(0, column_set_id); 125 layout->AddView(header); 126 } 127 128 // Message text. 129 views::Label* subtext = new views::Label(controller_->GetSubtext()); 130 subtext->SetMultiLine(true); 131 subtext->SetHorizontalAlignment(gfx::ALIGN_LEFT); 132 layout->StartRow(0, column_set_id); 133 layout->AddView( 134 subtext, 1, 1, 135 views::GridLayout::FILL, views::GridLayout::LEADING, 136 dialog_content_width, subtext->GetHeightForWidth(dialog_content_width)); 137 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 138 139 // Scrollable area for checkboxes. 140 ScrollableView* scroll_container = new ScrollableView(); 141 scroll_container->SetLayoutManager(new views::BoxLayout( 142 views::BoxLayout::kVertical, 0, 0, 143 views::kRelatedControlSmallVerticalSpacing)); 144 scroll_container->set_border(views::Border::CreateEmptyBorder( 145 views::kRelatedControlVerticalSpacing, 146 0, 147 views::kRelatedControlVerticalSpacing, 148 0)); 149 150 // Add attached galleries checkboxes. 151 checkbox_map_.clear(); 152 new_checkbox_map_.clear(); 153 GalleryPermissionsVector permissions = controller_->AttachedPermissions(); 154 for (GalleryPermissionsVector::const_iterator iter = permissions.begin(); 155 iter != permissions.end(); ++iter) { 156 int spacing = 0; 157 if (iter + 1 == permissions.end()) 158 spacing = views::kRelatedControlSmallVerticalSpacing; 159 AddOrUpdateGallery(iter->pref_info, iter->allowed, scroll_container, 160 spacing); 161 } 162 163 GalleryPermissionsVector unattached_permissions = 164 controller_->UnattachedPermissions(); 165 166 if (!unattached_permissions.empty()) { 167 // Separator line. 168 views::Separator* separator = new views::Separator( 169 views::Separator::HORIZONTAL); 170 scroll_container->AddChildView(separator); 171 172 // Unattached locations section. 173 views::Label* unattached_text = new views::Label( 174 controller_->GetUnattachedLocationsHeader()); 175 unattached_text->SetMultiLine(true); 176 unattached_text->SetHorizontalAlignment(gfx::ALIGN_LEFT); 177 unattached_text->set_border(views::Border::CreateEmptyBorder( 178 views::kRelatedControlVerticalSpacing, 179 views::kPanelHorizMargin, 180 views::kRelatedControlVerticalSpacing, 181 0)); 182 scroll_container->AddChildView(unattached_text); 183 184 // Add unattached galleries checkboxes. 185 for (GalleryPermissionsVector::const_iterator iter = 186 unattached_permissions.begin(); 187 iter != unattached_permissions.end(); ++iter) { 188 AddOrUpdateGallery(iter->pref_info, iter->allowed, scroll_container, 0); 189 } 190 } 191 192 confirm_available_ = controller_->HasPermittedGalleries(); 193 194 // Add the scrollable area to the outer dialog view. It will squeeze against 195 // the title/subtitle and buttons to occupy all available space in the dialog. 196 views::ScrollView* scroll_view = 197 views::ScrollView::CreateScrollViewWithBorder(); 198 scroll_view->SetContents(scroll_container); 199 layout->StartRowWithPadding(1, column_set_id, 200 0, views::kRelatedControlVerticalSpacing); 201 layout->AddView(scroll_view, 1, 1, 202 views::GridLayout::FILL, views::GridLayout::FILL, 203 dialog_content_width, kScrollAreaHeight); 204} 205 206void MediaGalleriesDialogViews::UpdateGalleries() { 207 InitChildViews(); 208 contents_->Layout(); 209} 210 211bool MediaGalleriesDialogViews::AddOrUpdateGallery( 212 const MediaGalleryPrefInfo& gallery, 213 bool permitted, 214 views::View* container, 215 int trailing_vertical_space) { 216 string16 label = gallery.GetGalleryDisplayName(); 217 string16 tooltip_text = gallery.GetGalleryTooltip(); 218 string16 details = gallery.GetGalleryAdditionalDetails(); 219 220 CheckboxMap::iterator iter = checkbox_map_.find(gallery.pref_id); 221 if (iter != checkbox_map_.end() && 222 gallery.pref_id != kInvalidMediaGalleryPrefId) { 223 views::Checkbox* checkbox = iter->second; 224 checkbox->SetChecked(permitted); 225 checkbox->SetText(label); 226 checkbox->SetElideBehavior(views::Label::ELIDE_IN_MIDDLE); 227 checkbox->SetTooltipText(tooltip_text); 228 // Replace the details string. 229 views::View* checkbox_view = checkbox->parent(); 230 DCHECK_EQ(2, checkbox_view->child_count()); 231 views::Label* secondary_text = 232 static_cast<views::Label*>(checkbox_view->child_at(1)); 233 secondary_text->SetText(details); 234 return false; 235 } 236 237 views::Checkbox* checkbox = new views::Checkbox(label); 238 checkbox->set_listener(this); 239 if (gallery.pref_id != kInvalidMediaGalleryPrefId) 240 checkbox->set_context_menu_controller(this); 241 checkbox->SetTooltipText(tooltip_text); 242 views::Label* secondary_text = new views::Label(details); 243 if (gallery.pref_id != kInvalidMediaGalleryPrefId) 244 secondary_text->set_context_menu_controller(this); 245 secondary_text->SetTooltipText(tooltip_text); 246 secondary_text->SetEnabledColor(kDeemphasizedTextColor); 247 secondary_text->SetTooltipText(tooltip_text); 248 secondary_text->set_border(views::Border::CreateEmptyBorder( 249 0, 250 views::kRelatedControlSmallHorizontalSpacing, 251 0, 252 views::kRelatedControlSmallHorizontalSpacing)); 253 254 views::View* checkbox_view = new views::View(); 255 if (gallery.pref_id != kInvalidMediaGalleryPrefId) 256 checkbox_view->set_context_menu_controller(this); 257 checkbox_view->set_border(views::Border::CreateEmptyBorder( 258 0, 259 views::kPanelHorizMargin, 260 trailing_vertical_space, 261 0)); 262 checkbox_view->SetLayoutManager( 263 new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0)); 264 checkbox_view->AddChildView(checkbox); 265 checkbox_view->AddChildView(secondary_text); 266 267 container->AddChildView(checkbox_view); 268 269 checkbox->SetChecked(permitted); 270 if (gallery.pref_id != kInvalidMediaGalleryPrefId) 271 checkbox_map_[gallery.pref_id] = checkbox; 272 else 273 new_checkbox_map_[checkbox] = gallery; 274 275 return true; 276} 277 278string16 MediaGalleriesDialogViews::GetWindowTitle() const { 279 return controller_->GetHeader(); 280} 281 282bool MediaGalleriesDialogViews::ShouldShowWindowTitle() const { 283 return DialogDelegate::UseNewStyle(); 284} 285 286void MediaGalleriesDialogViews::DeleteDelegate() { 287 controller_->DialogFinished(accepted_); 288} 289 290views::Widget* MediaGalleriesDialogViews::GetWidget() { 291 return contents_->GetWidget(); 292} 293 294const views::Widget* MediaGalleriesDialogViews::GetWidget() const { 295 return contents_->GetWidget(); 296} 297 298views::View* MediaGalleriesDialogViews::GetContentsView() { 299 return contents_; 300} 301 302string16 MediaGalleriesDialogViews::GetDialogButtonLabel( 303 ui::DialogButton button) const { 304 return l10n_util::GetStringUTF16(button == ui::DIALOG_BUTTON_OK ? 305 IDS_MEDIA_GALLERIES_DIALOG_CONFIRM : 306 IDS_MEDIA_GALLERIES_DIALOG_CANCEL); 307} 308 309bool MediaGalleriesDialogViews::IsDialogButtonEnabled( 310 ui::DialogButton button) const { 311 return button != ui::DIALOG_BUTTON_OK || confirm_available_; 312} 313 314ui::ModalType MediaGalleriesDialogViews::GetModalType() const { 315#if defined(USE_ASH) 316 return ui::MODAL_TYPE_CHILD; 317#else 318 return views::WidgetDelegate::GetModalType(); 319#endif 320} 321 322views::View* MediaGalleriesDialogViews::CreateExtraView() { 323 DCHECK(!add_gallery_button_); 324 add_gallery_button_ = new views::LabelButton(this, 325 l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_DIALOG_ADD_GALLERY)); 326 add_gallery_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON); 327 return add_gallery_button_; 328} 329 330bool MediaGalleriesDialogViews::Cancel() { 331 return true; 332} 333 334bool MediaGalleriesDialogViews::Accept() { 335 accepted_ = true; 336 337 return true; 338} 339 340// TODO(wittman): Remove this override once we move to the new style frame view 341// on all dialogs. 342views::NonClientFrameView* MediaGalleriesDialogViews::CreateNonClientFrameView( 343 views::Widget* widget) { 344 return CreateConstrainedStyleNonClientFrameView( 345 widget, 346 controller_->web_contents()->GetBrowserContext()); 347} 348 349void MediaGalleriesDialogViews::ButtonPressed(views::Button* sender, 350 const ui::Event& event) { 351 confirm_available_ = true; 352 GetWidget()->client_view()->AsDialogClientView()->UpdateDialogButtons(); 353 354 if (sender == add_gallery_button_) { 355 controller_->OnAddFolderClicked(); 356 return; 357 } 358 359 for (CheckboxMap::const_iterator iter = checkbox_map_.begin(); 360 iter != checkbox_map_.end(); ++iter) { 361 if (sender == iter->second) { 362 controller_->DidToggleGalleryId(iter->first, 363 iter->second->checked()); 364 return; 365 } 366 } 367 for (NewCheckboxMap::const_iterator iter = new_checkbox_map_.begin(); 368 iter != new_checkbox_map_.end(); ++iter) { 369 if (sender == iter->first) { 370 controller_->DidToggleNewGallery(iter->second, iter->first->checked()); 371 } 372 } 373} 374 375void MediaGalleriesDialogViews::ShowContextMenuForView( 376 views::View* source, 377 const gfx::Point& point, 378 ui::MenuSourceType source_type) { 379 for (CheckboxMap::const_iterator iter = checkbox_map_.begin(); 380 iter != checkbox_map_.end(); ++iter) { 381 if (iter->second->parent()->Contains(source)) { 382 ShowContextMenu(point, source_type, iter->first); 383 return; 384 } 385 } 386} 387 388void MediaGalleriesDialogViews::ShowContextMenu(const gfx::Point& point, 389 ui::MenuSourceType source_type, 390 MediaGalleryPrefId id) { 391 context_menu_runner_.reset(new views::MenuRunner( 392 controller_->GetContextMenuModel(id))); 393 394 if (context_menu_runner_->RunMenuAt( 395 GetWidget(), NULL, gfx::Rect(point.x(), point.y(), 0, 0), 396 views::MenuItemView::TOPLEFT, source_type, 397 views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU) == 398 views::MenuRunner::MENU_DELETED) { 399 return; 400 } 401} 402 403// MediaGalleriesDialogViewsController ----------------------------------------- 404 405// static 406MediaGalleriesDialog* MediaGalleriesDialog::Create( 407 MediaGalleriesDialogController* controller) { 408 return new MediaGalleriesDialogViews(controller); 409} 410