media_galleries_dialog_views.cc revision 3551c9c881056c480085172ff9840cab31610854
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 "content/public/browser/web_contents_view.h"
14#include "grit/generated_resources.h"
15#include "grit/locale_settings.h"
16#include "third_party/skia/include/core/SkColor.h"
17#include "ui/base/l10n/l10n_util.h"
18#include "ui/base/resource/resource_bundle.h"
19#include "ui/native_theme/native_theme.h"
20#include "ui/views/controls/button/checkbox.h"
21#include "ui/views/controls/button/label_button.h"
22#include "ui/views/controls/label.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
69namespace chrome {
70
71typedef MediaGalleriesDialogController::GalleryPermissionsVector
72    GalleryPermissionsVector;
73
74MediaGalleriesDialogViews::MediaGalleriesDialogViews(
75    MediaGalleriesDialogController* controller)
76    : controller_(controller),
77      window_(NULL),
78      contents_(new views::View()),
79      add_gallery_button_(NULL),
80      confirm_available_(false),
81      accepted_(false) {
82  InitChildViews();
83
84  // Ownership of |contents_| is handed off by this call. |window_| will take
85  // care of deleting itself after calling DeleteDelegate().
86  WebContentsModalDialogManager* web_contents_modal_dialog_manager =
87      WebContentsModalDialogManager::FromWebContents(
88          controller->web_contents());
89  DCHECK(web_contents_modal_dialog_manager);
90  WebContentsModalDialogManagerDelegate* modal_delegate =
91      web_contents_modal_dialog_manager->delegate();
92  DCHECK(modal_delegate);
93  window_ = views::Widget::CreateWindowAsFramelessChild(
94      this,
95      controller->web_contents()->GetView()->GetNativeView(),
96      modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
97  web_contents_modal_dialog_manager->ShowDialog(window_->GetNativeView());
98}
99
100MediaGalleriesDialogViews::~MediaGalleriesDialogViews() {}
101
102void MediaGalleriesDialogViews::InitChildViews() {
103  // Outer dialog layout.
104  contents_->RemoveAllChildViews(true);
105  int dialog_content_width = views::Widget::GetLocalizedContentsWidth(
106      IDS_MEDIA_GALLERIES_DIALOG_CONTENT_WIDTH_CHARS);
107  views::GridLayout* layout = views::GridLayout::CreatePanel(contents_);
108  contents_->SetLayoutManager(layout);
109
110  int column_set_id = 0;
111  views::ColumnSet* columns = layout->AddColumnSet(column_set_id);
112  columns->AddColumn(views::GridLayout::LEADING,
113                     views::GridLayout::LEADING,
114                     1,
115                     views::GridLayout::FIXED,
116                     dialog_content_width,
117                     0);
118
119  if (!DialogDelegate::UseNewStyle()) {
120    // Header text.
121    views::Label* header = new views::Label(controller_->GetHeader());
122    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
123    header->SetFont(rb.GetFont(ui::ResourceBundle::MediumFont));
124    header->SetHorizontalAlignment(gfx::ALIGN_LEFT);
125    layout->StartRow(0, column_set_id);
126    layout->AddView(header);
127  }
128
129  // Message text.
130  views::Label* subtext = new views::Label(controller_->GetSubtext());
131  subtext->SetMultiLine(true);
132  subtext->SetHorizontalAlignment(gfx::ALIGN_LEFT);
133  layout->StartRow(0, column_set_id);
134  layout->AddView(
135      subtext, 1, 1,
136      views::GridLayout::FILL, views::GridLayout::LEADING,
137      dialog_content_width, subtext->GetHeightForWidth(dialog_content_width));
138  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
139
140  // Scrollable area for checkboxes.
141  ScrollableView* scroll_container = new ScrollableView();
142  scroll_container->SetLayoutManager(new views::BoxLayout(
143      views::BoxLayout::kVertical, 0, 0,
144      views::kRelatedControlSmallVerticalSpacing));
145  scroll_container->set_border(views::Border::CreateEmptyBorder(
146      views::kRelatedControlVerticalSpacing,
147      0,
148      views::kRelatedControlVerticalSpacing,
149      0));
150
151  // Add attached galleries checkboxes.
152  checkbox_map_.clear();
153  GalleryPermissionsVector permissions = controller_->AttachedPermissions();
154  for (GalleryPermissionsVector::const_iterator iter = permissions.begin();
155       iter != permissions.end(); ++iter) {
156    int spacing = 0;
157    if (iter + 1 == permissions.end())
158      spacing = views::kRelatedControlSmallVerticalSpacing;
159    AddOrUpdateGallery(iter->pref_info, iter->allowed, scroll_container,
160                       spacing);
161  }
162
163  // Separator line.
164  views::Separator* separator = new views::Separator(
165      views::Separator::HORIZONTAL);
166  scroll_container->AddChildView(separator);
167
168  // Unattached locations section.
169  views::Label* unattached_text = new views::Label(
170      controller_->GetUnattachedLocationsHeader());
171  unattached_text->SetMultiLine(true);
172  unattached_text->SetHorizontalAlignment(gfx::ALIGN_LEFT);
173  unattached_text->set_border(views::Border::CreateEmptyBorder(
174      views::kRelatedControlVerticalSpacing,
175      views::kPanelHorizMargin,
176      views::kRelatedControlVerticalSpacing,
177      0));
178  scroll_container->AddChildView(unattached_text);
179
180  // Add unattached galleries checkboxes.
181  GalleryPermissionsVector unattached_permissions =
182      controller_->UnattachedPermissions();
183  for (GalleryPermissionsVector::const_iterator iter =
184           unattached_permissions.begin();
185       iter != unattached_permissions.end(); ++iter) {
186    AddOrUpdateGallery(iter->pref_info, iter->allowed, scroll_container, 0);
187  }
188
189  confirm_available_ = controller_->HasPermittedGalleries();
190
191  // Add the scrollable area to the outer dialog view. It will squeeze against
192  // the title/subtitle and buttons to occupy all available space in the dialog.
193  views::ScrollView* scroll_view =
194      views::ScrollView::CreateScrollViewWithBorder();
195  scroll_view->SetContents(scroll_container);
196  layout->StartRowWithPadding(1, column_set_id,
197                              0, views::kRelatedControlVerticalSpacing);
198  layout->AddView(scroll_view, 1, 1,
199                  views::GridLayout::FILL, views::GridLayout::FILL,
200                  dialog_content_width, kScrollAreaHeight);
201}
202
203void MediaGalleriesDialogViews::UpdateGallery(
204    const MediaGalleryPrefInfo& gallery,
205    bool permitted) {
206  InitChildViews();
207  contents_->Layout();
208}
209
210void MediaGalleriesDialogViews::ForgetGallery(MediaGalleryPrefId gallery) {
211  InitChildViews();
212  contents_->Layout();
213}
214
215bool MediaGalleriesDialogViews::AddOrUpdateGallery(
216    const MediaGalleryPrefInfo& gallery,
217    bool permitted,
218    views::View* container,
219    int trailing_vertical_space) {
220  string16 label = gallery.GetGalleryDisplayName();
221  string16 tooltip_text = gallery.GetGalleryTooltip();
222  string16 details = gallery.GetGalleryAdditionalDetails();
223
224  CheckboxMap::iterator iter = checkbox_map_.find(gallery.pref_id);
225  if (iter != checkbox_map_.end()) {
226    views::Checkbox* checkbox = iter->second;
227    checkbox->SetChecked(permitted);
228    checkbox->SetText(label);
229    checkbox->SetTooltipText(tooltip_text);
230    // Replace the details string.
231    views::View* checkbox_view = checkbox->parent();
232    DCHECK_EQ(2, checkbox_view->child_count());
233    views::Label* secondary_text =
234        static_cast<views::Label*>(checkbox_view->child_at(1));
235    secondary_text->SetText(details);
236
237    // Why is this returning false? Looks like that will mean it doesn't paint.
238    return false;
239  }
240
241  views::Checkbox* checkbox = new views::Checkbox(label);
242  checkbox->set_listener(this);
243  checkbox->SetTooltipText(tooltip_text);
244  views::Label* secondary_text = new views::Label(details);
245  secondary_text->SetTooltipText(tooltip_text);
246  secondary_text->SetEnabledColor(kDeemphasizedTextColor);
247  secondary_text->SetTooltipText(tooltip_text);
248  secondary_text->set_border(views::Border::CreateEmptyBorder(
249      0,
250      views::kRelatedControlSmallHorizontalSpacing,
251      0,
252      views::kRelatedControlSmallHorizontalSpacing));
253
254  views::View* checkbox_view = new views::View();
255  checkbox_view->set_border(views::Border::CreateEmptyBorder(
256      0,
257      views::kPanelHorizMargin,
258      trailing_vertical_space,
259      0));
260  checkbox_view->SetLayoutManager(
261      new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0));
262  checkbox_view->AddChildView(checkbox);
263  checkbox_view->AddChildView(secondary_text);
264
265  container->AddChildView(checkbox_view);
266
267  checkbox->SetChecked(permitted);
268  checkbox_map_[gallery.pref_id] = checkbox;
269
270  return true;
271}
272
273string16 MediaGalleriesDialogViews::GetWindowTitle() const {
274  return controller_->GetHeader();
275}
276
277bool MediaGalleriesDialogViews::ShouldShowWindowTitle() const {
278  return DialogDelegate::UseNewStyle();
279}
280
281void MediaGalleriesDialogViews::DeleteDelegate() {
282  controller_->DialogFinished(accepted_);
283}
284
285views::Widget* MediaGalleriesDialogViews::GetWidget() {
286  return contents_->GetWidget();
287}
288
289const views::Widget* MediaGalleriesDialogViews::GetWidget() const {
290  return contents_->GetWidget();
291}
292
293views::View* MediaGalleriesDialogViews::GetContentsView() {
294  return contents_;
295}
296
297string16 MediaGalleriesDialogViews::GetDialogButtonLabel(
298    ui::DialogButton button) const {
299  return l10n_util::GetStringUTF16(button == ui::DIALOG_BUTTON_OK ?
300      IDS_MEDIA_GALLERIES_DIALOG_CONFIRM :
301      IDS_MEDIA_GALLERIES_DIALOG_CANCEL);
302}
303
304bool MediaGalleriesDialogViews::IsDialogButtonEnabled(
305    ui::DialogButton button) const {
306  return button != ui::DIALOG_BUTTON_OK || confirm_available_;
307}
308
309ui::ModalType MediaGalleriesDialogViews::GetModalType() const {
310#if defined(USE_ASH)
311  return ui::MODAL_TYPE_CHILD;
312#else
313  return views::WidgetDelegate::GetModalType();
314#endif
315}
316
317views::View* MediaGalleriesDialogViews::CreateExtraView() {
318  DCHECK(!add_gallery_button_);
319  add_gallery_button_ = new views::LabelButton(this,
320      l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_DIALOG_ADD_GALLERY));
321  add_gallery_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
322  return add_gallery_button_;
323}
324
325bool MediaGalleriesDialogViews::Cancel() {
326  return true;
327}
328
329bool MediaGalleriesDialogViews::Accept() {
330  accepted_ = true;
331
332  return true;
333}
334
335// TODO(wittman): Remove this override once we move to the new style frame view
336// on all dialogs.
337views::NonClientFrameView* MediaGalleriesDialogViews::CreateNonClientFrameView(
338    views::Widget* widget) {
339  return CreateConstrainedStyleNonClientFrameView(
340      widget,
341      controller_->web_contents()->GetBrowserContext());
342}
343
344void MediaGalleriesDialogViews::ButtonPressed(views::Button* sender,
345                                              const ui::Event& event) {
346  confirm_available_ = true;
347  GetWidget()->client_view()->AsDialogClientView()->UpdateDialogButtons();
348
349  if (sender == add_gallery_button_) {
350    controller_->OnAddFolderClicked();
351    return;
352  }
353
354  for (CheckboxMap::const_iterator iter = checkbox_map_.begin();
355       iter != checkbox_map_.end(); ++iter) {
356    if (sender == iter->second) {
357      controller_->DidToggleGalleryId(iter->first,
358                                      iter->second->checked());
359      return;
360    }
361  }
362}
363
364// MediaGalleriesDialogViewsController -----------------------------------------
365
366// static
367MediaGalleriesDialog* MediaGalleriesDialog::Create(
368    MediaGalleriesDialogController* controller) {
369  return new MediaGalleriesDialogViews(controller);
370}
371
372}  // namespace chrome
373