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.
5 #include "chrome/browser/ui/views/extensions/media_galleries_dialog_views.h"
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"
32 using web_modal::WebContentsModalDialogManager
;
33 using web_modal::WebContentsModalDialogManagerDelegate
;
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 typedef MediaGalleriesDialogController::GalleryPermissionsVector
70 GalleryPermissionsVector
;
72 MediaGalleriesDialogViews::MediaGalleriesDialogViews(
73 MediaGalleriesDialogController
* controller
)
74 : controller_(controller
),
76 contents_(new views::View()),
77 add_gallery_button_(NULL
),
78 confirm_available_(false),
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());
96 MediaGalleriesDialogViews::~MediaGalleriesDialogViews() {}
98 void 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
);
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
,
111 views::GridLayout::FIXED
,
112 dialog_content_width
,
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
);
122 views::GridLayout::FILL
, views::GridLayout::LEADING
,
123 dialog_content_width
, subtext
->GetHeightForWidth(dialog_content_width
));
124 layout
->AddPaddingRow(0, views::kRelatedControlVerticalSpacing
);
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
,
134 views::kRelatedControlVerticalSpacing
,
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
) {
144 if (iter
+ 1 == permissions
.end())
145 spacing
= views::kRelatedControlSmallVerticalSpacing
;
146 AddOrUpdateGallery(iter
->pref_info
, iter
->allowed
, scroll_container
,
150 GalleryPermissionsVector unattached_permissions
=
151 controller_
->UnattachedPermissions();
153 if (!unattached_permissions
.empty()) {
155 views::Separator
* separator
= new views::Separator(
156 views::Separator::HORIZONTAL
);
157 scroll_container
->AddChildView(separator
);
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
,
169 scroll_container
->AddChildView(unattached_text
);
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);
179 confirm_available_
= controller_
->HasPermittedGalleries();
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
);
193 void MediaGalleriesDialogViews::UpdateGalleries() {
198 bool MediaGalleriesDialogViews::AddOrUpdateGallery(
199 const MediaGalleryPrefInfo
& gallery
,
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();
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
);
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(
237 views::kRelatedControlSmallHorizontalSpacing
,
239 views::kRelatedControlSmallHorizontalSpacing
));
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(
246 views::kPanelHorizMargin
,
247 trailing_vertical_space
,
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
);
254 container
->AddChildView(checkbox_view
);
256 checkbox
->SetChecked(permitted
);
257 if (gallery
.pref_id
!= kInvalidMediaGalleryPrefId
)
258 checkbox_map_
[gallery
.pref_id
] = checkbox
;
260 new_checkbox_map_
[checkbox
] = gallery
;
265 base::string16
MediaGalleriesDialogViews::GetWindowTitle() const {
266 return controller_
->GetHeader();
269 void MediaGalleriesDialogViews::DeleteDelegate() {
270 controller_
->DialogFinished(accepted_
);
273 views::Widget
* MediaGalleriesDialogViews::GetWidget() {
274 return contents_
->GetWidget();
277 const views::Widget
* MediaGalleriesDialogViews::GetWidget() const {
278 return contents_
->GetWidget();
281 views::View
* MediaGalleriesDialogViews::GetContentsView() {
285 base::string16
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
);
292 bool MediaGalleriesDialogViews::IsDialogButtonEnabled(
293 ui::DialogButton button
) const {
294 return button
!= ui::DIALOG_BUTTON_OK
|| confirm_available_
;
297 ui::ModalType
MediaGalleriesDialogViews::GetModalType() const {
299 return ui::MODAL_TYPE_CHILD
;
301 return views::WidgetDelegate::GetModalType();
305 views::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_BUTTON
);
310 return add_gallery_button_
;
313 bool MediaGalleriesDialogViews::Cancel() {
317 bool MediaGalleriesDialogViews::Accept() {
323 // TODO(wittman): Remove this override once we move to the new style frame view
325 views::NonClientFrameView
* MediaGalleriesDialogViews::CreateNonClientFrameView(
326 views::Widget
* widget
) {
327 return CreateConstrainedStyleNonClientFrameView(
329 controller_
->web_contents()->GetBrowserContext());
332 void MediaGalleriesDialogViews::ButtonPressed(views::Button
* sender
,
333 const ui::Event
& event
) {
334 confirm_available_
= true;
335 GetWidget()->client_view()->AsDialogClientView()->UpdateDialogButtons();
337 if (sender
== add_gallery_button_
) {
338 controller_
->OnAddFolderClicked();
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());
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());
358 void MediaGalleriesDialogViews::ShowContextMenuForView(
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
);
371 void 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
)));
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
) {
386 // MediaGalleriesDialogViewsController -----------------------------------------
389 MediaGalleriesDialog
* MediaGalleriesDialog::Create(
390 MediaGalleriesDialogController
* controller
) {
391 return new MediaGalleriesDialogViews(controller
);