1 // Copyright (c) 2006-2008 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.
5 #include "chrome/browser/views/download_shelf_view.h"
9 #include "chrome/app/theme/theme_resources.h"
10 #include "chrome/browser/browser.h"
11 #include "chrome/browser/download/download_item_model.h"
12 #include "chrome/browser/download/download_manager.h"
13 #include "chrome/browser/navigation_entry.h"
14 #include "chrome/browser/tab_contents.h"
15 #include "chrome/browser/views/download_item_view.h"
16 #include "chrome/browser/views/download_tab_view.h"
17 #include "chrome/common/gfx/chrome_canvas.h"
18 #include "chrome/common/l10n_util.h"
19 #include "base/logging.h"
20 #include "chrome/common/resource_bundle.h"
21 #include "chrome/views/background.h"
22 #include "chrome/views/button.h"
23 #include "chrome/views/image_view.h"
25 #include "generated_resources.h"
27 // Max number of download views we'll contain. Any time a view is added and
28 // we already have this many download views, one is removed.
29 static const int kMaxDownloadViews
= 15;
31 // Padding from left edge and first download view.
32 static const int kLeftPadding
= 2;
34 // Padding from right edge and close button/show downloads link.
35 static const int kRightPadding
= 10;
37 // Padding between the show all link and close button.
38 static const int kCloseAndLinkPadding
= 14;
40 // Padding between the download views.
41 static const int kDownloadPadding
= 10;
43 // Padding between the top/bottom and the content.
44 static const int kTopBottomPadding
= 2;
46 // Padding between the icon and 'show all downloads' link
47 static const int kDownloadsTitlePadding
= 4;
49 // Default background color for the shelf.
50 static const SkColor kBackgroundColor
= SkColorSetRGB(230, 237, 244);
53 static const SkColor kBorderColor
= SkColorSetRGB(214, 214, 214);
55 // New download item animation speed in milliseconds.
56 static const int kNewItemAnimationDurationMs
= 800;
58 // Shelf show/hide speed.
59 static const int kShelfAnimationDurationMs
= 120;
63 // Sets size->width() to view's preferred width + size->width().s
64 // Sets size->height() to the max of the view's preferred height and
66 void AdjustSize(ChromeViews::View
* view
, gfx::Size
* size
) {
67 gfx::Size view_preferred
= view
->GetPreferredSize();
68 size
->Enlarge(view_preferred
.width(), 0);
69 size
->set_height(std::max(view_preferred
.height(), size
->height()));
72 int CenterPosition(int size
, int target_size
) {
73 return std::max((target_size
- size
) / 2, kTopBottomPadding
);
78 DownloadShelfView::DownloadShelfView(TabContents
* tab_contents
)
79 : tab_contents_(tab_contents
) {
83 void DownloadShelfView::Init() {
84 ResourceBundle
&rb
= ResourceBundle::GetSharedInstance();
85 arrow_image_
= new ChromeViews::ImageView();
86 arrow_image_
->SetImage(rb
.GetBitmapNamed(IDR_DOWNLOADS_FAVICON
));
87 AddChildView(arrow_image_
);
90 new ChromeViews::Link(l10n_util::GetString(IDS_SHOW_ALL_DOWNLOADS
));
91 show_all_view_
->SetController(this);
92 AddChildView(show_all_view_
);
94 close_button_
= new ChromeViews::Button();
95 close_button_
->SetImage(ChromeViews::Button::BS_NORMAL
,
96 rb
.GetBitmapNamed(IDR_CLOSE_BAR
));
97 close_button_
->SetImage(ChromeViews::Button::BS_HOT
,
98 rb
.GetBitmapNamed(IDR_CLOSE_BAR_H
));
99 close_button_
->SetImage(ChromeViews::Button::BS_PUSHED
,
100 rb
.GetBitmapNamed(IDR_CLOSE_BAR_P
));
101 close_button_
->SetListener(this, 0);
102 AddChildView(close_button_
);
104 ChromeViews::Background::CreateSolidBackground(kBackgroundColor
));
106 new_item_animation_
.reset(new SlideAnimation(this));
107 new_item_animation_
->SetSlideDuration(kNewItemAnimationDurationMs
);
109 shelf_animation_
.reset(new SlideAnimation(this));
110 shelf_animation_
->SetSlideDuration(kShelfAnimationDurationMs
);
111 shelf_animation_
->Show();
114 void DownloadShelfView::AddDownloadView(View
* view
) {
116 download_views_
.push_back(view
);
118 if (download_views_
.size() > kMaxDownloadViews
)
119 RemoveDownloadView(*download_views_
.begin());
121 new_item_animation_
->Reset();
122 new_item_animation_
->Show();
125 void DownloadShelfView::ChangeTabContents(TabContents
* old_contents
,
126 TabContents
* new_contents
) {
127 DCHECK(old_contents
== tab_contents_
);
128 tab_contents_
= new_contents
;
131 void DownloadShelfView::AddDownload(DownloadItem
* download
) {
132 shelf_animation_
->Show();
134 DownloadItemView
* view
= new DownloadItemView(
135 download
, this, new DownloadItemModel(download
));
136 AddDownloadView(view
);
139 void DownloadShelfView::RemoveDownloadView(View
* view
) {
141 std::vector
<View
*>::iterator i
=
142 find(download_views_
.begin(), download_views_
.end(), view
);
143 DCHECK(i
!= download_views_
.end());
144 download_views_
.erase(i
);
145 RemoveChildView(view
);
147 if (download_views_
.empty())
148 tab_contents_
->SetDownloadShelfVisible(false);
153 void DownloadShelfView::Paint(ChromeCanvas
* canvas
) {
154 PaintBackground(canvas
);
158 void DownloadShelfView::PaintBorder(ChromeCanvas
* canvas
) {
159 canvas
->FillRectInt(kBorderColor
, 0, 0, width(), 1);
162 gfx::Size
DownloadShelfView::GetPreferredSize() {
163 gfx::Size
prefsize(kRightPadding
+ kLeftPadding
+ kCloseAndLinkPadding
, 0);
164 AdjustSize(close_button_
, &prefsize
);
165 AdjustSize(show_all_view_
, &prefsize
);
166 // Add one download view to the preferred size.
167 if (download_views_
.size() > 0) {
168 AdjustSize(*download_views_
.begin(), &prefsize
);
169 prefsize
.Enlarge(kDownloadPadding
, 0);
171 prefsize
.Enlarge(0, kTopBottomPadding
+ kTopBottomPadding
);
172 if (shelf_animation_
->IsAnimating()) {
173 prefsize
.set_height(static_cast<int>(
174 static_cast<double>(prefsize
.height()) *
175 shelf_animation_
->GetCurrentValue()));
180 void DownloadShelfView::AnimationProgressed(const Animation
*animation
) {
181 if (animation
== new_item_animation_
.get()) {
184 } else if (animation
== shelf_animation_
.get()) {
185 // Force a re-layout of the parent, which will call back into
186 // GetPreferredSize, where we will do our animation. In the case where the
187 // animation is hiding, we do a full resize - the fast resizing would
188 // otherwise leave blank white areas where the shelf was and where the
189 // user's eye is. Thankfully bottom-resizing is a lot faster than
191 tab_contents_
->ToolbarSizeChanged(shelf_animation_
->IsShowing());
195 void DownloadShelfView::AnimationEnded(const Animation
*animation
) {
196 if (animation
== shelf_animation_
.get()) {
197 tab_contents_
->SetDownloadShelfVisible(shelf_animation_
->IsShowing());
201 void DownloadShelfView::Layout() {
202 // When the download shelf is not visible it is not parented to anything,
203 // which means it is not safe to lay out the controls, so we return early.
204 // Otherwise, we can have problems when for example the user switches to
205 // another tab (that doesn't have a download shelf) _before_ the download
206 // has started and we'll crash when calling SetVisible() below because
207 // the NativeControlContainer ctor tries to use the Container.
211 gfx::Size image_size
= arrow_image_
->GetPreferredSize();
212 gfx::Size close_button_size
= close_button_
->GetPreferredSize();
213 gfx::Size show_all_size
= show_all_view_
->GetPreferredSize();
215 std::max
<int>(0, width() - kRightPadding
- close_button_size
.width() -
216 kCloseAndLinkPadding
- show_all_size
.width() -
217 image_size
.width() - kDownloadPadding
);
218 int next_x
= max_download_x
+ kDownloadPadding
;
219 // Align vertically with show_all_view_.
220 arrow_image_
->SetBounds(next_x
,
221 CenterPosition(show_all_size
.height(), height()),
222 image_size
.width(), image_size
.height());
223 next_x
+= image_size
.width() + kDownloadsTitlePadding
;
224 show_all_view_
->SetBounds(next_x
,
225 CenterPosition(show_all_size
.height(), height()),
226 show_all_size
.width(),
227 show_all_size
.height());
228 next_x
+= show_all_size
.width() + kCloseAndLinkPadding
;
229 close_button_
->SetBounds(next_x
,
230 CenterPosition(close_button_size
.height(), height()),
231 close_button_size
.width(),
232 close_button_size
.height());
234 next_x
= kLeftPadding
;
235 std::vector
<View
*>::reverse_iterator ri
;
236 for (ri
= download_views_
.rbegin(); ri
!= download_views_
.rend(); ++ri
) {
237 gfx::Size view_size
= (*ri
)->GetPreferredSize();
241 // Figure out width of item.
242 int item_width
= view_size
.width();
243 if (new_item_animation_
->IsAnimating() && ri
== download_views_
.rbegin()) {
244 item_width
= static_cast<int>(static_cast<double>(view_size
.width()) *
245 new_item_animation_
->GetCurrentValue());
248 next_x
+= (item_width
+ kDownloadPadding
);
250 // Make sure our item can be contained within the shelf.
251 if (next_x
< max_download_x
) {
252 (*ri
)->SetVisible(true);
253 (*ri
)->SetBounds(x
, CenterPosition(view_size
.height(), height()),
254 item_width
, view_size
.height());
256 (*ri
)->SetVisible(false);
261 // Open the download page.
262 void DownloadShelfView::LinkActivated(ChromeViews::Link
* source
,
265 NavigationController
* controller
= tab_contents_
->controller();
266 Browser
* browser
= Browser::GetBrowserForController(controller
, &index
);
268 browser
->ShowNativeUI(DownloadTabUI::GetURL());
271 void DownloadShelfView::ButtonPressed(ChromeViews::BaseButton
* button
) {
272 shelf_animation_
->Hide();