summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/search_engines/template_url_table_model.cc
diff options
context:
space:
mode:
authoravi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-23 19:45:42 +0000
committeravi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-23 19:45:42 +0000
commit62f7777cb7c9dba41286c17bab10e30152a5a841 (patch)
tree9eebf968b2c840b1536d4321ed0f086d96135eaf /chrome/browser/ui/search_engines/template_url_table_model.cc
parent4d8af92fa3a43f203679bbbd37968c127d056a4d (diff)
downloadchromium_src-62f7777cb7c9dba41286c17bab10e30152a5a841.zip
chromium_src-62f7777cb7c9dba41286c17bab10e30152a5a841.tar.gz
chromium_src-62f7777cb7c9dba41286c17bab10e30152a5a841.tar.bz2
Move the UI portions of search engine management to ui/search_engines.
BUG=none TEST=no visible change Review URL: http://codereview.chromium.org/6573008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75774 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/ui/search_engines/template_url_table_model.cc')
-rw-r--r--chrome/browser/ui/search_engines/template_url_table_model.cc381
1 files changed, 381 insertions, 0 deletions
diff --git a/chrome/browser/ui/search_engines/template_url_table_model.cc b/chrome/browser/ui/search_engines/template_url_table_model.cc
new file mode 100644
index 0000000..6c82c85
--- /dev/null
+++ b/chrome/browser/ui/search_engines/template_url_table_model.cc
@@ -0,0 +1,381 @@
+// Copyright (c) 2011 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 "chrome/browser/ui/search_engines/template_url_table_model.h"
+
+#include "base/callback.h"
+#include "base/i18n/rtl.h"
+#include "base/stl_util-inl.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/favicon_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_model.h"
+#include "grit/app_resources.h"
+#include "grit/generated_resources.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/models/table_model_observer.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/codec/png_codec.h"
+
+// Group IDs used by TemplateURLTableModel.
+static const int kMainGroupID = 0;
+static const int kOtherGroupID = 1;
+
+// ModelEntry ----------------------------------------------------
+
+// ModelEntry wraps a TemplateURL as returned from the TemplateURL.
+// ModelEntry also tracks state information about the URL.
+
+// Icon used while loading, or if a specific favicon can't be found.
+static SkBitmap* default_icon = NULL;
+
+class ModelEntry {
+ public:
+ explicit ModelEntry(TemplateURLTableModel* model,
+ const TemplateURL& template_url)
+ : template_url_(template_url),
+ load_state_(NOT_LOADED),
+ model_(model) {
+ if (!default_icon) {
+ default_icon = ResourceBundle::GetSharedInstance().
+ GetBitmapNamed(IDR_DEFAULT_FAVICON);
+ }
+ }
+
+ const TemplateURL& template_url() {
+ return template_url_;
+ }
+
+ SkBitmap GetIcon() {
+ if (load_state_ == NOT_LOADED)
+ LoadFavIcon();
+ if (!fav_icon_.isNull())
+ return fav_icon_;
+ return *default_icon;
+ }
+
+ // Resets internal status so that the next time the icon is asked for its
+ // fetched again. This should be invoked if the url is modified.
+ void ResetIcon() {
+ load_state_ = NOT_LOADED;
+ fav_icon_ = SkBitmap();
+ }
+
+ private:
+ // State of the favicon.
+ enum LoadState {
+ NOT_LOADED,
+ LOADING,
+ LOADED
+ };
+
+ void LoadFavIcon() {
+ load_state_ = LOADED;
+ FaviconService* favicon_service =
+ model_->template_url_model()->profile()->GetFaviconService(
+ Profile::EXPLICIT_ACCESS);
+ if (!favicon_service)
+ return;
+ GURL fav_icon_url = template_url().GetFavIconURL();
+ if (!fav_icon_url.is_valid()) {
+ // The favicon url isn't always set. Guess at one here.
+ if (template_url_.url() && template_url_.url()->IsValid()) {
+ GURL url = GURL(template_url_.url()->url());
+ if (url.is_valid())
+ fav_icon_url = TemplateURL::GenerateFaviconURL(url);
+ }
+ if (!fav_icon_url.is_valid())
+ return;
+ }
+ load_state_ = LOADING;
+ favicon_service->GetFavicon(fav_icon_url,
+ &request_consumer_,
+ NewCallback(this, &ModelEntry::OnFavIconDataAvailable));
+ }
+
+ void OnFavIconDataAvailable(
+ FaviconService::Handle handle,
+ bool know_favicon,
+ scoped_refptr<RefCountedMemory> data,
+ bool expired,
+ GURL icon_url) {
+ load_state_ = LOADED;
+ if (know_favicon && data.get() &&
+ gfx::PNGCodec::Decode(data->front(), data->size(), &fav_icon_)) {
+ model_->FavIconAvailable(this);
+ }
+ }
+
+ const TemplateURL& template_url_;
+ SkBitmap fav_icon_;
+ LoadState load_state_;
+ TemplateURLTableModel* model_;
+ CancelableRequestConsumer request_consumer_;
+
+ DISALLOW_COPY_AND_ASSIGN(ModelEntry);
+};
+
+// TemplateURLTableModel -----------------------------------------
+
+TemplateURLTableModel::TemplateURLTableModel(
+ TemplateURLModel* template_url_model)
+ : observer_(NULL),
+ template_url_model_(template_url_model) {
+ DCHECK(template_url_model);
+ template_url_model_->Load();
+ template_url_model_->AddObserver(this);
+ Reload();
+}
+
+TemplateURLTableModel::~TemplateURLTableModel() {
+ template_url_model_->RemoveObserver(this);
+ STLDeleteElements(&entries_);
+ entries_.clear();
+}
+
+void TemplateURLTableModel::Reload() {
+ STLDeleteElements(&entries_);
+ entries_.clear();
+
+ std::vector<const TemplateURL*> urls = template_url_model_->GetTemplateURLs();
+
+ // Keywords that can be made the default first.
+ for (std::vector<const TemplateURL*>::iterator i = urls.begin();
+ i != urls.end(); ++i) {
+ const TemplateURL& template_url = *(*i);
+ // NOTE: we don't use ShowInDefaultList here to avoid items bouncing around
+ // the lists while editing.
+ if (template_url.show_in_default_list())
+ entries_.push_back(new ModelEntry(this, template_url));
+ }
+
+ last_search_engine_index_ = static_cast<int>(entries_.size());
+
+ // Then the rest.
+ for (std::vector<const TemplateURL*>::iterator i = urls.begin();
+ i != urls.end(); ++i) {
+ const TemplateURL* template_url = *i;
+ // NOTE: we don't use ShowInDefaultList here to avoid things bouncing
+ // the lists while editing.
+ if (!template_url->show_in_default_list() &&
+ !template_url->IsExtensionKeyword()) {
+ entries_.push_back(new ModelEntry(this, *template_url));
+ }
+ }
+
+ if (observer_)
+ observer_->OnModelChanged();
+}
+
+int TemplateURLTableModel::RowCount() {
+ return static_cast<int>(entries_.size());
+}
+
+string16 TemplateURLTableModel::GetText(int row, int col_id) {
+ DCHECK(row >= 0 && row < RowCount());
+ const TemplateURL& url = entries_[row]->template_url();
+
+ switch (col_id) {
+ case IDS_SEARCH_ENGINES_EDITOR_DESCRIPTION_COLUMN: {
+ string16 url_short_name = url.short_name();
+ // TODO(xji): Consider adding a special case if the short name is a URL,
+ // since those should always be displayed LTR. Please refer to
+ // http://crbug.com/6726 for more information.
+ base::i18n::AdjustStringForLocaleDirection(&url_short_name);
+ if (template_url_model_->GetDefaultSearchProvider() == &url) {
+ return l10n_util::GetStringFUTF16(
+ IDS_SEARCH_ENGINES_EDITOR_DEFAULT_ENGINE,
+ url_short_name);
+ }
+ return url_short_name;
+ }
+
+ case IDS_SEARCH_ENGINES_EDITOR_KEYWORD_COLUMN: {
+ // Keyword should be domain name. Force it to have LTR directionality.
+ string16 keyword = url.keyword();
+ keyword = base::i18n::GetDisplayStringInLTRDirectionality(keyword);
+ return keyword;
+ }
+
+ default:
+ NOTREACHED();
+ return string16();
+ }
+}
+
+SkBitmap TemplateURLTableModel::GetIcon(int row) {
+ DCHECK(row >= 0 && row < RowCount());
+ return entries_[row]->GetIcon();
+}
+
+void TemplateURLTableModel::SetObserver(ui::TableModelObserver* observer) {
+ observer_ = observer;
+}
+
+bool TemplateURLTableModel::HasGroups() {
+ return true;
+}
+
+TemplateURLTableModel::Groups TemplateURLTableModel::GetGroups() {
+ Groups groups;
+
+ Group search_engine_group;
+ search_engine_group.title =
+ l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_MAIN_SEPARATOR);
+ search_engine_group.id = kMainGroupID;
+ groups.push_back(search_engine_group);
+
+ Group other_group;
+ other_group.title =
+ l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_OTHER_SEPARATOR);
+ other_group.id = kOtherGroupID;
+ groups.push_back(other_group);
+
+ return groups;
+}
+
+int TemplateURLTableModel::GetGroupID(int row) {
+ DCHECK(row >= 0 && row < RowCount());
+ return row < last_search_engine_index_ ? kMainGroupID : kOtherGroupID;
+}
+
+void TemplateURLTableModel::Remove(int index) {
+ // Remove the observer while we modify the model, that way we don't need to
+ // worry about the model calling us back when we mutate it.
+ template_url_model_->RemoveObserver(this);
+ const TemplateURL* template_url = &GetTemplateURL(index);
+
+ scoped_ptr<ModelEntry> entry(entries_[index]);
+ entries_.erase(entries_.begin() + index);
+ if (index < last_search_engine_index_)
+ last_search_engine_index_--;
+ if (observer_)
+ observer_->OnItemsRemoved(index, 1);
+
+ // Make sure to remove from the table model first, otherwise the
+ // TemplateURL would be freed.
+ template_url_model_->Remove(template_url);
+ template_url_model_->AddObserver(this);
+}
+
+void TemplateURLTableModel::Add(int index, TemplateURL* template_url) {
+ DCHECK(index >= 0 && index <= RowCount());
+ ModelEntry* entry = new ModelEntry(this, *template_url);
+ entries_.insert(entries_.begin() + index, entry);
+ if (observer_)
+ observer_->OnItemsAdded(index, 1);
+ template_url_model_->RemoveObserver(this);
+ template_url_model_->Add(template_url);
+ template_url_model_->AddObserver(this);
+}
+
+void TemplateURLTableModel::ModifyTemplateURL(int index,
+ const string16& title,
+ const string16& keyword,
+ const std::string& url) {
+ DCHECK(index >= 0 && index <= RowCount());
+ const TemplateURL* template_url = &GetTemplateURL(index);
+ template_url_model_->RemoveObserver(this);
+ template_url_model_->ResetTemplateURL(template_url, title, keyword, url);
+ if (template_url_model_->GetDefaultSearchProvider() == template_url &&
+ !TemplateURL::SupportsReplacement(template_url)) {
+ // The entry was the default search provider, but the url has been modified
+ // so that it no longer supports replacement. Reset the default search
+ // provider so that it doesn't point to a bogus entry.
+ template_url_model_->SetDefaultSearchProvider(NULL);
+ }
+ template_url_model_->AddObserver(this);
+ ReloadIcon(index); // Also calls NotifyChanged().
+}
+
+void TemplateURLTableModel::ReloadIcon(int index) {
+ DCHECK(index >= 0 && index < RowCount());
+
+ entries_[index]->ResetIcon();
+
+ NotifyChanged(index);
+}
+
+const TemplateURL& TemplateURLTableModel::GetTemplateURL(int index) {
+ return entries_[index]->template_url();
+}
+
+int TemplateURLTableModel::IndexOfTemplateURL(
+ const TemplateURL* template_url) {
+ for (std::vector<ModelEntry*>::iterator i = entries_.begin();
+ i != entries_.end(); ++i) {
+ ModelEntry* entry = *i;
+ if (&(entry->template_url()) == template_url)
+ return static_cast<int>(i - entries_.begin());
+ }
+ return -1;
+}
+
+int TemplateURLTableModel::MoveToMainGroup(int index) {
+ if (index < last_search_engine_index_)
+ return index; // Already in the main group.
+
+ ModelEntry* current_entry = entries_[index];
+ entries_.erase(index + entries_.begin());
+ if (observer_)
+ observer_->OnItemsRemoved(index, 1);
+
+ const int new_index = last_search_engine_index_++;
+ entries_.insert(entries_.begin() + new_index, current_entry);
+ if (observer_)
+ observer_->OnItemsAdded(new_index, 1);
+ return new_index;
+}
+
+int TemplateURLTableModel::MakeDefaultTemplateURL(int index) {
+ if (index < 0 || index >= RowCount()) {
+ NOTREACHED();
+ return -1;
+ }
+
+ const TemplateURL* keyword = &GetTemplateURL(index);
+ const TemplateURL* current_default =
+ template_url_model_->GetDefaultSearchProvider();
+ if (current_default == keyword)
+ return -1;
+
+ template_url_model_->RemoveObserver(this);
+ template_url_model_->SetDefaultSearchProvider(keyword);
+ template_url_model_->AddObserver(this);
+
+ // The formatting of the default engine is different; notify the table that
+ // both old and new entries have changed.
+ if (current_default != NULL) {
+ int old_index = IndexOfTemplateURL(current_default);
+ // current_default may not be in the list of TemplateURLs if the database is
+ // corrupt and the default TemplateURL is used from preferences
+ if (old_index >= 0)
+ NotifyChanged(old_index);
+ }
+ const int new_index = IndexOfTemplateURL(keyword);
+ NotifyChanged(new_index);
+
+ // Make sure the new default is in the main group.
+ return MoveToMainGroup(index);
+}
+
+void TemplateURLTableModel::NotifyChanged(int index) {
+ if (observer_) {
+ DCHECK_GE(index, 0);
+ observer_->OnItemsChanged(index, 1);
+ }
+}
+
+void TemplateURLTableModel::FavIconAvailable(ModelEntry* entry) {
+ std::vector<ModelEntry*>::iterator i =
+ find(entries_.begin(), entries_.end(), entry);
+ DCHECK(i != entries_.end());
+ NotifyChanged(static_cast<int>(i - entries_.begin()));
+}
+
+void TemplateURLTableModel::OnTemplateURLModelChanged() {
+ Reload();
+}