Home | History | Annotate | Download | only in extensions
      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 
     31 namespace {
     32 
     33 const int kScrollAreaHeight = 192;
     34 
     35 // This container has the right Layout() impl to use within a ScrollView.
     36 class 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 
     47 void 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 
     62 MediaGalleriesDialogViews::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 
     74 MediaGalleriesDialogViews::~MediaGalleriesDialogViews() {
     75   if (!ControllerHasWebContents())
     76     delete contents_;
     77 }
     78 
     79 void 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 
     90 void 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 
    178 void MediaGalleriesDialogViews::UpdateGalleries() {
    179   InitChildViews();
    180   contents_->Layout();
    181 
    182   if (ControllerHasWebContents())
    183     GetWidget()->client_view()->AsDialogClientView()->UpdateDialogButtons();
    184 }
    185 
    186 bool MediaGalleriesDialogViews::AddOrUpdateGallery(
    187     const MediaGalleriesDialogController::Entry& gallery,
    188     views::View* container,
    189     int trailing_vertical_space) {
    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(gallery.pref_info.GetGalleryDisplayName());
    197     checkbox->SetTooltipText(gallery.pref_info.GetGalleryTooltip());
    198     base::string16 details = gallery.pref_info.GetGalleryAdditionalDetails();
    199     iter->second->secondary_text()->SetText(details);
    200     iter->second->secondary_text()->SetVisible(details.length() > 0);
    201     iter->second->folder_viewer_button()->SetVisible(show_folder_viewer);
    202     return false;
    203   }
    204 
    205   MediaGalleryCheckboxView* gallery_view =
    206       new MediaGalleryCheckboxView(gallery.pref_info, show_folder_viewer,
    207                                    trailing_vertical_space, 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 
    215 base::string16 MediaGalleriesDialogViews::GetWindowTitle() const {
    216   return controller_->GetHeader();
    217 }
    218 
    219 void MediaGalleriesDialogViews::DeleteDelegate() {
    220   controller_->DialogFinished(accepted_);
    221 }
    222 
    223 views::Widget* MediaGalleriesDialogViews::GetWidget() {
    224   return contents_->GetWidget();
    225 }
    226 
    227 const views::Widget* MediaGalleriesDialogViews::GetWidget() const {
    228   return contents_->GetWidget();
    229 }
    230 
    231 views::View* MediaGalleriesDialogViews::GetContentsView() {
    232   return contents_;
    233 }
    234 
    235 base::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 
    242 bool MediaGalleriesDialogViews::IsDialogButtonEnabled(
    243     ui::DialogButton button) const {
    244   return button != ui::DIALOG_BUTTON_OK || confirm_available_;
    245 }
    246 
    247 ui::ModalType MediaGalleriesDialogViews::GetModalType() const {
    248   return ui::MODAL_TYPE_CHILD;
    249 }
    250 
    251 views::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 
    261 bool MediaGalleriesDialogViews::Cancel() {
    262   return true;
    263 }
    264 
    265 bool MediaGalleriesDialogViews::Accept() {
    266   accepted_ = true;
    267   return true;
    268 }
    269 
    270 void 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 
    296 void 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 
    309 void 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 
    327 bool MediaGalleriesDialogViews::ControllerHasWebContents() const {
    328   return controller_->WebContents() != NULL;
    329 }
    330 
    331 // MediaGalleriesDialogViewsController -----------------------------------------
    332 
    333 // static
    334 MediaGalleriesDialog* MediaGalleriesDialog::Create(
    335     MediaGalleriesDialogController* controller) {
    336   return new MediaGalleriesDialogViews(controller);
    337 }
    338