media_galleries_dialog_views.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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 "components/web_modal/web_contents_modal_dialog_host.h"
9#include "components/web_modal/web_contents_modal_dialog_manager.h"
10#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
11#include "content/public/browser/web_contents.h"
12#include "grit/generated_resources.h"
13#include "grit/locale_settings.h"
14#include "third_party/skia/include/core/SkColor.h"
15#include "ui/base/l10n/l10n_util.h"
16#include "ui/native_theme/native_theme.h"
17#include "ui/views/border.h"
18#include "ui/views/controls/button/checkbox.h"
19#include "ui/views/controls/button/label_button.h"
20#include "ui/views/controls/label.h"
21#include "ui/views/controls/menu/menu_runner.h"
22#include "ui/views/controls/scroll_view.h"
23#include "ui/views/controls/separator.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"
30
31using web_modal::WebContentsModalDialogManager;
32using web_modal::WebContentsModalDialogManagerDelegate;
33
34namespace {
35
36// Equal to the #969696 color used in spec (note WebUI color is #999).
37const SkColor kDeemphasizedTextColor = SkColorSetRGB(159, 159, 159);
38
39const int kScrollAreaHeight = 192;
40
41// This container has the right Layout() impl to use within a ScrollView.
42class ScrollableView : public views::View {
43 public:
44  ScrollableView() {}
45  virtual ~ScrollableView() {}
46
47  virtual void Layout() OVERRIDE;
48
49 private:
50  DISALLOW_COPY_AND_ASSIGN(ScrollableView);
51};
52
53void ScrollableView::Layout() {
54  gfx::Size pref = GetPreferredSize();
55  int width = pref.width();
56  int height = pref.height();
57  if (parent()) {
58    width = std::max(parent()->width(), width);
59    height = std::max(parent()->height(), height);
60  }
61  SetBounds(x(), y(), width, height);
62
63  views::View::Layout();
64}
65
66}  // namespace
67
68typedef MediaGalleriesDialogController::GalleryPermissionsVector
69    GalleryPermissionsVector;
70
71MediaGalleriesDialogViews::MediaGalleriesDialogViews(
72    MediaGalleriesDialogController* controller)
73    : controller_(controller),
74      window_(NULL),
75      contents_(new views::View()),
76      add_gallery_button_(NULL),
77      confirm_available_(false),
78      accepted_(false) {
79  InitChildViews();
80
81  // May be NULL during tests.
82  if (controller->web_contents()) {
83    // Ownership of |contents_| is handed off by this call. |window_| will take
84    // care of deleting itself after calling DeleteDelegate().
85    WebContentsModalDialogManager* web_contents_modal_dialog_manager =
86        WebContentsModalDialogManager::FromWebContents(
87            controller->web_contents());
88    DCHECK(web_contents_modal_dialog_manager);
89    WebContentsModalDialogManagerDelegate* modal_delegate =
90        web_contents_modal_dialog_manager->delegate();
91    DCHECK(modal_delegate);
92    window_ = views::Widget::CreateWindowAsFramelessChild(
93        this, modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
94    web_contents_modal_dialog_manager->ShowDialog(window_->GetNativeView());
95  }
96}
97
98MediaGalleriesDialogViews::~MediaGalleriesDialogViews() {
99  if (!controller_->web_contents())
100    delete contents_;
101}
102
103void MediaGalleriesDialogViews::InitChildViews() {
104  // Outer dialog layout.
105  contents_->RemoveAllChildViews(true);
106  int dialog_content_width = views::Widget::GetLocalizedContentsWidth(
107      IDS_MEDIA_GALLERIES_DIALOG_CONTENT_WIDTH_CHARS);
108  views::GridLayout* layout = views::GridLayout::CreatePanel(contents_);
109  contents_->SetLayoutManager(layout);
110
111  int column_set_id = 0;
112  views::ColumnSet* columns = layout->AddColumnSet(column_set_id);
113  columns->AddColumn(views::GridLayout::LEADING,
114                     views::GridLayout::LEADING,
115                     1,
116                     views::GridLayout::FIXED,
117                     dialog_content_width,
118                     0);
119
120  // Message text.
121  views::Label* subtext = new views::Label(controller_->GetSubtext());
122  subtext->SetMultiLine(true);
123  subtext->SetHorizontalAlignment(gfx::ALIGN_LEFT);
124  layout->StartRow(0, column_set_id);
125  layout->AddView(
126      subtext, 1, 1,
127      views::GridLayout::FILL, views::GridLayout::LEADING,
128      dialog_content_width, subtext->GetHeightForWidth(dialog_content_width));
129  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
130
131  // Scrollable area for checkboxes.
132  ScrollableView* scroll_container = new ScrollableView();
133  scroll_container->SetLayoutManager(new views::BoxLayout(
134      views::BoxLayout::kVertical, 0, 0,
135      views::kRelatedControlSmallVerticalSpacing));
136  scroll_container->SetBorder(
137      views::Border::CreateEmptyBorder(views::kRelatedControlVerticalSpacing,
138                                       0,
139                                       views::kRelatedControlVerticalSpacing,
140                                       0));
141
142  // Add attached galleries checkboxes.
143  checkbox_map_.clear();
144  new_checkbox_map_.clear();
145  GalleryPermissionsVector permissions = controller_->AttachedPermissions();
146  for (GalleryPermissionsVector::const_iterator iter = permissions.begin();
147       iter != permissions.end(); ++iter) {
148    int spacing = 0;
149    if (iter + 1 == permissions.end())
150      spacing = views::kRelatedControlSmallVerticalSpacing;
151    AddOrUpdateGallery(iter->pref_info, iter->allowed, scroll_container,
152                       spacing);
153  }
154
155  GalleryPermissionsVector unattached_permissions =
156      controller_->UnattachedPermissions();
157
158  if (!unattached_permissions.empty()) {
159    // Separator line.
160    views::Separator* separator = new views::Separator(
161        views::Separator::HORIZONTAL);
162    scroll_container->AddChildView(separator);
163
164    // Unattached locations section.
165    views::Label* unattached_text = new views::Label(
166        controller_->GetUnattachedLocationsHeader());
167    unattached_text->SetMultiLine(true);
168    unattached_text->SetHorizontalAlignment(gfx::ALIGN_LEFT);
169    unattached_text->SetBorder(
170        views::Border::CreateEmptyBorder(views::kRelatedControlVerticalSpacing,
171                                         views::kPanelHorizMargin,
172                                         views::kRelatedControlVerticalSpacing,
173                                         0));
174    scroll_container->AddChildView(unattached_text);
175
176    // Add unattached galleries checkboxes.
177    for (GalleryPermissionsVector::const_iterator iter =
178             unattached_permissions.begin();
179         iter != unattached_permissions.end(); ++iter) {
180      AddOrUpdateGallery(iter->pref_info, iter->allowed, scroll_container, 0);
181    }
182  }
183
184  confirm_available_ = controller_->HasPermittedGalleries();
185
186  // Add the scrollable area to the outer dialog view. It will squeeze against
187  // the title/subtitle and buttons to occupy all available space in the dialog.
188  views::ScrollView* scroll_view =
189      views::ScrollView::CreateScrollViewWithBorder();
190  scroll_view->SetContents(scroll_container);
191  layout->StartRowWithPadding(1, column_set_id,
192                              0, views::kRelatedControlVerticalSpacing);
193  layout->AddView(scroll_view, 1, 1,
194                  views::GridLayout::FILL, views::GridLayout::FILL,
195                  dialog_content_width, kScrollAreaHeight);
196}
197
198void MediaGalleriesDialogViews::UpdateGalleries() {
199  InitChildViews();
200  contents_->Layout();
201}
202
203bool MediaGalleriesDialogViews::AddOrUpdateGallery(
204    const MediaGalleryPrefInfo& gallery,
205    bool permitted,
206    views::View* container,
207    int trailing_vertical_space) {
208  base::string16 label = gallery.GetGalleryDisplayName();
209  base::string16 tooltip_text = gallery.GetGalleryTooltip();
210  base::string16 details = gallery.GetGalleryAdditionalDetails();
211
212  CheckboxMap::iterator iter = checkbox_map_.find(gallery.pref_id);
213  if (iter != checkbox_map_.end() &&
214      gallery.pref_id != kInvalidMediaGalleryPrefId) {
215    views::Checkbox* checkbox = iter->second;
216    checkbox->SetChecked(permitted);
217    checkbox->SetText(label);
218    checkbox->SetElideBehavior(views::Label::ELIDE_IN_MIDDLE);
219    checkbox->SetTooltipText(tooltip_text);
220    // Replace the details string.
221    views::View* checkbox_view = checkbox->parent();
222    DCHECK_EQ(2, checkbox_view->child_count());
223    views::Label* secondary_text =
224        static_cast<views::Label*>(checkbox_view->child_at(1));
225    secondary_text->SetText(details);
226    return false;
227  }
228
229  views::Checkbox* checkbox = new views::Checkbox(label);
230  checkbox->set_listener(this);
231  if (gallery.pref_id != kInvalidMediaGalleryPrefId)
232    checkbox->set_context_menu_controller(this);
233  checkbox->SetTooltipText(tooltip_text);
234  views::Label* secondary_text = new views::Label(details);
235  if (gallery.pref_id != kInvalidMediaGalleryPrefId)
236    secondary_text->set_context_menu_controller(this);
237  secondary_text->SetTooltipText(tooltip_text);
238  secondary_text->SetEnabledColor(kDeemphasizedTextColor);
239  secondary_text->SetTooltipText(tooltip_text);
240  secondary_text->SetBorder(views::Border::CreateEmptyBorder(
241      0,
242      views::kRelatedControlSmallHorizontalSpacing,
243      0,
244      views::kRelatedControlSmallHorizontalSpacing));
245
246  views::View* checkbox_view = new views::View();
247  if (gallery.pref_id != kInvalidMediaGalleryPrefId)
248    checkbox_view->set_context_menu_controller(this);
249  checkbox_view->SetBorder(views::Border::CreateEmptyBorder(
250      0, views::kPanelHorizMargin, trailing_vertical_space, 0));
251  checkbox_view->SetLayoutManager(
252      new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0));
253  checkbox_view->AddChildView(checkbox);
254  checkbox_view->AddChildView(secondary_text);
255
256  container->AddChildView(checkbox_view);
257
258  checkbox->SetChecked(permitted);
259  if (gallery.pref_id != kInvalidMediaGalleryPrefId)
260    checkbox_map_[gallery.pref_id] = checkbox;
261  else
262    new_checkbox_map_[checkbox] = gallery;
263
264  return true;
265}
266
267base::string16 MediaGalleriesDialogViews::GetWindowTitle() const {
268  return controller_->GetHeader();
269}
270
271void MediaGalleriesDialogViews::DeleteDelegate() {
272  controller_->DialogFinished(accepted_);
273}
274
275views::Widget* MediaGalleriesDialogViews::GetWidget() {
276  return contents_->GetWidget();
277}
278
279const views::Widget* MediaGalleriesDialogViews::GetWidget() const {
280  return contents_->GetWidget();
281}
282
283views::View* MediaGalleriesDialogViews::GetContentsView() {
284  return contents_;
285}
286
287base::string16 MediaGalleriesDialogViews::GetDialogButtonLabel(
288    ui::DialogButton button) const {
289  return l10n_util::GetStringUTF16(button == ui::DIALOG_BUTTON_OK ?
290      IDS_MEDIA_GALLERIES_DIALOG_CONFIRM :
291      IDS_MEDIA_GALLERIES_DIALOG_CANCEL);
292}
293
294bool MediaGalleriesDialogViews::IsDialogButtonEnabled(
295    ui::DialogButton button) const {
296  return button != ui::DIALOG_BUTTON_OK || confirm_available_;
297}
298
299ui::ModalType MediaGalleriesDialogViews::GetModalType() const {
300#if defined(USE_ASH)
301  return ui::MODAL_TYPE_CHILD;
302#else
303  return views::WidgetDelegate::GetModalType();
304#endif
305}
306
307views::View* MediaGalleriesDialogViews::CreateExtraView() {
308  DCHECK(!add_gallery_button_);
309  add_gallery_button_ = new views::LabelButton(this,
310      l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_DIALOG_ADD_GALLERY));
311  add_gallery_button_->SetStyle(views::Button::STYLE_BUTTON);
312  return add_gallery_button_;
313}
314
315bool MediaGalleriesDialogViews::Cancel() {
316  return true;
317}
318
319bool MediaGalleriesDialogViews::Accept() {
320  accepted_ = true;
321
322  return true;
323}
324
325void MediaGalleriesDialogViews::ButtonPressed(views::Button* sender,
326                                              const ui::Event& event) {
327  GetWidget()->client_view()->AsDialogClientView()->UpdateDialogButtons();
328
329  ButtonPressedAction(sender);
330}
331
332void MediaGalleriesDialogViews::ButtonPressedAction(views::Button* sender) {
333  confirm_available_ = true;
334
335  if (sender == add_gallery_button_) {
336    controller_->OnAddFolderClicked();
337    return;
338  }
339
340  for (CheckboxMap::const_iterator iter = checkbox_map_.begin();
341       iter != checkbox_map_.end(); ++iter) {
342    if (sender == iter->second) {
343      controller_->DidToggleGalleryId(iter->first,
344                                      iter->second->checked());
345      return;
346    }
347  }
348  for (NewCheckboxMap::const_iterator iter = new_checkbox_map_.begin();
349       iter != new_checkbox_map_.end(); ++iter) {
350    if (sender == iter->first) {
351      controller_->DidToggleNewGallery(iter->second, iter->first->checked());
352    }
353  }
354}
355
356void MediaGalleriesDialogViews::ShowContextMenuForView(
357    views::View* source,
358    const gfx::Point& point,
359    ui::MenuSourceType source_type) {
360  for (CheckboxMap::const_iterator iter = checkbox_map_.begin();
361       iter != checkbox_map_.end(); ++iter) {
362    if (iter->second->parent()->Contains(source)) {
363      ShowContextMenu(point, source_type, iter->first);
364      return;
365    }
366  }
367}
368
369void MediaGalleriesDialogViews::ShowContextMenu(const gfx::Point& point,
370                                                ui::MenuSourceType source_type,
371                                                MediaGalleryPrefId id) {
372  context_menu_runner_.reset(new views::MenuRunner(
373      controller_->GetContextMenu(id)));
374
375  if (context_menu_runner_->RunMenuAt(
376          GetWidget(), NULL, gfx::Rect(point.x(), point.y(), 0, 0),
377          views::MenuItemView::TOPLEFT, source_type,
378          views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU) ==
379      views::MenuRunner::MENU_DELETED) {
380    return;
381  }
382}
383
384// MediaGalleriesDialogViewsController -----------------------------------------
385
386// static
387MediaGalleriesDialog* MediaGalleriesDialog::Create(
388    MediaGalleriesDialogController* controller) {
389  return new MediaGalleriesDialogViews(controller);
390}
391