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 "base/prefs/pref_notifier_impl.h"
6
7#include "base/logging.h"
8#include "base/prefs/pref_service.h"
9#include "base/stl_util.h"
10
11PrefNotifierImpl::PrefNotifierImpl()
12    : pref_service_(NULL) {
13}
14
15PrefNotifierImpl::PrefNotifierImpl(PrefService* service)
16    : pref_service_(service) {
17}
18
19PrefNotifierImpl::~PrefNotifierImpl() {
20  DCHECK(thread_checker_.CalledOnValidThread());
21
22  // Verify that there are no pref observers when we shut down.
23  for (PrefObserverMap::iterator it = pref_observers_.begin();
24       it != pref_observers_.end(); ++it) {
25    PrefObserverList::Iterator obs_iterator(*(it->second));
26    if (obs_iterator.GetNext()) {
27      LOG(WARNING) << "pref observer found at shutdown " << it->first;
28    }
29  }
30
31  // Same for initialization observers.
32  if (!init_observers_.empty())
33    LOG(WARNING) << "Init observer found at shutdown.";
34
35  STLDeleteContainerPairSecondPointers(pref_observers_.begin(),
36                                       pref_observers_.end());
37  pref_observers_.clear();
38  init_observers_.clear();
39}
40
41void PrefNotifierImpl::AddPrefObserver(const char* path,
42                                       PrefObserver* obs) {
43  // Get the pref observer list associated with the path.
44  PrefObserverList* observer_list = NULL;
45  const PrefObserverMap::iterator observer_iterator =
46      pref_observers_.find(path);
47  if (observer_iterator == pref_observers_.end()) {
48    observer_list = new PrefObserverList;
49    pref_observers_[path] = observer_list;
50  } else {
51    observer_list = observer_iterator->second;
52  }
53
54  // Add the pref observer. ObserverList will DCHECK if it already is
55  // in the list.
56  observer_list->AddObserver(obs);
57}
58
59void PrefNotifierImpl::RemovePrefObserver(const char* path,
60                                          PrefObserver* obs) {
61  DCHECK(thread_checker_.CalledOnValidThread());
62
63  const PrefObserverMap::iterator observer_iterator =
64      pref_observers_.find(path);
65  if (observer_iterator == pref_observers_.end()) {
66    return;
67  }
68
69  PrefObserverList* observer_list = observer_iterator->second;
70  observer_list->RemoveObserver(obs);
71}
72
73void PrefNotifierImpl::AddInitObserver(base::Callback<void(bool)> obs) {
74  init_observers_.push_back(obs);
75}
76
77void PrefNotifierImpl::OnPreferenceChanged(const std::string& path) {
78  FireObservers(path);
79}
80
81void PrefNotifierImpl::OnInitializationCompleted(bool succeeded) {
82  DCHECK(thread_checker_.CalledOnValidThread());
83
84  // We must make a copy of init_observers_ and clear it before we run
85  // observers, or we can end up in this method re-entrantly before
86  // clearing the observers list.
87  PrefInitObserverList observers(init_observers_);
88  init_observers_.clear();
89
90  for (PrefInitObserverList::iterator it = observers.begin();
91       it != observers.end();
92       ++it) {
93    it->Run(succeeded);
94  }
95}
96
97void PrefNotifierImpl::FireObservers(const std::string& path) {
98  DCHECK(thread_checker_.CalledOnValidThread());
99
100  // Only send notifications for registered preferences.
101  if (!pref_service_->FindPreference(path.c_str()))
102    return;
103
104  const PrefObserverMap::iterator observer_iterator =
105      pref_observers_.find(path);
106  if (observer_iterator == pref_observers_.end())
107    return;
108
109  FOR_EACH_OBSERVER(PrefObserver,
110                    *(observer_iterator->second),
111                    OnPreferenceChanged(pref_service_, path));
112}
113
114void PrefNotifierImpl::SetPrefService(PrefService* pref_service) {
115  DCHECK(pref_service_ == NULL);
116  pref_service_ = pref_service;
117}
118