1// Copyright (c) 2011 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/instant/instant_unload_handler.h"
6
7#include "chrome/browser/ui/browser.h"
8#include "chrome/browser/ui/browser_navigator.h"
9#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
10#include "content/browser/renderer_host/render_view_host.h"
11#include "content/browser/tab_contents/tab_contents.h"
12#include "content/browser/tab_contents/tab_contents_delegate.h"
13
14// TabContentsDelegate implementation. This owns the TabContents supplied to the
15// constructor.
16class InstantUnloadHandler::TabContentsDelegateImpl
17    : public TabContentsDelegate {
18 public:
19  TabContentsDelegateImpl(InstantUnloadHandler* handler,
20                          TabContentsWrapper* tab_contents,
21                          int index)
22      : handler_(handler),
23        tab_contents_(tab_contents),
24        index_(index) {
25    tab_contents->tab_contents()->set_delegate(this);
26  }
27
28  ~TabContentsDelegateImpl() {
29  }
30
31  // Releases ownership of the TabContentsWrapper to the caller.
32  TabContentsWrapper* ReleaseTab() {
33    TabContentsWrapper* tab = tab_contents_.release();
34    tab->tab_contents()->set_delegate(NULL);
35    return tab;
36  }
37
38  // See description above field.
39  int index() const { return index_; }
40
41  // TabContentsDelegate overrides:
42  virtual void WillRunBeforeUnloadConfirm() {
43    handler_->Activate(this);
44  }
45
46  virtual bool ShouldSuppressDialogs() {
47    return true;  // Return true so dialogs are suppressed.
48  }
49
50  virtual void CloseContents(TabContents* source) {
51    handler_->Destroy(this);
52  }
53
54  // All of the following are overriden to do nothing (they are pure
55  // virtual). When we're attemping to close the tab, none of this matters.
56  virtual void OpenURLFromTab(TabContents* source,
57                              const GURL& url, const GURL& referrer,
58                              WindowOpenDisposition disposition,
59                              PageTransition::Type transition) {}
60  virtual void NavigationStateChanged(const TabContents* source,
61                                      unsigned changed_flags) {}
62  virtual void AddNewContents(TabContents* source,
63                              TabContents* new_contents,
64                              WindowOpenDisposition disposition,
65                              const gfx::Rect& initial_pos,
66                              bool user_gesture) {}
67  virtual void ActivateContents(TabContents* contents) {}
68  virtual void DeactivateContents(TabContents* contents) {}
69  virtual void LoadingStateChanged(TabContents* source) {}
70  virtual void MoveContents(TabContents* source, const gfx::Rect& pos) {}
71  virtual void UpdateTargetURL(TabContents* source, const GURL& url) {}
72
73 private:
74  InstantUnloadHandler* handler_;
75  scoped_ptr<TabContentsWrapper> tab_contents_;
76
77  // The index |tab_contents_| was originally at. If we add the tab back we add
78  // it at this index.
79  const int index_;
80
81  DISALLOW_COPY_AND_ASSIGN(TabContentsDelegateImpl);
82};
83
84InstantUnloadHandler::InstantUnloadHandler(Browser* browser)
85    : browser_(browser) {
86}
87
88InstantUnloadHandler::~InstantUnloadHandler() {
89}
90
91void InstantUnloadHandler::RunUnloadListenersOrDestroy(TabContentsWrapper* tab,
92                                                       int index) {
93  if (!tab->tab_contents()->NeedToFireBeforeUnload()) {
94    // Tab doesn't have any before unload listeners and can be safely deleted.
95    delete tab;
96    return;
97  }
98
99  // Tab has before unload listener. Install a delegate and fire the before
100  // unload listener.
101  TabContentsDelegateImpl* delegate =
102      new TabContentsDelegateImpl(this, tab, index);
103  delegates_.push_back(delegate);
104  // TODO: decide if we really want false here. false is used for tab closes,
105  // and is needed so that the tab correctly closes but it doesn't really match
106  // what's logically happening.
107  tab->tab_contents()->render_view_host()->FirePageBeforeUnload(false);
108}
109
110void InstantUnloadHandler::Activate(TabContentsDelegateImpl* delegate) {
111  // Take ownership of the TabContents from the delegate.
112  TabContentsWrapper* tab = delegate->ReleaseTab();
113  browser::NavigateParams params(browser_, tab);
114  params.disposition = NEW_FOREGROUND_TAB;
115  params.tabstrip_index = delegate->index();
116
117  // Remove (and delete) the delegate.
118  ScopedVector<TabContentsDelegateImpl>::iterator i =
119      std::find(delegates_.begin(), delegates_.end(), delegate);
120  DCHECK(i != delegates_.end());
121  delegates_.erase(i);
122  delegate = NULL;
123
124  // Add the tab back in.
125  browser::Navigate(&params);
126}
127
128void InstantUnloadHandler::Destroy(TabContentsDelegateImpl* delegate) {
129  ScopedVector<TabContentsDelegateImpl>::iterator i =
130      std::find(delegates_.begin(), delegates_.end(), delegate);
131  DCHECK(i != delegates_.end());
132  delegates_.erase(i);
133}
134