| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/drive/search_metadata.h" | 5 #include "chrome/browser/chromeos/drive/search_metadata.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <queue> | 8 #include <queue> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/i18n/string_search.h" | 11 #include "base/i18n/string_search.h" |
| 12 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
| 13 #include "chrome/browser/chromeos/drive/file_cache.h" | |
| 14 #include "chrome/browser/chromeos/drive/file_system_util.h" | 13 #include "chrome/browser/chromeos/drive/file_system_util.h" |
| 15 #include "content/public/browser/browser_thread.h" | 14 #include "content/public/browser/browser_thread.h" |
| 16 #include "net/base/escape.h" | 15 #include "net/base/escape.h" |
| 17 | 16 |
| 18 using content::BrowserThread; | 17 using content::BrowserThread; |
| 19 | 18 |
| 20 namespace drive { | 19 namespace drive { |
| 21 namespace internal { | 20 namespace internal { |
| 22 | 21 |
| 23 namespace { | 22 namespace { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 76 | 75 |
| 77 // Returns true if |entry| is eligible for the search |options| and should be | 76 // Returns true if |entry| is eligible for the search |options| and should be |
| 78 // tested for the match with the query. If | 77 // tested for the match with the query. If |
| 79 // SEARCH_METADATA_EXCLUDE_HOSTED_DOCUMENTS is requested, the hosted documents | 78 // SEARCH_METADATA_EXCLUDE_HOSTED_DOCUMENTS is requested, the hosted documents |
| 80 // are skipped. If SEARCH_METADATA_EXCLUDE_DIRECTORIES is requested, the | 79 // are skipped. If SEARCH_METADATA_EXCLUDE_DIRECTORIES is requested, the |
| 81 // directories are skipped. If SEARCH_METADATA_SHARED_WITH_ME is requested, only | 80 // directories are skipped. If SEARCH_METADATA_SHARED_WITH_ME is requested, only |
| 82 // the entries with shared-with-me label will be tested. If | 81 // the entries with shared-with-me label will be tested. If |
| 83 // SEARCH_METADATA_OFFLINE is requested, only hosted documents and cached files | 82 // SEARCH_METADATA_OFFLINE is requested, only hosted documents and cached files |
| 84 // match with the query. This option can not be used with other options. | 83 // match with the query. This option can not be used with other options. |
| 85 bool IsEligibleEntry(const ResourceEntry& entry, | 84 bool IsEligibleEntry(const ResourceEntry& entry, |
| 86 internal::FileCache* cache, | 85 ResourceMetadata::Iterator* it, |
| 87 int options) { | 86 int options) { |
| 88 if ((options & SEARCH_METADATA_EXCLUDE_HOSTED_DOCUMENTS) && | 87 if ((options & SEARCH_METADATA_EXCLUDE_HOSTED_DOCUMENTS) && |
| 89 entry.file_specific_info().is_hosted_document()) | 88 entry.file_specific_info().is_hosted_document()) |
| 90 return false; | 89 return false; |
| 91 | 90 |
| 92 if ((options & SEARCH_METADATA_EXCLUDE_DIRECTORIES) && | 91 if ((options & SEARCH_METADATA_EXCLUDE_DIRECTORIES) && |
| 93 entry.file_info().is_directory()) | 92 entry.file_info().is_directory()) |
| 94 return false; | 93 return false; |
| 95 | 94 |
| 96 if (options & SEARCH_METADATA_SHARED_WITH_ME) | 95 if (options & SEARCH_METADATA_SHARED_WITH_ME) |
| 97 return entry.shared_with_me(); | 96 return entry.shared_with_me(); |
| 98 | 97 |
| 99 if (options & SEARCH_METADATA_OFFLINE) { | 98 if (options & SEARCH_METADATA_OFFLINE) { |
| 100 if (entry.file_specific_info().is_hosted_document()) | 99 if (entry.file_specific_info().is_hosted_document()) |
| 101 return true; | 100 return true; |
| 102 FileCacheEntry cache_entry; | 101 FileCacheEntry cache_entry; |
| 103 cache->GetCacheEntry(entry.resource_id(), | 102 it->GetCacheEntry(&cache_entry); |
| 104 std::string(), | |
| 105 &cache_entry); | |
| 106 return cache_entry.is_present(); | 103 return cache_entry.is_present(); |
| 107 } | 104 } |
| 108 | 105 |
| 109 // Exclude "drive", "drive/root", and "drive/other". | 106 // Exclude "drive", "drive/root", and "drive/other". |
| 110 if (entry.resource_id() == util::kDriveGrandRootSpecialResourceId || | 107 if (entry.resource_id() == util::kDriveGrandRootSpecialResourceId || |
| 111 entry.parent_resource_id() == util::kDriveGrandRootSpecialResourceId) { | 108 entry.parent_resource_id() == util::kDriveGrandRootSpecialResourceId) { |
| 112 return false; | 109 return false; |
| 113 } | 110 } |
| 114 | 111 |
| 115 return true; | 112 return true; |
| 116 } | 113 } |
| 117 | 114 |
| 118 // Used to implement SearchMetadata. | 115 // Used to implement SearchMetadata. |
| 119 // Adds entry to the result when appropriate. | 116 // Adds entry to the result when appropriate. |
| 120 // In particular, if |query| is non-null, only adds files with the name matching | 117 // In particular, if |query| is non-null, only adds files with the name matching |
| 121 // the query. | 118 // the query. |
| 122 void MaybeAddEntryToResult( | 119 void MaybeAddEntryToResult( |
| 123 ResourceMetadata* resource_metadata, | 120 ResourceMetadata* resource_metadata, |
| 124 FileCache* cache, | 121 ResourceMetadata::Iterator* it, |
| 125 base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents* query, | 122 base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents* query, |
| 126 int options, | 123 int options, |
| 127 size_t at_most_num_matches, | 124 size_t at_most_num_matches, |
| 128 ScopedPriorityQueue<MetadataSearchResult, | 125 ScopedPriorityQueue<MetadataSearchResult, |
| 129 MetadataSearchResultComparator>* result_candidates, | 126 MetadataSearchResultComparator>* result_candidates) { |
| 130 const ResourceEntry& entry) { | |
| 131 DCHECK_GE(at_most_num_matches, result_candidates->size()); | 127 DCHECK_GE(at_most_num_matches, result_candidates->size()); |
| 132 | 128 |
| 129 const ResourceEntry& entry = it->Get(); |
| 130 |
| 133 // If the candidate set is already full, and this |entry| is old, do nothing. | 131 // If the candidate set is already full, and this |entry| is old, do nothing. |
| 134 // We perform this check first in order to avoid the costly find-and-highlight | 132 // We perform this check first in order to avoid the costly find-and-highlight |
| 135 // or FilePath lookup as much as possible. | 133 // or FilePath lookup as much as possible. |
| 136 if (result_candidates->size() == at_most_num_matches && | 134 if (result_candidates->size() == at_most_num_matches && |
| 137 !CompareByTimestamp(entry, result_candidates->top()->entry)) | 135 !CompareByTimestamp(entry, result_candidates->top()->entry)) |
| 138 return; | 136 return; |
| 139 | 137 |
| 140 // Add |entry| to the result if the entry is eligible for the given | 138 // Add |entry| to the result if the entry is eligible for the given |
| 141 // |options| and matches the query. The base name of the entry must | 139 // |options| and matches the query. The base name of the entry must |
| 142 // contain |query| to match the query. | 140 // contain |query| to match the query. |
| 143 std::string highlighted; | 141 std::string highlighted; |
| 144 if (!IsEligibleEntry(entry, cache, options) || | 142 if (!IsEligibleEntry(entry, it, options) || |
| 145 (query && !FindAndHighlight(entry.base_name(), query, &highlighted))) | 143 (query && !FindAndHighlight(entry.base_name(), query, &highlighted))) |
| 146 return; | 144 return; |
| 147 | 145 |
| 148 // Make space for |entry| when appropriate. | 146 // Make space for |entry| when appropriate. |
| 149 if (result_candidates->size() == at_most_num_matches) | 147 if (result_candidates->size() == at_most_num_matches) |
| 150 result_candidates->pop(); | 148 result_candidates->pop(); |
| 151 result_candidates->push(new MetadataSearchResult(entry, highlighted)); | 149 result_candidates->push(new MetadataSearchResult(entry, highlighted)); |
| 152 } | 150 } |
| 153 | 151 |
| 154 // Implements SearchMetadata(). | 152 // Implements SearchMetadata(). |
| 155 FileError SearchMetadataOnBlockingPool(ResourceMetadata* resource_metadata, | 153 FileError SearchMetadataOnBlockingPool(ResourceMetadata* resource_metadata, |
| 156 FileCache* cache, | |
| 157 const std::string& query_text, | 154 const std::string& query_text, |
| 158 int options, | 155 int options, |
| 159 int at_most_num_matches, | 156 int at_most_num_matches, |
| 160 MetadataSearchResultVector* results) { | 157 MetadataSearchResultVector* results) { |
| 161 ScopedPriorityQueue<MetadataSearchResult, | 158 ScopedPriorityQueue<MetadataSearchResult, |
| 162 MetadataSearchResultComparator> result_candidates; | 159 MetadataSearchResultComparator> result_candidates; |
| 163 | 160 |
| 164 // Prepare data structure for searching. | 161 // Prepare data structure for searching. |
| 165 base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents query( | 162 base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents query( |
| 166 base::UTF8ToUTF16(query_text)); | 163 base::UTF8ToUTF16(query_text)); |
| 167 | 164 |
| 168 // Iterate over entries. | 165 // Iterate over entries. |
| 169 scoped_ptr<ResourceMetadata::Iterator> it = resource_metadata->GetIterator(); | 166 scoped_ptr<ResourceMetadata::Iterator> it = resource_metadata->GetIterator(); |
| 170 for (; !it->IsAtEnd(); it->Advance()) { | 167 for (; !it->IsAtEnd(); it->Advance()) { |
| 171 MaybeAddEntryToResult(resource_metadata, cache, | 168 MaybeAddEntryToResult(resource_metadata, it.get(), |
| 172 query_text.empty() ? NULL : &query, | 169 query_text.empty() ? NULL : &query, |
| 173 options, | 170 options, |
| 174 at_most_num_matches, &result_candidates, it->Get()); | 171 at_most_num_matches, &result_candidates); |
| 175 } | 172 } |
| 176 | 173 |
| 177 // Prepare the result. | 174 // Prepare the result. |
| 178 for (; !result_candidates.empty(); result_candidates.pop()) { | 175 for (; !result_candidates.empty(); result_candidates.pop()) { |
| 179 // The path field of entries in result_candidates are empty at this point, | 176 // The path field of entries in result_candidates are empty at this point, |
| 180 // because we don't want to run the expensive metadata DB look up except for | 177 // because we don't want to run the expensive metadata DB look up except for |
| 181 // the final results. Hence, here we fill the part. | 178 // the final results. Hence, here we fill the part. |
| 182 base::FilePath path = resource_metadata->GetFilePath( | 179 base::FilePath path = resource_metadata->GetFilePath( |
| 183 result_candidates.top()->entry.resource_id()); | 180 result_candidates.top()->entry.resource_id()); |
| 184 if (path.empty()) | 181 if (path.empty()) |
| (...skipping 15 matching lines...) Expand all Loading... |
| 200 if (error != FILE_ERROR_OK) | 197 if (error != FILE_ERROR_OK) |
| 201 results.reset(); | 198 results.reset(); |
| 202 callback.Run(error, results.Pass()); | 199 callback.Run(error, results.Pass()); |
| 203 } | 200 } |
| 204 | 201 |
| 205 } // namespace | 202 } // namespace |
| 206 | 203 |
| 207 void SearchMetadata( | 204 void SearchMetadata( |
| 208 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner, | 205 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner, |
| 209 ResourceMetadata* resource_metadata, | 206 ResourceMetadata* resource_metadata, |
| 210 FileCache* cache, | |
| 211 const std::string& query, | 207 const std::string& query, |
| 212 int options, | 208 int options, |
| 213 int at_most_num_matches, | 209 int at_most_num_matches, |
| 214 const SearchMetadataCallback& callback) { | 210 const SearchMetadataCallback& callback) { |
| 215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 216 DCHECK_LE(0, at_most_num_matches); | 212 DCHECK_LE(0, at_most_num_matches); |
| 217 DCHECK(!callback.is_null()); | 213 DCHECK(!callback.is_null()); |
| 218 | 214 |
| 219 scoped_ptr<MetadataSearchResultVector> results( | 215 scoped_ptr<MetadataSearchResultVector> results( |
| 220 new MetadataSearchResultVector); | 216 new MetadataSearchResultVector); |
| 221 MetadataSearchResultVector* results_ptr = results.get(); | 217 MetadataSearchResultVector* results_ptr = results.get(); |
| 222 base::PostTaskAndReplyWithResult(blocking_task_runner.get(), | 218 base::PostTaskAndReplyWithResult(blocking_task_runner.get(), |
| 223 FROM_HERE, | 219 FROM_HERE, |
| 224 base::Bind(&SearchMetadataOnBlockingPool, | 220 base::Bind(&SearchMetadataOnBlockingPool, |
| 225 resource_metadata, | 221 resource_metadata, |
| 226 cache, | |
| 227 query, | 222 query, |
| 228 options, | 223 options, |
| 229 at_most_num_matches, | 224 at_most_num_matches, |
| 230 results_ptr), | 225 results_ptr), |
| 231 base::Bind(&RunSearchMetadataCallback, | 226 base::Bind(&RunSearchMetadataCallback, |
| 232 callback, | 227 callback, |
| 233 base::Passed(&results))); | 228 base::Passed(&results))); |
| 234 } | 229 } |
| 235 | 230 |
| 236 bool FindAndHighlight( | 231 bool FindAndHighlight( |
| (...skipping 16 matching lines...) Expand all Loading... |
| 253 highlighted_text->append(net::EscapeForHTML(base::UTF16ToUTF8(pre))); | 248 highlighted_text->append(net::EscapeForHTML(base::UTF16ToUTF8(pre))); |
| 254 highlighted_text->append("<b>"); | 249 highlighted_text->append("<b>"); |
| 255 highlighted_text->append(net::EscapeForHTML(base::UTF16ToUTF8(match))); | 250 highlighted_text->append(net::EscapeForHTML(base::UTF16ToUTF8(match))); |
| 256 highlighted_text->append("</b>"); | 251 highlighted_text->append("</b>"); |
| 257 highlighted_text->append(net::EscapeForHTML(base::UTF16ToUTF8(post))); | 252 highlighted_text->append(net::EscapeForHTML(base::UTF16ToUTF8(post))); |
| 258 return true; | 253 return true; |
| 259 } | 254 } |
| 260 | 255 |
| 261 } // namespace internal | 256 } // namespace internal |
| 262 } // namespace drive | 257 } // namespace drive |
| OLD | NEW |