Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(526)

Side by Side Diff: chrome/browser/ui/views/extensions/extension_install_dialog_view.cc

Issue 18854021: Making the extension permissions dialog scrollable, when needed (adding expandable sections for thi… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Even more param reductions Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <vector> 5 #include <vector>
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/compiler_specific.h" 9 #include "base/compiler_specific.h"
10 #include "base/i18n/rtl.h" 10 #include "base/i18n/rtl.h"
(...skipping 11 matching lines...) Expand all
22 #include "grit/chromium_strings.h" 22 #include "grit/chromium_strings.h"
23 #include "grit/generated_resources.h" 23 #include "grit/generated_resources.h"
24 #include "grit/google_chrome_strings.h" 24 #include "grit/google_chrome_strings.h"
25 #include "grit/theme_resources.h" 25 #include "grit/theme_resources.h"
26 #include "ui/base/animation/animation_delegate.h" 26 #include "ui/base/animation/animation_delegate.h"
27 #include "ui/base/animation/slide_animation.h" 27 #include "ui/base/animation/slide_animation.h"
28 #include "ui/base/l10n/l10n_util.h" 28 #include "ui/base/l10n/l10n_util.h"
29 #include "ui/base/resource/resource_bundle.h" 29 #include "ui/base/resource/resource_bundle.h"
30 #include "ui/gfx/transform.h" 30 #include "ui/gfx/transform.h"
31 #include "ui/views/border.h" 31 #include "ui/views/border.h"
32 #include "ui/views/controls/button/image_button.h"
32 #include "ui/views/controls/image_view.h" 33 #include "ui/views/controls/image_view.h"
33 #include "ui/views/controls/label.h" 34 #include "ui/views/controls/label.h"
34 #include "ui/views/controls/link.h" 35 #include "ui/views/controls/link.h"
35 #include "ui/views/controls/link_listener.h" 36 #include "ui/views/controls/link_listener.h"
36 #include "ui/views/controls/scroll_view.h" 37 #include "ui/views/controls/scroll_view.h"
37 #include "ui/views/controls/separator.h" 38 #include "ui/views/controls/separator.h"
38 #include "ui/views/layout/box_layout.h" 39 #include "ui/views/layout/box_layout.h"
39 #include "ui/views/layout/grid_layout.h" 40 #include "ui/views/layout/grid_layout.h"
40 #include "ui/views/layout/layout_constants.h" 41 #include "ui/views/layout/layout_constants.h"
41 #include "ui/views/view.h" 42 #include "ui/views/view.h"
42 #include "ui/views/widget/widget.h" 43 #include "ui/views/widget/widget.h"
43 #include "ui/views/window/dialog_delegate.h" 44 #include "ui/views/window/dialog_delegate.h"
44 45
45 using content::OpenURLParams; 46 using content::OpenURLParams;
46 using content::Referrer; 47 using content::Referrer;
47 using extensions::BundleInstaller; 48 using extensions::BundleInstaller;
48 49
49 namespace { 50 namespace {
50 51
51 // Size of extension icon in top left of dialog. 52 // Size of extension icon in top left of dialog.
52 const int kIconSize = 69; 53 const int kIconSize = 69;
53 54
55 // The dialog width.
56 const int kDialogWidth = 385;
57
58 // The dialog will resize based on its content, but this sets a maximum height
59 // before overflowing a scrollbar.
60 const int kDialogMaxHeight = 300;
61
54 // Width of the left column of the dialog when the extension requests 62 // Width of the left column of the dialog when the extension requests
55 // permissions. 63 // permissions.
56 const int kPermissionsLeftColumnWidth = 250; 64 const int kPermissionsLeftColumnWidth = 250;
57 65
58 // Width of the left column of the dialog when the extension requests no 66 // Width of the left column of the dialog when the extension requests no
59 // permissions. 67 // permissions.
60 const int kNoPermissionsLeftColumnWidth = 200; 68 const int kNoPermissionsLeftColumnWidth = 200;
61 69
62 // Width of the left column for bundle install prompts. There's only one column 70 // Width of the left column for bundle install prompts. There's only one column
63 // in this case, so make it wider than normal. 71 // in this case, so make it wider than normal.
(...skipping 23 matching lines...) Expand all
87 95
88 // Implements the extension installation dialog for TOOLKIT_VIEWS. 96 // Implements the extension installation dialog for TOOLKIT_VIEWS.
89 class ExtensionInstallDialogView : public views::DialogDelegateView, 97 class ExtensionInstallDialogView : public views::DialogDelegateView,
90 public views::LinkListener { 98 public views::LinkListener {
91 public: 99 public:
92 ExtensionInstallDialogView(content::PageNavigator* navigator, 100 ExtensionInstallDialogView(content::PageNavigator* navigator,
93 ExtensionInstallPrompt::Delegate* delegate, 101 ExtensionInstallPrompt::Delegate* delegate,
94 const ExtensionInstallPrompt::Prompt& prompt); 102 const ExtensionInstallPrompt::Prompt& prompt);
95 virtual ~ExtensionInstallDialogView(); 103 virtual ~ExtensionInstallDialogView();
96 104
97 // Changes the size of the containing widget to match the preferred size 105 // Called when one of the child elements has expanded/collapsed.
98 // of this dialog. 106 void ContentsChanged();
99 void SizeToContents();
100 107
101 private: 108 private:
102 // views::DialogDelegateView: 109 // views::DialogDelegateView:
103 virtual int GetDialogButtons() const OVERRIDE; 110 virtual int GetDialogButtons() const OVERRIDE;
104 virtual string16 GetDialogButtonLabel(ui::DialogButton button) const OVERRIDE; 111 virtual string16 GetDialogButtonLabel(ui::DialogButton button) const OVERRIDE;
105 virtual int GetDefaultDialogButton() const OVERRIDE; 112 virtual int GetDefaultDialogButton() const OVERRIDE;
106 virtual bool Cancel() OVERRIDE; 113 virtual bool Cancel() OVERRIDE;
107 virtual bool Accept() OVERRIDE; 114 virtual bool Accept() OVERRIDE;
108 115
109 // views::WidgetDelegate: 116 // views::WidgetDelegate:
110 virtual ui::ModalType GetModalType() const OVERRIDE; 117 virtual ui::ModalType GetModalType() const OVERRIDE;
111 virtual string16 GetWindowTitle() const OVERRIDE; 118 virtual string16 GetWindowTitle() const OVERRIDE;
112 119
113 // views::LinkListener: 120 // views::LinkListener:
114 virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE; 121 virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE;
115 122
123 // views::View:
Peter Kasting 2013/07/11 17:28:34 Nit: You don't directly subclass views::View, so i
124 virtual void Layout() OVERRIDE;
125 virtual gfx::Size GetPreferredSize() OVERRIDE;
126
116 bool is_inline_install() const { 127 bool is_inline_install() const {
117 return prompt_.type() == ExtensionInstallPrompt::INLINE_INSTALL_PROMPT; 128 return prompt_.type() == ExtensionInstallPrompt::INLINE_INSTALL_PROMPT;
118 } 129 }
119 130
120 bool is_bundle_install() const { 131 bool is_bundle_install() const {
121 return prompt_.type() == ExtensionInstallPrompt::BUNDLE_INSTALL_PROMPT; 132 return prompt_.type() == ExtensionInstallPrompt::BUNDLE_INSTALL_PROMPT;
122 } 133 }
123 134
124 bool is_external_install() const { 135 bool is_external_install() const {
125 return prompt_.type() == ExtensionInstallPrompt::EXTERNAL_INSTALL_PROMPT; 136 return prompt_.type() == ExtensionInstallPrompt::EXTERNAL_INSTALL_PROMPT;
126 } 137 }
127 138
128 content::PageNavigator* navigator_; 139 content::PageNavigator* navigator_;
129 ExtensionInstallPrompt::Delegate* delegate_; 140 ExtensionInstallPrompt::Delegate* delegate_;
130 ExtensionInstallPrompt::Prompt prompt_; 141 ExtensionInstallPrompt::Prompt prompt_;
131 142
143 // The scroll view containing all the details for the dialog (including all
144 // collapsible/expandable sections).
145 views::ScrollView* scroll_view_;
146
147 // The container view for the scroll view.
148 views::View* scrollable_;
149
150 // The preferred size of the dialog.
151 gfx::Size dialog_size_;
152
132 DISALLOW_COPY_AND_ASSIGN(ExtensionInstallDialogView); 153 DISALLOW_COPY_AND_ASSIGN(ExtensionInstallDialogView);
133 }; 154 };
134 155
135 // A view to display a single IssueAdviceInfoEntry. 156 // A view to display text with an expandable details section.
136 class IssueAdviceView : public views::View, 157 class ExpandableContainerView : public views::View,
137 public ui::AnimationDelegate { 158 public views::ButtonListener,
159 public views::LinkListener,
160 public ui::AnimationDelegate {
138 public: 161 public:
139 IssueAdviceView(ExtensionInstallDialogView* owner, 162 ExpandableContainerView(ExtensionInstallDialogView* owner,
140 const IssueAdviceInfoEntry& issue_advice, 163 const string16& description,
141 int horizontal_space); 164 const std::vector<string16>& details,
Peter Kasting 2013/07/11 17:28:34 Nit: You may want a typedef for vector<string16> s
142 virtual ~IssueAdviceView() {} 165 int horizontal_space,
166 bool show_bullets);
167 virtual ~ExpandableContainerView() {}
Peter Kasting 2013/07/11 17:28:34 Nit: Virtual functions generally shouldn't be inli
143 168
144 // Implementation of views::View: 169 // Implementation of views::View:
145 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
146 virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
147 virtual void ChildPreferredSizeChanged(views::View* child) OVERRIDE; 170 virtual void ChildPreferredSizeChanged(views::View* child) OVERRIDE;
148 171
172 // views::ButtonListener:
173 virtual void ButtonPressed(views::Button* sender,
174 const ui::Event& event) OVERRIDE;
175
176 // views::LinkListener:
177 virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE;
178
149 // Implementation of ui::AnimationDelegate: 179 // Implementation of ui::AnimationDelegate:
Peter Kasting 2013/07/11 17:28:34 Nit: Remove "Implementation of" for consistency
150 virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE; 180 virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE;
181 virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE;
151 182
152 private: 183 private:
153 // A view which displays all the details of an IssueAdviceInfoEntry. 184 // A view which displays all the details of an IssueAdviceInfoEntry.
154 class DetailsView : public views::View { 185 class DetailsView : public views::View {
155 public: 186 public:
156 explicit DetailsView(int horizontal_space); 187 explicit DetailsView(int horizontal_space, bool show_bullets);
157 virtual ~DetailsView() {} 188 virtual ~DetailsView() {}
158 189
159 // Implementation of views::View: 190 // Implementation of views::View:
160 virtual gfx::Size GetPreferredSize() OVERRIDE; 191 virtual gfx::Size GetPreferredSize() OVERRIDE;
161 192
162 void AddDetail(const string16& detail); 193 void AddDetail(const string16& detail);
163 194
164 // Animates this to be a height proportional to |state|. 195 // Animates this to be a height proportional to |state|.
165 void AnimateToState(double state); 196 void AnimateToState(double state);
166 197
167 private: 198 private:
168 views::GridLayout* layout_; 199 views::GridLayout* layout_;
169 double state_; 200 double state_;
170 201
202 // Whether to show bullets in front of each item in the details.
203 bool show_bullets_;
204
171 DISALLOW_COPY_AND_ASSIGN(DetailsView); 205 DISALLOW_COPY_AND_ASSIGN(DetailsView);
172 }; 206 };
173 207
208 // Expand/Collapse the detail section for this ExpandableContainerView.
209 void ToggleDetailLevel();
210
174 // The dialog that owns |this|. It's also an ancestor in the View hierarchy. 211 // The dialog that owns |this|. It's also an ancestor in the View hierarchy.
175 ExtensionInstallDialogView* owner_; 212 ExtensionInstallDialogView* owner_;
176 213
177 // A view for showing |issue_advice.details|. 214 // A view for showing |issue_advice.details|.
178 DetailsView* details_view_; 215 DetailsView* details_view_;
179 216
180 // The '>' zippy control. 217 // The '>' zippy control.
181 views::ImageView* arrow_view_; 218 views::ImageView* arrow_view_;
182 219
183 ui::SlideAnimation slide_animation_; 220 ui::SlideAnimation slide_animation_;
184 221
185 DISALLOW_COPY_AND_ASSIGN(IssueAdviceView); 222 // The 'more details' link shown under the heading (changes to 'hide details'
223 // when the details section is expanded).
224 views::Link* more_details_;
225
226 // The up/down arrow next to the 'more detail' link (points up/down depending
227 // on whether the details section is expanded).
228 views::ImageButton* arrow_toggle_;
229
230 // Whether the details section is expanded.
231 bool expanded_;
232
233 DISALLOW_COPY_AND_ASSIGN(ExpandableContainerView);
186 }; 234 };
187 235
188 void ShowExtensionInstallDialogImpl( 236 void ShowExtensionInstallDialogImpl(
189 const ExtensionInstallPrompt::ShowParams& show_params, 237 const ExtensionInstallPrompt::ShowParams& show_params,
190 ExtensionInstallPrompt::Delegate* delegate, 238 ExtensionInstallPrompt::Delegate* delegate,
191 const ExtensionInstallPrompt::Prompt& prompt) { 239 const ExtensionInstallPrompt::Prompt& prompt) {
192 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 240 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
193 CreateBrowserModalDialogViews( 241 CreateBrowserModalDialogViews(
194 new ExtensionInstallDialogView(show_params.navigator, delegate, prompt), 242 new ExtensionInstallDialogView(show_params.navigator, delegate, prompt),
195 show_params.parent_window)->Show(); 243 show_params.parent_window)->Show();
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
281 // +--------------------| | 329 // +--------------------| |
282 // | permission2 | | 330 // | permission2 | |
283 // +--------------------+------+ 331 // +--------------------+------+
284 // | oauth header | 332 // | oauth header |
285 // +---------------------------+ 333 // +---------------------------+
286 // | oauth issue 1 | 334 // | oauth issue 1 |
287 // +---------------------------+ 335 // +---------------------------+
288 // | oauth issue 2 | 336 // | oauth issue 2 |
289 // +---------------------------+ 337 // +---------------------------+
290 338
291 views::GridLayout* layout = views::GridLayout::CreatePanel(this); 339 scroll_view_ = new views::ScrollView();
292 SetLayoutManager(layout); 340 AddChildView(scroll_view_);
341 scrollable_ = new views::View();
342 scroll_view_->SetContents(scrollable_);
343
344 views::GridLayout* layout = views::GridLayout::CreatePanel(scrollable_);
345 scrollable_->SetLayoutManager(layout);
293 346
294 int column_set_id = 0; 347 int column_set_id = 0;
295 views::ColumnSet* column_set = layout->AddColumnSet(column_set_id); 348 views::ColumnSet* column_set = layout->AddColumnSet(column_set_id);
296 int left_column_width = 349 int left_column_width =
297 (prompt.ShouldShowPermissions() + prompt.GetOAuthIssueCount() + 350 (prompt.ShouldShowPermissions() + prompt.GetOAuthIssueCount() +
298 prompt.GetRetainedFileCount()) > 0 ? 351 prompt.GetRetainedFileCount()) > 0 ?
299 kPermissionsLeftColumnWidth : kNoPermissionsLeftColumnWidth; 352 kPermissionsLeftColumnWidth : kNoPermissionsLeftColumnWidth;
300 if (is_bundle_install()) 353 if (is_bundle_install())
301 left_column_width = kBundleLeftColumnWidth; 354 left_column_width = kBundleLeftColumnWidth;
302 if (is_external_install()) 355 if (is_external_install())
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
353 } else { 406 } else {
354 // This is the 'no special permissions' case, so span the line we add 407 // This is the 'no special permissions' case, so span the line we add
355 // (without a header) saying the extension has no special privileges. 408 // (without a header) saying the extension has no special privileges.
356 icon_row_span = 4; 409 icon_row_span = 4;
357 } 410 }
358 } else if (prompt.GetOAuthIssueCount()) { 411 } else if (prompt.GetOAuthIssueCount()) {
359 // Also span the permission header and each of the permission rows (all 412 // Also span the permission header and each of the permission rows (all
360 // have a padding row above it). 413 // have a padding row above it).
361 icon_row_span = 3 + prompt.GetOAuthIssueCount() * 2; 414 icon_row_span = 3 + prompt.GetOAuthIssueCount() * 2;
362 } else if (prompt.GetRetainedFileCount()) { 415 } else if (prompt.GetRetainedFileCount()) {
363 // Also span the permission header and each of the permission rows (all 416 // Also span the permission header and the retained files container.
364 // have a padding row above it). 417 icon_row_span = 4;
365 icon_row_span = 3 + prompt.GetRetainedFileCount() * 2;
366 } 418 }
367 layout->AddView(icon, 1, icon_row_span); 419 layout->AddView(icon, 1, icon_row_span);
368 } 420 }
369 421
370 if (is_inline_install()) { 422 if (is_inline_install()) {
371 layout->StartRow(0, column_set_id); 423 layout->StartRow(0, column_set_id);
372 views::View* rating = new views::View(); 424 views::View* rating = new views::View();
373 rating->SetLayoutManager(new views::BoxLayout( 425 rating->SetLayoutManager(new views::BoxLayout(
374 views::BoxLayout::kHorizontal, 0, 0, 0)); 426 views::BoxLayout::kHorizontal, 0, 0, 0));
375 layout->AddView(rating); 427 layout->AddView(rating);
(...skipping 14 matching lines...) Expand all
390 442
391 layout->StartRow(0, column_set_id); 443 layout->StartRow(0, column_set_id);
392 views::Link* store_link = new views::Link( 444 views::Link* store_link = new views::Link(
393 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_STORE_LINK)); 445 l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_STORE_LINK));
394 store_link->SetFont(rb.GetFont(ui::ResourceBundle::SmallFont)); 446 store_link->SetFont(rb.GetFont(ui::ResourceBundle::SmallFont));
395 store_link->set_listener(this); 447 store_link->set_listener(this);
396 layout->AddView(store_link); 448 layout->AddView(store_link);
397 } 449 }
398 450
399 if (is_bundle_install()) { 451 if (is_bundle_install()) {
400 BundleInstaller::ItemList items = prompt_.bundle()->GetItemsWithState( 452 BundleInstaller::ItemList items = prompt.bundle()->GetItemsWithState(
401 BundleInstaller::Item::STATE_PENDING); 453 BundleInstaller::Item::STATE_PENDING);
402 for (size_t i = 0; i < items.size(); ++i) { 454 for (size_t i = 0; i < items.size(); ++i) {
403 string16 extension_name = UTF8ToUTF16(items[i].localized_name); 455 string16 extension_name = UTF8ToUTF16(items[i].localized_name);
404 base::i18n::AdjustStringForLocaleDirection(&extension_name); 456 base::i18n::AdjustStringForLocaleDirection(&extension_name);
405 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 457 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
406 layout->StartRow(0, column_set_id); 458 layout->StartRow(0, column_set_id);
407 views::Label* extension_label = new views::Label( 459 views::Label* extension_label = new views::Label(
408 PrepareForDisplay(extension_name, true)); 460 PrepareForDisplay(extension_name, true));
409 extension_label->SetMultiLine(true); 461 extension_label->SetMultiLine(true);
410 extension_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 462 extension_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
443 495
444 for (size_t i = 0; i < prompt.GetPermissionCount(); ++i) { 496 for (size_t i = 0; i < prompt.GetPermissionCount(); ++i) {
445 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 497 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
446 layout->StartRow(0, column_set_id); 498 layout->StartRow(0, column_set_id);
447 views::Label* permission_label = new views::Label(PrepareForDisplay( 499 views::Label* permission_label = new views::Label(PrepareForDisplay(
448 prompt.GetPermission(i), true)); 500 prompt.GetPermission(i), true));
449 permission_label->SetMultiLine(true); 501 permission_label->SetMultiLine(true);
450 permission_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 502 permission_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
451 permission_label->SizeToFit(left_column_width); 503 permission_label->SizeToFit(left_column_width);
452 layout->AddView(permission_label); 504 layout->AddView(permission_label);
505
506 // If we have more details to provide, so show it un-expanded.
Peter Kasting 2013/07/11 17:28:34 Nit: Grammar
Yoyo Zhou 2013/07/11 17:39:48 nit: no 'so'
507 if (!prompt.GetPermissionsDetails(i).empty()) {
508 layout->StartRow(0, column_set_id);
509 std::vector<string16> details;
Peter Kasting 2013/07/11 17:28:34 Nit: Indenting is wrong
510 details.push_back(
511 PrepareForDisplay(prompt.GetPermissionsDetails(i), false));
512 ExpandableContainerView* details_container =
513 new ExpandableContainerView(
514 this,
Peter Kasting 2013/07/11 17:28:34 Nit: I suggest collapsing onto fewer lines, I find
515 string16(),
516 details,
517 left_column_width,
518 false);
519 layout->AddView(details_container);
520 }
453 } 521 }
454 } else { 522 } else {
455 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 523 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
456 layout->StartRow(0, column_set_id); 524 layout->StartRow(0, column_set_id);
457 views::Label* permission_label = new views::Label( 525 views::Label* permission_label = new views::Label(
458 l10n_util::GetStringUTF16(IDS_EXTENSION_NO_SPECIAL_PERMISSIONS)); 526 l10n_util::GetStringUTF16(IDS_EXTENSION_NO_SPECIAL_PERMISSIONS));
459 permission_label->SetMultiLine(true); 527 permission_label->SetMultiLine(true);
460 permission_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 528 permission_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
461 permission_label->SizeToFit(left_column_width); 529 permission_label->SizeToFit(left_column_width);
462 layout->AddView(permission_label); 530 layout->AddView(permission_label);
(...skipping 23 matching lines...) Expand all
486 oauth_header->SetMultiLine(true); 554 oauth_header->SetMultiLine(true);
487 oauth_header->SetHorizontalAlignment(gfx::ALIGN_LEFT); 555 oauth_header->SetHorizontalAlignment(gfx::ALIGN_LEFT);
488 oauth_header->SizeToFit(left_column_width); 556 oauth_header->SizeToFit(left_column_width);
489 layout->AddView(oauth_header); 557 layout->AddView(oauth_header);
490 558
491 for (size_t i = 0; i < prompt.GetOAuthIssueCount(); ++i) { 559 for (size_t i = 0; i < prompt.GetOAuthIssueCount(); ++i) {
492 layout->StartRowWithPadding( 560 layout->StartRowWithPadding(
493 0, column_set_id, 561 0, column_set_id,
494 0, views::kRelatedControlVerticalSpacing); 562 0, views::kRelatedControlVerticalSpacing);
495 563
496 IssueAdviceView* issue_advice_view = 564 std::vector<string16> details;
497 new IssueAdviceView(this, prompt.GetOAuthIssue(i), space_for_oauth); 565 const IssueAdviceInfoEntry& entry = prompt.GetOAuthIssue(i);
566 for (size_t x = 0; x < entry.details.size(); ++x)
567 details.push_back(entry.details[x]);
568 ExpandableContainerView* issue_advice_view =
569 new ExpandableContainerView(
570 this,
571 entry.description,
572 details,
573 space_for_oauth,
574 false);
498 layout->AddView(issue_advice_view); 575 layout->AddView(issue_advice_view);
499 } 576 }
500 } 577 }
501 if (prompt.GetRetainedFileCount()) { 578 if (prompt.GetRetainedFileCount()) {
502 // Slide in under the permissions or OAuth, if there are any. If there are 579 // Slide in under the permissions or OAuth, if there are any. If there are
503 // either, the retained files prompt stretches all the way to the right of 580 // either, the retained files prompt stretches all the way to the right of
504 // the dialog. If there are no permissions or OAuth, the retained files 581 // the dialog. If there are no permissions or OAuth, the retained files
505 // prompt just takes up the left column. 582 // prompt just takes up the left column.
506 int space_for_files = left_column_width; 583 int space_for_files = left_column_width;
507 if (prompt.GetPermissionCount() || prompt.GetOAuthIssueCount()) { 584 if (prompt.GetPermissionCount() || prompt.GetOAuthIssueCount()) {
508 space_for_files += kIconSize; 585 space_for_files += kIconSize;
509 column_set = layout->AddColumnSet(++column_set_id); 586 column_set = layout->AddColumnSet(++column_set_id);
510 column_set->AddColumn(views::GridLayout::FILL, 587 column_set->AddColumn(views::GridLayout::FILL,
511 views::GridLayout::FILL, 588 views::GridLayout::FILL,
512 1, 589 1,
513 views::GridLayout::USE_PREF, 590 views::GridLayout::USE_PREF,
514 0, // no fixed width 591 0, // no fixed width
515 space_for_files); 592 space_for_files);
516 } 593 }
517 594
518 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 595 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
519 596
520 layout->StartRow(0, column_set_id); 597 layout->StartRow(0, column_set_id);
521 views::Label* retained_files_header = NULL; 598 views::Label* retained_files_header = NULL;
522 retained_files_header = new views::Label(prompt.GetRetainedFilesHeading()); 599 retained_files_header =
600 new views::Label(prompt.GetRetainedFilesHeadingWithCount());
523 retained_files_header->SetMultiLine(true); 601 retained_files_header->SetMultiLine(true);
524 retained_files_header->SetHorizontalAlignment(gfx::ALIGN_LEFT); 602 retained_files_header->SetHorizontalAlignment(gfx::ALIGN_LEFT);
525 retained_files_header->SizeToFit(space_for_files); 603 retained_files_header->SizeToFit(space_for_files);
526 layout->AddView(retained_files_header); 604 layout->AddView(retained_files_header);
527 605
528 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
529 layout->StartRow(0, column_set_id); 606 layout->StartRow(0, column_set_id);
530 views::View* files_view = new views::View(); 607 std::vector<string16> details;
531 files_view->SetLayoutManager(new views::BoxLayout( 608 for (size_t i = 0; i < prompt.GetRetainedFileCount(); ++i)
532 views::BoxLayout::kVertical, 609 details.push_back(prompt.GetRetainedFile(i));
533 views::kRelatedControlHorizontalSpacing, 610 ExpandableContainerView* issue_advice_view =
534 0, 611 new ExpandableContainerView(
535 0)); 612 this,
536 for (size_t i = 0; i < prompt.GetRetainedFileCount(); ++i) { 613 string16(),
537 views::Label* retained_file_label = new views::Label(PrepareForDisplay( 614 details,
538 prompt.GetRetainedFile(i), true)); 615 space_for_files,
539 retained_file_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 616 false);
540 files_view->AddChildView(retained_file_label); 617 layout->AddView(issue_advice_view);
541 }
542 views::ScrollView* scroll_view =
543 new MaxSizeScrollView(kMaxRetainedFilesHeight, space_for_files);
544 scroll_view->SetContents(files_view);
545 layout->AddView(scroll_view);
546 } 618 }
619
620 gfx::Size scrollable_size = scrollable_->GetPreferredSize();
621 scrollable_->SetBoundsRect(gfx::Rect(scrollable_size));
622 dialog_size_ = gfx::Size(
623 kDialogWidth,
624 std::min(scrollable_size.height(), kDialogMaxHeight));
547 } 625 }
548 626
549 ExtensionInstallDialogView::~ExtensionInstallDialogView() {} 627 ExtensionInstallDialogView::~ExtensionInstallDialogView() {}
550 628
551 void ExtensionInstallDialogView::SizeToContents() { 629 void ExtensionInstallDialogView::ContentsChanged() {
552 GetWidget()->SetSize(GetWidget()->non_client_view()->GetPreferredSize()); 630 Layout();
553 } 631 }
554 632
555 int ExtensionInstallDialogView::GetDialogButtons() const { 633 int ExtensionInstallDialogView::GetDialogButtons() const {
556 int buttons = prompt_.GetDialogButtons(); 634 int buttons = prompt_.GetDialogButtons();
557 // Simply having just an OK button is *not* supported. See comment on function 635 // Simply having just an OK button is *not* supported. See comment on function
558 // GetDialogButtons in dialog_delegate.h for reasons. 636 // GetDialogButtons in dialog_delegate.h for reasons.
559 DCHECK_GT(buttons & ui::DIALOG_BUTTON_CANCEL, 0); 637 DCHECK_GT(buttons & ui::DIALOG_BUTTON_CANCEL, 0);
560 return buttons; 638 return buttons;
561 } 639 }
562 640
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
601 int event_flags) { 679 int event_flags) {
602 GURL store_url(extension_urls::GetWebstoreItemDetailURLPrefix() + 680 GURL store_url(extension_urls::GetWebstoreItemDetailURLPrefix() +
603 prompt_.extension()->id()); 681 prompt_.extension()->id());
604 OpenURLParams params( 682 OpenURLParams params(
605 store_url, Referrer(), NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_LINK, 683 store_url, Referrer(), NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_LINK,
606 false); 684 false);
607 navigator_->OpenURL(params); 685 navigator_->OpenURL(params);
608 GetWidget()->Close(); 686 GetWidget()->Close();
609 } 687 }
610 688
689 void ExtensionInstallDialogView::Layout() {
690 views::View* contents_view = scroll_view_->contents();
691 int content_width = width();
692 int content_height = contents_view->GetHeightForWidth(content_width);
693 if (content_height > height()) {
694 content_width -= scroll_view_->GetScrollBarWidth();
695 content_height = contents_view->GetHeightForWidth(content_width);
696 }
697 contents_view->SetBounds(0, 0, content_width, content_height);
698 scroll_view_->SetBounds(0, 0, width(), height());
699
700 DialogDelegateView::Layout();
701 }
702
703 gfx::Size ExtensionInstallDialogView::GetPreferredSize() {
704 return dialog_size_;
705 }
706
611 // static 707 // static
612 ExtensionInstallPrompt::ShowDialogCallback 708 ExtensionInstallPrompt::ShowDialogCallback
613 ExtensionInstallPrompt::GetDefaultShowDialogCallback() { 709 ExtensionInstallPrompt::GetDefaultShowDialogCallback() {
614 return base::Bind(&ShowExtensionInstallDialogImpl); 710 return base::Bind(&ShowExtensionInstallDialogImpl);
615 } 711 }
616 712
617 // IssueAdviceView::DetailsView ------------------------------------------------ 713 // ExpandableContainerView::DetailsView ----------------------------------------
618 714
619 IssueAdviceView::DetailsView::DetailsView(int horizontal_space) 715 ExpandableContainerView::DetailsView::DetailsView(
716 int horizontal_space, bool show_bullets)
Peter Kasting 2013/07/11 17:28:34 Nit: This is legal but I think one arg per line is
620 : layout_(new views::GridLayout(this)), 717 : layout_(new views::GridLayout(this)),
621 state_(0) { 718 state_(0),
719 show_bullets_(show_bullets) {
622 SetLayoutManager(layout_); 720 SetLayoutManager(layout_);
623 views::ColumnSet* column_set = layout_->AddColumnSet(0); 721 views::ColumnSet* column_set = layout_->AddColumnSet(0);
722 column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
624 column_set->AddColumn(views::GridLayout::LEADING, 723 column_set->AddColumn(views::GridLayout::LEADING,
625 views::GridLayout::LEADING, 724 views::GridLayout::LEADING,
626 0, 725 0,
627 views::GridLayout::FIXED, 726 views::GridLayout::FIXED,
628 horizontal_space, 727 horizontal_space,
629 0); 728 0);
630 } 729 }
631 730
632 void IssueAdviceView::DetailsView::AddDetail(const string16& detail) { 731 void ExpandableContainerView::DetailsView::AddDetail(const string16& detail) {
633 layout_->StartRowWithPadding(0, 0, 732 layout_->StartRowWithPadding(0, 0,
634 0, views::kRelatedControlSmallVerticalSpacing); 733 0, views::kRelatedControlSmallVerticalSpacing);
635 views::Label* detail_label = 734 views::Label* detail_label =
636 new views::Label(PrepareForDisplay(detail, true)); 735 new views::Label(PrepareForDisplay(detail, show_bullets_));
637 detail_label->SetMultiLine(true); 736 detail_label->SetMultiLine(true);
638 detail_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 737 detail_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
639 layout_->AddView(detail_label); 738 layout_->AddView(detail_label);
640 } 739 }
641 740
642 gfx::Size IssueAdviceView::DetailsView::GetPreferredSize() { 741 gfx::Size ExpandableContainerView::DetailsView::GetPreferredSize() {
643 gfx::Size size = views::View::GetPreferredSize(); 742 gfx::Size size = views::View::GetPreferredSize();
644 return gfx::Size(size.width(), size.height() * state_); 743 return gfx::Size(size.width(), size.height() * state_);
645 } 744 }
646 745
647 void IssueAdviceView::DetailsView::AnimateToState(double state) { 746 void ExpandableContainerView::DetailsView::AnimateToState(double state) {
648 state_ = state; 747 state_ = state;
649 PreferredSizeChanged(); 748 PreferredSizeChanged();
650 SchedulePaint(); 749 SchedulePaint();
651 } 750 }
652 751
653 // IssueAdviceView ------------------------------------------------------------- 752 // ExpandableContainerView -----------------------------------------------------
654 753
655 IssueAdviceView::IssueAdviceView(ExtensionInstallDialogView* owner, 754 ExpandableContainerView::ExpandableContainerView(
656 const IssueAdviceInfoEntry& issue_advice, 755 ExtensionInstallDialogView* owner,
657 int horizontal_space) 756 const string16& description,
757 const std::vector<string16>& details,
758 int horizontal_space,
759 bool show_bullets)
658 : owner_(owner), 760 : owner_(owner),
659 details_view_(NULL), 761 details_view_(NULL),
660 arrow_view_(NULL), 762 arrow_view_(NULL),
661 slide_animation_(this) { 763 slide_animation_(this),
662 // TODO(estade): replace this with a more appropriate image. 764 expanded_(false) {
663 const gfx::ImageSkia& image = *ui::ResourceBundle::GetSharedInstance().
664 GetImageSkiaNamed(IDR_OMNIBOX_TTS);
665
666 views::GridLayout* layout = new views::GridLayout(this); 765 views::GridLayout* layout = new views::GridLayout(this);
667 SetLayoutManager(layout); 766 SetLayoutManager(layout);
668 int column_set_id = 0; 767 int column_set_id = 0;
669 views::ColumnSet* column_set = layout->AddColumnSet(column_set_id); 768 views::ColumnSet* column_set = layout->AddColumnSet(column_set_id);
670 if (!issue_advice.details.empty()) {
671 column_set->AddColumn(views::GridLayout::LEADING,
672 views::GridLayout::LEADING,
673 0,
674 views::GridLayout::FIXED,
675 image.width(),
676 0);
677 horizontal_space -= image.width();
678 details_view_ = new DetailsView(horizontal_space);
679 }
680 column_set->AddColumn(views::GridLayout::LEADING, 769 column_set->AddColumn(views::GridLayout::LEADING,
681 views::GridLayout::FILL, 770 views::GridLayout::LEADING,
682 0, 771 0,
683 views::GridLayout::FIXED, 772 views::GridLayout::USE_PREF,
684 horizontal_space, 773 0,
685 0); 774 0);
686 layout->StartRow(0, column_set_id); 775 if (!description.empty()) {
776 layout->StartRow(0, column_set_id);
687 777
688 if (details_view_) { 778 views::Label* description_label =
689 arrow_view_ = new views::ImageView(); 779 new views::Label(PrepareForDisplay(description, true));
690 arrow_view_->SetImage(image); 780 description_label->SetMultiLine(true);
691 arrow_view_->SetVerticalAlignment(views::ImageView::CENTER); 781 description_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
692 layout->AddView(arrow_view_); 782 description_label->SizeToFit(horizontal_space);
783 layout->AddView(description_label);
693 } 784 }
694 785
695 views::Label* description_label = 786 if (details.empty())
696 new views::Label(PrepareForDisplay(issue_advice.description,
697 !details_view_));
698 description_label->SetMultiLine(true);
699 description_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
700 description_label->SizeToFit(horizontal_space);
701 layout->AddView(description_label);
702
703 if (!details_view_)
704 return; 787 return;
705 788
789 details_view_ = new DetailsView(horizontal_space, show_bullets);
790
706 layout->StartRow(0, column_set_id); 791 layout->StartRow(0, column_set_id);
707 layout->SkipColumns(1);
708 layout->AddView(details_view_); 792 layout->AddView(details_view_);
709 793
710 for (size_t i = 0; i < issue_advice.details.size(); ++i) 794 for (size_t i = 0; i < details.size(); ++i)
711 details_view_->AddDetail(issue_advice.details[i]); 795 details_view_->AddDetail(details[i]);
796
797 // Prepare the columns for the More Details row.
798 column_set = layout->AddColumnSet(++column_set_id);
799 column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
800 column_set->AddColumn(views::GridLayout::LEADING,
801 views::GridLayout::LEADING,
802 0,
803 views::GridLayout::USE_PREF,
804 0,
805 0);
806 column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
807 column_set->AddColumn(views::GridLayout::LEADING,
808 views::GridLayout::LEADING,
809 0,
810 views::GridLayout::USE_PREF,
811 0,
812 0);
813 column_set->AddColumn(views::GridLayout::LEADING,
814 views::GridLayout::LEADING,
815 0,
816 views::GridLayout::USE_PREF,
817 0,
818 0);
819
820 // Add the More Details link.
821 layout->StartRow(0, column_set_id);
822 more_details_ = new views::Link(
823 l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_DETAILS));
824 more_details_->set_listener(this);
825 more_details_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
826 layout->AddView(more_details_);
827
828 // Add the arrow after the More Details link.
829 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
830 arrow_toggle_ = new views::ImageButton(this);
831 arrow_toggle_->SetImage(views::Button::STATE_NORMAL,
832 rb.GetImageSkiaNamed(IDR_DOWN_ARROW));
833 layout->AddView(arrow_toggle_);
712 } 834 }
713 835
714 bool IssueAdviceView::OnMousePressed(const ui::MouseEvent& event) { 836 void ExpandableContainerView::ButtonPressed(
715 return details_view_ && event.IsLeftMouseButton(); 837 views::Button* sender, const ui::Event& event) {
838 ToggleDetailLevel();
716 } 839 }
717 840
718 void IssueAdviceView::OnMouseReleased(const ui::MouseEvent& event) { 841 void ExpandableContainerView::LinkClicked(
842 views::Link* source, int event_flags) {
843 ToggleDetailLevel();
844 }
845
846 void ExpandableContainerView::AnimationProgressed(
847 const ui::Animation* animation) {
848 DCHECK_EQ(animation, &slide_animation_);
Peter Kasting 2013/07/11 17:28:34 Nit: (expected, actual)
849
Peter Kasting 2013/07/11 17:28:34 Nit: I'd remove this blank line
850 if (details_view_)
851 details_view_->AnimateToState(animation->GetCurrentValue());
852 }
853
854 void ExpandableContainerView::AnimationEnded(const ui::Animation* animation) {
855 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
Peter Kasting 2013/07/11 17:28:34 Nit: Avoid non-const refs. (I know this is a comm
856 if (animation->GetCurrentValue() != 0.0) {
857 arrow_toggle_->SetImage(views::Button::STATE_NORMAL,
858 rb.GetImageSkiaNamed(IDR_UP_ARROW));
859 } else {
860 arrow_toggle_->SetImage(views::Button::STATE_NORMAL,
861 rb.GetImageSkiaNamed(IDR_DOWN_ARROW));
862 }
863
864 more_details_->SetText(
865 expanded_ ? l10n_util::GetStringUTF16(IDS_EXTENSIONS_HIDE_DETAILS) :
Peter Kasting 2013/07/11 17:28:34 Nit: Indentation of next line is unusual; prefer t
866 l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_DETAILS));
867 }
868
869 void ExpandableContainerView::ChildPreferredSizeChanged(views::View* child) {
870 owner_->ContentsChanged();
871 }
872
873 void ExpandableContainerView::ToggleDetailLevel() {
874 expanded_ = !expanded_;
875
719 if (slide_animation_.IsShowing()) 876 if (slide_animation_.IsShowing())
720 slide_animation_.Hide(); 877 slide_animation_.Hide();
721 else 878 else
722 slide_animation_.Show(); 879 slide_animation_.Show();
723 } 880 }
724
725 void IssueAdviceView::AnimationProgressed(const ui::Animation* animation) {
726 DCHECK_EQ(animation, &slide_animation_);
727
728 if (details_view_)
729 details_view_->AnimateToState(animation->GetCurrentValue());
730
731 if (arrow_view_) {
732 gfx::Transform rotate;
733 if (animation->GetCurrentValue() != 0.0) {
734 rotate.Translate(arrow_view_->width() / 2.0,
735 arrow_view_->height() / 2.0);
736 // TODO(estade): for some reason there are rendering errors at 90 degrees.
737 // Figure out why.
738 rotate.Rotate(animation->GetCurrentValue() * 89);
739 rotate.Translate(-arrow_view_->width() / 2.0,
740 -arrow_view_->height() / 2.0);
741 }
742 arrow_view_->SetTransform(rotate);
743 }
744 }
745
746 void IssueAdviceView::ChildPreferredSizeChanged(views::View* child) {
747 owner_->SizeToContents();
748 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698