Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(533)

Side by Side Diff: content/browser/download/download_query.cc

Issue 7825035: Implement chrome.experimental.downloads.search() (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: merge Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/download/download_query.h"
6
7 #include <set>
8 #include <string>
9 #include <vector>
10
11 #include "base/memory/scoped_ptr.h"
12 #include "base/stl_util.h"
13 #include "base/string16.h"
14 #include "base/string_split.h"
15 #include "base/utf_string_conversions.h"
16 #include "unicode/regex.h"
17 #include "content/browser/download/download_item.h"
18
19 namespace download_util {
20
21 // The FieldInterfaces allow us to keep the templateyness out of the header.
22
23 // Filter fields can be used to filter DownloadItems out of the result set.
24 class DownloadQuery::FilterFieldInterface {
25 public:
26 virtual ~FilterFieldInterface() {}
27 virtual DownloadQuery::FilterFieldName name() const = 0;
28 virtual bool is_set() const = 0;
29 virtual bool Matches(const DownloadItem& item) const = 0;
30 };
31
32 // Sort fields are used by DownloadComparator to sort DownloadItems.
33 class DownloadQuery::SortFieldInterface {
34 public:
35 virtual ~SortFieldInterface() {}
36 virtual DownloadQuery::SortFieldName name() const = 0;
37
38 // Return 0 when left's field is equivalent to right's field, -1 when left <
39 // right, or 1 when left > right.
40 virtual int Compare(const DownloadItem& left,
41 const DownloadItem& right) const = 0;
42 };
43
44 namespace {
45
46 // Functor passed to std::sort to sort DownloadItems.
47 class DownloadComparator {
48 public:
49 DownloadComparator(const DownloadQuery::OrderTerms& order_terms,
50 const DownloadQuery::SortFields& sort_fields)
51 : order_terms_(order_terms),
52 sort_fields_(sort_fields) {
53 }
54
55 // Returns true if |left| sorts before |right|.
56 bool operator() (const DownloadItem* left, const DownloadItem* right);
57
58 private:
59 const DownloadQuery::OrderTerms& order_terms_;
60 const DownloadQuery::SortFields& sort_fields_;
61
62 // std::sort requires this class to be copyable.
63 };
64
65 bool DownloadComparator::operator() (const DownloadItem* left,
66 const DownloadItem* right) {
67 for (DownloadQuery::OrderTerms::const_iterator order_term =
68 order_terms_.begin(); order_term != order_terms_.end(); ++order_term) {
69 DownloadQuery::SortFields::const_iterator sort_field_iter =
70 sort_fields_.find(order_term->name);
71 CHECK(sort_field_iter != sort_fields_.end()) << order_term->name;
72 const DownloadQuery::SortFieldInterface* sort_field =
73 sort_field_iter->second;
74 CHECK(sort_field);
75 CHECK_EQ(sort_field->name(), order_term->name);
76 int comparison = sort_field->Compare(*left, *right);
77 if (comparison != 0)
78 return order_term->ascending == (comparison < 0);
79 }
80 if (left->id() != right->id())
81 return left->id() < right->id();
82 CHECK_NE(left->db_handle(), right->db_handle());
83 return left->db_handle() < right->db_handle();
84 }
85
86 static int get_start_time(const DownloadItem& item) {
asanka 2011/10/20 19:29:16 Nit: These aren't trivial accessors.
87 return (item.start_time() - base::Time::UnixEpoch()).InMilliseconds();
88 }
89
90 static int get_end_time(const DownloadItem& item) {
91 return 0; // TODO(benjhayden): endTime
92 }
93
94 static bool get_danger_accepted(const DownloadItem& item) {
95 return (item.safety_state() == DownloadItem::DANGEROUS_BUT_VALIDATED);
96 }
97
98 static string16 get_filename(const DownloadItem& item) {
99 return item.full_path().LossyDisplayName();
100 }
101
102 template <typename ValueType>
103 class FilterField : public DownloadQuery::FilterFieldInterface {
104 public:
105 explicit FilterField(DownloadQuery::FilterFieldName name)
106 : name_(name),
107 is_set_(false) {
108 }
109 virtual ~FilterField() {}
110
111 virtual DownloadQuery::FilterFieldName name() const { return name_; }
112
113 virtual bool Set(const ValueType& value) {
114 value_ = value;
115 is_set_ = true;
116 return true;
117 }
118
119 virtual bool is_set() const { return is_set_; }
120
121 protected:
122 const ValueType& value() const { return value_; }
123
124 private:
125 DownloadQuery::FilterFieldName name_;
126 ValueType value_;
127 bool is_set_;
128 };
129
130 template <typename ValueType>
131 class SortField : public DownloadQuery::SortFieldInterface {
132 public:
133 explicit SortField(DownloadQuery::SortFieldName name)
134 : name_(name) {
135 }
136 virtual ~SortField() {}
137
138 virtual DownloadQuery::SortFieldName name() const { return name_; }
139
140 virtual ValueType GetField(const DownloadItem& item) const = 0;
141
142 virtual int Compare(const DownloadItem& left,
143 const DownloadItem& right) const {
144 ValueType left_value = GetField(left), right_value = GetField(right);
145 if (left_value > right_value) return 1;
146 if (left_value < right_value) return -1;
147 if (left_value == right_value) return 0;
148 NOTREACHED();
149 return 0;
150 }
151
152 private:
153 DownloadQuery::SortFieldName name_;
154 };
155
156 class FilterFieldQuery : public FilterField<string16> {
157 public:
158 FilterFieldQuery()
159 : FilterField<string16>(DownloadQuery::FILTER_FIELD_QUERY) {
160 }
161 virtual ~FilterFieldQuery() {}
162 virtual bool Set(const string16& value) {
163 base::SplitString(value, L' ', &terms_);
164 // TODO(benjhayden): Split query more intelligently. Quopri?
165 return FilterField<string16>::Set(value);
166 }
167
168 virtual bool Matches(const DownloadItem& item) const {
169 for (std::vector<string16>::const_iterator term = terms_.begin();
170 term != terms_.end(); ++term) {
171 if (!item.MatchesQuery(*term))
172 return false;
173 }
174 return true;
175 }
176
177 private:
178 std::vector<string16> terms_;
179 };
180
181 template <typename StringType>
182 class FilterFieldRegex : public FilterField<StringType> {
183 public:
184 explicit FilterFieldRegex(DownloadQuery::FilterFieldName name)
185 : FilterField<StringType>(name) {
186 }
187 virtual ~FilterFieldRegex() {}
188 virtual bool Set(const StringType& value) {
189 UParseError re_err;
190 UErrorCode re_status = U_ZERO_ERROR;
191 pattern_.reset(icu::RegexPattern::compile(
192 icu::UnicodeString::fromUTF8(ToUTF8(value)),
193 re_err, re_status));
194 return U_SUCCESS(re_status) &&
195 FilterField<StringType>::Set(value);
196 }
197
198 protected:
199 bool RegexMatches(const StringType& text) const {
200 UErrorCode status = U_ZERO_ERROR;
201 scoped_ptr<icu::RegexMatcher> matcher(pattern_->matcher(
202 icu::UnicodeString::fromUTF8(ToUTF8(text)), status));
203 return U_SUCCESS(status) &&
204 matcher->find(0, status);
205 }
206
207 virtual std::string ToUTF8(const StringType& s) const = 0;
208
209 private:
210 scoped_ptr<icu::RegexPattern> pattern_;
211 };
212
213 class FilterFieldUrlRegex : public FilterFieldRegex<std::string> {
214 public:
215 FilterFieldUrlRegex()
216 : FilterFieldRegex<std::string>(DownloadQuery::FILTER_FIELD_URL_REGEX) {
217 }
218 virtual ~FilterFieldUrlRegex() {}
219 virtual bool Matches(const DownloadItem& item) const {
220 return RegexMatches(item.original_url().spec());
221 }
222
223 protected:
224 virtual std::string ToUTF8(const std::string& s) const { return s; }
225 };
226
227 class FilterFieldFilenameRegex : public FilterFieldRegex<string16> {
228 public:
229 FilterFieldFilenameRegex()
230 : FilterFieldRegex<string16>(DownloadQuery::FILTER_FIELD_FILENAME_REGEX) {
231 }
232 virtual ~FilterFieldFilenameRegex() {}
233 virtual bool Matches(const DownloadItem& item) const {
234 return RegexMatches(get_filename(item));
235 }
236
237 protected:
238 virtual std::string ToUTF8(const string16& s) const { return UTF16ToUTF8(s); }
239 };
240
241 } // anonymous namespace
242
243 void DownloadQuery::SetSortField(DownloadQuery::SortFieldName name,
244 DownloadQuery::SortFieldInterface* field) {
245 DCHECK(sort_fields_.find(name) == sort_fields_.end());
246 sort_fields_[name] = field;
247 }
248
249 void DownloadQuery::SetFilterField(DownloadQuery::FilterFieldName name,
250 DownloadQuery::FilterFieldInterface* field) {
251 DCHECK(filter_fields_.find(name) == filter_fields_.end());
252 filter_fields_[name] = field;
253 }
254
255 #define DEFINE_FIELD(name_enum, class_name, field_type, value_type, \
256 method_sig, expr) \
257 Set ## field_type ## Field(name_enum, ({ \
258 class class_name : public field_type ## Field<value_type> { \
259 public: \
260 class_name() : field_type ## Field<value_type>(name_enum) {} \
261 virtual method_sig(const DownloadItem& item) const { return expr; } \
262 }; \
263 new class_name(); \
264 }))
265 #define SORT_FIELD(name, type, expr) \
266 DEFINE_FIELD(SORT_FIELD_ ## name, SortField ## name, Sort, type, \
267 type GetField, expr); \
268 DEFINE_FIELD(FILTER_FIELD_ ## name, FilterField ## name, Filter, type, \
269 bool Matches, (expr) == value())
270 #define FILTER_FIELD(name, type, expr) \
271 DEFINE_FIELD(FILTER_FIELD_ ## name, FilterField ## name, Filter, type, \
272 bool Matches, expr)
273
274 DownloadQuery::DownloadQuery()
275 : limit_(kuint32max),
276 delete_sort_fields_(&sort_fields_),
277 delete_filter_fields_(&filter_fields_) {
278 // All sort fields are also filter fields, but not all filter fields are sort
279 // fields.
280 // If you define a new sort or filter field, make sure that the type is
281 // enumerated in INSTANTIATE_SET below.
asanka 2011/10/20 19:29:16 Have you considered lazy initialization for these,
282 SORT_FIELD(START_TIME, int, get_start_time(item));
283 SORT_FIELD(URL, std::string, item.original_url().spec());
284 SORT_FIELD(FILENAME, string16, get_filename(item));
285 SORT_FIELD(DANGER, DownloadItem::DangerType, item.GetDangerType());
286 SORT_FIELD(DANGER_ACCEPTED, bool, get_danger_accepted(item));
287 SORT_FIELD(STATE, DownloadItem::DownloadState, item.state());
288 SORT_FIELD(PAUSED, bool, item.is_paused());
289 SORT_FIELD(MIME, std::string, item.mime_type());
290 SORT_FIELD(END_TIME, int, get_end_time(item));
291 SORT_FIELD(BYTES_RECEIVED, int, item.received_bytes());
292 SORT_FIELD(TOTAL_BYTES, int, item.total_bytes());
293 SORT_FIELD(FILE_SIZE, int, 0); // TODO
294 SORT_FIELD(ERROR, int, 0); // TODO
295
296 FILTER_FIELD(STARTED_BEFORE, int, get_start_time(item) < value());
297 FILTER_FIELD(STARTED_AFTER, int, get_start_time(item) > value());
298 FILTER_FIELD(ENDED_BEFORE, int, get_end_time(item) < value());
299 FILTER_FIELD(ENDED_AFTER, int, get_end_time(item) > value());
300 FILTER_FIELD(TOTAL_BYTES_GREATER, int, item.total_bytes() > value());
301 FILTER_FIELD(TOTAL_BYTES_LESS, int, item.total_bytes() < value());
302 FILTER_FIELD(FILE_SIZE_GREATER, int, false); // TODO
303 FILTER_FIELD(FILE_SIZE_LESS, int, false); // TODO
304 FILTER_FIELD(FILTER, base::Callback<bool(const DownloadItem& item)>,
305 value().Run(item));
306
307 SetFilterField(FILTER_FIELD_QUERY, new FilterFieldQuery());
308 SetFilterField(FILTER_FIELD_FILENAME_REGEX, new FilterFieldFilenameRegex());
309 SetFilterField(FILTER_FIELD_URL_REGEX, new FilterFieldUrlRegex());
310 }
311
312 #undef FILTER_FIELD
313 #undef SORT_FIELD
314
315 DownloadQuery::~DownloadQuery() {
316 }
317
318 template <typename ValueType>
319 bool DownloadQuery::Set(DownloadQuery::FilterFieldName name,
320 const ValueType& value) {
321 FilterFields::iterator iter = filter_fields_.find(name);
322 return (iter != filter_fields_.end()) &&
323 (iter->second != NULL) &&
324 (iter->second->name() == name) &&
325 static_cast<FilterField<ValueType>*>(iter->second)->Set(value);
asanka 2011/10/20 19:29:16 Would this do the correct thing for something like
326 }
327
328 #define INSTANTIATE_SET(type) \
cbentzel 2011/10/20 18:18:53 Dumb question: Why do you need to do the instantia
329 template bool DownloadQuery::Set( \
330 DownloadQuery::FilterFieldName name, const type& value)
331 INSTANTIATE_SET(int);
332 INSTANTIATE_SET(bool);
333 INSTANTIATE_SET(std::string);
334 INSTANTIATE_SET(string16);
335 INSTANTIATE_SET(base::Callback<bool(const DownloadItem& item)>);
336 INSTANTIATE_SET(DownloadItem::DownloadState);
337 INSTANTIATE_SET(DownloadItem::DangerType);
338 #undef INSTANTIATE_SET
339
340 bool DownloadQuery::Matches(const DownloadItem& item) const {
341 for (FilterFields::const_iterator filter_field = filter_fields_.begin();
342 filter_field != filter_fields_.end(); ++filter_field) {
343 if (filter_field->second->is_set() && !filter_field->second->Matches(item))
344 return false;
345 }
346 return true;
347 }
348
349 template <typename InputIterator>
350 void DownloadQuery::Search(InputIterator iter, const InputIterator last,
351 DownloadQuery::DownloadItems* results) const {
352 results->clear();
353 for (; iter != last; ++iter) {
354 if (Matches(**iter))
355 results->push_back(*iter);
356 }
357 if (!order_by_fields_.empty())
358 std::sort(results->begin(), results->end(),
359 DownloadComparator(order_by_fields_, sort_fields_));
360 if (results->size() > limit_)
361 results->resize(limit_);
362 }
363
364 #define INSTANTIATE_SEARCH(type) \
365 template void DownloadQuery::Search(type iter, const type last, \
366 DownloadQuery::DownloadItems* results) const
367 INSTANTIATE_SEARCH(std::set<DownloadItem*>::const_iterator);
368 INSTANTIATE_SEARCH(std::vector<DownloadItem*>::const_iterator);
369 #undef INSTANTIATE_SEARCH
370
371 } // namespace download_util
372
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698