Home | History | Annotate | Download | only in options
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/webui/options/search_engine_manager_handler.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/strings/string_number_conversions.h"
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "base/values.h"
     11 #include "chrome/browser/extensions/extension_service.h"
     12 #include "chrome/browser/profiles/profile.h"
     13 #include "chrome/browser/search_engines/template_url.h"
     14 #include "chrome/browser/search_engines/template_url_service.h"
     15 #include "chrome/browser/ui/search_engines/keyword_editor_controller.h"
     16 #include "chrome/browser/ui/search_engines/template_url_table_model.h"
     17 #include "chrome/common/extensions/api/omnibox/omnibox_handler.h"
     18 #include "chrome/common/extensions/extension.h"
     19 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
     20 #include "chrome/common/url_constants.h"
     21 #include "content/public/browser/web_ui.h"
     22 #include "grit/generated_resources.h"
     23 #include "grit/locale_settings.h"
     24 #include "ui/base/l10n/l10n_util.h"
     25 
     26 namespace {
     27 
     28 enum EngineInfoIndexes {
     29   ENGINE_NAME,
     30   ENGINE_KEYWORD,
     31   ENGINE_URL,
     32 };
     33 
     34 };  // namespace
     35 
     36 namespace options {
     37 
     38 SearchEngineManagerHandler::SearchEngineManagerHandler() {
     39 }
     40 
     41 SearchEngineManagerHandler::~SearchEngineManagerHandler() {
     42   if (list_controller_.get() && list_controller_->table_model())
     43     list_controller_->table_model()->SetObserver(NULL);
     44 }
     45 
     46 void SearchEngineManagerHandler::InitializeHandler() {
     47   list_controller_.reset(
     48       new KeywordEditorController(Profile::FromWebUI(web_ui())));
     49   DCHECK(list_controller_.get());
     50   list_controller_->table_model()->SetObserver(this);
     51 }
     52 
     53 void SearchEngineManagerHandler::InitializePage() {
     54   OnModelChanged();
     55 }
     56 
     57 void SearchEngineManagerHandler::GetLocalizedValues(
     58     base::DictionaryValue* localized_strings) {
     59   DCHECK(localized_strings);
     60 
     61   RegisterTitle(localized_strings, "searchEngineManagerPage",
     62                 IDS_SEARCH_ENGINES_EDITOR_WINDOW_TITLE);
     63   localized_strings->SetString("defaultSearchEngineListTitle",
     64       l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_MAIN_SEPARATOR));
     65   localized_strings->SetString("otherSearchEngineListTitle",
     66       l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_OTHER_SEPARATOR));
     67   localized_strings->SetString("extensionKeywordsListTitle",
     68       l10n_util::GetStringUTF16(
     69           IDS_SEARCH_ENGINES_EDITOR_EXTENSIONS_SEPARATOR));
     70   localized_strings->SetString("makeDefaultSearchEngineButton",
     71       l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_MAKE_DEFAULT_BUTTON));
     72   localized_strings->SetString("searchEngineTableNamePlaceholder",
     73       l10n_util::GetStringUTF16(IDS_SEARCH_ENGINE_ADD_NEW_NAME_PLACEHOLDER));
     74   localized_strings->SetString("searchEngineTableKeywordPlaceholder",
     75       l10n_util::GetStringUTF16(IDS_SEARCH_ENGINE_ADD_NEW_KEYWORD_PLACEHOLDER));
     76   localized_strings->SetString("searchEngineTableURLPlaceholder",
     77       l10n_util::GetStringUTF16(IDS_SEARCH_ENGINE_ADD_NEW_URL_PLACEHOLDER));
     78   localized_strings->SetString("editSearchEngineInvalidTitleToolTip",
     79       l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_INVALID_TITLE_TT));
     80   localized_strings->SetString("editSearchEngineInvalidKeywordToolTip",
     81       l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_INVALID_KEYWORD_TT));
     82   localized_strings->SetString("editSearchEngineInvalidURLToolTip",
     83       l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_INVALID_URL_TT));
     84 }
     85 
     86 void SearchEngineManagerHandler::RegisterMessages() {
     87   web_ui()->RegisterMessageCallback(
     88       "managerSetDefaultSearchEngine",
     89       base::Bind(&SearchEngineManagerHandler::SetDefaultSearchEngine,
     90                  base::Unretained(this)));
     91   web_ui()->RegisterMessageCallback(
     92       "removeSearchEngine",
     93       base::Bind(&SearchEngineManagerHandler::RemoveSearchEngine,
     94                  base::Unretained(this)));
     95   web_ui()->RegisterMessageCallback(
     96       "editSearchEngine",
     97       base::Bind(&SearchEngineManagerHandler::EditSearchEngine,
     98                  base::Unretained(this)));
     99   web_ui()->RegisterMessageCallback(
    100       "checkSearchEngineInfoValidity",
    101       base::Bind(&SearchEngineManagerHandler::CheckSearchEngineInfoValidity,
    102                  base::Unretained(this)));
    103   web_ui()->RegisterMessageCallback(
    104       "searchEngineEditCancelled",
    105       base::Bind(&SearchEngineManagerHandler::EditCancelled,
    106                  base::Unretained(this)));
    107   web_ui()->RegisterMessageCallback(
    108       "searchEngineEditCompleted",
    109       base::Bind(&SearchEngineManagerHandler::EditCompleted,
    110                  base::Unretained(this)));
    111 }
    112 
    113 void SearchEngineManagerHandler::OnModelChanged() {
    114   DCHECK(list_controller_.get());
    115   if (!list_controller_->loaded())
    116     return;
    117 
    118   // Find the default engine.
    119   const TemplateURL* default_engine =
    120       list_controller_->url_model()->GetDefaultSearchProvider();
    121   int default_index = list_controller_->table_model()->IndexOfTemplateURL(
    122       default_engine);
    123 
    124   // Build the first list (default search engine options).
    125   ListValue defaults_list;
    126   int last_default_engine_index =
    127       list_controller_->table_model()->last_search_engine_index();
    128   for (int i = 0; i < last_default_engine_index; ++i) {
    129     // Third argument is false, as the engine is not from an extension.
    130     defaults_list.Append(CreateDictionaryForEngine(
    131         i, i == default_index, false));
    132   }
    133 
    134   // Build the second list (other search templates).
    135   ListValue others_list;
    136   int last_other_engine_index =
    137       list_controller_->table_model()->last_other_engine_index();
    138   if (last_default_engine_index < 0)
    139     last_default_engine_index = 0;
    140   for (int i = last_default_engine_index; i < last_other_engine_index; ++i) {
    141     others_list.Append(CreateDictionaryForEngine(i, i == default_index, false));
    142   }
    143 
    144   // Build the extension keywords list.
    145   ListValue keyword_list;
    146   if (last_other_engine_index < 0)
    147     last_other_engine_index = 0;
    148   int engine_count = list_controller_->table_model()->RowCount();
    149   for (int i = last_other_engine_index; i < engine_count; ++i) {
    150     keyword_list.Append(CreateDictionaryForEngine(i, i == default_index, true));
    151   }
    152 
    153   web_ui()->CallJavascriptFunction("SearchEngineManager.updateSearchEngineList",
    154                                    defaults_list, others_list, keyword_list);
    155 }
    156 
    157 void SearchEngineManagerHandler::OnItemsChanged(int start, int length) {
    158   OnModelChanged();
    159 }
    160 
    161 void SearchEngineManagerHandler::OnItemsAdded(int start, int length) {
    162   OnModelChanged();
    163 }
    164 
    165 void SearchEngineManagerHandler::OnItemsRemoved(int start, int length) {
    166   OnModelChanged();
    167 }
    168 
    169 base::DictionaryValue* SearchEngineManagerHandler::CreateDictionaryForEngine(
    170     int index, bool is_default, bool is_extension) {
    171   TemplateURLTableModel* table_model = list_controller_->table_model();
    172   const TemplateURL* template_url = list_controller_->GetTemplateURL(index);
    173 
    174   base::DictionaryValue* dict = new base::DictionaryValue();
    175   dict->SetString("name",  template_url->short_name());
    176   dict->SetString("displayName", table_model->GetText(
    177     index, IDS_SEARCH_ENGINES_EDITOR_DESCRIPTION_COLUMN));
    178   dict->SetString("keyword", table_model->GetText(
    179     index, IDS_SEARCH_ENGINES_EDITOR_KEYWORD_COLUMN));
    180   dict->SetString("url", template_url->url_ref().DisplayURL());
    181   dict->SetBoolean("urlLocked", template_url->prepopulate_id() > 0);
    182   GURL icon_url = template_url->favicon_url();
    183   if (icon_url.is_valid())
    184     dict->SetString("iconURL", icon_url.spec());
    185   dict->SetString("modelIndex", base::IntToString(index));
    186 
    187   dict->SetBoolean("canBeRemoved",
    188       list_controller_->CanRemove(template_url) && !is_extension);
    189   dict->SetBoolean("canBeDefault",
    190       list_controller_->CanMakeDefault(template_url) && !is_extension);
    191   dict->SetBoolean("default", is_default);
    192   dict->SetBoolean("canBeEdited", list_controller_->CanEdit(template_url));
    193   dict->SetBoolean("isExtension", is_extension);
    194 
    195   return dict;
    196 }
    197 
    198 void SearchEngineManagerHandler::SetDefaultSearchEngine(const ListValue* args) {
    199   int index;
    200   if (!ExtractIntegerValue(args, &index)) {
    201     NOTREACHED();
    202     return;
    203   }
    204   if (index < 0 || index >= list_controller_->table_model()->RowCount())
    205     return;
    206 
    207   list_controller_->MakeDefaultTemplateURL(index);
    208 }
    209 
    210 void SearchEngineManagerHandler::RemoveSearchEngine(const ListValue* args) {
    211   int index;
    212   if (!ExtractIntegerValue(args, &index)) {
    213     NOTREACHED();
    214     return;
    215   }
    216   if (index < 0 || index >= list_controller_->table_model()->RowCount())
    217     return;
    218 
    219   if (list_controller_->CanRemove(list_controller_->GetTemplateURL(index)))
    220     list_controller_->RemoveTemplateURL(index);
    221 }
    222 
    223 void SearchEngineManagerHandler::EditSearchEngine(const ListValue* args) {
    224   int index;
    225   if (!ExtractIntegerValue(args, &index)) {
    226     NOTREACHED();
    227     return;
    228   }
    229 
    230   // Allow -1, which means we are adding a new engine.
    231   if (index < -1 || index >= list_controller_->table_model()->RowCount())
    232     return;
    233 
    234   edit_controller_.reset(new EditSearchEngineController(
    235       (index == -1) ? NULL : list_controller_->GetTemplateURL(index), this,
    236       Profile::FromWebUI(web_ui())));
    237 }
    238 
    239 void SearchEngineManagerHandler::OnEditedKeyword(
    240     TemplateURL* template_url,
    241     const string16& title,
    242     const string16& keyword,
    243     const std::string& url) {
    244   DCHECK(!url.empty());
    245   if (template_url)
    246     list_controller_->ModifyTemplateURL(template_url, title, keyword, url);
    247   else
    248     list_controller_->AddTemplateURL(title, keyword, url);
    249   edit_controller_.reset();
    250 }
    251 
    252 void SearchEngineManagerHandler::CheckSearchEngineInfoValidity(
    253     const ListValue* args)
    254 {
    255   if (!edit_controller_.get())
    256     return;
    257   string16 name;
    258   string16 keyword;
    259   std::string url;
    260   std::string modelIndex;
    261   if (!args->GetString(ENGINE_NAME, &name) ||
    262       !args->GetString(ENGINE_KEYWORD, &keyword) ||
    263       !args->GetString(ENGINE_URL, &url) ||
    264       !args->GetString(3, &modelIndex)) {
    265     NOTREACHED();
    266     return;
    267   }
    268 
    269   base::DictionaryValue validity;
    270   validity.SetBoolean("name", edit_controller_->IsTitleValid(name));
    271   validity.SetBoolean("keyword", edit_controller_->IsKeywordValid(keyword));
    272   validity.SetBoolean("url", edit_controller_->IsURLValid(url));
    273   StringValue indexValue(modelIndex);
    274   web_ui()->CallJavascriptFunction("SearchEngineManager.validityCheckCallback",
    275                                    validity, indexValue);
    276 }
    277 
    278 void SearchEngineManagerHandler::EditCancelled(const ListValue* args) {
    279   if (!edit_controller_.get())
    280     return;
    281   edit_controller_->CleanUpCancelledAdd();
    282   edit_controller_.reset();
    283 }
    284 
    285 void SearchEngineManagerHandler::EditCompleted(const ListValue* args) {
    286   if (!edit_controller_.get())
    287     return;
    288   string16 name;
    289   string16 keyword;
    290   std::string url;
    291   if (!args->GetString(ENGINE_NAME, &name) ||
    292       !args->GetString(ENGINE_KEYWORD, &keyword) ||
    293       !args->GetString(ENGINE_URL, &url)) {
    294     NOTREACHED();
    295     return;
    296   }
    297 
    298   // Recheck validity.  It's possible to get here with invalid input if e.g. the
    299   // user calls the right JS functions directly from the web inspector.
    300   if (edit_controller_->IsTitleValid(name) &&
    301       edit_controller_->IsKeywordValid(keyword) &&
    302       edit_controller_->IsURLValid(url))
    303     edit_controller_->AcceptAddOrEdit(name, keyword, url);
    304 }
    305 
    306 }  // namespace options
    307