summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/startup/session_crashed_prompt.cc
blob: fa75e048279ec3281e63a4e04cee826dff15614e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright (c) 2012 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/ui/startup/session_crashed_prompt.h"

#include "chrome/browser/api/infobars/confirm_infobar_delegate.h"
#include "chrome/browser/infobars/infobar_tab_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_restore.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/tab_contents/tab_contents.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/dom_storage_context.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"

namespace {

// A delegate for the InfoBar shown when the previous session has crashed.
class SessionCrashedInfoBarDelegate : public ConfirmInfoBarDelegate,
                                      public content::NotificationObserver {
 public:
  explicit SessionCrashedInfoBarDelegate(InfoBarTabHelper* infobar_helper);

 private:
  virtual ~SessionCrashedInfoBarDelegate();

  // ConfirmInfoBarDelegate:
  virtual gfx::Image* GetIcon() const OVERRIDE;
  virtual string16 GetMessageText() const OVERRIDE;
  virtual int GetButtons() const OVERRIDE;
  virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
  virtual bool Accept() OVERRIDE;

  // content::NotificationObserver:
  virtual void Observe(int type,
                       const content::NotificationSource& source,
                       const content::NotificationDetails& details) OVERRIDE;

  content::NotificationRegistrar registrar_;
  bool accepted_;
  bool removed_notification_received_;
  Browser* browser_;

  DISALLOW_COPY_AND_ASSIGN(SessionCrashedInfoBarDelegate);
};

SessionCrashedInfoBarDelegate::SessionCrashedInfoBarDelegate(
    InfoBarTabHelper* infobar_helper)
    : ConfirmInfoBarDelegate(infobar_helper),
      accepted_(false),
      removed_notification_received_(false),
      browser_(browser::FindBrowserWithWebContents(owner()->web_contents())) {
  // TODO(pkasting,marja): Once InfoBars own they delegates, this is not needed
  // any more. Then we can rely on delegates getting destroyed, and we can
  // initiate the session storage scavenging only in the destructor. (Currently,
  // info bars are leaked if they get closed while they're in background tabs.)
  registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
                 content::NotificationService::AllSources());
}

SessionCrashedInfoBarDelegate::~SessionCrashedInfoBarDelegate() {
  // If the info bar wasn't accepted, it was either dismissed or expired. In
  // that case, session restore won't happen.
  if (!accepted_ && !removed_notification_received_) {
    content::BrowserContext::GetDefaultStoragePartition(browser_->profile())->
        GetDOMStorageContext()->StartScavengingUnusedSessionStorage();
  }
}

gfx::Image* SessionCrashedInfoBarDelegate::GetIcon() const {
  return &ResourceBundle::GetSharedInstance().GetNativeImageNamed(
      IDR_INFOBAR_RESTORE_SESSION);
}

string16 SessionCrashedInfoBarDelegate::GetMessageText() const {
  return l10n_util::GetStringUTF16(IDS_SESSION_CRASHED_VIEW_MESSAGE);
}

int SessionCrashedInfoBarDelegate::GetButtons() const {
  return BUTTON_OK;
}

string16 SessionCrashedInfoBarDelegate::GetButtonLabel(
    InfoBarButton button) const {
  DCHECK_EQ(BUTTON_OK, button);
  return l10n_util::GetStringUTF16(IDS_SESSION_CRASHED_VIEW_RESTORE_BUTTON);
}

bool SessionCrashedInfoBarDelegate::Accept() {
  uint32 behavior = 0;
  if (browser_->tab_count() == 1 &&
      chrome::GetWebContentsAt(browser_, 0)->GetURL() ==
          GURL(chrome::kChromeUINewTabURL)) {
    // There is only one tab and its the new tab page, make session restore
    // clobber it.
    behavior = SessionRestore::CLOBBER_CURRENT_TAB;
  }
  SessionRestore::RestoreSession(
      browser_->profile(), browser_, behavior, std::vector<GURL>());
  accepted_ = true;
  return true;
}

void SessionCrashedInfoBarDelegate::Observe(
    int type,
    const content::NotificationSource& source,
    const content::NotificationDetails& details) {
  DCHECK(type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED);
  if (content::Details<std::pair<InfoBarDelegate*, bool> >(details)->first !=
      this)
    return;
  if (!accepted_) {
    content::BrowserContext::GetDefaultStoragePartition(browser_->profile())->
        GetDOMStorageContext()->StartScavengingUnusedSessionStorage();
    removed_notification_received_ = true;
  }
}

}  // namespace

namespace chrome {

void ShowSessionCrashedPrompt(Browser* browser) {
  // Assume that if the user is launching incognito they were previously
  // running incognito so that we have nothing to restore from.
  if (browser->profile()->IsOffTheRecord())
    return;

  // In ChromeBot tests, there might be a race. This line appears to get
  // called during shutdown and |tab| can be NULL.
  TabContents* tab = chrome::GetActiveTabContents(browser);
  if (!tab)
    return;

  // Don't show the info-bar if there are already info-bars showing.
  if (tab->infobar_tab_helper()->infobar_count() > 0)
    return;

  tab->infobar_tab_helper()->AddInfoBar(
      new SessionCrashedInfoBarDelegate(tab->infobar_tab_helper()));
}

}  // namespace chrome