template_url_table_model.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/favicon/favicon_service.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/favicon/favicon_service_factory.h"
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/favicon/favicon_types.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"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/cancelable_task_tracker.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.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static 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().
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GetImageSkiaNamed(IDR_DEFAULT_FAVICON);
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.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (template_url_->url_ref().IsValid()) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GURL url(template_url_->url());
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (url.is_valid())
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          favicon_url = TemplateURL::GenerateFaviconURL(url);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!favicon_url.is_valid())
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    load_state_ = LOADING;
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    favicon_service->GetFaviconImage(
9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        favicon_url, chrome::FAVICON, gfx::kFaviconSize,
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&ModelEntry::OnFaviconDataAvailable,
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Unretained(this)),
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        &tracker_);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void OnFaviconDataAvailable(const chrome::FaviconImageResult& image_result) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    load_state_ = LOADED;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!image_result.image.IsEmpty()) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      favicon_ = image_result.image.AsImageSkia();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      model_->FaviconAvailable(this);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TemplateURL* template_url_;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::ImageSkia favicon_;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadState load_state_;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TemplateURLTableModel* model_;
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CancelableTaskTracker tracker_;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ModelEntry);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TemplateURLTableModel -----------------------------------------
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TemplateURLTableModel::TemplateURLTableModel(
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TemplateURLService* template_url_service)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : observer_(NULL),
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      template_url_service_(template_url_service) {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(template_url_service);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->Load();
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->AddObserver(this);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Reload();
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TemplateURLTableModel::~TemplateURLTableModel() {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->RemoveObserver(this);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&entries_);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entries_.clear();
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TemplateURLTableModel::Reload() {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&entries_);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entries_.clear();
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TemplateURLService::TemplateURLVector urls =
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      template_url_service_->GetTemplateURLs();
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::vector<ModelEntry*> default_entries, other_entries, extension_entries;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Keywords that can be made the default first.
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (TemplateURLService::TemplateURLVector::iterator i = urls.begin();
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != urls.end(); ++i) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TemplateURL* template_url = *i;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // NOTE: we don't use ShowInDefaultList here to avoid items bouncing around
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the lists while editing.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (template_url->show_in_default_list())
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      default_entries.push_back(new ModelEntry(this, template_url));
156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    else if (template_url->IsExtensionKeyword())
157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      extension_entries.push_back(new ModelEntry(this, template_url));
158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    else
159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      other_entries.push_back(new ModelEntry(this, template_url));
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  last_search_engine_index_ = static_cast<int>(default_entries.size());
163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  last_other_engine_index_ = last_search_engine_index_ +
164868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      static_cast<int>(other_entries.size());
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  entries_.insert(entries_.end(),
167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  default_entries.begin(),
168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  default_entries.end());
169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  entries_.insert(entries_.end(),
171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  other_entries.begin(),
172868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  other_entries.end());
173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  entries_.insert(entries_.end(),
175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  extension_entries.begin(),
176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  extension_entries.end());
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (observer_)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observer_->OnModelChanged();
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TemplateURLTableModel::RowCount() {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<int>(entries_.size());
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)string16 TemplateURLTableModel::GetText(int row, int col_id) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(row >= 0 && row < RowCount());
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const TemplateURL* url = entries_[row]->template_url();
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (col_id == IDS_SEARCH_ENGINES_EDITOR_DESCRIPTION_COLUMN) {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    string16 url_short_name = url->short_name();
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(xji): Consider adding a special case if the short name is a URL,
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // since those should always be displayed LTR. Please refer to
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // http://crbug.com/6726 for more information.
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::i18n::AdjustStringForLocaleDirection(&url_short_name);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return (template_url_service_->GetDefaultSearchProvider() == url) ?
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        l10n_util::GetStringFUTF16(IDS_SEARCH_ENGINES_EDITOR_DEFAULT_ENGINE,
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   url_short_name) : url_short_name;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(IDS_SEARCH_ENGINES_EDITOR_KEYWORD_COLUMN, col_id);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Keyword should be domain name. Force it to have LTR directionality.
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::i18n::GetDisplayStringInLTRDirectionality(url->keyword());
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::ImageSkia TemplateURLTableModel::GetIcon(int row) {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(row >= 0 && row < RowCount());
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return entries_[row]->GetIcon();
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TemplateURLTableModel::SetObserver(ui::TableModelObserver* observer) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observer_ = observer;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TemplateURLTableModel::HasGroups() {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TemplateURLTableModel::Groups TemplateURLTableModel::GetGroups() {
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Groups groups;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Group search_engine_group;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  search_engine_group.title =
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_MAIN_SEPARATOR);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  search_engine_group.id = kMainGroupID;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  groups.push_back(search_engine_group);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Group other_group;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  other_group.title =
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_OTHER_SEPARATOR);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  other_group.id = kOtherGroupID;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  groups.push_back(other_group);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
233868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Group extension_group;
234868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  extension_group.title =
235868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_EXTENSIONS_SEPARATOR);
236868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  extension_group.id = kExtensionGroupID;
237868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  groups.push_back(extension_group);
238868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return groups;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TemplateURLTableModel::GetGroupID(int row) {
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(row >= 0 && row < RowCount());
244868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (row < last_search_engine_index_)
245868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return kMainGroupID;
246868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return row < last_other_engine_index_ ? kOtherGroupID : kExtensionGroupID;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TemplateURLTableModel::Remove(int index) {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove the observer while we modify the model, that way we don't need to
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // worry about the model calling us back when we mutate it.
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->RemoveObserver(this);
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TemplateURL* template_url = GetTemplateURL(index);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ModelEntry> entry(entries_[index]);
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entries_.erase(entries_.begin() + index);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (index < last_search_engine_index_)
258868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    --last_search_engine_index_;
259868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (index < last_other_engine_index_)
260868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    --last_other_engine_index_;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (observer_)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observer_->OnItemsRemoved(index, 1);
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure to remove from the table model first, otherwise the
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TemplateURL would be freed.
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->Remove(template_url);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->AddObserver(this);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TemplateURLTableModel::Add(int index,
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const string16& short_name,
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const string16& keyword,
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const std::string& url) {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(index >= 0 && index <= RowCount());
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!url.empty());
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->RemoveObserver(this);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TemplateURLData data;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data.short_name = short_name;
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data.SetKeyword(keyword);
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data.SetURL(url);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TemplateURL* turl = new TemplateURL(template_url_service_->profile(), data);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->Add(turl);
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ModelEntry* entry = new ModelEntry(this, turl);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->AddObserver(this);
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entries_.insert(entries_.begin() + index, entry);
286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (index <= last_other_engine_index_)
287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ++last_other_engine_index_;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (observer_)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observer_->OnItemsAdded(index, 1);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TemplateURLTableModel::ModifyTemplateURL(int index,
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              const string16& title,
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              const string16& keyword,
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              const std::string& url) {
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(index >= 0 && index <= RowCount());
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!url.empty());
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TemplateURL* template_url = GetTemplateURL(index);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The default search provider should support replacement.
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(template_url_service_->GetDefaultSearchProvider() != template_url ||
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         template_url->SupportsReplacement());
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->RemoveObserver(this);
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->ResetTemplateURL(template_url, title, keyword, url);
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->AddObserver(this);
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReloadIcon(index);  // Also calls NotifyChanged().
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TemplateURLTableModel::ReloadIcon(int index) {
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(index >= 0 && index < RowCount());
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entries_[index]->ResetIcon();
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyChanged(index);
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TemplateURL* TemplateURLTableModel::GetTemplateURL(int index) {
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return entries_[index]->template_url();
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TemplateURLTableModel::IndexOfTemplateURL(
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const TemplateURL* template_url) {
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<ModelEntry*>::iterator i = entries_.begin();
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != entries_.end(); ++i) {
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ModelEntry* entry = *i;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (entry->template_url() == template_url)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return static_cast<int>(i - entries_.begin());
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return -1;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TemplateURLTableModel::MoveToMainGroup(int index) {
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (index < last_search_engine_index_)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return index;  // Already in the main group.
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ModelEntry* current_entry = entries_[index];
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entries_.erase(index + entries_.begin());
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (observer_)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observer_->OnItemsRemoved(index, 1);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int new_index = last_search_engine_index_++;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entries_.insert(entries_.begin() + new_index, current_entry);
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (observer_)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observer_->OnItemsAdded(new_index, 1);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new_index;
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TemplateURLTableModel::MakeDefaultTemplateURL(int index) {
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (index < 0 || index >= RowCount()) {
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TemplateURL* keyword = GetTemplateURL(index);
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const TemplateURL* current_default =
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      template_url_service_->GetDefaultSearchProvider();
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (current_default == keyword)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->RemoveObserver(this);
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->SetDefaultSearchProvider(keyword);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template_url_service_->AddObserver(this);
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The formatting of the default engine is different; notify the table that
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // both old and new entries have changed.
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (current_default != NULL) {
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int old_index = IndexOfTemplateURL(current_default);
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // current_default may not be in the list of TemplateURLs if the database is
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // corrupt and the default TemplateURL is used from preferences
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (old_index >= 0)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NotifyChanged(old_index);
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int new_index = IndexOfTemplateURL(keyword);
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyChanged(new_index);
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure the new default is in the main group.
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return MoveToMainGroup(index);
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TemplateURLTableModel::NotifyChanged(int index) {
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (observer_) {
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_GE(index, 0);
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observer_->OnItemsChanged(index, 1);
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TemplateURLTableModel::FaviconAvailable(ModelEntry* entry) {
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<ModelEntry*>::iterator i =
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::find(entries_.begin(), entries_.end(), entry);
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(i != entries_.end());
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyChanged(static_cast<int>(i - entries_.begin()));
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TemplateURLTableModel::OnTemplateURLServiceChanged() {
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Reload();
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
396