summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authormattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-26 21:25:18 +0000
committermattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-26 21:25:18 +0000
commitff8389293372e9b7b2db0799f5f9a512af694cf8 (patch)
tree59b6b2b58084952fecf7a95e216f33d8617ef49a /chrome
parent85233a9f663380dbefc405bb068f8544fdcec38c (diff)
downloadchromium_src-ff8389293372e9b7b2db0799f5f9a512af694cf8.zip
chromium_src-ff8389293372e9b7b2db0799f5f9a512af694cf8.tar.gz
chromium_src-ff8389293372e9b7b2db0799f5f9a512af694cf8.tar.bz2
Refactor the win KeywordEditorView for cross platform friendliness.
The TableModel is moved to search_engines/template_url_table_model.* The shared logic, and ownership of the url_model_ and table_model_, is moved to search_engines/keyword_editor_controller.* BUG=13326 Review URL: http://codereview.chromium.org/146138 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19421 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/search_engines/keyword_editor_controller.cc98
-rw-r--r--chrome/browser/search_engines/keyword_editor_controller.h72
-rw-r--r--chrome/browser/search_engines/keyword_editor_controller_unittest.cc (renamed from chrome/browser/views/keyword_editor_view_unittest.cc)37
-rw-r--r--chrome/browser/search_engines/template_url_table_model.cc371
-rw-r--r--chrome/browser/search_engines/template_url_table_model.h110
-rw-r--r--chrome/browser/views/keyword_editor_view.cc456
-rw-r--r--chrome/browser/views/keyword_editor_view.h117
-rw-r--r--chrome/chrome.gyp6
8 files changed, 706 insertions, 561 deletions
diff --git a/chrome/browser/search_engines/keyword_editor_controller.cc b/chrome/browser/search_engines/keyword_editor_controller.cc
new file mode 100644
index 0000000..022af56
--- /dev/null
+++ b/chrome/browser/search_engines/keyword_editor_controller.cc
@@ -0,0 +1,98 @@
+// Copyright (c) 2009 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/search_engines/keyword_editor_controller.h"
+
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/search_engines/template_url_table_model.h"
+
+KeywordEditorController::KeywordEditorController(Profile* profile)
+ : profile_(profile) {
+ table_model_.reset(new TemplateURLTableModel(profile->GetTemplateURLModel()));
+}
+
+KeywordEditorController::~KeywordEditorController() {
+}
+
+int KeywordEditorController::AddTemplateURL(const std::wstring& title,
+ const std::wstring& keyword,
+ const std::wstring& url) {
+ DCHECK(!url.empty());
+
+ UserMetrics::RecordAction(L"KeywordEditor_AddKeyword", profile_);
+
+ TemplateURL* template_url = new TemplateURL();
+ template_url->set_short_name(title);
+ template_url->set_keyword(keyword);
+ template_url->SetURL(url, 0, 0);
+
+ // There's a bug (1090726) in TableView with groups enabled such that newly
+ // added items in groups ALWAYS appear at the end, regardless of the index
+ // passed in. Worse yet, the selected rows get messed up when this happens
+ // causing other problems. As a work around we always add the item to the end
+ // of the list.
+ const int new_index = table_model_->RowCount();
+ table_model_->Add(new_index, template_url);
+
+ return new_index;
+}
+
+void KeywordEditorController::ModifyTemplateURL(const TemplateURL* template_url,
+ const std::wstring& title,
+ const std::wstring& keyword,
+ const std::wstring& url) {
+ const int index = table_model_->IndexOfTemplateURL(template_url);
+ if (index == -1) {
+ // Will happen if url was deleted out from under us while the user was
+ // editing it.
+ return;
+ }
+
+ // Don't do anything if the entry didn't change.
+ if (template_url->short_name() == title &&
+ template_url->keyword() == keyword &&
+ ((url.empty() && !template_url->url()) ||
+ (!url.empty() && template_url->url() &&
+ template_url->url()->url() == url))) {
+ return;
+ }
+
+ table_model_->ModifyTemplateURL(index, title, keyword, url);
+
+ UserMetrics::RecordAction(L"KeywordEditor_ModifiedKeyword", profile_);
+}
+
+bool KeywordEditorController::CanMakeDefault(const TemplateURL* url) const {
+ return (url != url_model()->GetDefaultSearchProvider() &&
+ url->url() &&
+ url->url()->SupportsReplacement());
+}
+
+bool KeywordEditorController::CanRemove(const TemplateURL* url) const {
+ return url != url_model()->GetDefaultSearchProvider();
+}
+
+void KeywordEditorController::RemoveTemplateURL(int index) {
+ table_model_->Remove(index);
+ UserMetrics::RecordAction(L"KeywordEditor_RemoveKeyword", profile_);
+}
+
+int KeywordEditorController::MakeDefaultTemplateURL(int index) {
+ return table_model_->MakeDefaultTemplateURL(index);
+}
+
+bool KeywordEditorController::loaded() const {
+ return url_model()->loaded();
+}
+
+const TemplateURL* KeywordEditorController::GetTemplateURL(int index) const {
+ return &table_model_->GetTemplateURL(index);
+}
+
+TemplateURLModel* KeywordEditorController::url_model() const {
+ return table_model_->template_url_model();
+}
diff --git a/chrome/browser/search_engines/keyword_editor_controller.h b/chrome/browser/search_engines/keyword_editor_controller.h
new file mode 100644
index 0000000..1aafc2c
--- /dev/null
+++ b/chrome/browser/search_engines/keyword_editor_controller.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_SEARCH_ENGINES_KEYWORD_EDITOR_CONTROLLER_H_
+#define CHROME_BROWSER_SEARCH_ENGINES_KEYWORD_EDITOR_CONTROLLER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+
+class Profile;
+class TemplateURL;
+class TemplateURLModel;
+class TemplateURLTableModel;
+
+class KeywordEditorController {
+ public:
+ explicit KeywordEditorController(Profile* profile);
+ ~KeywordEditorController();
+
+ // Invoked when the user succesfully fills out the add keyword dialog.
+ // Propagates the change to the TemplateURLModel and updates the table model.
+ // Returns the index of the added URL.
+ int AddTemplateURL(const std::wstring& title,
+ const std::wstring& keyword,
+ const std::wstring& url);
+
+ // Invoked when the user modifies a TemplateURL. Updates the TemplateURLModel
+ // and table model appropriately.
+ void ModifyTemplateURL(const TemplateURL* template_url,
+ const std::wstring& title,
+ const std::wstring& keyword,
+ const std::wstring& url);
+
+ // Return true if the given |url| can be made the default.
+ bool CanMakeDefault(const TemplateURL* url) const;
+
+ // Return true if the given |url| can be removed.
+ bool CanRemove(const TemplateURL* url) const;
+
+ // Remove the TemplateURL at the specified index in the TableModel.
+ void RemoveTemplateURL(int index);
+
+ // Make the TemplateURL at the specified index (into the TableModel) the
+ // default search provider. Return the new index, or -1 if nothing was done.
+ int MakeDefaultTemplateURL(int index);
+
+ // Return true if the |url_model_| data is loaded.
+ bool loaded() const;
+
+ // Return the TemplateURL corresponding to the |index| in the model.
+ const TemplateURL* GetTemplateURL(int index) const;
+
+ TemplateURLTableModel* table_model() {
+ return table_model_.get();
+ }
+
+ TemplateURLModel* url_model() const;
+
+ private:
+ // The profile.
+ Profile* profile_;
+
+ // Model for the TableView.
+ scoped_ptr<TemplateURLTableModel> table_model_;
+
+ DISALLOW_COPY_AND_ASSIGN(KeywordEditorController);
+};
+
+#endif // CHROME_BROWSER_SEARCH_ENGINES_KEYWORD_EDITOR_CONTROLLER_H_
diff --git a/chrome/browser/views/keyword_editor_view_unittest.cc b/chrome/browser/search_engines/keyword_editor_controller_unittest.cc
index c23ee4e..87d3db5 100644
--- a/chrome/browser/views/keyword_editor_view_unittest.cc
+++ b/chrome/browser/search_engines/keyword_editor_controller_unittest.cc
@@ -1,19 +1,20 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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 "app/table_model_observer.h"
#include "chrome/browser/profile.h"
+#include "chrome/browser/search_engines/keyword_editor_controller.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
-#include "chrome/browser/views/keyword_editor_view.h"
+#include "chrome/browser/search_engines/template_url_table_model.h"
#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
// Base class for keyword editor tests. Creates a profile containing an
// empty TemplateURLModel.
-class KeywordEditorViewTest : public testing::Test,
- public TableModelObserver {
+class KeywordEditorControllerTest : public testing::Test,
+ public TableModelObserver {
public:
virtual void SetUp() {
model_changed_count_ = items_changed_count_ = added_count_ =
@@ -24,8 +25,8 @@ class KeywordEditorViewTest : public testing::Test,
model_ = profile_->GetTemplateURLModel();
- editor_.reset(new KeywordEditorView(profile_.get()));
- editor_->table_model_->SetObserver(this);
+ controller_.reset(new KeywordEditorController(profile_.get()));
+ controller_->table_model()->SetObserver(this);
}
virtual void OnModelChanged() {
@@ -59,13 +60,13 @@ class KeywordEditorViewTest : public testing::Test,
}
TemplateURLTableModel* table_model() const {
- return editor_->table_model_.get();
+ return controller_->table_model();
}
protected:
MessageLoopForUI message_loop_;
scoped_ptr<TestingProfile> profile_;
- scoped_ptr<KeywordEditorView> editor_;
+ scoped_ptr<KeywordEditorController> controller_;
TemplateURLModel* model_;
int model_changed_count_;
@@ -75,8 +76,8 @@ class KeywordEditorViewTest : public testing::Test,
};
// Tests adding a TemplateURL.
-TEST_F(KeywordEditorViewTest, Add) {
- editor_->AddTemplateURL(L"a", L"b", L"http://c");
+TEST_F(KeywordEditorControllerTest, Add) {
+ controller_->AddTemplateURL(L"a", L"b", L"http://c");
// Verify the observer was notified.
VerifyChangeCount(0, 0, 1, 0);
@@ -87,7 +88,7 @@ TEST_F(KeywordEditorViewTest, Add) {
ASSERT_EQ(1, table_model()->RowCount());
// Verify the TemplateURLModel has the new entry.
- ASSERT_EQ(1, model_->GetTemplateURLs().size());
+ ASSERT_EQ(1U, model_->GetTemplateURLs().size());
// Verify the entry is what we added.
const TemplateURL* turl = model_->GetTemplateURLs()[0];
@@ -98,13 +99,13 @@ TEST_F(KeywordEditorViewTest, Add) {
}
// Tests modifying a TemplateURL.
-TEST_F(KeywordEditorViewTest, Modify) {
- editor_->AddTemplateURL(L"a", L"b", L"http://c");
+TEST_F(KeywordEditorControllerTest, Modify) {
+ controller_->AddTemplateURL(L"a", L"b", L"http://c");
ClearChangeCount();
// Modify the entry.
const TemplateURL* turl = model_->GetTemplateURLs()[0];
- editor_->ModifyTemplateURL(turl, L"a1", L"b1", L"http://c1");
+ controller_->ModifyTemplateURL(turl, L"a1", L"b1", L"http://c1");
// Make sure it was updated appropriately.
VerifyChangeCount(0, 1, 0, 0);
@@ -115,12 +116,12 @@ TEST_F(KeywordEditorViewTest, Modify) {
}
// Tests making a TemplateURL the default search provider.
-TEST_F(KeywordEditorViewTest, MakeDefault) {
- editor_->AddTemplateURL(L"a", L"b", L"http://c{searchTerms}");
+TEST_F(KeywordEditorControllerTest, MakeDefault) {
+ controller_->AddTemplateURL(L"a", L"b", L"http://c{searchTerms}");
ClearChangeCount();
const TemplateURL* turl = model_->GetTemplateURLs()[0];
- editor_->MakeDefaultSearchProvider(0);
+ controller_->MakeDefaultTemplateURL(0);
// Making an item the default sends a handful of changes. Which are sent isn't
// important, what is important is 'something' is sent.
ASSERT_TRUE(items_changed_count_ > 0 || added_count_ > 0 ||
@@ -130,7 +131,7 @@ TEST_F(KeywordEditorViewTest, MakeDefault) {
// Mutates the TemplateURLModel and make sure table model is updating
// appropriately.
-TEST_F(KeywordEditorViewTest, MutateTemplateURLModel) {
+TEST_F(KeywordEditorControllerTest, MutateTemplateURLModel) {
TemplateURL* turl = new TemplateURL();
turl->set_keyword(L"a");
turl->set_short_name(L"b");
diff --git a/chrome/browser/search_engines/template_url_table_model.cc b/chrome/browser/search_engines/template_url_table_model.cc
new file mode 100644
index 0000000..d519e85
--- /dev/null
+++ b/chrome/browser/search_engines/template_url_table_model.cc
@@ -0,0 +1,371 @@
+// Copyright (c) 2009 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/search_engines/template_url_table_model.h"
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "app/table_model_observer.h"
+#include "base/gfx/png_decoder.h"
+#include "chrome/browser/history/history.h"
+#include "chrome/browser/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"
+
+// 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;
+ HistoryService* hs =
+ model_->template_url_model()->profile()->GetHistoryService(
+ Profile::EXPLICIT_ACCESS);
+ if (!hs)
+ 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(WideToUTF16Hack(template_url_.url()->url()));
+ if (url.is_valid())
+ fav_icon_url = TemplateURL::GenerateFaviconURL(url);
+ }
+ if (!fav_icon_url.is_valid())
+ return;
+ }
+ load_state_ = LOADING;
+ hs->GetFavIcon(fav_icon_url,
+ &request_consumer_,
+ NewCallback(this, &ModelEntry::OnFavIconDataAvailable));
+ }
+
+ void OnFavIconDataAvailable(
+ HistoryService::Handle handle,
+ bool know_favicon,
+ scoped_refptr<RefCountedBytes> data,
+ bool expired,
+ GURL icon_url) {
+ load_state_ = LOADED;
+ if (know_favicon && data.get() &&
+ PNGDecoder::Decode(&data->data, &fav_icon_)) {
+ model_->FavIconAvailable(this);
+ }
+ }
+
+ const TemplateURL& template_url_;
+ SkBitmap fav_icon_;
+ LoadState load_state_;
+ TemplateURLTableModel* model_;
+ CancelableRequestConsumer request_consumer_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(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())
+ entries_.push_back(new ModelEntry(this, *template_url));
+ }
+
+ if (observer_)
+ observer_->OnModelChanged();
+}
+
+int TemplateURLTableModel::RowCount() {
+ return static_cast<int>(entries_.size());
+}
+
+std::wstring 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: {
+ std::wstring 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.
+ l10n_util::AdjustStringForLocaleDirection(url_short_name,
+ &url_short_name);
+ return (template_url_model_->GetDefaultSearchProvider() == &url) ?
+ l10n_util::GetStringF(IDS_SEARCH_ENGINES_EDITOR_DEFAULT_ENGINE,
+ url_short_name) : url_short_name;
+ }
+
+ case IDS_SEARCH_ENGINES_EDITOR_KEYWORD_COLUMN: {
+ const std::wstring& keyword = url.keyword();
+ // Keyword should be domain name. Force it to have LTR directionality.
+ if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) {
+ std::wstring localized_keyword = keyword;
+ l10n_util::WrapStringWithLTRFormatting(&localized_keyword);
+ return localized_keyword;
+ }
+ return keyword;
+ break;
+ }
+
+ default:
+ NOTREACHED();
+ return std::wstring();
+ }
+}
+
+SkBitmap TemplateURLTableModel::GetIcon(int row) {
+ DCHECK(row >= 0 && row < RowCount());
+ return entries_[row]->GetIcon();
+}
+
+void TemplateURLTableModel::SetObserver(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::GetString(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::GetString(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_[static_cast<int>(index)]);
+ entries_.erase(entries_.begin() + static_cast<int>(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 std::wstring& title,
+ const std::wstring& keyword,
+ const std::wstring& 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 -1; // 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)
+ NotifyChanged(IndexOfTemplateURL(current_default));
+ 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_)
+ 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();
+}
diff --git a/chrome/browser/search_engines/template_url_table_model.h b/chrome/browser/search_engines/template_url_table_model.h
new file mode 100644
index 0000000..aef40bc
--- /dev/null
+++ b/chrome/browser/search_engines/template_url_table_model.h
@@ -0,0 +1,110 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_TABLE_MODEL_H_
+#define CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_TABLE_MODEL_H_
+
+#include "app/table_model.h"
+#include "chrome/browser/search_engines/template_url_model.h"
+
+class ModelEntry;
+class SkBitmap;
+class TemplateURL;
+class TemplateURLModel;
+class TemplateURLTableModel;
+
+// TemplateURLTableModel is the TableModel implementation used by
+// KeywordEditorView to show the keywords in a TableView.
+//
+// TemplateURLTableModel has two columns, the first showing the description,
+// the second the keyword.
+//
+// TemplateURLTableModel maintains a vector of ModelEntrys that correspond to
+// each row in the tableview. Each ModelEntry wraps a TemplateURL, providing
+// the favicon. The entries in the model are sorted such that non-generated
+// appear first (grouped together) and are followed by generated keywords.
+
+class TemplateURLTableModel : public TableModel,
+ TemplateURLModelObserver {
+ public:
+ explicit TemplateURLTableModel(TemplateURLModel* template_url_model);
+
+ virtual ~TemplateURLTableModel();
+
+ // Reloads the entries from the TemplateURLModel. This should ONLY be invoked
+ // if the TemplateURLModel wasn't initially loaded and has been loaded.
+ void Reload();
+
+ // TableModel overrides.
+ virtual int RowCount();
+ virtual std::wstring GetText(int row, int column);
+ virtual SkBitmap GetIcon(int row);
+ virtual void SetObserver(TableModelObserver* observer);
+ virtual bool HasGroups();
+ virtual Groups GetGroups();
+ virtual int GetGroupID(int row);
+
+ // Removes the entry at the specified index.
+ void Remove(int index);
+
+ // Adds a new entry at the specified index.
+ void Add(int index, TemplateURL* template_url);
+
+ // Update the entry at the specified index.
+ void ModifyTemplateURL(int index, const std::wstring& title,
+ const std::wstring& keyword, const std::wstring& url);
+
+ // Reloads the icon at the specified index.
+ void ReloadIcon(int index);
+
+ // Returns The TemplateURL at the specified index.
+ const TemplateURL& GetTemplateURL(int index);
+
+ // Returns the index of the TemplateURL, or -1 if it the TemplateURL is not
+ // found.
+ int IndexOfTemplateURL(const TemplateURL* template_url);
+
+ // Moves the keyword at the specified index to be at the end of the main
+ // group. Returns the new index. This does nothing if the entry is already
+ // in the main group.
+ int MoveToMainGroup(int index);
+
+ // Make the TemplateURL at |index| the default. Returns the new index, or -1
+ // if the index is invalid or it is already the default.
+ int MakeDefaultTemplateURL(int index);
+
+ // If there is an observer, it's notified the selected row has changed.
+ void NotifyChanged(int index);
+
+ TemplateURLModel* template_url_model() const { return template_url_model_; }
+
+ // Returns the index of the last entry shown in the search engines group.
+ int last_search_engine_index() const { return last_search_engine_index_; }
+
+ private:
+ friend class ModelEntry;
+
+ // Notification that a model entry has fetched its icon.
+ void FavIconAvailable(ModelEntry* entry);
+
+ // TemplateURLModelObserver notification.
+ virtual void OnTemplateURLModelChanged();
+
+ TableModelObserver* observer_;
+
+ // The entries.
+ std::vector<ModelEntry*> entries_;
+
+ // The model we're displaying entries from.
+ TemplateURLModel* template_url_model_;
+
+ // Index of the last search engine in entries_. This is used to determine the
+ // group boundaries.
+ int last_search_engine_index_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(TemplateURLTableModel);
+};
+
+
+#endif // CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_TABLE_MODEL_H_
diff --git a/chrome/browser/views/keyword_editor_view.cc b/chrome/browser/views/keyword_editor_view.cc
index bfdd65d..ec68263 100644
--- a/chrome/browser/views/keyword_editor_view.cc
+++ b/chrome/browser/views/keyword_editor_view.cc
@@ -7,24 +7,19 @@
#include <vector>
#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
-#include "base/gfx/png_decoder.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
-#include "chrome/browser/history/history.h"
#include "chrome/browser/profile.h"
-#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/search_engines/template_url_table_model.h"
#include "chrome/browser/views/browser_dialogs.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
#include "googleurl/src/gurl.h"
-#include "grit/app_resources.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "grit/theme_resources.h"
-#include "third_party/skia/include/core/SkBitmap.h"
#include "views/background.h"
#include "views/grid_layout.h"
#include "views/controls/button/native_button.h"
@@ -38,10 +33,6 @@
using views::GridLayout;
using views::NativeButton;
-// Group IDs used by TemplateURLTableModel.
-static const int kMainGroupID = 0;
-static const int kOtherGroupID = 1;
-
namespace browser {
// Declared in browser_dialogs.h so others don't have to depend on our header.
@@ -51,288 +42,6 @@ void ShowKeywordEditorView(Profile* profile) {
} // namespace browser
-// 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)
- : model_(model),
- template_url_(template_url) {
- load_state_ = NOT_LOADED;
- 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;
- HistoryService* hs =
- model_->template_url_model()->profile()->GetHistoryService(
- Profile::EXPLICIT_ACCESS);
- if (!hs)
- 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;
- hs->GetFavIcon(fav_icon_url,
- &request_consumer_,
- NewCallback(this, &ModelEntry::OnFavIconDataAvailable));
- }
-
- void OnFavIconDataAvailable(
- HistoryService::Handle handle,
- bool know_favicon,
- scoped_refptr<RefCountedBytes> data,
- bool expired,
- GURL icon_url) {
- load_state_ = LOADED;
- if (know_favicon && data.get() &&
- PNGDecoder::Decode(&data->data, &fav_icon_)) {
- model_->FavIconAvailable(this);
- }
- }
-
- const TemplateURL& template_url_;
- SkBitmap fav_icon_;
- LoadState load_state_;
- TemplateURLTableModel* model_;
- CancelableRequestConsumer request_consumer_;
-
- DISALLOW_EVIL_CONSTRUCTORS(ModelEntry);
-};
-
-// TemplateURLTableModel -----------------------------------------
-
-TemplateURLTableModel::TemplateURLTableModel(
- TemplateURLModel* template_url_model)
- : observer_(NULL),
- template_url_model_(template_url_model) {
- DCHECK(template_url_model);
- Reload();
-}
-
-TemplateURLTableModel::~TemplateURLTableModel() {
- 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())
- entries_.push_back(new ModelEntry(this, *template_url));
- }
-
- if (observer_)
- observer_->OnModelChanged();
-}
-
-int TemplateURLTableModel::RowCount() {
- return static_cast<int>(entries_.size());
-}
-
-std::wstring 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: {
- std::wstring 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.
- l10n_util::AdjustStringForLocaleDirection(url_short_name,
- &url_short_name);
- return (template_url_model_->GetDefaultSearchProvider() == &url) ?
- l10n_util::GetStringF(IDS_SEARCH_ENGINES_EDITOR_DEFAULT_ENGINE,
- url_short_name) : url_short_name;
- }
-
- case IDS_SEARCH_ENGINES_EDITOR_KEYWORD_COLUMN: {
- const std::wstring& keyword = url.keyword();
- // Keyword should be domain name. Force it to have LTR directionality.
- if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) {
- std::wstring localized_keyword = keyword;
- l10n_util::WrapStringWithLTRFormatting(&localized_keyword);
- return localized_keyword;
- }
- return keyword;
- break;
- }
-
- default:
- NOTREACHED();
- return std::wstring();
- }
-}
-
-SkBitmap TemplateURLTableModel::GetIcon(int row) {
- DCHECK(row >= 0 && row < RowCount());
- return entries_[row]->GetIcon();
-}
-
-void TemplateURLTableModel::SetObserver(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::GetString(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::GetString(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) {
- scoped_ptr<ModelEntry> entry(entries_[static_cast<int>(index)]);
- entries_.erase(entries_.begin() + static_cast<int>(index));
- if (index < last_search_engine_index_)
- last_search_engine_index_--;
- if (observer_)
- observer_->OnItemsRemoved(index, 1);
-}
-
-void TemplateURLTableModel::Add(int index, const 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);
-}
-
-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;
-}
-
-void TemplateURLTableModel::MoveToMainGroup(int index) {
- if (index < last_search_engine_index_)
- return; // 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);
-}
-
-void TemplateURLTableModel::NotifyChanged(int index) {
- if (observer_)
- 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()));
-}
// KeywordEditorView ----------------------------------------------------------
@@ -362,17 +71,15 @@ void KeywordEditorView::Show(Profile* profile) {
KeywordEditorView::KeywordEditorView(Profile* profile)
: profile_(profile),
- url_model_(profile->GetTemplateURLModel()) {
- DCHECK(url_model_);
+ controller_(new KeywordEditorController(profile)) {
+ DCHECK(controller_->url_model());
+ controller_->url_model()->AddObserver(this);
Init();
}
KeywordEditorView::~KeywordEditorView() {
- // Only remove the listener if we installed one.
- if (table_model_.get()) {
- table_view_->SetModel(NULL);
- url_model_->RemoveObserver(this);
- }
+ table_view_->SetModel(NULL);
+ controller_->url_model()->RemoveObserver(this);
}
void KeywordEditorView::OnEditedKeyword(const TemplateURL* template_url,
@@ -380,75 +87,15 @@ void KeywordEditorView::OnEditedKeyword(const TemplateURL* template_url,
const std::wstring& keyword,
const std::wstring& url) {
if (template_url) {
- ModifyTemplateURL(template_url, title, keyword, url);
+ controller_->ModifyTemplateURL(template_url, title, keyword, url);
+
+ // Force the make default button to update.
+ OnSelectionChanged();
} else {
- AddTemplateURL(title, keyword, url);
+ table_view_->Select(controller_->AddTemplateURL(title, keyword, url));
}
}
-void KeywordEditorView::AddTemplateURL(const std::wstring& title,
- const std::wstring& keyword,
- const std::wstring& url) {
- DCHECK(!url.empty());
-
- UserMetrics::RecordAction(L"KeywordEditor_AddKeyword", profile_);
-
- TemplateURL* template_url = new TemplateURL();
- template_url->set_short_name(title);
- template_url->set_keyword(keyword);
- template_url->SetURL(url, 0, 0);
-
- // There's a bug (1090726) in TableView with groups enabled such that newly
- // added items in groups ALWAYS appear at the end, regardless of the index
- // passed in. Worse yet, the selected rows get messed up when this happens
- // causing other problems. As a work around we always add the item to the end
- // of the list.
- const int new_index = table_model_->RowCount();
- url_model_->RemoveObserver(this);
- table_model_->Add(new_index, template_url);
- url_model_->Add(template_url);
- url_model_->AddObserver(this);
-
- table_view_->Select(new_index);
-}
-
-void KeywordEditorView::ModifyTemplateURL(const TemplateURL* template_url,
- const std::wstring& title,
- const std::wstring& keyword,
- const std::wstring& url) {
- const int index = table_model_->IndexOfTemplateURL(template_url);
- if (index == -1) {
- // Will happen if url was deleted out from under us while the user was
- // editing it.
- return;
- }
-
- // Don't do anything if the entry didn't change.
- if (template_url->short_name() == title &&
- template_url->keyword() == keyword &&
- ((url.empty() && !template_url->url()) ||
- (!url.empty() && template_url->url() &&
- template_url->url()->url() == url))) {
- return;
- }
-
- url_model_->RemoveObserver(this);
- url_model_->ResetTemplateURL(template_url, title, keyword, url);
- if (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.
- url_model_->SetDefaultSearchProvider(NULL);
- }
- url_model_->AddObserver(this);
- table_model_->ReloadIcon(index); // Also calls NotifyChanged().
-
- // Force the make default button to update.
- OnSelectionChanged();
-
- UserMetrics::RecordAction(L"KeywordEditor_ModifiedKeyword", profile_);
-}
gfx::Size KeywordEditorView::GetPreferredSize() {
return gfx::Size(views::Window::GetLocalizedContentsSize(
@@ -483,13 +130,6 @@ views::View* KeywordEditorView::GetContentsView() {
}
void KeywordEditorView::Init() {
- DCHECK(!table_model_.get());
-
- url_model_->Load();
- url_model_->AddObserver(this);
-
- table_model_.reset(new TemplateURLTableModel(url_model_));
-
std::vector<TableColumn> columns;
columns.push_back(
TableColumn(IDS_SEARCH_ENGINES_EDITOR_DESCRIPTION_COLUMN,
@@ -499,13 +139,13 @@ void KeywordEditorView::Init() {
TableColumn(IDS_SEARCH_ENGINES_EDITOR_KEYWORD_COLUMN,
TableColumn::LEFT, -1, .25));
columns.back().sortable = true;
- table_view_ = new views::TableView(table_model_.get(), columns,
+ table_view_ = new views::TableView(controller_->table_model(), columns,
views::ICON_AND_TEXT, false, true, true);
table_view_->SetObserver(this);
add_button_ = new views::NativeButton(
this, l10n_util::GetString(IDS_SEARCH_ENGINES_EDITOR_NEW_BUTTON));
- add_button_->SetEnabled(url_model_->loaded());
+ add_button_->SetEnabled(controller_->loaded());
edit_button_ = new views::NativeButton(
this, l10n_util::GetString(IDS_SEARCH_ENGINES_EDITOR_EDIT_BUTTON));
@@ -566,12 +206,9 @@ void KeywordEditorView::OnSelectionChanged() {
bool can_remove = false;
if (selected_row_count == 1) {
const TemplateURL* selected_url =
- &table_model_->GetTemplateURL(table_view_->FirstSelectedRow());
- can_make_default =
- (selected_url != url_model_->GetDefaultSearchProvider() &&
- selected_url->url() &&
- selected_url->url()->SupportsReplacement());
- can_remove = (selected_url != url_model_->GetDefaultSearchProvider());
+ controller_->GetTemplateURL(table_view_->FirstSelectedRow());
+ can_make_default = controller_->CanMakeDefault(selected_url);
+ can_remove = controller_->CanRemove(selected_url);
}
remove_button_->SetEnabled(can_remove);
make_default_button_->SetEnabled(can_make_default);
@@ -587,74 +224,37 @@ void KeywordEditorView::ButtonPressed(views::Button* sender) {
browser::EditSearchEngine(GetWindow()->GetNativeWindow(), NULL, this,
profile_);
} else if (sender == remove_button_) {
- DCHECK(table_view_->SelectedRowCount() > 0);
- // 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.
- url_model_->RemoveObserver(this);
+ DCHECK(table_view_->SelectedRowCount() == 1);
int last_view_row = -1;
for (views::TableView::iterator i = table_view_->SelectionBegin();
i != table_view_->SelectionEnd(); ++i) {
last_view_row = table_view_->model_to_view(*i);
- const TemplateURL* template_url = &table_model_->GetTemplateURL(*i);
- // Make sure to remove from the table model first, otherwise the
- // TemplateURL would be freed.
- table_model_->Remove(*i);
- url_model_->Remove(template_url);
+ controller_->RemoveTemplateURL(*i);
}
- if (last_view_row >= table_model_->RowCount())
- last_view_row = table_model_->RowCount() - 1;
+ if (last_view_row >= controller_->table_model()->RowCount())
+ last_view_row = controller_->table_model()->RowCount() - 1;
if (last_view_row >= 0)
table_view_->Select(table_view_->view_to_model(last_view_row));
- url_model_->AddObserver(this);
- UserMetrics::RecordAction(L"KeywordEditor_RemoveKeyword", profile_);
} else if (sender == edit_button_) {
const int selected_row = table_view_->FirstSelectedRow();
const TemplateURL* template_url =
- &table_model_->GetTemplateURL(selected_row);
+ controller_->GetTemplateURL(selected_row);
browser::EditSearchEngine(GetWindow()->GetNativeWindow(), template_url,
this, profile_);
} else if (sender == make_default_button_) {
- MakeDefaultSearchProvider();
+ MakeDefaultTemplateURL();
} else {
NOTREACHED();
}
}
void KeywordEditorView::OnTemplateURLModelChanged() {
- table_model_->Reload();
- add_button_->SetEnabled(url_model_->loaded());
-}
-
-void KeywordEditorView::MakeDefaultSearchProvider() {
- MakeDefaultSearchProvider(table_view_->FirstSelectedRow());
+ add_button_->SetEnabled(controller_->loaded());
}
-void KeywordEditorView::MakeDefaultSearchProvider(int index) {
- if (index < 0 || index >= table_model_->RowCount()) {
- NOTREACHED();
- return;
- }
- const TemplateURL* keyword = &table_model_->GetTemplateURL(index);
- const TemplateURL* current_default = url_model_->GetDefaultSearchProvider();
- if (current_default == keyword)
- return;
-
- url_model_->RemoveObserver(this);
- url_model_->SetDefaultSearchProvider(keyword);
- 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) {
- table_model_->NotifyChanged(table_model_->IndexOfTemplateURL(
- current_default));
- }
- const int new_index = table_model_->IndexOfTemplateURL(keyword);
- table_model_->NotifyChanged(new_index);
-
- // Make sure the new default is in the main group.
- table_model_->MoveToMainGroup(index);
-
- // And select it.
- table_view_->Select(table_model_->IndexOfTemplateURL(keyword));
+void KeywordEditorView::MakeDefaultTemplateURL() {
+ int new_index =
+ controller_->MakeDefaultTemplateURL(table_view_->FirstSelectedRow());
+ if (new_index >= 0)
+ table_view_->Select(new_index);
}
diff --git a/chrome/browser/views/keyword_editor_view.h b/chrome/browser/views/keyword_editor_view.h
index c906d65..dd0cc89 100644
--- a/chrome/browser/views/keyword_editor_view.h
+++ b/chrome/browser/views/keyword_editor_view.h
@@ -10,6 +10,7 @@
#include "app/table_model.h"
#include "chrome/browser/search_engines/edit_search_engine_controller.h"
+#include "chrome/browser/search_engines/keyword_editor_controller.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "views/controls/button/button.h"
#include "views/controls/table/table_view_observer.h"
@@ -25,95 +26,10 @@ namespace {
class BorderView;
}
-class ModelEntry;
class SkBitmap;
class TemplateURLModel;
class TemplateURLTableModel;
-// TemplateURLTableModel is the TableModel implementation used by
-// KeywordEditorView to show the keywords in a TableView.
-//
-// TemplateURLTableModel has two columns, the first showing the description,
-// the second the keyword.
-//
-// TemplateURLTableModel maintains a vector of ModelEntrys that correspond to
-// each row in the tableview. Each ModelEntry wraps a TemplateURL, providing
-// the favicon. The entries in the model are sorted such that non-generated
-// appear first (grouped together) and are followed by generated keywords.
-
-class TemplateURLTableModel : public TableModel {
- public:
- explicit TemplateURLTableModel(TemplateURLModel* template_url_model);
-
- virtual ~TemplateURLTableModel();
-
- // Reloads the entries from the TemplateURLModel. This should ONLY be invoked
- // if the TemplateURLModel wasn't initially loaded and has been loaded.
- void Reload();
-
- // TableModel overrides.
- virtual int RowCount();
- virtual std::wstring GetText(int row, int column);
- virtual SkBitmap GetIcon(int row);
- virtual void SetObserver(TableModelObserver* observer);
- virtual bool HasGroups();
- virtual Groups GetGroups();
- virtual int GetGroupID(int row);
-
- // Removes the entry at the specified index. This does NOT propagate the
- // change to the backend.
- void Remove(int index);
-
- // Adds a new entry at the specified index. This does not propagate the
- // change to the backend.
- void Add(int index, const TemplateURL* template_url);
-
- // Reloads the icon at the specified index.
- void ReloadIcon(int index);
-
- // Returns The TemplateURL at the specified index.
- const TemplateURL& GetTemplateURL(int index);
-
- // Returns the index of the TemplateURL, or -1 if it the TemplateURL is not
- // found.
- int IndexOfTemplateURL(const TemplateURL* template_url);
-
- // Moves the keyword at the specified index to be at the end of the main
- // group. Returns the new index. This does nothing if the entry is already
- // in the main group.
- void MoveToMainGroup(int index);
-
- // If there is an observer, it's notified the selected row has changed.
- void NotifyChanged(int index);
-
- TemplateURLModel* template_url_model() const { return template_url_model_; }
-
- // Returns the index of the last entry shown in the search engines group.
- int last_search_engine_index() const { return last_search_engine_index_; }
-
- private:
- friend class ModelEntry;
-
- // Notification that a model entry has fetched its icon.
- void FavIconAvailable(ModelEntry* entry);
-
- TableModelObserver* observer_;
-
- // The entries.
- std::vector<ModelEntry*> entries_;
-
- // The model we're displaying entries from.
- TemplateURLModel* template_url_model_;
-
- // Index of the last search engine in entries_. This is used to determine the
- // group boundaries.
- int last_search_engine_index_;
-
- DISALLOW_EVIL_CONSTRUCTORS(TemplateURLTableModel);
-};
-
-// KeywordEditorView ----------------------------------------------------------
-
// KeywordEditorView allows the user to edit keywords.
class KeywordEditorView : public views::View,
@@ -122,8 +38,6 @@ class KeywordEditorView : public views::View,
public TemplateURLModelObserver,
public views::DialogDelegate,
public EditSearchEngineControllerDelegate {
- friend class KeywordEditorViewTest;
- FRIEND_TEST(KeywordEditorViewTest, MakeDefault);
public:
// Shows the KeywordEditorView for the specified profile. If there is a
// KeywordEditorView already open, it is closed and a new one is shown.
@@ -139,19 +53,6 @@ class KeywordEditorView : public views::View,
const std::wstring& keyword,
const std::wstring& url);
- // Invoked when the user succesfully fills out the add keyword dialog.
- // Propagates the change to the TemplateURLModel and updates the table model.
- void AddTemplateURL(const std::wstring& title,
- const std::wstring& keyword,
- const std::wstring& url);
-
- // Invoked when the user modifies a TemplateURL. Updates the TemplateURLModel
- // and table model appropriately.
- void ModifyTemplateURL(const TemplateURL* template_url,
- const std::wstring& title,
- const std::wstring& keyword,
- const std::wstring& url);
-
// Overriden to invoke Layout.
virtual gfx::Size GetPreferredSize();
@@ -163,9 +64,6 @@ class KeywordEditorView : public views::View,
virtual bool Cancel();
virtual views::View* GetContentsView();
- // Returns the TemplateURLModel we're using.
- TemplateURLModel* template_url_model() const { return url_model_; }
-
private:
void Init();
@@ -184,21 +82,12 @@ class KeywordEditorView : public views::View,
virtual void OnTemplateURLModelChanged();
// Toggles whether the selected keyword is the default search provider.
- void MakeDefaultSearchProvider();
-
- // Make the TemplateURL at the specified index (into the TableModel) the
- // default search provider.
- void MakeDefaultSearchProvider(int index);
+ void MakeDefaultTemplateURL();
// The profile.
Profile* profile_;
- // Model containing TemplateURLs. We listen for changes on this and propagate
- // them to the table model.
- TemplateURLModel* url_model_;
-
- // Model for the TableView.
- scoped_ptr<TemplateURLTableModel> table_model_;
+ scoped_ptr<KeywordEditorController> controller_;
// All the views are added as children, so that we don't need to delete
// them directly.
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 0a0c614..3329313 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -1357,6 +1357,8 @@
'browser/sandbox_policy.h',
'browser/search_engines/edit_search_engine_controller.cc',
'browser/search_engines/edit_search_engine_controller.h',
+ 'browser/search_engines/keyword_editor_controller.cc',
+ 'browser/search_engines/keyword_editor_controller.h',
'browser/search_engines/template_url.cc',
'browser/search_engines/template_url.h',
'browser/search_engines/template_url_fetcher.cc',
@@ -1367,6 +1369,8 @@
'browser/search_engines/template_url_parser.h',
'browser/search_engines/template_url_prepopulate_data.cc',
'browser/search_engines/template_url_prepopulate_data.h',
+ 'browser/search_engines/template_url_table_model.cc',
+ 'browser/search_engines/template_url_table_model.h',
'browser/session_startup_pref.cc',
'browser/session_startup_pref.h',
'browser/sessions/base_session_service.cc',
@@ -3502,6 +3506,7 @@
'browser/safe_browsing/safe_browsing_blocking_page_unittest.cc',
'browser/safe_browsing/safe_browsing_database_unittest.cc',
'browser/safe_browsing/safe_browsing_util_unittest.cc',
+ 'browser/search_engines/keyword_editor_controller_unittest.cc',
'browser/search_engines/template_url_model_unittest.cc',
'browser/search_engines/template_url_parser_unittest.cc',
'browser/search_engines/template_url_prepopulate_data_unittest.cc',
@@ -3526,7 +3531,6 @@
'browser/utility_process_host_unittest.cc',
'browser/views/bookmark_context_menu_test.cc',
'browser/views/bookmark_editor_view_unittest.cc',
- 'browser/views/keyword_editor_view_unittest.cc',
'browser/visitedlink_unittest.cc',
'browser/webdata/web_database_unittest.cc',
'browser/window_sizer_unittest.cc',