diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
commit | 09911bf300f1a419907a9412154760efd0b7abc3 (patch) | |
tree | f131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/download_util.cc | |
parent | 586acc5fe142f498261f52c66862fa417c3d52d2 (diff) | |
download | chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2 |
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/download_util.cc')
-rw-r--r-- | chrome/browser/download_util.cc | 456 |
1 files changed, 456 insertions, 0 deletions
diff --git a/chrome/browser/download_util.cc b/chrome/browser/download_util.cc new file mode 100644 index 0000000..7a4ff51 --- /dev/null +++ b/chrome/browser/download_util.cc @@ -0,0 +1,456 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Download utility implementation + +#include <string> + +#include "chrome/browser/download_util.h" + +#include "base/base_drag_source.h" +#include "base/file_util.h" +#include "base/gfx/image_operations.h" +#include "chrome/app/theme/theme_resources.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/download_manager.h" +#include "chrome/common/clipboard_service.h" +#include "chrome/browser/drag_utils.h" +#include "chrome/common/gfx/chrome_canvas.h" +#include "chrome/common/l10n_util.h" +#include "chrome/common/os_exchange_data.h" +#include "chrome/common/resource_bundle.h" +#include "chrome/views/view.h" +#include "generated_resources.h" +#include "SkPath.h" +#include "SkShader.h" + +namespace download_util { + +// BaseContextMenu ------------------------------------------------------------- + +BaseContextMenu::BaseContextMenu(DownloadItem* download) : download_(download) { +} + +BaseContextMenu::~BaseContextMenu() { +} + +// How many times to cycle the complete animation. This should be an odd number +// so that the animation ends faded out. +static const int kCompleteAnimationCycles = 5; + +bool BaseContextMenu::IsItemChecked(int id) const { + switch (id) { + case OPEN_WHEN_COMPLETE: + return download_->open_when_complete(); + case ALWAYS_OPEN_TYPE: { + const std::wstring extension = + file_util::GetFileExtensionFromPath(download_->full_path()); + return download_->manager()->ShouldOpenFileExtension(extension); + } + } + return false; +} + +bool BaseContextMenu::IsItemDefault(int id) const { + return false; +} + +std::wstring BaseContextMenu::GetLabel(int id) const { + switch (id) { + case SHOW_IN_FOLDER: + return l10n_util::GetString(IDS_DOWNLOAD_LINK_SHOW); + case COPY_LINK: + return l10n_util::GetString(IDS_CONTENT_CONTEXT_COPYLINKLOCATION); + case COPY_PATH: + return l10n_util::GetString(IDS_DOWNLOAD_MENU_COPY_PATH); + case COPY_FILE: + return l10n_util::GetString(IDS_DOWNLOAD_MENU_COPY_FILE); + case OPEN_WHEN_COMPLETE: + if (download_->state() == DownloadItem::IN_PROGRESS) + return l10n_util::GetString(IDS_DOWNLOAD_MENU_OPEN_WHEN_COMPLETE); + return l10n_util::GetString(IDS_DOWNLOAD_MENU_OPEN); + case ALWAYS_OPEN_TYPE: + return l10n_util::GetString(IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE); + case REMOVE_ITEM: + return l10n_util::GetString(IDS_DOWNLOAD_MENU_REMOVE_ITEM); + case CANCEL: + return l10n_util::GetString(IDS_DOWNLOAD_MENU_CANCEL); + default: + NOTREACHED(); + } + return std::wstring(); +} + +bool BaseContextMenu::SupportsCommand(int id) const { + return id > 0 && id < MENU_LAST; +} + +bool BaseContextMenu::IsCommandEnabled(int id) const { + switch (id) { + case SHOW_IN_FOLDER: + case COPY_PATH: + case COPY_FILE: + case OPEN_WHEN_COMPLETE: + return download_->state() != DownloadItem::CANCELLED; + case ALWAYS_OPEN_TYPE: + return CanOpenDownload(download_); + case CANCEL: + return download_->state() == DownloadItem::IN_PROGRESS; + default: + return id > 0 && id < MENU_LAST; + } +} + +void BaseContextMenu::ExecuteCommand(int id) { + ClipboardService* clipboard = g_browser_process->clipboard_service(); + DCHECK(clipboard); + switch (id) { + case SHOW_IN_FOLDER: + download_->manager()->ShowDownloadInShell(download_); + break; + case COPY_LINK: + clipboard->Clear(); + clipboard->WriteText(download_->url()); + break; + case COPY_PATH: + clipboard->Clear(); + clipboard->WriteText(download_->full_path()); + break; + case COPY_FILE: + // TODO(paulg): Move to OSExchangeData when implementing drag and drop? + clipboard->Clear(); + clipboard->WriteFile(download_->full_path()); + break; + case OPEN_WHEN_COMPLETE: + OpenDownload(download_); + break; + case ALWAYS_OPEN_TYPE: { + const std::wstring extension = + file_util::GetFileExtensionFromPath(download_->full_path()); + download_->manager()->OpenFilesOfExtension( + extension, !IsItemChecked(ALWAYS_OPEN_TYPE)); + break; + } + case REMOVE_ITEM: + download_->Remove(); + break; + case CANCEL: + download_->Cancel(true); + break; + default: + NOTREACHED(); + } +} + +// DownloadShelfContextMenu ---------------------------------------------------- + +DownloadShelfContextMenu::DownloadShelfContextMenu( + DownloadItem* download, + HWND window, + DownloadItemView::BaseDownloadItemModel* model, + const CPoint& point) + : BaseContextMenu(download), + model_(model) { + DCHECK(model_); + + // The menu's anchor point is determined based on the UI layout. + Menu::AnchorPoint anchor_point; + if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) + anchor_point = Menu::TOPRIGHT; + else + anchor_point = Menu::TOPLEFT; + + Menu context_menu(this, anchor_point, window); + if (download->state() == DownloadItem::COMPLETE) + context_menu.AppendMenuItem(OPEN_WHEN_COMPLETE, L"", Menu::NORMAL); + else + context_menu.AppendMenuItem(OPEN_WHEN_COMPLETE, L"", Menu::CHECKBOX); + context_menu.AppendMenuItem(ALWAYS_OPEN_TYPE, L"", Menu::CHECKBOX); + context_menu.AppendSeparator(); + context_menu.AppendMenuItem(SHOW_IN_FOLDER, L"", Menu::NORMAL); + context_menu.AppendSeparator(); + context_menu.AppendMenuItem(CANCEL, L"", Menu::NORMAL); + context_menu.RunMenuAt(point.x, point.y); +} + +DownloadShelfContextMenu::~DownloadShelfContextMenu() { +} + +bool DownloadShelfContextMenu::IsItemDefault(int id) const { + return id == OPEN_WHEN_COMPLETE; +} + +void DownloadShelfContextMenu::ExecuteCommand(int id) { + if (id == CANCEL) + model_->CancelTask(); + else + BaseContextMenu::ExecuteCommand(id); +} + +// DownloadDestinationContextMenu ---------------------------------------------- + +DownloadDestinationContextMenu::DownloadDestinationContextMenu( + DownloadItem* download, + HWND window, + const CPoint& point) + : BaseContextMenu(download) { + // The menu's anchor point is determined based on the UI layout. + Menu::AnchorPoint anchor_point; + if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) + anchor_point = Menu::TOPRIGHT; + else + anchor_point = Menu::TOPLEFT; + + Menu context_menu(this, anchor_point, window); + context_menu.AppendMenuItem(SHOW_IN_FOLDER, L"", Menu::NORMAL); + context_menu.AppendSeparator(); + context_menu.AppendMenuItem(COPY_LINK, L"", Menu::NORMAL); + context_menu.AppendMenuItem(COPY_PATH, L"", Menu::NORMAL); + context_menu.AppendMenuItem(COPY_FILE, L"", Menu::NORMAL); + context_menu.AppendSeparator(); + context_menu.AppendMenuItem(OPEN_WHEN_COMPLETE, L"", Menu::CHECKBOX); + context_menu.AppendMenuItem(ALWAYS_OPEN_TYPE, L"", Menu::CHECKBOX); + context_menu.AppendSeparator(); + context_menu.AppendMenuItem(REMOVE_ITEM, L"", Menu::NORMAL); + context_menu.RunMenuAt(point.x, point.y); +} + +DownloadDestinationContextMenu::~DownloadDestinationContextMenu() { +} + +// Download opening ------------------------------------------------------------ + +bool CanOpenDownload(DownloadItem* download) { + const std::wstring extension = + file_util::GetFileExtensionFromPath(download->full_path()); + return !download->manager()->IsExecutable(extension); +} + +void OpenDownload(DownloadItem* download) { + if (download->state() == DownloadItem::IN_PROGRESS) + download->set_open_when_complete(!download->open_when_complete()); + else if (download->state() == DownloadItem::COMPLETE) + download->manager()->OpenDownloadInShell(download, NULL); +} + +// Download progress painting -------------------------------------------------- + +// Common bitmaps used for download progress animations. We load them once the +// first time we do a progress paint, then reuse them as they are always the +// same. +SkBitmap* g_foreground_16 = NULL; +SkBitmap* g_background_16 = NULL; +SkBitmap* g_foreground_32 = NULL; +SkBitmap* g_background_32 = NULL; + +void PaintDownloadProgress(ChromeCanvas* canvas, + ChromeViews::View* containing_view, + int origin_x, + int origin_y, + int start_angle, + int percent_done, + PaintDownloadProgressSize size) { + DCHECK(containing_view); + + // Load up our common bitmaps + if (!g_background_16) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + g_foreground_16 = rb.GetBitmapNamed(IDR_DOWNLOAD_PROGRESS_FOREGROUND_16); + g_background_16 = rb.GetBitmapNamed(IDR_DOWNLOAD_PROGRESS_BACKGROUND_16); + g_foreground_32 = rb.GetBitmapNamed(IDR_DOWNLOAD_PROGRESS_FOREGROUND_32); + g_background_32 = rb.GetBitmapNamed(IDR_DOWNLOAD_PROGRESS_BACKGROUND_32); + } + + SkBitmap* background = (size == BIG) ? g_background_32 : g_background_16; + SkBitmap* foreground = (size == BIG) ? g_foreground_32 : g_foreground_16; + + const int kProgressIconSize = GetProgressIconSize(size); + + int height = background->height(); + + // We start by storing the bounds of the background and foreground bitmaps + // so that it is easy to mirror the bounds if the UI layout is RTL. + gfx::Rect background_bounds(origin_x, origin_y, + background->width(), background->height()); + gfx::Rect foreground_bounds(origin_x, origin_y, + foreground->width(), foreground->height()); + + // Mirror the positions if necessary. + int mirrored_x = containing_view->MirroredLeftPointForRect(background_bounds); + background_bounds.set_x(mirrored_x); + mirrored_x = containing_view->MirroredLeftPointForRect(foreground_bounds); + foreground_bounds.set_x(mirrored_x); + + // Draw the background progress image. + SkPaint background_paint; + canvas->DrawBitmapInt(*background, + background_bounds.x(), + background_bounds.y(), + background_paint); + + // Layer the foreground progress image in an arc proportional to the download + // progress. The arc grows clockwise, starting in the midnight position, as + // the download progresses. However, if the download does not have known total + // size (the server didn't give us one), then we just spin an arc around until + // we're done. + float sweep_angle = 0.0; + float start_pos = static_cast<float>(kStartAngleDegrees); + if (percent_done < 0) { + sweep_angle = kUnknownAngleDegrees; + start_pos = static_cast<float>(start_angle); + } else if (percent_done > 0) { + sweep_angle = static_cast<float>(kMaxDegrees / 100.0 * percent_done); + } + + // Set up an arc clipping region for the foreground image. Don't bother using + // a clipping region if it would round to 360 (really 0) degrees, since that + // would eliminate the foreground completely and be quite confusing (it would + // look like 0% complete when it should be almost 100%). + SkPaint foreground_paint; + if (sweep_angle < static_cast<float>(kMaxDegrees - 1)) { + SkRect oval; + oval.set(SkIntToScalar(foreground_bounds.x()), + SkIntToScalar(foreground_bounds.y()), + SkIntToScalar(foreground_bounds.x() + kProgressIconSize), + SkIntToScalar(foreground_bounds.y() + kProgressIconSize)); + SkPath path; + path.arcTo(oval, + SkFloatToScalar(start_pos), + SkFloatToScalar(sweep_angle), false); + path.lineTo(SkIntToScalar(foreground_bounds.x() + kProgressIconSize / 2), + SkIntToScalar(foreground_bounds.y() + kProgressIconSize / 2)); + + SkShader* shader = + SkShader::CreateBitmapShader(*foreground, + SkShader::kClamp_TileMode, + SkShader::kClamp_TileMode); + SkMatrix shader_scale; + shader_scale.setTranslate(SkIntToScalar(foreground_bounds.x()), + SkIntToScalar(foreground_bounds.y())); + shader->setLocalMatrix(shader_scale); + foreground_paint.setShader(shader); + foreground_paint.setAntiAlias(true); + shader->unref(); + canvas->drawPath(path, foreground_paint); + return; + } + + canvas->DrawBitmapInt(*foreground, + foreground_bounds.x(), + foreground_bounds.y(), + foreground_paint); +} + +void PaintDownloadComplete(ChromeCanvas* canvas, + ChromeViews::View* containing_view, + int origin_x, + int origin_y, + double animation_progress, + PaintDownloadProgressSize size) { + DCHECK(containing_view); + + // Load up our common bitmaps. + if (!g_foreground_16) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + g_foreground_16 = rb.GetBitmapNamed(IDR_DOWNLOAD_PROGRESS_FOREGROUND_16); + g_foreground_32 = rb.GetBitmapNamed(IDR_DOWNLOAD_PROGRESS_FOREGROUND_32); + } + + SkBitmap* complete = (size == BIG) ? g_foreground_32 : g_foreground_16; + + // Mirror the positions if necessary. + gfx::Rect complete_bounds(origin_x, origin_y, + complete->width(), complete->height()); + complete_bounds.set_x( + containing_view->MirroredLeftPointForRect(complete_bounds)); + + // Start at full opacity, then loop back and forth five times before ending + // at zero opacity. + static const double PI = 3.141592653589793; + double opacity = sin(animation_progress * PI * kCompleteAnimationCycles + + PI/2) / 2 + 0.5; + + SkRect bounds; + bounds.set(SkIntToScalar(complete_bounds.x()), + SkIntToScalar(complete_bounds.y()), + SkIntToScalar(complete_bounds.x() + complete_bounds.width()), + SkIntToScalar(complete_bounds.y() + complete_bounds.height())); + canvas->saveLayerAlpha(&bounds, + static_cast<int>(255.0 * opacity), + SkCanvas::kARGB_ClipLayer_SaveFlag); + canvas->drawARGB(0, 255, 255, 255, SkPorterDuff::kClear_Mode); + canvas->DrawBitmapInt(*complete, complete_bounds.x(), complete_bounds.y()); + canvas->restore(); +} + +// XP and Vista must support icons of this size. +const int kBigIconSize = 32; +const int kSmallIconSize = 16; + +// Our progress halo around the icon +const int kBigProgressIconSize = 52; +const int kSmallProgressIconSize = 39; + +int GetIconSize(PaintDownloadProgressSize size) { + if (size == SMALL) + return kSmallIconSize; + return kBigIconSize; +} + +int GetProgressIconSize(PaintDownloadProgressSize size) { + if (size == SMALL) + return kSmallProgressIconSize; + return kBigProgressIconSize ; +} + +int GetProgressIconOffset(PaintDownloadProgressSize size) { + if (size == SMALL) + return (kSmallProgressIconSize - kSmallIconSize) / 2; + return (kBigProgressIconSize - kBigIconSize) / 2; +} + +// Download dragging +void DragDownload(const DownloadItem* download, SkBitmap* icon) { + DCHECK(download); + + // Set up our OLE machinery + scoped_refptr<OSExchangeData> data(new OSExchangeData); + if (icon) + drag_utils::CreateDragImageForFile(download->file_name(), icon, data); + data->SetFilename(download->full_path()); + scoped_refptr<BaseDragSource> drag_source(new BaseDragSource); + + // Run the drag and drop loop + DWORD effects; + DoDragDrop(data.get(), drag_source.get(), DROPEFFECT_COPY | DROPEFFECT_LINK, + &effects); +} + + +} // namespace download_util |