Home | History | Annotate | Download | only in prefs
      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 // A helper class that stays in sync with a preference (bool, int, real,
      6 // string or filepath).  For example:
      7 //
      8 // class MyClass {
      9 //  public:
     10 //   MyClass(PrefService* prefs) {
     11 //     my_string_.Init(prefs::kHomePage, prefs, NULL /* no observer */);
     12 //   }
     13 //  private:
     14 //   StringPrefMember my_string_;
     15 // };
     16 //
     17 // my_string_ should stay in sync with the prefs::kHomePage pref and will
     18 // update if either the pref changes or if my_string_.SetValue is called.
     19 //
     20 // An optional observer can be passed into the Init method which can be used to
     21 // notify MyClass of changes. Note that if you use SetValue(), the observer
     22 // will not be notified.
     23 
     24 #ifndef CHROME_BROWSER_PREFS_PREF_MEMBER_H_
     25 #define CHROME_BROWSER_PREFS_PREF_MEMBER_H_
     26 #pragma once
     27 
     28 #include <string>
     29 
     30 #include "base/basictypes.h"
     31 #include "base/file_path.h"
     32 #include "base/memory/ref_counted.h"
     33 #include "base/values.h"
     34 #include "content/browser/browser_thread.h"
     35 #include "content/common/notification_observer.h"
     36 
     37 class PrefService;
     38 
     39 namespace subtle {
     40 
     41 class PrefMemberBase : public NotificationObserver {
     42  protected:
     43   class Internal : public base::RefCountedThreadSafe<Internal> {
     44    public:
     45     Internal();
     46 
     47     // Update the value, either by calling |UpdateValueInternal| directly
     48     // or by dispatching to the right thread.
     49     // Takes ownership of |value|.
     50     virtual void UpdateValue(Value* value, bool is_managed) const;
     51 
     52     void MoveToThread(BrowserThread::ID thread_id);
     53 
     54     // See PrefMember<> for description.
     55     bool IsManaged() const {
     56       return is_managed_;
     57     }
     58 
     59    protected:
     60     friend class base::RefCountedThreadSafe<Internal>;
     61     virtual ~Internal();
     62 
     63     void CheckOnCorrectThread() const {
     64       DCHECK(IsOnCorrectThread());
     65     }
     66 
     67    private:
     68     // This method actually updates the value. It should only be called from
     69     // the thread the PrefMember is on.
     70     virtual bool UpdateValueInternal(const Value& value) const = 0;
     71 
     72     bool IsOnCorrectThread() const;
     73 
     74     BrowserThread::ID thread_id_;
     75     mutable bool is_managed_;
     76 
     77     DISALLOW_COPY_AND_ASSIGN(Internal);
     78   };
     79 
     80   PrefMemberBase();
     81   virtual ~PrefMemberBase();
     82 
     83   // See PrefMember<> for description.
     84   void Init(const char* pref_name, PrefService* prefs,
     85             NotificationObserver* observer);
     86 
     87   virtual void CreateInternal() const = 0;
     88 
     89   // See PrefMember<> for description.
     90   void Destroy();
     91 
     92   void MoveToThread(BrowserThread::ID thread_id);
     93 
     94   // NotificationObserver
     95   virtual void Observe(NotificationType type,
     96                        const NotificationSource& source,
     97                        const NotificationDetails& details);
     98 
     99   void VerifyValuePrefName() const {
    100     DCHECK(!pref_name_.empty());
    101   }
    102 
    103   // This method is used to do the actual sync with the preference.
    104   // Note: it is logically const, because it doesn't modify the state
    105   // seen by the outside world. It is just doing a lazy load behind the scenes.
    106   virtual void UpdateValueFromPref() const;
    107 
    108   // Verifies the preference name, and lazily loads the preference value if
    109   // it hasn't been loaded yet.
    110   void VerifyPref() const;
    111 
    112   const std::string& pref_name() const { return pref_name_; }
    113   PrefService* prefs() { return prefs_; }
    114   const PrefService* prefs() const { return prefs_; }
    115 
    116   virtual Internal* internal() const = 0;
    117 
    118  // Ordered the members to compact the class instance.
    119  private:
    120   std::string pref_name_;
    121   NotificationObserver* observer_;
    122   PrefService* prefs_;
    123 
    124  protected:
    125   bool setting_value_;
    126 };
    127 
    128 }  // namespace subtle
    129 
    130 template <typename ValueType>
    131 class PrefMember : public subtle::PrefMemberBase {
    132  public:
    133   // Defer initialization to an Init method so it's easy to make this class be
    134   // a member variable.
    135   PrefMember() {}
    136   virtual ~PrefMember() {}
    137 
    138   // Do the actual initialization of the class.  |observer| may be null if you
    139   // don't want any notifications of changes.
    140   // This method should only be called on the UI thread.
    141   void Init(const char* pref_name, PrefService* prefs,
    142             NotificationObserver* observer) {
    143     subtle::PrefMemberBase::Init(pref_name, prefs, observer);
    144   }
    145 
    146   // Unsubscribes the PrefMember from the PrefService. After calling this
    147   // function, the PrefMember may not be used any more.
    148   // This method should only be called on the UI thread.
    149   void Destroy() {
    150     subtle::PrefMemberBase::Destroy();
    151   }
    152 
    153   // Moves the PrefMember to another thread, allowing read accesses from there.
    154   // Changes from the PrefService will be propagated asynchronously
    155   // via PostTask.
    156   // This method should only be used from the thread the PrefMember is currently
    157   // on, which is the UI thread by default.
    158   void MoveToThread(BrowserThread::ID thread_id) {
    159     subtle::PrefMemberBase::MoveToThread(thread_id);
    160   }
    161 
    162   // Check whether the pref is managed, i.e. controlled externally through
    163   // enterprise configuration management (e.g. windows group policy). Returns
    164   // false for unknown prefs.
    165   // This method should only be used from the thread the PrefMember is currently
    166   // on, which is the UI thread unless changed by |MoveToThread|.
    167   bool IsManaged() const {
    168     VerifyPref();
    169     return internal_->IsManaged();
    170   }
    171 
    172   // Retrieve the value of the member variable.
    173   // This method should only be used from the thread the PrefMember is currently
    174   // on, which is the UI thread unless changed by |MoveToThread|.
    175   ValueType GetValue() const {
    176     VerifyPref();
    177     return internal_->value();
    178   }
    179 
    180   // Provided as a convenience.
    181   ValueType operator*() const {
    182     return GetValue();
    183   }
    184 
    185   // Set the value of the member variable.
    186   // This method should only be called on the UI thread.
    187   void SetValue(const ValueType& value) {
    188     VerifyValuePrefName();
    189     setting_value_ = true;
    190     UpdatePref(value);
    191     setting_value_ = false;
    192   }
    193 
    194   // Set the value of the member variable if it is not managed.
    195   // This method should only be called on the UI thread.
    196   void SetValueIfNotManaged(const ValueType& value) {
    197     if (!IsManaged()) {
    198       SetValue(value);
    199     }
    200   }
    201 
    202   // Returns the pref name.
    203   const std::string& GetPrefName() const {
    204     return pref_name();
    205   }
    206 
    207  private:
    208   class Internal : public subtle::PrefMemberBase::Internal {
    209    public:
    210     Internal() : value_(ValueType()) {}
    211 
    212     ValueType value() {
    213       CheckOnCorrectThread();
    214       return value_;
    215     }
    216 
    217    protected:
    218     virtual ~Internal() {}
    219 
    220     virtual bool UpdateValueInternal(const Value& value) const;
    221 
    222     // We cache the value of the pref so we don't have to keep walking the pref
    223     // tree.
    224     mutable ValueType value_;
    225 
    226     DISALLOW_COPY_AND_ASSIGN(Internal);
    227   };
    228 
    229   virtual Internal* internal() const { return internal_; }
    230   virtual void CreateInternal() const {
    231     internal_ = new Internal();
    232   }
    233 
    234   // This method is used to do the actual sync with pref of the specified type.
    235   virtual void UpdatePref(const ValueType& value);
    236 
    237   mutable scoped_refptr<Internal> internal_;
    238 
    239   DISALLOW_COPY_AND_ASSIGN(PrefMember);
    240 };
    241 
    242 typedef PrefMember<bool> BooleanPrefMember;
    243 typedef PrefMember<int> IntegerPrefMember;
    244 typedef PrefMember<double> DoublePrefMember;
    245 typedef PrefMember<std::string> StringPrefMember;
    246 typedef PrefMember<FilePath> FilePathPrefMember;
    247 typedef PrefMember<ListValue*> ListPrefMember;
    248 
    249 #endif  // CHROME_BROWSER_PREFS_PREF_MEMBER_H_
    250