1// Copyright (c) 2012 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/extensions/theme_installed_infobar_delegate.h"
6
7#include <string>
8
9#include "base/strings/utf_string_conversions.h"
10#include "chrome/browser/chrome_notification_types.h"
11#include "chrome/browser/extensions/extension_service.h"
12#include "chrome/browser/infobars/infobar_service.h"
13#include "chrome/browser/profiles/profile.h"
14#include "chrome/browser/themes/theme_service.h"
15#include "chrome/browser/themes/theme_service_factory.h"
16#include "chrome/browser/ui/browser_finder.h"
17#include "chrome/browser/ui/tabs/tab_strip_model.h"
18#include "chrome/grit/generated_resources.h"
19#include "components/infobars/core/infobar.h"
20#include "content/public/browser/notification_source.h"
21#include "extensions/browser/extension_system.h"
22#include "extensions/common/extension.h"
23#include "grit/theme_resources.h"
24#include "ui/base/l10n/l10n_util.h"
25
26
27// static
28void ThemeInstalledInfoBarDelegate::Create(
29    const extensions::Extension* new_theme,
30    Profile* profile,
31    const std::string& previous_theme_id,
32    bool previous_using_system_theme) {
33  DCHECK(new_theme);
34  if (!new_theme->is_theme())
35    return;
36
37  // Create the new infobar.
38  // FindTabbedBrowser() is called with |match_original_profiles| true because a
39  // theme install in either a normal or incognito window for a profile affects
40  // all normal and incognito windows for that profile.
41  Browser* browser =
42      chrome::FindTabbedBrowser(profile, true, chrome::GetActiveDesktop());
43  if (!browser)
44    return;
45  content::WebContents* web_contents =
46      browser->tab_strip_model()->GetActiveWebContents();
47  if (!web_contents)
48    return;
49  InfoBarService* infobar_service =
50      InfoBarService::FromWebContents(web_contents);
51  ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile);
52  scoped_ptr<infobars::InfoBar> new_infobar(
53      ConfirmInfoBarDelegate::CreateInfoBar(scoped_ptr<ConfirmInfoBarDelegate>(
54          new ThemeInstalledInfoBarDelegate(
55              extensions::ExtensionSystem::Get(profile)->extension_service(),
56              theme_service, new_theme,
57              previous_theme_id, previous_using_system_theme))));
58
59  // If there's a previous theme infobar, just replace that instead of adding a
60  // new one.
61  for (size_t i = 0; i < infobar_service->infobar_count(); ++i) {
62    infobars::InfoBar* old_infobar = infobar_service->infobar_at(i);
63    ThemeInstalledInfoBarDelegate* theme_infobar =
64        old_infobar->delegate()->AsThemePreviewInfobarDelegate();
65    if (theme_infobar) {
66      // If the user installed the same theme twice, ignore the second install
67      // and keep the first install info bar, so that they can easily undo to
68      // get back the previous theme.
69      if (theme_infobar->theme_id_ != new_theme->id()) {
70        infobar_service->ReplaceInfoBar(old_infobar, new_infobar.Pass());
71        theme_service->OnInfobarDisplayed();
72      }
73      return;
74    }
75  }
76
77  // No previous theme infobar, so add this.
78  infobar_service->AddInfoBar(new_infobar.Pass());
79  theme_service->OnInfobarDisplayed();
80}
81
82ThemeInstalledInfoBarDelegate::ThemeInstalledInfoBarDelegate(
83    ExtensionService* extension_service,
84    ThemeService* theme_service,
85    const extensions::Extension* new_theme,
86    const std::string& previous_theme_id,
87    bool previous_using_system_theme)
88    : ConfirmInfoBarDelegate(),
89      extension_service_(extension_service),
90      theme_service_(theme_service),
91      name_(new_theme->name()),
92      theme_id_(new_theme->id()),
93      previous_theme_id_(previous_theme_id),
94      previous_using_system_theme_(previous_using_system_theme) {
95  registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
96                 content::Source<ThemeService>(theme_service_));
97}
98
99ThemeInstalledInfoBarDelegate::~ThemeInstalledInfoBarDelegate() {
100  // We don't want any notifications while we're running our destructor.
101  registrar_.RemoveAll();
102
103  theme_service_->OnInfobarDestroyed();
104}
105
106int ThemeInstalledInfoBarDelegate::GetIconID() const {
107  // TODO(aa): Reply with the theme's icon, but this requires reading it
108  // asynchronously from disk.
109  return IDR_INFOBAR_THEME;
110}
111
112infobars::InfoBarDelegate::Type ThemeInstalledInfoBarDelegate::GetInfoBarType()
113    const {
114  return PAGE_ACTION_TYPE;
115}
116
117ThemeInstalledInfoBarDelegate*
118    ThemeInstalledInfoBarDelegate::AsThemePreviewInfobarDelegate() {
119  return this;
120}
121
122base::string16 ThemeInstalledInfoBarDelegate::GetMessageText() const {
123  return l10n_util::GetStringFUTF16(IDS_THEME_INSTALL_INFOBAR_LABEL,
124                                    base::UTF8ToUTF16(name_));
125}
126
127int ThemeInstalledInfoBarDelegate::GetButtons() const {
128  return BUTTON_CANCEL;
129}
130
131base::string16 ThemeInstalledInfoBarDelegate::GetButtonLabel(
132    InfoBarButton button) const {
133  DCHECK_EQ(BUTTON_CANCEL, button);
134  return l10n_util::GetStringUTF16(IDS_THEME_INSTALL_INFOBAR_UNDO_BUTTON);
135}
136
137bool ThemeInstalledInfoBarDelegate::Cancel() {
138  if (!previous_theme_id_.empty()) {
139    const extensions::Extension* previous_theme =
140        extension_service_->GetExtensionById(previous_theme_id_, true);
141    if (previous_theme) {
142      theme_service_->SetTheme(previous_theme);
143      return false;  // The theme change will close us.
144    }
145  }
146
147  if (previous_using_system_theme_)
148    theme_service_->UseSystemTheme();
149  else
150    theme_service_->UseDefaultTheme();
151  return false;  // The theme change will close us.
152}
153
154void ThemeInstalledInfoBarDelegate::Observe(
155    int type,
156    const content::NotificationSource& source,
157    const content::NotificationDetails& details) {
158  DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type);
159  // If the new theme is different from what this info bar is associated with,
160  // close this info bar since it is no longer relevant.
161  if (theme_id_ != theme_service_->GetThemeID())
162    infobar()->RemoveSelf();
163}
164