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

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: Polishing 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:
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,
142 virtual ~IssueAdviceView() {} 165 int horizontal_space,
166 bool show_bullets);
167 virtual ~ExpandableContainerView() {}
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:
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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 views::ImageView* icon = new views::ImageView(); 391 views::ImageView* icon = new views::ImageView();
339 icon->SetImageSize(size); 392 icon->SetImageSize(size);
340 icon->SetImage(*image); 393 icon->SetImage(*image);
341 icon->SetHorizontalAlignment(views::ImageView::CENTER); 394 icon->SetHorizontalAlignment(views::ImageView::CENTER);
342 icon->SetVerticalAlignment(views::ImageView::CENTER); 395 icon->SetVerticalAlignment(views::ImageView::CENTER);
343 int icon_row_span = 1; 396 int icon_row_span = 1;
344 if (is_inline_install()) { 397 if (is_inline_install()) {
345 // Also span the rating, user_count and store_link rows. 398 // Also span the rating, user_count and store_link rows.
346 icon_row_span = 4; 399 icon_row_span = 4;
347 } else if (prompt.ShouldShowPermissions()) { 400 } else if (prompt.ShouldShowPermissions()) {
348 size_t permission_count = prompt.GetPermissionCount(); 401 size_t permission_count = prompt.GetPermissionCount(true);
349 if (permission_count > 0) { 402 if (permission_count > 0) {
350 // Also span the permission header and each of the permission rows (all 403 // Also span the permission header and each of the permission rows (all
351 // have a padding row above it). 404 // have a padding row above it).
352 icon_row_span = 3 + permission_count * 2; 405 icon_row_span = 3 + permission_count * 2;
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);
411 extension_label->SizeToFit(left_column_width); 463 extension_label->SizeToFit(left_column_width);
412 layout->AddView(extension_label); 464 layout->AddView(extension_label);
413 } 465 }
414 } 466 }
415 467
416 if (prompt.ShouldShowPermissions()) { 468 if (prompt.ShouldShowPermissions()) {
417 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 469 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
418 470
419 if (prompt.GetPermissionCount() > 0) { 471 if (prompt.GetPermissionCount(true) > 0) {
420 if (is_inline_install()) { 472 if (is_inline_install()) {
421 layout->StartRow(0, column_set_id); 473 layout->StartRow(0, column_set_id);
422 layout->AddView(new views::Separator(views::Separator::HORIZONTAL), 474 layout->AddView(new views::Separator(views::Separator::HORIZONTAL),
423 3, 1, views::GridLayout::FILL, views::GridLayout::FILL); 475 3, 1, views::GridLayout::FILL, views::GridLayout::FILL);
424 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 476 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
425 } 477 }
426 478
427 layout->StartRow(0, column_set_id); 479 layout->StartRow(0, column_set_id);
428 views::Label* permissions_header = NULL; 480 views::Label* permissions_header = NULL;
429 if (is_bundle_install()) { 481 if (is_bundle_install()) {
430 // We need to pass the Font in the constructor, rather than calling 482 // We need to pass the Font in the constructor, rather than calling
431 // SetFont later, because otherwise SizeToFit mis-judges the width 483 // SetFont later, because otherwise SizeToFit mis-judges the width
432 // of the line. 484 // of the line.
433 permissions_header = new views::Label( 485 permissions_header = new views::Label(
434 prompt.GetPermissionsHeading(), 486 prompt.GetPermissionsHeading(),
435 rb.GetFont(ui::ResourceBundle::MediumFont)); 487 rb.GetFont(ui::ResourceBundle::MediumFont));
436 } else { 488 } else {
437 permissions_header = new views::Label(prompt.GetPermissionsHeading()); 489 permissions_header = new views::Label(prompt.GetPermissionsHeading());
438 } 490 }
439 permissions_header->SetMultiLine(true); 491 permissions_header->SetMultiLine(true);
440 permissions_header->SetHorizontalAlignment(gfx::ALIGN_LEFT); 492 permissions_header->SetHorizontalAlignment(gfx::ALIGN_LEFT);
441 permissions_header->SizeToFit(left_column_width); 493 permissions_header->SizeToFit(left_column_width);
442 layout->AddView(permissions_header); 494 layout->AddView(permissions_header);
443 495
444 for (size_t i = 0; i < prompt.GetPermissionCount(); ++i) { 496 for (size_t i = 0; i < prompt.GetPermissionCount(false); ++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, false), 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 // When the long for and short form differ, it means we have more
507 // details to provide, so show it unexpanded.
508 if (prompt.GetPermission(i, true) != prompt.GetPermission(i, false)) {
Yoyo Zhou 2013/07/10 23:18:58 These will differ whenever there is any host list.
509 layout->StartRow(0, column_set_id);
510 std::vector<string16> details;
511 details.push_back(
512 PrepareForDisplay(prompt.GetPermission(i, true), false));
513 ExpandableContainerView* details_container =
514 new ExpandableContainerView(
515 this,
516 string16(),
517 details,
518 left_column_width,
519 false);
520 layout->AddView(details_container);
521 }
453 } 522 }
454 } else { 523 } else {
455 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 524 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
456 layout->StartRow(0, column_set_id); 525 layout->StartRow(0, column_set_id);
457 views::Label* permission_label = new views::Label( 526 views::Label* permission_label = new views::Label(
458 l10n_util::GetStringUTF16(IDS_EXTENSION_NO_SPECIAL_PERMISSIONS)); 527 l10n_util::GetStringUTF16(IDS_EXTENSION_NO_SPECIAL_PERMISSIONS));
459 permission_label->SetMultiLine(true); 528 permission_label->SetMultiLine(true);
460 permission_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 529 permission_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
461 permission_label->SizeToFit(left_column_width); 530 permission_label->SizeToFit(left_column_width);
462 layout->AddView(permission_label); 531 layout->AddView(permission_label);
463 } 532 }
464 } 533 }
465 534
466 if (prompt.GetOAuthIssueCount()) { 535 if (prompt.GetOAuthIssueCount()) {
467 // Slide in under the permissions, if there are any. If there are 536 // Slide in under the permissions, if there are any. If there are
468 // permissions, the OAuth prompt stretches all the way to the right of the 537 // permissions, the OAuth prompt stretches all the way to the right of the
469 // dialog. If there are no permissions, the OAuth prompt just takes up the 538 // dialog. If there are no permissions, the OAuth prompt just takes up the
470 // left column. 539 // left column.
471 int space_for_oauth = left_column_width; 540 int space_for_oauth = left_column_width;
472 if (prompt.GetPermissionCount()) { 541 if (prompt.GetPermissionCount(true)) {
473 space_for_oauth += kIconSize; 542 space_for_oauth += kIconSize;
474 column_set = layout->AddColumnSet(++column_set_id); 543 column_set = layout->AddColumnSet(++column_set_id);
475 column_set->AddColumn(views::GridLayout::FILL, 544 column_set->AddColumn(views::GridLayout::FILL,
476 views::GridLayout::FILL, 545 views::GridLayout::FILL,
477 1, 546 1,
478 views::GridLayout::USE_PREF, 547 views::GridLayout::USE_PREF,
479 0, // no fixed width 548 0, // no fixed width
480 space_for_oauth); 549 space_for_oauth);
481 } 550 }
482 551
483 layout->StartRowWithPadding(0, column_set_id, 552 layout->StartRowWithPadding(0, column_set_id,
484 0, views::kRelatedControlVerticalSpacing); 553 0, views::kRelatedControlVerticalSpacing);
485 views::Label* oauth_header = new views::Label(prompt.GetOAuthHeading()); 554 views::Label* oauth_header = new views::Label(prompt.GetOAuthHeading());
486 oauth_header->SetMultiLine(true); 555 oauth_header->SetMultiLine(true);
487 oauth_header->SetHorizontalAlignment(gfx::ALIGN_LEFT); 556 oauth_header->SetHorizontalAlignment(gfx::ALIGN_LEFT);
488 oauth_header->SizeToFit(left_column_width); 557 oauth_header->SizeToFit(left_column_width);
489 layout->AddView(oauth_header); 558 layout->AddView(oauth_header);
490 559
491 for (size_t i = 0; i < prompt.GetOAuthIssueCount(); ++i) { 560 for (size_t i = 0; i < prompt.GetOAuthIssueCount(); ++i) {
492 layout->StartRowWithPadding( 561 layout->StartRowWithPadding(
493 0, column_set_id, 562 0, column_set_id,
494 0, views::kRelatedControlVerticalSpacing); 563 0, views::kRelatedControlVerticalSpacing);
495 564
496 IssueAdviceView* issue_advice_view = 565 std::vector<string16> details;
497 new IssueAdviceView(this, prompt.GetOAuthIssue(i), space_for_oauth); 566 const IssueAdviceInfoEntry& entry = prompt.GetOAuthIssue(i);
567 for (size_t x = 0; x < entry.details.size(); ++x)
568 details.push_back(entry.details[x]);
569 ExpandableContainerView* issue_advice_view =
570 new ExpandableContainerView(
571 this,
572 entry.description,
573 details,
574 space_for_oauth,
575 false);
498 layout->AddView(issue_advice_view); 576 layout->AddView(issue_advice_view);
499 } 577 }
500 } 578 }
501 if (prompt.GetRetainedFileCount()) { 579 if (prompt.GetRetainedFileCount()) {
502 // Slide in under the permissions or OAuth, if there are any. If there are 580 // 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 581 // 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 582 // the dialog. If there are no permissions or OAuth, the retained files
505 // prompt just takes up the left column. 583 // prompt just takes up the left column.
506 int space_for_files = left_column_width; 584 int space_for_files = left_column_width;
507 if (prompt.GetPermissionCount() || prompt.GetOAuthIssueCount()) { 585 if (prompt.GetPermissionCount(true) || prompt.GetOAuthIssueCount()) {
508 space_for_files += kIconSize; 586 space_for_files += kIconSize;
509 column_set = layout->AddColumnSet(++column_set_id); 587 column_set = layout->AddColumnSet(++column_set_id);
510 column_set->AddColumn(views::GridLayout::FILL, 588 column_set->AddColumn(views::GridLayout::FILL,
511 views::GridLayout::FILL, 589 views::GridLayout::FILL,
512 1, 590 1,
513 views::GridLayout::USE_PREF, 591 views::GridLayout::USE_PREF,
514 0, // no fixed width 592 0, // no fixed width
515 space_for_files); 593 space_for_files);
516 } 594 }
517 595
518 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 596 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
519 597
520 layout->StartRow(0, column_set_id); 598 layout->StartRow(0, column_set_id);
521 views::Label* retained_files_header = NULL; 599 views::Label* retained_files_header = NULL;
522 retained_files_header = new views::Label(prompt.GetRetainedFilesHeading()); 600 retained_files_header =
601 new views::Label(prompt.GetRetainedFilesHeadingWithCount());
523 retained_files_header->SetMultiLine(true); 602 retained_files_header->SetMultiLine(true);
524 retained_files_header->SetHorizontalAlignment(gfx::ALIGN_LEFT); 603 retained_files_header->SetHorizontalAlignment(gfx::ALIGN_LEFT);
525 retained_files_header->SizeToFit(space_for_files); 604 retained_files_header->SizeToFit(space_for_files);
526 layout->AddView(retained_files_header); 605 layout->AddView(retained_files_header);
527 606
528 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
529 layout->StartRow(0, column_set_id); 607 layout->StartRow(0, column_set_id);
530 views::View* files_view = new views::View(); 608 std::vector<string16> details;
531 files_view->SetLayoutManager(new views::BoxLayout( 609 for (size_t i = 0; i < prompt.GetRetainedFileCount(); ++i)
532 views::BoxLayout::kVertical, 610 details.push_back(prompt.GetRetainedFile(i));
533 views::kRelatedControlHorizontalSpacing, 611 ExpandableContainerView* issue_advice_view =
534 0, 612 new ExpandableContainerView(
535 0)); 613 this,
536 for (size_t i = 0; i < prompt.GetRetainedFileCount(); ++i) { 614 string16(),
537 views::Label* retained_file_label = new views::Label(PrepareForDisplay( 615 details,
538 prompt.GetRetainedFile(i), true)); 616 space_for_files,
539 retained_file_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 617 false);
540 files_view->AddChildView(retained_file_label); 618 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 } 619 }
620
621 gfx::Size scrollable_size = scrollable_->GetPreferredSize();
622 scrollable_->SetBoundsRect(gfx::Rect(scrollable_size));
623 dialog_size_ = gfx::Size(
624 kDialogWidth,
625 std::min(scrollable_size.height(), kDialogMaxHeight));
547 } 626 }
548 627
549 ExtensionInstallDialogView::~ExtensionInstallDialogView() {} 628 ExtensionInstallDialogView::~ExtensionInstallDialogView() {}
550 629
551 void ExtensionInstallDialogView::SizeToContents() { 630 void ExtensionInstallDialogView::ContentsChanged() {
552 GetWidget()->SetSize(GetWidget()->non_client_view()->GetPreferredSize()); 631 Layout();
553 } 632 }
554 633
555 int ExtensionInstallDialogView::GetDialogButtons() const { 634 int ExtensionInstallDialogView::GetDialogButtons() const {
556 int buttons = prompt_.GetDialogButtons(); 635 int buttons = prompt_.GetDialogButtons();
557 // Simply having just an OK button is *not* supported. See comment on function 636 // Simply having just an OK button is *not* supported. See comment on function
558 // GetDialogButtons in dialog_delegate.h for reasons. 637 // GetDialogButtons in dialog_delegate.h for reasons.
559 DCHECK_GT(buttons & ui::DIALOG_BUTTON_CANCEL, 0); 638 DCHECK_GT(buttons & ui::DIALOG_BUTTON_CANCEL, 0);
560 return buttons; 639 return buttons;
561 } 640 }
562 641
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
601 int event_flags) { 680 int event_flags) {
602 GURL store_url(extension_urls::GetWebstoreItemDetailURLPrefix() + 681 GURL store_url(extension_urls::GetWebstoreItemDetailURLPrefix() +
603 prompt_.extension()->id()); 682 prompt_.extension()->id());
604 OpenURLParams params( 683 OpenURLParams params(
605 store_url, Referrer(), NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_LINK, 684 store_url, Referrer(), NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_LINK,
606 false); 685 false);
607 navigator_->OpenURL(params); 686 navigator_->OpenURL(params);
608 GetWidget()->Close(); 687 GetWidget()->Close();
609 } 688 }
610 689
690 void ExtensionInstallDialogView::Layout() {
691 views::View* contents_view = scroll_view_->contents();
692 int content_width = width();
693 int content_height = contents_view->GetHeightForWidth(content_width);
694 if (content_height > height()) {
695 content_width -= scroll_view_->GetScrollBarWidth();
696 content_height = contents_view->GetHeightForWidth(content_width);
697 }
698 contents_view->SetBounds(0, 0, content_width, content_height);
699 scroll_view_->SetBounds(0, 0, width(), height());
700
701 DialogDelegateView::Layout();
702 }
703
704 gfx::Size ExtensionInstallDialogView::GetPreferredSize() {
705 return dialog_size_;
706 }
707
611 // static 708 // static
612 ExtensionInstallPrompt::ShowDialogCallback 709 ExtensionInstallPrompt::ShowDialogCallback
613 ExtensionInstallPrompt::GetDefaultShowDialogCallback() { 710 ExtensionInstallPrompt::GetDefaultShowDialogCallback() {
614 return base::Bind(&ShowExtensionInstallDialogImpl); 711 return base::Bind(&ShowExtensionInstallDialogImpl);
615 } 712 }
616 713
617 // IssueAdviceView::DetailsView ------------------------------------------------ 714 // ExpandableContainerView::DetailsView ----------------------------------------
618 715
619 IssueAdviceView::DetailsView::DetailsView(int horizontal_space) 716 ExpandableContainerView::DetailsView::DetailsView(
717 int horizontal_space, bool show_bullets)
620 : layout_(new views::GridLayout(this)), 718 : layout_(new views::GridLayout(this)),
621 state_(0) { 719 state_(0),
720 show_bullets_(show_bullets) {
622 SetLayoutManager(layout_); 721 SetLayoutManager(layout_);
623 views::ColumnSet* column_set = layout_->AddColumnSet(0); 722 views::ColumnSet* column_set = layout_->AddColumnSet(0);
723 column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
624 column_set->AddColumn(views::GridLayout::LEADING, 724 column_set->AddColumn(views::GridLayout::LEADING,
625 views::GridLayout::LEADING, 725 views::GridLayout::LEADING,
626 0, 726 0,
627 views::GridLayout::FIXED, 727 views::GridLayout::FIXED,
628 horizontal_space, 728 horizontal_space,
629 0); 729 0);
630 } 730 }
631 731
632 void IssueAdviceView::DetailsView::AddDetail(const string16& detail) { 732 void ExpandableContainerView::DetailsView::AddDetail(const string16& detail) {
633 layout_->StartRowWithPadding(0, 0, 733 layout_->StartRowWithPadding(0, 0,
634 0, views::kRelatedControlSmallVerticalSpacing); 734 0, views::kRelatedControlSmallVerticalSpacing);
635 views::Label* detail_label = 735 views::Label* detail_label =
636 new views::Label(PrepareForDisplay(detail, true)); 736 new views::Label(PrepareForDisplay(detail, show_bullets_));
637 detail_label->SetMultiLine(true); 737 detail_label->SetMultiLine(true);
638 detail_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 738 detail_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
639 layout_->AddView(detail_label); 739 layout_->AddView(detail_label);
640 } 740 }
641 741
642 gfx::Size IssueAdviceView::DetailsView::GetPreferredSize() { 742 gfx::Size ExpandableContainerView::DetailsView::GetPreferredSize() {
643 gfx::Size size = views::View::GetPreferredSize(); 743 gfx::Size size = views::View::GetPreferredSize();
644 return gfx::Size(size.width(), size.height() * state_); 744 return gfx::Size(size.width(), size.height() * state_);
645 } 745 }
646 746
647 void IssueAdviceView::DetailsView::AnimateToState(double state) { 747 void ExpandableContainerView::DetailsView::AnimateToState(double state) {
648 state_ = state; 748 state_ = state;
649 PreferredSizeChanged(); 749 PreferredSizeChanged();
650 SchedulePaint(); 750 SchedulePaint();
651 } 751 }
652 752
653 // IssueAdviceView ------------------------------------------------------------- 753 // ExpandableContainerView -----------------------------------------------------
654 754
655 IssueAdviceView::IssueAdviceView(ExtensionInstallDialogView* owner, 755 ExpandableContainerView::ExpandableContainerView(
656 const IssueAdviceInfoEntry& issue_advice, 756 ExtensionInstallDialogView* owner,
657 int horizontal_space) 757 const string16& description,
758 const std::vector<string16>& details,
759 int horizontal_space,
760 bool show_bullets)
658 : owner_(owner), 761 : owner_(owner),
659 details_view_(NULL), 762 details_view_(NULL),
660 arrow_view_(NULL), 763 arrow_view_(NULL),
661 slide_animation_(this) { 764 slide_animation_(this),
662 // TODO(estade): replace this with a more appropriate image. 765 expanded_(false) {
663 const gfx::ImageSkia& image = *ui::ResourceBundle::GetSharedInstance().
664 GetImageSkiaNamed(IDR_OMNIBOX_TTS);
665
666 views::GridLayout* layout = new views::GridLayout(this); 766 views::GridLayout* layout = new views::GridLayout(this);
667 SetLayoutManager(layout); 767 SetLayoutManager(layout);
668 int column_set_id = 0; 768 int column_set_id = 0;
669 views::ColumnSet* column_set = layout->AddColumnSet(column_set_id); 769 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, 770 column_set->AddColumn(views::GridLayout::LEADING,
681 views::GridLayout::FILL, 771 views::GridLayout::LEADING,
682 0, 772 0,
683 views::GridLayout::FIXED, 773 views::GridLayout::USE_PREF,
684 horizontal_space, 774 0,
685 0); 775 0);
686 layout->StartRow(0, column_set_id); 776 if (!description.empty()) {
777 layout->StartRow(0, column_set_id);
687 778
688 if (details_view_) { 779 views::Label* description_label =
689 arrow_view_ = new views::ImageView(); 780 new views::Label(PrepareForDisplay(description, true));
690 arrow_view_->SetImage(image); 781 description_label->SetMultiLine(true);
691 arrow_view_->SetVerticalAlignment(views::ImageView::CENTER); 782 description_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
692 layout->AddView(arrow_view_); 783 description_label->SizeToFit(horizontal_space);
784 layout->AddView(description_label);
693 } 785 }
694 786
695 views::Label* description_label = 787 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; 788 return;
705 789
790 details_view_ = new DetailsView(horizontal_space, show_bullets);
791
706 layout->StartRow(0, column_set_id); 792 layout->StartRow(0, column_set_id);
707 layout->SkipColumns(1);
708 layout->AddView(details_view_); 793 layout->AddView(details_view_);
709 794
710 for (size_t i = 0; i < issue_advice.details.size(); ++i) 795 for (size_t i = 0; i < details.size(); ++i)
711 details_view_->AddDetail(issue_advice.details[i]); 796 details_view_->AddDetail(details[i]);
797
798 // Prepare the columns for the More Details row.
799 column_set = layout->AddColumnSet(++column_set_id);
800 column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
801 column_set->AddColumn(views::GridLayout::LEADING,
802 views::GridLayout::LEADING,
803 0,
804 views::GridLayout::USE_PREF,
805 0,
806 0);
807 column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
808 column_set->AddColumn(views::GridLayout::LEADING,
809 views::GridLayout::LEADING,
810 0,
811 views::GridLayout::USE_PREF,
812 0,
813 0);
814 column_set->AddColumn(views::GridLayout::LEADING,
815 views::GridLayout::LEADING,
816 0,
817 views::GridLayout::USE_PREF,
818 0,
819 0);
820
821 // Add the More Details link.
822 layout->StartRow(0, column_set_id);
823 more_details_ = new views::Link(
824 l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_DETAILS));
825 more_details_->set_listener(this);
826 more_details_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
827 layout->AddView(more_details_);
828
829 // Add the arrow after the More Details link.
830 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
831 arrow_toggle_ = new views::ImageButton(this);
832 arrow_toggle_->SetImage(views::Button::STATE_NORMAL,
833 rb.GetImageSkiaNamed(IDR_DOWN_ARROW));
834 layout->AddView(arrow_toggle_);
712 } 835 }
713 836
714 bool IssueAdviceView::OnMousePressed(const ui::MouseEvent& event) { 837 void ExpandableContainerView::ButtonPressed(
715 return details_view_ && event.IsLeftMouseButton(); 838 views::Button* sender, const ui::Event& event) {
839 ToggleDetailLevel();
716 } 840 }
717 841
718 void IssueAdviceView::OnMouseReleased(const ui::MouseEvent& event) { 842 void ExpandableContainerView::LinkClicked(
843 views::Link* source, int event_flags) {
844 ToggleDetailLevel();
845 }
846
847 void ExpandableContainerView::AnimationProgressed(
848 const ui::Animation* animation) {
849 DCHECK_EQ(animation, &slide_animation_);
850
851 if (details_view_)
852 details_view_->AnimateToState(animation->GetCurrentValue());
853 }
854
855 void ExpandableContainerView::AnimationEnded(const ui::Animation* animation) {
856 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
857 if (animation->GetCurrentValue() != 0.0) {
858 arrow_toggle_->SetImage(views::Button::STATE_NORMAL,
859 rb.GetImageSkiaNamed(IDR_UP_ARROW));
860 } else {
861 arrow_toggle_->SetImage(views::Button::STATE_NORMAL,
862 rb.GetImageSkiaNamed(IDR_DOWN_ARROW));
863 }
864
865 more_details_->SetText(
866 expanded_ ? l10n_util::GetStringUTF16(IDS_EXTENSIONS_HIDE_DETAILS) :
867 l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_DETAILS));
868 }
869
870 void ExpandableContainerView::ChildPreferredSizeChanged(views::View* child) {
871 owner_->ContentsChanged();
872 }
873
874 void ExpandableContainerView::ToggleDetailLevel() {
875 expanded_ = !expanded_;
876
719 if (slide_animation_.IsShowing()) 877 if (slide_animation_.IsShowing())
720 slide_animation_.Hide(); 878 slide_animation_.Hide();
721 else 879 else
722 slide_animation_.Show(); 880 slide_animation_.Show();
723 } 881 }
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