Home | History | Annotate | Download | only in glue
      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/sync/glue/theme_util.h"
      6 
      7 #include <string>
      8 
      9 #include "base/logging.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "chrome/browser/extensions/extension_install_ui.h"
     12 #include "chrome/browser/extensions/extension_service.h"
     13 #include "chrome/browser/extensions/extension_updater.h"
     14 #if defined(TOOLKIT_USES_GTK)
     15 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
     16 #endif
     17 #include "chrome/browser/profiles/profile.h"
     18 #include "chrome/browser/sync/protocol/theme_specifics.pb.h"
     19 #include "chrome/browser/themes/theme_service.h"
     20 #include "chrome/browser/themes/theme_service_factory.h"
     21 #include "chrome/common/extensions/extension.h"
     22 #include "chrome/common/extensions/extension_constants.h"
     23 #include "googleurl/src/gurl.h"
     24 
     25 namespace browser_sync {
     26 
     27 const char kCurrentThemeClientTag[] = "current_theme";
     28 
     29 namespace {
     30 
     31 bool IsSystemThemeDistinctFromDefaultTheme() {
     32 #if defined(TOOLKIT_USES_GTK)
     33   return true;
     34 #else
     35   return false;
     36 #endif
     37 }
     38 
     39 bool UseSystemTheme(Profile* profile) {
     40 #if defined(TOOLKIT_USES_GTK)
     41   return GtkThemeService::GetFrom(profile)->UseGtkTheme();
     42 #else
     43   return false;
     44 #endif
     45 }
     46 
     47 }  // namespace
     48 
     49 bool AreThemeSpecificsEqual(const sync_pb::ThemeSpecifics& a,
     50                             const sync_pb::ThemeSpecifics& b) {
     51   return AreThemeSpecificsEqualHelper(
     52       a, b, IsSystemThemeDistinctFromDefaultTheme());
     53 }
     54 
     55 bool AreThemeSpecificsEqualHelper(
     56     const sync_pb::ThemeSpecifics& a,
     57     const sync_pb::ThemeSpecifics& b,
     58     bool is_system_theme_distinct_from_default_theme) {
     59   if (a.use_custom_theme() != b.use_custom_theme()) {
     60     return false;
     61   }
     62 
     63   if (a.use_custom_theme()) {
     64     // We're using a custom theme, so simply compare IDs since those
     65     // are guaranteed unique.
     66     return a.custom_theme_id() == b.custom_theme_id();
     67   } else if (is_system_theme_distinct_from_default_theme) {
     68     // We're not using a custom theme, but we care about system
     69     // vs. default.
     70     return a.use_system_theme_by_default() == b.use_system_theme_by_default();
     71   } else {
     72     // We're not using a custom theme, and we don't care about system
     73     // vs. default.
     74     return true;
     75   }
     76 }
     77 
     78 namespace {
     79 
     80 bool IsTheme(const Extension& extension) {
     81   return extension.is_theme();
     82 }
     83 
     84 }  // namespace
     85 
     86 void SetCurrentThemeFromThemeSpecifics(
     87     const sync_pb::ThemeSpecifics& theme_specifics,
     88     Profile* profile) {
     89   DCHECK(profile);
     90   if (theme_specifics.use_custom_theme()) {
     91     // TODO(akalin): Figure out what to do about third-party themes
     92     // (i.e., those not on either Google gallery).
     93     std::string id(theme_specifics.custom_theme_id());
     94     GURL update_url(theme_specifics.custom_theme_update_url());
     95     VLOG(1) << "Applying theme " << id << " with update_url " << update_url;
     96     ExtensionServiceInterface* extensions_service =
     97         profile->GetExtensionService();
     98     CHECK(extensions_service);
     99     const Extension* extension = extensions_service->GetExtensionById(id, true);
    100     if (extension) {
    101       if (!extension->is_theme()) {
    102         VLOG(1) << "Extension " << id << " is not a theme; aborting";
    103         return;
    104       }
    105       if (!extensions_service->IsExtensionEnabled(id)) {
    106         VLOG(1) << "Theme " << id << " is not enabled; aborting";
    107         return;
    108       }
    109       // Get previous theme info before we set the new theme.
    110       std::string previous_theme_id;
    111       {
    112         const Extension* current_theme =
    113             ThemeServiceFactory::GetThemeForProfile(profile);
    114         if (current_theme) {
    115           DCHECK(current_theme->is_theme());
    116           previous_theme_id = current_theme->id();
    117         }
    118       }
    119       bool previous_use_system_theme = UseSystemTheme(profile);
    120       // An enabled theme extension with the given id was found, so
    121       // just set the current theme to it.
    122       ThemeServiceFactory::GetForProfile(profile)->SetTheme(extension);
    123       // Pretend the theme was just installed.
    124       ExtensionInstallUI::ShowThemeInfoBar(
    125           previous_theme_id, previous_use_system_theme,
    126           extension, profile);
    127     } else {
    128       // No extension with this id exists -- we must install it; we do
    129       // so by adding it as a pending extension and then triggering an
    130       // auto-update cycle.
    131       // Themes don't need to install silently as they just pop up an
    132       // informational dialog after installation instead of a
    133       // confirmation dialog.
    134       const bool kInstallSilently = false;
    135       const bool kEnableOnInstall = true;
    136       const bool kEnableIncognitoOnInstall = false;
    137       extensions_service->pending_extension_manager()->AddFromSync(
    138           id, update_url, &IsTheme,
    139           kInstallSilently, kEnableOnInstall, kEnableIncognitoOnInstall);
    140       extensions_service->CheckForUpdatesSoon();
    141     }
    142   } else if (theme_specifics.use_system_theme_by_default()) {
    143     ThemeServiceFactory::GetForProfile(profile)->SetNativeTheme();
    144   } else {
    145     ThemeServiceFactory::GetForProfile(profile)->UseDefaultTheme();
    146   }
    147 }
    148 
    149 bool UpdateThemeSpecificsOrSetCurrentThemeIfNecessary(
    150     Profile* profile, sync_pb::ThemeSpecifics* theme_specifics) {
    151   if (!theme_specifics->use_custom_theme() &&
    152       (ThemeServiceFactory::GetThemeForProfile(profile) ||
    153        (UseSystemTheme(profile) &&
    154         IsSystemThemeDistinctFromDefaultTheme()))) {
    155     GetThemeSpecificsFromCurrentTheme(profile, theme_specifics);
    156     return true;
    157   } else {
    158     SetCurrentThemeFromThemeSpecificsIfNecessary(*theme_specifics, profile);
    159     return false;
    160   }
    161 }
    162 
    163 void GetThemeSpecificsFromCurrentTheme(
    164     Profile* profile,
    165     sync_pb::ThemeSpecifics* theme_specifics) {
    166   DCHECK(profile);
    167   const Extension* current_theme =
    168       ThemeServiceFactory::GetThemeForProfile(profile);
    169   if (current_theme) {
    170     DCHECK(current_theme->is_theme());
    171   }
    172   GetThemeSpecificsFromCurrentThemeHelper(
    173       current_theme,
    174       IsSystemThemeDistinctFromDefaultTheme(),
    175       UseSystemTheme(profile),
    176       theme_specifics);
    177 }
    178 
    179 void GetThemeSpecificsFromCurrentThemeHelper(
    180     const Extension* current_theme,
    181     bool is_system_theme_distinct_from_default_theme,
    182     bool use_system_theme_by_default,
    183     sync_pb::ThemeSpecifics* theme_specifics) {
    184   bool use_custom_theme = (current_theme != NULL);
    185   theme_specifics->set_use_custom_theme(use_custom_theme);
    186   if (is_system_theme_distinct_from_default_theme) {
    187     theme_specifics->set_use_system_theme_by_default(
    188         use_system_theme_by_default);
    189   } else {
    190     DCHECK(!use_system_theme_by_default);
    191   }
    192   if (use_custom_theme) {
    193     DCHECK(current_theme);
    194     DCHECK(current_theme->is_theme());
    195     theme_specifics->set_custom_theme_name(current_theme->name());
    196     theme_specifics->set_custom_theme_id(current_theme->id());
    197     theme_specifics->set_custom_theme_update_url(
    198         current_theme->update_url().spec());
    199   } else {
    200     DCHECK(!current_theme);
    201     theme_specifics->clear_custom_theme_name();
    202     theme_specifics->clear_custom_theme_id();
    203     theme_specifics->clear_custom_theme_update_url();
    204   }
    205 }
    206 
    207 void SetCurrentThemeFromThemeSpecificsIfNecessary(
    208     const sync_pb::ThemeSpecifics& theme_specifics, Profile* profile) {
    209   DCHECK(profile);
    210   sync_pb::ThemeSpecifics old_theme_specifics;
    211   GetThemeSpecificsFromCurrentTheme(profile, &old_theme_specifics);
    212   if (!AreThemeSpecificsEqual(old_theme_specifics, theme_specifics)) {
    213     SetCurrentThemeFromThemeSpecifics(theme_specifics, profile);
    214   }
    215 }
    216 
    217 }  // namespace browser_sync
    218