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.
5 #include "chrome/browser/ui/views/extensions/media_galleries_scan_result_dialog_views.h"
7 #include "components/web_modal/web_contents_modal_dialog_host.h"
8 #include "components/web_modal/web_contents_modal_dialog_manager.h"
9 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
10 #include "content/public/browser/web_contents.h"
11 #include "grit/generated_resources.h"
12 #include "grit/locale_settings.h"
13 #include "grit/theme_resources.h"
14 #include "grit/ui_resources.h"
15 #include "third_party/skia/include/core/SkColor.h"
16 #include "ui/base/l10n/l10n_util.h"
17 #include "ui/base/resource/resource_bundle.h"
18 #include "ui/views/border.h"
19 #include "ui/views/controls/button/checkbox.h"
20 #include "ui/views/controls/button/image_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/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"
31 typedef MediaGalleriesScanResultDialogController::OrderedScanResults
36 // TODO(vandebo) move this to a common place.
37 // Equal to the #969696 color used in spec (note WebUI color is #999).
38 const SkColor kDeemphasizedTextColor = SkColorSetRGB(159, 159, 159);
40 const int kScrollAreaHeight = 192;
42 // This container has the right Layout() impl to use within a ScrollView.
43 class ScrollableView : public views::View {
46 virtual ~ScrollableView() {}
48 virtual void Layout() OVERRIDE;
51 DISALLOW_COPY_AND_ASSIGN(ScrollableView);
54 void ScrollableView::Layout() {
55 gfx::Size pref = GetPreferredSize();
56 int width = pref.width();
57 int height = pref.height();
59 width = std::max(parent()->width(), width);
60 height = std::max(parent()->height(), height);
62 SetBounds(x(), y(), width, height);
64 views::View::Layout();
69 MediaGalleriesScanResultDialogViews::MediaGalleriesScanResultDialogViews(
70 MediaGalleriesScanResultDialogController* controller)
71 : controller_(controller),
73 contents_(new views::View()),
77 // Ownership of |contents_| is handed off by this call. |window_| will take
78 // care of deleting itself after calling DeleteDelegate().
79 web_modal::WebContentsModalDialogManager* web_contents_modal_dialog_manager =
80 web_modal::WebContentsModalDialogManager::FromWebContents(
81 controller->web_contents());
82 DCHECK(web_contents_modal_dialog_manager);
83 web_modal::WebContentsModalDialogManagerDelegate* modal_delegate =
84 web_contents_modal_dialog_manager->delegate();
85 DCHECK(modal_delegate);
86 window_ = views::Widget::CreateWindowAsFramelessChild(
87 this, modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
88 web_contents_modal_dialog_manager->ShowDialog(window_->GetNativeView());
91 MediaGalleriesScanResultDialogViews::~MediaGalleriesScanResultDialogViews() {}
93 void MediaGalleriesScanResultDialogViews::InitChildViews() {
94 // Outer dialog layout.
95 contents_->RemoveAllChildViews(true);
96 int dialog_content_width = views::Widget::GetLocalizedContentsWidth(
97 IDS_MEDIA_GALLERIES_DIALOG_CONTENT_WIDTH_CHARS);
98 views::GridLayout* layout = views::GridLayout::CreatePanel(contents_);
99 contents_->SetLayoutManager(layout);
101 int column_set_id = 0;
102 views::ColumnSet* columns = layout->AddColumnSet(column_set_id);
103 columns->AddColumn(views::GridLayout::LEADING,
104 views::GridLayout::LEADING,
106 views::GridLayout::FIXED,
107 dialog_content_width,
111 views::Label* subtext = new views::Label(controller_->GetSubtext());
112 subtext->SetMultiLine(true);
113 subtext->SetHorizontalAlignment(gfx::ALIGN_LEFT);
114 layout->StartRow(0, column_set_id);
117 views::GridLayout::FILL, views::GridLayout::LEADING,
118 dialog_content_width, subtext->GetHeightForWidth(dialog_content_width));
119 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
121 // Scrollable area for checkboxes.
122 ScrollableView* scroll_container = new ScrollableView();
123 scroll_container->SetLayoutManager(new views::BoxLayout(
124 views::BoxLayout::kVertical, 0, 0,
125 views::kRelatedControlSmallVerticalSpacing));
126 scroll_container->SetBorder(views::Border::CreateEmptyBorder(
127 views::kRelatedControlVerticalSpacing,
129 views::kRelatedControlVerticalSpacing,
132 // Add attached galleries checkboxes.
133 gallery_view_map_.clear();
134 OrderedScanResults scan_results = controller_->GetGalleryList();
135 for (OrderedScanResults::const_iterator it = scan_results.begin();
136 it != scan_results.end();
139 if (it + 1 == scan_results.end())
140 spacing = views::kRelatedControlSmallVerticalSpacing;
141 AddOrUpdateScanResult(it->pref_info, it->selected, scroll_container,
145 // Add the scrollable area to the outer dialog view. It will squeeze against
146 // the title/subtitle and buttons to occupy all available space in the dialog.
147 views::ScrollView* scroll_view =
148 views::ScrollView::CreateScrollViewWithBorder();
149 scroll_view->SetContents(scroll_container);
150 layout->StartRowWithPadding(1, column_set_id,
151 0, views::kRelatedControlVerticalSpacing);
152 layout->AddView(scroll_view, 1, 1,
153 views::GridLayout::FILL, views::GridLayout::FILL,
154 dialog_content_width, kScrollAreaHeight);
157 void MediaGalleriesScanResultDialogViews::UpdateResults() {
162 bool MediaGalleriesScanResultDialogViews::AddOrUpdateScanResult(
163 const MediaGalleryPrefInfo& gallery,
165 views::View* container,
166 int trailing_vertical_space) {
167 base::string16 label = gallery.GetGalleryDisplayName();
168 base::string16 tooltip_text = gallery.GetGalleryTooltip();
169 base::string16 details = gallery.GetGalleryAdditionalDetails();
170 bool is_attached = gallery.IsGalleryAvailable();
172 GalleryViewMap::iterator it = gallery_view_map_.find(gallery.pref_id);
173 if (it != gallery_view_map_.end()) {
174 views::Checkbox* checkbox = it->second.checkbox;
175 checkbox->SetChecked(selected);
176 checkbox->SetText(label);
177 checkbox->SetElideBehavior(views::Label::ELIDE_IN_MIDDLE);
178 checkbox->SetTooltipText(tooltip_text);
179 // Replace the details string.
180 it->second.folder_viewer_button->SetVisible(is_attached);
181 it->second.secondary_text->SetText(details);
185 views::Checkbox* checkbox = new views::Checkbox(label);
186 checkbox->set_listener(this);
187 checkbox->set_context_menu_controller(this);
188 checkbox->SetTooltipText(tooltip_text);
190 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
191 views::ImageButton* folder_viewer_button = new views::ImageButton(this);
192 folder_viewer_button->set_context_menu_controller(this);
193 folder_viewer_button->SetImage(views::ImageButton::STATE_NORMAL,
194 rb.GetImageSkiaNamed(IDR_FILE_FOLDER));
195 folder_viewer_button->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
196 views::ImageButton::ALIGN_MIDDLE);
197 folder_viewer_button->SetAccessibleName(l10n_util::GetStringUTF16(
198 IDS_MEDIA_GALLERIES_SCAN_RESULT_OPEN_FOLDER_VIEW_ACCESSIBILITY_NAME));
199 folder_viewer_button->SetFocusable(true);
200 folder_viewer_button->SetVisible(is_attached);
202 views::Label* secondary_text = new views::Label(details);
203 secondary_text->set_context_menu_controller(this);
204 secondary_text->SetTooltipText(tooltip_text);
205 secondary_text->SetEnabledColor(kDeemphasizedTextColor);
206 secondary_text->SetTooltipText(tooltip_text);
207 secondary_text->SetBorder(views::Border::CreateEmptyBorder(
209 views::kRelatedControlSmallHorizontalSpacing,
211 views::kRelatedControlSmallHorizontalSpacing));
213 views::View* checkbox_view = new views::View();
214 checkbox_view->SetBorder(views::Border::CreateEmptyBorder(
215 0, views::kPanelHorizMargin, trailing_vertical_space, 0));
216 checkbox_view->set_context_menu_controller(this);
217 checkbox_view->SetLayoutManager(
218 new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0));
219 checkbox_view->AddChildView(checkbox);
220 checkbox_view->AddChildView(folder_viewer_button);
221 checkbox_view->AddChildView(secondary_text);
223 container->AddChildView(checkbox_view);
225 checkbox->SetChecked(selected);
226 gallery_view_map_[gallery.pref_id].checkbox = checkbox;
227 gallery_view_map_[gallery.pref_id].folder_viewer_button =
228 folder_viewer_button;
229 gallery_view_map_[gallery.pref_id].secondary_text = secondary_text;
234 base::string16 MediaGalleriesScanResultDialogViews::GetWindowTitle() const {
235 return controller_->GetHeader();
238 void MediaGalleriesScanResultDialogViews::DeleteDelegate() {
239 controller_->DialogFinished(accepted_);
242 views::Widget* MediaGalleriesScanResultDialogViews::GetWidget() {
243 return contents_->GetWidget();
246 const views::Widget* MediaGalleriesScanResultDialogViews::GetWidget() const {
247 return contents_->GetWidget();
250 views::View* MediaGalleriesScanResultDialogViews::GetContentsView() {
254 base::string16 MediaGalleriesScanResultDialogViews::GetDialogButtonLabel(
255 ui::DialogButton button) const {
256 return l10n_util::GetStringUTF16(button == ui::DIALOG_BUTTON_OK ?
257 IDS_MEDIA_GALLERIES_DIALOG_CONFIRM :
258 IDS_MEDIA_GALLERIES_DIALOG_CANCEL);
261 ui::ModalType MediaGalleriesScanResultDialogViews::GetModalType() const {
263 return ui::MODAL_TYPE_CHILD;
265 return views::WidgetDelegate::GetModalType();
269 bool MediaGalleriesScanResultDialogViews::Cancel() {
273 bool MediaGalleriesScanResultDialogViews::Accept() {
279 void MediaGalleriesScanResultDialogViews::ButtonPressed(
280 views::Button* sender,
281 const ui::Event& event) {
282 GetWidget()->client_view()->AsDialogClientView()->UpdateDialogButtons();
284 for (GalleryViewMap::const_iterator it = gallery_view_map_.begin();
285 it != gallery_view_map_.end(); ++it) {
286 if (sender == it->second.checkbox) {
287 controller_->DidToggleGalleryId(it->first,
288 it->second.checkbox->checked());
291 if (sender == it->second.folder_viewer_button) {
292 controller_->DidClickOpenFolderViewer(it->first);
298 void MediaGalleriesScanResultDialogViews::ShowContextMenuForView(
300 const gfx::Point& point,
301 ui::MenuSourceType source_type) {
302 for (GalleryViewMap::const_iterator it = gallery_view_map_.begin();
303 it != gallery_view_map_.end(); ++it) {
304 if (it->second.checkbox->parent()->Contains(source)) {
305 ShowContextMenu(point, source_type, it->first);
312 void MediaGalleriesScanResultDialogViews::ShowContextMenu(
313 const gfx::Point& point,
314 ui::MenuSourceType source_type,
315 MediaGalleryPrefId id) {
316 context_menu_runner_.reset(new views::MenuRunner(
317 controller_->GetContextMenu(id)));
319 if (context_menu_runner_->RunMenuAt(
320 GetWidget(), NULL, gfx::Rect(point.x(), point.y(), 0, 0),
321 views::MenuItemView::TOPLEFT, source_type,
322 views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU) ==
323 views::MenuRunner::MENU_DELETED) {
328 // MediaGalleriesScanResultDialogViewsController -------------------------------
331 MediaGalleriesScanResultDialog* MediaGalleriesScanResultDialog::Create(
332 MediaGalleriesScanResultDialogController* controller) {
333 return new MediaGalleriesScanResultDialogViews(controller);