summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorpinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-09 16:22:48 +0000
committerpinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-09 16:22:48 +0000
commitacd70444b3eba65ce7d867aa61bcdb3b63dd9369 (patch)
tree9e23bb455c45c0b8bb79cc08b01c046a99dc7c94 /chrome/browser
parent2af577d4f70b5392f63c4bed35f890ace92a4e0a (diff)
downloadchromium_src-acd70444b3eba65ce7d867aa61bcdb3b63dd9369.zip
chromium_src-acd70444b3eba65ce7d867aa61bcdb3b63dd9369.tar.gz
chromium_src-acd70444b3eba65ce7d867aa61bcdb3b63dd9369.tar.bz2
Implement default search popup.
BUG=13151 TEST=default search popup persistance. Review URL: http://codereview.chromium.org/119310 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17947 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/cocoa/preferences_window_controller.h2
-rw-r--r--chrome/browser/cocoa/preferences_window_controller.mm35
-rw-r--r--chrome/browser/cocoa/search_engine_list_model.h45
-rw-r--r--chrome/browser/cocoa/search_engine_list_model.mm112
-rw-r--r--chrome/browser/cocoa/search_engine_list_model_unittest.mm95
5 files changed, 289 insertions, 0 deletions
diff --git a/chrome/browser/cocoa/preferences_window_controller.h b/chrome/browser/cocoa/preferences_window_controller.h
index e7f7734..a39531c 100644
--- a/chrome/browser/cocoa/preferences_window_controller.h
+++ b/chrome/browser/cocoa/preferences_window_controller.h
@@ -12,6 +12,7 @@
class PrefObserverBridge;
class PrefService;
class Profile;
+@class SearchEngineListModel;
// A window controller that handles the preferences window. The bulk of the
// work is handled via Cocoa Bindings and getter/setter methods that wrap
@@ -40,6 +41,7 @@ class Profile;
StringPrefMember homepage_;
BooleanPrefMember showHomeButton_;
BooleanPrefMember showPageOptionButtons_;
+ scoped_nsobject<SearchEngineListModel> searchEngineModel_;
// Used when creating a new home page url to make the new cell editable.
BOOL pendingSelectForEdit_;
diff --git a/chrome/browser/cocoa/preferences_window_controller.mm b/chrome/browser/cocoa/preferences_window_controller.mm
index cd800cb..5df094c 100644
--- a/chrome/browser/cocoa/preferences_window_controller.mm
+++ b/chrome/browser/cocoa/preferences_window_controller.mm
@@ -12,6 +12,7 @@
#include "chrome/browser/browser_list.h"
#import "chrome/browser/cocoa/clear_browsing_data_controller.h"
#import "chrome/browser/cocoa/custom_home_pages_model.h"
+#import "chrome/browser/cocoa/search_engine_list_model.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/profile.h"
@@ -110,6 +111,17 @@ class PrefObserverBridge : public NotificationObserver {
name:kHomepageEntryChangedNotification
object:nil];
+ // Set up the model for the default search popup. Register for notifications
+ // about when the model changes so we can update the selection in the view.
+ searchEngineModel_.reset(
+ [[SearchEngineListModel alloc]
+ initWithModel:profile->GetTemplateURLModel()]);
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(searchEngineModelChanged:)
+ name:kSearchEngineListModelChangedNotification
+ object:searchEngineModel_.get()];
+
// This needs to be done before awakeFromNib: because the bindings set up
// in the nib rely on it.
[self registerPrefObservers];
@@ -471,6 +483,29 @@ enum { kHomepageNewTabPage, kHomepageURL };
showPageOptionButtons_.SetValue(value ? true : false);
}
+// Getter for the |searchEngineModel| property for bindings.
+- (id)searchEngineModel {
+ return searchEngineModel_.get();
+}
+
+// Bindings for the search engine popup. We not binding directly to the model
+// in order to siphon off the setter so we can record the metric. If we're
+// doing it with one, might as well do it with both.
+- (NSUInteger)searchEngineSelectedIndex {
+ return [searchEngineModel_ defaultIndex];
+}
+
+- (void)setSearchEngineSelectedIndex:(NSUInteger)index {
+ [self recordUserAction:L"Options_SearchEngineChanged"];
+ [searchEngineModel_ setDefaultIndex:index];
+}
+
+// Called when the search engine model changes. Update the selection in the
+// popup by tickling the bindings with the new value.
+- (void)searchEngineModelChanged:(NSNotification*)notify {
+ [self setSearchEngineSelectedIndex:[self searchEngineSelectedIndex]];
+}
+
// Called when the user clicks the button to make Chromium the default
// browser. Registers http and https.
- (IBAction)makeDefaultBrowser:(id)sender {
diff --git a/chrome/browser/cocoa/search_engine_list_model.h b/chrome/browser/cocoa/search_engine_list_model.h
new file mode 100644
index 0000000..3d1fd58
--- /dev/null
+++ b/chrome/browser/cocoa/search_engine_list_model.h
@@ -0,0 +1,45 @@
+// 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_COCOA_SEARCH_ENGINE_LIST_MODEL_H_
+#define CHROME_BROWSER_COCOA_SEARCH_ENGINE_LIST_MODEL_H_
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+
+class TemplateURLModel;
+class SearchEngineObserver;
+
+// The model for the "default search engine" combobox in preferences. Bridges
+// between the cross-platform TemplateURLModel and Cocoa while watching for
+// changes to the cross-platform model.
+
+@interface SearchEngineListModel : NSObject {
+ @private
+ TemplateURLModel* model_; // weak, owned by Profile
+ scoped_ptr<SearchEngineObserver> observer_; // watches for model changes
+ scoped_nsobject<NSArray> engines_;
+}
+
+// Initialize with the given template model.
+- (id)initWithModel:(TemplateURLModel*)model;
+
+// Returns an array of NSString's corresponding to the user-visible names of the
+// search engines.
+- (NSArray*)searchEngines;
+
+// The index into |-searchEngines| of the current default search engine. The
+// setter changes the back-end preference.
+- (NSUInteger)defaultIndex;
+- (void)setDefaultIndex:(NSUInteger)index;
+
+@end
+
+// Broadcast when the cross-platform model changes. This can be used to update
+// any view state that may rely on the position of items in the list.
+extern NSString* const kSearchEngineListModelChangedNotification;
+
+#endif // CHROME_BROWSER_COCOA_SEARCH_ENGINE_LIST_MODEL_H_
diff --git a/chrome/browser/cocoa/search_engine_list_model.mm b/chrome/browser/cocoa/search_engine_list_model.mm
new file mode 100644
index 0000000..1900231
--- /dev/null
+++ b/chrome/browser/cocoa/search_engine_list_model.mm
@@ -0,0 +1,112 @@
+// 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.
+
+#import "chrome/browser/cocoa/search_engine_list_model.h"
+
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_model.h"
+
+NSString* const kSearchEngineListModelChangedNotification =
+ @"kSearchEngineListModelChangedNotification";
+
+@interface SearchEngineListModel(Private)
+- (void)buildEngineList;
+@end
+
+// C++ bridge from TemplateURLModel to our Obj-C model. When it's told about
+// model changes, notifies us to rebuild the list.
+class SearchEngineObserver : public TemplateURLModelObserver {
+ public:
+ SearchEngineObserver(SearchEngineListModel* notify)
+ : notify_(notify) { }
+ virtual ~SearchEngineObserver() { };
+
+ private:
+ // TemplateURLModelObserver methods.
+ virtual void OnTemplateURLModelChanged() { [notify_ buildEngineList]; }
+
+ SearchEngineListModel* notify_; // weak, owns us
+};
+
+@implementation SearchEngineListModel
+
+// The windows code allows for a NULL |model| and checks for it throughout
+// the code, though I'm not sure why. We follow suit.
+- (id)initWithModel:(TemplateURLModel*)model {
+ if ((self = [super init])) {
+ model_ = model;
+ if (model_) {
+ observer_.reset(new SearchEngineObserver(self));
+ model_->Load();
+ model_->AddObserver(observer_.get());
+ [self buildEngineList];
+ }
+ }
+ return self;
+}
+
+- (void)dealloc {
+ if (model_)
+ model_->RemoveObserver(observer_.get());
+ [super dealloc];
+}
+
+// Returns an array of NSString's corresponding to the user-visible names of the
+// search engines.
+- (NSArray*)searchEngines {
+ return engines_.get();
+}
+
+- (void)setSearchEngines:(NSArray*)engines {
+ engines_.reset([engines retain]);
+
+ // Tell anyone who's listening that something has changed so they need to
+ // adjust the UI.
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:kSearchEngineListModelChangedNotification
+ object:nil];
+}
+
+// Walks the model and builds an array of NSStrings to display to the user.
+// Assumes there is a non-NULL model.
+- (void)buildEngineList {
+ scoped_nsobject<NSMutableArray> engines([[NSMutableArray alloc] init]);
+
+ typedef std::vector<const TemplateURL*> TemplateURLs;
+ TemplateURLs modelURLs = model_->GetTemplateURLs();
+ for (size_t i = 0; i < modelURLs.size(); ++i) {
+ if (modelURLs[i]->ShowInDefaultList())
+ [engines addObject:base::SysWideToNSString(modelURLs[i]->short_name())];
+ }
+
+ [self setSearchEngines:engines.get()];
+}
+
+// The index into |-searchEngines| of the current default search engine.
+- (NSUInteger)defaultIndex {
+ if (!model_) return 0;
+
+ const TemplateURL* defaultSearchProvider = model_->GetDefaultSearchProvider();
+ if (defaultSearchProvider) {
+ typedef std::vector<const TemplateURL*> TemplateURLs;
+ TemplateURLs urls = model_->GetTemplateURLs();
+ TemplateURLs::iterator i =
+ find(urls.begin(), urls.end(), defaultSearchProvider);
+ if (i != urls.end())
+ return static_cast<int>(i - urls.begin());
+ }
+ return 0;
+}
+
+- (void)setDefaultIndex:(NSUInteger)index {
+ if (model_) {
+ typedef std::vector<const TemplateURL*> TemplateURLs;
+ TemplateURLs urls = model_->GetTemplateURLs();
+ DCHECK(index < urls.size());
+ model_->SetDefaultSearchProvider(urls[index]);
+ }
+}
+
+@end
diff --git a/chrome/browser/cocoa/search_engine_list_model_unittest.mm b/chrome/browser/cocoa/search_engine_list_model_unittest.mm
new file mode 100644
index 0000000..9e592e7
--- /dev/null
+++ b/chrome/browser/cocoa/search_engine_list_model_unittest.mm
@@ -0,0 +1,95 @@
+// 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 "base/scoped_nsobject.h"
+#include "chrome/browser/cocoa/browser_test_helper.h"
+#import "chrome/browser/cocoa/search_engine_list_model.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_model.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// A helper for NSNotifications. Makes a note that it's been called back.
+@interface SearchEngineListHelper : NSObject {
+ @public
+ BOOL sawNotification_;
+}
+@end
+
+@implementation SearchEngineListHelper
+- (void)entryChanged:(NSNotification*)notify {
+ sawNotification_ = YES;
+}
+@end
+
+class SearchEngineListModelTest : public testing::Test {
+ public:
+ SearchEngineListModelTest() {
+ // Build a fake set of template urls.
+ template_model_.reset(new TemplateURLModel(helper_.profile()));
+ TemplateURL* t_url = new TemplateURL();
+ t_url->SetURL(L"http://www.google.com/foo/bar", 0, 0);
+ t_url->set_keyword(L"keyword");
+ t_url->set_short_name(L"google");
+ t_url->set_show_in_default_list(true);
+ template_model_->Add(t_url);
+ t_url = new TemplateURL();
+ t_url->SetURL(L"http://www.google2.com/foo/bar", 0, 0);
+ t_url->set_keyword(L"keyword2");
+ t_url->set_short_name(L"google2");
+ t_url->set_show_in_default_list(true);
+ template_model_->Add(t_url);
+ EXPECT_EQ(template_model_->GetTemplateURLs().size(), 2U);
+
+ model_.reset([[SearchEngineListModel alloc]
+ initWithModel:template_model_.get()]);
+ notification_helper_.reset([[SearchEngineListHelper alloc] init]);
+ [[NSNotificationCenter defaultCenter]
+ addObserver:notification_helper_.get()
+ selector:@selector(entryChanged:)
+ name:kSearchEngineListModelChangedNotification
+ object:nil];
+ }
+ ~SearchEngineListModelTest() {
+ [[NSNotificationCenter defaultCenter]
+ removeObserver:notification_helper_.get()];
+ }
+
+ BrowserTestHelper helper_;
+ scoped_ptr<TemplateURLModel> template_model_;
+ scoped_nsobject<SearchEngineListModel> model_;
+ scoped_nsobject<SearchEngineListHelper> notification_helper_;
+};
+
+TEST_F(SearchEngineListModelTest, Init) {
+ scoped_nsobject<SearchEngineListModel> model(
+ [[SearchEngineListModel alloc] initWithModel:template_model_.get()]);
+}
+
+TEST_F(SearchEngineListModelTest, Engines) {
+ NSArray* engines = [model_ searchEngines];
+ // TODO(pinkerton): because the templates we create aren't truly parsable,
+ // they won't pass the "displayable" test and thus we don't get any results.
+ EXPECT_EQ([engines count], /* 2U */ 0U);
+}
+
+TEST_F(SearchEngineListModelTest, Default) {
+ EXPECT_EQ([model_ defaultIndex], 0U);
+
+ [model_ setDefaultIndex:1];
+ EXPECT_EQ([model_ defaultIndex], 1U);
+}
+
+// Make sure that when the back-end model changes that we get a notification.
+TEST_F(SearchEngineListModelTest, Notification) {
+ // Add one more item to force a notification.
+ TemplateURL* t_url = new TemplateURL();
+ t_url->SetURL(L"http://www.google3.com/foo/bar", 0, 0);
+ t_url->set_keyword(L"keyword3");
+ t_url->set_short_name(L"google3");
+ t_url->set_show_in_default_list(true);
+ template_model_->Add(t_url);
+
+ EXPECT_TRUE(notification_helper_.get()->sawNotification_);
+}