summaryrefslogtreecommitdiffstats
path: root/base/prefs
diff options
context:
space:
mode:
authorderat@chromium.org <derat@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-30 20:21:17 +0000
committerderat@chromium.org <derat@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-30 20:21:17 +0000
commit9eec53fe1841f7ae4d5684074fc3118ef66bb943 (patch)
treebb2fe9582ddb8569bcb0b390cc2c45d4e61e30ca /base/prefs
parentd39bf7539abbc238e8e5a73937b9531feeabb530 (diff)
downloadchromium_src-9eec53fe1841f7ae4d5684074fc3118ef66bb943.zip
chromium_src-9eec53fe1841f7ae4d5684074fc3118ef66bb943.tar.gz
chromium_src-9eec53fe1841f7ae4d5684074fc3118ef66bb943.tar.bz2
Move ScopedUserPrefUpdate to base/prefs.
Move this outside of Chrome to enable moving ExtensionPrefs to the top-level extensions/ directory. BUG=313284 TBR=sky@chromium.org Review URL: https://codereview.chromium.org/46073004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@231905 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/prefs')
-rw-r--r--base/prefs/scoped_user_pref_update.cc36
-rw-r--r--base/prefs/scoped_user_pref_update.h108
-rw-r--r--base/prefs/scoped_user_pref_update_unittest.cc81
3 files changed, 225 insertions, 0 deletions
diff --git a/base/prefs/scoped_user_pref_update.cc b/base/prefs/scoped_user_pref_update.cc
new file mode 100644
index 0000000..c86b163
--- /dev/null
+++ b/base/prefs/scoped_user_pref_update.cc
@@ -0,0 +1,36 @@
+// Copyright 2013 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 "base/prefs/scoped_user_pref_update.h"
+
+#include "base/logging.h"
+#include "base/prefs/pref_notifier.h"
+#include "base/prefs/pref_service.h"
+
+namespace subtle {
+
+ScopedUserPrefUpdateBase::ScopedUserPrefUpdateBase(PrefService* service,
+ const char* path)
+ : service_(service),
+ path_(path),
+ value_(NULL) {}
+
+ScopedUserPrefUpdateBase::~ScopedUserPrefUpdateBase() {
+ Notify();
+}
+
+Value* ScopedUserPrefUpdateBase::GetValueOfType(base::Value::Type type) {
+ if (!value_)
+ value_ = service_->GetMutableUserPref(path_.c_str(), type);
+ return value_;
+}
+
+void ScopedUserPrefUpdateBase::Notify() {
+ if (value_) {
+ service_->ReportUserPrefChanged(path_);
+ value_ = NULL;
+ }
+}
+
+} // namespace subtle
diff --git a/base/prefs/scoped_user_pref_update.h b/base/prefs/scoped_user_pref_update.h
new file mode 100644
index 0000000..82d6739
--- /dev/null
+++ b/base/prefs/scoped_user_pref_update.h
@@ -0,0 +1,108 @@
+// Copyright 2013 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.
+//
+// A helper class that assists preferences in firing notifications when lists
+// or dictionaries are changed.
+
+#ifndef BASE_PREFS_SCOPED_USER_PREF_UPDATE_H_
+#define BASE_PREFS_SCOPED_USER_PREF_UPDATE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_service.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/values.h"
+
+class PrefService;
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+}
+
+namespace subtle {
+
+// Base class for ScopedUserPrefUpdateTemplate that contains the parts
+// that do not depend on ScopedUserPrefUpdateTemplate's template parameter.
+//
+// We need this base class mostly for making it a friend of PrefService
+// and getting access to PrefService::GetMutableUserPref and
+// PrefService::ReportUserPrefChanged.
+class BASE_PREFS_EXPORT ScopedUserPrefUpdateBase : public base::NonThreadSafe {
+ protected:
+ ScopedUserPrefUpdateBase(PrefService* service, const char* path);
+
+ // Calls Notify().
+ ~ScopedUserPrefUpdateBase();
+
+ // Sets |value_| to |service_|->GetMutableUserPref and returns it.
+ base::Value* GetValueOfType(base::Value::Type type);
+
+ private:
+ // If |value_| is not null, triggers a notification of PrefObservers and
+ // resets |value_|.
+ void Notify();
+
+ // Weak pointer.
+ PrefService* service_;
+ // Path of the preference being updated.
+ std::string path_;
+ // Cache of value from user pref store (set between Get() and Notify() calls).
+ base::Value* value_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedUserPrefUpdateBase);
+};
+
+} // namespace subtle
+
+// Class to support modifications to DictionaryValues and ListValues while
+// guaranteeing that PrefObservers are notified of changed values.
+//
+// This class may only be used on the UI thread as it requires access to the
+// PrefService.
+template <typename T, base::Value::Type type_enum_value>
+class ScopedUserPrefUpdate : public subtle::ScopedUserPrefUpdateBase {
+ public:
+ ScopedUserPrefUpdate(PrefService* service, const char* path)
+ : ScopedUserPrefUpdateBase(service, path) {}
+
+ // Triggers an update notification if Get() was called.
+ virtual ~ScopedUserPrefUpdate() {}
+
+ // Returns a mutable |T| instance that
+ // - is already in the user pref store, or
+ // - is (silently) created and written to the user pref store if none existed
+ // before.
+ //
+ // Calling Get() implies that an update notification is necessary at
+ // destruction time.
+ //
+ // The ownership of the return value remains with the user pref store.
+ // Virtual so it can be overriden in subclasses that transform the value
+ // before returning it (for example to return a subelement of a dictionary).
+ virtual T* Get() {
+ return static_cast<T*>(GetValueOfType(type_enum_value));
+ }
+
+ T& operator*() {
+ return *Get();
+ }
+
+ T* operator->() {
+ return Get();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedUserPrefUpdate);
+};
+
+typedef ScopedUserPrefUpdate<base::DictionaryValue,
+ base::Value::TYPE_DICTIONARY>
+ DictionaryPrefUpdate;
+typedef ScopedUserPrefUpdate<base::ListValue, base::Value::TYPE_LIST>
+ ListPrefUpdate;
+
+#endif // BASE_PREFS_SCOPED_USER_PREF_UPDATE_H_
diff --git a/base/prefs/scoped_user_pref_update_unittest.cc b/base/prefs/scoped_user_pref_update_unittest.cc
new file mode 100644
index 0000000..505526c
--- /dev/null
+++ b/base/prefs/scoped_user_pref_update_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright 2013 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 "base/prefs/mock_pref_change_callback.h"
+#include "base/prefs/pref_change_registrar.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/scoped_user_pref_update.h"
+#include "base/prefs/testing_pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Mock;
+
+class ScopedUserPrefUpdateTest : public testing::Test {
+ public:
+ ScopedUserPrefUpdateTest() : observer_(&prefs_) {}
+ virtual ~ScopedUserPrefUpdateTest() {}
+
+ protected:
+ virtual void SetUp() {
+ prefs_.registry()->RegisterDictionaryPref(kPref);
+ registrar_.Init(&prefs_);
+ registrar_.Add(kPref, observer_.GetCallback());
+ }
+
+ static const char kPref[];
+ static const char kKey[];
+ static const char kValue[];
+
+ TestingPrefServiceSimple prefs_;
+ MockPrefChangeCallback observer_;
+ PrefChangeRegistrar registrar_;
+};
+
+const char ScopedUserPrefUpdateTest::kPref[] = "name";
+const char ScopedUserPrefUpdateTest::kKey[] = "key";
+const char ScopedUserPrefUpdateTest::kValue[] = "value";
+
+TEST_F(ScopedUserPrefUpdateTest, RegularUse) {
+ // Dictionary that will be expected to be set at the end.
+ DictionaryValue expected_dictionary;
+ expected_dictionary.SetString(kKey, kValue);
+
+ {
+ EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
+ DictionaryPrefUpdate update(&prefs_, kPref);
+ DictionaryValue* value = update.Get();
+ ASSERT_TRUE(value);
+ value->SetString(kKey, kValue);
+
+ // The dictionary was created for us but the creation should have happened
+ // silently without notifications.
+ Mock::VerifyAndClearExpectations(&observer_);
+
+ // Modifications happen online and are instantly visible, though.
+ const DictionaryValue* current_value = prefs_.GetDictionary(kPref);
+ ASSERT_TRUE(current_value);
+ EXPECT_TRUE(expected_dictionary.Equals(current_value));
+
+ // Now we are leaving the scope of the update so we should be notified.
+ observer_.Expect(kPref, &expected_dictionary);
+ }
+ Mock::VerifyAndClearExpectations(&observer_);
+
+ const DictionaryValue* current_value = prefs_.GetDictionary(kPref);
+ ASSERT_TRUE(current_value);
+ EXPECT_TRUE(expected_dictionary.Equals(current_value));
+}
+
+TEST_F(ScopedUserPrefUpdateTest, NeverTouchAnything) {
+ const DictionaryValue* old_value = prefs_.GetDictionary(kPref);
+ EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
+ {
+ DictionaryPrefUpdate update(&prefs_, kPref);
+ }
+ const DictionaryValue* new_value = prefs_.GetDictionary(kPref);
+ EXPECT_EQ(old_value, new_value);
+ Mock::VerifyAndClearExpectations(&observer_);
+}