15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/search_engines/template_url_table_model.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/rtl.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/task/cancelable_task_tracker.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/favicon/favicon_service.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/favicon/favicon_service_factory.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/search_engines/template_url.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/search_engines/template_url_service.h"
180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "components/favicon_base/favicon_types.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/ui_resources.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/models/table_model_observer.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/favicon_size.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image_skia.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Group IDs used by TemplateURLTableModel.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMainGroupID = 0;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kOtherGroupID = 1;
31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)static const int kExtensionGroupID = 2;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ModelEntry ----------------------------------------------------
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ModelEntry wraps a TemplateURL as returned from the TemplateURL.
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ModelEntry also tracks state information about the URL.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Icon used while loading, or if a specific favicon can't be found.
39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)static const gfx::ImageSkia* default_icon = NULL;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ModelEntry {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ModelEntry(TemplateURLTableModel* model, TemplateURL* template_url)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : template_url_(template_url),
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        load_state_(NOT_LOADED),
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        model_(model) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!default_icon) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default_icon = ResourceBundle::GetSharedInstance().
49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          GetNativeImageNamed(IDR_DEFAULT_FAVICON).ToImageSkia();
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TemplateURL* template_url() {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return template_url_;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::ImageSkia GetIcon() {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (load_state_ == NOT_LOADED)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LoadFavicon();
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!favicon_.isNull())
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return favicon_;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return *default_icon;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Resets internal status so that the next time the icon is asked for its
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // fetched again. This should be invoked if the url is modified.
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ResetIcon() {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    load_state_ = NOT_LOADED;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    favicon_ = gfx::ImageSkia();
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // State of the favicon.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum LoadState {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOT_LOADED,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOADING,
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOADED
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void LoadFavicon() {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    load_state_ = LOADED;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FaviconService* favicon_service = FaviconServiceFactory::GetForProfile(
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        model_->template_url_service()->profile(), Profile::EXPLICIT_ACCESS);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!favicon_service)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GURL favicon_url = template_url()->favicon_url();
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!favicon_url.is_valid()) {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The favicon url isn't always set. Guess at one here.
89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (template_url_->url_ref().IsValid(
90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)              model_->template_url_service()->search_terms_data())) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GURL url(template_url_->url());
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (url.is_valid())
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicon_url = TemplateURL::GenerateFaviconURL(url);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!favicon_url.is_valid())
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    load_state_ = LOADING;
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_service->GetFaviconImage(
1000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        favicon_url,
1010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        favicon_base::FAVICON,
1020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        gfx::kFaviconSize,
1030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        base::Bind(&ModelEntry::OnFaviconDataAvailable, base::Unretained(this)),
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        &tracker_);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  void OnFaviconDataAvailable(
1080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      const favicon_base::FaviconImageResult& image_result) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    load_state_ = LOADED;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!image_result.image.IsEmpty()) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_ = image_result.image.AsImageSkia();
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      model_->FaviconAvailable(this);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TemplateURL* template_url_;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::ImageSkia favicon_;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadState load_state_;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TemplateURLTableModel* model_;
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::CancelableTaskTracker tracker_;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ModelEntry);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TemplateURLTableModel -----------------------------------------
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TemplateURLTableModel::TemplateURLTableModel(
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TemplateURLService* template_url_service)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : observer_(NULL),
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      template_url_service_(template_url_service) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(template_url_service);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->Load();
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->AddObserver(this);
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Reload();
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TemplateURLTableModel::~TemplateURLTableModel() {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->RemoveObserver(this);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&entries_);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entries_.clear();
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TemplateURLTableModel::Reload() {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&entries_);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entries_.clear();
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TemplateURLService::TemplateURLVector urls =
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      template_url_service_->GetTemplateURLs();
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::vector<ModelEntry*> default_entries, other_entries, extension_entries;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Keywords that can be made the default first.
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (TemplateURLService::TemplateURLVector::iterator i = urls.begin();
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != urls.end(); ++i) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TemplateURL* template_url = *i;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // NOTE: we don't use ShowInDefaultList here to avoid items bouncing around
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the lists while editing.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (template_url->show_in_default_list())
158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      default_entries.push_back(new ModelEntry(this, template_url));
1591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    else if (template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION)
160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      extension_entries.push_back(new ModelEntry(this, template_url));
161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    else
162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      other_entries.push_back(new ModelEntry(this, template_url));
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  last_search_engine_index_ = static_cast<int>(default_entries.size());
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  last_other_engine_index_ = last_search_engine_index_ +
167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      static_cast<int>(other_entries.size());
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  entries_.insert(entries_.end(),
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  default_entries.begin(),
171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  default_entries.end());
172868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  entries_.insert(entries_.end(),
174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  other_entries.begin(),
175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  other_entries.end());
176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  entries_.insert(entries_.end(),
178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  extension_entries.begin(),
179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  extension_entries.end());
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (observer_)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observer_->OnModelChanged();
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TemplateURLTableModel::RowCount() {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<int>(entries_.size());
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 TemplateURLTableModel::GetText(int row, int col_id) {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(row >= 0 && row < RowCount());
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const TemplateURL* url = entries_[row]->template_url();
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (col_id == IDS_SEARCH_ENGINES_EDITOR_DESCRIPTION_COLUMN) {
193a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::string16 url_short_name = url->short_name();
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(xji): Consider adding a special case if the short name is a URL,
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // since those should always be displayed LTR. Please refer to
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // http://crbug.com/6726 for more information.
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::i18n::AdjustStringForLocaleDirection(&url_short_name);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return (template_url_service_->GetDefaultSearchProvider() == url) ?
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        l10n_util::GetStringFUTF16(IDS_SEARCH_ENGINES_EDITOR_DEFAULT_ENGINE,
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   url_short_name) : url_short_name;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(IDS_SEARCH_ENGINES_EDITOR_KEYWORD_COLUMN, col_id);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Keyword should be domain name. Force it to have LTR directionality.
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::i18n::GetDisplayStringInLTRDirectionality(url->keyword());
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::ImageSkia TemplateURLTableModel::GetIcon(int row) {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(row >= 0 && row < RowCount());
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return entries_[row]->GetIcon();
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TemplateURLTableModel::SetObserver(ui::TableModelObserver* observer) {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observer_ = observer;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TemplateURLTableModel::HasGroups() {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TemplateURLTableModel::Groups TemplateURLTableModel::GetGroups() {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Groups groups;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Group search_engine_group;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  search_engine_group.title =
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_MAIN_SEPARATOR);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  search_engine_group.id = kMainGroupID;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  groups.push_back(search_engine_group);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Group other_group;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  other_group.title =
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_OTHER_SEPARATOR);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  other_group.id = kOtherGroupID;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  groups.push_back(other_group);
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
236868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Group extension_group;
237868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  extension_group.title =
238868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_EXTENSIONS_SEPARATOR);
239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  extension_group.id = kExtensionGroupID;
240868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  groups.push_back(extension_group);
241868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return groups;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TemplateURLTableModel::GetGroupID(int row) {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(row >= 0 && row < RowCount());
247868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (row < last_search_engine_index_)
248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return kMainGroupID;
249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return row < last_other_engine_index_ ? kOtherGroupID : kExtensionGroupID;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TemplateURLTableModel::Remove(int index) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove the observer while we modify the model, that way we don't need to
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // worry about the model calling us back when we mutate it.
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->RemoveObserver(this);
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TemplateURL* template_url = GetTemplateURL(index);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  scoped_ptr<ModelEntry> entry(RemoveEntry(index));
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure to remove from the table model first, otherwise the
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TemplateURL would be freed.
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->Remove(template_url);
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->AddObserver(this);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TemplateURLTableModel::Add(int index,
267a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                const base::string16& short_name,
268a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                const base::string16& keyword,
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const std::string& url) {
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(index >= 0 && index <= RowCount());
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!url.empty());
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->RemoveObserver(this);
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TemplateURLData data;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data.short_name = short_name;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data.SetKeyword(keyword);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data.SetURL(url);
277f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  TemplateURL* turl = new TemplateURL(data);
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->Add(turl);
27958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  scoped_ptr<ModelEntry> entry(new ModelEntry(this, turl));
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->AddObserver(this);
28158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  AddEntry(index, entry.Pass());
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TemplateURLTableModel::ModifyTemplateURL(int index,
285a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                              const base::string16& title,
286a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                              const base::string16& keyword,
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              const std::string& url) {
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(index >= 0 && index <= RowCount());
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!url.empty());
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TemplateURL* template_url = GetTemplateURL(index);
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The default search provider should support replacement.
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(template_url_service_->GetDefaultSearchProvider() != template_url ||
293f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)         template_url->SupportsReplacement(
294f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)             template_url_service_->search_terms_data()));
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->RemoveObserver(this);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->ResetTemplateURL(template_url, title, keyword, url);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->AddObserver(this);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReloadIcon(index);  // Also calls NotifyChanged().
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TemplateURLTableModel::ReloadIcon(int index) {
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(index >= 0 && index < RowCount());
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entries_[index]->ResetIcon();
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyChanged(index);
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TemplateURL* TemplateURLTableModel::GetTemplateURL(int index) {
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return entries_[index]->template_url();
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TemplateURLTableModel::IndexOfTemplateURL(
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const TemplateURL* template_url) {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<ModelEntry*>::iterator i = entries_.begin();
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != entries_.end(); ++i) {
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ModelEntry* entry = *i;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (entry->template_url() == template_url)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return static_cast<int>(i - entries_.begin());
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return -1;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TemplateURLTableModel::MoveToMainGroup(int index) {
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (index < last_search_engine_index_)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return index;  // Already in the main group.
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  scoped_ptr<ModelEntry> current_entry(RemoveEntry(index));
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int new_index = last_search_engine_index_++;
33058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  AddEntry(new_index, current_entry.Pass());
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new_index;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TemplateURLTableModel::MakeDefaultTemplateURL(int index) {
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (index < 0 || index >= RowCount()) {
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TemplateURL* keyword = GetTemplateURL(index);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const TemplateURL* current_default =
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      template_url_service_->GetDefaultSearchProvider();
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (current_default == keyword)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->RemoveObserver(this);
3475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  template_url_service_->SetUserSelectedDefaultSearchProvider(keyword);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->AddObserver(this);
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The formatting of the default engine is different; notify the table that
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // both old and new entries have changed.
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (current_default != NULL) {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int old_index = IndexOfTemplateURL(current_default);
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // current_default may not be in the list of TemplateURLs if the database is
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // corrupt and the default TemplateURL is used from preferences
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (old_index >= 0)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NotifyChanged(old_index);
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int new_index = IndexOfTemplateURL(keyword);
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyChanged(new_index);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure the new default is in the main group.
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return MoveToMainGroup(index);
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TemplateURLTableModel::NotifyChanged(int index) {
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (observer_) {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_GE(index, 0);
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observer_->OnItemsChanged(index, 1);
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TemplateURLTableModel::FaviconAvailable(ModelEntry* entry) {
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<ModelEntry*>::iterator i =
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::find(entries_.begin(), entries_.end(), entry);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(i != entries_.end());
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyChanged(static_cast<int>(i - entries_.begin()));
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TemplateURLTableModel::OnTemplateURLServiceChanged() {
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Reload();
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
38358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
38458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochscoped_ptr<ModelEntry> TemplateURLTableModel::RemoveEntry(int index) {
38558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  scoped_ptr<ModelEntry> entry(entries_[index]);
38658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  entries_.erase(index + entries_.begin());
38758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  if (index < last_search_engine_index_)
38858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    --last_search_engine_index_;
38958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  if (index < last_other_engine_index_)
39058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    --last_other_engine_index_;
39158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  if (observer_)
39258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    observer_->OnItemsRemoved(index, 1);
39358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  return entry.Pass();
39458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch}
39558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
39658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochvoid TemplateURLTableModel::AddEntry(int index, scoped_ptr<ModelEntry> entry) {
39758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  entries_.insert(entries_.begin() + index, entry.release());
39858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  if (index <= last_other_engine_index_)
39958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    ++last_other_engine_index_;
40058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  if (observer_)
40158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    observer_->OnItemsAdded(index, 1);
40258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch}
403