media_galleries_dialog_views.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
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 "chrome/browser/ui/views/extensions/media_gallery_checkbox_view.h"
10#include "components/web_modal/web_contents_modal_dialog_manager.h"
11#include "content/public/browser/web_contents.h"
12#include "grit/generated_resources.h"
13#include "grit/locale_settings.h"
14#include "ui/base/l10n/l10n_util.h"
15#include "ui/native_theme/native_theme.h"
16#include "ui/views/border.h"
17#include "ui/views/controls/button/checkbox.h"
18#include "ui/views/controls/button/image_button.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
31namespace {
32
33const int kScrollAreaHeight = 192;
34
35// This container has the right Layout() impl to use within a ScrollView.
36class ScrollableView : public views::View {
37 public:
38  ScrollableView() {}
39  virtual ~ScrollableView() {}
40
41  virtual void Layout() OVERRIDE;
42
43 private:
44  DISALLOW_COPY_AND_ASSIGN(ScrollableView);
45};
46
47void ScrollableView::Layout() {
48  gfx::Size pref = GetPreferredSize();
49  int width = pref.width();
50  int height = pref.height();
51  if (parent()) {
52    width = parent()->width();
53    height = std::max(parent()->height(), height);
54  }
55  SetBounds(x(), y(), width, height);
56
57  views::View::Layout();
58}
59
60}  // namespace
61
62MediaGalleriesDialogViews::MediaGalleriesDialogViews(
63    MediaGalleriesDialogController* controller)
64    : controller_(controller),
65      contents_(new views::View()),
66      auxiliary_button_(NULL),
67      confirm_available_(false),
68      accepted_(false) {
69  InitChildViews();
70  if (ControllerHasWebContents())
71    ShowWebModalDialogViews(this, controller->WebContents());
72}
73
74MediaGalleriesDialogViews::~MediaGalleriesDialogViews() {
75  if (!ControllerHasWebContents())
76    delete contents_;
77}
78
79void MediaGalleriesDialogViews::AcceptDialogForTesting() {
80  accepted_ = true;
81
82  web_modal::WebContentsModalDialogManager* web_contents_modal_dialog_manager =
83      web_modal::WebContentsModalDialogManager::FromWebContents(
84          controller_->WebContents());
85  DCHECK(web_contents_modal_dialog_manager);
86  web_modal::WebContentsModalDialogManager::TestApi(
87      web_contents_modal_dialog_manager).CloseAllDialogs();
88}
89
90void MediaGalleriesDialogViews::InitChildViews() {
91  // Outer dialog layout.
92  contents_->RemoveAllChildViews(true);
93  checkbox_map_.clear();
94
95  int dialog_content_width = views::Widget::GetLocalizedContentsWidth(
96      IDS_MEDIA_GALLERIES_DIALOG_CONTENT_WIDTH_CHARS);
97  views::GridLayout* layout = views::GridLayout::CreatePanel(contents_);
98  contents_->SetLayoutManager(layout);
99
100  int column_set_id = 0;
101  views::ColumnSet* columns = layout->AddColumnSet(column_set_id);
102  columns->AddColumn(views::GridLayout::LEADING,
103                     views::GridLayout::LEADING,
104                     1,
105                     views::GridLayout::FIXED,
106                     dialog_content_width,
107                     0);
108
109  // Message text.
110  views::Label* subtext = new views::Label(controller_->GetSubtext());
111  subtext->SetMultiLine(true);
112  subtext->SetHorizontalAlignment(gfx::ALIGN_LEFT);
113  layout->StartRow(0, column_set_id);
114  layout->AddView(
115      subtext, 1, 1,
116      views::GridLayout::FILL, views::GridLayout::LEADING,
117      dialog_content_width, subtext->GetHeightForWidth(dialog_content_width));
118  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
119
120  // Scrollable area for checkboxes.
121  ScrollableView* scroll_container = new ScrollableView();
122  scroll_container->SetLayoutManager(new views::BoxLayout(
123      views::BoxLayout::kVertical, 0, 0,
124      views::kRelatedControlSmallVerticalSpacing));
125  scroll_container->SetBorder(
126      views::Border::CreateEmptyBorder(views::kRelatedControlVerticalSpacing,
127                                       0,
128                                       views::kRelatedControlVerticalSpacing,
129                                       0));
130
131  std::vector<base::string16> section_headers =
132      controller_->GetSectionHeaders();
133  for (size_t i = 0; i < section_headers.size(); i++) {
134    MediaGalleriesDialogController::Entries entries =
135        controller_->GetSectionEntries(i);
136
137    // Header and separator line.
138    if (!section_headers[i].empty() && !entries.empty()) {
139      views::Separator* separator = new views::Separator(
140          views::Separator::HORIZONTAL);
141      scroll_container->AddChildView(separator);
142
143      views::Label* header = new views::Label(section_headers[i]);
144      header->SetMultiLine(true);
145      header->SetHorizontalAlignment(gfx::ALIGN_LEFT);
146      header->SetBorder(views::Border::CreateEmptyBorder(
147          views::kRelatedControlVerticalSpacing,
148          views::kPanelHorizMargin,
149          views::kRelatedControlVerticalSpacing,
150          0));
151      scroll_container->AddChildView(header);
152    }
153
154    // Checkboxes.
155    MediaGalleriesDialogController::Entries::const_iterator iter;
156    for (iter = entries.begin(); iter != entries.end(); ++iter) {
157      int spacing = 0;
158      if (iter + 1 == entries.end())
159        spacing = views::kRelatedControlSmallVerticalSpacing;
160      AddOrUpdateGallery(*iter, scroll_container, spacing);
161    }
162  }
163
164  confirm_available_ = controller_->IsAcceptAllowed();
165
166  // Add the scrollable area to the outer dialog view. It will squeeze against
167  // the title/subtitle and buttons to occupy all available space in the dialog.
168  views::ScrollView* scroll_view =
169      views::ScrollView::CreateScrollViewWithBorder();
170  scroll_view->SetContents(scroll_container);
171  layout->StartRowWithPadding(1, column_set_id,
172                              0, views::kRelatedControlVerticalSpacing);
173  layout->AddView(scroll_view, 1, 1,
174                  views::GridLayout::FILL, views::GridLayout::FILL,
175                  dialog_content_width, kScrollAreaHeight);
176}
177
178void MediaGalleriesDialogViews::UpdateGalleries() {
179  InitChildViews();
180  contents_->Layout();
181}
182
183bool MediaGalleriesDialogViews::AddOrUpdateGallery(
184    const MediaGalleriesDialogController::Entry& gallery,
185    views::View* container,
186    int trailing_vertical_space) {
187  base::string16 label = gallery.pref_info.GetGalleryDisplayName();
188  base::string16 tooltip_text = gallery.pref_info.GetGalleryTooltip();
189  base::string16 details = gallery.pref_info.GetGalleryAdditionalDetails();
190  bool show_folder_viewer = controller_->ShouldShowFolderViewer(gallery);
191
192  CheckboxMap::iterator iter = checkbox_map_.find(gallery.pref_info.pref_id);
193  if (iter != checkbox_map_.end()) {
194    views::Checkbox* checkbox = iter->second->checkbox();
195    checkbox->SetChecked(gallery.selected);
196    checkbox->SetText(label);
197    checkbox->SetTooltipText(tooltip_text);
198    iter->second->secondary_text()->SetText(details);
199    iter->second->secondary_text()->SetVisible(details.length() > 0);
200    iter->second->folder_viewer_button()->SetVisible(show_folder_viewer);
201    return false;
202  }
203
204  MediaGalleryCheckboxView* gallery_view =
205      new MediaGalleryCheckboxView(label, tooltip_text, details,
206                                   show_folder_viewer, trailing_vertical_space,
207                                   this, this);
208  gallery_view->checkbox()->SetChecked(gallery.selected);
209  container->AddChildView(gallery_view);
210  checkbox_map_[gallery.pref_info.pref_id] = gallery_view;
211
212  return true;
213}
214
215base::string16 MediaGalleriesDialogViews::GetWindowTitle() const {
216  return controller_->GetHeader();
217}
218
219void MediaGalleriesDialogViews::DeleteDelegate() {
220  controller_->DialogFinished(accepted_);
221}
222
223views::Widget* MediaGalleriesDialogViews::GetWidget() {
224  return contents_->GetWidget();
225}
226
227const views::Widget* MediaGalleriesDialogViews::GetWidget() const {
228  return contents_->GetWidget();
229}
230
231views::View* MediaGalleriesDialogViews::GetContentsView() {
232  return contents_;
233}
234
235base::string16 MediaGalleriesDialogViews::GetDialogButtonLabel(
236    ui::DialogButton button) const {
237  if (button == ui::DIALOG_BUTTON_OK)
238    return controller_->GetAcceptButtonText();
239  return l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_DIALOG_CANCEL);
240}
241
242bool MediaGalleriesDialogViews::IsDialogButtonEnabled(
243    ui::DialogButton button) const {
244  return button != ui::DIALOG_BUTTON_OK || confirm_available_;
245}
246
247ui::ModalType MediaGalleriesDialogViews::GetModalType() const {
248  return ui::MODAL_TYPE_CHILD;
249}
250
251views::View* MediaGalleriesDialogViews::CreateExtraView() {
252  DCHECK(!auxiliary_button_);
253  base::string16 button_label = controller_->GetAuxiliaryButtonText();
254  if (!button_label.empty()) {
255    auxiliary_button_ = new views::LabelButton(this, button_label);
256    auxiliary_button_->SetStyle(views::Button::STYLE_BUTTON);
257  }
258  return auxiliary_button_;
259}
260
261bool MediaGalleriesDialogViews::Cancel() {
262  return true;
263}
264
265bool MediaGalleriesDialogViews::Accept() {
266  accepted_ = true;
267  return true;
268}
269
270void MediaGalleriesDialogViews::ButtonPressed(views::Button* sender,
271                                              const ui::Event& /* event */) {
272  confirm_available_ = true;
273
274  if (ControllerHasWebContents())
275    GetWidget()->client_view()->AsDialogClientView()->UpdateDialogButtons();
276
277  if (sender == auxiliary_button_) {
278    controller_->DidClickAuxiliaryButton();
279    return;
280  }
281
282  for (CheckboxMap::const_iterator iter = checkbox_map_.begin();
283       iter != checkbox_map_.end(); ++iter) {
284    if (sender == iter->second->checkbox()) {
285      controller_->DidToggleEntry(iter->first,
286                                  iter->second->checkbox()->checked());
287      return;
288    }
289    if (sender == iter->second->folder_viewer_button()) {
290      controller_->DidClickOpenFolderViewer(iter->first);
291      return;
292    }
293  }
294}
295
296void MediaGalleriesDialogViews::ShowContextMenuForView(
297    views::View* source,
298    const gfx::Point& point,
299    ui::MenuSourceType source_type) {
300  for (CheckboxMap::const_iterator iter = checkbox_map_.begin();
301       iter != checkbox_map_.end(); ++iter) {
302    if (iter->second->Contains(source)) {
303      ShowContextMenu(point, source_type, iter->first);
304      return;
305    }
306  }
307}
308
309void MediaGalleriesDialogViews::ShowContextMenu(const gfx::Point& point,
310                                                ui::MenuSourceType source_type,
311                                                MediaGalleryPrefId id) {
312  context_menu_runner_.reset(new views::MenuRunner(
313      controller_->GetContextMenu(id)));
314
315  if (context_menu_runner_->RunMenuAt(
316          GetWidget(),
317          NULL,
318          gfx::Rect(point.x(), point.y(), 0, 0),
319          views::MENU_ANCHOR_TOPLEFT,
320          source_type,
321          views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU) ==
322      views::MenuRunner::MENU_DELETED) {
323    return;
324  }
325}
326
327bool MediaGalleriesDialogViews::ControllerHasWebContents() const {
328  return controller_->WebContents() != NULL;
329}
330
331// MediaGalleriesDialogViewsController -----------------------------------------
332
333// static
334MediaGalleriesDialog* MediaGalleriesDialog::Create(
335    MediaGalleriesDialogController* controller) {
336  return new MediaGalleriesDialogViews(controller);
337}
338