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

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

Issue 8601012: DownloadQuery filters and sorts DownloadItems. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: comments Created 9 years 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 <algorithm>
8 #include <set>
9 #include <string>
10 #include <vector>
11
12 #include "base/bind.h"
13 #include "base/callback.h"
14 #include "base/logging.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/stl_util.h"
17 #include "base/string16.h"
18 #include "base/string_split.h"
19 #include "base/time.h"
20 #include "base/utf_string_conversions.h"
21 #include "content/browser/download/download_item.h"
22 #include "googleurl/src/gurl.h"
23 #include "unicode/regex.h"
24
25 namespace {
26
27 // The next several functions are helpers for making Callbacks that access
28 // DownloadItem fields.
29
30 static bool MatchesQuery(const string16& value, const DownloadItem& item) {
31 return item.MatchesQuery(value);
32 }
33
34 static int GetStartTime(const DownloadItem& item) {
35 return (item.GetStartTime() - base::Time::UnixEpoch()).InMilliseconds();
36 }
37
38 static int GetEndTime(const DownloadItem& item) {
39 return 0; // TODO
40 }
41
42 static bool GetDangerAccepted(const DownloadItem& item) {
43 return (item.GetSafetyState() == DownloadItem::DANGEROUS_BUT_VALIDATED);
44 }
45
46 static string16 GetFilename(const DownloadItem& item) {
47 // This filename will be compared with strings that could be passed in by the
48 // user, who only sees LossyDisplayNames.
49 return item.GetFullPath().LossyDisplayName();
50 }
51
52 static std::string GetFilenameUTF8(const DownloadItem& item) {
53 return UTF16ToUTF8(GetFilename(item));
54 }
Randy Smith (Not in Mondays) 2011/12/01 19:24:30 How do these two routines relate to what actually
benjhayden 2011/12/02 22:31:53 I don't understand all the differences between los
asanka 2011/12/05 05:17:10 On OS_POSIX the contents of the FilePath is interp
55
56 static std::string GetUrl(const DownloadItem& item) {
Randy Smith (Not in Mondays) 2011/12/01 19:24:30 Do we have long term plans about giving the extens
benjhayden 2011/12/02 22:31:53 See http://crbug.com/106084
57 return item.GetOriginalUrl().spec();
58 }
59
60 static DownloadItem::DownloadState GetState(const DownloadItem& item) {
61 return item.GetState();
62 }
63
64 static DownloadStateInfo::DangerType GetDangerType(const DownloadItem& item) {
65 return item.GetDangerType();
66 }
67
68 static int GetReceivedBytes(const DownloadItem& item) {
69 return item.GetReceivedBytes();
70 }
71
72 static int GetTotalBytes(const DownloadItem& item) {
73 return item.GetTotalBytes();
74 }
75
76 static std::string GetMimeType(const DownloadItem& item) {
77 return item.GetMimeType();
78 }
79
80 static bool IsPaused(const DownloadItem& item) {
81 return item.IsPaused();
82 }
83
84 // Wrap Callback to work around a bug in base::Bind/Callback where the inner
85 // callback is nullified when the outer callback is Run.
86 template<typename ValueType>
87 class InnerCallback {
88 public:
89 typedef base::Callback<ValueType(const DownloadItem&)> CallbackType;
90
91 explicit InnerCallback(const CallbackType& inner) : inner_(inner) {}
92 ~InnerCallback() {}
93
94 // Mimic Callback's interface to facilitate removing InnerCallback when the
95 // bug is fixed.
96 ValueType Run(const DownloadItem& item) const { return inner_.Run(item); }
97
98 private:
99 CallbackType inner_;
100 };
101
102 enum ComparisonType {LT, EQ, GT};
103
104 // Returns true if |item| matches the filter specified by |value|, |cmptype|,
105 // and |accessor|. |accessor| is conceptually a function that takes a
106 // DownloadItem and returns one of its fields, which is then compared to
107 // |value|.
108 template<typename ValueType>
109 static bool FieldMatches(
110 const ValueType& value,
111 ComparisonType cmptype,
112 const InnerCallback<ValueType>& accessor,
113 const DownloadItem& item) {
114 switch (cmptype) {
115 case LT: return accessor.Run(item) < value;
116 case EQ: return accessor.Run(item) == value;
117 case GT: return accessor.Run(item) > value;
118 }
119 return false;
120 }
121
122 // Returns true if |accessor.Run(item)| matches |pattern|.
123 static bool FindRegex(
124 icu::RegexPattern* pattern,
125 const InnerCallback<std::string>& accessor,
126 const DownloadItem& item) {
127 icu::UnicodeString input(accessor.Run(item).c_str());
128 UErrorCode status = U_ZERO_ERROR;
129 scoped_ptr<icu::RegexMatcher> matcher(pattern->matcher(input, status));
130 return matcher->find();
131 }
132
133 // Returns a ComparisonType to indicate whether a field in |left| is less than,
134 // greater than or equal to the same field in |right|.
135 template<typename ValueType>
136 static ComparisonType Compare(
137 const InnerCallback<ValueType>& accessor,
138 const DownloadItem& left, const DownloadItem& right) {
139 ValueType left_value = accessor.Run(left);
140 ValueType right_value = accessor.Run(right);
141 if (left_value > right_value) return GT;
142 if (left_value < right_value) return LT;
143 DCHECK_EQ(left_value, right_value);
144 return EQ;
145 }
146
147 } // anonymous namespace
148
149 DownloadQuery::DownloadQuery()
150 : limit_(kuint32max) {
151 }
152
153 DownloadQuery::~DownloadQuery() {
154 }
155
156 // Filter() pushes a new FilterType to filter_fields_. Most FilterTypes are
157 // Callbacks to FieldMatches<>(). Search() iterates over given DownloadItems,
158 // discarding items for which any filter returns false. A DownloadQuery may have
159 // zero or more FilterTypes.
160
161 void DownloadQuery::Filter(const DownloadQuery::FilterType& value) {
162 filter_fields_.push_back(value);
163 }
164
165 void DownloadQuery::Filter(DownloadItem::DownloadState state) {
166 filter_fields_.push_back(base::Bind(
167 &FieldMatches<DownloadItem::DownloadState>,
168 state,
169 EQ,
170 InnerCallback<DownloadItem::DownloadState>(base::Bind(&GetState))));
171 }
172
173 void DownloadQuery::Filter(DownloadStateInfo::DangerType danger) {
174 filter_fields_.push_back(base::Bind(
175 &FieldMatches<DownloadStateInfo::DangerType>,
176 danger,
177 EQ,
178 InnerCallback<DownloadStateInfo::DangerType>(base::Bind(
179 &GetDangerType))));
180 }
181
182 bool DownloadQuery::Filter(DownloadQuery::FilterFieldName name, int value) {
183 switch (static_cast<int>(name)) {
184 case FILTER_FIELD_START_TIME:
185 Filter(base::Bind(&FieldMatches<int>, value, EQ,
186 InnerCallback<int>(base::Bind(&GetStartTime))));
187 return true;
188 case FILTER_FIELD_STARTED_BEFORE:
189 Filter(base::Bind(&FieldMatches<int>, value, GT,
190 InnerCallback<int>(base::Bind(&GetStartTime))));
191 return true;
192 case FILTER_FIELD_STARTED_AFTER:
193 Filter(base::Bind(&FieldMatches<int>, value, LT,
194 InnerCallback<int>(base::Bind(&GetStartTime))));
195 return true;
196 case FILTER_FIELD_END_TIME:
197 Filter(base::Bind(&FieldMatches<int>, value, EQ,
198 InnerCallback<int>(base::Bind(&GetEndTime))));
199 return true;
200 case FILTER_FIELD_ENDED_BEFORE:
201 Filter(base::Bind(&FieldMatches<int>, value, GT,
202 InnerCallback<int>(base::Bind(&GetEndTime))));
203 return true;
204 case FILTER_FIELD_ENDED_AFTER:
205 Filter(base::Bind(&FieldMatches<int>, value, LT,
206 InnerCallback<int>(base::Bind(&GetEndTime))));
207 return true;
208 case FILTER_FIELD_BYTES_RECEIVED:
209 Filter(base::Bind(&FieldMatches<int>, value, EQ,
210 InnerCallback<int>(base::Bind(&GetReceivedBytes))));
211 return true;
212 case FILTER_FIELD_TOTAL_BYTES:
213 Filter(base::Bind(&FieldMatches<int>, value, EQ,
214 InnerCallback<int>(base::Bind(&GetTotalBytes))));
215 return true;
216 case FILTER_FIELD_TOTAL_BYTES_GREATER:
217 Filter(base::Bind(&FieldMatches<int>, value, LT,
218 InnerCallback<int>(base::Bind(&GetTotalBytes))));
219 return true;
220 case FILTER_FIELD_TOTAL_BYTES_LESS:
221 Filter(base::Bind(&FieldMatches<int>, value, GT,
222 InnerCallback<int>(base::Bind(&GetTotalBytes))));
223 return true;
224 case FILTER_FIELD_FILE_SIZE:
225 case FILTER_FIELD_FILE_SIZE_GREATER:
226 case FILTER_FIELD_FILE_SIZE_LESS:
227 case FILTER_FIELD_ERROR:
228 NOTIMPLEMENTED();
229 return false;
230 }
231 return false;
232 }
233
234 bool DownloadQuery::Filter(DownloadQuery::FilterFieldName name, bool value) {
235 switch (static_cast<int>(name)) {
236 case FILTER_FIELD_DANGER_ACCEPTED:
237 Filter(base::Bind(&FieldMatches<bool>, value, EQ,
238 InnerCallback<bool>(base::Bind(&GetDangerAccepted))));
239 return true;
240 case FILTER_FIELD_PAUSED:
241 Filter(base::Bind(&FieldMatches<bool>, value, EQ,
242 InnerCallback<bool>(base::Bind(&IsPaused))));
243 return true;
244 }
245 return false;
246 }
247
248 bool DownloadQuery::FilterRegex(
249 const std::string& regex_str,
250 const InnerCallback<std::string>::CallbackType& accessor) {
251 UParseError re_err;
252 UErrorCode re_status = U_ZERO_ERROR;
253 scoped_ptr<icu::RegexPattern> pattern(icu::RegexPattern::compile(
254 icu::UnicodeString::fromUTF8(regex_str), re_err, re_status));
255 if (!U_SUCCESS(re_status)) return false;
256 Filter(base::Bind(&FindRegex, base::Owned(pattern.release()),
257 InnerCallback<std::string>(accessor)));
258 return true;
259 }
260
261 bool DownloadQuery::Filter(
262 DownloadQuery::FilterFieldName name, const std::string& value) {
263 switch (static_cast<int>(name)) {
264 case FILTER_FIELD_MIME:
265 Filter(base::Bind(&FieldMatches<std::string>, value, EQ,
266 InnerCallback<std::string>(base::Bind(&GetMimeType))));
267 return true;
268 case FILTER_FIELD_URL:
269 Filter(base::Bind(&FieldMatches<std::string>, value, EQ,
270 InnerCallback<std::string>(base::Bind(&GetUrl))));
271 return true;
272 case FILTER_FIELD_URL_REGEX:
273 return FilterRegex(value, base::Bind(&GetUrl));
274 }
275 return false;
276 }
277
278 bool DownloadQuery::Filter(
279 DownloadQuery::FilterFieldName name, const string16& value) {
280 switch (static_cast<int>(name)) {
281 case FILTER_FIELD_QUERY:
282 Filter(base::Bind(&MatchesQuery, value));
283 return true;
284 case FILTER_FIELD_FILENAME:
285 Filter(base::Bind(&FieldMatches<string16>, value, EQ,
286 InnerCallback<string16>(base::Bind(&GetFilename))));
287 return true;
288 case FILTER_FIELD_FILENAME_REGEX:
289 return FilterRegex(UTF16ToUTF8(value), base::Bind(&GetFilenameUTF8));
290 }
291 return false;
292 }
293
294 bool DownloadQuery::Matches(const DownloadItem& item) const {
295 for (FilterFieldVector::const_iterator filter = filter_fields_.begin();
296 filter != filter_fields_.end(); ++filter) {
297 if (!filter->Run(item))
298 return false;
299 }
300 return true;
301 }
302
303 // Sort() creates a SortField and pushes it onto sort_fields_. A SortField is a
304 // direction and a Callback to Compare<>(). After filtering, Search() makes a
305 // DownloadComparator functor from the sort_fields_ and passes the
306 // DownloadComparator to std::partial_sort. std::partial_sort calls the
307 // DownloadComparator with different pairs of DownloadItems. DownloadComparator
308 // iterates over the sort fields until a callback returns ComparisonType LT or
309 // GT. DownloadComparator returns true or false depending on that
310 // ComparisonType and the sort field's direction in order to indicate to
311 // std::partial_sort whether the left item is after or before the right item. If
312 // all sort fields return EQ, then DownloadComparator compares GetId or
313 // GetDbHandle. A DownloadQuery may have zero or more SortFields, but there is
314 // one DownloadComparator per call to Search().
315
316 struct DownloadQuery::SortField {
317 typedef base::Callback<ComparisonType(
318 const DownloadItem&, const DownloadItem&)> SortType;
319
320 SortField(DownloadQuery::SortFieldDirection adirection,
321 const SortType& asorter)
322 : direction(adirection),
323 sorter(asorter) {
324 }
325 ~SortField() {}
326
327 DownloadQuery::SortFieldDirection direction;
328 SortType sorter;
329 };
330
331 class DownloadQuery::DownloadComparator {
332 public:
333 DownloadComparator(const DownloadQuery::SortFieldVector& terms)
334 : terms_(terms) {
335 }
336
337 // Returns true if |left| sorts before |right|.
338 bool operator() (const DownloadItem* left, const DownloadItem* right);
339
340 private:
341 const DownloadQuery::SortFieldVector& terms_;
342
343 // std::sort requires this class to be copyable.
344 };
345
346 bool DownloadQuery::DownloadComparator::operator() (
347 const DownloadItem* left, const DownloadItem* right) {
348 for (DownloadQuery::SortFieldVector::const_iterator term = terms_.begin();
349 term != terms_.end(); ++term) {
350 switch ((*term).sorter.Run(*left, *right)) {
351 case LT: return ((*term).direction == DownloadQuery::ASCENDING);
352 case GT: return ((*term).direction == DownloadQuery::DESCENDING);
353 case EQ: continue;
354 }
355 }
356 if (left->GetId() != right->GetId())
357 return left->GetId() < right->GetId();
358 CHECK_NE(left->GetDbHandle(), right->GetDbHandle());
359 return left->GetDbHandle() < right->GetDbHandle();
360 }
361
362 void DownloadQuery::Sort(DownloadQuery::SortFieldName name,
363 DownloadQuery::SortFieldDirection direction) {
364 switch (name) {
365 case SORT_FIELD_START_TIME:
366 sort_fields_.push_back(SortField(direction, base::Bind(
367 &Compare<int>, InnerCallback<int>(base::Bind(&GetStartTime)))));
368 break;
369 case SORT_FIELD_URL:
370 sort_fields_.push_back(SortField(direction, base::Bind(
371 &Compare<std::string>,
372 InnerCallback<std::string>(base::Bind(&GetUrl)))));
373 break;
374 case SORT_FIELD_FILENAME:
375 sort_fields_.push_back(SortField(direction, base::Bind(
376 &Compare<string16>,
377 InnerCallback<string16>(base::Bind(&GetFilename)))));
378 break;
379 case SORT_FIELD_DANGER:
380 sort_fields_.push_back(SortField(direction, base::Bind(
381 &Compare<DownloadStateInfo::DangerType>,
382 InnerCallback<DownloadStateInfo::DangerType>(base::Bind(
383 &GetDangerType)))));
384 break;
385 case SORT_FIELD_DANGER_ACCEPTED:
386 sort_fields_.push_back(SortField(direction, base::Bind(
387 &Compare<bool>,
388 InnerCallback<bool>(base::Bind(&GetDangerAccepted)))));
389 break;
390 case SORT_FIELD_STATE:
391 sort_fields_.push_back(SortField(direction, base::Bind(
392 &Compare<DownloadItem::DownloadState>,
393 InnerCallback<DownloadItem::DownloadState>(base::Bind(&GetState)))));
394 break;
395 case SORT_FIELD_PAUSED:
396 sort_fields_.push_back(SortField(direction, base::Bind(
397 &Compare<bool>, InnerCallback<bool>(base::Bind(&IsPaused)))));
398 break;
399 case SORT_FIELD_MIME:
400 sort_fields_.push_back(SortField(direction, base::Bind(
401 &Compare<std::string>,
402 InnerCallback<std::string>(base::Bind(&GetMimeType)))));
403 break;
404 case SORT_FIELD_END_TIME:
405 sort_fields_.push_back(SortField(direction, base::Bind(
406 &Compare<int>, InnerCallback<int>(base::Bind(&GetEndTime)))));
407 break;
408 case SORT_FIELD_BYTES_RECEIVED:
409 sort_fields_.push_back(SortField(direction, base::Bind(
410 &Compare<int>, InnerCallback<int>(base::Bind(&GetReceivedBytes)))));
411 break;
412 case SORT_FIELD_TOTAL_BYTES:
413 sort_fields_.push_back(SortField(direction, base::Bind(
414 &Compare<int>, InnerCallback<int>(base::Bind(&GetTotalBytes)))));
415 break;
416 case SORT_FIELD_FILE_SIZE:
417 case SORT_FIELD_ERROR:
418 NOTIMPLEMENTED();
419 break;
420 default: NOTREACHED();
421 }
422 }
423
424 template <typename InputIterator>
425 void DownloadQuery::Search(InputIterator iter, const InputIterator last,
426 DownloadQuery::DownloadVector* results) const {
427 results->clear();
428 for (; iter != last; ++iter) {
429 if (Matches(**iter))
430 results->push_back(*iter);
431 }
432 if (!sort_fields_.empty())
433 std::partial_sort(results->begin(),
434 results->begin() + std::min(limit_, results->size()),
435 results->end(),
436 DownloadComparator(sort_fields_));
437 if (results->size() > limit_)
438 results->resize(limit_);
439 }
440
441 template void DownloadQuery::Search(
442 std::set<DownloadItem*>::const_iterator iter,
443 const std::set<DownloadItem*>::const_iterator last,
444 DownloadQuery::DownloadVector* results) const;
445 template void DownloadQuery::Search(
446 std::vector<DownloadItem*>::const_iterator iter,
447 const std::vector<DownloadItem*>::const_iterator last,
448 DownloadQuery::DownloadVector* results) const;
449 template void DownloadQuery::Search(
450 std::vector<DownloadItem*>::iterator iter,
451 const std::vector<DownloadItem*>::iterator last,
452 DownloadQuery::DownloadVector* results) const;
453
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698