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)
523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "chrome/browser/autocomplete/shortcuts_backend.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/guid.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/case_conversion.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_notifications.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_service.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/shortcuts_database.h"
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/omnibox/omnibox_log.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/browser/search_engines/template_url_service_factory.h"
23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/common/chrome_constants.h"
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/omnibox/autocomplete_input.h"
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/omnibox/autocomplete_match.h"
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/omnibox/autocomplete_match_type.h"
286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "components/omnibox/autocomplete_result.h"
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "components/omnibox/base_search_provider.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_details.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h"
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/browser/notification_types.h"
34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Takes Match classification vector and removes all matched positions,
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// compacting repetitions if necessary.
4223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)std::string StripMatchMarkers(const ACMatchClassifications& matches) {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ACMatchClassifications unmatched;
444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (ACMatchClassifications::const_iterator i(matches.begin());
454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       i != matches.end(); ++i) {
464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    AutocompleteMatch::AddLastClassificationIfNecessary(
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        &unmatched, i->offset, i->style & ~ACMatchClassification::MATCH);
484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return AutocompleteMatch::ClassificationsToString(unmatched);
504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Normally shortcuts have the same match type as the original match they were
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// created from, but for certain match types, we should modify the shortcut's
544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// type slightly to reflect that the origin of the shortcut is historical.
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)AutocompleteMatch::Type GetTypeForShortcut(AutocompleteMatch::Type type) {
564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  switch (type) {
574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    case AutocompleteMatchType::URL_WHAT_YOU_TYPED:
584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    case AutocompleteMatchType::NAVSUGGEST:
59010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    case AutocompleteMatchType::NAVSUGGEST_PERSONALIZED:
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return AutocompleteMatchType::HISTORY_URL;
614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
62effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    case AutocompleteMatchType::SEARCH_OTHER_ENGINE:
63effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return type;
644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    default:
66effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return AutocompleteMatch::IsSearchType(type) ?
67effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          AutocompleteMatchType::SEARCH_HISTORY : type;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ShortcutsBackend -----------------------------------------------------------
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ShortcutsBackend::ShortcutsBackend(Profile* profile, bool suppress_db)
77effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    : profile_(profile),
78effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      current_state_(NOT_INITIALIZED),
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      no_db_access_(suppress_db) {
804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!suppress_db) {
8123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    db_ = new history::ShortcutsDatabase(
824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        profile->GetPath().Append(chrome::kShortcutsDatabaseName));
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |profile| can be NULL in tests.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile) {
8623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    notification_registrar_.Add(
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this,
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
8923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        content::Source<Profile>(profile));
9023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    notification_registrar_.Add(
9123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        this, chrome::NOTIFICATION_HISTORY_URLS_DELETED,
9223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        content::Source<Profile>(profile));
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShortcutsBackend::Init() {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (current_state_ != NOT_INITIALIZED)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (no_db_access_) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    current_state_ = INITIALIZED;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  current_state_ = INITIALIZING;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&ShortcutsBackend::InitInternal, this));
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)bool ShortcutsBackend::DeleteShortcutsWithURL(const GURL& shortcut_url) {
11123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return initialized() && DeleteShortcutsWithURL(shortcut_url, true);
1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ShortcutsBackend::AddObserver(ShortcutsBackendObserver* obs) {
1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  observer_list_.AddObserver(obs);
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ShortcutsBackend::RemoveObserver(ShortcutsBackendObserver* obs) {
1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  observer_list_.RemoveObserver(obs);
1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void ShortcutsBackend::AddOrUpdateShortcut(const base::string16& text,
1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                           const AutocompleteMatch& match) {
124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  const base::string16 text_lowercase(base::i18n::ToLower(text));
1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const base::Time now(base::Time::Now());
1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (ShortcutMap::const_iterator it(
1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       shortcuts_map_.lower_bound(text_lowercase));
1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       it != shortcuts_map_.end() &&
1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)           StartsWith(it->first, text_lowercase, true); ++it) {
1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (match.destination_url == it->second.match_core.destination_url) {
13123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      UpdateShortcut(history::ShortcutsDatabase::Shortcut(
132effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          it->second.id, text, MatchToMatchCore(match, profile_), now,
13323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          it->second.number_of_hits + 1));
1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return;
1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
1364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
13723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  AddShortcut(history::ShortcutsDatabase::Shortcut(
138effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      base::GenerateGUID(), text, MatchToMatchCore(match, profile_), now, 1));
1394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)ShortcutsBackend::~ShortcutsBackend() {
1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
14423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// static
14523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)history::ShortcutsDatabase::Shortcut::MatchCore
146effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    ShortcutsBackend::MatchToMatchCore(const AutocompleteMatch& match,
147effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                       Profile* profile) {
148effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const AutocompleteMatch::Type match_type = GetTypeForShortcut(match.type);
149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  TemplateURLService* service =
150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      TemplateURLServiceFactory::GetForProfile(profile);
151effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const AutocompleteMatch& normalized_match =
152effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      AutocompleteMatch::IsSpecializedSearchType(match.type) ?
153effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          BaseSearchProvider::CreateSearchSuggestion(
154effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch              match.search_terms_args->search_terms, match_type,
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              (match.transition == ui::PAGE_TRANSITION_KEYWORD),
156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              match.GetTemplateURL(service, false),
157f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)              UIThreadSearchTermsData(profile)) :
158effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          match;
15923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return history::ShortcutsDatabase::Shortcut::MatchCore(
160effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      normalized_match.fill_into_edit, normalized_match.destination_url,
161effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      normalized_match.contents,
162effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      StripMatchMarkers(normalized_match.contents_class),
163effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      normalized_match.description,
164effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      StripMatchMarkers(normalized_match.description_class),
165effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      normalized_match.transition, match_type, normalized_match.keyword);
16623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
16723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
1684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ShortcutsBackend::ShutdownOnUIThread() {
1694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(!BrowserThread::IsThreadInitialized(BrowserThread::UI) ||
1704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)         BrowserThread::CurrentlyOn(BrowserThread::UI));
1714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  notification_registrar_.RemoveAll();
1724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ShortcutsBackend::Observe(int type,
1754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                               const content::NotificationSource& source,
1764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                               const content::NotificationDetails& details) {
1774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!initialized())
1784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
1794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (type == extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED) {
1814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // When an extension is unloaded, we want to remove any Shortcuts associated
1824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // with it.
18323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    DeleteShortcutsWithURL(content::Details<extensions::UnloadedExtensionInfo>(
1844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        details)->extension->url(), false);
1854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
1864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK_EQ(chrome::NOTIFICATION_HISTORY_URLS_DELETED, type);
1894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const history::URLsDeletedDetails* deleted_details =
1904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      content::Details<const history::URLsDeletedDetails>(details).ptr();
1910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (deleted_details->all_history) {
1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DeleteAllShortcuts();
1930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
1940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
1950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
19623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  const history::URLRows& rows(deleted_details->rows);
19723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  history::ShortcutsDatabase::ShortcutIDs shortcut_ids;
1984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (GuidMap::const_iterator it(guid_map_.begin()); it != guid_map_.end();
1994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        ++it) {
2004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (std::find_if(
20123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        rows.begin(), rows.end(), history::URLRow::URLRowHasURL(
2024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            it->second->second.match_core.destination_url)) != rows.end())
2034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      shortcut_ids.push_back(it->first);
2044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
20523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DeleteShortcutsWithIDs(shortcut_ids);
2064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ShortcutsBackend::InitInternal() {
2094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(current_state_ == INITIALIZING);
2104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  db_->Init();
21123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  history::ShortcutsDatabase::GuidToShortcutMap shortcuts;
2124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  db_->LoadShortcuts(&shortcuts);
2134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  temp_shortcuts_map_.reset(new ShortcutMap);
2144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  temp_guid_map_.reset(new GuidMap);
21523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  for (history::ShortcutsDatabase::GuidToShortcutMap::const_iterator it(
2164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       shortcuts.begin()); it != shortcuts.end(); ++it) {
2174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    (*temp_guid_map_)[it->first] = temp_shortcuts_map_->insert(
2184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        std::make_pair(base::i18n::ToLower(it->second.text), it->second));
2194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
2204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
2214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      base::Bind(&ShortcutsBackend::InitCompleted, this));
2224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ShortcutsBackend::InitCompleted() {
2254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  temp_guid_map_->swap(guid_map_);
2264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  temp_shortcuts_map_->swap(shortcuts_map_);
2274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  temp_shortcuts_map_.reset(NULL);
2284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  temp_guid_map_.reset(NULL);
2294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  current_state_ = INITIALIZED;
2304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  FOR_EACH_OBSERVER(ShortcutsBackendObserver, observer_list_,
2314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                    OnShortcutsLoaded());
2324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
23423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)bool ShortcutsBackend::AddShortcut(
23523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const history::ShortcutsDatabase::Shortcut& shortcut) {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!initialized())
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(guid_map_.find(shortcut.id) == guid_map_.end());
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  guid_map_[shortcut.id] = shortcuts_map_.insert(
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::make_pair(base::i18n::ToLower(shortcut.text), shortcut));
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(ShortcutsBackendObserver, observer_list_,
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    OnShortcutsChanged());
24323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return no_db_access_ ||
24423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      BrowserThread::PostTask(
24523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          BrowserThread::DB, FROM_HERE,
24623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          base::Bind(base::IgnoreResult(
24723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                         &history::ShortcutsDatabase::AddShortcut),
24823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                     db_.get(), shortcut));
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)bool ShortcutsBackend::UpdateShortcut(
25223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const history::ShortcutsDatabase::Shortcut& shortcut) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!initialized())
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  GuidMap::iterator it(guid_map_.find(shortcut.id));
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it != guid_map_.end())
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shortcuts_map_.erase(it->second);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  guid_map_[shortcut.id] = shortcuts_map_.insert(
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::make_pair(base::i18n::ToLower(shortcut.text), shortcut));
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(ShortcutsBackendObserver, observer_list_,
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    OnShortcutsChanged());
26223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return no_db_access_ ||
26323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      BrowserThread::PostTask(
26423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          BrowserThread::DB, FROM_HERE,
26523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          base::Bind(base::IgnoreResult(
26623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                         &history::ShortcutsDatabase::UpdateShortcut),
26723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                     db_.get(), shortcut));
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)bool ShortcutsBackend::DeleteShortcutsWithIDs(
27123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const history::ShortcutsDatabase::ShortcutIDs& shortcut_ids) {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!initialized())
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < shortcut_ids.size(); ++i) {
2754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    GuidMap::iterator it(guid_map_.find(shortcut_ids[i]));
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (it != guid_map_.end()) {
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shortcuts_map_.erase(it->second);
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      guid_map_.erase(it);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(ShortcutsBackendObserver, observer_list_,
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    OnShortcutsChanged());
28323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return no_db_access_ ||
28423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      BrowserThread::PostTask(
28523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          BrowserThread::DB, FROM_HERE,
28623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          base::Bind(base::IgnoreResult(
28723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                         &history::ShortcutsDatabase::DeleteShortcutsWithIDs),
28823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                     db_.get(), shortcut_ids));
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)bool ShortcutsBackend::DeleteShortcutsWithURL(const GURL& url,
2924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                              bool exact_match) {
2934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const std::string& url_spec = url.spec();
29423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  history::ShortcutsDatabase::ShortcutIDs shortcut_ids;
2954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (GuidMap::iterator it(guid_map_.begin()); it != guid_map_.end(); ) {
2964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (exact_match ?
2974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        (it->second->second.match_core.destination_url == url) :
2984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        StartsWithASCII(it->second->second.match_core.destination_url.spec(),
2994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                        url_spec, true)) {
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shortcut_ids.push_back(it->first);
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shortcuts_map_.erase(it->second);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      guid_map_.erase(it++);
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++it;
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(ShortcutsBackendObserver, observer_list_,
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    OnShortcutsChanged());
3094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return no_db_access_ ||
3104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      BrowserThread::PostTask(
3114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          BrowserThread::DB, FROM_HERE,
31223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          base::Bind(base::IgnoreResult(
31323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                         &history::ShortcutsDatabase::DeleteShortcutsWithURL),
31423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                     db_.get(), url_spec));
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShortcutsBackend::DeleteAllShortcuts() {
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!initialized())
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shortcuts_map_.clear();
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  guid_map_.clear();
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(ShortcutsBackendObserver, observer_list_,
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    OnShortcutsChanged());
32423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return no_db_access_ ||
32523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      BrowserThread::PostTask(
32623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          BrowserThread::DB, FROM_HERE,
32723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          base::Bind(base::IgnoreResult(
32823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                         &history::ShortcutsDatabase::DeleteAllShortcuts),
32923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                     db_.get()));
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
331