OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "chrome/browser/download_tab_view.h" | |
6 | |
7 #include <time.h> | |
8 | |
9 #include <algorithm> | |
10 #include <functional> | |
11 | |
12 #include "base/file_util.h" | |
13 #include "base/string_util.h" | |
14 #include "base/task.h" | |
15 #include "base/time_format.h" | |
16 #include "base/timer.h" | |
17 #include "chrome/app/theme/theme_resources.h" | |
18 #include "chrome/browser/browser_process.h" | |
19 #include "chrome/browser/download_manager.h" | |
20 #include "chrome/browser/download_util.h" | |
21 #include "chrome/browser/profile.h" | |
22 #include "chrome/browser/user_metrics.h" | |
23 #include "chrome/common/gfx/chrome_canvas.h" | |
24 #include "chrome/common/gfx/chrome_font.h" | |
25 #include "chrome/common/l10n_util.h" | |
26 #include "chrome/common/resource_bundle.h" | |
27 #include "chrome/common/stl_util-inl.h" | |
28 #include "chrome/common/time_format.h" | |
29 #include "chrome/views/background.h" | |
30 #include "googleurl/src/gurl.h" | |
31 #include "generated_resources.h" | |
32 | |
33 // Approximate spacing, in pixels, taken from initial UI mock up screens | |
34 static const int kVerticalPadding = 5; | |
35 static const int kHorizontalButtonPadding = 15; | |
36 | |
37 // For vertical and horizontal element spacing | |
38 static const int kSpacer = 20; | |
39 | |
40 // Horizontal space between the left edge of the entries and the | |
41 // left edge of the view. | |
42 static const int kLeftMargin = 38; | |
43 | |
44 // x-position of the icon (massage this so it visually matches | |
45 // kDestinationSearchOffset in native_ui_contents.cc | |
46 static const int kDownloadIconOffset = 132; | |
47 | |
48 // Padding between the progress icon and the title, url | |
49 static const int kInfoPadding = 16; | |
50 | |
51 // Horizontal distance from the left window edge to the left icon edge | |
52 static const int kDateSize = 132; | |
53 | |
54 // Maximum size of the text for the file name or URL | |
55 static const int kFilenameSize = 350; | |
56 | |
57 // Maximum size of the progress text during download, which is taken | |
58 // out of kFilenameSize | |
59 static const int kProgressSize = 170; | |
60 | |
61 // Status label color (grey) | |
62 static const SkColor kStatusColor = SkColorSetRGB(128, 128, 128); | |
63 | |
64 // URL label color (green) | |
65 static const SkColor kUrlColor = SkColorSetRGB(0, 128, 0); | |
66 | |
67 // Paused download indicator (red) | |
68 static const SkColor kPauseColor = SkColorSetRGB(128, 0, 0); | |
69 | |
70 // Selected item background color | |
71 static const SkColor kSelectedItemColor = SkColorSetRGB(215, 232, 255); | |
72 | |
73 // State key used to identify search text. | |
74 static const wchar_t kSearchTextKey[] = L"st"; | |
75 | |
76 // Sorting functor for DownloadItem -------------------------------------------- | |
77 | |
78 // Sort DownloadItems into ascending order by their start time. | |
79 class DownloadItemSorter : public std::binary_function<DownloadItem*, | |
80 DownloadItem*, | |
81 bool> { | |
82 public: | |
83 bool operator()(const DownloadItem* lhs, const DownloadItem* rhs) { | |
84 return lhs->start_time() < rhs->start_time(); | |
85 } | |
86 }; | |
87 | |
88 | |
89 // DownloadItemTabView implementation ------------------------------------------ | |
90 DownloadItemTabView::DownloadItemTabView() | |
91 : model_(NULL), | |
92 parent_(NULL) { | |
93 // Create our element views using empty strings for now, | |
94 // set them based on the model's state in Layout(). | |
95 since_ = new ChromeViews::Label(L""); | |
96 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
97 ChromeFont font = rb.GetFont(ResourceBundle::WebFont); | |
98 since_->SetHorizontalAlignment(ChromeViews::Label::ALIGN_LEFT); | |
99 since_->SetFont(font); | |
100 AddChildView(since_); | |
101 | |
102 date_ = new ChromeViews::Label(L""); | |
103 date_->SetColor(kStatusColor); | |
104 date_->SetHorizontalAlignment(ChromeViews::Label::ALIGN_LEFT); | |
105 date_->SetFont(font); | |
106 AddChildView(date_); | |
107 | |
108 // file_name_ is enabled once the download has finished and we can open | |
109 // it via ShellExecute. | |
110 file_name_ = new ChromeViews::Link(L""); | |
111 file_name_->SetHorizontalAlignment(ChromeViews::Label::ALIGN_LEFT); | |
112 file_name_->SetController(this); | |
113 file_name_->SetFont(font); | |
114 AddChildView(file_name_); | |
115 | |
116 // Set our URL name | |
117 download_url_ = new ChromeViews::Label(L""); | |
118 download_url_->SetColor(kUrlColor); | |
119 download_url_->SetHorizontalAlignment(ChromeViews::Label::ALIGN_LEFT); | |
120 download_url_->SetFont(font); | |
121 AddChildView(download_url_); | |
122 | |
123 // Set our time remaining | |
124 time_remaining_ = new ChromeViews::Label(L""); | |
125 time_remaining_->SetColor(kStatusColor); | |
126 time_remaining_->SetHorizontalAlignment(ChromeViews::Label::ALIGN_LEFT); | |
127 time_remaining_->SetFont(font); | |
128 AddChildView(time_remaining_); | |
129 | |
130 // Set our download progress | |
131 download_progress_ = new ChromeViews::Label(L""); | |
132 download_progress_->SetColor(kStatusColor); | |
133 download_progress_->SetHorizontalAlignment(ChromeViews::Label::ALIGN_LEFT); | |
134 download_progress_->SetFont(font); | |
135 AddChildView(download_progress_); | |
136 | |
137 // Set our 'Pause', 'Cancel' and 'Show in folder' links using | |
138 // actual strings, since these are constant | |
139 pause_ = new ChromeViews::Link(l10n_util::GetString(IDS_DOWNLOAD_LINK_PAUSE)); | |
140 pause_->SetController(this); | |
141 pause_->SetFont(font); | |
142 AddChildView(pause_); | |
143 | |
144 cancel_ = new ChromeViews::Link( | |
145 l10n_util::GetString(IDS_DOWNLOAD_LINK_CANCEL)); | |
146 cancel_->SetController(this); | |
147 cancel_->SetFont(font); | |
148 AddChildView(cancel_); | |
149 | |
150 show_ = new ChromeViews::Link(l10n_util::GetString(IDS_DOWNLOAD_LINK_SHOW)); | |
151 show_->SetController(this); | |
152 show_->SetFont(font); | |
153 AddChildView(show_); | |
154 } | |
155 | |
156 DownloadItemTabView::~DownloadItemTabView() { | |
157 } | |
158 | |
159 void DownloadItemTabView::SetModel(DownloadItem* model, | |
160 DownloadTabView* parent) { | |
161 DCHECK(model && parent); | |
162 model_ = model; | |
163 parent_ = parent; | |
164 parent_->LookupIcon(model_); | |
165 } | |
166 | |
167 void DownloadItemTabView::GetPreferredSize(CSize* out) { | |
168 CSize pause_size; | |
169 pause_->GetPreferredSize(&pause_size); | |
170 CSize cancel_size; | |
171 cancel_->GetPreferredSize(&cancel_size); | |
172 CSize show_size; | |
173 show_->GetPreferredSize(&show_size); | |
174 | |
175 out->cx = download_util::kBigProgressIconSize + | |
176 2 * kSpacer + | |
177 kHorizontalButtonPadding + | |
178 kFilenameSize + | |
179 std::max(pause_size.cx + cancel_size.cx + kHorizontalButtonPadding, | |
180 show_size.cx); | |
181 | |
182 out->cy = download_util::kBigProgressIconSize; | |
183 } | |
184 | |
185 // Each DownloadItemTabView has reasonably complex layout requirements | |
186 // that are based on the state of its model. To make the code much simpler | |
187 // to read, Layout() is split into state specific code which will result | |
188 // in some redundant code. | |
189 void DownloadItemTabView::Layout() { | |
190 DCHECK(model_); | |
191 switch (model_->state()) { | |
192 case DownloadItem::COMPLETE: | |
193 LayoutComplete(); | |
194 break; | |
195 case DownloadItem::CANCELLED: | |
196 LayoutCancelled(); | |
197 break; | |
198 case DownloadItem::IN_PROGRESS: | |
199 LayoutInProgress(); | |
200 break; | |
201 case DownloadItem::REMOVING: | |
202 break; | |
203 default: | |
204 NOTREACHED(); | |
205 } | |
206 } | |
207 | |
208 // Only display the date if the download is the last that occurred | |
209 // on a given day. | |
210 void DownloadItemTabView::LayoutDate() { | |
211 if (!parent_->ShouldDrawDateForDownload(model_)) { | |
212 since_->SetVisible(false); | |
213 date_->SetVisible(false); | |
214 return; | |
215 } | |
216 | |
217 CSize since_size; | |
218 | |
219 since_->SetText(TimeFormat::RelativeDate(model_->start_time(), NULL)); | |
220 since_->GetPreferredSize(&since_size); | |
221 since_->SetBounds(kLeftMargin, download_util::kBigProgressIconOffset, | |
222 kDateSize, since_size.cy); | |
223 since_->SetVisible(true); | |
224 | |
225 CSize date_size; | |
226 date_->SetText(base::TimeFormatShortDate(model_->start_time())); | |
227 date_->GetPreferredSize(&date_size); | |
228 date_->SetBounds(kLeftMargin, since_size.cy + kVerticalPadding + | |
229 download_util::kBigProgressIconOffset, | |
230 kDateSize, date_size.cy); | |
231 date_->SetVisible(true); | |
232 } | |
233 | |
234 // DownloadItem::COMPLETE state layout | |
235 void DownloadItemTabView::LayoutComplete() { | |
236 // Hide unused UI elements | |
237 pause_->SetVisible(false); | |
238 pause_->SetEnabled(false); | |
239 cancel_->SetVisible(false); | |
240 cancel_->SetEnabled(false); | |
241 time_remaining_->SetVisible(false); | |
242 download_progress_->SetVisible(false); | |
243 | |
244 LayoutDate(); | |
245 int dx = kDownloadIconOffset - download_util::kBigProgressIconOffset + | |
246 download_util::kBigProgressIconSize + kInfoPadding; | |
247 | |
248 // File name and URL | |
249 CSize file_name_size; | |
250 file_name_->SetText(model_->file_name()); | |
251 file_name_->GetPreferredSize(&file_name_size); | |
252 file_name_->SetBounds(dx, download_util::kBigProgressIconOffset, | |
253 std::min(kFilenameSize, | |
254 static_cast<int>(file_name_size.cx)), | |
255 file_name_size.cy); | |
256 file_name_->SetVisible(true); | |
257 file_name_->SetEnabled(true); | |
258 | |
259 GURL url(model_->url()); | |
260 download_url_->SetURL(url); | |
261 CSize url_size; | |
262 download_url_->GetPreferredSize(&url_size); | |
263 download_url_->SetBounds(dx, | |
264 file_name_size.cy + kVerticalPadding + | |
265 download_util::kBigProgressIconOffset, | |
266 std::min(kFilenameSize, | |
267 static_cast<int>(GetWidth() - dx)), | |
268 url_size.cy); | |
269 download_url_->SetVisible(true); | |
270 dx += kFilenameSize + kSpacer; | |
271 | |
272 // Action button (text is constant and set in constructor) | |
273 CSize show_size; | |
274 show_->GetPreferredSize(&show_size); | |
275 show_->SetBounds(dx, ((file_name_size.cy + url_size.cy) / 2) + | |
276 download_util::kBigProgressIconOffset, | |
277 show_size.cx, show_size.cy); | |
278 show_->SetVisible(true); | |
279 show_->SetEnabled(true); | |
280 } | |
281 | |
282 // DownloadItem::CANCELLED state layout | |
283 void DownloadItemTabView::LayoutCancelled() { | |
284 // Hide unused UI elements | |
285 show_->SetVisible(false); | |
286 show_->SetEnabled(false); | |
287 pause_->SetVisible(false); | |
288 pause_->SetEnabled(false); | |
289 cancel_->SetVisible(false); | |
290 cancel_->SetEnabled(false); | |
291 | |
292 LayoutDate(); | |
293 int dx = kDownloadIconOffset - download_util::kBigProgressIconOffset + | |
294 download_util::kBigProgressIconSize + kInfoPadding; | |
295 | |
296 // File name and URL, truncated to show cancelled status | |
297 CSize file_name_size; | |
298 file_name_->SetText(model_->file_name()); | |
299 file_name_->GetPreferredSize(&file_name_size); | |
300 file_name_->SetBounds(dx, download_util::kBigProgressIconOffset, | |
301 kFilenameSize - kProgressSize - kSpacer, | |
302 file_name_size.cy); | |
303 file_name_->SetVisible(true); | |
304 file_name_->SetEnabled(false); | |
305 | |
306 GURL url(model_->url()); | |
307 download_url_->SetURL(url); | |
308 CSize url_size; | |
309 download_url_->GetPreferredSize(&url_size); | |
310 download_url_->SetBounds(dx, | |
311 file_name_size.cy + kVerticalPadding + | |
312 download_util::kBigProgressIconOffset, | |
313 std::min(kFilenameSize - kProgressSize - kSpacer, | |
314 static_cast<int>(GetWidth() - dx)), | |
315 url_size.cy); | |
316 download_url_->SetVisible(true); | |
317 | |
318 dx += kFilenameSize - kProgressSize; | |
319 | |
320 // Display cancelled status | |
321 CSize cancel_size; | |
322 time_remaining_->SetColor(kStatusColor); | |
323 time_remaining_->SetText(l10n_util::GetString(IDS_DOWNLOAD_TAB_CANCELLED)); | |
324 time_remaining_->GetPreferredSize(&cancel_size); | |
325 time_remaining_->SetBounds(dx, download_util::kBigProgressIconOffset, | |
326 kProgressSize, cancel_size.cy); | |
327 time_remaining_->SetVisible(true); | |
328 | |
329 // Display received size, we may not know the total size if the server didn't | |
330 // provide a content-length. | |
331 int64 total = model_->total_bytes(); | |
332 int64 size = model_->received_bytes(); | |
333 DataUnits amount_units = GetByteDisplayUnits(size); | |
334 std::wstring received_size = FormatBytes(size, amount_units, true); | |
335 std::wstring amount = received_size; | |
336 | |
337 // We don't know which string we'll end up using for constructing the final | |
338 // progress string so we need to adjust both strings for the locale | |
339 // direction. | |
340 std::wstring amount_localized; | |
341 if (l10n_util::AdjustStringForLocaleDirection(amount, &amount_localized)) { | |
342 amount.assign(amount_localized); | |
343 received_size.assign(amount_localized); | |
344 } | |
345 | |
346 if (total > 0) { | |
347 amount_units = GetByteDisplayUnits(total); | |
348 std::wstring total_text = FormatBytes(total, amount_units, true); | |
349 std::wstring total_text_localized; | |
350 if (l10n_util::AdjustStringForLocaleDirection(total_text, | |
351 &total_text_localized)) | |
352 total_text.assign(total_text_localized); | |
353 | |
354 // Note that there is no need to adjust the new amount string for the | |
355 // locale direction as ChromeViews::Label does that for us. | |
356 amount = l10n_util::GetStringF(IDS_DOWNLOAD_TAB_PROGRESS_SIZE, | |
357 received_size, | |
358 total_text); | |
359 } | |
360 | |
361 CSize byte_size; | |
362 download_progress_->SetText(amount); | |
363 download_progress_->GetPreferredSize(&byte_size); | |
364 download_progress_->SetBounds(dx, | |
365 file_name_size.cy + kVerticalPadding + | |
366 download_util::kBigProgressIconOffset, | |
367 kProgressSize, | |
368 byte_size.cy); | |
369 download_progress_->SetVisible(true); | |
370 } | |
371 | |
372 // DownloadItem::IN_PROGRESS state layout | |
373 void DownloadItemTabView::LayoutInProgress() { | |
374 // Hide unused UI elements | |
375 show_->SetVisible(false); | |
376 show_->SetEnabled(false); | |
377 | |
378 LayoutDate(); | |
379 int dx = kDownloadIconOffset - download_util::kBigProgressIconOffset + | |
380 download_util::kBigProgressIconSize + | |
381 kInfoPadding; | |
382 | |
383 // File name and URL, truncated to show progress status | |
384 CSize file_name_size; | |
385 file_name_->SetText(model_->file_name()); | |
386 file_name_->GetPreferredSize(&file_name_size); | |
387 file_name_->SetBounds(dx, download_util::kBigProgressIconOffset, | |
388 kFilenameSize - kProgressSize - kSpacer, | |
389 file_name_size.cy); | |
390 file_name_->SetVisible(true); | |
391 file_name_->SetEnabled(false); | |
392 | |
393 GURL url(model_->url()); | |
394 download_url_->SetURL(url); | |
395 CSize url_size; | |
396 download_url_->GetPreferredSize(&url_size); | |
397 download_url_->SetBounds(dx, file_name_size.cy + kVerticalPadding + | |
398 download_util::kBigProgressIconOffset, | |
399 std::min(kFilenameSize - kProgressSize - kSpacer, | |
400 static_cast<int>(GetWidth() - dx)), | |
401 url_size.cy); | |
402 download_url_->SetVisible(true); | |
403 | |
404 dx += kFilenameSize - kProgressSize; | |
405 | |
406 // Set the time remaining and progress display strings. This can | |
407 // be complicated by not having received the total download size | |
408 // In that case, we can't calculate time remaining so we just | |
409 // display speed and received size. | |
410 | |
411 // Size | |
412 int64 total = model_->total_bytes(); | |
413 int64 size = model_->received_bytes(); | |
414 DataUnits amount_units = GetByteDisplayUnits(size); | |
415 std::wstring received_size = FormatBytes(size, amount_units, true); | |
416 std::wstring amount = received_size; | |
417 | |
418 // Adjust both strings for the locale direction since we don't yet know which | |
419 // string we'll end up using for constructing the final progress string. | |
420 std::wstring amount_localized; | |
421 if (l10n_util::AdjustStringForLocaleDirection(amount, &amount_localized)) { | |
422 amount.assign(amount_localized); | |
423 received_size.assign(amount_localized); | |
424 } | |
425 | |
426 if (total > 0) { | |
427 amount_units = GetByteDisplayUnits(total); | |
428 std::wstring total_text = FormatBytes(total, amount_units, true); | |
429 std::wstring total_text_localized; | |
430 if (l10n_util::AdjustStringForLocaleDirection(total_text, | |
431 &total_text_localized)) | |
432 total_text.assign(total_text_localized); | |
433 | |
434 amount = l10n_util::GetStringF(IDS_DOWNLOAD_TAB_PROGRESS_SIZE, | |
435 received_size, | |
436 total_text); | |
437 | |
438 // We adjust the 'amount' string in case we use it as part of the progress | |
439 // text. | |
440 if (l10n_util::AdjustStringForLocaleDirection(amount, &amount_localized)) | |
441 amount.assign(amount_localized); | |
442 } | |
443 | |
444 // Speed | |
445 int64 speed = model_->CurrentSpeed(); | |
446 std::wstring progress = amount; | |
447 if (!model_->is_paused() && speed > 0) { | |
448 amount_units = GetByteDisplayUnits(speed); | |
449 std::wstring speed_text = FormatSpeed(speed, amount_units, true); | |
450 std::wstring speed_text_localized; | |
451 if (l10n_util::AdjustStringForLocaleDirection(speed_text, | |
452 &speed_text_localized)) | |
453 speed_text.assign(speed_text_localized); | |
454 | |
455 progress = l10n_util::GetStringF(IDS_DOWNLOAD_TAB_PROGRESS_SPEED, | |
456 speed_text, | |
457 amount); | |
458 | |
459 // For some reason, the appearance of the dash character ('-') in a string | |
460 // causes Windows to ignore the 'LRE'/'RLE'/'PDF' Unicode formatting | |
461 // characters within the string and this causes the string to be displayed | |
462 // incorrectly on RTL UIs. Therefore, we add the Unicode right-to-left | |
463 // override character (U+202E) if the locale is RTL in order to fix this | |
464 // problem. | |
465 if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) | |
466 progress.insert(0, L"\x202E"); | |
467 } | |
468 | |
469 // Time remaining | |
470 int y_pos = file_name_size.cy + kVerticalPadding + | |
471 download_util::kBigProgressIconOffset; | |
472 CSize time_size; | |
473 time_remaining_->SetColor(kStatusColor); | |
474 if (model_->is_paused()) { | |
475 time_remaining_->SetColor(kPauseColor); | |
476 time_remaining_->SetText( | |
477 l10n_util::GetString(IDS_DOWNLOAD_PROGRESS_PAUSED)); | |
478 time_remaining_->GetPreferredSize(&time_size); | |
479 time_remaining_->SetBounds(dx, download_util::kBigProgressIconOffset, | |
480 kProgressSize, time_size.cy); | |
481 time_remaining_->SetVisible(true); | |
482 } else if (total > 0) { | |
483 TimeDelta remaining; | |
484 if (model_->TimeRemaining(&remaining)) | |
485 time_remaining_->SetText(TimeFormat::TimeRemaining(remaining)); | |
486 time_remaining_->GetPreferredSize(&time_size); | |
487 time_remaining_->SetBounds(dx, download_util::kBigProgressIconOffset, | |
488 kProgressSize, time_size.cy); | |
489 time_remaining_->SetVisible(true); | |
490 } else { | |
491 time_remaining_->SetText(L""); | |
492 y_pos = ((file_name_size.cy + url_size.cy) / 2) + | |
493 download_util::kBigProgressIconOffset; | |
494 } | |
495 | |
496 CSize byte_size; | |
497 download_progress_->SetText(progress); | |
498 download_progress_->GetPreferredSize(&byte_size); | |
499 download_progress_->SetBounds(dx, y_pos, | |
500 kProgressSize, byte_size.cy); | |
501 download_progress_->SetVisible(true); | |
502 | |
503 dx += kProgressSize + kSpacer; | |
504 y_pos = ((file_name_size.cy + url_size.cy) / 2) + | |
505 download_util::kBigProgressIconOffset; | |
506 | |
507 // Pause (or Resume) / Cancel buttons. | |
508 if (model_->is_paused()) | |
509 pause_->SetText(l10n_util::GetString(IDS_DOWNLOAD_LINK_RESUME)); | |
510 else | |
511 pause_->SetText(l10n_util::GetString(IDS_DOWNLOAD_LINK_PAUSE)); | |
512 | |
513 CSize pause_size; | |
514 pause_->SetVisible(true); | |
515 pause_->SetEnabled(true); | |
516 pause_->GetPreferredSize(&pause_size); | |
517 pause_->SetBounds(dx, y_pos, pause_size.cx, pause_size.cy); | |
518 | |
519 dx += pause_size.cx + kHorizontalButtonPadding; | |
520 | |
521 CSize cancel_size; | |
522 cancel_->GetPreferredSize(&cancel_size); | |
523 cancel_->SetBounds(dx, y_pos, cancel_size.cx, cancel_size.cy); | |
524 cancel_->SetVisible(true); | |
525 cancel_->SetEnabled(true); | |
526 } | |
527 | |
528 void DownloadItemTabView::Paint(ChromeCanvas* canvas) { | |
529 PaintBackground(canvas); | |
530 | |
531 if (model_->state() == DownloadItem::IN_PROGRESS) { | |
532 download_util::PaintDownloadProgress(canvas, | |
533 this, | |
534 kDownloadIconOffset - | |
535 download_util::kBigProgressIconOffset, | |
536 0, | |
537 parent_->start_angle(), | |
538 model_->PercentComplete(), | |
539 download_util::BIG); | |
540 } | |
541 | |
542 // Most of the UI elements in the DownloadItemTabView are represented as | |
543 // child Views and therefore they get mirrored automatically in | |
544 // right-to-left UIs. The download item icon is not contained within a child | |
545 // View so we need to mirror it manually if the locale is RTL. | |
546 SkBitmap* icon = parent_->LookupIcon(model_); | |
547 if (icon) { | |
548 gfx::Rect icon_bounds(kDownloadIconOffset, | |
549 download_util::kBigProgressIconOffset, | |
550 icon->width(), icon->height()); | |
551 icon_bounds.set_x(MirroredLeftPointForRect(icon_bounds)); | |
552 canvas->DrawBitmapInt(*icon, icon_bounds.x(), icon_bounds.y()); | |
553 } | |
554 } | |
555 | |
556 void DownloadItemTabView::PaintBackground(ChromeCanvas* canvas) { | |
557 if (parent_->ItemIsSelected(model_)) { | |
558 // Before we paint the border and the focus rect, we need to mirror the | |
559 // highlighted area if the View is using a right-to-left UI layout. We need | |
560 // to explicitly mirror the position because the highlighted area is | |
561 // directly painted on the canvas (as opposed to being represented as a | |
562 // child View like the rest of the UI elements in DownloadItemTabView). | |
563 gfx::Rect highlighted_bounds(kDownloadIconOffset - | |
564 download_util::kBigProgressIconOffset, | |
565 0, | |
566 download_util::kBigProgressIconSize + | |
567 kInfoPadding + kFilenameSize, | |
568 download_util::kBigProgressIconSize); | |
569 highlighted_bounds.set_x(MirroredLeftPointForRect(highlighted_bounds)); | |
570 | |
571 canvas->FillRectInt(kSelectedItemColor, | |
572 highlighted_bounds.x(), | |
573 highlighted_bounds.y(), | |
574 highlighted_bounds.width(), | |
575 highlighted_bounds.height()); | |
576 | |
577 canvas->DrawFocusRect(highlighted_bounds.x(), | |
578 highlighted_bounds.y(), | |
579 highlighted_bounds.width(), | |
580 highlighted_bounds.height()); | |
581 } | |
582 } | |
583 | |
584 void DownloadItemTabView::DidChangeBounds(const CRect& previous, | |
585 const CRect& current) { | |
586 Layout(); | |
587 } | |
588 | |
589 bool DownloadItemTabView::OnMousePressed(const ChromeViews::MouseEvent& event) { | |
590 CPoint point(event.GetX(), event.GetY()); | |
591 | |
592 // If the click is in the highlight region, then highlight this download. | |
593 // Otherwise, remove the highlighting from any download. | |
594 CRect select_rect(kDownloadIconOffset - download_util::kBigProgressIconOffset, | |
595 0, | |
596 kDownloadIconOffset - | |
597 download_util::kBigProgressIconOffset + | |
598 download_util::kBigProgressIconSize + kInfoPadding + | |
599 kFilenameSize, | |
600 download_util::kBigProgressIconSize); | |
601 | |
602 // The position of the highlighted region does not take into account the | |
603 // View's UI layout so we have to manually mirror the position if the View is | |
604 // using a right-to-left UI layout. | |
605 gfx::Rect mirrored_rect(select_rect); | |
606 select_rect.MoveToX(MirroredLeftPointForRect(mirrored_rect)); | |
607 if (select_rect.PtInRect(point)) { | |
608 parent_->ItemBecameSelected(model_); | |
609 | |
610 if (event.IsRightMouseButton()) { | |
611 ChromeViews::View::ConvertPointToScreen(this, &point); | |
612 | |
613 download_util::DownloadDestinationContextMenu menu( | |
614 model_, GetViewContainer()->GetHWND(), point); | |
615 } | |
616 } else { | |
617 parent_->ItemBecameSelected(NULL); | |
618 } | |
619 | |
620 return true; | |
621 } | |
622 | |
623 // Handle drag (file copy) operations. | |
624 bool DownloadItemTabView::OnMouseDragged(const ChromeViews::MouseEvent& event) { | |
625 if (model_->state() != DownloadItem::COMPLETE) | |
626 return false; | |
627 | |
628 CPoint point(event.GetX(), event.GetY()); | |
629 | |
630 // In order to make sure drag and drop works as expected when the UI is | |
631 // mirrored, we can either flip the mouse X coordinate or flip the X position | |
632 // of the drag rectangle. Flipping the mouse X coordinate is easier. | |
633 point.x = MirroredXCoordinateInsideView(point.x); | |
634 CRect drag_rect(kDownloadIconOffset - download_util::kBigProgressIconOffset, | |
635 0, | |
636 kDownloadIconOffset - download_util::kBigProgressIconOffset + | |
637 download_util::kBigProgressIconSize + kInfoPadding + | |
638 kFilenameSize, | |
639 download_util::kBigProgressIconSize); | |
640 | |
641 if (drag_rect.PtInRect(point)) { | |
642 SkBitmap* icon = parent_->LookupIcon(model_); | |
643 if (icon) | |
644 download_util::DragDownload(model_, icon); | |
645 } | |
646 | |
647 return true; | |
648 } | |
649 | |
650 void DownloadItemTabView::LinkActivated(ChromeViews::Link* source, | |
651 int event_flags) { | |
652 // There are several links in our view that could have been clicked: | |
653 if (source == file_name_) { | |
654 ChromeViews::ViewContainer* container = this->GetViewContainer(); | |
655 HWND parent_window = container ? container->GetHWND() : NULL; | |
656 model_->manager()->OpenDownloadInShell(model_, parent_window); | |
657 } else if (source == pause_) { | |
658 model_->TogglePause(); | |
659 } else if (source == cancel_) { | |
660 model_->Cancel(true /* update history service */); | |
661 } else if (source == show_) { | |
662 model_->manager()->ShowDownloadInShell(model_); | |
663 } else { | |
664 NOTREACHED(); | |
665 } | |
666 | |
667 parent_->ItemBecameSelected(model_); | |
668 } | |
669 | |
670 | |
671 // DownloadTabView implementation ---------------------------------------------- | |
672 | |
673 DownloadTabView::DownloadTabView(DownloadManager* model) | |
674 : model_(model), | |
675 start_angle_(download_util::kStartAngleDegrees), | |
676 scroll_helper_(kSpacer, download_util::kBigProgressIconSize + kSpacer), | |
677 selected_index_(-1) { | |
678 DCHECK(model_); | |
679 } | |
680 | |
681 DownloadTabView::~DownloadTabView() { | |
682 StopDownloadProgress(); | |
683 model_->RemoveObserver(this); | |
684 | |
685 // DownloadManager owns the contents. | |
686 downloads_.clear(); | |
687 ClearDownloadInProgress(); | |
688 | |
689 icon_consumer_.CancelAllRequests(); | |
690 } | |
691 | |
692 void DownloadTabView::Initialize() { | |
693 model_->AddObserver(this); | |
694 } | |
695 | |
696 // Start progress animation timers when we get our first (in-progress) download. | |
697 void DownloadTabView::StartDownloadProgress() { | |
698 if (progress_timer_.IsRunning()) | |
699 return; | |
700 progress_timer_.Start( | |
701 TimeDelta::FromMilliseconds(download_util::kProgressRateMs), this, | |
702 &DownloadTabView::UpdateDownloadProgress); | |
703 } | |
704 | |
705 // Stop progress animation when there are no more in-progress downloads. | |
706 void DownloadTabView::StopDownloadProgress() { | |
707 progress_timer_.Stop(); | |
708 } | |
709 | |
710 // Update our animations. | |
711 void DownloadTabView::UpdateDownloadProgress() { | |
712 start_angle_ = (start_angle_ + download_util::kUnknownIncrementDegrees) % | |
713 download_util::kMaxDegrees; | |
714 SchedulePaint(); | |
715 } | |
716 | |
717 void DownloadTabView::DidChangeBounds(const CRect& previous, | |
718 const CRect& current) { | |
719 Layout(); | |
720 } | |
721 | |
722 void DownloadTabView::Layout() { | |
723 CRect r; | |
724 DetachAllFloatingViews(); | |
725 View* v = GetParent(); | |
726 if (v) { | |
727 v->GetLocalBounds(&r, true); | |
728 int x = GetX(); | |
729 int y = GetY(); | |
730 int w = v->GetWidth(); | |
731 int h = static_cast<int>(downloads_.size()) * | |
732 (download_util::kBigProgressIconSize + kSpacer) + kSpacer; | |
733 SetBounds(x, y, w, h); | |
734 } | |
735 } | |
736 | |
737 // Paint our scrolled region | |
738 void DownloadTabView::Paint(ChromeCanvas* canvas) { | |
739 ChromeViews::View::Paint(canvas); | |
740 | |
741 if (download_util::kBigIconSize == 0 || downloads_.size() == 0) | |
742 return; | |
743 | |
744 SkRect clip; | |
745 if (canvas->getClipBounds(&clip)) { | |
746 int row_start = (SkScalarRound(clip.fTop) - kSpacer) / | |
747 (download_util::kBigProgressIconSize + kSpacer); | |
748 int row_stop = SkScalarRound(clip.fBottom) / | |
749 (download_util::kBigProgressIconSize + kSpacer); | |
750 SkRect download_rect; | |
751 for (int i = row_start; i <= row_stop; ++i) { | |
752 int y = i * (download_util::kBigProgressIconSize + kSpacer) + kSpacer; | |
753 if (HasFloatingViewForPoint(0, y)) | |
754 continue; | |
755 download_rect.set(SkIntToScalar(0), | |
756 SkIntToScalar(y), | |
757 SkIntToScalar(GetWidth()), | |
758 SkIntToScalar(y + download_util::kBigProgressIconSize)); | |
759 if (SkRect::Intersects(clip, download_rect)) { | |
760 // The DownloadManager stores downloads earliest first, but this | |
761 // view displays latest first, so adjust the index: | |
762 int index = static_cast<int>(downloads_.size()) - 1 - i; | |
763 download_renderer_.SetModel(downloads_[index], this); | |
764 PaintFloatingView(canvas, &download_renderer_, | |
765 0, y, | |
766 GetWidth(), download_util::kBigProgressIconSize); | |
767 } | |
768 } | |
769 } | |
770 } | |
771 | |
772 // Draw the DownloadItemTabView for the current position. | |
773 bool DownloadTabView::GetFloatingViewIDForPoint(int x, int y, int* id) { | |
774 if (y < kSpacer || | |
775 y > (kSpacer + download_util::kBigProgressIconSize) * | |
776 static_cast<int>(downloads_.size())) | |
777 return false; | |
778 | |
779 // Are we hovering over a download or the spacer? If we're over the | |
780 // download, create a floating view for it. | |
781 if ((y - kSpacer) % (download_util::kBigProgressIconSize + kSpacer) < | |
782 download_util::kBigProgressIconSize) { | |
783 int row = y / (download_util::kBigProgressIconSize + kSpacer); | |
784 *id = static_cast<int>(downloads_.size()) - 1 - row; | |
785 return true; | |
786 } | |
787 return false; | |
788 } | |
789 | |
790 ChromeViews::View* DownloadTabView::CreateFloatingViewForIndex(int index) { | |
791 if (index >= static_cast<int>(downloads_.size())) { | |
792 // It's possible that the downloads have been cleared via the "Clear | |
793 // Browsing Data" command, so this index is gone. | |
794 return NULL; | |
795 } | |
796 | |
797 DownloadItemTabView* dl = new DownloadItemTabView(); | |
798 dl->SetModel(downloads_[index], this); | |
799 int row = static_cast<int>(downloads_.size()) - 1 - index; | |
800 int y_pos = row * (download_util::kBigProgressIconSize + kSpacer) + kSpacer; | |
801 dl->SetBounds(0, y_pos, GetWidth(), download_util::kBigProgressIconSize); | |
802 dl->Layout(); | |
803 AttachFloatingView(dl, index); | |
804 return dl; | |
805 } | |
806 | |
807 bool DownloadTabView::EnumerateFloatingViews( | |
808 ChromeViews::View::FloatingViewPosition position, | |
809 int starting_id, int* id) { | |
810 DCHECK(id); | |
811 return View::EnumerateFloatingViewsForInterval( | |
812 0, static_cast<int>(downloads_.size()), false, position, starting_id, id); | |
813 } | |
814 | |
815 ChromeViews::View* DownloadTabView::ValidateFloatingViewForID(int id) { | |
816 return CreateFloatingViewForIndex(id); | |
817 } | |
818 | |
819 void DownloadTabView::OnDownloadUpdated(DownloadItem* download) { | |
820 switch (download->state()) { | |
821 case DownloadItem::COMPLETE: | |
822 case DownloadItem::CANCELLED: { | |
823 base::hash_set<DownloadItem*>::iterator d = in_progress_.find(download); | |
824 if (d != in_progress_.end()) { | |
825 (*d)->RemoveObserver(this); | |
826 in_progress_.erase(d); | |
827 } | |
828 if (in_progress_.empty()) | |
829 StopDownloadProgress(); | |
830 LoadIcon(download); | |
831 break; | |
832 } | |
833 case DownloadItem::IN_PROGRESS: { | |
834 // If all IN_PROGRESS downloads are paused, don't waste CPU issuing any | |
835 // further progress updates until at least one download is active again. | |
836 if (download->is_paused()) { | |
837 bool continue_update = false; | |
838 base::hash_set<DownloadItem*>::iterator it = in_progress_.begin(); | |
839 for (; it != in_progress_.end(); ++it) { | |
840 if (!(*it)->is_paused()) { | |
841 continue_update = true; | |
842 break; | |
843 } | |
844 } | |
845 if (!continue_update) | |
846 StopDownloadProgress(); | |
847 } else { | |
848 StartDownloadProgress(); | |
849 } | |
850 break; | |
851 } | |
852 case DownloadItem::REMOVING: | |
853 // Handled below. | |
854 break; | |
855 default: | |
856 NOTREACHED(); | |
857 break; | |
858 } | |
859 | |
860 OrderedDownloads::iterator it = find(downloads_.begin(), | |
861 downloads_.end(), | |
862 download); | |
863 if (it == downloads_.end()) | |
864 return; | |
865 | |
866 const int index = static_cast<int>(it - downloads_.begin()); | |
867 DownloadItemTabView* view = | |
868 static_cast<DownloadItemTabView*>(RetrieveFloatingViewForID(index)); | |
869 if (view) { | |
870 if (download->state() != DownloadItem::REMOVING) { | |
871 view->Layout(); | |
872 SchedulePaintForViewAtIndex(index); | |
873 } else if (selected_index_ == index) { | |
874 selected_index_ = -1; | |
875 } | |
876 } | |
877 } | |
878 | |
879 // A download has started or been deleted. Query our DownloadManager for the | |
880 // current set of downloads, which will call us back in SetDownloads once it | |
881 // has retrieved them. | |
882 void DownloadTabView::ModelChanged() { | |
883 downloads_.clear(); | |
884 ClearDownloadInProgress(); | |
885 DetachAllFloatingViews(); | |
886 | |
887 // Issue the query. | |
888 model_->GetDownloads(this, search_text_); | |
889 } | |
890 | |
891 void DownloadTabView::SetDownloads(std::vector<DownloadItem*>& downloads) { | |
892 // Stop progress timers. | |
893 StopDownloadProgress(); | |
894 | |
895 // Clear out old state and remove self as observer for each download. | |
896 downloads_.clear(); | |
897 ClearDownloadInProgress(); | |
898 | |
899 // Swap new downloads in. | |
900 downloads_.swap(downloads); | |
901 sort(downloads_.begin(), downloads_.end(), DownloadItemSorter()); | |
902 | |
903 // Scan for any in progress downloads and add ourself to them as an observer. | |
904 for (OrderedDownloads::iterator it = downloads_.begin(); | |
905 it != downloads_.end(); ++it) { | |
906 DownloadItem* download = *it; | |
907 if (download->state() == DownloadItem::IN_PROGRESS) { | |
908 download->AddObserver(this); | |
909 in_progress_.insert(download); | |
910 } | |
911 } | |
912 | |
913 // Start any progress timers if required. | |
914 if (!in_progress_.empty()) | |
915 StartDownloadProgress(); | |
916 | |
917 // Update the UI. | |
918 selected_index_ = -1; | |
919 GetParent()->GetParent()->Layout(); | |
920 SchedulePaint(); | |
921 } | |
922 | |
923 | |
924 // If we have the icon in our cache, then return it. If not, look it up via the | |
925 // IconManager. Ignore in progress requests (duplicates). | |
926 SkBitmap* DownloadTabView::LookupIcon(DownloadItem* download) { | |
927 IconManager* im = g_browser_process->icon_manager(); | |
928 // Fast look up. | |
929 SkBitmap* icon = im->LookupIcon(download->full_path(), IconLoader::NORMAL); | |
930 | |
931 // Expensive look up. | |
932 if (!icon) | |
933 LoadIcon(download); | |
934 | |
935 return icon; | |
936 } | |
937 | |
938 // Bypass the caches and perform the Icon extraction directly. This is useful in | |
939 // the case where the download has completed and we want to re-check the file | |
940 // to see if it has an embedded icon (which we couldn't do at download start). | |
941 void DownloadTabView::LoadIcon(DownloadItem* download) { | |
942 IconManager* im = g_browser_process->icon_manager(); | |
943 IconManager::Handle h = | |
944 im->LoadIcon(download->full_path(), IconLoader::NORMAL, | |
945 &icon_consumer_, | |
946 NewCallback(this, &DownloadTabView::OnExtractIconComplete)); | |
947 icon_consumer_.SetClientData(im, h, download); | |
948 } | |
949 | |
950 void DownloadTabView::ClearDownloadInProgress() { | |
951 for (base::hash_set<DownloadItem*>::iterator it = in_progress_.begin(); | |
952 it != in_progress_.end(); ++it) | |
953 (*it)->RemoveObserver(this); | |
954 in_progress_.clear(); | |
955 } | |
956 | |
957 // Check to see if the download is the latest download on a given day. | |
958 // We use this to determine when to draw the date next to a particular | |
959 // download view: if the DownloadItem is the latest download on a given | |
960 // day, the date gets drawn. | |
961 bool DownloadTabView::ShouldDrawDateForDownload(DownloadItem* download) { | |
962 DCHECK(download); | |
963 OrderedDownloads::iterator it = find(downloads_.begin(), | |
964 downloads_.end(), | |
965 download); | |
966 DCHECK(it != downloads_.end()); | |
967 const int index = static_cast<int>(it - downloads_.begin()); | |
968 | |
969 // If download is the last or only download, it draws the date. | |
970 if (downloads_.size() - 1 == index) | |
971 return true; | |
972 | |
973 const DownloadItem* next = downloads_[index + 1]; | |
974 | |
975 Time next_midnight = next->start_time().LocalMidnight(); | |
976 Time curr_midnight = download->start_time().LocalMidnight(); | |
977 if (next_midnight == curr_midnight) { | |
978 // 'next' happened today: let it draw the date so we don't have to. | |
979 return false; | |
980 } | |
981 return true; | |
982 } | |
983 | |
984 int DownloadTabView::GetPageScrollIncrement( | |
985 ChromeViews::ScrollView* scroll_view, bool is_horizontal, | |
986 bool is_positive) { | |
987 return scroll_helper_.GetPageScrollIncrement(scroll_view, is_horizontal, | |
988 is_positive); | |
989 } | |
990 | |
991 int DownloadTabView::GetLineScrollIncrement( | |
992 ChromeViews::ScrollView* scroll_view, bool is_horizontal, | |
993 bool is_positive) { | |
994 return scroll_helper_.GetLineScrollIncrement(scroll_view, is_horizontal, | |
995 is_positive); | |
996 } | |
997 | |
998 void DownloadTabView::ItemBecameSelected(const DownloadItem* download) { | |
999 int index = -1; | |
1000 if (download != NULL) { | |
1001 OrderedDownloads::const_iterator it = find(downloads_.begin(), | |
1002 downloads_.end(), | |
1003 download); | |
1004 DCHECK(it != downloads_.end()); | |
1005 index = static_cast<int>(it - downloads_.begin()); | |
1006 if (index == selected_index_) | |
1007 return; // Avoid unnecessary paint. | |
1008 } | |
1009 | |
1010 if (selected_index_ >= 0) | |
1011 SchedulePaintForViewAtIndex(selected_index_); | |
1012 if (index >= 0) | |
1013 SchedulePaintForViewAtIndex(index); | |
1014 selected_index_ = index; | |
1015 } | |
1016 | |
1017 bool DownloadTabView::ItemIsSelected(DownloadItem* download) { | |
1018 OrderedDownloads::iterator it = find(downloads_.begin(), | |
1019 downloads_.end(), | |
1020 download); | |
1021 if (it != downloads_.end()) | |
1022 return selected_index_ == static_cast<int>(it - downloads_.begin()); | |
1023 return false; | |
1024 } | |
1025 | |
1026 void DownloadTabView::SchedulePaintForViewAtIndex(int index) { | |
1027 int y = GetYPositionForIndex(index); | |
1028 SchedulePaint(0, y, GetWidth(), download_util::kBigProgressIconSize); | |
1029 } | |
1030 | |
1031 int DownloadTabView::GetYPositionForIndex(int index) { | |
1032 int row = static_cast<int>(downloads_.size()) - 1 - index; | |
1033 return row * (download_util::kBigProgressIconSize + kSpacer) + kSpacer; | |
1034 } | |
1035 | |
1036 void DownloadTabView::SetSearchText(const std::wstring& search_text) { | |
1037 search_text_ = search_text; | |
1038 model_->GetDownloads(this, search_text_); | |
1039 } | |
1040 | |
1041 // The 'icon_bitmap' is ignored here, since it is cached by the IconManager. | |
1042 // When the paint message runs, we'll use the fast IconManager lookup API to | |
1043 // retrieve it. | |
1044 void DownloadTabView::OnExtractIconComplete(IconManager::Handle handle, | |
1045 SkBitmap* icon_bitmap) { | |
1046 IconManager* im = g_browser_process->icon_manager(); | |
1047 DownloadItem* download = icon_consumer_.GetClientData(im, handle); | |
1048 OrderedDownloads::iterator it = find(downloads_.begin(), | |
1049 downloads_.end(), | |
1050 download); | |
1051 if (it != downloads_.end()) { | |
1052 const int index = static_cast<int>(it - downloads_.begin()); | |
1053 SchedulePaintForViewAtIndex(index); | |
1054 } | |
1055 } | |
1056 | |
1057 // DownloadTabUIFactory ------------------------------------------------------ | |
1058 | |
1059 class DownloadTabUIFactory : public NativeUIFactory { | |
1060 public: | |
1061 DownloadTabUIFactory() {} | |
1062 virtual ~DownloadTabUIFactory() {} | |
1063 | |
1064 virtual NativeUI* CreateNativeUIForURL(const GURL& url, | |
1065 NativeUIContents* contents) { | |
1066 return new DownloadTabUI(contents); | |
1067 } | |
1068 | |
1069 private: | |
1070 DISALLOW_EVIL_CONSTRUCTORS(DownloadTabUIFactory); | |
1071 }; | |
1072 | |
1073 // DownloadTabUI ------------------------------------------------------------- | |
1074 | |
1075 DownloadTabUI::DownloadTabUI(NativeUIContents* contents) | |
1076 #pragma warning(suppress: 4355) // Okay to pass "this" here. | |
1077 : searchable_container_(this), | |
1078 download_tab_view_(NULL), | |
1079 contents_(contents) { | |
1080 DownloadManager* dlm = contents_->profile()->GetDownloadManager(); | |
1081 download_tab_view_ = new DownloadTabView(dlm); | |
1082 searchable_container_.SetContents(download_tab_view_); | |
1083 download_tab_view_->Initialize(); | |
1084 | |
1085 NotificationService* ns = NotificationService::current(); | |
1086 ns->AddObserver(this, NOTIFY_DOWNLOAD_START, | |
1087 NotificationService::AllSources()); | |
1088 ns->AddObserver(this, NOTIFY_DOWNLOAD_STOP, | |
1089 NotificationService::AllSources()); | |
1090 | |
1091 // Spin the throbber if there are active downloads, since we may have been | |
1092 // created after the NOTIFY_DOWNLOAD_START was sent. If the download manager | |
1093 // has not been created, don't bother since it will negatively impact start | |
1094 // up time with history requests. | |
1095 Profile* profile = contents_->profile(); | |
1096 if (profile && | |
1097 profile->HasCreatedDownloadManager() && | |
1098 profile->GetDownloadManager()->in_progress_count() > 0) | |
1099 contents_->SetIsLoading(true, NULL); | |
1100 } | |
1101 | |
1102 DownloadTabUI::~DownloadTabUI() { | |
1103 NotificationService* ns = NotificationService::current(); | |
1104 ns->RemoveObserver(this, NOTIFY_DOWNLOAD_START, | |
1105 NotificationService::AllSources()); | |
1106 ns->RemoveObserver(this, NOTIFY_DOWNLOAD_STOP, | |
1107 NotificationService::AllSources()); | |
1108 } | |
1109 | |
1110 const std::wstring DownloadTabUI::GetTitle() const { | |
1111 return l10n_util::GetString(IDS_DOWNLOAD_TITLE); | |
1112 } | |
1113 | |
1114 const int DownloadTabUI::GetFavIconID() const { | |
1115 return IDR_DOWNLOADS_FAVICON; | |
1116 } | |
1117 | |
1118 const int DownloadTabUI::GetSectionIconID() const { | |
1119 return IDR_DOWNLOADS_SECTION; | |
1120 } | |
1121 | |
1122 const std::wstring DownloadTabUI::GetSearchButtonText() const { | |
1123 return l10n_util::GetString(IDS_DOWNLOAD_SEARCH_BUTTON); | |
1124 } | |
1125 | |
1126 ChromeViews::View* DownloadTabUI::GetView() { | |
1127 return &searchable_container_; | |
1128 } | |
1129 | |
1130 void DownloadTabUI::WillBecomeVisible(NativeUIContents* parent) { | |
1131 UserMetrics::RecordAction(L"Destination_Downloads", parent->profile()); | |
1132 } | |
1133 | |
1134 void DownloadTabUI::WillBecomeInvisible(NativeUIContents* parent) { | |
1135 } | |
1136 | |
1137 void DownloadTabUI::Navigate(const PageState& state) { | |
1138 std::wstring search_text; | |
1139 state.GetProperty(kSearchTextKey, &search_text); | |
1140 download_tab_view_->SetSearchText(search_text); | |
1141 searchable_container_.GetSearchField()->SetText(search_text); | |
1142 } | |
1143 | |
1144 bool DownloadTabUI::SetInitialFocus() { | |
1145 searchable_container_.GetSearchField()->RequestFocus(); | |
1146 return true; | |
1147 } | |
1148 | |
1149 // static | |
1150 GURL DownloadTabUI::GetURL() { | |
1151 std::string spec(NativeUIContents::GetScheme()); | |
1152 spec.append("://downloads"); | |
1153 return GURL(spec); | |
1154 } | |
1155 | |
1156 // static | |
1157 NativeUIFactory* DownloadTabUI::GetNativeUIFactory() { | |
1158 return new DownloadTabUIFactory(); | |
1159 } | |
1160 | |
1161 void DownloadTabUI::DoSearch(const std::wstring& new_text) { | |
1162 download_tab_view_->SetSearchText(new_text); | |
1163 PageState* page_state = contents_->page_state().Copy(); | |
1164 page_state->SetProperty(kSearchTextKey, new_text); | |
1165 contents_->SetPageState(page_state); | |
1166 } | |
1167 | |
1168 void DownloadTabUI::Observe(NotificationType type, | |
1169 const NotificationSource& source, | |
1170 const NotificationDetails& details) { | |
1171 switch (type) { | |
1172 case NOTIFY_DOWNLOAD_START: | |
1173 case NOTIFY_DOWNLOAD_STOP: | |
1174 DCHECK(profile()->HasCreatedDownloadManager()); | |
1175 contents_->SetIsLoading( | |
1176 profile()->GetDownloadManager()->in_progress_count() > 0, | |
1177 NULL); | |
1178 break; | |
1179 default: | |
1180 break; | |
1181 } | |
1182 } | |
1183 | |
OLD | NEW |