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/plugin_exceptions_table_model.h"
6
7#include "base/auto_reset.h"
8#include "base/sys_string_conversions.h"
9#include "base/utf_string_conversions.h"
10#include "content/common/notification_service.h"
11#include "grit/generated_resources.h"
12#include "ui/base/l10n/l10n_util.h"
13#include "ui/base/models/table_model_observer.h"
14
15PluginExceptionsTableModel::PluginExceptionsTableModel(
16    HostContentSettingsMap* content_settings_map,
17    HostContentSettingsMap* otr_content_settings_map)
18    : map_(content_settings_map),
19      otr_map_(otr_content_settings_map),
20      updates_disabled_(false),
21      observer_(NULL) {
22  registrar_.Add(this, NotificationType::CONTENT_SETTINGS_CHANGED,
23                 NotificationService::AllSources());
24}
25
26PluginExceptionsTableModel::~PluginExceptionsTableModel() {
27}
28
29bool PluginExceptionsTableModel::CanRemoveRows(const Rows& rows) const {
30  return !rows.empty();
31}
32
33void PluginExceptionsTableModel::RemoveRows(const Rows& rows) {
34  AutoReset<bool> tmp(&updates_disabled_, true);
35  bool reload_all = false;
36  // Iterate over the rows starting with the highest ones so we can delete
37  // entries from |settings_| without the other indices shifting.
38  for (Rows::const_reverse_iterator it = rows.rbegin();
39       it != rows.rend(); ++it) {
40    DCHECK_LT(*it, settings_.size());
41    SettingsEntry entry = settings_[*it];
42    HostContentSettingsMap* map = entry.is_otr ? otr_map_ : map_;
43    map->SetContentSetting(entry.pattern,
44                           CONTENT_SETTINGS_TYPE_PLUGINS,
45                           resources_[entry.plugin_id],
46                           CONTENT_SETTING_DEFAULT);
47    settings_.erase(settings_.begin() + *it);
48    row_counts_[entry.plugin_id]--;
49    if (!reload_all) {
50      // If we remove the last exception for a plugin, recreate all groups
51      // to get correct IDs.
52      if (row_counts_[entry.plugin_id] == 0)  {
53        reload_all = true;
54      } else {
55        if (observer_)
56          observer_->OnItemsRemoved(*it, 1);
57      }
58    }
59  }
60  if (reload_all) {
61    // This also notifies the observer.
62    ReloadSettings();
63  }
64}
65
66void PluginExceptionsTableModel::RemoveAll() {
67  AutoReset<bool> tmp(&updates_disabled_, true);
68  map_->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS);
69  if (otr_map_)
70    otr_map_->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS);
71
72  ClearSettings();
73  if (observer_)
74    observer_->OnModelChanged();
75}
76
77int PluginExceptionsTableModel::RowCount() {
78  return settings_.size();
79}
80
81string16 PluginExceptionsTableModel::GetText(int row, int column_id) {
82  DCHECK_GE(row, 0);
83  DCHECK_LT(row, static_cast<int>(settings_.size()));
84  SettingsEntry& entry = settings_[row];
85  if (column_id == IDS_EXCEPTIONS_PATTERN_HEADER ||
86      column_id == IDS_EXCEPTIONS_HOSTNAME_HEADER) {
87    return UTF8ToUTF16(entry.pattern.AsString());
88  } else if (column_id == IDS_EXCEPTIONS_ACTION_HEADER) {
89    switch (entry.setting) {
90      case CONTENT_SETTING_ALLOW:
91        return l10n_util::GetStringUTF16(IDS_EXCEPTIONS_ALLOW_BUTTON);
92      case CONTENT_SETTING_BLOCK:
93        return l10n_util::GetStringUTF16(IDS_EXCEPTIONS_BLOCK_BUTTON);
94      default:
95        NOTREACHED();
96    }
97  } else {
98    NOTREACHED();
99  }
100  return string16();
101}
102
103bool PluginExceptionsTableModel::HasGroups() {
104  return true;
105}
106
107void PluginExceptionsTableModel::SetObserver(ui::TableModelObserver* observer) {
108  observer_ = observer;
109}
110
111ui::TableModel::Groups PluginExceptionsTableModel::GetGroups() {
112  return groups_;
113}
114
115int PluginExceptionsTableModel::GetGroupID(int row) {
116  DCHECK_LT(row, static_cast<int>(settings_.size()));
117  return settings_[row].plugin_id;
118}
119
120void PluginExceptionsTableModel::Observe(NotificationType type,
121                                         const NotificationSource& source,
122                                         const NotificationDetails& details) {
123  if (!updates_disabled_)
124    ReloadSettings();
125}
126
127void PluginExceptionsTableModel::ClearSettings() {
128  settings_.clear();
129  groups_.clear();
130  row_counts_.clear();
131  resources_.clear();
132}
133
134void PluginExceptionsTableModel::GetPlugins(
135    std::vector<webkit::npapi::PluginGroup>* plugin_groups) {
136  webkit::npapi::PluginList::Singleton()->GetPluginGroups(false, plugin_groups);
137}
138
139void PluginExceptionsTableModel::LoadSettings() {
140  int group_id = 0;
141  std::vector<webkit::npapi::PluginGroup> plugins;
142  GetPlugins(&plugins);
143  for (size_t i = 0; i < plugins.size(); ++i) {
144    std::string plugin = plugins[i].identifier();
145    HostContentSettingsMap::SettingsForOneType settings;
146    map_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
147                                plugin,
148                                &settings);
149    HostContentSettingsMap::SettingsForOneType otr_settings;
150    if (otr_map_) {
151      otr_map_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
152                                      plugin,
153                                      &otr_settings);
154    }
155    string16 title = plugins[i].GetGroupName();
156    for (HostContentSettingsMap::SettingsForOneType::iterator setting_it =
157             settings.begin();
158         setting_it != settings.end(); ++setting_it) {
159      SettingsEntry entry = {
160        setting_it->first,
161        group_id,
162        setting_it->second,
163        false
164      };
165      settings_.push_back(entry);
166    }
167    for (HostContentSettingsMap::SettingsForOneType::iterator setting_it =
168             otr_settings.begin();
169         setting_it != otr_settings.end(); ++setting_it) {
170      SettingsEntry entry = {
171        setting_it->first,
172        group_id,
173        setting_it->second,
174        true
175      };
176      settings_.push_back(entry);
177    }
178    int num_plugins = settings.size() + otr_settings.size();
179    if (num_plugins > 0) {
180      Group group = { title, group_id++ };
181      groups_.push_back(group);
182      resources_.push_back(plugin);
183      row_counts_.push_back(num_plugins);
184    }
185  }
186}
187
188void PluginExceptionsTableModel::ReloadSettings() {
189  ClearSettings();
190  LoadSettings();
191
192  if (observer_)
193    observer_->OnModelChanged();
194}
195