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