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/prefs/pref_notifier_impl.h"
6
7#include "base/stl_util-inl.h"
8#include "chrome/browser/prefs/pref_service.h"
9#include "content/common/notification_observer.h"
10#include "content/common/notification_service.h"
11
12PrefNotifierImpl::PrefNotifierImpl(PrefService* service)
13    : pref_service_(service) {
14}
15
16PrefNotifierImpl::~PrefNotifierImpl() {
17  DCHECK(CalledOnValidThread());
18
19  // Verify that there are no pref observers when we shut down.
20  for (PrefObserverMap::iterator it = pref_observers_.begin();
21       it != pref_observers_.end(); ++it) {
22    NotificationObserverList::Iterator obs_iterator(*(it->second));
23    if (obs_iterator.GetNext()) {
24      LOG(WARNING) << "pref observer found at shutdown " << it->first;
25    }
26  }
27
28  STLDeleteContainerPairSecondPointers(pref_observers_.begin(),
29                                       pref_observers_.end());
30  pref_observers_.clear();
31}
32
33void PrefNotifierImpl::AddPrefObserver(const char* path,
34                                       NotificationObserver* obs) {
35  // Get the pref observer list associated with the path.
36  NotificationObserverList* observer_list = NULL;
37  const PrefObserverMap::iterator observer_iterator =
38      pref_observers_.find(path);
39  if (observer_iterator == pref_observers_.end()) {
40    observer_list = new NotificationObserverList;
41    pref_observers_[path] = observer_list;
42  } else {
43    observer_list = observer_iterator->second;
44  }
45
46  // Verify that this observer doesn't already exist.
47  NotificationObserverList::Iterator it(*observer_list);
48  NotificationObserver* existing_obs;
49  while ((existing_obs = it.GetNext()) != NULL) {
50    DCHECK(existing_obs != obs) << path << " observer already registered";
51    if (existing_obs == obs)
52      return;
53  }
54
55  // Ok, safe to add the pref observer.
56  observer_list->AddObserver(obs);
57}
58
59void PrefNotifierImpl::RemovePrefObserver(const char* path,
60                                          NotificationObserver* obs) {
61  DCHECK(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  NotificationObserverList* observer_list = observer_iterator->second;
70  observer_list->RemoveObserver(obs);
71}
72
73void PrefNotifierImpl::OnPreferenceChanged(const std::string& path) {
74  FireObservers(path);
75}
76
77void PrefNotifierImpl::OnInitializationCompleted() {
78  DCHECK(CalledOnValidThread());
79
80  NotificationService::current()->Notify(
81      NotificationType::PREF_INITIALIZATION_COMPLETED,
82      Source<PrefService>(pref_service_),
83      NotificationService::NoDetails());
84}
85
86void PrefNotifierImpl::FireObservers(const std::string& path) {
87  DCHECK(CalledOnValidThread());
88
89  // Only send notifications for registered preferences.
90  if (!pref_service_->FindPreference(path.c_str()))
91    return;
92
93  const PrefObserverMap::iterator observer_iterator =
94      pref_observers_.find(path);
95  if (observer_iterator == pref_observers_.end())
96    return;
97
98  NotificationObserverList::Iterator it(*(observer_iterator->second));
99  NotificationObserver* observer;
100  while ((observer = it.GetNext()) != NULL) {
101    observer->Observe(NotificationType::PREF_CHANGED,
102                      Source<PrefService>(pref_service_),
103                      Details<const std::string>(&path));
104  }
105}
106