// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/instant/instant_unload_handler.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/tab_contents/tab_contents_delegate.h"
// TabContentsDelegate implementation. This owns the TabContents supplied to the
// constructor.
class InstantUnloadHandler::TabContentsDelegateImpl
: public TabContentsDelegate {
public:
TabContentsDelegateImpl(InstantUnloadHandler* handler,
TabContentsWrapper* tab_contents,
int index)
: handler_(handler),
tab_contents_(tab_contents),
index_(index) {
tab_contents->tab_contents()->set_delegate(this);
}
~TabContentsDelegateImpl() {
}
// Releases ownership of the TabContentsWrapper to the caller.
TabContentsWrapper* ReleaseTab() {
TabContentsWrapper* tab = tab_contents_.release();
tab->tab_contents()->set_delegate(NULL);
return tab;
}
// See description above field.
int index() const { return index_; }
// TabContentsDelegate overrides:
virtual void WillRunBeforeUnloadConfirm() {
handler_->Activate(this);
}
virtual bool ShouldSuppressDialogs() {
return true; // Return true so dialogs are suppressed.
}
virtual void CloseContents(TabContents* source) {
handler_->Destroy(this);
}
// All of the following are overriden to do nothing (they are pure
// virtual). When we're attemping to close the tab, none of this matters.
virtual void OpenURLFromTab(TabContents* source,
const GURL& url, const GURL& referrer,
WindowOpenDisposition disposition,
PageTransition::Type transition) {}
virtual void NavigationStateChanged(const TabContents* source,
unsigned changed_flags) {}
virtual void AddNewContents(TabContents* source,
TabContents* new_contents,
WindowOpenDisposition disposition,
const gfx::Rect& initial_pos,
bool user_gesture) {}
virtual void ActivateContents(TabContents* contents) {}
virtual void DeactivateContents(TabContents* contents) {}
virtual void LoadingStateChanged(TabContents* source) {}
virtual void MoveContents(TabContents* source, const gfx::Rect& pos) {}
virtual void UpdateTargetURL(TabContents* source, const GURL& url) {}
private:
InstantUnloadHandler* handler_;
scoped_ptr<TabContentsWrapper> tab_contents_;
// The index |tab_contents_| was originally at. If we add the tab back we add
// it at this index.
const int index_;
DISALLOW_COPY_AND_ASSIGN(TabContentsDelegateImpl);
};
InstantUnloadHandler::InstantUnloadHandler(Browser* browser)
: browser_(browser) {
}
InstantUnloadHandler::~InstantUnloadHandler() {
}
void InstantUnloadHandler::RunUnloadListenersOrDestroy(TabContentsWrapper* tab,
int index) {
if (!tab->tab_contents()->NeedToFireBeforeUnload()) {
// Tab doesn't have any before unload listeners and can be safely deleted.
delete tab;
return;
}
// Tab has before unload listener. Install a delegate and fire the before
// unload listener.
TabContentsDelegateImpl* delegate =
new TabContentsDelegateImpl(this, tab, index);
delegates_.push_back(delegate);
// TODO: decide if we really want false here. false is used for tab closes,
// and is needed so that the tab correctly closes but it doesn't really match
// what's logically happening.
tab->tab_contents()->render_view_host()->FirePageBeforeUnload(false);
}
void InstantUnloadHandler::Activate(TabContentsDelegateImpl* delegate) {
// Take ownership of the TabContents from the delegate.
TabContentsWrapper* tab = delegate->ReleaseTab();
browser::NavigateParams params(browser_, tab);
params.disposition = NEW_FOREGROUND_TAB;
params.tabstrip_index = delegate->index();
// Remove (and delete) the delegate.
ScopedVector<TabContentsDelegateImpl>::iterator i =
std::find(delegates_.begin(), delegates_.end(), delegate);
DCHECK(i != delegates_.end());
delegates_.erase(i);
delegate = NULL;
// Add the tab back in.
browser::Navigate(¶ms);
}
void InstantUnloadHandler::Destroy(TabContentsDelegateImpl* delegate) {
ScopedVector<TabContentsDelegateImpl>::iterator i =
std::find(delegates_.begin(), delegates_.end(), delegate);
DCHECK(i != delegates_.end());
delegates_.erase(i);
}