summaryrefslogtreecommitdiffstats
path: root/chrome/browser/download_util.cc
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
commit09911bf300f1a419907a9412154760efd0b7abc3 (patch)
treef131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/download_util.cc
parent586acc5fe142f498261f52c66862fa417c3d52d2 (diff)
downloadchromium_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.cc456
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