diff options
author | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-26 21:25:18 +0000 |
---|---|---|
committer | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-26 21:25:18 +0000 |
commit | ff8389293372e9b7b2db0799f5f9a512af694cf8 (patch) | |
tree | 59b6b2b58084952fecf7a95e216f33d8617ef49a /chrome | |
parent | 85233a9f663380dbefc405bb068f8544fdcec38c (diff) | |
download | chromium_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.cc | 98 | ||||
-rw-r--r-- | chrome/browser/search_engines/keyword_editor_controller.h | 72 | ||||
-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.cc | 371 | ||||
-rw-r--r-- | chrome/browser/search_engines/template_url_table_model.h | 110 | ||||
-rw-r--r-- | chrome/browser/views/keyword_editor_view.cc | 456 | ||||
-rw-r--r-- | chrome/browser/views/keyword_editor_view.h | 117 | ||||
-rw-r--r-- | chrome/chrome.gyp | 6 |
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', |