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/notifications/notification_exceptions_table_model.h"
6
7#include "base/auto_reset.h"
8#include "chrome/common/content_settings.h"
9#include "chrome/common/content_settings_helper.h"
10#include "chrome/common/content_settings_types.h"
11#include "chrome/common/url_constants.h"
12#include "content/common/notification_service.h"
13#include "content/common/notification_type.h"
14#include "grit/generated_resources.h"
15#include "ui/base/l10n/l10n_util.h"
16#include "ui/base/models/table_model_observer.h"
17
18struct NotificationExceptionsTableModel::Entry {
19  Entry(const GURL& origin, ContentSetting setting);
20  bool operator<(const Entry& b) const;
21
22  GURL origin;
23  ContentSetting setting;
24};
25
26NotificationExceptionsTableModel::NotificationExceptionsTableModel(
27    DesktopNotificationService* service)
28    : service_(service),
29      updates_disabled_(false),
30      observer_(NULL) {
31  registrar_.Add(this, NotificationType::DESKTOP_NOTIFICATION_SETTINGS_CHANGED,
32                 NotificationService::AllSources());
33  LoadEntries();
34}
35
36NotificationExceptionsTableModel::~NotificationExceptionsTableModel() {}
37
38bool NotificationExceptionsTableModel::CanRemoveRows(
39    const Rows& rows) const {
40  return !rows.empty();
41}
42
43void NotificationExceptionsTableModel::RemoveRows(const Rows& rows) {
44  AutoReset<bool> tmp(&updates_disabled_, true);
45  // This is O(n^2) in rows.size(). Since n is small, that's ok.
46  for (Rows::const_reverse_iterator i(rows.rbegin()); i != rows.rend(); ++i) {
47    size_t row = *i;
48    Entry* entry = &entries_[row];
49    if (entry->setting == CONTENT_SETTING_ALLOW) {
50      service_->ResetAllowedOrigin(entry->origin);
51    } else {
52      DCHECK_EQ(entry->setting, CONTENT_SETTING_BLOCK);
53      service_->ResetBlockedOrigin(entry->origin);
54    }
55    entries_.erase(entries_.begin() + row);  // Note: |entry| is now garbage.
56    if (observer_)
57      observer_->OnItemsRemoved(row, 1);
58  }
59}
60
61void NotificationExceptionsTableModel::RemoveAll() {
62  AutoReset<bool> tmp(&updates_disabled_, true);
63  entries_.clear();
64  service_->ResetAllOrigins();
65  if (observer_)
66    observer_->OnModelChanged();
67}
68
69int NotificationExceptionsTableModel::RowCount() {
70  return static_cast<int>(entries_.size());
71}
72
73string16 NotificationExceptionsTableModel::GetText(int row,
74                                                   int column_id) {
75  const Entry& entry = entries_[row];
76  if (column_id == IDS_EXCEPTIONS_HOSTNAME_HEADER) {
77    return content_settings_helper::OriginToString16(entry.origin);
78  }
79
80  if (column_id == IDS_EXCEPTIONS_ACTION_HEADER) {
81    switch (entry.setting) {
82      case CONTENT_SETTING_ALLOW:
83        return l10n_util::GetStringUTF16(IDS_EXCEPTIONS_ALLOW_BUTTON);
84      case CONTENT_SETTING_BLOCK:
85        return l10n_util::GetStringUTF16(IDS_EXCEPTIONS_BLOCK_BUTTON);
86      default:
87        break;
88    }
89  }
90
91  NOTREACHED();
92  return string16();
93}
94
95void NotificationExceptionsTableModel::SetObserver(
96    ui::TableModelObserver* observer) {
97  observer_ = observer;
98}
99
100void NotificationExceptionsTableModel::Observe(
101    NotificationType type,
102    const NotificationSource& source,
103    const NotificationDetails& details) {
104  if (!updates_disabled_) {
105    DCHECK(type == NotificationType::DESKTOP_NOTIFICATION_SETTINGS_CHANGED);
106    entries_.clear();
107    LoadEntries();
108
109    if (observer_)
110      observer_->OnModelChanged();
111  }
112}
113
114void NotificationExceptionsTableModel::LoadEntries() {
115  std::vector<GURL> allowed(service_->GetAllowedOrigins());
116  std::vector<GURL> blocked(service_->GetBlockedOrigins());
117  entries_.reserve(allowed.size() + blocked.size());
118  for (size_t i = 0; i < allowed.size(); ++i)
119    entries_.push_back(Entry(allowed[i], CONTENT_SETTING_ALLOW));
120  for (size_t i = 0; i < blocked.size(); ++i)
121    entries_.push_back(Entry(blocked[i], CONTENT_SETTING_BLOCK));
122  std::sort(entries_.begin(), entries_.end());
123}
124
125NotificationExceptionsTableModel::Entry::Entry(
126    const GURL& in_origin,
127    ContentSetting in_setting)
128    : origin(in_origin),
129      setting(in_setting) {
130}
131
132bool NotificationExceptionsTableModel::Entry::operator<(
133    const NotificationExceptionsTableModel::Entry& b) const {
134  DCHECK_NE(origin, b.origin);
135  return origin < b.origin;
136}
137