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