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