media_galleries_dialog_views.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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
69typedef MediaGalleriesDialogController::GalleryPermissionsVector
70    GalleryPermissionsVector;
71
72MediaGalleriesDialogViews::MediaGalleriesDialogViews(
73    MediaGalleriesDialogController* controller)
74    : controller_(controller),
75      window_(NULL),
76      contents_(new views::View()),
77      add_gallery_button_(NULL),
78      confirm_available_(false),
79      accepted_(false) {
80  InitChildViews();
81
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,
93      controller->web_contents()->GetView()->GetNativeView(),
94      modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
95  web_contents_modal_dialog_manager->ShowDialog(window_->GetNativeView());
96  web_contents_modal_dialog_manager->SetCloseOnInterstitialWebUI(
97      window_->GetNativeView(), true);
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  GalleryPermissionsVector unattached_permissions =
164      controller_->UnattachedPermissions();
165
166  if (!unattached_permissions.empty()) {
167    // Separator line.
168    views::Separator* separator = new views::Separator(
169        views::Separator::HORIZONTAL);
170    scroll_container->AddChildView(separator);
171
172    // Unattached locations section.
173    views::Label* unattached_text = new views::Label(
174        controller_->GetUnattachedLocationsHeader());
175    unattached_text->SetMultiLine(true);
176    unattached_text->SetHorizontalAlignment(gfx::ALIGN_LEFT);
177    unattached_text->set_border(views::Border::CreateEmptyBorder(
178        views::kRelatedControlVerticalSpacing,
179        views::kPanelHorizMargin,
180        views::kRelatedControlVerticalSpacing,
181        0));
182    scroll_container->AddChildView(unattached_text);
183
184    // Add unattached galleries checkboxes.
185    for (GalleryPermissionsVector::const_iterator iter =
186             unattached_permissions.begin();
187         iter != unattached_permissions.end(); ++iter) {
188      AddOrUpdateGallery(iter->pref_info, iter->allowed, scroll_container, 0);
189    }
190  }
191
192  confirm_available_ = controller_->HasPermittedGalleries();
193
194  // Add the scrollable area to the outer dialog view. It will squeeze against
195  // the title/subtitle and buttons to occupy all available space in the dialog.
196  views::ScrollView* scroll_view =
197      views::ScrollView::CreateScrollViewWithBorder();
198  scroll_view->SetContents(scroll_container);
199  layout->StartRowWithPadding(1, column_set_id,
200                              0, views::kRelatedControlVerticalSpacing);
201  layout->AddView(scroll_view, 1, 1,
202                  views::GridLayout::FILL, views::GridLayout::FILL,
203                  dialog_content_width, kScrollAreaHeight);
204}
205
206void MediaGalleriesDialogViews::UpdateGallery(
207    const MediaGalleryPrefInfo& gallery,
208    bool permitted) {
209  InitChildViews();
210  contents_->Layout();
211}
212
213void MediaGalleriesDialogViews::ForgetGallery(MediaGalleryPrefId gallery) {
214  InitChildViews();
215  contents_->Layout();
216}
217
218bool MediaGalleriesDialogViews::AddOrUpdateGallery(
219    const MediaGalleryPrefInfo& gallery,
220    bool permitted,
221    views::View* container,
222    int trailing_vertical_space) {
223  string16 label = gallery.GetGalleryDisplayName();
224  string16 tooltip_text = gallery.GetGalleryTooltip();
225  string16 details = gallery.GetGalleryAdditionalDetails();
226
227  CheckboxMap::iterator iter = checkbox_map_.find(gallery.pref_id);
228  if (iter != checkbox_map_.end()) {
229    views::Checkbox* checkbox = iter->second;
230    checkbox->SetChecked(permitted);
231    checkbox->SetText(label);
232    checkbox->SetElideBehavior(views::Label::ELIDE_IN_MIDDLE);
233    checkbox->SetTooltipText(tooltip_text);
234    // Replace the details string.
235    views::View* checkbox_view = checkbox->parent();
236    DCHECK_EQ(2, checkbox_view->child_count());
237    views::Label* secondary_text =
238        static_cast<views::Label*>(checkbox_view->child_at(1));
239    secondary_text->SetText(details);
240
241    // Why is this returning false? Looks like that will mean it doesn't paint.
242    return false;
243  }
244
245  views::Checkbox* checkbox = new views::Checkbox(label);
246  checkbox->set_listener(this);
247  checkbox->SetTooltipText(tooltip_text);
248  views::Label* secondary_text = new views::Label(details);
249  secondary_text->SetTooltipText(tooltip_text);
250  secondary_text->SetEnabledColor(kDeemphasizedTextColor);
251  secondary_text->SetTooltipText(tooltip_text);
252  secondary_text->set_border(views::Border::CreateEmptyBorder(
253      0,
254      views::kRelatedControlSmallHorizontalSpacing,
255      0,
256      views::kRelatedControlSmallHorizontalSpacing));
257
258  views::View* checkbox_view = new views::View();
259  checkbox_view->set_border(views::Border::CreateEmptyBorder(
260      0,
261      views::kPanelHorizMargin,
262      trailing_vertical_space,
263      0));
264  checkbox_view->SetLayoutManager(
265      new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0));
266  checkbox_view->AddChildView(checkbox);
267  checkbox_view->AddChildView(secondary_text);
268
269  container->AddChildView(checkbox_view);
270
271  checkbox->SetChecked(permitted);
272  checkbox_map_[gallery.pref_id] = checkbox;
273
274  return true;
275}
276
277string16 MediaGalleriesDialogViews::GetWindowTitle() const {
278  return controller_->GetHeader();
279}
280
281bool MediaGalleriesDialogViews::ShouldShowWindowTitle() const {
282  return DialogDelegate::UseNewStyle();
283}
284
285void MediaGalleriesDialogViews::DeleteDelegate() {
286  controller_->DialogFinished(accepted_);
287}
288
289views::Widget* MediaGalleriesDialogViews::GetWidget() {
290  return contents_->GetWidget();
291}
292
293const views::Widget* MediaGalleriesDialogViews::GetWidget() const {
294  return contents_->GetWidget();
295}
296
297views::View* MediaGalleriesDialogViews::GetContentsView() {
298  return contents_;
299}
300
301string16 MediaGalleriesDialogViews::GetDialogButtonLabel(
302    ui::DialogButton button) const {
303  return l10n_util::GetStringUTF16(button == ui::DIALOG_BUTTON_OK ?
304      IDS_MEDIA_GALLERIES_DIALOG_CONFIRM :
305      IDS_MEDIA_GALLERIES_DIALOG_CANCEL);
306}
307
308bool MediaGalleriesDialogViews::IsDialogButtonEnabled(
309    ui::DialogButton button) const {
310  return button != ui::DIALOG_BUTTON_OK || confirm_available_;
311}
312
313ui::ModalType MediaGalleriesDialogViews::GetModalType() const {
314#if defined(USE_ASH)
315  return ui::MODAL_TYPE_CHILD;
316#else
317  return views::WidgetDelegate::GetModalType();
318#endif
319}
320
321views::View* MediaGalleriesDialogViews::CreateExtraView() {
322  DCHECK(!add_gallery_button_);
323  add_gallery_button_ = new views::LabelButton(this,
324      l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_DIALOG_ADD_GALLERY));
325  add_gallery_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
326  return add_gallery_button_;
327}
328
329bool MediaGalleriesDialogViews::Cancel() {
330  return true;
331}
332
333bool MediaGalleriesDialogViews::Accept() {
334  accepted_ = true;
335
336  return true;
337}
338
339// TODO(wittman): Remove this override once we move to the new style frame view
340// on all dialogs.
341views::NonClientFrameView* MediaGalleriesDialogViews::CreateNonClientFrameView(
342    views::Widget* widget) {
343  return CreateConstrainedStyleNonClientFrameView(
344      widget,
345      controller_->web_contents()->GetBrowserContext());
346}
347
348void MediaGalleriesDialogViews::ButtonPressed(views::Button* sender,
349                                              const ui::Event& event) {
350  confirm_available_ = true;
351  GetWidget()->client_view()->AsDialogClientView()->UpdateDialogButtons();
352
353  if (sender == add_gallery_button_) {
354    controller_->OnAddFolderClicked();
355    return;
356  }
357
358  for (CheckboxMap::const_iterator iter = checkbox_map_.begin();
359       iter != checkbox_map_.end(); ++iter) {
360    if (sender == iter->second) {
361      controller_->DidToggleGalleryId(iter->first,
362                                      iter->second->checked());
363      return;
364    }
365  }
366}
367
368// MediaGalleriesDialogViewsController -----------------------------------------
369
370// static
371MediaGalleriesDialog* MediaGalleriesDialog::Create(
372    MediaGalleriesDialogController* controller) {
373  return new MediaGalleriesDialogViews(controller);
374}
375