| 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/string_util.h" | 11 #include "base/i18n/string_search.h" |
| 12 #include "base/strings/utf_string_conversions.h" |
| 12 #include "chrome/browser/chromeos/drive/file_cache.h" | 13 #include "chrome/browser/chromeos/drive/file_cache.h" |
| 13 #include "chrome/browser/chromeos/drive/file_system_util.h" | 14 #include "chrome/browser/chromeos/drive/file_system_util.h" |
| 14 #include "content/public/browser/browser_thread.h" | 15 #include "content/public/browser/browser_thread.h" |
| 15 #include "net/base/escape.h" | 16 #include "net/base/escape.h" |
| 16 | 17 |
| 17 using content::BrowserThread; | 18 using content::BrowserThread; |
| 18 | 19 |
| 19 namespace drive { | 20 namespace drive { |
| 20 namespace internal { | 21 namespace internal { |
| 21 | 22 |
| 22 namespace { | 23 namespace { |
| 23 | 24 |
| 24 // Used to sort the result canididates per the last accessed/modified time. The | 25 // Used to sort the result candidates per the last accessed/modified time. The |
| 25 // recently accessed/modified files come first. | 26 // recently accessed/modified files come first. |
| 26 bool CompareByTimestamp(const ResourceEntry& a, const ResourceEntry& b) { | 27 bool CompareByTimestamp(const ResourceEntry& a, const ResourceEntry& b) { |
| 27 const PlatformFileInfoProto& a_file_info = a.file_info(); | 28 const PlatformFileInfoProto& a_file_info = a.file_info(); |
| 28 const PlatformFileInfoProto& b_file_info = b.file_info(); | 29 const PlatformFileInfoProto& b_file_info = b.file_info(); |
| 29 | 30 |
| 30 if (a_file_info.last_accessed() != b_file_info.last_accessed()) | 31 if (a_file_info.last_accessed() != b_file_info.last_accessed()) |
| 31 return a_file_info.last_accessed() > b_file_info.last_accessed(); | 32 return a_file_info.last_accessed() > b_file_info.last_accessed(); |
| 32 | 33 |
| 33 // When the entries have the same last access time (which happens quite often | 34 // When the entries have the same last access time (which happens quite often |
| 34 // because Drive server doesn't set the field until an entry is viewed via | 35 // because Drive server doesn't set the field until an entry is viewed via |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 const std::string& query, | 123 const std::string& query, |
| 123 int options, | 124 int options, |
| 124 size_t at_most_num_matches, | 125 size_t at_most_num_matches, |
| 125 ScopedPriorityQueue<MetadataSearchResult, | 126 ScopedPriorityQueue<MetadataSearchResult, |
| 126 MetadataSearchResultComparator>* result_candidates, | 127 MetadataSearchResultComparator>* result_candidates, |
| 127 const ResourceEntry& entry) { | 128 const ResourceEntry& entry) { |
| 128 DCHECK_GE(at_most_num_matches, result_candidates->size()); | 129 DCHECK_GE(at_most_num_matches, result_candidates->size()); |
| 129 | 130 |
| 130 // Add |entry| to the result if the entry is eligible for the given | 131 // Add |entry| to the result if the entry is eligible for the given |
| 131 // |options| and matches the query. The base name of the entry must | 132 // |options| and matches the query. The base name of the entry must |
| 132 // contains |query| to match the query. | 133 // contain |query| to match the query. |
| 133 std::string highlighted; | 134 std::string highlighted; |
| 134 if (!IsEligibleEntry(entry, cache, options) || | 135 if (!IsEligibleEntry(entry, cache, options) || |
| 135 !FindAndHighlight(entry.base_name(), query, &highlighted)) | 136 !FindAndHighlight(entry.base_name(), query, &highlighted)) |
| 136 return; | 137 return; |
| 137 | 138 |
| 138 base::FilePath path = resource_metadata->GetFilePath(entry.resource_id()); | 139 base::FilePath path = resource_metadata->GetFilePath(entry.resource_id()); |
| 139 if (path.empty()) | 140 if (path.empty()) |
| 140 return; | 141 return; |
| 141 | 142 |
| 142 // Make space for |entry| when appropriate. | 143 // Make space for |entry| when appropriate. |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 bool FindAndHighlight(const std::string& text, | 210 bool FindAndHighlight(const std::string& text, |
| 210 const std::string& query, | 211 const std::string& query, |
| 211 std::string* highlighted_text) { | 212 std::string* highlighted_text) { |
| 212 DCHECK(highlighted_text); | 213 DCHECK(highlighted_text); |
| 213 highlighted_text->clear(); | 214 highlighted_text->clear(); |
| 214 | 215 |
| 215 // For empty query, any filename matches with no highlighted text. | 216 // For empty query, any filename matches with no highlighted text. |
| 216 if (query.empty()) | 217 if (query.empty()) |
| 217 return true; | 218 return true; |
| 218 | 219 |
| 219 // TODO(satorux): Should support non-ASCII characters. | 220 string16 text16 = base::UTF8ToUTF16(text); |
| 220 std::string lower_text = StringToLowerASCII(text); | 221 string16 query16 = base::UTF8ToUTF16(query); |
| 221 std::string lower_query = StringToLowerASCII(query); | 222 size_t match_start = 0; |
| 222 | 223 size_t match_length = 0; |
| 223 int num_matches = 0; | 224 if (!base::i18n::StringSearchIgnoringCaseAndAccents( |
| 224 std::string::size_type cursor = 0; | 225 query16, text16, &match_start, &match_length)) { |
| 225 | 226 return false; |
| 226 while (cursor < text.size()) { | |
| 227 std::string::size_type matched_position = | |
| 228 lower_text.find(lower_query, cursor); | |
| 229 if (matched_position == std::string::npos) | |
| 230 break; | |
| 231 ++num_matches; | |
| 232 | |
| 233 std::string skipped_piece = | |
| 234 net::EscapeForHTML(text.substr(cursor, matched_position - cursor)); | |
| 235 std::string matched_piece = | |
| 236 net::EscapeForHTML(text.substr(matched_position, query.size())); | |
| 237 | |
| 238 highlighted_text->append(skipped_piece); | |
| 239 highlighted_text->append("<b>" + matched_piece + "</b>"); | |
| 240 | |
| 241 cursor = matched_position + query.size(); | |
| 242 } | 227 } |
| 243 if (num_matches == 0) | 228 string16 pre = text16.substr(0, match_start); |
| 244 return false; | 229 string16 match = text16.substr(match_start, match_length); |
| 245 | 230 string16 post = text16.substr(match_start + match_length); |
| 246 std::string remaining_piece = text.substr(cursor); | 231 highlighted_text->append(net::EscapeForHTML(UTF16ToUTF8(pre))); |
| 247 highlighted_text->append(net::EscapeForHTML(remaining_piece)); | 232 highlighted_text->append("<b>"); |
| 248 | 233 highlighted_text->append(net::EscapeForHTML(UTF16ToUTF8(match))); |
| 234 highlighted_text->append("</b>"); |
| 235 highlighted_text->append(net::EscapeForHTML(UTF16ToUTF8(post))); |
| 249 return true; | 236 return true; |
| 250 } | 237 } |
| 251 | 238 |
| 252 } // namespace internal | 239 } // namespace internal |
| 253 } // namespace drive | 240 } // namespace drive |
| OLD | NEW |