| Index: chrome/browser/views/download_item_view.cc
|
| ===================================================================
|
| --- chrome/browser/views/download_item_view.cc (revision 26536)
|
| +++ chrome/browser/views/download_item_view.cc (working copy)
|
| @@ -72,12 +72,12 @@
|
| class DownloadShelfContextMenuWin : public DownloadShelfContextMenu,
|
| public views::Menu::Delegate {
|
| public:
|
| - DownloadShelfContextMenuWin(BaseDownloadItemModel* model,
|
| - gfx::NativeView window,
|
| - const gfx::Point& point)
|
| + DownloadShelfContextMenuWin(BaseDownloadItemModel* model)
|
| : DownloadShelfContextMenu(model) {
|
| DCHECK(model);
|
| + }
|
|
|
| + void Run(gfx::NativeView window, const gfx::Point& point) {
|
| // The menu's anchor point is determined based on the UI layout.
|
| views::Menu::AnchorPoint anchor_point;
|
| if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT)
|
| @@ -105,30 +105,48 @@
|
| context_menu->RunMenuAt(point.x(), point.y());
|
| }
|
|
|
| + // This method runs when the caller has been deleted and we should not attempt
|
| + // to access |download_|.
|
| + void Stop() {
|
| + download_ = NULL;
|
| + model_ = NULL;
|
| + }
|
| +
|
| // Menu::Delegate implementation ---------------------------------------------
|
|
|
| virtual bool IsItemChecked(int id) const {
|
| + if (!download_)
|
| + return false;
|
| return ItemIsChecked(id);
|
| }
|
|
|
| virtual bool IsItemDefault(int id) const {
|
| + if (!download_)
|
| + return false;
|
| return ItemIsDefault(id);
|
| }
|
|
|
| virtual std::wstring GetLabel(int id) const {
|
| + if (!download_)
|
| + return std::wstring();
|
| return GetItemLabel(id);
|
| }
|
|
|
| virtual bool SupportsCommand(int id) const {
|
| + if (!download_)
|
| + return false;
|
| return id > 0 && id < MENU_LAST;
|
| }
|
|
|
| virtual bool IsCommandEnabled(int id) const {
|
| + if (!download_)
|
| + return false;
|
| return IsItemCommandEnabled(id);
|
| }
|
|
|
| virtual void ExecuteCommand(int id) {
|
| - return ExecuteItemCommand(id);
|
| + if (download_)
|
| + ExecuteItemCommand(id);
|
| }
|
| };
|
|
|
| @@ -155,7 +173,8 @@
|
| dangerous_download_label_sized_(false),
|
| disabled_while_opening_(false),
|
| creation_time_(base::Time::Now()),
|
| - ALLOW_THIS_IN_INITIALIZER_LIST(reenable_method_factory_(this)) {
|
| + ALLOW_THIS_IN_INITIALIZER_LIST(reenable_method_factory_(this)),
|
| + active_menu_(NULL) {
|
| DCHECK(download_);
|
| download_->AddObserver(this);
|
|
|
| @@ -320,6 +339,10 @@
|
| }
|
|
|
| DownloadItemView::~DownloadItemView() {
|
| + if (active_menu_) {
|
| + active_menu_->Stop();
|
| + active_menu_ = NULL;
|
| + }
|
| icon_consumer_.CancelAllRequests();
|
| StopDownloadProgress();
|
| download_->RemoveObserver(this);
|
| @@ -817,12 +840,18 @@
|
| point.set_x(drop_down_x_left_);
|
|
|
| views::View::ConvertPointToScreen(this, &point);
|
| - DownloadShelfContextMenuWin menu(model_.get(),
|
| - GetWidget()->GetNativeView(),
|
| - point);
|
| + DownloadShelfContextMenuWin menu(model_.get());
|
| +
|
| + // Protect against deletion while the menu is running. This can happen if
|
| + // the menu is showing when an auto-opened download completes and the user
|
| + // chooses a menu entry.
|
| + active_menu_ = &menu;
|
| + menu.Run(GetWidget()->GetNativeView(), point);
|
| +
|
| // If the menu action was to remove the download, this view will also be
|
| // invalid so we must not access 'this' in this case.
|
| if (menu.download()) {
|
| + active_menu_ = NULL;
|
| drop_down_pressed_ = false;
|
| // Showing the menu blocks. Here we revert the state.
|
| SetState(NORMAL, NORMAL);
|
|
|