blob: 763eaf5a182cd638fafd6b0ccea22d846119b4dd [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/extensions/media_galleries_dialog_views.h"
#include <stddef.h>
#include "base/bind.h"
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/browser/ui/views/extensions/media_gallery_checkbox_view.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/grit/locale_settings.h"
#include "components/constrained_window/constrained_window_views.h"
#include "components/web_modal/web_contents_modal_dialog_manager.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/controls/separator.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/view.h"
namespace {
const int kScrollAreaHeight = 192;
// This container has the right Layout() impl to use within a ScrollView.
class ScrollableView : public views::View {
public:
ScrollableView() {}
~ScrollableView() override {}
void Layout() override;
private:
DISALLOW_COPY_AND_ASSIGN(ScrollableView);
};
void ScrollableView::Layout() {
gfx::Size pref = GetPreferredSize();
int width = pref.width();
int height = pref.height();
if (parent()) {
width = parent()->width();
height = std::max(parent()->height(), height);
}
SetBounds(x(), y(), width, height);
views::View::Layout();
}
} // namespace
MediaGalleriesDialogViews::MediaGalleriesDialogViews(
MediaGalleriesDialogController* controller)
: controller_(controller),
contents_(new views::View()),
auxiliary_button_(NULL),
confirm_available_(false),
accepted_(false) {
InitChildViews();
if (ControllerHasWebContents()) {
constrained_window::ShowWebModalDialogViews(this,
controller->WebContents());
}
chrome::RecordDialogCreation(chrome::DialogIdentifier::MEDIA_GALLERIES);
}
MediaGalleriesDialogViews::~MediaGalleriesDialogViews() {
if (!ControllerHasWebContents())
delete contents_;
}
void MediaGalleriesDialogViews::AcceptDialogForTesting() {
accepted_ = true;
web_modal::WebContentsModalDialogManager* manager =
web_modal::WebContentsModalDialogManager::FromWebContents(
controller_->WebContents());
DCHECK(manager);
web_modal::WebContentsModalDialogManager::TestApi(manager).CloseAllDialogs();
}
void MediaGalleriesDialogViews::InitChildViews() {
// Outer dialog layout.
contents_->RemoveAllChildViews(true);
checkbox_map_.clear();
ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
contents_->SetBorder(views::CreateEmptyBorder(
provider->GetDialogInsetsForContentType(views::TEXT, views::CONTROL)));
const int dialog_content_width = views::Widget::GetLocalizedContentsWidth(
IDS_MEDIA_GALLERIES_DIALOG_CONTENT_WIDTH_CHARS);
views::GridLayout* layout = contents_->SetLayoutManager(
std::make_unique<views::GridLayout>(contents_));
int column_set_id = 0;
views::ColumnSet* columns = layout->AddColumnSet(column_set_id);
columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::LEADING,
1.0, views::GridLayout::FIXED, dialog_content_width, 0);
// Message text.
const int vertical_padding =
provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL);
views::Label* subtext = new views::Label(controller_->GetSubtext());
subtext->SetMultiLine(true);
subtext->SetHorizontalAlignment(gfx::ALIGN_LEFT);
layout->StartRow(views::GridLayout::kFixedSize, column_set_id);
layout->AddView(
subtext, 1, 1,
views::GridLayout::FILL, views::GridLayout::LEADING,
dialog_content_width, subtext->GetHeightForWidth(dialog_content_width));
layout->AddPaddingRow(views::GridLayout::kFixedSize, vertical_padding);
// Scrollable area for checkboxes.
const int small_vertical_padding =
provider->GetDistanceMetric(DISTANCE_RELATED_CONTROL_VERTICAL_SMALL);
auto scroll_container = std::make_unique<ScrollableView>();
scroll_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::kVertical, gfx::Insets(), small_vertical_padding));
scroll_container->SetBorder(
views::CreateEmptyBorder(vertical_padding, 0, vertical_padding, 0));
std::vector<base::string16> section_headers =
controller_->GetSectionHeaders();
for (size_t i = 0; i < section_headers.size(); i++) {
MediaGalleriesDialogController::Entries entries =
controller_->GetSectionEntries(i);
// Header and separator line.
if (!section_headers[i].empty() && !entries.empty()) {
views::Separator* separator = new views::Separator();
scroll_container->AddChildView(separator);
views::Label* header = new views::Label(section_headers[i]);
header->SetMultiLine(true);
header->SetHorizontalAlignment(gfx::ALIGN_LEFT);
header->SetBorder(views::CreateEmptyBorder(
vertical_padding,
provider->GetInsetsMetric(views::INSETS_DIALOG).left(),
vertical_padding, 0));
scroll_container->AddChildView(header);
}
// Checkboxes.
MediaGalleriesDialogController::Entries::const_iterator iter;
for (iter = entries.begin(); iter != entries.end(); ++iter) {
int spacing = iter + 1 == entries.end() ? small_vertical_padding : 0;
AddOrUpdateGallery(*iter, scroll_container.get(), spacing);
}
}
confirm_available_ = controller_->IsAcceptAllowed();
// Add the scrollable area to the outer dialog view. It will squeeze against
// the title/subtitle and buttons to occupy all available space in the dialog.
auto* scroll_view = views::ScrollView::CreateScrollViewWithBorder();
scroll_view->SetContents(std::move(scroll_container));
layout->StartRowWithPadding(1.0, column_set_id, views::GridLayout::kFixedSize,
vertical_padding);
layout->AddView(scroll_view, 1.0, 1.0, views::GridLayout::FILL,
views::GridLayout::FILL, dialog_content_width,
kScrollAreaHeight);
}
void MediaGalleriesDialogViews::UpdateGalleries() {
InitChildViews();
contents_->Layout();
if (ControllerHasWebContents())
DialogModelChanged();
}
bool MediaGalleriesDialogViews::AddOrUpdateGallery(
const MediaGalleriesDialogController::Entry& gallery,
views::View* container,
int trailing_vertical_space) {
auto iter = checkbox_map_.find(gallery.pref_info.pref_id);
if (iter != checkbox_map_.end()) {
views::Checkbox* checkbox = iter->second->checkbox();
checkbox->SetChecked(gallery.selected);
checkbox->SetText(gallery.pref_info.GetGalleryDisplayName());
checkbox->SetTooltipText(gallery.pref_info.GetGalleryTooltip());
base::string16 details = gallery.pref_info.GetGalleryAdditionalDetails();
iter->second->secondary_text()->SetText(details);
iter->second->secondary_text()->SetVisible(details.length() > 0);
return false;
}
MediaGalleryCheckboxView* gallery_view = new MediaGalleryCheckboxView(
gallery.pref_info, trailing_vertical_space, this, this);
gallery_view->checkbox()->SetChecked(gallery.selected);
container->AddChildView(gallery_view);
checkbox_map_[gallery.pref_info.pref_id] = gallery_view;
return true;
}
base::string16 MediaGalleriesDialogViews::GetWindowTitle() const {
return controller_->GetHeader();
}
bool MediaGalleriesDialogViews::ShouldShowCloseButton() const {
return false;
}
void MediaGalleriesDialogViews::DeleteDelegate() {
controller_->DialogFinished(accepted_);
}
views::Widget* MediaGalleriesDialogViews::GetWidget() {
return contents_->GetWidget();
}
const views::Widget* MediaGalleriesDialogViews::GetWidget() const {
return contents_->GetWidget();
}
views::View* MediaGalleriesDialogViews::GetContentsView() {
return contents_;
}
base::string16 MediaGalleriesDialogViews::GetDialogButtonLabel(
ui::DialogButton button) const {
if (button == ui::DIALOG_BUTTON_OK)
return controller_->GetAcceptButtonText();
return l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_DIALOG_CANCEL);
}
bool MediaGalleriesDialogViews::IsDialogButtonEnabled(
ui::DialogButton button) const {
return button != ui::DIALOG_BUTTON_OK || confirm_available_;
}
ui::ModalType MediaGalleriesDialogViews::GetModalType() const {
return ui::MODAL_TYPE_CHILD;
}
views::View* MediaGalleriesDialogViews::CreateExtraView() {
DCHECK(!auxiliary_button_);
base::string16 button_label = controller_->GetAuxiliaryButtonText();
if (!button_label.empty()) {
auxiliary_button_ =
views::MdTextButton::CreateSecondaryUiButton(this, button_label);
}
return auxiliary_button_;
}
bool MediaGalleriesDialogViews::Cancel() {
return true;
}
bool MediaGalleriesDialogViews::Accept() {
accepted_ = true;
return true;
}
void MediaGalleriesDialogViews::ButtonPressed(views::Button* sender,
const ui::Event& /* event */) {
confirm_available_ = true;
if (ControllerHasWebContents())
DialogModelChanged();
if (sender == auxiliary_button_) {
controller_->DidClickAuxiliaryButton();
return;
}
for (CheckboxMap::const_iterator iter = checkbox_map_.begin();
iter != checkbox_map_.end(); ++iter) {
if (sender == iter->second->checkbox()) {
controller_->DidToggleEntry(iter->first,
iter->second->checkbox()->checked());
return;
}
}
}
void MediaGalleriesDialogViews::ShowContextMenuForViewImpl(
views::View* source,
const gfx::Point& point,
ui::MenuSourceType source_type) {
for (CheckboxMap::const_iterator iter = checkbox_map_.begin();
iter != checkbox_map_.end(); ++iter) {
if (iter->second->Contains(source)) {
ShowContextMenu(point, source_type, iter->first);
return;
}
}
}
void MediaGalleriesDialogViews::ShowContextMenu(const gfx::Point& point,
ui::MenuSourceType source_type,
MediaGalleryPrefId id) {
context_menu_runner_.reset(new views::MenuRunner(
controller_->GetContextMenu(id),
views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU,
base::BindRepeating(&MediaGalleriesDialogViews::OnMenuClosed,
base::Unretained(this))));
context_menu_runner_->RunMenuAt(
GetWidget(), NULL,
gfx::Rect(point.x(), point.y(), views::GridLayout::kFixedSize, 0),
views::MENU_ANCHOR_TOPLEFT, source_type);
}
bool MediaGalleriesDialogViews::ControllerHasWebContents() const {
return controller_->WebContents() != NULL;
}
void MediaGalleriesDialogViews::OnMenuClosed() {
context_menu_runner_.reset();
}
// MediaGalleriesDialogViewsController -----------------------------------------
// static
MediaGalleriesDialog* MediaGalleriesDialog::Create(
MediaGalleriesDialogController* controller) {
return new MediaGalleriesDialogViews(controller);
}